Merge package:yaml into the tools monorepo
diff --git a/.github/ISSUE_TEMPLATE/bazel_worker.md b/.github/ISSUE_TEMPLATE/bazel_worker.md
new file mode 100644
index 0000000..db70c0d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bazel_worker.md
@@ -0,0 +1,5 @@
+---
+name: "package:bazel_worker"
+about: "Create a bug or file a feature request against package:bazel_worker."
+labels: "package:bazel_worker"
+---
diff --git a/.github/ISSUE_TEMPLATE/benchmark_harness.md b/.github/ISSUE_TEMPLATE/benchmark_harness.md
new file mode 100644
index 0000000..2f788b0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/benchmark_harness.md
@@ -0,0 +1,5 @@
+---
+name: "package:benchmark_harness"
+about: "Create a bug or file a feature request against package:benchmark_harness."
+labels: "package:benchmark_harness"
+---
diff --git a/.github/ISSUE_TEMPLATE/boolean_selector.md b/.github/ISSUE_TEMPLATE/boolean_selector.md
new file mode 100644
index 0000000..0b7737a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/boolean_selector.md
@@ -0,0 +1,5 @@
+---
+name: "package:boolean_selector"
+about: "Create a bug or file a feature request against package:boolean_selector."
+labels: "package:boolean_selector"
+---
diff --git a/.github/ISSUE_TEMPLATE/browser_launcher.md b/.github/ISSUE_TEMPLATE/browser_launcher.md
new file mode 100644
index 0000000..f893b1f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/browser_launcher.md
@@ -0,0 +1,5 @@
+---
+name: "package:browser_launcher"
+about: "Create a bug or file a feature request against package:browser_launcher."
+labels: "package:browser_launcher"
+---
diff --git a/.github/ISSUE_TEMPLATE/cli_config.md b/.github/ISSUE_TEMPLATE/cli_config.md
new file mode 100644
index 0000000..c47fbcf
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/cli_config.md
@@ -0,0 +1,5 @@
+---
+name: "package:cli_config"
+about: "Create a bug or file a feature request against package:cli_config."
+labels: "package:cli_config"
+---
diff --git a/.github/ISSUE_TEMPLATE/cli_util.md b/.github/ISSUE_TEMPLATE/cli_util.md
new file mode 100644
index 0000000..ec090f1
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/cli_util.md
@@ -0,0 +1,5 @@
+---
+name: "package:cli_util"
+about: "Create a bug or file a feature request against package:cli_util."
+labels: "package:cli_util"
+---
diff --git a/.github/ISSUE_TEMPLATE/clock.md b/.github/ISSUE_TEMPLATE/clock.md
new file mode 100644
index 0000000..73dc6c7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/clock.md
@@ -0,0 +1,5 @@
+---
+name: "package:clock"
+about: "Create a bug or file a feature request against package:clock."
+labels: "package:clock"
+---
diff --git a/.github/ISSUE_TEMPLATE/code_builder.md b/.github/ISSUE_TEMPLATE/code_builder.md
new file mode 100644
index 0000000..62f89f9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/code_builder.md
@@ -0,0 +1,5 @@
+---
+name: "package:code_builder"
+about: "Create a bug or file a feature request against package:code_builder."
+labels: "package:code_builder"
+---
diff --git a/.github/ISSUE_TEMPLATE/coverage.md b/.github/ISSUE_TEMPLATE/coverage.md
new file mode 100644
index 0000000..d0b0fb7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/coverage.md
@@ -0,0 +1,5 @@
+---
+name: "package:coverage"
+about: "Create a bug or file a feature request against package:coverage."
+labels: "package:coverage"
+---
diff --git a/.github/ISSUE_TEMPLATE/csslib.md b/.github/ISSUE_TEMPLATE/csslib.md
new file mode 100644
index 0000000..670d354
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/csslib.md
@@ -0,0 +1,5 @@
+---
+name: "package:csslib"
+about: "Create a bug or file a feature request against package:csslib."
+labels: "package:csslib"
+---
diff --git a/.github/ISSUE_TEMPLATE/extension_discovery.md b/.github/ISSUE_TEMPLATE/extension_discovery.md
new file mode 100644
index 0000000..165b7cb
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/extension_discovery.md
@@ -0,0 +1,5 @@
+---
+name: "package:extension_discovery"
+about: "Create a bug or file a feature request against package:extension_discovery."
+labels: "package:extension_discovery"
+---
diff --git a/.github/ISSUE_TEMPLATE/file.md b/.github/ISSUE_TEMPLATE/file.md
new file mode 100644
index 0000000..3430d7e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/file.md
@@ -0,0 +1,5 @@
+---
+name: "package:file"
+about: "Create a bug or file a feature request against package:file."
+labels: "package:file"
+---
diff --git a/.github/ISSUE_TEMPLATE/graphs.md b/.github/ISSUE_TEMPLATE/graphs.md
new file mode 100644
index 0000000..b4cb60f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/graphs.md
@@ -0,0 +1,5 @@
+---
+name: "package:graphs"
+about: "Create a bug or file a feature request against package:graphs."
+labels: "package:graphs"
+---
diff --git a/.github/ISSUE_TEMPLATE/html.md b/.github/ISSUE_TEMPLATE/html.md
new file mode 100644
index 0000000..b128343
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/html.md
@@ -0,0 +1,5 @@
+---
+name: "package:html"
+about: "Create a bug or file a feature request against package:html."
+labels: "package:html"
+---
diff --git a/.github/ISSUE_TEMPLATE/io.md b/.github/ISSUE_TEMPLATE/io.md
new file mode 100644
index 0000000..5646f0f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/io.md
@@ -0,0 +1,5 @@
+---
+name: "package:io"
+about: "Create a bug or file a feature request against package:io."
+labels: "package:io"
+---
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/json_rpc_2.md b/.github/ISSUE_TEMPLATE/json_rpc_2.md
new file mode 100644
index 0000000..b4dec80
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/json_rpc_2.md
@@ -0,0 +1,5 @@
+---
+name: "package:json_rpc_2"
+about: "Create a bug or file a feature request against package:json_rpc_2."
+labels: "package:json_rpc_2"
+---
diff --git a/.github/ISSUE_TEMPLATE/mime.md b/.github/ISSUE_TEMPLATE/mime.md
new file mode 100644
index 0000000..9a3c57e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/mime.md
@@ -0,0 +1,5 @@
+---
+name: "package:mime"
+about: "Create a bug or file a feature request against package:mime."
+labels: "package:mime"
+---
diff --git a/.github/ISSUE_TEMPLATE/oauth2.md b/.github/ISSUE_TEMPLATE/oauth2.md
new file mode 100644
index 0000000..396f2e2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/oauth2.md
@@ -0,0 +1,5 @@
+---
+name: "package:oauth2"
+about: "Create a bug or file a feature request against package:oauth2."
+labels: "package:oauth2"
+---
diff --git a/.github/ISSUE_TEMPLATE/package_config.md b/.github/ISSUE_TEMPLATE/package_config.md
new file mode 100644
index 0000000..f6322d0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/package_config.md
@@ -0,0 +1,5 @@
+---
+name: "package:package_config"
+about: "Create a bug or file a feature request against package:package_config."
+labels: "package:package_config"
+---
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/pool.md b/.github/ISSUE_TEMPLATE/pool.md
new file mode 100644
index 0000000..7af32c4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/pool.md
@@ -0,0 +1,5 @@
+---
+name: "package:pool"
+about: "Create a bug or file a feature request against package:pool."
+labels: "package:pool"
+---
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/pub_semver.md b/.github/ISSUE_TEMPLATE/pub_semver.md
new file mode 100644
index 0000000..c7db9b5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/pub_semver.md
@@ -0,0 +1,5 @@
+---
+name: "package:pub_semver"
+about: "Create a bug or file a feature request against package:pub_semver."
+labels: "package:pub_semver"
+---
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/source_map_stack_trace.md b/.github/ISSUE_TEMPLATE/source_map_stack_trace.md
new file mode 100644
index 0000000..66d4e32
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/source_map_stack_trace.md
@@ -0,0 +1,5 @@
+---
+name: "package:source_map_stack_trace"
+about: "Create a bug or file a feature request against package:source_map_stack_trace."
+labels: "package:source_map_stack_trace"
+---
diff --git a/.github/ISSUE_TEMPLATE/source_maps.md b/.github/ISSUE_TEMPLATE/source_maps.md
new file mode 100644
index 0000000..a1e390a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/source_maps.md
@@ -0,0 +1,5 @@
+---
+name: "package:source_maps"
+about: "Create a bug or file a feature request against package:source_maps."
+labels: "package:source_maps"
+---
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/source_span.md b/.github/ISSUE_TEMPLATE/source_span.md
new file mode 100644
index 0000000..7dbb3c4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/source_span.md
@@ -0,0 +1,5 @@
+---
+name: "package:source_span"
+about: "Create a bug or file a feature request against package:source_span."
+labels: "package:source_span"
+---
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/sse.md b/.github/ISSUE_TEMPLATE/sse.md
new file mode 100644
index 0000000..17cc488
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/sse.md
@@ -0,0 +1,5 @@
+---
+name: "package:sse"
+about: "Create a bug or file a feature request against package:sse."
+labels: "package:sse"
+---
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/unified_analytics.md b/.github/ISSUE_TEMPLATE/unified_analytics.md
new file mode 100644
index 0000000..163951e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/unified_analytics.md
@@ -0,0 +1,5 @@
+---
+name: "package:unified_analytics - bug or enhancement"
+about: "Create a bug or file a feature request against package:unified_analytics."
+labels: "package:unified_analytics"
+---
diff --git a/.github/ISSUE_TEMPLATE/unified_analytics_event.yml b/.github/ISSUE_TEMPLATE/unified_analytics_event.yml
new file mode 100644
index 0000000..52c8d83
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/unified_analytics_event.yml
@@ -0,0 +1,47 @@
+name: "package:unified_analytics - request a new event"
+description: "Create a request for collecting a new event or new event data."
+labels: "package:unified_analytics"
+body:
+ - type: markdown
+ attributes:
+ value: |
+ An event is an action that a user, or the tool, performs.
+ You can see the events that are being collected [here](../../pkgs/unified_analytics/lib/src/enums.dart)
+ and the data associated with those events [here](../../pkgs/unified_analytics/lib/src/event.dart).
+ - type: checkboxes
+ attributes:
+ label: Has this already been approved in the privacy design documentation?
+ options:
+ - label: This field is already covered in the PDD
+ description: |
+ You can request that a new event be added to the package
+ regardless of whether it's included in the privacy design documentation.
+ However, the privacy team will need to approve before it is added.
+
+ - type: textarea
+ attributes:
+ label: Event name
+ description: |
+ If the event already exists, please tell us the name of the event
+ you would like to add data to.
+
+ If this is a new event, tell us the name, description, and tool owner.
+ Possible tool owners can be found in the `DashTool` enum [here](../../pkgs/unified_analytics/lib/src/enums.dart).
+
+ For example, pub_get represents pub package resolution details. The owner is the Dart tool.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Event data
+ description: |
+ Event data are key-value pairs that are associated with an event.
+ Please list the different event data associated with this event.
+ You should also include a description of the event data values.
+
+ For example, if the event is pub_get, one event data may be
+ the packageName. The values would be the name of the package
+ as a string.
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/unified_analytics_user_property.yml b/.github/ISSUE_TEMPLATE/unified_analytics_user_property.yml
new file mode 100644
index 0000000..3fc960e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/unified_analytics_user_property.yml
@@ -0,0 +1,37 @@
+name: "package:unified_analytics - request a new user property"
+description: "Create a request for collecting a new user property."
+labels: "package:unified_analytics"
+body:
+ - type: markdown
+ attributes:
+ value: |
+ A user property is a key-value pair that is used to segment users.
+ For example, the Flutter channel that the user is on. You can see
+ which user properties are being collected
+ [here](../../pkgs/unified_analytics/lib/src/user_property.dart).
+
+ - type: checkboxes
+ attributes:
+ label: Has this already been approved in the privacy design documentation?
+ options:
+ - label: This field is already covered in the PDD
+ description: |
+ You can request that a new user property be added to the package
+ regardless of whether it's included in the privacy design documentation.
+ However, the privacy team will need to approve before it is added.
+
+ - type: textarea
+ attributes:
+ label: User property name
+ description: |
+ Please tell us the name of the user property you would like to add (e.g. flutter_channel).
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: User property values
+ description: |
+ Please list or describe the unique values for this property (e.g. master, beta, stable).
+ validations:
+ required: true
diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml
new file mode 100644
index 0000000..bf6b38a
--- /dev/null
+++ b/.github/dependabot.yaml
@@ -0,0 +1,14 @@
+# Dependabot configuration file.
+version: 2
+
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ schedule:
+ interval: monthly
+ labels:
+ - autosubmit
+ groups:
+ github-actions:
+ patterns:
+ - "*"
diff --git a/.github/labeler.yml b/.github/labeler.yml
new file mode 100644
index 0000000..1cc4b20
--- /dev/null
+++ b/.github/labeler.yml
@@ -0,0 +1,113 @@
+# Configuration for .github/workflows/pull_request_label.yml.
+
+'type-infra':
+ - changed-files:
+ - any-glob-to-any-file: '.github/**'
+
+'package:bazel_worker':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/bazel_worker/**'
+
+'package:benchmark_harness':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/benchmark_harness/**'
+
+'package:boolean_selector':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/boolean_selector/**'
+
+'package:browser_launcher':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/browser_launcher/**'
+
+'package:cli_config':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/cli_config/**'
+
+'package:cli_util':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/cli_util/**'
+
+'package:clock':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/clock/**'
+
+'package:code_builder':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/code_builder/**'
+
+'package:coverage':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/coverage/**'
+
+'package:csslib':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/csslib/**'
+
+'package:extension_discovery':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/extension_discovery/**'
+
+'package:file':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/file/**'
+
+'package:file_testing':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/file_testing/**'
+
+'package:graphs':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/graphs/**'
+
+'package:html':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/html/**'
+
+'package:io':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/io/**'
+
+'package:json_rpc_2':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/json_rpc_2/**'
+
+'package:mime':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/mime/**'
+
+'package:oauth2':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/oauth2/**'
+
+'package:package_config':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/package_config/**'
+
+'package:pool':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/pool/**'
+
+'package:pub_semver':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/pub_semver/**'
+
+'package:source_map_stack_trace':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/source_map_stack_trace/**'
+
+'package:source_maps':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/source_maps/**'
+
+'package:source_span':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/source_span/**'
+
+'package:sse':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/sse/**'
+
+'package:unified_analytics':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/unified_analytics/**'
diff --git a/.github/workflows/bazel_worker.yaml b/.github/workflows/bazel_worker.yaml
new file mode 100644
index 0000000..0eb06da
--- /dev/null
+++ b/.github/workflows/bazel_worker.yaml
@@ -0,0 +1,41 @@
+name: package:bazel_worker
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/bazel_worker.yml'
+ - 'pkgs/bazel_worker/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/bazel_worker.yml'
+ - 'pkgs/bazel_worker/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/bazel_worker/
+
+jobs:
+ # Run the test script against the latest dev build.
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [3.4, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - run: "dart format --output=none --set-exit-if-changed ."
+ - name: Test
+ run: ./tool/travis.sh
diff --git a/.github/workflows/benchmark_harness.yaml b/.github/workflows/benchmark_harness.yaml
new file mode 100644
index 0000000..8e0cc8a
--- /dev/null
+++ b/.github/workflows/benchmark_harness.yaml
@@ -0,0 +1,74 @@
+name: package:benchmark_harness
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/benchmark_harness.yml'
+ - 'pkgs/benchmark_harness/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/benchmark_harness.yml'
+ - 'pkgs/benchmark_harness/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+defaults:
+ run:
+ working-directory: pkgs/benchmark_harness/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.2, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests
+ run: dart test --platform chrome
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/boolean_selector.yaml b/.github/workflows/boolean_selector.yaml
new file mode 100644
index 0000000..3e35050
--- /dev/null
+++ b/.github/workflows/boolean_selector.yaml
@@ -0,0 +1,72 @@
+name: package:boolean_selector
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/boolean_selector.yml'
+ - 'pkgs/boolean_selector/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/boolean_selector.yml'
+ - 'pkgs/boolean_selector/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/boolean_selector/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.1, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests
+ run: dart test --platform chrome
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/browser_launcher.yaml b/.github/workflows/browser_launcher.yaml
new file mode 100644
index 0000000..41bf8da
--- /dev/null
+++ b/.github/workflows/browser_launcher.yaml
@@ -0,0 +1,46 @@
+name: package:browser_launcher
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/browser_launcher.yml'
+ - 'pkgs/browser_launcher/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/browser_launcher.yml'
+ - 'pkgs/browser_launcher/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+ DISPLAY: ':99'
+
+defaults:
+ run:
+ working-directory: pkgs/browser_launcher/
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ sdk: [3.4, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+
+ - run: dart pub get
+
+ - run: dart format --output=none --set-exit-if-changed .
+ - run: dart analyze --fatal-infos
+
+ - name: Run Xvfb
+ run: Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
+
+ - run: dart test
diff --git a/.github/workflows/cli_config.yml b/.github/workflows/cli_config.yml
new file mode 100644
index 0000000..0ef1524
--- /dev/null
+++ b/.github/workflows/cli_config.yml
@@ -0,0 +1,79 @@
+name: package:cli_config
+permissions: read-all
+
+on:
+ pull_request:
+ paths:
+ - ".github/workflows/cli_config.yml"
+ - "pkgs/cli_config/**"
+ push:
+ branches: [main]
+ paths:
+ - ".github/workflows/cli_config.yml"
+ - "pkgs/cli_config/**"
+ schedule:
+ - cron: "0 0 * * 0" # weekly
+
+jobs:
+ build_linux:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: pkgs/cli_config
+ strategy:
+ matrix:
+ sdk: [stable, dev] # {pkgs.versions}
+ include:
+ - sdk: stable
+ run-tests: true
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{matrix.sdk}}
+
+ - run: dart pub get
+
+ - run: dart analyze --fatal-infos
+
+ - run: dart format --output=none --set-exit-if-changed .
+ if: ${{matrix.run-tests}}
+
+ - run: dart test
+ if: ${{matrix.run-tests}}
+
+ - name: Install coverage
+ run: dart pub global activate coverage
+ if: ${{ matrix.sdk == 'stable' }}
+ - name: Collect coverage
+ run: dart pub global run coverage:test_with_coverage
+ if: ${{ matrix.sdk == 'stable' }}
+ - name: Upload coverage
+ uses: coverallsapp/github-action@cfd0633edbd2411b532b808ba7a8b5e04f76d2c8
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ flag-name: cli_config_linux
+ path-to-lcov: ./pkgs/cli_config/coverage/lcov.info
+ if: ${{ matrix.sdk == 'stable' }}
+
+ build_windows:
+ runs-on: windows-latest
+ defaults:
+ run:
+ working-directory: pkgs/cli_config
+ strategy:
+ matrix:
+ sdk: [stable, dev] # {pkgs.versions}
+ include:
+ - sdk: stable
+ run-tests: true
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{matrix.sdk}}
+
+ - run: dart pub get
+
+ - run: dart test
+ if: ${{matrix.run-tests}}
diff --git a/.github/workflows/cli_util.yaml b/.github/workflows/cli_util.yaml
new file mode 100644
index 0000000..1c9fec0
--- /dev/null
+++ b/.github/workflows/cli_util.yaml
@@ -0,0 +1,66 @@
+name: package:cli_util
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/cli_util.yml'
+ - 'pkgs/cli_util/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/cli_util.yml'
+ - 'pkgs/cli_util/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/cli_util/
+
+jobs:
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest]
+ sdk: ['3.4', dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run tests
+ run: dart test --test-randomize-ordering-seed=random
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/clock.yaml b/.github/workflows/clock.yaml
new file mode 100644
index 0000000..aef0895
--- /dev/null
+++ b/.github/workflows/clock.yaml
@@ -0,0 +1,75 @@
+name: package:clock
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/clock.yml'
+ - 'pkgs/clock/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/clock.yml'
+ - 'pkgs/clock/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/clock/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.4, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests
+ run: dart test --platform chrome
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/code_builder.yaml b/.github/workflows/code_builder.yaml
new file mode 100644
index 0000000..2b2ad16
--- /dev/null
+++ b/.github/workflows/code_builder.yaml
@@ -0,0 +1,68 @@
+name: package:code_builder
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/code_builder.yml'
+ - 'pkgs/code_builder/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/code_builder.yml'
+ - 'pkgs/code_builder/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/code_builder/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev and an earlier stable version.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos .
+ if: always() && steps.install.outcome == 'success'
+
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest]
+ sdk: [3.5.0, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 0000000..ca4463f
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,99 @@
+name: Dart CI
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/coverage.yml'
+ - 'pkgs/coverage/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/coverage.yml'
+ - 'pkgs/coverage/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: pkgs/coverage/
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, macos-latest, windows-latest
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ defaults:
+ run:
+ working-directory: pkgs/coverage/
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ sdk: [3.4, dev]
+ exclude:
+ # VM service times out on windows before Dart 3.5
+ # https://github.com/dart-lang/coverage/issues/490
+ - os: windows-latest
+ sdk: 3.4
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+
+ coverage:
+ needs: test
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: pkgs/coverage/
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: dev
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Collect and report coverage
+ run: dart run bin/test_with_coverage.dart --port=9292
+ - name: Upload coverage
+ uses: coverallsapp/github-action@cfd0633edbd2411b532b808ba7a8b5e04f76d2c8
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ path-to-lcov: pkgs/coverage/coverage/lcov.info
diff --git a/.github/workflows/csslib.yaml b/.github/workflows/csslib.yaml
new file mode 100644
index 0000000..c370293
--- /dev/null
+++ b/.github/workflows/csslib.yaml
@@ -0,0 +1,72 @@
+name: package:csslib
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/csslib.yml'
+ - 'pkgs/csslib/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/csslib.yml'
+ - 'pkgs/csslib/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/csslib/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest, windows-latest]
+ sdk: [3.1, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/extension_discovery.yml b/.github/workflows/extension_discovery.yml
new file mode 100644
index 0000000..dd129a7
--- /dev/null
+++ b/.github/workflows/extension_discovery.yml
@@ -0,0 +1,47 @@
+name: package:extension_discovery
+permissions: read-all
+
+on:
+ pull_request:
+ paths:
+ - '.github/workflows/unified_analytics.yml'
+ - 'pkgs/extension_discovery/**'
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/extension_discovery.yml'
+ - 'pkgs/extension_discovery/**'
+ schedule:
+ - cron: '0 0 * * 0' # weekly
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: pkgs/extension_discovery
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [stable, dev] # {pkgs.versions}
+ include:
+ - sdk: stable
+ check-formatting: true
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{matrix.sdk}}
+
+ - run: dart pub get
+ - run: |
+ (cd example/hello_world && dart pub get)
+ (cd example/hello_world_app && dart pub get)
+ (cd example/hello_world_german && dart pub get)
+
+ - run: dart analyze --fatal-infos
+
+ - run: dart format --output=none --set-exit-if-changed .
+ if: ${{matrix.check-formatting}}
+
+ - run: dart test
diff --git a/.github/workflows/file.yml b/.github/workflows/file.yml
new file mode 100644
index 0000000..e8c3bff
--- /dev/null
+++ b/.github/workflows/file.yml
@@ -0,0 +1,66 @@
+name: package:file
+permissions: read-all
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/file.yml'
+ - 'pkgs/file/**'
+ - 'pkgs/file_testing/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/file.yml'
+ - 'pkgs/file/**'
+ - 'pkgs/file_testing/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+jobs:
+ correctness:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ package: [file, file_testing]
+
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: dev
+
+ - name: Install ${{ matrix.package }} dependencies
+ working-directory: pkgs/${{ matrix.package }}
+ run: dart pub get
+
+ - name: Verify formatting in ${{ matrix.package }}
+ working-directory: pkgs/${{ matrix.package }}
+ run: dart format --output=none --set-exit-if-changed .
+
+ - name: Analyze package ${{ matrix.package }} source
+ working-directory: pkgs/${{ matrix.package }}
+ run: dart analyze --fatal-infos
+
+ test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ package: [file]
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ sdk: [stable, dev]
+
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+
+ - name: Install ${{ matrix.package }} dependencies
+ working-directory: pkgs/${{ matrix.package }}
+ run: dart pub get
+
+ - name: Run ${{ matrix.package }} Tests
+ working-directory: pkgs/${{ matrix.package }}
+ run: dart pub run test -j1
diff --git a/.github/workflows/graphs.yml b/.github/workflows/graphs.yml
new file mode 100644
index 0000000..c86ebb1
--- /dev/null
+++ b/.github/workflows/graphs.yml
@@ -0,0 +1,43 @@
+name: package:graphs
+
+permissions: read-all
+
+on:
+ # Run CI on all PRs (against any branch) and on pushes to the main branch.
+ pull_request:
+ paths:
+ - '.github/workflows/graphs.yml'
+ - 'pkgs/graphs/**'
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/graphs.yml'
+ - 'pkgs/graphs/**'
+ schedule:
+ - cron: '0 0 * * 0' # weekly
+
+defaults:
+ run:
+ working-directory: pkgs/graphs
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [stable, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+
+ - run: dart pub get
+
+ - run: dart analyze --fatal-infos
+
+ - run: dart format --output=none --set-exit-if-changed .
+ if: ${{ matrix.sdk == 'stable' }}
+
+ - run: dart test
diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml
new file mode 100644
index 0000000..f258f8b
--- /dev/null
+++ b/.github/workflows/health.yaml
@@ -0,0 +1,14 @@
+name: Health
+on:
+ pull_request:
+ branches: [ main ]
+ types: [opened, synchronize, reopened, labeled, unlabeled]
+
+jobs:
+ health:
+ uses: dart-lang/ecosystem/.github/workflows/health.yaml@main
+ with:
+ ignore_coverage: "**.mock.dart,**.g.dart"
+ ignore_license: "**.mock.dart,**.g.dart,**.mocks.dart"
+ permissions:
+ pull-requests: write
diff --git a/.github/workflows/html.yaml b/.github/workflows/html.yaml
new file mode 100644
index 0000000..e4eb9fa
--- /dev/null
+++ b/.github/workflows/html.yaml
@@ -0,0 +1,61 @@
+name: package:html
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/html.yml'
+ - 'pkgs/html/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/html.yml'
+ - 'pkgs/html/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/html/
+
+jobs:
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: dev
+ - id: install
+ run: dart pub get
+ - run: dart format --output=none --set-exit-if-changed .
+ if: steps.install.outcome == 'success'
+ - run: dart analyze --fatal-infos
+ if: steps.install.outcome == 'success'
+
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest]
+ sdk: [3.2, stable, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ run: dart pub get
+ - run: dart test --platform vm
+ if: steps.install.outcome == 'success'
+ - run: dart test --platform chrome
+ if: steps.install.outcome == 'success'
diff --git a/.github/workflows/io.yaml b/.github/workflows/io.yaml
new file mode 100644
index 0000000..0c719a6
--- /dev/null
+++ b/.github/workflows/io.yaml
@@ -0,0 +1,72 @@
+name: package:io
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/io.yml'
+ - 'pkgs/io/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/io.yml'
+ - 'pkgs/io/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/io/
+
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev and stable.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev, 3.4]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev, stable
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [dev, 3.4]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - run: dart test
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/json_rpc_2.yaml b/.github/workflows/json_rpc_2.yaml
new file mode 100644
index 0000000..c5b0883
--- /dev/null
+++ b/.github/workflows/json_rpc_2.yaml
@@ -0,0 +1,75 @@
+name: package:json_rpc_2
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/json_rpc_2.yml'
+ - 'pkgs/json_rpc_2/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/json_rpc_2.yml'
+ - 'pkgs/json_rpc_2/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/json_rpc_2/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.4, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run browser tests
+ run: dart test --platform chrome --compiler dart2wasm,dart2js
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/mime.yml b/.github/workflows/mime.yml
new file mode 100644
index 0000000..44dbf82
--- /dev/null
+++ b/.github/workflows/mime.yml
@@ -0,0 +1,45 @@
+name: Dart CI
+
+on:
+ schedule:
+ # “At 00:00 (UTC) on Sunday.”
+ - cron: '0 0 * * 0'
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/mime.yml'
+ - 'pkgs/mime/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/mime.yml'
+ - 'pkgs/mime/**'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: pkgs/mime/
+
+ strategy:
+ matrix:
+ os: [ubuntu-latest]
+ sdk: [3.2, dev]
+ steps:
+ # These are the latest versions of the github actions; dependabot will
+ # send PRs to keep these up-to-date.
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+
+ - name: Install dependencies
+ run: dart pub get
+
+ - name: Verify formatting
+ run: dart format --output=none --set-exit-if-changed .
+
+ - name: Analyze project source
+ run: dart analyze --fatal-infos
+
+ - name: Run tests
+ run: dart test
diff --git a/.github/workflows/no-response.yml b/.github/workflows/no-response.yml
new file mode 100644
index 0000000..ab1ac49
--- /dev/null
+++ b/.github/workflows/no-response.yml
@@ -0,0 +1,37 @@
+# A workflow to close issues where the author hasn't responded to a request for
+# more information; see https://github.com/actions/stale.
+
+name: No Response
+
+# Run as a daily cron.
+on:
+ schedule:
+ # Every day at 8am
+ - cron: '0 8 * * *'
+
+# All permissions not specified are set to 'none'.
+permissions:
+ issues: write
+ pull-requests: write
+
+jobs:
+ no-response:
+ runs-on: ubuntu-latest
+ if: ${{ github.repository_owner == 'dart-lang' }}
+ steps:
+ - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e
+ with:
+ # Don't automatically mark inactive issues+PRs as stale.
+ days-before-stale: -1
+ # Close needs-info issues and PRs after 14 days of inactivity.
+ days-before-close: 14
+ stale-issue-label: "needs-info"
+ close-issue-message: >
+ Without additional information we're not able to resolve this issue.
+ Feel free to add more info or respond to any questions above and we
+ can reopen the case. Thanks for your contribution!
+ stale-pr-label: "needs-info"
+ close-pr-message: >
+ Without additional information we're not able to resolve this PR.
+ Feel free to add more info or respond to any questions above.
+ Thanks for your contribution!
diff --git a/.github/workflows/oauth2.yml b/.github/workflows/oauth2.yml
new file mode 100644
index 0000000..0485646
--- /dev/null
+++ b/.github/workflows/oauth2.yml
@@ -0,0 +1,79 @@
+name: Dart CI
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/oauth2.yml'
+ - 'pkgs/oauth2/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/oauth2.yml'
+ - 'pkgs/oauth2/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+jobs:
+ # Check code formatting and lints against Dart dev, check analyzer warnings
+ # against the oldest supported SDK.
+ analyze:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: pkgs/oauth2/
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: matrix.sdk == 'dev' && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: matrix.sdk == 'dev' && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze
+ if: matrix.sdk != 'dev' && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ defaults:
+ run:
+ working-directory: pkgs/oauth2/
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.4, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests
+ run: dart test --platform chrome
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/package_config.yaml b/.github/workflows/package_config.yaml
new file mode 100644
index 0000000..416ea1a
--- /dev/null
+++ b/.github/workflows/package_config.yaml
@@ -0,0 +1,71 @@
+name: package:package_config
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/package_config.yml'
+ - 'pkgs/package_config/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/package_config.yml'
+ - 'pkgs/package_config/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/package_config/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, windows-latest]
+ sdk: [3.4, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run tests
+ run: dart test -p chrome,vm
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/pool.yaml b/.github/workflows/pool.yaml
new file mode 100644
index 0000000..6d64062
--- /dev/null
+++ b/.github/workflows/pool.yaml
@@ -0,0 +1,78 @@
+name: package:pool
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/pool.yaml'
+ - 'pkgs/pool/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/pool.yaml'
+ - 'pkgs/pool/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/pool/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.4, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests
+ run: dart test --platform chrome
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests - wasm
+ run: dart test --platform chrome -c dart2wasm
+ if: always() && steps.install.outcome == 'success' && matrix.sdk == 'dev'
diff --git a/.github/workflows/post_summaries.yaml b/.github/workflows/post_summaries.yaml
new file mode 100644
index 0000000..f5c8be8
--- /dev/null
+++ b/.github/workflows/post_summaries.yaml
@@ -0,0 +1,17 @@
+name: Comment on the pull request
+
+on:
+ # Trigger this workflow after the Health workflow completes. This workflow will have permissions to
+ # do things like create comments on the PR, even if the original workflow couldn't.
+ workflow_run:
+ workflows:
+ - Publish
+ - Health
+ types:
+ - completed
+
+jobs:
+ upload:
+ uses: dart-lang/ecosystem/.github/workflows/post_summaries.yaml@main
+ permissions:
+ pull-requests: write
diff --git a/.github/workflows/pub_semver.yaml b/.github/workflows/pub_semver.yaml
new file mode 100644
index 0000000..ba0db18
--- /dev/null
+++ b/.github/workflows/pub_semver.yaml
@@ -0,0 +1,75 @@
+name: package:pub_semver
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/pub_semver.yaml'
+ - 'pkgs/pub_semver/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/pub_semver.yaml'
+ - 'pkgs/pub_semver/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/pub_semver/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.4, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests
+ run: dart test --platform chrome --compiler dart2js,dart2wasm
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
new file mode 100644
index 0000000..2ec45aa
--- /dev/null
+++ b/.github/workflows/publish.yaml
@@ -0,0 +1,16 @@
+# A CI configuration to auto-publish pub packages.
+
+name: Publish
+
+on:
+ pull_request:
+ branches: [ main ]
+ push:
+ tags: [ '[A-z]+-v[0-9]+.[0-9]+.[0-9]+' ]
+
+jobs:
+ publish:
+ if: ${{ github.repository_owner == 'dart-lang' }}
+ uses: dart-lang/ecosystem/.github/workflows/publish.yaml@main
+ with:
+ write-comments: false
diff --git a/.github/workflows/pull_request_label.yml b/.github/workflows/pull_request_label.yml
new file mode 100644
index 0000000..54e3df5
--- /dev/null
+++ b/.github/workflows/pull_request_label.yml
@@ -0,0 +1,22 @@
+# This workflow applies labels to pull requests based on the paths that are
+# modified in the pull request.
+#
+# Edit `.github/labeler.yml` to configure labels. For more information, see
+# https://github.com/actions/labeler.
+
+name: Pull Request Labeler
+permissions: read-all
+
+on:
+ pull_request_target
+
+jobs:
+ label:
+ permissions:
+ pull-requests: write
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9
+ with:
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ sync-labels: true
diff --git a/.github/workflows/source_map_stack_trace.yml b/.github/workflows/source_map_stack_trace.yml
new file mode 100644
index 0000000..11d0b10
--- /dev/null
+++ b/.github/workflows/source_map_stack_trace.yml
@@ -0,0 +1,76 @@
+name: Dart CI
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/source_map_stack_trace.yml'
+ - 'pkgs/source_map_stack_trace/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/source_map_stack_trace.yml'
+ - 'pkgs/source_map_stack_trace/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: pkgs/source_map_stack_trace/
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ defaults:
+ run:
+ working-directory: pkgs/source_map_stack_trace/
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.3, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests
+ run: dart test --platform chrome
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/source_maps.yaml b/.github/workflows/source_maps.yaml
new file mode 100644
index 0000000..2ae0f20
--- /dev/null
+++ b/.github/workflows/source_maps.yaml
@@ -0,0 +1,72 @@
+name: package:source_maps
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/source_maps.yaml'
+ - 'pkgs/source_maps/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/source_maps.yaml'
+ - 'pkgs/source_maps/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/source_maps/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.3.0, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/source_span.yaml b/.github/workflows/source_span.yaml
new file mode 100644
index 0000000..2c2ba05
--- /dev/null
+++ b/.github/workflows/source_span.yaml
@@ -0,0 +1,75 @@
+name: package:source_span
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/source_span.yml'
+ - 'pkgs/source_span/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/source_span.yml'
+ - 'pkgs/source_span/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/source_span/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.1.0, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+ - name: Run Chrome tests
+ run: dart test --platform chrome
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/sse.yaml b/.github/workflows/sse.yaml
new file mode 100644
index 0000000..9e2f212
--- /dev/null
+++ b/.github/workflows/sse.yaml
@@ -0,0 +1,73 @@
+name: package:sse
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/sse.yaml'
+ - 'pkgs/sse/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/sse.yaml'
+ - 'pkgs/sse/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/sse/
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.3, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - uses: nanasess/setup-chromedriver@42cc2998329f041de87dc3cfa33a930eacd57eaa
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm --test-randomize-ordering-seed=random -j 1
+ if: always() && steps.install.outcome == 'success'
diff --git a/.github/workflows/unified_analytics.yml b/.github/workflows/unified_analytics.yml
new file mode 100644
index 0000000..f3b3bf4
--- /dev/null
+++ b/.github/workflows/unified_analytics.yml
@@ -0,0 +1,43 @@
+name: package:unified_analytics
+permissions: read-all
+
+on:
+ pull_request:
+ paths:
+ - '.github/workflows/unified_analytics.yml'
+ - 'pkgs/unified_analytics/**'
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/unified_analytics.yml'
+ - 'pkgs/unified_analytics/**'
+ schedule:
+ - cron: '0 0 * * 0' # weekly
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: pkgs/unified_analytics
+ strategy:
+ matrix:
+ sdk: [stable, dev] # {pkgs.versions}
+ include:
+ - sdk: stable
+ run-tests: true
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{matrix.sdk}}
+
+ - run: dart pub get
+
+ - run: dart analyze --fatal-infos
+
+ - run: dart format --output=none --set-exit-if-changed .
+ if: ${{matrix.run-tests}}
+
+ - run: dart test
+ if: ${{matrix.run-tests}}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5509140
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.DS_Store
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 0000000..7694822
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1,5 @@
+# The CODEOWNERS file helps to define individuals or teams that responsible
+# for code within the repository
+# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
+
+/pkgs/unified_analytics/ @andrewkolos
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..3c28563
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,51 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement (CLA). You (or your employer) retain the copyright to your
+contribution; this simply gives us permission to use and redistribute your
+contributions as part of the project. Head over to
+<https://cla.developers.google.com/> to see your current agreements on file or
+to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code Reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult
+[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
+information on using pull requests.
+
+## Coding style
+
+The Dart source code in this repo follows the:
+
+ * [Dart style guide](https://dart.dev/guides/language/effective-dart/style)
+
+You should familiarize yourself with those guidelines.
+
+## File headers
+
+All files in the Dart project must start with the following header; if you add a
+new file please also add this. The year should be a single number stating the
+year the file was created (don't use a range like "2011-2012"). Additionally, if
+you edit an existing file, you shouldn't update the year.
+
+ // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+ // for details. All rights reserved. Use of this source code is governed by a
+ // BSD-style license that can be found in the LICENSE file.
+
+## Community Guidelines
+
+This project follows
+[Google's Open Source Community Guidelines](https://opensource.google/conduct/).
+
+We pledge to maintain an open and welcoming environment. For details, see our
+[code of conduct](https://dart.dev/code-of-conduct).
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4fd5739
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2023, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..79d1dde
--- /dev/null
+++ b/README.md
@@ -0,0 +1,51 @@
+<!-- [](https://github.com/dart-lang/tools/actions/workflows/dart.yml) -->
+
+## Overview
+
+This repository is home to tooling related Dart packages. Generally, this means
+packages published through the
+[tools.dart.dev](https://pub.dev/publishers/tools.dart.dev) publisher that
+don't naturally belong to other topic monorepos (like
+[dart-lang/build](https://github.com/dart-lang/build),
+[dart-lang/test](https://github.com/dart-lang/test), or
+[dart-lang/shelf](https://github.com/dart-lang/shelf)).
+
+## Packages
+
+| Package | Description | Issues | Version |
+| --- | --- | --- | --- |
+| [bazel_worker](pkgs/bazel_worker/) | Protocol and utilities to implement or invoke persistent bazel workers. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Abazel_worker) | [](https://pub.dev/packages/bazel_worker) |
+| [benchmark_harness](pkgs/benchmark_harness/) | The official Dart project benchmark harness. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Abenchmark_harness) | [](https://pub.dev/packages/benchmark_harness) |
+| [boolean_selector](pkgs/boolean_selector/) | A flexible syntax for boolean expressions, based on a simplified version of Dart's expression syntax. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aboolean_selector) | [](https://pub.dev/packages/boolean_selector) |
+| [browser_launcher](pkgs/browser_launcher/) | Provides a standardized way to launch web browsers for testing and tools. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Abrowser_launcher) | [](https://pub.dev/packages/browser_launcher) |
+| [cli_config](pkgs/cli_config/) | A library to take config values from configuration files, CLI arguments, and environment variables. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acli_config) | [](https://pub.dev/packages/cli_config) |
+| [cli_util](pkgs/cli_util/) | A library to help in building Dart command-line apps. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acli_util) | [](https://pub.dev/packages/cli_util) |
+| [clock](pkgs/clock/) | A fakeable wrapper for dart:core clock APIs. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aclock) | [](https://pub.dev/packages/clock) |
+| [code_builder](pkgs/code_builder/) | A fluent, builder-based library for generating valid Dart code. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acode_builder) | [](https://pub.dev/packages/code_builder) |
+| [coverage](pkgs/coverage/) | Coverage data manipulation and formatting | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acoverage) | [](https://pub.dev/packages/coverage) |
+| [csslib](pkgs/csslib/) | A library for parsing and analyzing CSS (Cascading Style Sheets). | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acsslib) | [](https://pub.dev/packages/csslib) |
+| [extension_discovery](pkgs/extension_discovery/) | A convention and utilities for package extension discovery. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aextension_discovery) | [](https://pub.dev/packages/extension_discovery) |
+| [file](pkgs/file/) | A pluggable, mockable file system abstraction for Dart. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Afile) | [](https://pub.dev/packages/file) |
+| [file_testing](pkgs/file_testing/) | Testing utilities for package:file. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Afile_testing) | [](https://pub.dev/packages/file_testing) |
+| [graphs](pkgs/graphs/) | Graph algorithms that operate on graphs in any representation. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Agraphs) | [](https://pub.dev/packages/graphs) |
+| [html](pkgs/html/) | APIs for parsing and manipulating HTML content outside the browser. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ahtml) | [](https://pub.dev/packages/html) |
+| [io](pkgs/io/) | Utilities for the Dart VM Runtime including support for ANSI colors, file copying, and standard exit code values. | [](https://pub.dev/packages/io) |
+| [json_rpc_2](pkgs/json_rpc_2/) | Utilities to write a client or server using the JSON-RPC 2.0 spec. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ajson_rpc_2) | [](https://pub.dev/packages/json_rpc_2) |
+| [mime](pkgs/mime/) | Utilities for handling media (MIME) types, including determining a type from a file extension and file contents. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Amime) | [](https://pub.dev/packages/mime) |
+| [oauth2](pkgs/oauth2/) | A client library for authenticating with a remote service via OAuth2 on behalf of a user, and making authorized HTTP requests with the user's OAuth2 credentials. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aoauth2) | [](https://pub.dev/packages/oauth2) |
+| [package_config](pkgs/package_config/) | Support for reading and writing Dart Package Configuration files. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Apackage_config) | [](https://pub.dev/packages/package_config) |
+| [pool](pkgs/pool/) | Manage a finite pool of resources. Useful for controlling concurrent file system or network requests. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Apool) | [](https://pub.dev/packages/pool) |
+| [pub_semver](pkgs/pub_semver/) | Versions and version constraints implementing pub's versioning policy. This is very similar to vanilla semver, with a few corner cases. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Apub_semver) | [](https://pub.dev/packages/pub_semver) |
+| [source_map_stack_trace](pkgs/source_map_stack_trace/) | A package for applying source maps to stack traces. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_map_stack_trace) | [](https://pub.dev/packages/source_map_stack_trace) |
+| [source_maps](pkgs/source_maps/) | A library to programmatically manipulate source map files. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_maps) | [](https://pub.dev/packages/source_maps) |
+| [source_span](pkgs/source_span/) | Provides a standard representation for source code locations and spans. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_span) | [](https://pub.dev/packages/source_span) |
+| [sse](pkgs/sse/) | Provides client and server functionality for setting up bi-directional communication through Server Sent Events (SSE) and corresponding POST requests. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asse) | [](https://pub.dev/packages/sse) |
+| [unified_analytics](pkgs/unified_analytics/) | A package for logging analytics for all Dart and Flutter related tooling to Google Analytics. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aunified_analytics) | [](https://pub.dev/packages/unified_analytics) |
+
+## Publishing automation
+
+For information about our publishing automation and release process, see
+https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.
+
+For additional information about contributing, see our
+[contributing](CONTRIBUTING.md) page.
diff --git a/pkgs/bazel_worker/.gitignore b/pkgs/bazel_worker/.gitignore
new file mode 100644
index 0000000..00035d7
--- /dev/null
+++ b/pkgs/bazel_worker/.gitignore
@@ -0,0 +1,10 @@
+.buildlog
+.DS_Store
+.idea
+.pub/
+.settings/
+build/
+packages
+.packages
+pubspec.lock
+.dart_tool
diff --git a/pkgs/bazel_worker/AUTHORS b/pkgs/bazel_worker/AUTHORS
new file mode 100644
index 0000000..e8063a8
--- /dev/null
+++ b/pkgs/bazel_worker/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/bazel_worker/CHANGELOG.md b/pkgs/bazel_worker/CHANGELOG.md
new file mode 100644
index 0000000..d74d967
--- /dev/null
+++ b/pkgs/bazel_worker/CHANGELOG.md
@@ -0,0 +1,193 @@
+## 1.1.3-wip
+
+* Require Dart SDK `^3.4.0`.
+
+## 1.1.2
+
+* Require Dart SDK `^3.1.0`.
+* Move to `dart-lang/tools` monorepo.
+
+## 1.1.1
+
+* Fix a bug where if spawnWorker threw an error, work requests would hang
+ forever instead of failing.
+
+## 1.1.0
+
+* Add constructors with named parameters to
+ the generated worker protocol messages.
+* Include comments on the generated worker protocol API.
+
+## 1.0.3
+
+* Require `package:protobuf` >= 3.0.0.
+* Require Dart SDK >= 2.19.0
+
+## 1.0.2
+
+* Expand pub documentation to improve pub score.
+
+## 1.0.1
+
+* Require Dart SDK >=2.14.0
+* Drop dependency on `package:pedantic`.
+
+## 1.0.0
+
+* Improve `AsyncMessageGrouper` performance.
+* Add `benchmark/benchmark.dart` measuring `AsyncMessageGrouper` performance.
+
+## 1.0.0-nullsafety.0
+
+* Migrate to null safety.
+* Use `WorkResponse` with `exitCode` set to `EXIT_CODE_BROKEN_PIPE` instead of
+ `null` responses.
+
+## 0.1.25+1-dev
+
+* Regenerate proto code and fix some new analysis hints.
+
+## 0.1.25
+
+* Add `isBroadcast` implementation to `TestStdin` classes.
+
+## 0.1.24
+
+* Check for closed port when trying to read a response in
+ `IsolateDriverConnection` and return `null` if there is nothing to be read.
+
+## 0.1.23+1
+
+* Don't rely on `exitCode` to know when a worker terminates, instead wait for
+ the input stream to close.
+ * The SDK may also start throwing instead of returning a `null` here, so this
+ pre-emptively guards against that.
+
+## 0.1.23
+
+* Support protobuf `1.x`.
+* Added a tool for updating generated proto files and updated them
+ using the latest version of the protoc_plugin package.
+ * This required a lower bound bump of the `protobuf` package to `0.14.4`.
+
+## 0.1.22
+
+* Require protobuf 0.14.0.
+
+## 0.1.21+1
+
+* Don't rely on `exitCode` to know when a worker terminates, instead wait for
+ the input stream to close. Backport of fix in `0.1.23+1` in a version that
+ does not require a newer protobuf.
+
+## 0.1.21
+
+* Make `TestStdinAsync` behave like a `Stream<Uint8List>`
+
+## 0.1.20
+
+* Close worker `outputStream` on `cancel`.
+
+## 0.1.19
+
+* Work around https://github.com/dart-lang/sdk/issues/35874.
+
+## 0.1.18
+
+* Add a `trackWork` optional named argument to `BazelDriver.doWork`. This allows
+ the caller to know when a work request is actually sent to a worker.
+
+## 0.1.17
+
+* Allow protobuf 0.13.0.
+
+## 0.1.16
+
+* Update the worker_protocol.pb.dart file with the latest proto generator.
+* Require protobuf 0.11.0.
+
+## 0.1.15
+
+* Update the worker_protocol.pb.dart file with the latest proto generator.
+* Require protobuf 0.10.4.
+
+## 0.1.14
+
+* Allow workers to support running in isolates. To support running in isolates,
+ workers must modify their `main` method to accept a `SendPort` then use it
+ when creating the `AsyncWorkerConnection`. See `async_worker` in `e2e_test`.
+
+## 0.1.13
+
+* Support protobuf 0.10.0.
+
+## 0.1.12
+
+* Set max SDK version to `<3.0.0`.
+
+## 0.1.11
+
+* Added support for protobuf 0.9.0.
+
+## 0.1.10
+
+* Update the SDK dependency to 2.0.0-dev.17.0.
+* Update to protobuf version 0.8.0
+* Remove usages of deprecated upper-case constants from the SDK.
+
+## 0.1.9
+
+* Update the worker_protocol.pb.dart file with the latest proto generator.
+
+## 0.1.8
+
+* Add `Future cancel()` method to `DriverConnection`, which in the case of a
+ `StdDriverConnection` closes the input stream.
+ * The `terminateWorkers` method on `BazelWorkerDriver` now calls `cancel` on
+ all worker connections to ensure the vm can exit correctly.
+
+## 0.1.7
+
+* Update the `BazelWorkerDriver` class to handle worker crashes, and retry work
+ requests. The number of retries is configurable with the new `int maxRetries`
+ optional arg to the `BazelWorkerDriver` constructor.
+
+## 0.1.6
+
+* Update the worker_protocol.pb.dart file with the latest proto generator.
+* Add support for package:async 2.x and package:protobuf 6.x.
+
+## 0.1.5
+
+* Change TestStdinAsync.controller to StreamController<List<int>> (instead of
+ using dynamic as the type argument).
+
+## 0.1.4
+
+* Added `BazelWorkerDriver` class, which can be used to implement the bazel side
+ of the protocol. This allows you to speak to any process which knows the bazel
+ protocol from your own process.
+* Changed `WorkerConnection#readRequest` to return a `FutureOr<WorkRequest>`
+ instead of dynamic.
+
+## 0.1.3
+
+* Add automatic intercepting of print calls and append them to
+ `response.output`. This makes more libraries work out of the box, as printing
+ would previously cause an error due to communication over stdin/stdout.
+ * Note that using stdin/stdout directly will still cause an error, but that is
+ less common.
+
+## 0.1.2
+
+* Add better handling for the case where stdin gives an error instead of an EOF.
+
+## 0.1.1
+
+* Export `AsyncMessageGrouper` and `SyncMessageGrouper` as part of the testing
+ library. These can assist when writing e2e tests and communicating with a
+ worker process.
+
+## 0.1.0
+
+* Initial version.
diff --git a/pkgs/bazel_worker/LICENSE b/pkgs/bazel_worker/LICENSE
new file mode 100644
index 0000000..2372431
--- /dev/null
+++ b/pkgs/bazel_worker/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2016, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/bazel_worker/README.md b/pkgs/bazel_worker/README.md
new file mode 100644
index 0000000..22a86dc
--- /dev/null
+++ b/pkgs/bazel_worker/README.md
@@ -0,0 +1,66 @@
+Tools for creating a persistent worker loop for [bazel](https://bazel.build/).
+
+## Usage
+
+There are two abstract classes provided by this package, `AsyncWorkerLoop` and
+`SyncWorkerLoop`. These each have a `performRequest` method which you must
+implement.
+
+Lets look at a simple example of a `SyncWorkerLoop` implementation:
+
+```dart
+import 'dart:io';
+import 'package:bazel_worker/bazel_worker.dart';
+
+void main() {
+ // Blocks until it gets an EOF from stdin.
+ SyncSimpleWorker().run();
+}
+
+class SyncSimpleWorker extends SyncWorkerLoop {
+ /// Must synchronously return a [WorkResponse], since this is a
+ /// [SyncWorkerLoop].
+ WorkResponse performRequest(WorkRequest request) {
+ File('hello.txt').writeAsStringSync('hello world!');
+ return WorkResponse()..exitCode = EXIT_CODE_OK;
+ }
+}
+```
+
+And now the same thing, implemented as an `AsyncWorkerLoop`:
+
+```dart
+import 'dart:io';
+import 'package:bazel_worker/bazel_worker.dart';
+
+void main() {
+ // Doesn't block, runs tasks async as they are received on stdin.
+ AsyncSimpleWorker().run();
+}
+
+class AsyncSimpleWorker extends AsyncWorkerLoop {
+ /// Must return a [Future<WorkResponse>], since this is an
+ /// [AsyncWorkerLoop].
+ Future<WorkResponse> performRequest(WorkRequest request) async {
+ await File('hello.txt').writeAsString('hello world!');
+ return WorkResponse()..exitCode = EXIT_CODE_OK;
+ }
+}
+```
+
+As you can see, these are nearly identical, it mostly comes down to the
+constraints on your package and personal preference which one you choose to
+implement.
+
+## Testing
+
+A `package:bazel_worker/testing.dart` file is also provided, which can greatly
+assist with writing unit tests for your worker. See the
+`test/worker_loop_test.dart` test included in this package for an example of how
+the helpers can be used.
+
+## Features and bugs
+
+Please file feature requests and bugs at the [issue tracker][tracker].
+
+[tracker]: https://github.com/dart-lang/tools/issues
diff --git a/pkgs/bazel_worker/analysis_options.yaml b/pkgs/bazel_worker/analysis_options.yaml
new file mode 100644
index 0000000..2648764
--- /dev/null
+++ b/pkgs/bazel_worker/analysis_options.yaml
@@ -0,0 +1,9 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ errors:
+ # For the generated file
+ lines_longer_than_80_chars: ignore
diff --git a/pkgs/bazel_worker/benchmark/benchmark.dart b/pkgs/bazel_worker/benchmark/benchmark.dart
new file mode 100644
index 0000000..035e2b8
--- /dev/null
+++ b/pkgs/bazel_worker/benchmark/benchmark.dart
@@ -0,0 +1,57 @@
+import 'dart:math';
+import 'dart:typed_data';
+
+import 'package:bazel_worker/bazel_worker.dart';
+import 'package:bazel_worker/src/async_message_grouper.dart';
+
+/// Benchmark for `AsyncMessageGrouper`.
+Future<void> main() async {
+ // Create a large work request with 10,000 inputs.
+ var workRequest = WorkRequest();
+ for (var i = 0; i != 10000; ++i) {
+ var path = 'blaze-bin/some/path/to/a/file/that/is/an/input/$i';
+ workRequest
+ ..arguments.add('--input=$path')
+ ..inputs.add(Input(
+ path: '',
+ digest: List.filled(70, 0x11),
+ ));
+ }
+
+ // Serialize it.
+ var requestBytes = workRequest.writeToBuffer();
+ var length = requestBytes.length;
+ print('Request has $length requestBytes.');
+
+ // Add the length in front base 128 encoded as in the worker protocol.
+ requestBytes =
+ Uint8List.fromList(requestBytes.toList()..insertAll(0, _varInt(length)));
+
+ // Split into 10000 byte chunks.
+ var lists = <Uint8List>[];
+ for (var i = 0; i < requestBytes.length; i += 10000) {
+ lists.add(Uint8List.sublistView(
+ requestBytes, i, min(i + 10000, requestBytes.length)));
+ }
+
+ // Time `AsyncMessageGrouper` and deserialization.
+ for (var i = 0; i != 30; ++i) {
+ var stopwatch = Stopwatch()..start();
+ var asyncGrouper = AsyncMessageGrouper(Stream.fromIterable(lists));
+ var message = (await asyncGrouper.next)!;
+ print('Grouped in ${stopwatch.elapsedMilliseconds}ms');
+ stopwatch.reset();
+ WorkRequest.fromBuffer(message);
+ print('Deserialized in ${stopwatch.elapsedMilliseconds}ms');
+ }
+}
+
+Uint8List _varInt(int value) {
+ var result = <int>[];
+ while (value >= 0x80) {
+ result.add(0x80 | (value & 0x7f));
+ value >>= 7;
+ }
+ result.add(value);
+ return Uint8List.fromList(result);
+}
diff --git a/pkgs/bazel_worker/e2e_test/analysis_options.yaml b/pkgs/bazel_worker/e2e_test/analysis_options.yaml
new file mode 120000
index 0000000..c9e0d9f
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/analysis_options.yaml
@@ -0,0 +1 @@
+../analysis_options.yaml
\ No newline at end of file
diff --git a/pkgs/bazel_worker/e2e_test/bin/async_worker.dart b/pkgs/bazel_worker/e2e_test/bin/async_worker.dart
new file mode 100644
index 0000000..80d624f
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/bin/async_worker.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:e2e_test/async_worker.dart';
+
+/// This worker can run in one of two ways: normally, using stdin/stdout, or
+/// in an isolate, communicating over a [SendPort].
+Future main(List<String> args, [SendPort? sendPort]) async {
+ await ExampleAsyncWorker(sendPort).run();
+}
diff --git a/pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart b/pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart
new file mode 100644
index 0000000..a94875d
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:e2e_test/forwards_to_isolate_async_worker.dart';
+
+/// Wraps the worker provided by `async_worker.dart`, launching it in an
+/// isolate. Requests are forwarded to the isolate and responses are returned
+/// directly from the isolate.
+///
+/// Anyone actually using the facility to wrap a worker in an isolate will want
+/// to use this code to do additional work, for example post processing one of
+/// the output files.
+Future main(List<String> args, [SendPort? message]) async {
+ var receivePort = ReceivePort();
+ await Isolate.spawnUri(
+ Uri.file('async_worker.dart'), [], receivePort.sendPort);
+
+ var worker = await ForwardsToIsolateAsyncWorker.create(receivePort);
+ await worker.run();
+}
diff --git a/pkgs/bazel_worker/e2e_test/bin/sync_worker.dart b/pkgs/bazel_worker/e2e_test/bin/sync_worker.dart
new file mode 100644
index 0000000..9bdcc77
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/bin/sync_worker.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:e2e_test/sync_worker.dart';
+
+void main() {
+ ExampleSyncWorker().run();
+}
diff --git a/pkgs/bazel_worker/e2e_test/lib/async_worker.dart b/pkgs/bazel_worker/e2e_test/lib/async_worker.dart
new file mode 100644
index 0000000..d48d87c
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/lib/async_worker.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:bazel_worker/bazel_worker.dart';
+
+/// Example worker that just returns in its response all the arguments passed
+/// separated by newlines.
+class ExampleAsyncWorker extends AsyncWorkerLoop {
+ /// Set [sendPort] to run in an isolate.
+ ExampleAsyncWorker([SendPort? sendPort])
+ : super(connection: AsyncWorkerConnection(sendPort: sendPort));
+
+ @override
+ Future<WorkResponse> performRequest(WorkRequest request) async {
+ return WorkResponse(
+ exitCode: 0,
+ output: request.arguments.join('\n'),
+ );
+ }
+}
diff --git a/pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart b/pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart
new file mode 100644
index 0000000..bb937b2
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:bazel_worker/bazel_worker.dart';
+import 'package:bazel_worker/driver.dart';
+
+/// Example worker that just forwards requests to an isolate.
+class ForwardsToIsolateAsyncWorker extends AsyncWorkerLoop {
+ final IsolateDriverConnection _isolateDriverConnection;
+
+ static Future<ForwardsToIsolateAsyncWorker> create(
+ ReceivePort receivePort) async {
+ return ForwardsToIsolateAsyncWorker(
+ await IsolateDriverConnection.create(receivePort));
+ }
+
+ ForwardsToIsolateAsyncWorker(this._isolateDriverConnection);
+
+ @override
+ Future<WorkResponse> performRequest(WorkRequest request) {
+ _isolateDriverConnection.writeRequest(request);
+ return _isolateDriverConnection.readResponse();
+ }
+}
diff --git a/pkgs/bazel_worker/e2e_test/lib/sync_worker.dart b/pkgs/bazel_worker/e2e_test/lib/sync_worker.dart
new file mode 100644
index 0000000..687ecdd
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/lib/sync_worker.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:bazel_worker/bazel_worker.dart';
+
+/// Example worker that just returns in its response all the arguments passed
+/// separated by newlines.
+class ExampleSyncWorker extends SyncWorkerLoop {
+ @override
+ WorkResponse performRequest(WorkRequest request) {
+ return WorkResponse(exitCode: 0, output: request.arguments.join('\n'));
+ }
+}
diff --git a/pkgs/bazel_worker/e2e_test/pubspec.yaml b/pkgs/bazel_worker/e2e_test/pubspec.yaml
new file mode 100644
index 0000000..56f00cd
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/pubspec.yaml
@@ -0,0 +1,15 @@
+name: e2e_test
+publish_to: none
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ bazel_worker:
+ path: ../
+
+dev_dependencies:
+ cli_util: ^0.4.2
+ dart_flutter_team_lints: ^1.0.0
+ path: ^1.8.0
+ test: ^1.16.0
diff --git a/pkgs/bazel_worker/e2e_test/test/e2e_test.dart b/pkgs/bazel_worker/e2e_test/test/e2e_test.dart
new file mode 100644
index 0000000..caa813a
--- /dev/null
+++ b/pkgs/bazel_worker/e2e_test/test/e2e_test.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:bazel_worker/driver.dart';
+import 'package:cli_util/cli_util.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+
+void main() {
+ var dart = p.join(sdkPath, 'bin', 'dart');
+ runE2eTestForWorker('sync worker',
+ () => Process.start(dart, [p.join('bin', 'sync_worker.dart')]));
+ runE2eTestForWorker('async worker',
+ () => Process.start(dart, [p.join('bin', 'async_worker.dart')]));
+ runE2eTestForWorker(
+ 'async worker in isolate',
+ () =>
+ Process.start(dart, [p.join('bin', 'async_worker_in_isolate.dart')]));
+}
+
+void runE2eTestForWorker(String groupName, SpawnWorker spawnWorker) {
+ late BazelWorkerDriver driver;
+ group(groupName, () {
+ setUp(() {
+ driver = BazelWorkerDriver(spawnWorker);
+ });
+
+ tearDown(() async {
+ await driver.terminateWorkers();
+ });
+
+ test('single work request', () async {
+ await _doRequests(driver, count: 1);
+ });
+
+ test('lots of requests', () async {
+ await _doRequests(driver, count: 1000);
+ });
+ });
+}
+
+/// Runs [count] work requests through [driver], and asserts that they all
+/// completed with the correct response.
+Future _doRequests(BazelWorkerDriver driver, {int? count}) async {
+ count ??= 100;
+ var requests = List.generate(count, (requestNum) {
+ var request = WorkRequest(
+ arguments: List.generate(requestNum, (argNum) => '$argNum'),
+ );
+ return request;
+ });
+ var responses = await Future.wait(requests.map(driver.doWork));
+ for (var i = 0; i < responses.length; i++) {
+ var request = requests[i];
+ var response = responses[i];
+ expect(response.exitCode, EXIT_CODE_OK);
+ expect(response.output, request.arguments.join('\n'));
+ }
+}
diff --git a/pkgs/bazel_worker/example/README.md b/pkgs/bazel_worker/example/README.md
new file mode 100644
index 0000000..dad3b79
--- /dev/null
+++ b/pkgs/bazel_worker/example/README.md
@@ -0,0 +1,3 @@
+Run `dart example/client.dart`. The client will start up a worker process, send
+a single work request, read a file written by the worker, then terminate the
+worker.
diff --git a/pkgs/bazel_worker/example/client.dart b/pkgs/bazel_worker/example/client.dart
new file mode 100644
index 0000000..7147fcb
--- /dev/null
+++ b/pkgs/bazel_worker/example/client.dart
@@ -0,0 +1,22 @@
+import 'dart:io';
+
+import 'package:bazel_worker/driver.dart';
+
+void main() async {
+ var scratchSpace = await Directory.systemTemp.createTemp();
+ var driver = BazelWorkerDriver(
+ () => Process.start(Platform.resolvedExecutable,
+ [Platform.script.resolve('worker.dart').toFilePath()],
+ workingDirectory: scratchSpace.path),
+ maxWorkers: 4);
+ var response = await driver.doWork(WorkRequest(arguments: ['foo']));
+ if (response.exitCode != EXIT_CODE_OK) {
+ print('Worker request failed');
+ } else {
+ print('Worker request succeeded, file content:');
+ var outputFile = File.fromUri(scratchSpace.uri.resolve('hello.txt'));
+ print(await outputFile.readAsString());
+ }
+ await scratchSpace.delete(recursive: true);
+ await driver.terminateWorkers();
+}
diff --git a/pkgs/bazel_worker/example/worker.dart b/pkgs/bazel_worker/example/worker.dart
new file mode 100644
index 0000000..ba3f48c
--- /dev/null
+++ b/pkgs/bazel_worker/example/worker.dart
@@ -0,0 +1,15 @@
+import 'dart:io';
+import 'package:bazel_worker/bazel_worker.dart';
+
+void main() {
+ // Blocks until it gets an EOF from stdin.
+ SyncSimpleWorker().run();
+}
+
+class SyncSimpleWorker extends SyncWorkerLoop {
+ @override
+ WorkResponse performRequest(WorkRequest request) {
+ File('hello.txt').writeAsStringSync(request.arguments.first);
+ return WorkResponse(exitCode: EXIT_CODE_OK);
+ }
+}
diff --git a/pkgs/bazel_worker/lib/bazel_worker.dart b/pkgs/bazel_worker/lib/bazel_worker.dart
new file mode 100644
index 0000000..d77b53f
--- /dev/null
+++ b/pkgs/bazel_worker/lib/bazel_worker.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/constants.dart';
+export 'src/message_grouper.dart';
+export 'src/worker/async_worker_loop.dart';
+export 'src/worker/sync_worker_loop.dart';
+export 'src/worker/worker_connection.dart';
+export 'src/worker/worker_loop.dart';
+export 'src/worker_protocol.pb.dart';
diff --git a/pkgs/bazel_worker/lib/driver.dart b/pkgs/bazel_worker/lib/driver.dart
new file mode 100644
index 0000000..362841c
--- /dev/null
+++ b/pkgs/bazel_worker/lib/driver.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/constants.dart';
+export 'src/driver/driver.dart';
+export 'src/driver/driver_connection.dart';
+export 'src/message_grouper.dart';
+export 'src/worker_protocol.pb.dart';
diff --git a/pkgs/bazel_worker/lib/src/async_message_grouper.dart b/pkgs/bazel_worker/lib/src/async_message_grouper.dart
new file mode 100644
index 0000000..e1f0dea
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/async_message_grouper.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:math';
+import 'dart:typed_data';
+
+import 'package:async/async.dart';
+import 'package:protobuf/protobuf.dart';
+
+import 'message_grouper.dart';
+
+/// Collects stream data into messages by interpreting it as
+/// base-128 encoded lengths interleaved with raw data.
+class AsyncMessageGrouper implements MessageGrouper {
+ /// The input stream.
+ final StreamQueue<List<int>> _inputQueue;
+
+ /// The current input buffer.
+ List<int> _inputBuffer = [];
+
+ /// Position in the current input buffer.
+ int _inputBufferPos = 0;
+
+ /// Completes after [cancel] is called or `inputStream` is closed.
+ Future<void> get done => _done.future;
+ final _done = Completer<void>();
+
+ /// Whether currently reading length or raw data.
+ bool _readingLength = true;
+
+ /// If reading length, buffer to build up length one byte at a time until
+ /// done.
+ List<int> _lengthBuffer = [];
+
+ /// If reading raw data, buffer for the data.
+ Uint8List _message = Uint8List(0);
+
+ /// If reading raw data, position in the buffer.
+ int _messagePos = 0;
+
+ AsyncMessageGrouper(Stream<List<int>> inputStream)
+ : _inputQueue = StreamQueue(inputStream);
+
+ /// Returns the next full message that is received, or null if none are left.
+ @override
+ Future<List<int>?> get next async {
+ try {
+ // Loop while there is data in the input buffer or the input stream.
+ while (
+ _inputBufferPos != _inputBuffer.length || await _inputQueue.hasNext) {
+ // If the input buffer is empty fill it from the input stream.
+ if (_inputBufferPos == _inputBuffer.length) {
+ _inputBuffer = await _inputQueue.next;
+ _inputBufferPos = 0;
+ }
+
+ // Loop over the input buffer. Might return without reading the full
+ // buffer if a message completes. Then, this is tracked in
+ // `_inputBufferPos`.
+ while (_inputBufferPos != _inputBuffer.length) {
+ if (_readingLength) {
+ // Reading message length byte by byte.
+ var byte = _inputBuffer[_inputBufferPos++];
+ _lengthBuffer.add(byte);
+ // Check for the last byte in the length, and then read it.
+ if ((byte & 0x80) == 0) {
+ var reader = CodedBufferReader(_lengthBuffer);
+ var length = reader.readInt32();
+ _lengthBuffer = [];
+
+ // Special case: don't keep reading an empty message, return it
+ // and `_readingLength` stays true.
+ if (length == 0) {
+ return Uint8List(0);
+ }
+
+ // Switch to reading raw data. Allocate message buffer and reset
+ // `_messagePos`.
+ _readingLength = false;
+ _message = Uint8List(length);
+ _messagePos = 0;
+ }
+ } else {
+ // Copy as much as possible from the input buffer. Limit is the
+ // smaller of the remaining length to fill in the message and the
+ // remaining length in the buffer.
+ var lengthToCopy = min(_message.length - _messagePos,
+ _inputBuffer.length - _inputBufferPos);
+ _message.setRange(
+ _messagePos,
+ _messagePos + lengthToCopy,
+ _inputBuffer.sublist(
+ _inputBufferPos, _inputBufferPos + lengthToCopy));
+ _messagePos += lengthToCopy;
+ _inputBufferPos += lengthToCopy;
+
+ // If there is a complete message to return, return it and switch
+ // back to reading length.
+ if (_messagePos == _message.length) {
+ var result = _message;
+ // Don't keep a reference to the message.
+ _message = Uint8List(0);
+ _readingLength = true;
+ return result;
+ }
+ }
+ }
+ }
+
+ // If there is nothing left in the queue then cancel the subscription.
+ unawaited(cancel());
+ } catch (e) {
+ // It appears we sometimes get an exception instead of -1 as expected when
+ // stdin closes, this handles that in the same way (returning a null
+ // message)
+ return null;
+ }
+ return null;
+ }
+
+ /// Stop listening to the stream for further updates.
+ Future cancel() {
+ if (!_done.isCompleted) {
+ _done.complete(null);
+ return _inputQueue.cancel()!;
+ }
+ return done;
+ }
+}
diff --git a/pkgs/bazel_worker/lib/src/constants.dart b/pkgs/bazel_worker/lib/src/constants.dart
new file mode 100644
index 0000000..a6d044a
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/constants.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: constant_identifier_names
+
+const int EXIT_CODE_OK = 0;
+const int EXIT_CODE_ERROR = 15;
+const int EXIT_CODE_BROKEN_PIPE = 32;
diff --git a/pkgs/bazel_worker/lib/src/driver/driver.dart b/pkgs/bazel_worker/lib/src/driver/driver.dart
new file mode 100644
index 0000000..4a78020
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/driver/driver.dart
@@ -0,0 +1,239 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:io';
+
+import '../constants.dart';
+import '../worker_protocol.pb.dart';
+import 'driver_connection.dart';
+
+typedef SpawnWorker = Future<Process> Function();
+
+/// A driver for talking to a bazel worker.
+///
+/// This allows you to use any binary that supports the bazel worker protocol in
+/// the same way that bazel would, but from another dart process instead.
+class BazelWorkerDriver {
+ /// Idle worker processes.
+ final _idleWorkers = <Process>[];
+
+ /// The maximum number of idle workers at any given time.
+ final int _maxIdleWorkers;
+
+ /// The maximum number of times to retry a [_WorkAttempt] if there is an error.
+ final int _maxRetries;
+
+ /// The maximum number of concurrent workers to run at any given time.
+ final int _maxWorkers;
+
+ /// The number of currently active workers.
+ int get _numWorkers => _readyWorkers.length + _spawningWorkers.length;
+
+ /// All workers that are fully spawned and ready to handle work.
+ final _readyWorkers = <Process>[];
+
+ /// All workers that are in the process of being spawned.
+ final _spawningWorkers = <Future<Process>>[];
+
+ /// Work requests that haven't been started yet.
+ final _workQueue = Queue<_WorkAttempt>();
+
+ /// Factory method that spawns a worker process.
+ final SpawnWorker _spawnWorker;
+
+ BazelWorkerDriver(this._spawnWorker,
+ {int? maxIdleWorkers, int? maxWorkers, int? maxRetries})
+ : _maxIdleWorkers = maxIdleWorkers ?? 4,
+ _maxWorkers = maxWorkers ?? 4,
+ _maxRetries = maxRetries ?? 4;
+
+ /// Waits for an available worker, and then sends [WorkRequest] to it.
+ ///
+ /// If [trackWork] is provided it will be invoked with a [Future] once the
+ /// [request] has been actually sent to the worker. This allows the caller
+ /// to determine when actual work is being done versus just waiting for an
+ /// available worker.
+ Future<WorkResponse> doWork(WorkRequest request,
+ {void Function(Future<WorkResponse?>)? trackWork}) {
+ var attempt = _WorkAttempt(request, trackWork: trackWork);
+ _workQueue.add(attempt);
+ _runWorkQueue();
+ return attempt.response;
+ }
+
+ /// Calls `kill` on all worker processes.
+ Future terminateWorkers() async {
+ for (var worker in _readyWorkers.toList()) {
+ _killWorker(worker);
+ }
+ await Future.wait(_spawningWorkers.map((worker) async {
+ _killWorker(await worker);
+ }));
+ }
+
+ /// Runs as many items in [_workQueue] as possible given the number of
+ /// available workers.
+ ///
+ /// Will spawn additional workers until [_maxWorkers] has been reached.
+ ///
+ /// This method synchronously drains the [_workQueue] and [_idleWorkers], but
+ /// some tasks may not actually start right away if they need to wait for a
+ /// worker to spin up.
+ void _runWorkQueue() {
+ // Bail out conditions, we will continue to call ourselves indefinitely
+ // until one of these is met.
+ if (_workQueue.isEmpty) return;
+ if (_numWorkers == _maxWorkers && _idleWorkers.isEmpty) return;
+ if (_numWorkers > _maxWorkers) {
+ throw StateError('Internal error, created to many workers. Please '
+ 'file a bug at https://github.com/dart-lang/bazel_worker/issues/new');
+ }
+
+ // At this point we definitely want to run a task, we just need to decide
+ // whether or not we need to start up a new worker.
+ var attempt = _workQueue.removeFirst();
+ if (_idleWorkers.isNotEmpty) {
+ _runWorker(_idleWorkers.removeLast(), attempt);
+ } else {
+ // No need to block here, we want to continue to synchronously drain the
+ // work queue.
+ var futureWorker = _spawnWorker();
+ _spawningWorkers.add(futureWorker);
+ futureWorker.then((worker) {
+ _spawningWorkers.remove(futureWorker);
+ _readyWorkers.add(worker);
+ var connection = StdDriverConnection.forWorker(worker);
+ _workerConnections[worker] = connection;
+ _runWorker(worker, attempt);
+
+ // When the worker exits we should retry running the work queue in case
+ // there is more work to be done. This is primarily just a defensive
+ // thing but is cheap to do.
+ //
+ // We don't use `exitCode` because it is null for detached processes (
+ // which is common for workers).
+ connection.done.then((_) {
+ _idleWorkers.remove(worker);
+ _readyWorkers.remove(worker);
+ _runWorkQueue();
+ });
+ }).onError<Object>((e, s) {
+ _spawningWorkers.remove(futureWorker);
+ if (attempt.responseCompleter.isCompleted) return;
+ attempt.responseCompleter.completeError(e, s);
+ });
+ }
+ // Recursively calls itself until one of the bail out conditions are met.
+ _runWorkQueue();
+ }
+
+ /// Sends [attempt] to [worker].
+ ///
+ /// Once the worker responds then it will be added back to the pool of idle
+ /// workers.
+ void _runWorker(Process worker, _WorkAttempt attempt) {
+ var rescheduled = false;
+
+ runZonedGuarded(() async {
+ var connection = _workerConnections[worker]!;
+
+ connection.writeRequest(attempt.request);
+ var responseFuture = connection.readResponse();
+ if (attempt.trackWork != null) {
+ attempt.trackWork!(responseFuture);
+ }
+ var response = await responseFuture;
+
+ // It is possible for us to complete with an error response due to an
+ // unhandled async error before we get here.
+ if (!attempt.responseCompleter.isCompleted) {
+ if (response.exitCode == EXIT_CODE_BROKEN_PIPE) {
+ rescheduled = _tryReschedule(attempt);
+ if (rescheduled) return;
+ stderr.writeln('Failed to run request ${attempt.request}');
+ response = WorkResponse(
+ exitCode: EXIT_CODE_ERROR,
+ output:
+ 'Invalid response from worker, this probably means it wrote '
+ 'invalid output or died.',
+ );
+ }
+ attempt.responseCompleter.complete(response);
+ _cleanUp(worker);
+ }
+ }, (e, s) {
+ // Note that we don't need to do additional cleanup here on failures. If
+ // the worker dies that is already handled in a generic fashion, we just
+ // need to make sure we complete with a valid response.
+ if (!attempt.responseCompleter.isCompleted) {
+ rescheduled = _tryReschedule(attempt);
+ if (rescheduled) return;
+ var response = WorkResponse(
+ exitCode: EXIT_CODE_ERROR,
+ output: 'Error running worker:\n$e\n$s',
+ );
+ attempt.responseCompleter.complete(response);
+ _cleanUp(worker);
+ }
+ });
+ }
+
+ /// Performs post-work cleanup for [worker].
+ void _cleanUp(Process worker) {
+ // If the worker crashes, it won't be in `_readyWorkers` any more, and
+ // we don't want to add it to _idleWorkers.
+ if (_readyWorkers.contains(worker)) {
+ _idleWorkers.add(worker);
+ }
+
+ // Do additional work if available.
+ _runWorkQueue();
+
+ // If the worker wasn't immediately used we might have to many idle
+ // workers now, kill one if necessary.
+ if (_idleWorkers.length > _maxIdleWorkers) {
+ // Note that whenever we spawn a worker we listen for its exit code
+ // and clean it up so we don't need to do that here.
+ var worker = _idleWorkers.removeLast();
+ _killWorker(worker);
+ }
+ }
+
+ /// Attempts to reschedule a failed [attempt].
+ ///
+ /// Returns whether or not the job was successfully rescheduled.
+ bool _tryReschedule(_WorkAttempt attempt) {
+ if (attempt.timesRetried >= _maxRetries) return false;
+ stderr.writeln('Rescheduling failed request...');
+ attempt.timesRetried++;
+ _workQueue.add(attempt);
+ _runWorkQueue();
+ return true;
+ }
+
+ void _killWorker(Process worker) {
+ _workerConnections[worker]!.cancel();
+ _readyWorkers.remove(worker);
+ _idleWorkers.remove(worker);
+ worker.kill();
+ }
+}
+
+/// Encapsulates an attempt to fulfill a [WorkRequest], a completer for the
+/// [WorkResponse], and the number of times it has been retried.
+class _WorkAttempt {
+ final WorkRequest request;
+ final responseCompleter = Completer<WorkResponse>();
+ final void Function(Future<WorkResponse?>)? trackWork;
+
+ Future<WorkResponse> get response => responseCompleter.future;
+
+ int timesRetried = 0;
+
+ _WorkAttempt(this.request, {this.trackWork});
+}
+
+final _workerConnections = Expando<DriverConnection>('connection');
diff --git a/pkgs/bazel_worker/lib/src/driver/driver_connection.dart b/pkgs/bazel_worker/lib/src/driver/driver_connection.dart
new file mode 100644
index 0000000..b419deb
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/driver/driver_connection.dart
@@ -0,0 +1,129 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'dart:isolate';
+
+import '../async_message_grouper.dart';
+import '../constants.dart';
+import '../message_grouper.dart';
+import '../utils.dart';
+import '../worker_protocol.pb.dart';
+
+/// A connection from a `BazelWorkerDriver` to a worker.
+///
+/// Unlike `WorkerConnection` there is no synchronous version of this class.
+/// This is because drivers talk to multiple workers, so they should never block
+/// when waiting for the response of any individual worker.
+abstract class DriverConnection {
+ Future<WorkResponse> readResponse();
+
+ void writeRequest(WorkRequest request);
+
+ Future cancel();
+}
+
+/// Default implementation of [DriverConnection] that works with [Stdin]
+/// and [Stdout].
+class StdDriverConnection implements DriverConnection {
+ final AsyncMessageGrouper _messageGrouper;
+ final StreamSink<List<int>> _outputStream;
+
+ Future<void> get done => _messageGrouper.done;
+
+ StdDriverConnection(
+ {Stream<List<int>>? inputStream, StreamSink<List<int>>? outputStream})
+ : _messageGrouper = AsyncMessageGrouper(inputStream ?? stdin),
+ _outputStream = outputStream ?? stdout;
+
+ factory StdDriverConnection.forWorker(Process worker) => StdDriverConnection(
+ inputStream: worker.stdout, outputStream: worker.stdin);
+
+ /// Note: This will attempts to recover from invalid proto messages by parsing
+ /// them as strings. This is a common error case for workers (they print a
+ /// message to stdout on accident). This isn't perfect however as it only
+ /// happens if the parsing throws, you can still hang indefinitely if the
+ /// [MessageGrouper] doesn't find what it thinks is the end of a proto
+ /// message.
+ @override
+ Future<WorkResponse> readResponse() async {
+ var buffer = await _messageGrouper.next;
+ if (buffer == null) {
+ return WorkResponse(
+ exitCode: EXIT_CODE_BROKEN_PIPE,
+ output: 'Connection to worker closed',
+ );
+ }
+
+ WorkResponse response;
+ try {
+ response = WorkResponse.fromBuffer(buffer);
+ } catch (_) {
+ try {
+ // Try parsing the message as a string and set that as the output.
+ var output = utf8.decode(buffer);
+ var response = WorkResponse(
+ exitCode: EXIT_CODE_ERROR,
+ output: 'Worker sent an invalid response:\n$output',
+ );
+ return response;
+ } catch (_) {
+ // Fall back to original exception and rethrow if we fail to parse as
+ // a string.
+ }
+ rethrow;
+ }
+ return response;
+ }
+
+ @override
+ void writeRequest(WorkRequest request) {
+ _outputStream.add(protoToDelimitedBuffer(request));
+ }
+
+ @override
+ Future cancel() async {
+ await _outputStream.close();
+ await _messageGrouper.cancel();
+ }
+}
+
+/// [DriverConnection] that works with an isolate via a [SendPort].
+class IsolateDriverConnection implements DriverConnection {
+ final StreamIterator _receivePortIterator;
+ final SendPort _sendPort;
+
+ IsolateDriverConnection._(this._receivePortIterator, this._sendPort);
+
+ /// Creates a driver connection for a worker in an isolate. Provide the
+ /// [receivePort] attached to the [SendPort] that the isolate was created
+ /// with.
+ static Future<IsolateDriverConnection> create(ReceivePort receivePort) async {
+ var receivePortIterator = StreamIterator(receivePort);
+ await receivePortIterator.moveNext();
+ var sendPort = receivePortIterator.current as SendPort;
+ return IsolateDriverConnection._(receivePortIterator, sendPort);
+ }
+
+ @override
+ Future<WorkResponse> readResponse() async {
+ if (!await _receivePortIterator.moveNext()) {
+ return WorkResponse(
+ exitCode: EXIT_CODE_BROKEN_PIPE,
+ output: 'Connection to worker closed.',
+ );
+ }
+ return WorkResponse.fromBuffer(_receivePortIterator.current as List<int>);
+ }
+
+ @override
+ void writeRequest(WorkRequest request) {
+ _sendPort.send(request.writeToBuffer());
+ }
+
+ @override
+ Future cancel() async {}
+}
diff --git a/pkgs/bazel_worker/lib/src/message_grouper.dart b/pkgs/bazel_worker/lib/src/message_grouper.dart
new file mode 100644
index 0000000..31aa204
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/message_grouper.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'async_message_grouper.dart';
+import 'sync_message_grouper.dart';
+
+/// Interface for a [MessageGrouper], which groups bytes in delimited proto
+/// format into the bytes for each message.
+///
+/// This interface should not generally be implemented directly, instead use
+/// the [SyncMessageGrouper] or [AsyncMessageGrouper] implementations.
+abstract class MessageGrouper {
+ /// Returns either a [List<int>] or a [Future<List<int>>].
+ dynamic get next;
+}
diff --git a/pkgs/bazel_worker/lib/src/message_grouper_state.dart b/pkgs/bazel_worker/lib/src/message_grouper_state.dart
new file mode 100644
index 0000000..2656835
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/message_grouper_state.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+
+import 'package:protobuf/protobuf.dart';
+
+import 'message_grouper.dart';
+
+/// State held by the [MessageGrouper] while waiting for additional data to
+/// arrive.
+class MessageGrouperState {
+ /// Reads the initial length.
+ var _lengthReader = _LengthReader();
+
+ /// Reads messages from a stream of bytes.
+ _MessageReader? _messageReader;
+
+ /// Handle one byte at a time.
+ ///
+ /// Returns a [List<int>] of message bytes if [byte] was the last byte in a
+ /// message, otherwise returns `null`.
+ List<int>? handleInput(int byte) {
+ if (!_lengthReader.done) {
+ _lengthReader.readByte(byte);
+ if (_lengthReader.done) {
+ _messageReader = _MessageReader(_lengthReader.length);
+ }
+ } else {
+ assert(_messageReader != null);
+ _messageReader!.readByte(byte);
+ }
+
+ if (_lengthReader.done && _messageReader!.done) {
+ var message = _messageReader!.message;
+ reset();
+ return message;
+ }
+
+ return null;
+ }
+
+ /// Reset the state so that we are ready to receive the next message.
+ void reset() {
+ _lengthReader = _LengthReader();
+ _messageReader = null;
+ }
+}
+
+/// Reads a length one byte at a time.
+///
+/// The base-128 encoding is in little-endian order, with the high bit set on
+/// all bytes but the last. This was chosen since it's the same as the
+/// base-128 encoding used by protobufs, so it allows a modest amount of code
+/// reuse at the other end of the protocol.
+class _LengthReader {
+ /// Whether or not we are done reading the length.
+ bool get done => _done;
+ bool _done = false;
+
+ /// If [_done] is `true`, the decoded value of the length bytes received so
+ /// far (if any), otherwise unitialized.
+ late int _length;
+
+ /// The length read in. You are only allowed to read this if [_done] is
+ /// `true`.
+ int get length {
+ assert(_done);
+ return _length;
+ }
+
+ final List<int> _buffer = <int>[];
+
+ /// Read a single byte into [_length].
+ void readByte(int byte) {
+ assert(!_done);
+ _buffer.add(byte);
+
+ // Check for the last byte in the length, and then read it.
+ if ((byte & 0x80) == 0) {
+ _done = true;
+ var reader = CodedBufferReader(_buffer);
+ _length = reader.readInt32();
+ }
+ }
+}
+
+/// Reads some number of bytes from a stream, one byte at a time.
+class _MessageReader {
+ /// Whether or not we are done reading bytes from the stream.
+ bool get done => _done;
+ bool _done;
+
+ /// The total length of the message to be read.
+ final int _length;
+
+ /// A [Uint8List] which holds the message data. You are only allowed to read
+ /// this if [_done] is `true`.
+ Uint8List get message {
+ assert(_done);
+ return _message;
+ }
+
+ final Uint8List _message;
+
+ /// If [_done] is `false`, the number of message bytes that have been received
+ /// so far. Otherwise zero.
+ int _numMessageBytesReceived = 0;
+
+ _MessageReader(int length)
+ : _message = Uint8List(length),
+ _length = length,
+ _done = length == 0;
+
+ /// Reads [byte] into [_message].
+ void readByte(int byte) {
+ assert(!done);
+
+ _message[_numMessageBytesReceived++] = byte;
+ if (_numMessageBytesReceived == _length) _done = true;
+ }
+}
diff --git a/pkgs/bazel_worker/lib/src/sync_message_grouper.dart b/pkgs/bazel_worker/lib/src/sync_message_grouper.dart
new file mode 100644
index 0000000..b8f7b36
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/sync_message_grouper.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'message_grouper.dart';
+import 'message_grouper_state.dart';
+
+/// Groups bytes in delimited proto format into the bytes for each message.
+class SyncMessageGrouper implements MessageGrouper {
+ final _state = MessageGrouperState();
+ final Stdin _stdin;
+
+ SyncMessageGrouper(this._stdin);
+
+ /// Blocks until the next full message is received, and then returns it.
+ ///
+ /// Returns null at end of file.
+ @override
+ List<int>? get next {
+ try {
+ List<int>? message;
+ while (message == null) {
+ var nextByte = _stdin.readByteSync();
+ if (nextByte == -1) return null;
+ message = _state.handleInput(nextByte);
+ }
+ return message;
+ } catch (e) {
+ // It appears we sometimes get an exception instead of -1 as expected when
+ // stdin closes, this handles that in the same way (returning a null
+ // message)
+ return null;
+ }
+ }
+}
diff --git a/pkgs/bazel_worker/lib/src/utils.dart b/pkgs/bazel_worker/lib/src/utils.dart
new file mode 100644
index 0000000..609b435
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/utils.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+
+import 'package:protobuf/protobuf.dart';
+
+List<int> protoToDelimitedBuffer(GeneratedMessage message) {
+ var messageBuffer = CodedBufferWriter();
+ message.writeToCodedBufferWriter(messageBuffer);
+
+ var delimiterBuffer = CodedBufferWriter();
+ delimiterBuffer.writeInt32NoTag(messageBuffer.lengthInBytes);
+
+ var result =
+ Uint8List(messageBuffer.lengthInBytes + delimiterBuffer.lengthInBytes);
+
+ delimiterBuffer.writeTo(result);
+ messageBuffer.writeTo(result, delimiterBuffer.lengthInBytes);
+
+ return result;
+}
diff --git a/pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart b/pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart
new file mode 100644
index 0000000..5182b55
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import '../constants.dart';
+import '../worker_protocol.pb.dart';
+import 'worker_connection.dart';
+import 'worker_loop.dart';
+
+/// Persistent Bazel worker loop.
+///
+/// Extend this class and implement the `performRequest` method.
+abstract class AsyncWorkerLoop implements WorkerLoop {
+ final AsyncWorkerConnection connection;
+
+ AsyncWorkerLoop({AsyncWorkerConnection? connection})
+ : connection = connection ?? StdAsyncWorkerConnection();
+
+ /// Perform a single [WorkRequest], and return a [WorkResponse].
+ @override
+ Future<WorkResponse> performRequest(WorkRequest request);
+
+ /// Run the worker loop. The returned [Future] doesn't complete until
+ /// [connection#readRequest] returns `null`.
+ @override
+ Future run() async {
+ while (true) {
+ late WorkResponse response;
+ try {
+ var request = await connection.readRequest();
+ if (request == null) break;
+ var printMessages = StringBuffer();
+ response = await runZoned(() => performRequest(request),
+ zoneSpecification:
+ ZoneSpecification(print: (self, parent, zone, message) {
+ printMessages.writeln();
+ printMessages.write(message);
+ }));
+ if (printMessages.isNotEmpty) {
+ response.output = '${response.output}$printMessages';
+ }
+ } catch (e, s) {
+ response = WorkResponse(
+ exitCode: EXIT_CODE_ERROR,
+ output: '$e\n$s',
+ );
+ }
+
+ connection.writeResponse(response);
+ }
+ }
+}
diff --git a/pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart b/pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart
new file mode 100644
index 0000000..a857105
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
+
+import '../constants.dart';
+import '../worker_protocol.pb.dart';
+import 'worker_connection.dart';
+import 'worker_loop.dart';
+
+/// Persistent Bazel worker loop.
+///
+/// Extend this class and implement the `performRequest` method.
+abstract class SyncWorkerLoop implements WorkerLoop {
+ final SyncWorkerConnection connection;
+
+ SyncWorkerLoop({SyncWorkerConnection? connection})
+ : connection = connection ?? StdSyncWorkerConnection();
+
+ /// Perform a single [WorkRequest], and return a [WorkResponse].
+ @override
+ WorkResponse performRequest(WorkRequest request);
+
+ /// Run the worker loop. Blocks until [connection#readRequest] returns `null`.
+ @override
+ void run() {
+ while (true) {
+ late WorkResponse response;
+ try {
+ var request = connection.readRequest();
+ if (request == null) break;
+ var printMessages = StringBuffer();
+ response = runZoned(() => performRequest(request), zoneSpecification:
+ ZoneSpecification(print: (self, parent, zone, message) {
+ printMessages.writeln();
+ printMessages.write(message);
+ }));
+ if (printMessages.isNotEmpty) {
+ response.output = '${response.output}$printMessages';
+ }
+ } catch (e, s) {
+ response = WorkResponse(
+ exitCode: EXIT_CODE_ERROR,
+ output: '$e\n$s',
+ );
+ }
+
+ connection.writeResponse(response);
+ }
+ }
+}
diff --git a/pkgs/bazel_worker/lib/src/worker/worker_connection.dart b/pkgs/bazel_worker/lib/src/worker/worker_connection.dart
new file mode 100644
index 0000000..b395316
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/worker/worker_connection.dart
@@ -0,0 +1,124 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:typed_data';
+
+import '../async_message_grouper.dart';
+import '../sync_message_grouper.dart';
+import '../utils.dart';
+import '../worker_protocol.pb.dart';
+
+/// A connection from a worker to a driver (driver could be bazel, a dart
+/// program using `BazelWorkerDriver`, or any other process that speaks the
+/// protocol).
+abstract class WorkerConnection {
+ /// Reads a [WorkRequest] or returns `null` if there are none left.
+ ///
+ /// See [AsyncWorkerConnection] and [SyncWorkerConnection] for more narrow
+ /// interfaces.
+ FutureOr<WorkRequest?> readRequest();
+
+ void writeResponse(WorkResponse response);
+}
+
+abstract class AsyncWorkerConnection implements WorkerConnection {
+ /// Creates a [StdAsyncWorkerConnection] with the specified [inputStream]
+ /// and [outputStream], unless [sendPort] is specified, in which case
+ /// creates a [SendPortAsyncWorkerConnection].
+ factory AsyncWorkerConnection(
+ {Stream<List<int>>? inputStream,
+ StreamSink<List<int>>? outputStream,
+ SendPort? sendPort}) =>
+ sendPort == null
+ ? StdAsyncWorkerConnection(
+ inputStream: inputStream, outputStream: outputStream)
+ : SendPortAsyncWorkerConnection(sendPort);
+
+ @override
+ Future<WorkRequest?> readRequest();
+}
+
+abstract class SyncWorkerConnection implements WorkerConnection {
+ @override
+ WorkRequest? readRequest();
+}
+
+/// Default implementation of [AsyncWorkerConnection] that works with [Stdin]
+/// and [Stdout].
+class StdAsyncWorkerConnection implements AsyncWorkerConnection {
+ final AsyncMessageGrouper _messageGrouper;
+ final StreamSink<List<int>> _outputStream;
+
+ StdAsyncWorkerConnection(
+ {Stream<List<int>>? inputStream, StreamSink<List<int>>? outputStream})
+ : _messageGrouper = AsyncMessageGrouper(inputStream ?? stdin),
+ _outputStream = outputStream ?? stdout;
+
+ @override
+ Future<WorkRequest?> readRequest() async {
+ var buffer = await _messageGrouper.next;
+ if (buffer == null) return null;
+
+ return WorkRequest.fromBuffer(buffer);
+ }
+
+ @override
+ void writeResponse(WorkResponse response) {
+ _outputStream.add(protoToDelimitedBuffer(response));
+ }
+}
+
+/// Implementation of [AsyncWorkerConnection] for running in an isolate.
+class SendPortAsyncWorkerConnection implements AsyncWorkerConnection {
+ final ReceivePort receivePort;
+ final StreamIterator<Uint8List> receivePortIterator;
+ final SendPort sendPort;
+
+ factory SendPortAsyncWorkerConnection(SendPort sendPort) {
+ var receivePort = ReceivePort();
+ sendPort.send(receivePort.sendPort);
+ return SendPortAsyncWorkerConnection._(receivePort, sendPort);
+ }
+
+ SendPortAsyncWorkerConnection._(this.receivePort, this.sendPort)
+ : receivePortIterator = StreamIterator(receivePort.cast());
+
+ @override
+ Future<WorkRequest?> readRequest() async {
+ if (!await receivePortIterator.moveNext()) return null;
+ return WorkRequest.fromBuffer(receivePortIterator.current);
+ }
+
+ @override
+ void writeResponse(WorkResponse response) {
+ sendPort.send(response.writeToBuffer());
+ }
+}
+
+/// Default implementation of [SyncWorkerConnection] that works with [Stdin] and
+/// [Stdout].
+class StdSyncWorkerConnection implements SyncWorkerConnection {
+ final SyncMessageGrouper _messageGrouper;
+ final Stdout _stdoutStream;
+
+ StdSyncWorkerConnection({Stdin? stdinStream, Stdout? stdoutStream})
+ : _messageGrouper = SyncMessageGrouper(stdinStream ?? stdin),
+ _stdoutStream = stdoutStream ?? stdout;
+
+ @override
+ WorkRequest? readRequest() {
+ var buffer = _messageGrouper.next;
+ if (buffer == null) return null;
+
+ return WorkRequest.fromBuffer(buffer);
+ }
+
+ @override
+ void writeResponse(WorkResponse response) {
+ _stdoutStream.add(protoToDelimitedBuffer(response));
+ }
+}
diff --git a/pkgs/bazel_worker/lib/src/worker/worker_loop.dart b/pkgs/bazel_worker/lib/src/worker/worker_loop.dart
new file mode 100644
index 0000000..5723fd1
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/worker/worker_loop.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../worker_protocol.pb.dart';
+import 'async_worker_loop.dart';
+import 'sync_worker_loop.dart';
+
+/// Interface for a [WorkerLoop].
+///
+/// This interface should not generally be implemented directly, instead use
+/// the [SyncWorkerLoop] or [AsyncWorkerLoop] implementations.
+abstract class WorkerLoop {
+ /// Perform a single [WorkRequest], and return either a [WorkResponse] or
+ /// a [Future<WorkResponse>].
+ dynamic performRequest(WorkRequest request);
+
+ /// Run the worker loop. Should return either a [Future] or `null`.
+ dynamic run();
+}
diff --git a/pkgs/bazel_worker/lib/src/worker_protocol.pb.dart b/pkgs/bazel_worker/lib/src/worker_protocol.pb.dart
new file mode 100644
index 0000000..8b7a7a9
--- /dev/null
+++ b/pkgs/bazel_worker/lib/src/worker_protocol.pb.dart
@@ -0,0 +1,384 @@
+//
+// Generated code. Do not modify.
+// source: worker_protocol.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+/// An input file.
+class Input extends $pb.GeneratedMessage {
+ factory Input({
+ $core.String? path,
+ $core.List<$core.int>? digest,
+ }) {
+ final $result = create();
+ if (path != null) {
+ $result.path = path;
+ }
+ if (digest != null) {
+ $result.digest = digest;
+ }
+ return $result;
+ }
+ Input._() : super();
+ factory Input.fromBuffer($core.List<$core.int> i,
+ [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+ create()..mergeFromBuffer(i, r);
+ factory Input.fromJson($core.String i,
+ [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+ create()..mergeFromJson(i, r);
+
+ static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+ _omitMessageNames ? '' : 'Input',
+ package: const $pb.PackageName(_omitMessageNames ? '' : 'blaze.worker'),
+ createEmptyInstance: create)
+ ..aOS(1, _omitFieldNames ? '' : 'path')
+ ..a<$core.List<$core.int>>(
+ 2, _omitFieldNames ? '' : 'digest', $pb.PbFieldType.OY)
+ ..hasRequiredFields = false;
+
+ @$core.Deprecated('Using this can add significant overhead to your binary. '
+ 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+ 'Will be removed in next major version')
+ Input clone() => Input()..mergeFromMessage(this);
+ @$core.Deprecated('Using this can add significant overhead to your binary. '
+ 'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+ 'Will be removed in next major version')
+ Input copyWith(void Function(Input) updates) =>
+ super.copyWith((message) => updates(message as Input)) as Input;
+
+ $pb.BuilderInfo get info_ => _i;
+
+ @$core.pragma('dart2js:noInline')
+ static Input create() => Input._();
+ Input createEmptyInstance() => create();
+ static $pb.PbList<Input> createRepeated() => $pb.PbList<Input>();
+ @$core.pragma('dart2js:noInline')
+ static Input getDefault() =>
+ _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Input>(create);
+ static Input? _defaultInstance;
+
+ /// The path in the file system where to read this input artifact from. This is
+ /// either a path relative to the execution root (the worker process is
+ /// launched with the working directory set to the execution root), or an
+ /// absolute path.
+ @$pb.TagNumber(1)
+ $core.String get path => $_getSZ(0);
+ @$pb.TagNumber(1)
+ set path($core.String v) {
+ $_setString(0, v);
+ }
+
+ @$pb.TagNumber(1)
+ $core.bool hasPath() => $_has(0);
+ @$pb.TagNumber(1)
+ void clearPath() => clearField(1);
+
+ /// A hash-value of the contents. The format of the contents is unspecified and
+ /// the digest should be treated as an opaque token. This can be empty in some
+ /// cases.
+ @$pb.TagNumber(2)
+ $core.List<$core.int> get digest => $_getN(1);
+ @$pb.TagNumber(2)
+ set digest($core.List<$core.int> v) {
+ $_setBytes(1, v);
+ }
+
+ @$pb.TagNumber(2)
+ $core.bool hasDigest() => $_has(1);
+ @$pb.TagNumber(2)
+ void clearDigest() => clearField(2);
+}
+
+/// This represents a single work unit that Blaze sends to the worker.
+class WorkRequest extends $pb.GeneratedMessage {
+ factory WorkRequest({
+ $core.Iterable<$core.String>? arguments,
+ $core.Iterable<Input>? inputs,
+ $core.int? requestId,
+ $core.bool? cancel,
+ $core.int? verbosity,
+ $core.String? sandboxDir,
+ }) {
+ final $result = create();
+ if (arguments != null) {
+ $result.arguments.addAll(arguments);
+ }
+ if (inputs != null) {
+ $result.inputs.addAll(inputs);
+ }
+ if (requestId != null) {
+ $result.requestId = requestId;
+ }
+ if (cancel != null) {
+ $result.cancel = cancel;
+ }
+ if (verbosity != null) {
+ $result.verbosity = verbosity;
+ }
+ if (sandboxDir != null) {
+ $result.sandboxDir = sandboxDir;
+ }
+ return $result;
+ }
+ WorkRequest._() : super();
+ factory WorkRequest.fromBuffer($core.List<$core.int> i,
+ [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+ create()..mergeFromBuffer(i, r);
+ factory WorkRequest.fromJson($core.String i,
+ [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+ create()..mergeFromJson(i, r);
+
+ static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+ _omitMessageNames ? '' : 'WorkRequest',
+ package: const $pb.PackageName(_omitMessageNames ? '' : 'blaze.worker'),
+ createEmptyInstance: create)
+ ..pPS(1, _omitFieldNames ? '' : 'arguments')
+ ..pc<Input>(2, _omitFieldNames ? '' : 'inputs', $pb.PbFieldType.PM,
+ subBuilder: Input.create)
+ ..a<$core.int>(3, _omitFieldNames ? '' : 'requestId', $pb.PbFieldType.O3)
+ ..aOB(4, _omitFieldNames ? '' : 'cancel')
+ ..a<$core.int>(5, _omitFieldNames ? '' : 'verbosity', $pb.PbFieldType.O3)
+ ..aOS(6, _omitFieldNames ? '' : 'sandboxDir')
+ ..hasRequiredFields = false;
+
+ @$core.Deprecated('Using this can add significant overhead to your binary. '
+ 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+ 'Will be removed in next major version')
+ WorkRequest clone() => WorkRequest()..mergeFromMessage(this);
+ @$core.Deprecated('Using this can add significant overhead to your binary. '
+ 'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+ 'Will be removed in next major version')
+ WorkRequest copyWith(void Function(WorkRequest) updates) =>
+ super.copyWith((message) => updates(message as WorkRequest))
+ as WorkRequest;
+
+ $pb.BuilderInfo get info_ => _i;
+
+ @$core.pragma('dart2js:noInline')
+ static WorkRequest create() => WorkRequest._();
+ WorkRequest createEmptyInstance() => create();
+ static $pb.PbList<WorkRequest> createRepeated() => $pb.PbList<WorkRequest>();
+ @$core.pragma('dart2js:noInline')
+ static WorkRequest getDefault() => _defaultInstance ??=
+ $pb.GeneratedMessage.$_defaultFor<WorkRequest>(create);
+ static WorkRequest? _defaultInstance;
+
+ @$pb.TagNumber(1)
+ $core.List<$core.String> get arguments => $_getList(0);
+
+ /// The inputs that the worker is allowed to read during execution of this
+ /// request.
+ @$pb.TagNumber(2)
+ $core.List<Input> get inputs => $_getList(1);
+
+ /// Each WorkRequest must have either a unique
+ /// request_id or request_id = 0. If request_id is 0, this WorkRequest must be
+ /// processed alone (singleplex), otherwise the worker may process multiple
+ /// WorkRequests in parallel (multiplexing). As an exception to the above, if
+ /// the cancel field is true, the request_id must be the same as a previously
+ /// sent WorkRequest. The request_id must be attached unchanged to the
+ /// corresponding WorkResponse. Only one singleplex request may be sent to a
+ /// worker at a time.
+ @$pb.TagNumber(3)
+ $core.int get requestId => $_getIZ(2);
+ @$pb.TagNumber(3)
+ set requestId($core.int v) {
+ $_setSignedInt32(2, v);
+ }
+
+ @$pb.TagNumber(3)
+ $core.bool hasRequestId() => $_has(2);
+ @$pb.TagNumber(3)
+ void clearRequestId() => clearField(3);
+
+ /// EXPERIMENTAL: When true, this is a cancel request, indicating that a
+ /// previously sent WorkRequest with the same request_id should be cancelled.
+ /// The arguments and inputs fields must be empty and should be ignored.
+ @$pb.TagNumber(4)
+ $core.bool get cancel => $_getBF(3);
+ @$pb.TagNumber(4)
+ set cancel($core.bool v) {
+ $_setBool(3, v);
+ }
+
+ @$pb.TagNumber(4)
+ $core.bool hasCancel() => $_has(3);
+ @$pb.TagNumber(4)
+ void clearCancel() => clearField(4);
+
+ /// Values greater than 0 indicate that the worker may output extra debug
+ /// information to stderr (which will go into the worker log). Setting the
+ /// --worker_verbose flag for Bazel makes this flag default to 10.
+ @$pb.TagNumber(5)
+ $core.int get verbosity => $_getIZ(4);
+ @$pb.TagNumber(5)
+ set verbosity($core.int v) {
+ $_setSignedInt32(4, v);
+ }
+
+ @$pb.TagNumber(5)
+ $core.bool hasVerbosity() => $_has(4);
+ @$pb.TagNumber(5)
+ void clearVerbosity() => clearField(5);
+
+ /// The relative directory inside the workers working directory where the
+ /// inputs and outputs are placed, for sandboxing purposes. For singleplex
+ /// workers, this is unset, as they can use their working directory as sandbox.
+ /// For multiplex workers, this will be set when the
+ /// --experimental_worker_multiplex_sandbox flag is set _and_ the execution
+ /// requirements for the worker includes 'supports-multiplex-sandbox'.
+ /// The paths in `inputs` will not contain this prefix, but the actual files
+ /// will be placed/must be written relative to this directory. The worker
+ /// implementation is responsible for resolving the file paths.
+ @$pb.TagNumber(6)
+ $core.String get sandboxDir => $_getSZ(5);
+ @$pb.TagNumber(6)
+ set sandboxDir($core.String v) {
+ $_setString(5, v);
+ }
+
+ @$pb.TagNumber(6)
+ $core.bool hasSandboxDir() => $_has(5);
+ @$pb.TagNumber(6)
+ void clearSandboxDir() => clearField(6);
+}
+
+/// The worker sends this message to Blaze when it finished its work on the
+/// WorkRequest message.
+class WorkResponse extends $pb.GeneratedMessage {
+ factory WorkResponse({
+ $core.int? exitCode,
+ $core.String? output,
+ $core.int? requestId,
+ $core.bool? wasCancelled,
+ }) {
+ final $result = create();
+ if (exitCode != null) {
+ $result.exitCode = exitCode;
+ }
+ if (output != null) {
+ $result.output = output;
+ }
+ if (requestId != null) {
+ $result.requestId = requestId;
+ }
+ if (wasCancelled != null) {
+ $result.wasCancelled = wasCancelled;
+ }
+ return $result;
+ }
+ WorkResponse._() : super();
+ factory WorkResponse.fromBuffer($core.List<$core.int> i,
+ [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+ create()..mergeFromBuffer(i, r);
+ factory WorkResponse.fromJson($core.String i,
+ [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+ create()..mergeFromJson(i, r);
+
+ static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+ _omitMessageNames ? '' : 'WorkResponse',
+ package: const $pb.PackageName(_omitMessageNames ? '' : 'blaze.worker'),
+ createEmptyInstance: create)
+ ..a<$core.int>(1, _omitFieldNames ? '' : 'exitCode', $pb.PbFieldType.O3)
+ ..aOS(2, _omitFieldNames ? '' : 'output')
+ ..a<$core.int>(3, _omitFieldNames ? '' : 'requestId', $pb.PbFieldType.O3)
+ ..aOB(4, _omitFieldNames ? '' : 'wasCancelled')
+ ..hasRequiredFields = false;
+
+ @$core.Deprecated('Using this can add significant overhead to your binary. '
+ 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+ 'Will be removed in next major version')
+ WorkResponse clone() => WorkResponse()..mergeFromMessage(this);
+ @$core.Deprecated('Using this can add significant overhead to your binary. '
+ 'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+ 'Will be removed in next major version')
+ WorkResponse copyWith(void Function(WorkResponse) updates) =>
+ super.copyWith((message) => updates(message as WorkResponse))
+ as WorkResponse;
+
+ $pb.BuilderInfo get info_ => _i;
+
+ @$core.pragma('dart2js:noInline')
+ static WorkResponse create() => WorkResponse._();
+ WorkResponse createEmptyInstance() => create();
+ static $pb.PbList<WorkResponse> createRepeated() =>
+ $pb.PbList<WorkResponse>();
+ @$core.pragma('dart2js:noInline')
+ static WorkResponse getDefault() => _defaultInstance ??=
+ $pb.GeneratedMessage.$_defaultFor<WorkResponse>(create);
+ static WorkResponse? _defaultInstance;
+
+ @$pb.TagNumber(1)
+ $core.int get exitCode => $_getIZ(0);
+ @$pb.TagNumber(1)
+ set exitCode($core.int v) {
+ $_setSignedInt32(0, v);
+ }
+
+ @$pb.TagNumber(1)
+ $core.bool hasExitCode() => $_has(0);
+ @$pb.TagNumber(1)
+ void clearExitCode() => clearField(1);
+
+ /// This is printed to the user after the WorkResponse has been received and is
+ /// supposed to contain compiler warnings / errors etc. - thus we'll use a
+ /// string type here, which gives us UTF-8 encoding.
+ @$pb.TagNumber(2)
+ $core.String get output => $_getSZ(1);
+ @$pb.TagNumber(2)
+ set output($core.String v) {
+ $_setString(1, v);
+ }
+
+ @$pb.TagNumber(2)
+ $core.bool hasOutput() => $_has(1);
+ @$pb.TagNumber(2)
+ void clearOutput() => clearField(2);
+
+ /// This field must be set to the same request_id as the WorkRequest it is a
+ /// response to. Since worker processes which support multiplex worker will
+ /// handle multiple WorkRequests in parallel, this ID will be used to
+ /// determined which WorkerProxy does this WorkResponse belong to.
+ @$pb.TagNumber(3)
+ $core.int get requestId => $_getIZ(2);
+ @$pb.TagNumber(3)
+ set requestId($core.int v) {
+ $_setSignedInt32(2, v);
+ }
+
+ @$pb.TagNumber(3)
+ $core.bool hasRequestId() => $_has(2);
+ @$pb.TagNumber(3)
+ void clearRequestId() => clearField(3);
+
+ /// EXPERIMENTAL When true, indicates that this response was sent due to
+ /// receiving a cancel request. The exit_code and output fields should be empty
+ /// and will be ignored. Exactly one WorkResponse must be sent for each
+ /// non-cancelling WorkRequest received by the worker, but if the worker
+ /// received a cancel request, it doesn't matter if it replies with a regular
+ /// WorkResponse or with one where was_cancelled = true.
+ @$pb.TagNumber(4)
+ $core.bool get wasCancelled => $_getBF(3);
+ @$pb.TagNumber(4)
+ set wasCancelled($core.bool v) {
+ $_setBool(3, v);
+ }
+
+ @$pb.TagNumber(4)
+ $core.bool hasWasCancelled() => $_has(3);
+ @$pb.TagNumber(4)
+ void clearWasCancelled() => clearField(4);
+}
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames =
+ $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/pkgs/bazel_worker/lib/testing.dart b/pkgs/bazel_worker/lib/testing.dart
new file mode 100644
index 0000000..3ae4c1f
--- /dev/null
+++ b/pkgs/bazel_worker/lib/testing.dart
@@ -0,0 +1,203 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'bazel_worker.dart';
+
+export 'src/async_message_grouper.dart';
+export 'src/sync_message_grouper.dart';
+export 'src/utils.dart' show protoToDelimitedBuffer;
+
+/// Interface for a mock [Stdin] object that allows you to add bytes manually.
+abstract class TestStdin implements Stdin {
+ void addInputBytes(List<int> bytes);
+
+ void close();
+}
+
+/// A [Stdin] mock object which only implements `readByteSync`.
+class TestStdinSync implements TestStdin {
+ /// Pending bytes to be delivered synchronously.
+ final Queue<int> pendingBytes = Queue<int>();
+
+ /// Adds all the [bytes] to this stream.
+ @override
+ void addInputBytes(List<int> bytes) {
+ pendingBytes.addAll(bytes);
+ }
+
+ /// Add a -1 to signal EOF.
+ @override
+ void close() {
+ pendingBytes.add(-1);
+ }
+
+ @override
+ int readByteSync() {
+ return pendingBytes.removeFirst();
+ }
+
+ @override
+ bool get isBroadcast => false;
+
+ @override
+ void noSuchMethod(Invocation invocation) {
+ throw StateError('Unexpected invocation ${invocation.memberName}.');
+ }
+}
+
+/// A mock [Stdin] object which only implements `listen`.
+///
+/// Note: You must call [close] in order for the loop to exit properly.
+class TestStdinAsync implements TestStdin {
+ /// Controls the stream for async delivery of bytes.
+ final StreamController<Uint8List> _controller = StreamController();
+ StreamController<Uint8List> get controller => _controller;
+
+ /// Adds all the [bytes] to this stream.
+ @override
+ void addInputBytes(List<int> bytes) {
+ _controller.add(Uint8List.fromList(bytes));
+ }
+
+ /// Closes this stream. This is necessary for the [AsyncWorkerLoop] to exit.
+ @override
+ void close() {
+ _controller.close();
+ }
+
+ @override
+ StreamSubscription<Uint8List> listen(void Function(Uint8List bytes)? onData,
+ {Function? onError, void Function()? onDone, bool? cancelOnError}) {
+ return _controller.stream.listen(onData,
+ onError: onError, onDone: onDone, cancelOnError: cancelOnError);
+ }
+
+ @override
+ bool get isBroadcast => false;
+
+ @override
+ void noSuchMethod(Invocation invocation) {
+ throw StateError('Unexpected invocation ${invocation.memberName}.');
+ }
+}
+
+/// A [Stdout] mock object.
+class TestStdoutStream implements Stdout {
+ final List<List<int>> writes = <List<int>>[];
+
+ @override
+ void add(List<int> bytes) {
+ writes.add(bytes);
+ }
+
+ @override
+ void noSuchMethod(Invocation invocation) {
+ throw StateError('Unexpected invocation ${invocation.memberName}.');
+ }
+}
+
+/// Interface for a [TestWorkerConnection] which records its responses
+abstract class TestWorkerConnection implements WorkerConnection {
+ List<WorkResponse> get responses;
+}
+
+/// Interface for a [TestWorkerLoop] which allows you to enqueue responses.
+abstract class TestWorkerLoop implements WorkerLoop {
+ void enqueueResponse(WorkResponse response);
+
+ /// If set, this message will be printed during the call to `performRequest`.
+ String? get printMessage;
+}
+
+/// A [StdSyncWorkerConnection] which records its responses.
+class TestSyncWorkerConnection extends StdSyncWorkerConnection
+ implements TestWorkerConnection {
+ @override
+ final List<WorkResponse> responses = <WorkResponse>[];
+
+ TestSyncWorkerConnection(Stdin stdinStream, Stdout stdoutStream)
+ : super(stdinStream: stdinStream, stdoutStream: stdoutStream);
+
+ @override
+ void writeResponse(WorkResponse response) {
+ super.writeResponse(response);
+ responses.add(response);
+ }
+}
+
+/// A [SyncWorkerLoop] for testing.
+class TestSyncWorkerLoop extends SyncWorkerLoop implements TestWorkerLoop {
+ final List<WorkRequest> requests = <WorkRequest>[];
+ final Queue<WorkResponse> _responses = Queue<WorkResponse>();
+
+ @override
+ final String? printMessage;
+
+ TestSyncWorkerLoop(SyncWorkerConnection connection, {this.printMessage})
+ : super(connection: connection);
+
+ @override
+ WorkResponse performRequest(WorkRequest request) {
+ requests.add(request);
+ if (printMessage != null) print(printMessage);
+ return _responses.removeFirst();
+ }
+
+ /// Adds [response] to the queue. These will be returned from
+ /// [performRequest] in the order they are added, otherwise it will throw
+ /// if the queue is empty.
+ @override
+ void enqueueResponse(WorkResponse response) {
+ _responses.addLast(response);
+ }
+}
+
+/// A [StdAsyncWorkerConnection] which records its responses.
+class TestAsyncWorkerConnection extends StdAsyncWorkerConnection
+ implements TestWorkerConnection {
+ @override
+ final List<WorkResponse> responses = <WorkResponse>[];
+
+ TestAsyncWorkerConnection(
+ Stream<List<int>> inputStream, StreamSink<List<int>> outputStream)
+ : super(inputStream: inputStream, outputStream: outputStream);
+
+ @override
+ void writeResponse(WorkResponse response) {
+ super.writeResponse(response);
+ responses.add(response);
+ }
+}
+
+/// A [AsyncWorkerLoop] for testing.
+class TestAsyncWorkerLoop extends AsyncWorkerLoop implements TestWorkerLoop {
+ final List<WorkRequest> requests = <WorkRequest>[];
+ final Queue<WorkResponse> _responses = Queue<WorkResponse>();
+
+ @override
+ final String? printMessage;
+
+ TestAsyncWorkerLoop(AsyncWorkerConnection connection, {this.printMessage})
+ : super(connection: connection);
+
+ @override
+ Future<WorkResponse> performRequest(WorkRequest request) async {
+ requests.add(request);
+ if (printMessage != null) print(printMessage);
+ return _responses.removeFirst();
+ }
+
+ /// Adds [response] to the queue. These will be returned from
+ /// [performRequest] in the order they are added, otherwise it will throw
+ /// if the queue is empty.
+ @override
+ void enqueueResponse(WorkResponse response) {
+ _responses.addLast(response);
+ }
+}
diff --git a/pkgs/bazel_worker/pubspec.yaml b/pkgs/bazel_worker/pubspec.yaml
new file mode 100644
index 0000000..561a791
--- /dev/null
+++ b/pkgs/bazel_worker/pubspec.yaml
@@ -0,0 +1,17 @@
+name: bazel_worker
+version: 1.1.3-wip
+description: >-
+ Protocol and utilities to implement or invoke persistent bazel workers.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/bazel_worker
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Abazel_worker
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ async: ^2.5.0
+ protobuf: ^3.0.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.0
diff --git a/pkgs/bazel_worker/test/driver_connection_test.dart b/pkgs/bazel_worker/test/driver_connection_test.dart
new file mode 100644
index 0000000..3bbb56d
--- /dev/null
+++ b/pkgs/bazel_worker/test/driver_connection_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:isolate';
+
+import 'package:bazel_worker/src/constants.dart';
+import 'package:bazel_worker/src/driver/driver_connection.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('IsolateDriverConnection', () {
+ test('handles closed port', () async {
+ var isolatePort = ReceivePort();
+ var outsidePort = ReceivePort();
+ isolatePort.sendPort.send(outsidePort.sendPort);
+ var connection = await IsolateDriverConnection.create(isolatePort);
+
+ isolatePort.close();
+
+ expect((await connection.readResponse()).exitCode, EXIT_CODE_BROKEN_PIPE);
+ });
+ });
+}
diff --git a/pkgs/bazel_worker/test/driver_test.dart b/pkgs/bazel_worker/test/driver_test.dart
new file mode 100644
index 0000000..c397830
--- /dev/null
+++ b/pkgs/bazel_worker/test/driver_test.dart
@@ -0,0 +1,277 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:io';
+
+import 'package:bazel_worker/bazel_worker.dart';
+import 'package:bazel_worker/driver.dart';
+import 'package:test/test.dart';
+
+void main() {
+ BazelWorkerDriver? driver;
+ final disconnectedResponse = WorkResponse(
+ exitCode: EXIT_CODE_BROKEN_PIPE,
+ output: 'Connection closed',
+ )..freeze();
+
+ group('basic driver', () {
+ test('can run a single request', () async {
+ await _doRequests(count: 1);
+ await _doRequests(count: 1);
+ });
+
+ test('can run multiple batches of requests through multiple workers',
+ () async {
+ var maxWorkers = 4;
+ var maxIdleWorkers = 2;
+ driver = BazelWorkerDriver(MockWorker.spawn,
+ maxWorkers: maxWorkers, maxIdleWorkers: maxIdleWorkers);
+ for (var i = 0; i < 10; i++) {
+ await _doRequests(driver: driver);
+ expect(MockWorker.liveWorkers.length, maxIdleWorkers);
+ // No workers should be killed while there is ongoing work, but they
+ // should be cleaned up once there isn't any more work to do.
+ expect(MockWorker.deadWorkers.length,
+ (maxWorkers - maxIdleWorkers) * (i + 1));
+ }
+ });
+
+ test('can run multiple requests through one worker', () async {
+ var maxWorkers = 1;
+ var maxIdleWorkers = 1;
+ driver = BazelWorkerDriver(MockWorker.spawn,
+ maxWorkers: maxWorkers, maxIdleWorkers: maxIdleWorkers);
+ for (var i = 0; i < 10; i++) {
+ await _doRequests(driver: driver);
+ expect(MockWorker.liveWorkers.length, 1);
+ expect(MockWorker.deadWorkers.length, 0);
+ }
+ });
+
+ test('can run one request through multiple workers', () async {
+ driver =
+ BazelWorkerDriver(MockWorker.spawn, maxWorkers: 4, maxIdleWorkers: 4);
+ for (var i = 0; i < 10; i++) {
+ await _doRequests(driver: driver, count: 1);
+ expect(MockWorker.liveWorkers.length, 1);
+ expect(MockWorker.deadWorkers.length, 0);
+ }
+ });
+
+ test('can run with maxIdleWorkers == 0', () async {
+ var maxWorkers = 4;
+ driver = BazelWorkerDriver(MockWorker.spawn,
+ maxWorkers: maxWorkers, maxIdleWorkers: 0);
+ for (var i = 0; i < 10; i++) {
+ await _doRequests(driver: driver);
+ expect(MockWorker.liveWorkers.length, 0);
+ expect(MockWorker.deadWorkers.length, maxWorkers * (i + 1));
+ }
+ });
+
+ test('trackWork gets invoked when a worker is actually ready', () async {
+ var maxWorkers = 2;
+ driver = BazelWorkerDriver(MockWorker.spawn, maxWorkers: maxWorkers);
+ var tracking = <Future>[];
+ await _doRequests(
+ driver: driver,
+ count: 10,
+ trackWork: (Future response) {
+ // We should never be tracking more than `maxWorkers` jobs at a time.
+ expect(tracking.length, lessThan(maxWorkers));
+ tracking.add(response);
+ response.then((_) => tracking.remove(response));
+ });
+ });
+
+ group('failing workers', () {
+ /// A driver which spawns [numBadWorkers] failing workers and then good
+ /// ones after that, and which will retry [maxRetries] times.
+ void createDriver({int maxRetries = 2, int numBadWorkers = 2}) {
+ var numSpawned = 0;
+ driver = BazelWorkerDriver(
+ () async => MockWorker(workerLoopFactory: (MockWorker worker) {
+ var connection = StdAsyncWorkerConnection(
+ inputStream: worker._stdinController.stream,
+ outputStream: worker._stdoutController.sink);
+ if (numSpawned < numBadWorkers) {
+ numSpawned++;
+ return ThrowingMockWorkerLoop(
+ worker, MockWorker.responseQueue, connection);
+ } else {
+ return MockWorkerLoop(MockWorker.responseQueue,
+ connection: connection);
+ }
+ }),
+ maxRetries: maxRetries);
+ }
+
+ test('should retry up to maxRetries times', () async {
+ createDriver();
+ var expectedResponse = WorkResponse();
+ MockWorker.responseQueue.addAll(
+ [disconnectedResponse, disconnectedResponse, expectedResponse]);
+ var actualResponse = await driver!.doWork(WorkRequest());
+ // The first 2 null responses are thrown away, and we should get the
+ // third one.
+ expect(actualResponse, expectedResponse);
+
+ expect(MockWorker.deadWorkers.length, 2);
+ expect(MockWorker.liveWorkers.length, 1);
+ });
+
+ test('should fail if it exceeds maxRetries failures', () async {
+ createDriver(maxRetries: 2, numBadWorkers: 3);
+ MockWorker.responseQueue.addAll(
+ [disconnectedResponse, disconnectedResponse, WorkResponse()]);
+ var actualResponse = await driver!.doWork(WorkRequest());
+ // Should actually get a bad response.
+ expect(actualResponse.exitCode, 15);
+ expect(
+ actualResponse.output,
+ 'Invalid response from worker, this probably means it wrote '
+ 'invalid output or died.');
+
+ expect(MockWorker.deadWorkers.length, 3);
+ });
+ });
+
+ test('handles spawnWorker failures', () async {
+ driver = BazelWorkerDriver(() async => throw StateError('oh no!'),
+ maxRetries: 0);
+ expect(driver!.doWork(WorkRequest()), throwsA(isA<StateError>()));
+ });
+
+ tearDown(() async {
+ await driver?.terminateWorkers();
+ expect(MockWorker.liveWorkers, isEmpty);
+ MockWorker.deadWorkers.clear();
+ MockWorker.responseQueue.clear();
+ });
+ });
+}
+
+/// Runs [count] of fake work requests through [driver], and asserts that they
+/// all completed.
+Future _doRequests(
+ {BazelWorkerDriver? driver,
+ int count = 100,
+ void Function(Future<WorkResponse?>)? trackWork}) async {
+ // If we create a driver, we need to make sure and terminate it.
+ var terminateDriver = driver == null;
+ driver ??= BazelWorkerDriver(MockWorker.spawn);
+ var requests = List.generate(count, (_) => WorkRequest());
+ var responses = List.generate(count, (_) => WorkResponse());
+ MockWorker.responseQueue.addAll(responses);
+ var actualResponses = await Future.wait(
+ requests.map((request) => driver!.doWork(request, trackWork: trackWork)));
+ expect(actualResponses, unorderedEquals(responses));
+ if (terminateDriver) await driver.terminateWorkers();
+}
+
+/// A mock worker loop that returns work responses from the provided list.
+///
+/// Throws if it runs out of responses.
+class MockWorkerLoop extends AsyncWorkerLoop {
+ final Queue<WorkResponse> _responseQueue;
+
+ MockWorkerLoop(this._responseQueue, {super.connection});
+
+ @override
+ Future<WorkResponse> performRequest(WorkRequest request) async {
+ print('Performing request $request');
+ return _responseQueue.removeFirst();
+ }
+}
+
+/// A mock worker loop with a custom `run` function that throws.
+class ThrowingMockWorkerLoop extends MockWorkerLoop {
+ final MockWorker _mockWorker;
+
+ ThrowingMockWorkerLoop(this._mockWorker, Queue<WorkResponse> responseQueue,
+ AsyncWorkerConnection connection)
+ : super(responseQueue, connection: connection);
+
+ /// Run the worker loop. The returned [Future] doesn't complete until
+ /// [connection#readRequest] returns `null`.
+ @override
+ Future run() async {
+ while (true) {
+ var request = await connection.readRequest();
+ if (request == null) break;
+ await performRequest(request);
+ _mockWorker.kill();
+ }
+ }
+}
+
+/// A mock worker process.
+///
+/// Items in [responseQueue] will be returned in order based on requests.
+///
+/// If there are no items left in [responseQueue] then it will throw.
+class MockWorker implements Process {
+ /// Spawns a new [MockWorker].
+ static Future<MockWorker> spawn() async => MockWorker();
+
+ /// Static queue of pending responses, these are shared by all workers.
+ ///
+ /// If this is empty and a request is received then it will throw.
+ static final responseQueue = Queue<WorkResponse>();
+
+ /// Static list of all live workers.
+ static final liveWorkers = <MockWorker>[];
+
+ /// Static list of all the dead workers.
+ static final deadWorkers = <MockWorker>[];
+
+ /// Standard constructor, creates a [WorkerLoop] from [workerLoopFactory] or
+ /// a [MockWorkerLoop] if no factory is provided.
+ MockWorker({WorkerLoop Function(MockWorker)? workerLoopFactory}) {
+ liveWorkers.add(this);
+ var workerLoop = workerLoopFactory != null
+ ? workerLoopFactory(this)
+ : MockWorkerLoop(responseQueue,
+ connection: StdAsyncWorkerConnection(
+ inputStream: _stdinController.stream,
+ outputStream: _stdoutController.sink));
+ workerLoop.run();
+ }
+
+ @override
+ Future<int> get exitCode => throw UnsupportedError('Not needed.');
+
+ @override
+ Stream<List<int>> get stdout => _stdoutController.stream;
+ final _stdoutController = StreamController<List<int>>();
+
+ @override
+ Stream<List<int>> get stderr => _stderrController.stream;
+ final _stderrController = StreamController<List<int>>();
+
+ @override
+ late final IOSink stdin = IOSink(_stdinController.sink);
+ final _stdinController = StreamController<List<int>>();
+
+ @override
+ int get pid => throw UnsupportedError('Not needed.');
+
+ @override
+ bool kill(
+ [ProcessSignal processSignal = ProcessSignal.sigterm, int exitCode = 0]) {
+ if (_killed) return false;
+ () async {
+ await _stdoutController.close();
+ await _stderrController.close();
+ await _stdinController.close();
+ }();
+ deadWorkers.add(this);
+ liveWorkers.remove(this);
+ return true;
+ }
+
+ final _killed = false;
+}
diff --git a/pkgs/bazel_worker/test/message_grouper_test.dart b/pkgs/bazel_worker/test/message_grouper_test.dart
new file mode 100644
index 0000000..475190e
--- /dev/null
+++ b/pkgs/bazel_worker/test/message_grouper_test.dart
@@ -0,0 +1,145 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:bazel_worker/bazel_worker.dart';
+import 'package:bazel_worker/testing.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('AsyncMessageGrouper', () {
+ runTests(TestStdinAsync.new, AsyncMessageGrouper.new);
+ });
+
+ group('SyncMessageGrouper', () {
+ runTests(TestStdinSync.new, SyncMessageGrouper.new);
+ });
+}
+
+void runTests(TestStdin Function() stdinFactory,
+ MessageGrouper Function(Stdin) messageGrouperFactory) {
+ late MessageGrouper messageGrouper;
+
+ late TestStdin stdinStream;
+
+ setUp(() {
+ stdinStream = stdinFactory();
+ messageGrouper = messageGrouperFactory(stdinStream);
+ });
+
+ /// Check that if the message grouper produces the [expectedOutput] in
+ /// response to the corresponding [input].
+ Future check(List<int> input, List<List<int>> expectedOutput) async {
+ stdinStream.addInputBytes(input);
+ for (var chunk in expectedOutput) {
+ expect(await messageGrouper.next, equals(chunk));
+ }
+ }
+
+ /// Make a simple message having the given [length]
+ List<int> makeMessage(int length) {
+ var result = <int>[];
+ for (var i = 0; i < length; i++) {
+ result.add(i & 0xff);
+ }
+ return result;
+ }
+
+ test('Empty message', () async {
+ await check([0], [[]]);
+ });
+
+ test('Short message', () async {
+ await check([
+ 5,
+ 10,
+ 20,
+ 30,
+ 40,
+ 50
+ ], [
+ [10, 20, 30, 40, 50]
+ ]);
+ });
+
+ test('Message with 2-byte length', () async {
+ var len = 0x155;
+ var msg = makeMessage(len);
+ var encodedLen = [0xd5, 0x02];
+ await check([...encodedLen, ...msg], [msg]);
+ });
+
+ test('Message with 3-byte length', () async {
+ var len = 0x4103;
+ var msg = makeMessage(len);
+ var encodedLen = [0x83, 0x82, 0x01];
+ await check([...encodedLen, ...msg], [msg]);
+ });
+
+ test('Multiple messages', () async {
+ await check([
+ 2,
+ 10,
+ 20,
+ 2,
+ 30,
+ 40
+ ], [
+ [10, 20],
+ [30, 40]
+ ]);
+ });
+
+ test('Empty message at start', () async {
+ await check([
+ 0,
+ 2,
+ 10,
+ 20
+ ], [
+ [],
+ [10, 20]
+ ]);
+ });
+
+ test('Empty message at end', () async {
+ await check([
+ 2,
+ 10,
+ 20,
+ 0
+ ], [
+ [10, 20],
+ []
+ ]);
+ });
+
+ test('Empty message in the middle', () async {
+ await check([
+ 2,
+ 10,
+ 20,
+ 0,
+ 2,
+ 30,
+ 40
+ ], [
+ [10, 20],
+ [],
+ [30, 40]
+ ]);
+ });
+
+ test('Handles the case when stdin gives an error instead of EOF', () async {
+ if (stdinStream is TestStdinSync) {
+ // Reading will now cause an error as pendingBytes is empty.
+ (stdinStream as TestStdinSync).pendingBytes.clear();
+ expect(messageGrouper.next, isNull);
+ } else if (stdinStream is TestStdinAsync) {
+ (stdinStream as TestStdinAsync).controller.addError('Error!');
+ expect(await messageGrouper.next, isNull);
+ }
+ });
+}
diff --git a/pkgs/bazel_worker/test/test_all.dart b/pkgs/bazel_worker/test/test_all.dart
new file mode 100644
index 0000000..7eb6b11
--- /dev/null
+++ b/pkgs/bazel_worker/test/test_all.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'driver_connection_test.dart' as driver_connection;
+import 'driver_test.dart' as driver;
+import 'message_grouper_test.dart' as message_grouper;
+import 'worker_loop_test.dart' as worker_loop;
+
+void main() {
+ driver.main();
+ message_grouper.main();
+ worker_loop.main();
+ driver_connection.main();
+}
diff --git a/pkgs/bazel_worker/test/worker_loop_test.dart b/pkgs/bazel_worker/test/worker_loop_test.dart
new file mode 100644
index 0000000..50d2151
--- /dev/null
+++ b/pkgs/bazel_worker/test/worker_loop_test.dart
@@ -0,0 +1,122 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:bazel_worker/bazel_worker.dart';
+import 'package:bazel_worker/testing.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('SyncWorkerLoop', () {
+ runTests(TestStdinSync.new, TestSyncWorkerConnection.new,
+ TestSyncWorkerLoop.new);
+ });
+
+ group('AsyncWorkerLoop', () {
+ runTests(TestStdinAsync.new, TestAsyncWorkerConnection.new,
+ TestAsyncWorkerLoop.new);
+ });
+
+ group('SyncWorkerLoopWithPrint', () {
+ runTests(
+ TestStdinSync.new,
+ TestSyncWorkerConnection.new,
+ (TestSyncWorkerConnection connection) =>
+ TestSyncWorkerLoop(connection, printMessage: 'Goodbye!'));
+ });
+
+ group('AsyncWorkerLoopWithPrint', () {
+ runTests(
+ TestStdinAsync.new,
+ TestAsyncWorkerConnection.new,
+ (TestAsyncWorkerConnection connection) =>
+ TestAsyncWorkerLoop(connection, printMessage: 'Goodbye!'));
+ });
+}
+
+void runTests<T extends TestWorkerConnection>(
+ TestStdin Function() stdinFactory,
+ T Function(Stdin, Stdout) workerConnectionFactory,
+ TestWorkerLoop Function(T) workerLoopFactory) {
+ late TestStdin stdinStream;
+ late TestStdoutStream stdoutStream;
+ late T connection;
+ late TestWorkerLoop workerLoop;
+
+ setUp(() {
+ stdinStream = stdinFactory();
+ stdoutStream = TestStdoutStream();
+ connection = workerConnectionFactory(stdinStream, stdoutStream);
+ workerLoop = workerLoopFactory(connection);
+ });
+
+ test('basic', () async {
+ var request = WorkRequest(arguments: ['--foo=bar']);
+ stdinStream.addInputBytes(protoToDelimitedBuffer(request));
+ stdinStream.close();
+
+ var response = WorkResponse(output: 'Hello World');
+ workerLoop.enqueueResponse(response);
+
+ // Make sure `print` never gets called in the parent zone.
+ var printMessages = <String>[];
+ await runZoned(() => workerLoop.run(), zoneSpecification:
+ ZoneSpecification(print: (self, parent, zone, message) {
+ printMessages.add(message);
+ }));
+ expect(printMessages, isEmpty,
+ reason: 'The worker loop should hide all print calls from the parent '
+ 'zone.');
+
+ expect(connection.responses, hasLength(1));
+ expect(connection.responses[0], response);
+ if (workerLoop.printMessage != null) {
+ expect(response.output, endsWith(workerLoop.printMessage!),
+ reason: 'Print messages should get appended to the response output.');
+ }
+
+ // Check that a serialized version was written to std out.
+ expect(stdoutStream.writes, hasLength(1));
+ expect(stdoutStream.writes[0], protoToDelimitedBuffer(response));
+ });
+
+ test('Exception in the worker.', () async {
+ var request = WorkRequest(arguments: ['--foo=bar']);
+ stdinStream.addInputBytes(protoToDelimitedBuffer(request));
+ stdinStream.close();
+
+ // Didn't enqueue a response, so this will throw inside of `performRequest`.
+ await workerLoop.run();
+
+ expect(connection.responses, hasLength(1));
+ var response = connection.responses[0];
+ expect(response.exitCode, EXIT_CODE_ERROR);
+
+ // Check that a serialized version was written to std out.
+ expect(stdoutStream.writes, hasLength(1));
+ expect(stdoutStream.writes[0], protoToDelimitedBuffer(response));
+ });
+
+ test('Stops at EOF', () async {
+ stdinStream.addInputBytes([-1]);
+ stdinStream.close();
+ await workerLoop.run();
+ });
+
+ test('Stops if stdin gives an error instead of EOF', () async {
+ if (stdinStream is TestStdinSync) {
+ // Reading will now cause an error as pendingBytes is empty.
+ (stdinStream as TestStdinSync).pendingBytes.clear();
+ await workerLoop.run();
+ } else if (stdinStream is TestStdinAsync) {
+ var done = Completer<void>();
+ // ignore: avoid_dynamic_calls
+ workerLoop.run().then((_) => done.complete(null));
+ (stdinStream as TestStdinAsync).controller.addError('Error!!');
+ await done.future;
+ }
+ });
+}
diff --git a/pkgs/bazel_worker/tool/travis.sh b/pkgs/bazel_worker/tool/travis.sh
new file mode 100755
index 0000000..05adb02
--- /dev/null
+++ b/pkgs/bazel_worker/tool/travis.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Fast fail the script on failures.
+set -e
+
+dart pub get
+
+# Verify that the libraries are error free.
+dart analyze --fatal-infos \
+ lib/bazel_worker.dart \
+ lib/driver.dart \
+ lib/testing.dart \
+ test/test_all.dart
+
+# Run the tests.
+dart test
+
+pushd e2e_test
+dart pub get
+dart analyze --fatal-infos test/e2e_test.dart
+dart test
+popd
diff --git a/pkgs/bazel_worker/tool/update_proto.sh b/pkgs/bazel_worker/tool/update_proto.sh
new file mode 100755
index 0000000..3f77a06
--- /dev/null
+++ b/pkgs/bazel_worker/tool/update_proto.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+if [ -z "$1" ]; then
+ echo "Expected exactly one argument which is the protoc_plugin version to use"
+else
+ echo "Using protoc_plugin version $1"
+ dart pub global activate protoc_plugin "$1"
+fi
+
+BAZEL_REPO=.dart_tool/bazel_worker/bazel.git/
+# Bash away old versions if they exist
+rm -rf "$BAZEL_REPO"
+git clone --depth 1 https://github.com/bazelbuild/bazel.git "$BAZEL_REPO"
+
+protoc --proto_path="${BAZEL_REPO}/src/main/protobuf" --dart_out="lib/src" worker_protocol.proto
+dart format lib/src/worker_protocol.pb.dart
+
+# We only care about the *.pb.dart file, not the extra files
+rm lib/src/worker_protocol.pbenum.dart
+rm lib/src/worker_protocol.pbjson.dart
+rm lib/src/worker_protocol.pbserver.dart
+
+rm -rf "$BAZEL_REPO"
diff --git a/pkgs/benchmark_harness/.gitignore b/pkgs/benchmark_harness/.gitignore
new file mode 100644
index 0000000..2afa93d
--- /dev/null
+++ b/pkgs/benchmark_harness/.gitignore
@@ -0,0 +1,4 @@
+.dart_tool
+.packages
+.pub
+pubspec.lock
diff --git a/pkgs/benchmark_harness/CHANGELOG.md b/pkgs/benchmark_harness/CHANGELOG.md
new file mode 100644
index 0000000..fceecb8
--- /dev/null
+++ b/pkgs/benchmark_harness/CHANGELOG.md
@@ -0,0 +1,50 @@
+## 2.3.1
+
+- Move to `dart-lang/tools` monorepo.
+
+## 2.3.0
+
+- Require Dart 3.2.
+- Add ScoreEmitterV2 interface, documented with the intention to change
+ScoreEmitter interface to match it in the next major release,
+ a breaking change.
+- Add `PerfBenchmarkBase` class which runs the 'perf stat' command from
+linux-tools on a benchmark and reports metrics from the hardware
+performance counters and the iteration count, as well as the run time
+measurement reported by `BenchmarkBase`.
+
+## 2.2.2
+
+- Added package topics to the pubspec file.
+- Require Dart 2.19.
+
+## 2.2.1
+
+- Improve convergence speed of `BenchmarkBase` measuring algorithm by allowing
+some degree of measuring jitter.
+
+## 2.2.0
+
+- Change measuring algorithm in `BenchmarkBase` to avoid calling stopwatch
+methods repeatedly in the measuring loop. This makes measurement work better
+for `run` methods which are small themselves.
+
+## 2.1.0
+
+- Add AsyncBenchmarkBase.
+
+## 2.0.0
+
+- Stable null safety release.
+
+## 2.0.0-nullsafety.0
+
+- Opt in to null safety.
+
+## 1.0.6
+
+- Require at least Dart 2.1.
+
+## 1.0.5
+
+- Updates to support Dart 2.
diff --git a/pkgs/benchmark_harness/LICENSE b/pkgs/benchmark_harness/LICENSE
new file mode 100644
index 0000000..db5bf46
--- /dev/null
+++ b/pkgs/benchmark_harness/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2021, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/pkgs/benchmark_harness/README.md b/pkgs/benchmark_harness/README.md
new file mode 100644
index 0000000..f156f23
--- /dev/null
+++ b/pkgs/benchmark_harness/README.md
@@ -0,0 +1,116 @@
+[](https://github.com/dart-lang/tools/actions/workflows/benchmark_harness.yaml)
+[](https://pub.dev/packages/benchmark_harness)
+[](https://pub.dev/packages/benchmark_harness/publisher)
+
+The Dart project benchmark harness is the recommended starting point when
+building a benchmark for Dart.
+
+## Interpreting Results
+
+By default, the reported runtime in `BenchmarkBase` is not for a single call to
+`run()`, but for the average time it takes to call `run()` __10 times__ for
+legacy reasons. The benchmark harness executes a 10-call timing loop repeatedly
+until 2 seconds have elapsed; the reported result is the average of the runtimes
+for each loop. This behavior will change in a future major version.
+
+Benchmarks extending `BenchmarkBase` can opt into the reporting the average time
+to call `run()` once by overriding the `exercise` method:
+
+```dart
+ @override
+ void exercise() => run();
+```
+
+`AsyncBenchmarkBase` already reports the average time to call `run()` __once__.
+
+## Comparing Results
+
+If you are running the same benchmark, on the same machine, running the same OS,
+the reported run times can be carefully compared across runs.
+Carefully because there are a variety of factors which
+could cause error in the run time, for example, the load from
+other applications running on your machine could alter the result.
+
+Comparing the run time of different benchmarks is not recommended.
+In other words, don't compare apples with oranges.
+
+## Features
+
+* `BenchmarkBase` class that all new benchmarks should `extend`.
+* `AsyncBenchmarkBase` for asynchronous benchmarks.
+* Template benchmark that you can copy and paste when building new benchmarks.
+
+## Getting Started
+
+1\. Add the following to your project's **pubspec.yaml**
+
+```yaml
+dependencies:
+ benchmark_harness: any
+```
+
+2\. Install pub packages
+
+```sh
+dart pub install
+```
+
+3\. Add the following import:
+
+```dart
+import 'package:benchmark_harness/benchmark_harness.dart';
+```
+
+4\. Create a benchmark class which inherits from `BenchmarkBase` or
+ `AsyncBenchmarkBase`.
+
+## Example
+
+Create a dart file in the
+[`benchmark/`](https://dart.dev/tools/pub/package-layout#tests-and-benchmarks)
+folder of your package.
+
+```dart
+// Import BenchmarkBase class.
+import 'package:benchmark_harness/benchmark_harness.dart';
+
+// Create a new benchmark by extending BenchmarkBase
+class TemplateBenchmark extends BenchmarkBase {
+ const TemplateBenchmark() : super('Template');
+
+ static void main() {
+ const TemplateBenchmark().report();
+ }
+
+ // The benchmark code.
+ @override
+ void run() {}
+
+ // Not measured setup code executed prior to the benchmark runs.
+ @override
+ void setup() {}
+
+ // Not measured teardown code executed after the benchmark runs.
+ @override
+ void teardown() {}
+
+ // To opt into the reporting the time per run() instead of per 10 run() calls.
+ //@override
+ //void exercise() => run();
+}
+
+void main() {
+ // Run TemplateBenchmark
+ TemplateBenchmark.main();
+}
+```
+
+### Output
+
+```console
+Template(RunTime): 0.1568472448997197 us.
+```
+
+This is the average amount of time it takes to run `run()` 10 times for
+`BenchmarkBase` and once for `AsyncBenchmarkBase`.
+> µs is an abbreviation for microseconds.
diff --git a/pkgs/benchmark_harness/analysis_options.yaml b/pkgs/benchmark_harness/analysis_options.yaml
new file mode 100644
index 0000000..9a77232
--- /dev/null
+++ b/pkgs/benchmark_harness/analysis_options.yaml
@@ -0,0 +1,14 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-inference: true
+ strict-casts: true
+
+linter:
+ rules:
+ - avoid_unused_constructor_parameters
+ - cancel_subscriptions
+ - literal_only_boolean_expressions
+ - no_adjacent_strings_in_list
+ - unnecessary_await_in_return
diff --git a/pkgs/benchmark_harness/example/template.dart b/pkgs/benchmark_harness/example/template.dart
new file mode 100644
index 0000000..d13a98b
--- /dev/null
+++ b/pkgs/benchmark_harness/example/template.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Import BenchmarkBase class.
+import 'package:benchmark_harness/benchmark_harness.dart';
+
+// Create a new benchmark by extending BenchmarkBase
+class TemplateBenchmark extends BenchmarkBase {
+ const TemplateBenchmark() : super('Template');
+
+ static void main() {
+ const TemplateBenchmark().report();
+ }
+
+ // The benchmark code.
+ @override
+ void run() {}
+
+ // Not measured setup code executed prior to the benchmark runs.
+ @override
+ void setup() {}
+
+ // Not measures teardown code executed after the benchmark runs.
+ @override
+ void teardown() {}
+
+ // To opt into the reporting the time per run() instead of per 10 run() calls.
+ //@override
+ //void exercise() => run();
+}
+
+void main() {
+ // Run TemplateBenchmark
+ TemplateBenchmark.main();
+}
diff --git a/pkgs/benchmark_harness/integration_test/perf_benchmark_test.dart b/pkgs/benchmark_harness/integration_test/perf_benchmark_test.dart
new file mode 100644
index 0000000..339777f
--- /dev/null
+++ b/pkgs/benchmark_harness/integration_test/perf_benchmark_test.dart
@@ -0,0 +1,26 @@
+// Copyright 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:benchmark_harness/perf_benchmark_harness.dart';
+import 'package:test/test.dart';
+
+class PerfBenchmark extends PerfBenchmarkBase {
+ PerfBenchmark(super.name);
+ int runCount = 0;
+
+ @override
+ void run() {
+ runCount++;
+ for (final i in List.filled(1000, 7)) {
+ runCount += i - i;
+ }
+ }
+}
+
+void main() {
+ test('run is called', () async {
+ final benchmark = PerfBenchmark('ForLoop');
+ await benchmark.reportPerf();
+ });
+}
diff --git a/pkgs/benchmark_harness/lib/benchmark_harness.dart b/pkgs/benchmark_harness/lib/benchmark_harness.dart
new file mode 100644
index 0000000..b46a36f
--- /dev/null
+++ b/pkgs/benchmark_harness/lib/benchmark_harness.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/async_benchmark_base.dart';
+export 'src/benchmark_base.dart' show BenchmarkBase;
+export 'src/score_emitter.dart';
diff --git a/pkgs/benchmark_harness/lib/perf_benchmark_harness.dart b/pkgs/benchmark_harness/lib/perf_benchmark_harness.dart
new file mode 100644
index 0000000..3de8329
--- /dev/null
+++ b/pkgs/benchmark_harness/lib/perf_benchmark_harness.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/perf_benchmark_base_stub.dart'
+ if (dart.library.io) 'src/perf_benchmark_base.dart';
+export 'src/score_emitter.dart';
diff --git a/pkgs/benchmark_harness/lib/src/async_benchmark_base.dart b/pkgs/benchmark_harness/lib/src/async_benchmark_base.dart
new file mode 100644
index 0000000..1472ee7
--- /dev/null
+++ b/pkgs/benchmark_harness/lib/src/async_benchmark_base.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'score_emitter.dart';
+
+class AsyncBenchmarkBase {
+ final String name;
+ final ScoreEmitter emitter;
+
+ /// Empty constructor.
+ const AsyncBenchmarkBase(this.name, {this.emitter = const PrintEmitter()});
+
+ /// The benchmark code.
+ ///
+ /// This function is not used, if both [warmup] and [exercise] are
+ /// overwritten.
+ Future<void> run() async {}
+
+ /// Runs a short version of the benchmark. By default invokes [run] once.
+ Future<void> warmup() async {
+ await run();
+ }
+
+ /// Exercises the benchmark. By default invokes [run] once.
+ Future<void> exercise() async {
+ await run();
+ }
+
+ /// Not measured setup code executed prior to the benchmark runs.
+ Future<void> setup() async {}
+
+ /// Not measures teardown code executed after the benchmark runs.
+ Future<void> teardown() async {}
+
+ /// Measures the score for this benchmark by executing it repeatedly until
+ /// time minimum has been reached.
+ static Future<double> measureFor(
+ Future<void> Function() f, int minimumMillis) async {
+ final minimumMicros = minimumMillis * 1000;
+ final watch = Stopwatch()..start();
+ var iter = 0;
+ var elapsed = 0;
+ while (elapsed < minimumMicros) {
+ await f();
+ elapsed = watch.elapsedMicroseconds;
+ iter++;
+ }
+ return elapsed / iter;
+ }
+
+ /// Measures the score for the benchmark and returns it.
+ Future<double> measure() async {
+ await setup();
+ try {
+ // Warmup for at least 100ms. Discard result.
+ await measureFor(warmup, 100);
+ // Run the benchmark for at least 2000ms.
+ return await measureFor(exercise, 2000);
+ } finally {
+ await teardown();
+ }
+ }
+
+ /// Run the benchmark and report results on the [emitter].
+ Future<void> report() async {
+ emitter.emit(name, await measure());
+ }
+}
diff --git a/pkgs/benchmark_harness/lib/src/benchmark_base.dart b/pkgs/benchmark_harness/lib/src/benchmark_base.dart
new file mode 100644
index 0000000..bc874f5
--- /dev/null
+++ b/pkgs/benchmark_harness/lib/src/benchmark_base.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' as math;
+
+import 'score_emitter.dart';
+
+const int minimumMeasureDurationMillis = 2000;
+
+class BenchmarkBase {
+ final String name;
+ final ScoreEmitter emitter;
+
+ const BenchmarkBase(this.name, {this.emitter = const PrintEmitter()});
+
+ /// The benchmark code.
+ ///
+ /// This function is not used, if both [warmup] and [exercise] are
+ /// overwritten.
+ void run() {}
+
+ /// Runs a short version of the benchmark. By default invokes [run] once.
+ void warmup() {
+ run();
+ }
+
+ /// Exercises the benchmark. By default invokes [run] 10 times.
+ void exercise() {
+ for (var i = 0; i < 10; i++) {
+ run();
+ }
+ }
+
+ /// Not measured setup code executed prior to the benchmark runs.
+ void setup() {}
+
+ /// Not measured teardown code executed after the benchmark runs.
+ void teardown() {}
+
+ /// Measures the score for this benchmark by executing it enough times
+ /// to reach [minimumMillis].
+
+ /// Measures the score for this benchmark by executing it repeatedly until
+ /// time minimum has been reached.
+ static double measureFor(void Function() f, int minimumMillis) =>
+ measureForImpl(f, minimumMillis).score;
+
+ /// Measures the score for the benchmark and returns it.
+ double measure() {
+ setup();
+ // Warmup for at least 100ms. Discard result.
+ measureForImpl(warmup, 100);
+ // Run the benchmark for at least 2000ms.
+ var result = measureForImpl(exercise, minimumMeasureDurationMillis);
+ teardown();
+ return result.score;
+ }
+
+ void report() {
+ emitter.emit(name, measure());
+ }
+}
+
+/// Measures the score for this benchmark by executing it enough times
+/// to reach [minimumMillis].
+Measurement measureForImpl(void Function() f, int minimumMillis) {
+ final minimumMicros = minimumMillis * 1000;
+ // If running a long measurement permit some amount of measurement jitter
+ // to avoid discarding results that are almost good, but not quite there.
+ final allowedJitter =
+ minimumMillis < 1000 ? 0 : (minimumMicros * 0.1).floor();
+ var iter = 2;
+ var totalIterations = iter;
+ final watch = Stopwatch()..start();
+ while (true) {
+ watch.reset();
+ for (var i = 0; i < iter; i++) {
+ f();
+ }
+ final elapsed = watch.elapsedMicroseconds;
+ final measurement = Measurement(elapsed, iter, totalIterations);
+ if (measurement.elapsedMicros >= (minimumMicros - allowedJitter)) {
+ return measurement;
+ }
+
+ iter = measurement.estimateIterationsNeededToReach(
+ minimumMicros: minimumMicros);
+ totalIterations += iter;
+ }
+}
+
+class Measurement {
+ final int elapsedMicros;
+ final int iterations;
+ final int totalIterations;
+
+ Measurement(this.elapsedMicros, this.iterations, this.totalIterations);
+
+ double get score => elapsedMicros / iterations;
+
+ int estimateIterationsNeededToReach({required int minimumMicros}) {
+ final elapsed = roundDownToMillisecond(elapsedMicros);
+ return elapsed == 0
+ ? iterations * 1000
+ : (iterations * math.max(minimumMicros / elapsed, 1.5)).ceil();
+ }
+
+ static int roundDownToMillisecond(int micros) => (micros ~/ 1000) * 1000;
+
+ @override
+ String toString() => '$elapsedMicros in $iterations iterations';
+}
diff --git a/pkgs/benchmark_harness/lib/src/perf_benchmark_base.dart b/pkgs/benchmark_harness/lib/src/perf_benchmark_base.dart
new file mode 100644
index 0000000..1b7fb92
--- /dev/null
+++ b/pkgs/benchmark_harness/lib/src/perf_benchmark_base.dart
@@ -0,0 +1,135 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'benchmark_base.dart';
+import 'score_emitter.dart';
+
+class PerfBenchmarkBase extends BenchmarkBase {
+ late final Directory fifoDir;
+ late final String perfControlFifo;
+ late final RandomAccessFile openedFifo;
+ late final String perfControlAck;
+ late final RandomAccessFile openedAck;
+ late final Process perfProcess;
+ late final List<String> perfProcessArgs;
+
+ PerfBenchmarkBase(super.name,
+ {ScoreEmitterV2 super.emitter = const PrintEmitterV2()});
+
+ ScoreEmitterV2 get _emitterV2 => emitter as ScoreEmitterV2;
+
+ Future<void> _createFifos() async {
+ perfControlFifo = '${fifoDir.path}/perf_control_fifo';
+ perfControlAck = '${fifoDir.path}/perf_control_ack';
+ for (final path in [perfControlFifo, perfControlAck]) {
+ final fifoResult = await Process.run('mkfifo', [path]);
+ if (fifoResult.exitCode != 0) {
+ throw ProcessException('mkfifo', [path],
+ 'Cannot create fifo: ${fifoResult.stderr}', fifoResult.exitCode);
+ }
+ }
+ }
+
+ Future<void> _startPerfStat() async {
+ await _createFifos();
+ perfProcessArgs = [
+ 'stat',
+ '--delay=-1',
+ '--control=fifo:$perfControlFifo,$perfControlAck',
+ '-x\\t',
+ '--pid=$pid',
+ ];
+ perfProcess = await Process.start('perf', perfProcessArgs);
+ }
+
+ void _enablePerf() {
+ openedFifo = File(perfControlFifo).openSync(mode: FileMode.writeOnly);
+ openedAck = File(perfControlAck).openSync();
+ openedFifo.writeStringSync('enable\n');
+ _waitForAck();
+ }
+
+ Future<void> _stopPerfStat(int totalIterations) async {
+ openedFifo.writeStringSync('disable\n');
+ openedFifo.closeSync();
+ _waitForAck();
+ openedAck.closeSync();
+ perfProcess.kill(ProcessSignal.sigint);
+ unawaited(perfProcess.stdout.drain());
+ final lines = await perfProcess.stderr
+ .transform(utf8.decoder)
+ .transform(const LineSplitter())
+ .toList();
+ final exitCode = await perfProcess.exitCode;
+ // Exit code from perf is -SIGINT when terminated with SIGINT.
+ if (exitCode != 0 && exitCode != -ProcessSignal.sigint.signalNumber) {
+ throw ProcessException(
+ 'perf', perfProcessArgs, lines.join('\n'), exitCode);
+ }
+
+ const metrics = {
+ 'cycles': 'CpuCycles',
+ 'page-faults': 'MajorPageFaults',
+ };
+ for (final line in lines) {
+ if (line.split('\t')
+ case [
+ String counter,
+ _,
+ String event && ('cycles' || 'page-faults'),
+ ...
+ ]) {
+ _emitterV2.emit(name, double.parse(counter) / totalIterations,
+ metric: metrics[event]!);
+ }
+ }
+ _emitterV2.emit('$name.totalIterations', totalIterations.toDouble(),
+ metric: 'Count');
+ }
+
+ /// Measures the score for the benchmark and returns it.
+ Future<double> measurePerf() async {
+ Measurement result;
+ setup();
+ try {
+ fifoDir = await Directory.systemTemp.createTemp('fifo');
+ try {
+ // Warmup for at least 100ms. Discard result.
+ measureForImpl(warmup, 100);
+ await _startPerfStat();
+ try {
+ _enablePerf();
+ // Run the benchmark for at least 2000ms.
+ result = measureForImpl(exercise, minimumMeasureDurationMillis);
+ await _stopPerfStat(result.totalIterations);
+ } catch (_) {
+ perfProcess.kill(ProcessSignal.sigkill);
+ rethrow;
+ }
+ } finally {
+ await fifoDir.delete(recursive: true);
+ }
+ } finally {
+ teardown();
+ }
+ return result.score;
+ }
+
+ Future<void> reportPerf() async {
+ _emitterV2.emit(name, await measurePerf(), unit: 'us.');
+ }
+
+ void _waitForAck() {
+ // Perf writes 'ack\n\x00' to the acknowledgement fifo.
+ const ackLength = 'ack\n\x00'.length;
+ var ack = <int>[...openedAck.readSync(ackLength)];
+ while (ack.length < ackLength) {
+ ack.addAll(openedAck.readSync(ackLength - ack.length));
+ }
+ }
+}
diff --git a/pkgs/benchmark_harness/lib/src/perf_benchmark_base_stub.dart b/pkgs/benchmark_harness/lib/src/perf_benchmark_base_stub.dart
new file mode 100644
index 0000000..81aa0ea
--- /dev/null
+++ b/pkgs/benchmark_harness/lib/src/perf_benchmark_base_stub.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'benchmark_base.dart';
+import 'score_emitter.dart';
+
+class PerfBenchmarkBase extends BenchmarkBase {
+ PerfBenchmarkBase(super.name, {super.emitter = const PrintEmitter()});
+
+ Future<double> measurePerf() async {
+ return super.measure();
+ }
+
+ Future<void> reportPerf() async {
+ super.report();
+ }
+}
diff --git a/pkgs/benchmark_harness/lib/src/score_emitter.dart b/pkgs/benchmark_harness/lib/src/score_emitter.dart
new file mode 100644
index 0000000..4407118
--- /dev/null
+++ b/pkgs/benchmark_harness/lib/src/score_emitter.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class ScoreEmitter {
+ void emit(String testName, double value);
+}
+
+class PrintEmitter implements ScoreEmitter {
+ const PrintEmitter();
+
+ @override
+ void emit(String testName, double value) {
+ print('$testName(RunTime): $value us.');
+ }
+}
+
+/// New interface for [ScoreEmitter]. [ScoreEmitter] will be changed to
+/// this interface in the next major version release, and this class will
+/// be deprecated and removed. That release will be a breaking change.
+abstract class ScoreEmitterV2 implements ScoreEmitter {
+ @override
+ void emit(String testName, double value,
+ {String metric = 'RunTime', String unit});
+}
+
+/// New implementation of [PrintEmitter] implementing the [ScoreEmitterV2]
+/// interface. [PrintEmitter] will be changed to this implementation in the
+/// next major version release.
+class PrintEmitterV2 implements ScoreEmitterV2 {
+ const PrintEmitterV2();
+
+ @override
+ void emit(String testName, double value,
+ {String metric = 'RunTime', String unit = ''}) {
+ print(['$testName($metric):', value, if (unit.isNotEmpty) unit].join(' '));
+ }
+}
diff --git a/pkgs/benchmark_harness/pubspec.yaml b/pkgs/benchmark_harness/pubspec.yaml
new file mode 100644
index 0000000..7d5a9d1
--- /dev/null
+++ b/pkgs/benchmark_harness/pubspec.yaml
@@ -0,0 +1,18 @@
+name: benchmark_harness
+version: 2.3.1
+description: The official Dart project benchmark harness.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/benchmark_harness
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Abenchmark_harness
+
+topics:
+ - benchmarking
+
+environment:
+ sdk: ^3.2.0
+
+dev_dependencies:
+ build_runner: ^2.0.0
+ build_web_compilers: ^4.0.0
+ dart_flutter_team_lints: ^3.0.0
+ path: ^1.8.0
+ test: ^1.16.0
diff --git a/pkgs/benchmark_harness/test/benchmark_harness_test.dart b/pkgs/benchmark_harness/test/benchmark_harness_test.dart
new file mode 100644
index 0000000..7f88584
--- /dev/null
+++ b/pkgs/benchmark_harness/test/benchmark_harness_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('benchmark_harness', () {
+ test('run is called', () {
+ final benchmark = MockBenchmark();
+ final micros = benchmark.measure();
+ expect(micros, isPositive);
+ expect(benchmark.runCount, isPositive);
+ });
+ test('async run is awaited', () async {
+ final benchmark = MockAsyncBenchmark();
+ final micros = await benchmark.measure();
+ expect(micros, isPositive);
+ expect(benchmark.runCount, isPositive);
+ });
+ });
+}
+
+class MockBenchmark extends BenchmarkBase {
+ int runCount = 0;
+
+ MockBenchmark() : super('mock benchmark');
+
+ @override
+ void run() {
+ runCount++;
+ }
+}
+
+class MockAsyncBenchmark extends AsyncBenchmarkBase {
+ int runCount = 0;
+ MockAsyncBenchmark() : super('mock benchmark');
+
+ @override
+ Future<void> run() async {
+ await Future<void>.delayed(Duration.zero);
+ runCount++;
+ }
+}
diff --git a/pkgs/benchmark_harness/test/result_emitter_test.dart b/pkgs/benchmark_harness/test/result_emitter_test.dart
new file mode 100644
index 0000000..e2cd1ea
--- /dev/null
+++ b/pkgs/benchmark_harness/test/result_emitter_test.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:test/test.dart';
+
+void main() {
+ benchmarkHarnessTest();
+}
+
+class MockResultEmitter extends ScoreEmitter {
+ int emitCount = 0;
+
+ @override
+ void emit(String name, double value) {
+ emitCount++;
+ }
+}
+
+// Create a new benchmark which has an emitter.
+class BenchmarkWithResultEmitter extends BenchmarkBase {
+ const BenchmarkWithResultEmitter(ScoreEmitter emitter)
+ : super('Template', emitter: emitter);
+
+ @override
+ void run() {}
+
+ @override
+ void setup() {}
+
+ @override
+ void teardown() {}
+}
+
+void benchmarkHarnessTest() {
+ MockResultEmitter createMockEmitter() {
+ var emitter = MockResultEmitter();
+ return emitter;
+ }
+
+ group('ResultEmitter', () {
+ test('should be called when emitter is provided', () {
+ var emitter = createMockEmitter();
+ var testBenchmark = BenchmarkWithResultEmitter(emitter);
+ testBenchmark.report();
+
+ expect(emitter.emitCount, equals(1));
+ });
+ });
+}
diff --git a/pkgs/boolean_selector/.gitignore b/pkgs/boolean_selector/.gitignore
new file mode 100644
index 0000000..49ce72d
--- /dev/null
+++ b/pkgs/boolean_selector/.gitignore
@@ -0,0 +1,3 @@
+.dart_tool/
+.packages
+pubspec.lock
diff --git a/pkgs/boolean_selector/AUTHORS b/pkgs/boolean_selector/AUTHORS
new file mode 100644
index 0000000..e8063a8
--- /dev/null
+++ b/pkgs/boolean_selector/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/boolean_selector/CHANGELOG.md b/pkgs/boolean_selector/CHANGELOG.md
new file mode 100644
index 0000000..f870787
--- /dev/null
+++ b/pkgs/boolean_selector/CHANGELOG.md
@@ -0,0 +1,44 @@
+## 2.1.2
+
+* Increase the SDK minimum to `3.1.0`.
+* Move to `dart-lang/tools` monorepo.
+
+## 2.1.1
+
+* Increase the SDK minimum to `2.17.0`.
+* Populate the pubspec `repository` field.
+
+## 2.1.0
+
+* Stable release for null safety.
+
+## 2.0.0
+
+* Breaking: `BooleanSelector.evaluate` always takes a `bool Function(String)`.
+ For use cases previously passing a `Set<String>`, tear off the `.contains`
+ method. For use cases passing an `Iterable<String>` it may be worthwhile to
+ first use `.toSet()` before tearing off `.contains`.
+
+## 1.0.5
+
+* Update package metadata & add `example/` folder
+
+## 1.0.4
+
+* Now requires Dart 2.
+
+## 1.0.3
+
+* Work around an inference bug in the new common front-end.
+
+## 1.0.2
+
+* Declare compatibility with `string_scanner` 1.0.0.
+
+## 1.0.1
+
+* Fix all strong mode warnings.
+
+## 1.0.0
+
+* Initial release.
diff --git a/pkgs/boolean_selector/LICENSE b/pkgs/boolean_selector/LICENSE
new file mode 100644
index 0000000..ac7d7af
--- /dev/null
+++ b/pkgs/boolean_selector/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2016, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/boolean_selector/README.md b/pkgs/boolean_selector/README.md
new file mode 100644
index 0000000..8d58dbb
--- /dev/null
+++ b/pkgs/boolean_selector/README.md
@@ -0,0 +1,42 @@
+[](https://github.com/dart-lang/tools/actions/workflows/boolean_selector.yaml)
+[](https://pub.dev/packages/boolean_selector)
+[](https://pub.dev/packages/boolean_selector/publisher)
+
+The `boolean_selector` package defines a simple and flexible syntax for boolean
+expressions. It can be used for filtering based on user-defined expressions. For
+example, the [`test`][test] package uses boolean selectors to allow users to
+define what platforms their tests support.
+
+[test]: https://github.com/dart-lang/test
+
+The boolean selector syntax is based on a simplified version of Dart's
+expression syntax. Selectors can contain identifiers, parentheses, and boolean
+operators, including `||`, `&&`, `!`, and `? :`. Any valid Dart identifier is
+allowed, and identifiers may also contain hyphens. For example, `chrome`,
+`chrome || content-shell`, and `js || (vm && linux)` are all valid boolean
+selectors.
+
+A boolean selector is parsed from a string using
+[`BooleanSelector.parse()`][parse], and evaluated against a set of variables
+using [`BooleanSelector.evaluate()`][evaluate]. The variables are supplied as
+a function that takes a variable name and returns its value. For example:
+
+[parse]: https://pub.dev/documentation/boolean_selector/latest/boolean_selector/BooleanSelector/BooleanSelector.parse.html
+
+[evaluate]: https://pub.dev/documentation/boolean_selector/latest/boolean_selector/BooleanSelector/evaluate.html
+
+```dart
+import 'package:boolean_selector/boolean_selector.dart';
+
+void main(List<String> args) {
+ var selector = BooleanSelector.parse("(x && y) || z");
+ print(selector.evaluate((variable) => args.contains(variable)));
+}
+```
+
+## Versioning
+
+If this package adds new features to the boolean selector syntax, it will
+increment its major version number. This ensures that packages that expose the
+syntax to their users will be able to update their own minor versions, so their
+users can indicate that they rely on the new syntax.
diff --git a/pkgs/boolean_selector/analysis_options.yaml b/pkgs/boolean_selector/analysis_options.yaml
new file mode 100644
index 0000000..af2619a
--- /dev/null
+++ b/pkgs/boolean_selector/analysis_options.yaml
@@ -0,0 +1,6 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+linter:
+ rules:
+ - avoid_unused_constructor_parameters
+ - cancel_subscriptions
diff --git a/pkgs/boolean_selector/example/example.dart b/pkgs/boolean_selector/example/example.dart
new file mode 100644
index 0000000..a4f7879
--- /dev/null
+++ b/pkgs/boolean_selector/example/example.dart
@@ -0,0 +1,6 @@
+import 'package:boolean_selector/boolean_selector.dart';
+
+void main(List<String> args) {
+ var selector = BooleanSelector.parse('(x && y) || z');
+ print(selector.evaluate((variable) => args.contains(variable)));
+}
diff --git a/pkgs/boolean_selector/lib/boolean_selector.dart b/pkgs/boolean_selector/lib/boolean_selector.dart
new file mode 100644
index 0000000..1c42641
--- /dev/null
+++ b/pkgs/boolean_selector/lib/boolean_selector.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+import 'src/all.dart';
+import 'src/impl.dart';
+import 'src/none.dart';
+
+/// A boolean expression that evaluates to `true` or `false` based on certain
+/// inputs.
+///
+/// The syntax is mostly Dart's expression syntax restricted to boolean
+/// operations. See [the README][] for full details.
+///
+/// [the README]: https://github.com/dart-lang/boolean_selector/blob/master/README.md
+///
+/// Boolean selectors support structural equality. Two selectors that have the
+/// same parsed structure are considered equal.
+abstract class BooleanSelector {
+ /// A selector that accepts all inputs.
+ static const all = All();
+
+ /// A selector that accepts no inputs.
+ static const none = None();
+
+ /// All the variables in this selector, in the order they appear.
+ Iterable<String> get variables;
+
+ /// Parses [selector].
+ ///
+ /// This will throw a [SourceSpanFormatException] if the selector is
+ /// malformed or if it uses an undefined variable.
+ factory BooleanSelector.parse(String selector) = BooleanSelectorImpl.parse;
+
+ /// Returns whether the selector matches the given [semantics].
+ ///
+ /// The [semantics] define which variables evaluate to `true` or `false`. When
+ /// passed a variable name it should return the value of that variable.
+ bool evaluate(bool Function(String variable) semantics);
+
+ /// Returns a new [BooleanSelector] that matches only inputs matched by both
+ /// `this` and [other].
+ BooleanSelector intersection(BooleanSelector other);
+
+ /// Returns a new [BooleanSelector] that matches all inputs matched by either
+ /// `this` or [other].
+ BooleanSelector union(BooleanSelector other);
+
+ /// Throws a [FormatException] if any variables are undefined.
+ ///
+ /// The [isDefined] function should return `true` for any variables that are
+ /// considered valid, and `false` for any invalid or undefined variables.
+ void validate(bool Function(String variable) isDefined);
+}
diff --git a/pkgs/boolean_selector/lib/src/all.dart b/pkgs/boolean_selector/lib/src/all.dart
new file mode 100644
index 0000000..3424319
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/all.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../boolean_selector.dart';
+
+/// A selector that matches all inputs.
+class All implements BooleanSelector {
+ // TODO(nweiz): Stop explicitly providing a type argument when sdk#32412 is
+ // fixed.
+ @override
+ final Iterable<String> variables = const <String>[];
+
+ const All();
+
+ @override
+ bool evaluate(bool Function(String variable) semantics) => true;
+
+ @override
+ BooleanSelector intersection(BooleanSelector other) => other;
+
+ @override
+ BooleanSelector union(BooleanSelector other) => this;
+
+ @override
+ void validate(bool Function(String variable) isDefined) {}
+
+ @override
+ String toString() => '<all>';
+}
diff --git a/pkgs/boolean_selector/lib/src/ast.dart b/pkgs/boolean_selector/lib/src/ast.dart
new file mode 100644
index 0000000..d0d8583
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/ast.dart
@@ -0,0 +1,210 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+import 'visitor.dart';
+
+/// The superclass of nodes in the boolean selector abstract syntax tree.
+abstract class Node {
+ /// The span indicating where this node came from.
+ ///
+ /// This is a [FileSpan] because the nodes are parsed from a single continuous
+ /// string, but the string itself isn't actually a file. It might come from a
+ /// statically-parsed annotation or from a parameter.
+ ///
+ /// This may be `null` for nodes without source information.
+ FileSpan? get span;
+
+ /// All the variables in this node, in the order they appear.
+ Iterable<String> get variables;
+
+ /// Calls the appropriate [Visitor] method on `this` and returns the result.
+ T accept<T>(Visitor<T> visitor);
+}
+
+/// A single variable.
+class VariableNode implements Node {
+ @override
+ final FileSpan? span;
+
+ /// The variable name.
+ final String name;
+
+ @override
+ Iterable<String> get variables => [name];
+
+ VariableNode(this.name, [this.span]);
+
+ @override
+ T accept<T>(Visitor<T> visitor) => visitor.visitVariable(this);
+
+ @override
+ String toString() => name;
+
+ @override
+ bool operator ==(Object other) => other is VariableNode && name == other.name;
+
+ @override
+ int get hashCode => name.hashCode;
+}
+
+/// A negation expression.
+class NotNode implements Node {
+ @override
+ final FileSpan? span;
+
+ /// The expression being negated.
+ final Node child;
+
+ @override
+ Iterable<String> get variables => child.variables;
+
+ NotNode(this.child, [this.span]);
+
+ @override
+ T accept<T>(Visitor<T> visitor) => visitor.visitNot(this);
+
+ @override
+ String toString() =>
+ child is VariableNode || child is NotNode ? '!$child' : '!($child)';
+
+ @override
+ bool operator ==(Object other) => other is NotNode && child == other.child;
+
+ @override
+ int get hashCode => ~child.hashCode;
+}
+
+/// An or expression.
+class OrNode implements Node {
+ @override
+ FileSpan? get span => _expandSafe(left.span, right.span);
+
+ /// The left-hand branch of the expression.
+ final Node left;
+
+ /// The right-hand branch of the expression.
+ final Node right;
+
+ @override
+ Iterable<String> get variables sync* {
+ yield* left.variables;
+ yield* right.variables;
+ }
+
+ OrNode(this.left, this.right);
+
+ @override
+ T accept<T>(Visitor<T> visitor) => visitor.visitOr(this);
+
+ @override
+ String toString() {
+ var string1 = left is AndNode || left is ConditionalNode ? '($left)' : left;
+ var string2 =
+ right is AndNode || right is ConditionalNode ? '($right)' : right;
+
+ return '$string1 || $string2';
+ }
+
+ @override
+ bool operator ==(Object other) =>
+ other is OrNode && left == other.left && right == other.right;
+
+ @override
+ int get hashCode => left.hashCode ^ right.hashCode;
+}
+
+/// An and expression.
+class AndNode implements Node {
+ @override
+ FileSpan? get span => _expandSafe(left.span, right.span);
+
+ /// The left-hand branch of the expression.
+ final Node left;
+
+ /// The right-hand branch of the expression.
+ final Node right;
+
+ @override
+ Iterable<String> get variables sync* {
+ yield* left.variables;
+ yield* right.variables;
+ }
+
+ AndNode(this.left, this.right);
+
+ @override
+ T accept<T>(Visitor<T> visitor) => visitor.visitAnd(this);
+
+ @override
+ String toString() {
+ var string1 = left is OrNode || left is ConditionalNode ? '($left)' : left;
+ var string2 =
+ right is OrNode || right is ConditionalNode ? '($right)' : right;
+
+ return '$string1 && $string2';
+ }
+
+ @override
+ bool operator ==(Object other) =>
+ other is AndNode && left == other.left && right == other.right;
+
+ @override
+ int get hashCode => left.hashCode ^ right.hashCode;
+}
+
+/// A ternary conditional expression.
+class ConditionalNode implements Node {
+ @override
+ FileSpan? get span => _expandSafe(condition.span, whenFalse.span);
+
+ /// The condition expression to check.
+ final Node condition;
+
+ /// The branch to run if the condition is true.
+ final Node whenTrue;
+
+ /// The branch to run if the condition is false.
+ final Node whenFalse;
+
+ @override
+ Iterable<String> get variables sync* {
+ yield* condition.variables;
+ yield* whenTrue.variables;
+ yield* whenFalse.variables;
+ }
+
+ ConditionalNode(this.condition, this.whenTrue, this.whenFalse);
+
+ @override
+ T accept<T>(Visitor<T> visitor) => visitor.visitConditional(this);
+
+ @override
+ String toString() {
+ var conditionString =
+ condition is ConditionalNode ? '($condition)' : condition;
+ var trueString = whenTrue is ConditionalNode ? '($whenTrue)' : whenTrue;
+ return '$conditionString ? $trueString : $whenFalse';
+ }
+
+ @override
+ bool operator ==(Object other) =>
+ other is ConditionalNode &&
+ condition == other.condition &&
+ whenTrue == other.whenTrue &&
+ whenFalse == other.whenFalse;
+
+ @override
+ int get hashCode =>
+ condition.hashCode ^ whenTrue.hashCode ^ whenFalse.hashCode;
+}
+
+/// Like [FileSpan.expand], except if [start] and [end] are `null` or from
+/// different files it returns `null` rather than throwing an error.
+FileSpan? _expandSafe(FileSpan? start, FileSpan? end) {
+ if (start == null || end == null) return null;
+ if (start.file != end.file) return null;
+ return start.expand(end);
+}
diff --git a/pkgs/boolean_selector/lib/src/evaluator.dart b/pkgs/boolean_selector/lib/src/evaluator.dart
new file mode 100644
index 0000000..ee57149
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/evaluator.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'ast.dart';
+import 'visitor.dart';
+
+/// A visitor for evaluating boolean selectors against a specific set of
+/// semantics.
+class Evaluator implements Visitor<bool> {
+ final bool Function(String variable) _semantics;
+
+ Evaluator(this._semantics);
+
+ @override
+ bool visitVariable(VariableNode node) => _semantics(node.name);
+
+ @override
+ bool visitNot(NotNode node) => !node.child.accept(this);
+
+ @override
+ bool visitOr(OrNode node) =>
+ node.left.accept(this) || node.right.accept(this);
+
+ @override
+ bool visitAnd(AndNode node) =>
+ node.left.accept(this) && node.right.accept(this);
+
+ @override
+ bool visitConditional(ConditionalNode node) => node.condition.accept(this)
+ ? node.whenTrue.accept(this)
+ : node.whenFalse.accept(this);
+}
diff --git a/pkgs/boolean_selector/lib/src/impl.dart b/pkgs/boolean_selector/lib/src/impl.dart
new file mode 100644
index 0000000..cafb1a4
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/impl.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+import '../boolean_selector.dart';
+import 'ast.dart';
+import 'evaluator.dart';
+import 'intersection_selector.dart';
+import 'parser.dart';
+import 'union_selector.dart';
+import 'validator.dart';
+
+/// The concrete implementation of a [BooleanSelector] parsed from a string.
+///
+/// This is separate from [BooleanSelector] so that [intersection] and [union]
+/// can check to see whether they're passed a [BooleanSelectorImpl] or a
+/// different class that implements [BooleanSelector].
+class BooleanSelectorImpl implements BooleanSelector {
+ /// The parsed AST.
+ final Node _selector;
+
+ /// Parses [selector].
+ ///
+ /// This will throw a [SourceSpanFormatException] if the selector is
+ /// malformed or if it uses an undefined variable.
+ BooleanSelectorImpl.parse(String selector)
+ : _selector = Parser(selector).parse();
+
+ BooleanSelectorImpl._(this._selector);
+
+ @override
+ Iterable<String> get variables => _selector.variables;
+
+ @override
+ bool evaluate(bool Function(String variable) semantics) =>
+ _selector.accept(Evaluator(semantics));
+
+ @override
+ BooleanSelector intersection(BooleanSelector other) {
+ if (other == BooleanSelector.all) return this;
+ if (other == BooleanSelector.none) return other;
+ return other is BooleanSelectorImpl
+ ? BooleanSelectorImpl._(AndNode(_selector, other._selector))
+ : IntersectionSelector(this, other);
+ }
+
+ @override
+ BooleanSelector union(BooleanSelector other) {
+ if (other == BooleanSelector.all) return other;
+ if (other == BooleanSelector.none) return this;
+ return other is BooleanSelectorImpl
+ ? BooleanSelectorImpl._(OrNode(_selector, other._selector))
+ : UnionSelector(this, other);
+ }
+
+ @override
+ void validate(bool Function(String variable) isDefined) {
+ _selector.accept(Validator(isDefined));
+ }
+
+ @override
+ String toString() => _selector.toString();
+
+ @override
+ bool operator ==(Object other) =>
+ other is BooleanSelectorImpl && _selector == other._selector;
+
+ @override
+ int get hashCode => _selector.hashCode;
+}
diff --git a/pkgs/boolean_selector/lib/src/intersection_selector.dart b/pkgs/boolean_selector/lib/src/intersection_selector.dart
new file mode 100644
index 0000000..3bf468c
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/intersection_selector.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../boolean_selector.dart';
+import 'union_selector.dart';
+
+/// A selector that matches inputs that both of its sub-selectors match.
+class IntersectionSelector implements BooleanSelector {
+ final BooleanSelector _selector1;
+ final BooleanSelector _selector2;
+
+ @override
+ Iterable<String> get variables sync* {
+ yield* _selector1.variables;
+ yield* _selector2.variables;
+ }
+
+ IntersectionSelector(this._selector1, this._selector2);
+
+ @override
+ bool evaluate(bool Function(String variable) semantics) =>
+ _selector1.evaluate(semantics) && _selector2.evaluate(semantics);
+
+ @override
+ BooleanSelector intersection(BooleanSelector other) =>
+ IntersectionSelector(this, other);
+
+ @override
+ BooleanSelector union(BooleanSelector other) => UnionSelector(this, other);
+
+ @override
+ void validate(bool Function(String variable) isDefined) {
+ _selector1.validate(isDefined);
+ _selector2.validate(isDefined);
+ }
+
+ @override
+ String toString() => '($_selector1) && ($_selector2)';
+
+ @override
+ bool operator ==(Object other) =>
+ other is IntersectionSelector &&
+ _selector1 == other._selector1 &&
+ _selector2 == other._selector2;
+
+ @override
+ int get hashCode => _selector1.hashCode ^ _selector2.hashCode;
+}
diff --git a/pkgs/boolean_selector/lib/src/none.dart b/pkgs/boolean_selector/lib/src/none.dart
new file mode 100644
index 0000000..08ac08a
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/none.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../boolean_selector.dart';
+
+/// A selector that matches no inputs.
+class None implements BooleanSelector {
+ @override
+ final Iterable<String> variables = const [];
+
+ const None();
+
+ @override
+ bool evaluate(bool Function(String variable) semantics) => false;
+
+ @override
+ BooleanSelector intersection(BooleanSelector other) => this;
+
+ @override
+ BooleanSelector union(BooleanSelector other) => other;
+
+ @override
+ void validate(bool Function(String) isDefined) {}
+
+ @override
+ String toString() => '<none>';
+}
diff --git a/pkgs/boolean_selector/lib/src/parser.dart b/pkgs/boolean_selector/lib/src/parser.dart
new file mode 100644
index 0000000..368ce5e
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/parser.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+import 'ast.dart';
+import 'scanner.dart';
+import 'token.dart';
+
+/// A class for parsing a boolean selector.
+///
+/// Boolean selectors use a stripped-down version of the Dart expression syntax
+/// that only contains variables, parentheses, and boolean operators. Variables
+/// may also contain dashes, contrary to Dart's syntax; this allows consistency
+/// with command-line arguments.
+class Parser {
+ /// The scanner that tokenizes the selector.
+ final Scanner _scanner;
+
+ Parser(String selector) : _scanner = Scanner(selector);
+
+ /// Parses the selector.
+ ///
+ /// This must only be called once per parser.
+ Node parse() {
+ var selector = _conditional();
+
+ if (_scanner.peek().type != TokenType.endOfFile) {
+ throw SourceSpanFormatException(
+ 'Expected end of input.', _scanner.peek().span);
+ }
+
+ return selector;
+ }
+
+ /// Parses a conditional:
+ ///
+ /// conditionalExpression:
+ /// logicalOrExpression ("?" conditionalExpression ":"
+ /// conditionalExpression)?
+ Node _conditional() {
+ var condition = _or();
+ if (!_scanner.scan(TokenType.questionMark)) return condition;
+
+ var whenTrue = _conditional();
+ if (!_scanner.scan(TokenType.colon)) {
+ throw SourceSpanFormatException('Expected ":".', _scanner.peek().span);
+ }
+
+ var whenFalse = _conditional();
+ return ConditionalNode(condition, whenTrue, whenFalse);
+ }
+
+ /// Parses a logical or:
+ ///
+ /// logicalOrExpression:
+ /// logicalAndExpression ("||" logicalOrExpression)?
+ Node _or() {
+ var left = _and();
+ if (!_scanner.scan(TokenType.or)) return left;
+ return OrNode(left, _or());
+ }
+
+ /// Parses a logical and:
+ ///
+ /// logicalAndExpression:
+ /// simpleExpression ("&&" logicalAndExpression)?
+ Node _and() {
+ var left = _simpleExpression();
+ if (!_scanner.scan(TokenType.and)) return left;
+ return AndNode(left, _and());
+ }
+
+ /// Parses a simple expression:
+ ///
+ /// simpleExpression:
+ /// "!" simpleExpression |
+ /// "(" conditionalExpression ")" |
+ /// IDENTIFIER
+ Node _simpleExpression() {
+ var token = _scanner.next();
+ switch (token.type) {
+ case TokenType.not:
+ var child = _simpleExpression();
+ return NotNode(child, token.span.expand(child.span!));
+
+ case TokenType.leftParen:
+ var child = _conditional();
+ if (!_scanner.scan(TokenType.rightParen)) {
+ throw SourceSpanFormatException(
+ 'Expected ")".', _scanner.peek().span);
+ }
+ return child;
+
+ case TokenType.identifier:
+ return VariableNode((token as IdentifierToken).name, token.span);
+
+ default:
+ throw SourceSpanFormatException('Expected expression.', token.span);
+ }
+ }
+}
diff --git a/pkgs/boolean_selector/lib/src/scanner.dart b/pkgs/boolean_selector/lib/src/scanner.dart
new file mode 100644
index 0000000..25c4a11
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/scanner.dart
@@ -0,0 +1,144 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:string_scanner/string_scanner.dart';
+
+import 'token.dart';
+
+/// A regular expression matching both whitespace and single-line comments.
+///
+/// This will only match if consumes at least one character.
+final _whitespaceAndSingleLineComments = RegExp(r'([ \t\n]+|//[^\n]*(\n|$))+');
+
+/// A regular expression matching the body of a multi-line comment, after `/*`
+/// but before `*/` or a nested `/*`.
+///
+/// This will only match if it consumes at least one character.
+final _multiLineCommentBody = RegExp(r'([^/*]|/[^*]|\*[^/])+');
+
+/// A regular expression matching a hyphenated identifier.
+///
+/// This is like a standard Dart identifier, except that it can also contain
+/// hyphens.
+final _hyphenatedIdentifier = RegExp(r'[a-zA-Z_-][a-zA-Z0-9_-]*');
+
+/// A scanner that converts a boolean selector string into a stream of tokens.
+class Scanner {
+ /// The underlying string scanner.
+ final SpanScanner _scanner;
+
+ /// The next token to emit.
+ Token? _next;
+
+ /// Whether the scanner has emitted a [TokenType.endOfFile] token.
+ bool _endOfFileEmitted = false;
+
+ Scanner(String selector) : _scanner = SpanScanner(selector);
+
+ /// Returns the next token that will be returned by [next].
+ ///
+ /// Throws a [StateError] if a [TokenType.endOfFile] token has already been
+ /// consumed.
+ Token peek() => _next ??= _readNext();
+
+ /// Consumes and returns the next token in the stream.
+ ///
+ /// Throws a [StateError] if a [TokenType.endOfFile] token has already been
+ /// consumed.
+ Token next() {
+ var token = _next ?? _readNext();
+ _endOfFileEmitted = token.type == TokenType.endOfFile;
+ _next = null;
+ return token;
+ }
+
+ /// If the next token matches [type], consumes it and returns `true`;
+ /// otherwise, returns `false`.
+ ///
+ /// Throws a [StateError] if a [TokenType.endOfFile] token has already been
+ /// consumed.
+ bool scan(TokenType type) {
+ if (peek().type != type) return false;
+ next();
+ return true;
+ }
+
+ /// Scan and return the next token in the stream.
+ Token _readNext() {
+ if (_endOfFileEmitted) throw StateError('No more tokens.');
+
+ _consumeWhitespace();
+ if (_scanner.isDone) {
+ return Token(TokenType.endOfFile, _scanner.spanFrom(_scanner.state));
+ }
+
+ return switch (_scanner.peekChar()) {
+ 0x28 /* ( */ => _scanOperator(TokenType.leftParen),
+ 0x29 /* ) */ => _scanOperator(TokenType.rightParen),
+ 0x3F /* ? */ => _scanOperator(TokenType.questionMark),
+ 0x3A /* : */ => _scanOperator(TokenType.colon),
+ 0x21 /* ! */ => _scanOperator(TokenType.not),
+ 0x7C /* | */ => _scanOr(),
+ 0x26 /* & */ => _scanAnd(),
+ _ => _scanIdentifier()
+ };
+ }
+
+ /// Scans a single-character operator and returns a token of type [type].
+ ///
+ /// This assumes that the caller has already verified that the next character
+ /// is correct for the given operator.
+ Token _scanOperator(TokenType type) {
+ var start = _scanner.state;
+ _scanner.readChar();
+ return Token(type, _scanner.spanFrom(start));
+ }
+
+ /// Scans a `||` operator and returns the appropriate token.
+ ///
+ /// This validates that the next two characters are `||`.
+ Token _scanOr() {
+ var start = _scanner.state;
+ _scanner.expect('||');
+ return Token(TokenType.or, _scanner.spanFrom(start));
+ }
+
+ /// Scans a `&&` operator and returns the appropriate token.
+ ///
+ /// This validates that the next two characters are `&&`.
+ Token _scanAnd() {
+ var start = _scanner.state;
+ _scanner.expect('&&');
+ return Token(TokenType.and, _scanner.spanFrom(start));
+ }
+
+ /// Scans and returns an identifier token.
+ Token _scanIdentifier() {
+ _scanner.expect(_hyphenatedIdentifier, name: 'expression');
+ return IdentifierToken(_scanner.lastMatch![0]!, _scanner.lastSpan!);
+ }
+
+ /// Consumes all whitespace and comments immediately following the cursor's
+ /// current position.
+ void _consumeWhitespace() {
+ while (_scanner.scan(_whitespaceAndSingleLineComments) ||
+ _multiLineComment()) {
+ // Do nothing.
+ }
+ }
+
+ /// Consumes a single multi-line comment.
+ ///
+ /// Returns whether or not a comment was consumed.
+ bool _multiLineComment() {
+ if (!_scanner.scan('/*')) return false;
+
+ while (_scanner.scan(_multiLineCommentBody) || _multiLineComment()) {
+ // Do nothing.
+ }
+ _scanner.expect('*/');
+
+ return true;
+ }
+}
diff --git a/pkgs/boolean_selector/lib/src/token.dart b/pkgs/boolean_selector/lib/src/token.dart
new file mode 100644
index 0000000..19e6864
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/token.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+/// A token in a boolean selector.
+class Token {
+ /// The type of the token.
+ final TokenType type;
+
+ /// The span indicating where this token came from.
+ ///
+ /// This is a [FileSpan] because the tokens are parsed from a single
+ /// continuous string, but the string itself isn't actually a file. It might
+ /// come from a statically-parsed annotation or from a parameter.
+ final FileSpan span;
+
+ Token(this.type, this.span);
+}
+
+/// A token representing an identifier.
+class IdentifierToken implements Token {
+ @override
+ final type = TokenType.identifier;
+ @override
+ final FileSpan span;
+
+ /// The name of the identifier.
+ final String name;
+
+ IdentifierToken(this.name, this.span);
+
+ @override
+ String toString() => 'identifier "$name"';
+}
+
+/// An enumeration of types of tokens.
+class TokenType {
+ /// A `(` character.
+ static const leftParen = TokenType._('left paren');
+
+ /// A `)` character.
+ static const rightParen = TokenType._('right paren');
+
+ /// A `||` sequence.
+ static const or = TokenType._('or');
+
+ /// A `&&` sequence.
+ static const and = TokenType._('and');
+
+ /// A `!` character.
+ static const not = TokenType._('not');
+
+ /// A `?` character.
+ static const questionMark = TokenType._('question mark');
+
+ /// A `:` character.
+ static const colon = TokenType._('colon');
+
+ /// A named identifier.
+ static const identifier = TokenType._('identifier');
+
+ /// The end of the selector.
+ static const endOfFile = TokenType._('end of file');
+
+ /// The name of the token type.
+ final String name;
+
+ const TokenType._(this.name);
+
+ @override
+ String toString() => name;
+}
diff --git a/pkgs/boolean_selector/lib/src/union_selector.dart b/pkgs/boolean_selector/lib/src/union_selector.dart
new file mode 100644
index 0000000..e355eb2
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/union_selector.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../boolean_selector.dart';
+import 'intersection_selector.dart';
+
+/// A selector that matches inputs that either of its sub-selectors match.
+class UnionSelector implements BooleanSelector {
+ final BooleanSelector _selector1;
+ final BooleanSelector _selector2;
+
+ UnionSelector(this._selector1, this._selector2);
+
+ @override
+ List<String> get variables =>
+ _selector1.variables.toList()..addAll(_selector2.variables);
+
+ @override
+ bool evaluate(bool Function(String variable) semantics) =>
+ _selector1.evaluate(semantics) || _selector2.evaluate(semantics);
+
+ @override
+ BooleanSelector intersection(BooleanSelector other) =>
+ IntersectionSelector(this, other);
+
+ @override
+ BooleanSelector union(BooleanSelector other) => UnionSelector(this, other);
+
+ @override
+ void validate(bool Function(String variable) isDefined) {
+ _selector1.validate(isDefined);
+ _selector2.validate(isDefined);
+ }
+
+ @override
+ String toString() => '($_selector1) && ($_selector2)';
+
+ @override
+ bool operator ==(Object other) =>
+ other is UnionSelector &&
+ _selector1 == other._selector1 &&
+ _selector2 == other._selector2;
+
+ @override
+ int get hashCode => _selector1.hashCode ^ _selector2.hashCode;
+}
diff --git a/pkgs/boolean_selector/lib/src/validator.dart b/pkgs/boolean_selector/lib/src/validator.dart
new file mode 100644
index 0000000..a7f49f2
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/validator.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+import 'ast.dart';
+import 'visitor.dart';
+
+typedef _IsDefined = bool Function(String variable);
+
+/// An AST visitor that ensures that all variables are valid.
+class Validator extends RecursiveVisitor {
+ final _IsDefined _isDefined;
+
+ Validator(this._isDefined);
+
+ @override
+ void visitVariable(VariableNode node) {
+ if (_isDefined(node.name)) return;
+ throw SourceSpanFormatException('Undefined variable.', node.span);
+ }
+}
diff --git a/pkgs/boolean_selector/lib/src/visitor.dart b/pkgs/boolean_selector/lib/src/visitor.dart
new file mode 100644
index 0000000..c6808c2
--- /dev/null
+++ b/pkgs/boolean_selector/lib/src/visitor.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'ast.dart';
+
+/// The interface for visitors of the boolean selector AST.
+abstract class Visitor<T> {
+ T visitVariable(VariableNode node);
+ T visitNot(NotNode node);
+ T visitOr(OrNode node);
+ T visitAnd(AndNode node);
+ T visitConditional(ConditionalNode node);
+}
+
+/// An abstract superclass for side-effect-based visitors.
+///
+/// The default implementations of this visitor's methods just traverse the AST
+/// and do nothing with it.
+abstract class RecursiveVisitor implements Visitor<void> {
+ const RecursiveVisitor();
+
+ @override
+ void visitVariable(VariableNode node) {}
+
+ @override
+ void visitNot(NotNode node) {
+ node.child.accept(this);
+ }
+
+ @override
+ void visitOr(OrNode node) {
+ node.left.accept(this);
+ node.right.accept(this);
+ }
+
+ @override
+ void visitAnd(AndNode node) {
+ node.left.accept(this);
+ node.right.accept(this);
+ }
+
+ @override
+ void visitConditional(ConditionalNode node) {
+ node.condition.accept(this);
+ node.whenTrue.accept(this);
+ node.whenFalse.accept(this);
+ }
+}
diff --git a/pkgs/boolean_selector/pubspec.yaml b/pkgs/boolean_selector/pubspec.yaml
new file mode 100644
index 0000000..89e49cc
--- /dev/null
+++ b/pkgs/boolean_selector/pubspec.yaml
@@ -0,0 +1,18 @@
+name: boolean_selector
+version: 2.1.2
+description: >-
+ A flexible syntax for boolean expressions, based on a simplified version of
+ Dart's expression syntax.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/boolean_selector
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aboolean_selector
+
+environment:
+ sdk: ^3.1.0
+
+dependencies:
+ source_span: ^1.8.0
+ string_scanner: ^1.1.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.0
diff --git a/pkgs/boolean_selector/test/equality_test.dart b/pkgs/boolean_selector/test/equality_test.dart
new file mode 100644
index 0000000..c5ccb64
--- /dev/null
+++ b/pkgs/boolean_selector/test/equality_test.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:boolean_selector/boolean_selector.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('variable', () {
+ _expectEqualsSelf('foo');
+ });
+
+ test('not', () {
+ _expectEqualsSelf('!foo');
+ });
+
+ test('or', () {
+ _expectEqualsSelf('foo || bar');
+ });
+
+ test('and', () {
+ _expectEqualsSelf('foo && bar');
+ });
+
+ test('conditional', () {
+ _expectEqualsSelf('foo ? bar : baz');
+ });
+
+ test('all', () {
+ expect(BooleanSelector.all, equals(BooleanSelector.all));
+ });
+
+ test('none', () {
+ expect(BooleanSelector.none, equals(BooleanSelector.none));
+ });
+
+ test("redundant parens don't matter", () {
+ expect(BooleanSelector.parse('foo && (bar && baz)'),
+ equals(BooleanSelector.parse('foo && (bar && baz)')));
+ });
+
+ test('meaningful parens do matter', () {
+ expect(BooleanSelector.parse('(foo && bar) || baz'),
+ equals(BooleanSelector.parse('foo && bar || baz')));
+ });
+}
+
+void _expectEqualsSelf(String selector) {
+ expect(
+ BooleanSelector.parse(selector), equals(BooleanSelector.parse(selector)));
+}
diff --git a/pkgs/boolean_selector/test/evaluate_test.dart b/pkgs/boolean_selector/test/evaluate_test.dart
new file mode 100644
index 0000000..2d94906
--- /dev/null
+++ b/pkgs/boolean_selector/test/evaluate_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:boolean_selector/boolean_selector.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('operator:', () {
+ test('conditional', () {
+ _expectEval('true ? true : false', true);
+ _expectEval('true ? false : true', false);
+ _expectEval('false ? true : false', false);
+ _expectEval('false ? false : true', true);
+ });
+
+ test('or', () {
+ _expectEval('true || true', true);
+ _expectEval('true || false', true);
+ _expectEval('false || true', true);
+ _expectEval('false || false', false);
+ });
+
+ test('and', () {
+ _expectEval('true && true', true);
+ _expectEval('true && false', false);
+ _expectEval('false && true', false);
+ _expectEval('false && false', false);
+ });
+
+ test('not', () {
+ _expectEval('!true', false);
+ _expectEval('!false', true);
+ });
+ });
+
+ test('with a semantics function', () {
+ _expectEval('foo', false, semantics: (variable) => variable.contains('a'));
+ _expectEval('bar', true, semantics: (variable) => variable.contains('a'));
+ _expectEval('baz', true, semantics: (variable) => variable.contains('a'));
+ });
+}
+
+/// Asserts that [expression] evaluates to [result] against [semantics].
+///
+/// By default, "true" is true and all other variables are "false".
+void _expectEval(String expression, bool result,
+ {bool Function(String variable)? semantics}) {
+ expect(_eval(expression, semantics: semantics), equals(result),
+ reason: 'Expected "$expression" to evaluate to $result.');
+}
+
+/// Returns the result of evaluating [expression] on [semantics].
+///
+/// By default, "true" is true and all other variables are "false".
+bool _eval(String expression, {bool Function(String variable)? semantics}) {
+ var selector = BooleanSelector.parse(expression);
+ return selector.evaluate(semantics ?? (v) => v == 'true');
+}
diff --git a/pkgs/boolean_selector/test/parser_test.dart b/pkgs/boolean_selector/test/parser_test.dart
new file mode 100644
index 0000000..ba55e70
--- /dev/null
+++ b/pkgs/boolean_selector/test/parser_test.dart
@@ -0,0 +1,298 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:boolean_selector/src/ast.dart';
+import 'package:boolean_selector/src/parser.dart';
+import 'package:test/test.dart';
+
+/// A matcher that asserts that a value is a [ConditionalNode].
+const _isConditionalNode = TypeMatcher<ConditionalNode>();
+
+/// A matcher that asserts that a value is an [OrNode].
+const _isOrNode = TypeMatcher<OrNode>();
+
+/// A matcher that asserts that a value is an [AndNode].
+const _isAndNode = TypeMatcher<AndNode>();
+
+/// A matcher that asserts that a value is a [NotNode].
+const _isNotNode = TypeMatcher<NotNode>();
+
+void main() {
+ group('parses a conditional expression', () {
+ test('with identifiers', () {
+ var node = _parse(' a ? b : c ');
+ expect(node.toString(), equals('a ? b : c'));
+
+ expect(node.span, isNotNull);
+ expect(node.span!.text, equals('a ? b : c'));
+ expect(node.span!.start.offset, equals(2));
+ expect(node.span!.end.offset, equals(11));
+ });
+
+ test('with nested ors', () {
+ // Should parse as "(a || b) ? (c || d) : (e || f)".
+ // Should not parse as "a || (b ? (c || d) : (e || f))".
+ // Should not parse as "((a || b) ? (c || d) : e) || f".
+ // Should not parse as "a || (b ? (c || d) : e) || f".
+ _expectToString('a || b ? c || d : e || f', 'a || b ? c || d : e || f');
+ });
+
+ test('with a conditional expression as branch 1', () {
+ // Should parse as "a ? (b ? c : d) : e".
+ var node = _parse('a ? b ? c : d : e');
+ expect(node, _isConditionalNode);
+ node as ConditionalNode; // promote node
+
+ expect(node.condition, _isVar('a'));
+ expect(node.whenFalse, _isVar('e'));
+
+ expect(node.whenTrue, _isConditionalNode);
+ var whenTrue = node.whenTrue as ConditionalNode;
+ expect(whenTrue.condition, _isVar('b'));
+ expect(whenTrue.whenTrue, _isVar('c'));
+ expect(whenTrue.whenFalse, _isVar('d'));
+ });
+
+ test('with a conditional expression as branch 2', () {
+ // Should parse as "a ? b : (c ? d : e)".
+ // Should not parse as "(a ? b : c) ? d : e".
+ var node = _parse('a ? b : c ? d : e');
+ expect(node, _isConditionalNode);
+ node as ConditionalNode; //promote node
+
+ expect(node.condition, _isVar('a'));
+ expect(node.whenTrue, _isVar('b'));
+
+ expect(node.whenFalse, _isConditionalNode);
+ var whenFalse = node.whenFalse as ConditionalNode;
+ expect(whenFalse.condition, _isVar('c'));
+ expect(whenFalse.whenTrue, _isVar('d'));
+ expect(whenFalse.whenFalse, _isVar('e'));
+ });
+
+ group('which must have', () {
+ test('an expression after the ?', () {
+ expect(() => _parse('a ?'), throwsFormatException);
+ expect(() => _parse('a ? && b'), throwsFormatException);
+ });
+
+ test('a :', () {
+ expect(() => _parse('a ? b'), throwsFormatException);
+ expect(() => _parse('a ? b && c'), throwsFormatException);
+ });
+
+ test('an expression after the :', () {
+ expect(() => _parse('a ? b :'), throwsFormatException);
+ expect(() => _parse('a ? b : && c'), throwsFormatException);
+ });
+ });
+ });
+
+ group('parses an or expression', () {
+ test('with identifiers', () {
+ var node = _parse(' a || b ');
+ expect(node, _isOrNode);
+ node as OrNode; //promote node
+
+ expect(node.left, _isVar('a'));
+ expect(node.right, _isVar('b'));
+
+ expect(node.span, isNotNull);
+ expect(node.span!.text, equals('a || b'));
+ expect(node.span!.start.offset, equals(2));
+ expect(node.span!.end.offset, equals(8));
+ });
+
+ test('with nested ands', () {
+ // Should parse as "(a && b) || (c && d)".
+ // Should not parse as "a && (b || c) && d".
+ var node = _parse('a && b || c && d');
+ expect(node, _isOrNode);
+ node as OrNode; //promote node
+
+ expect(node.left, _isAndNode);
+ var left = node.left as AndNode;
+ expect(left.left, _isVar('a'));
+ expect(left.right, _isVar('b'));
+
+ expect(node.right, _isAndNode);
+ var right = node.right as AndNode;
+ expect(right.left, _isVar('c'));
+ expect(right.right, _isVar('d'));
+ });
+
+ test('with trailing ors', () {
+ // Should parse as "a || (b || (c || d))", although it doesn't affect the
+ // semantics.
+ var node = _parse('a || b || c || d');
+
+ for (var variable in ['a', 'b', 'c']) {
+ expect(node, _isOrNode);
+ node as OrNode; //promote node
+
+ expect(node.left, _isVar(variable));
+ node = node.right;
+ }
+ expect(node, _isVar('d'));
+ });
+
+ test('which must have an expression after the ||', () {
+ expect(() => _parse('a ||'), throwsFormatException);
+ expect(() => _parse('a || && b'), throwsFormatException);
+ });
+ });
+
+ group('parses an and expression', () {
+ test('with identifiers', () {
+ var node = _parse(' a && b ');
+ expect(node, _isAndNode);
+ node as AndNode; //promote node
+
+ expect(node.left, _isVar('a'));
+ expect(node.right, _isVar('b'));
+
+ expect(node.span, isNotNull);
+ expect(node.span!.text, equals('a && b'));
+ expect(node.span!.start.offset, equals(2));
+ expect(node.span!.end.offset, equals(8));
+ });
+
+ test('with nested nots', () {
+ // Should parse as "(!a) && (!b)", obviously.
+ // Should not parse as "!(a && (!b))".
+ var node = _parse('!a && !b');
+ expect(node, _isAndNode);
+ node as AndNode; //promote node
+
+ expect(node.left, _isNotNode);
+ var left = node.left as NotNode;
+ expect(left.child, _isVar('a'));
+
+ expect(node.right, _isNotNode);
+ var right = node.right as NotNode;
+ expect(right.child, _isVar('b'));
+ });
+
+ test('with trailing ands', () {
+ // Should parse as "a && (b && (c && d))", although it doesn't affect the
+ // semantics since .
+ var node = _parse('a && b && c && d');
+
+ for (var variable in ['a', 'b', 'c']) {
+ expect(node, _isAndNode);
+ node as AndNode; //promote node
+
+ expect(node.left, _isVar(variable));
+ node = node.right;
+ }
+ expect(node, _isVar('d'));
+ });
+
+ test('which must have an expression after the &&', () {
+ expect(() => _parse('a &&'), throwsFormatException);
+ expect(() => _parse('a && && b'), throwsFormatException);
+ });
+ });
+
+ group('parses a not expression', () {
+ test('with an identifier', () {
+ var node = _parse(' ! a ');
+ expect(node, _isNotNode);
+ node as NotNode; //promote node
+ expect(node.child, _isVar('a'));
+
+ expect(node.span, isNotNull);
+ expect(node.span!.text, equals('! a'));
+ expect(node.span!.start.offset, equals(2));
+ expect(node.span!.end.offset, equals(5));
+ });
+
+ test('with a parenthesized expression', () {
+ var node = _parse('!(a || b)');
+ expect(node, _isNotNode);
+ node as NotNode; //promote node
+
+ expect(node.child, _isOrNode);
+ var child = node.child as OrNode;
+ expect(child.left, _isVar('a'));
+ expect(child.right, _isVar('b'));
+ });
+
+ test('with a nested not', () {
+ var node = _parse('!!a');
+ expect(node, _isNotNode);
+ node as NotNode; //promote node
+
+ expect(node.child, _isNotNode);
+ var child = node.child as NotNode;
+ expect(child.child, _isVar('a'));
+ });
+
+ test('which must have an expression after the !', () {
+ expect(() => _parse('!'), throwsFormatException);
+ expect(() => _parse('! && a'), throwsFormatException);
+ });
+ });
+
+ group('parses a parenthesized expression', () {
+ test('with an identifier', () {
+ var node = _parse('(a)');
+ expect(node, _isVar('a'));
+ });
+
+ test('controls precedence', () {
+ // Without parentheses, this would parse as "(a || b) ? c : d".
+ var node = _parse('a || (b ? c : d)');
+
+ expect(node, _isOrNode);
+ node as OrNode; //promote node
+
+ expect(node.left, _isVar('a'));
+
+ expect(node.right, _isConditionalNode);
+ var right = node.right as ConditionalNode;
+ expect(right.condition, _isVar('b'));
+ expect(right.whenTrue, _isVar('c'));
+ expect(right.whenFalse, _isVar('d'));
+ });
+
+ group('which must have', () {
+ test('an expression within the ()', () {
+ expect(() => _parse('()'), throwsFormatException);
+ expect(() => _parse('( && a )'), throwsFormatException);
+ });
+
+ test('a matching )', () {
+ expect(() => _parse('( a'), throwsFormatException);
+ });
+ });
+ });
+
+ group('disallows', () {
+ test('an empty selector', () {
+ expect(() => _parse(''), throwsFormatException);
+ });
+
+ test('too many expressions', () {
+ expect(() => _parse('a b'), throwsFormatException);
+ });
+ });
+}
+
+/// Parses [selector] and returns its root node.
+Node _parse(String selector) => Parser(selector).parse();
+
+/// A matcher that asserts that a value is a [VariableNode] with the given
+/// [name].
+Matcher _isVar(String name) => predicate(
+ (dynamic value) => value is VariableNode && value.name == name,
+ 'is a variable named "$name"');
+
+void _expectToString(String selector, [String? result]) {
+ result ??= selector;
+ expect(_toString(selector), equals(result),
+ reason: 'Expected toString of "$selector" to be "$result".');
+}
+
+String _toString(String selector) => Parser(selector).parse().toString();
diff --git a/pkgs/boolean_selector/test/scanner_test.dart b/pkgs/boolean_selector/test/scanner_test.dart
new file mode 100644
index 0000000..7ad78e2
--- /dev/null
+++ b/pkgs/boolean_selector/test/scanner_test.dart
@@ -0,0 +1,279 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:boolean_selector/src/scanner.dart';
+import 'package:boolean_selector/src/token.dart';
+import 'package:test/test.dart';
+
+/// A matcher that asserts that a value is a [IdentifierToken].
+const _isIdentifierToken = TypeMatcher<IdentifierToken>();
+
+void main() {
+ group('peek()', () {
+ test('returns the next token without consuming it', () {
+ var scanner = Scanner('( )');
+ expect(scanner.peek().type, equals(TokenType.leftParen));
+ expect(scanner.peek().type, equals(TokenType.leftParen));
+ expect(scanner.peek().type, equals(TokenType.leftParen));
+ });
+
+ test('returns an end-of-file token at the end of a file', () {
+ var scanner = Scanner('( )');
+ scanner.next();
+ scanner.next();
+
+ var token = scanner.peek();
+ expect(token.type, equals(TokenType.endOfFile));
+ expect(token.span.start.offset, equals(3));
+ expect(token.span.end.offset, equals(3));
+ });
+
+ test('throws a StateError if called after end-of-file was consumed', () {
+ var scanner = Scanner('( )');
+ scanner.next();
+ scanner.next();
+ scanner.next();
+ expect(() => scanner.peek(), throwsStateError);
+ });
+ });
+
+ group('next()', () {
+ test('consumes and returns the next token', () {
+ var scanner = Scanner('( )');
+ expect(scanner.next().type, equals(TokenType.leftParen));
+ expect(scanner.peek().type, equals(TokenType.rightParen));
+ expect(scanner.next().type, equals(TokenType.rightParen));
+ });
+
+ test('returns an end-of-file token at the end of a file', () {
+ var scanner = Scanner('( )');
+ scanner.next();
+ scanner.next();
+
+ var token = scanner.next();
+ expect(token.type, equals(TokenType.endOfFile));
+ expect(token.span.start.offset, equals(3));
+ expect(token.span.end.offset, equals(3));
+ });
+
+ test('throws a StateError if called after end-of-file was consumed', () {
+ var scanner = Scanner('( )');
+ scanner.next();
+ scanner.next();
+ scanner.next();
+ expect(() => scanner.next(), throwsStateError);
+ });
+ });
+
+ group('scan()', () {
+ test('consumes a matching token and returns true', () {
+ var scanner = Scanner('( )');
+ expect(scanner.scan(TokenType.leftParen), isTrue);
+ expect(scanner.peek().type, equals(TokenType.rightParen));
+ });
+
+ test("doesn't consume a matching token and returns false", () {
+ var scanner = Scanner('( )');
+ expect(scanner.scan(TokenType.questionMark), isFalse);
+ expect(scanner.peek().type, equals(TokenType.leftParen));
+ });
+
+ test('throws a StateError called after end-of-file was consumed', () {
+ var scanner = Scanner('( )');
+ scanner.next();
+ scanner.next();
+ scanner.next();
+ expect(() => scanner.scan(TokenType.endOfFile), throwsStateError);
+ });
+ });
+
+ group('scans a simple token:', () {
+ test('left paren', () => _expectSimpleScan('(', TokenType.leftParen));
+ test('right paren', () => _expectSimpleScan(')', TokenType.rightParen));
+ test('or', () => _expectSimpleScan('||', TokenType.or));
+ test('and', () => _expectSimpleScan('&&', TokenType.and));
+ test('not', () => _expectSimpleScan('!', TokenType.not));
+ test('question mark', () => _expectSimpleScan('?', TokenType.questionMark));
+ test('colon', () => _expectSimpleScan(':', TokenType.colon));
+ });
+
+ group('scans an identifier that', () {
+ test('is simple', () {
+ var token = _scan(' foo ');
+ expect(token, _isIdentifierToken);
+ token as IdentifierToken; // promote token
+
+ expect(token.name, equals('foo'));
+ expect(token.span.text, equals('foo'));
+ expect(token.span.start.offset, equals(3));
+ expect(token.span.end.offset, equals(6));
+ });
+
+ test('is a single character', () {
+ var token = _scan('f');
+ expect(token, _isIdentifierToken);
+ expect((token as IdentifierToken).name, equals('f'));
+ });
+
+ test('has a leading underscore', () {
+ var token = _scan('_foo');
+ expect(token, _isIdentifierToken);
+ expect((token as IdentifierToken).name, equals('_foo'));
+ });
+
+ test('has a leading dash', () {
+ var token = _scan('-foo');
+ expect(token, _isIdentifierToken);
+ expect((token as IdentifierToken).name, equals('-foo'));
+ });
+
+ test('contains an underscore', () {
+ var token = _scan('foo_bar');
+ expect(token, _isIdentifierToken);
+ expect((token as IdentifierToken).name, equals('foo_bar'));
+ });
+
+ test('contains a dash', () {
+ var token = _scan('foo-bar');
+ expect(token, _isIdentifierToken);
+ expect((token as IdentifierToken).name, equals('foo-bar'));
+ });
+
+ test('is capitalized', () {
+ var token = _scan('FOO');
+ expect(token, _isIdentifierToken);
+ expect((token as IdentifierToken).name, equals('FOO'));
+ });
+
+ test('contains numbers', () {
+ var token = _scan('foo123');
+ expect(token, _isIdentifierToken);
+ expect((token as IdentifierToken).name, equals('foo123'));
+ });
+ });
+
+ test('scans an empty selector', () {
+ expect(_scan('').type, equals(TokenType.endOfFile));
+ });
+
+ test('scans multiple tokens', () {
+ var scanner = Scanner('(foo && bar)');
+
+ var token = scanner.next();
+ expect(token.type, equals(TokenType.leftParen));
+ expect(token.span.start.offset, equals(0));
+ expect(token.span.end.offset, equals(1));
+
+ token = scanner.next();
+ expect(token.type, equals(TokenType.identifier));
+ expect((token as IdentifierToken).name, equals('foo'));
+ expect(token.span.start.offset, equals(1));
+ expect(token.span.end.offset, equals(4));
+
+ token = scanner.next();
+ expect(token.type, equals(TokenType.and));
+ expect(token.span.start.offset, equals(5));
+ expect(token.span.end.offset, equals(7));
+
+ token = scanner.next();
+ expect(token.type, equals(TokenType.identifier));
+ expect((token as IdentifierToken).name, equals('bar'));
+ expect(token.span.start.offset, equals(8));
+ expect(token.span.end.offset, equals(11));
+
+ token = scanner.next();
+ expect(token.type, equals(TokenType.rightParen));
+ expect(token.span.start.offset, equals(11));
+ expect(token.span.end.offset, equals(12));
+
+ token = scanner.next();
+ expect(token.type, equals(TokenType.endOfFile));
+ expect(token.span.start.offset, equals(12));
+ expect(token.span.end.offset, equals(12));
+ });
+
+ group('ignores', () {
+ test('a single-line comment', () {
+ var scanner = Scanner('( // &&\n// ||\n)');
+ expect(scanner.next().type, equals(TokenType.leftParen));
+ expect(scanner.next().type, equals(TokenType.rightParen));
+ expect(scanner.next().type, equals(TokenType.endOfFile));
+ });
+
+ test('a single-line comment without a trailing newline', () {
+ var scanner = Scanner('( // &&');
+ expect(scanner.next().type, equals(TokenType.leftParen));
+ expect(scanner.next().type, equals(TokenType.endOfFile));
+ });
+
+ test('a multi-line comment', () {
+ var scanner = Scanner('( /* && * /\n|| */\n)');
+ expect(scanner.next().type, equals(TokenType.leftParen));
+ expect(scanner.next().type, equals(TokenType.rightParen));
+ expect(scanner.next().type, equals(TokenType.endOfFile));
+ });
+
+ test('a multi-line nested comment', () {
+ var scanner = Scanner('(/* && /* ? /* || */ : */ ! */)');
+ expect(scanner.next().type, equals(TokenType.leftParen));
+ expect(scanner.next().type, equals(TokenType.rightParen));
+ expect(scanner.next().type, equals(TokenType.endOfFile));
+ });
+
+ test("Dart's notion of whitespace", () {
+ var scanner = Scanner('( \t \n)');
+ expect(scanner.next().type, equals(TokenType.leftParen));
+ expect(scanner.next().type, equals(TokenType.rightParen));
+ expect(scanner.next().type, equals(TokenType.endOfFile));
+ });
+ });
+
+ group('disallows', () {
+ test('a single |', () {
+ expect(() => _scan('|'), throwsFormatException);
+ });
+
+ test('"| |"', () {
+ expect(() => _scan('| |'), throwsFormatException);
+ });
+
+ test('a single &', () {
+ expect(() => _scan('&'), throwsFormatException);
+ });
+
+ test('"& &"', () {
+ expect(() => _scan('& &'), throwsFormatException);
+ });
+
+ test('an unknown operator', () {
+ expect(() => _scan('=='), throwsFormatException);
+ });
+
+ test('unicode', () {
+ expect(() => _scan('öh'), throwsFormatException);
+ });
+
+ test('an unclosed multi-line comment', () {
+ expect(() => _scan('/*'), throwsFormatException);
+ });
+
+ test('an unopened multi-line comment', () {
+ expect(() => _scan('*/'), throwsFormatException);
+ });
+ });
+}
+
+/// Asserts that the first token scanned from [selector] has type [type],
+/// and that that token's span is exactly [selector].
+void _expectSimpleScan(String selector, TokenType type) {
+ // Complicate the selector to test that the span covers it correctly.
+ var token = _scan(' $selector ');
+ expect(token.type, equals(type));
+ expect(token.span.text, equals(selector));
+ expect(token.span.start.offset, equals(3));
+ expect(token.span.end.offset, equals(3 + selector.length));
+}
+
+/// Scans a single token from [selector].
+Token _scan(String selector) => Scanner(selector).next();
diff --git a/pkgs/boolean_selector/test/to_string_test.dart b/pkgs/boolean_selector/test/to_string_test.dart
new file mode 100644
index 0000000..971e5b9
--- /dev/null
+++ b/pkgs/boolean_selector/test/to_string_test.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:boolean_selector/boolean_selector.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('toString() for', () {
+ test('a variable is its name', () {
+ _expectToString('foo');
+ _expectToString('a-b');
+ });
+
+ group('not', () {
+ test("doesn't parenthesize a variable", () => _expectToString('!a'));
+ test("doesn't parenthesize a nested not", () => _expectToString('!!a'));
+ test('parenthesizes an or', () => _expectToString('!(a || b)'));
+ test('parenthesizes an and', () => _expectToString('!(a && b)'));
+ test('parenthesizes a condition', () => _expectToString('!(a ? b : c)'));
+ });
+
+ group('or', () {
+ test("doesn't parenthesize variables", () => _expectToString('a || b'));
+ test("doesn't parenthesize nots", () => _expectToString('!a || !b'));
+
+ test("doesn't parenthesize ors", () {
+ _expectToString('a || b || c || d');
+ _expectToString('((a || b) || c) || d', 'a || b || c || d');
+ });
+
+ test('parenthesizes ands',
+ () => _expectToString('a && b || c && d', '(a && b) || (c && d)'));
+
+ test('parenthesizes conditions',
+ () => _expectToString('(a ? b : c) || (e ? f : g)'));
+ });
+
+ group('and', () {
+ test("doesn't parenthesize variables", () => _expectToString('a && b'));
+ test("doesn't parenthesize nots", () => _expectToString('!a && !b'));
+
+ test(
+ 'parenthesizes ors',
+ () =>
+ _expectToString('(a || b) && (c || d)', '(a || b) && (c || d)'));
+
+ test("doesn't parenthesize ands", () {
+ _expectToString('a && b && c && d');
+ _expectToString('((a && b) && c) && d', 'a && b && c && d');
+ });
+
+ test('parenthesizes conditions',
+ () => _expectToString('(a ? b : c) && (e ? f : g)'));
+ });
+
+ group('conditional', () {
+ test(
+ "doesn't parenthesize variables", () => _expectToString('a ? b : c'));
+
+ test("doesn't parenthesize nots", () => _expectToString('!a ? !b : !c'));
+
+ test("doesn't parenthesize ors",
+ () => _expectToString('a || b ? c || d : e || f'));
+
+ test("doesn't parenthesize ands",
+ () => _expectToString('a && b ? c && d : e && f'));
+
+ test('parenthesizes non-trailing conditions', () {
+ _expectToString('(a ? b : c) ? (e ? f : g) : h ? i : j');
+ _expectToString('(a ? b : c) ? (e ? f : g) : (h ? i : j)',
+ '(a ? b : c) ? (e ? f : g) : h ? i : j');
+ });
+ });
+ });
+}
+
+void _expectToString(String selector, [String? result]) {
+ result ??= selector;
+ expect(_toString(selector), equals(result),
+ reason: 'Expected toString of "$selector" to be "$result".');
+}
+
+String _toString(String selector) => BooleanSelector.parse(selector).toString();
diff --git a/pkgs/boolean_selector/test/validate_test.dart b/pkgs/boolean_selector/test/validate_test.dart
new file mode 100644
index 0000000..ec5b7eb
--- /dev/null
+++ b/pkgs/boolean_selector/test/validate_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:boolean_selector/boolean_selector.dart';
+import 'package:test/test.dart';
+
+var _selector = BooleanSelector.parse('foo && bar && baz');
+
+void main() {
+ test('throws if any variables are undefined', () {
+ expect(() => _selector.validate((variable) => variable == 'bar'),
+ throwsFormatException);
+ });
+
+ test("doesn't throw if all variables are defined", () {
+ // Should not throw.
+ _selector.validate((variable) => true);
+ });
+}
diff --git a/pkgs/boolean_selector/test/variables_test.dart b/pkgs/boolean_selector/test/variables_test.dart
new file mode 100644
index 0000000..5331409
--- /dev/null
+++ b/pkgs/boolean_selector/test/variables_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:boolean_selector/boolean_selector.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('a variable reports itself', () {
+ expect(BooleanSelector.parse('foo').variables, equals(['foo']));
+ });
+
+ test('a negation reports its contents', () {
+ expect(BooleanSelector.parse('!foo').variables, equals(['foo']));
+ });
+
+ test('a parenthesized expression reports its contents', () {
+ expect(BooleanSelector.parse('(foo)').variables, equals(['foo']));
+ });
+
+ test('an or reports its contents', () {
+ expect(
+ BooleanSelector.parse('foo || bar').variables, equals(['foo', 'bar']));
+ });
+
+ test('an and reports its contents', () {
+ expect(
+ BooleanSelector.parse('foo && bar').variables, equals(['foo', 'bar']));
+ });
+
+ test('a conditional reports its contents', () {
+ expect(BooleanSelector.parse('foo ? bar : baz').variables,
+ equals(['foo', 'bar', 'baz']));
+ });
+
+ test('BooleanSelector.all reports no variables', () {
+ expect(BooleanSelector.all.variables, isEmpty);
+ });
+
+ test('BooleanSelector.none reports no variables', () {
+ expect(BooleanSelector.none.variables, isEmpty);
+ });
+}
diff --git a/pkgs/browser_launcher/.gitignore b/pkgs/browser_launcher/.gitignore
new file mode 100644
index 0000000..ec8eae3
--- /dev/null
+++ b/pkgs/browser_launcher/.gitignore
@@ -0,0 +1,4 @@
+# Don’t commit the following directories created by pub.
+.dart_tool/
+.packages
+pubspec.lock
diff --git a/pkgs/browser_launcher/AUTHORS b/pkgs/browser_launcher/AUTHORS
new file mode 100644
index 0000000..e8063a8
--- /dev/null
+++ b/pkgs/browser_launcher/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/browser_launcher/CHANGELOG.md b/pkgs/browser_launcher/CHANGELOG.md
new file mode 100644
index 0000000..f375056
--- /dev/null
+++ b/pkgs/browser_launcher/CHANGELOG.md
@@ -0,0 +1,71 @@
+## 1.1.3
+
+- Move to `dart-lang/tools` monorepo.
+
+## 1.1.2
+
+- Require Dart 3.4
+- Log errors from chrome
+- Allow tests to detect headless-only environment (for CI).
+- Add extra flags that may help disable additional throttling in background tabs
+- Add `--use-mock-keychain` flag to avoid blocking dialog on MacOS.
+
+## 1.1.1
+
+- Populate the pubspec `repository` field.
+
+## 1.1.0
+
+- Add optional `signIn` argument to `startWithDebugPort`.
+ To be used together with `user-data-dir` to start a Chrome
+ window signed in to the default profile with extensions enabled.
+- Enable the `avoid_dynamic_calls` lint.
+
+## 1.0.0
+
+- Migrate to null-safety.
+
+## 0.1.10
+
+- Support `webkit_inspection_protocol` version `^1.0.0`.
+
+## 0.1.9
+
+- Add support for Chrome executables in `CHROME_PATH`.
+
+## 0.1.8
+
+- Log `STDERR` on Chrome launch failure.
+
+## 0.1.7
+
+- Widen the dependency range on `package:webkit_inspection_protocol`.
+
+## 0.1.6
+
+- Update lower Dart SDK requirement to `2.2.0`.
+- Update the dependency range on `package:webkit_inspection_protocol`.
+
+## 0.1.5
+
+- Add a parameter to use a specified user-data-dir instead of a system temp.
+
+## 0.1.4
+
+- Start Chrome maximized.
+
+## 0.1.3
+
+- widen the version constraint on `package:webkit_inspection_protocol`
+
+## 0.1.2
+
+- lower min sdk version to match Flutter stable
+
+## 0.1.1
+
+- added example
+
+## 0.1.0
+
+- initial release
diff --git a/pkgs/browser_launcher/LICENSE b/pkgs/browser_launcher/LICENSE
new file mode 100644
index 0000000..7670007
--- /dev/null
+++ b/pkgs/browser_launcher/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2019, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/browser_launcher/README.md b/pkgs/browser_launcher/README.md
new file mode 100644
index 0000000..f6398b6
--- /dev/null
+++ b/pkgs/browser_launcher/README.md
@@ -0,0 +1,8 @@
+[](https://github.com/dart-lang/tools/actions/workflows/browser_launcher.yaml)
+[](https://pub.dev/packages/browser_launcher)
+[](https://pub.dev/packages/browser_launcher/publisher)
+
+Provides a standardized way to launch web browsers.
+
+Currently, Chrome is the only supported browser; support for other browsers may
+be added in the future.
diff --git a/pkgs/browser_launcher/analysis_options.yaml b/pkgs/browser_launcher/analysis_options.yaml
new file mode 100644
index 0000000..9125368
--- /dev/null
+++ b/pkgs/browser_launcher/analysis_options.yaml
@@ -0,0 +1,32 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_classes_with_only_static_members
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_returning_this
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - join_return_with_assignment
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - no_runtimeType_toString
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - require_trailing_commas
+ - unnecessary_raw_strings
+ - use_if_null_to_convert_nulls_to_bools
+ - use_raw_strings
+ - use_string_buffers
diff --git a/pkgs/browser_launcher/example/main.dart b/pkgs/browser_launcher/example/main.dart
new file mode 100644
index 0000000..6814bce
--- /dev/null
+++ b/pkgs/browser_launcher/example/main.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:browser_launcher/browser_launcher.dart';
+
+const _googleUrl = 'https://www.google.com/';
+const _googleImagesUrl = 'https://www.google.com/imghp?hl=en';
+
+Future<void> main() async {
+ // Launches a chrome browser with two tabs open to [_googleUrl] and
+ // [_googleImagesUrl].
+ await Chrome.start([_googleUrl, _googleImagesUrl]);
+ print('launched Chrome');
+
+ // Pause briefly before opening Chrome with a debug port.
+ await Future<void>.delayed(const Duration(seconds: 3));
+
+ // Launches a chrome browser open to [_googleUrl]. Since we are launching with
+ // a debug port, we will use a variety of different launch configurations,
+ // such as launching in a new browser.
+ final chrome = await Chrome.startWithDebugPort([_googleUrl], debugPort: 8888);
+ print('launched Chrome with a debug port');
+
+ // When running this dart code, observe that the browser stays open for 3
+ // seconds before we close it.
+ await Future<void>.delayed(const Duration(seconds: 3));
+
+ await chrome.close();
+ print('closed Chrome');
+}
diff --git a/pkgs/browser_launcher/lib/browser_launcher.dart b/pkgs/browser_launcher/lib/browser_launcher.dart
new file mode 100644
index 0000000..7d85dad
--- /dev/null
+++ b/pkgs/browser_launcher/lib/browser_launcher.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/chrome.dart';
diff --git a/pkgs/browser_launcher/lib/src/chrome.dart b/pkgs/browser_launcher/lib/src/chrome.dart
new file mode 100644
index 0000000..8ee14f0
--- /dev/null
+++ b/pkgs/browser_launcher/lib/src/chrome.dart
@@ -0,0 +1,237 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:logging/logging.dart';
+import 'package:path/path.dart' as p;
+import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
+
+const _chromeEnvironments = ['CHROME_EXECUTABLE', 'CHROME_PATH'];
+const _linuxExecutable = 'google-chrome';
+const _macOSExecutable =
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
+const _windowsExecutable = r'Google\Chrome\Application\chrome.exe';
+
+String get _executable {
+ for (var chromeEnv in _chromeEnvironments) {
+ if (Platform.environment.containsKey(chromeEnv)) {
+ return Platform.environment[chromeEnv]!;
+ }
+ }
+ if (Platform.isLinux) return _linuxExecutable;
+ if (Platform.isMacOS) return _macOSExecutable;
+ if (Platform.isWindows) {
+ final windowsPrefixes = [
+ Platform.environment['LOCALAPPDATA'],
+ Platform.environment['PROGRAMFILES'],
+ Platform.environment['PROGRAMFILES(X86)'],
+ ];
+ return p.join(
+ windowsPrefixes.firstWhere(
+ (prefix) {
+ if (prefix == null) return false;
+ final path = p.join(prefix, _windowsExecutable);
+ return File(path).existsSync();
+ },
+ orElse: () => '.',
+ )!,
+ _windowsExecutable,
+ );
+ }
+ throw StateError('Unexpected platform type.');
+}
+
+/// Manager for an instance of Chrome.
+class Chrome {
+ static final _logger = Logger('BROWSER_LAUNCHER.CHROME');
+
+ Chrome._(
+ this.debugPort,
+ this.chromeConnection, {
+ Process? process,
+ Directory? dataDir,
+ this.deleteDataDir = false,
+ }) : _process = process,
+ _dataDir = dataDir;
+
+ final int debugPort;
+ final ChromeConnection chromeConnection;
+ final Process? _process;
+ final Directory? _dataDir;
+ final bool deleteDataDir;
+
+ /// Connects to an instance of Chrome with an open debug port.
+ static Future<Chrome> fromExisting(int port) async =>
+ _connect(Chrome._(port, ChromeConnection('localhost', port)));
+
+ /// Starts Chrome with the given arguments and a specific port.
+ ///
+ /// Each url in [urls] will be loaded in a separate tab.
+ ///
+ /// If [userDataDir] is `null`, a new temp directory will be
+ /// passed to chrome as a user data directory. Chrome will
+ /// start without sign in and with extensions disabled.
+ ///
+ /// If [userDataDir] is not `null`, it will be passed to chrome
+ /// as a user data directory. Chrome will start signed into
+ /// the default profile with extensions enabled if [signIn]
+ /// is also true.
+ static Future<Chrome> startWithDebugPort(
+ List<String> urls, {
+ int debugPort = 0,
+ bool headless = false,
+ String? userDataDir,
+ bool signIn = false,
+ }) async {
+ Directory dataDir;
+ if (userDataDir == null) {
+ signIn = false;
+ dataDir = Directory.systemTemp.createTempSync();
+ } else {
+ dataDir = Directory(userDataDir);
+ }
+ final port = debugPort == 0 ? await findUnusedPort() : debugPort;
+ final args = [
+ // Using a tmp directory ensures that a new instance of chrome launches
+ // allowing for the remote debug port to be enabled.
+ '--user-data-dir=${dataDir.path}',
+ '--remote-debugging-port=$port',
+ // When the DevTools has focus we don't want to slow down the application.
+ '--disable-background-timer-throttling',
+ '--disable-blink-features=TimerThrottlingForBackgroundTabs',
+ '--disable-features=IntensiveWakeUpThrottling',
+ // Since we are using a temp profile, disable features that slow the
+ // Chrome launch.
+ if (!signIn) '--disable-extensions',
+ '--disable-popup-blocking',
+ if (!signIn) '--bwsi',
+ '--no-first-run',
+ '--no-default-browser-check',
+ '--disable-default-apps',
+ '--disable-translate',
+ '--start-maximized',
+ // When running on MacOS, Chrome may open system dialogs requesting
+ // credentials. This uses a mock keychain to avoid that dialog from
+ // blocking.
+ '--use-mock-keychain',
+ ];
+ if (headless) {
+ args.add('--headless');
+ }
+
+ final process = await _startProcess(urls, args: args);
+
+ // Wait until the DevTools are listening before trying to connect.
+ final errorLines = <String>[];
+ try {
+ final stderr = process.stderr.asBroadcastStream();
+ stderr
+ .transform(utf8.decoder)
+ .transform(const LineSplitter())
+ .listen(_logger.fine);
+
+ await stderr
+ .transform(utf8.decoder)
+ .transform(const LineSplitter())
+ .firstWhere((line) {
+ errorLines.add(line);
+ return line.startsWith('DevTools listening');
+ }).timeout(const Duration(seconds: 60));
+ } on TimeoutException catch (e, s) {
+ _logger.severe('Unable to connect to Chrome DevTools', e, s);
+ throw Exception(
+ 'Unable to connect to Chrome DevTools: $e.\n\n'
+ 'Chrome STDERR:\n${errorLines.join('\n')}',
+ );
+ }
+
+ return _connect(
+ Chrome._(
+ port,
+ ChromeConnection('localhost', port),
+ process: process,
+ dataDir: dataDir,
+ deleteDataDir: userDataDir == null,
+ ),
+ );
+ }
+
+ /// Starts Chrome with the given arguments.
+ ///
+ /// Each url in [urls] will be loaded in a separate tab.
+ static Future<Process> start(
+ List<String> urls, {
+ List<String> args = const [],
+ }) async =>
+ await _startProcess(urls, args: args);
+
+ static Future<Process> _startProcess(
+ List<String> urls, {
+ List<String> args = const [],
+ }) async {
+ final processArgs = args.toList()..addAll(urls);
+ return await Process.start(_executable, processArgs);
+ }
+
+ static Future<Chrome> _connect(Chrome chrome) async {
+ // The connection is lazy. Try a simple call to make sure the provided
+ // connection is valid.
+ try {
+ await chrome.chromeConnection.getTabs();
+ } catch (e) {
+ await chrome.close();
+ throw ChromeError(
+ 'Unable to connect to Chrome debug port: ${chrome.debugPort}\n $e',
+ );
+ }
+ return chrome;
+ }
+
+ Future<void> close() async {
+ chromeConnection.close();
+ _process?.kill(ProcessSignal.sigkill);
+ await _process?.exitCode;
+ try {
+ // Chrome starts another process as soon as it dies that modifies the
+ // profile information. Give it some time before attempting to delete
+ // the directory.
+ if (deleteDataDir) {
+ await Future<void>.delayed(const Duration(milliseconds: 500));
+ await _dataDir?.delete(recursive: true);
+ }
+ } catch (_) {
+ // Silently fail if we can't clean up the profile information.
+ // It is a system tmp directory so it should get cleaned up eventually.
+ }
+ }
+}
+
+class ChromeError extends Error {
+ final String details;
+ ChromeError(this.details);
+
+ @override
+ String toString() => 'ChromeError: $details';
+}
+
+/// Returns a port that is probably, but not definitely, not in use.
+///
+/// This has a built-in race condition: another process may bind this port at
+/// any time after this call has returned.
+Future<int> findUnusedPort() async {
+ int port;
+ ServerSocket socket;
+ try {
+ socket =
+ await ServerSocket.bind(InternetAddress.loopbackIPv6, 0, v6Only: true);
+ } on SocketException {
+ socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
+ }
+ port = socket.port;
+ await socket.close();
+ return port;
+}
diff --git a/pkgs/browser_launcher/pubspec.yaml b/pkgs/browser_launcher/pubspec.yaml
new file mode 100644
index 0000000..e046097
--- /dev/null
+++ b/pkgs/browser_launcher/pubspec.yaml
@@ -0,0 +1,17 @@
+name: browser_launcher
+version: 1.1.3
+description: Provides a standardized way to launch web browsers for testing and tools.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/browser_launcher
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Abrowser_launcher
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ logging: ^1.0.0
+ path: ^1.8.0
+ webkit_inspection_protocol: ^1.0.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.17.3
diff --git a/pkgs/browser_launcher/test/chrome_test.dart b/pkgs/browser_launcher/test/chrome_test.dart
new file mode 100644
index 0000000..9243768
--- /dev/null
+++ b/pkgs/browser_launcher/test/chrome_test.dart
@@ -0,0 +1,226 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@OnPlatform({'windows': Skip('appveyor is not setup to install Chrome')})
+library;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:browser_launcher/src/chrome.dart';
+import 'package:logging/logging.dart';
+import 'package:test/test.dart';
+import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
+
+const _headlessOnlyEnvironment = 'HEADLESS_ONLY';
+
+bool get headlessOnlyEnvironment =>
+ Platform.environment[_headlessOnlyEnvironment] == 'true';
+
+void _configureLogging(bool verbose) {
+ Logger.root.level = verbose ? Level.ALL : Level.INFO;
+ Logger.root.onRecord.listen((record) {
+ print('${record.level.name}: ${record.time}: ${record.message}');
+ });
+}
+
+void main() {
+ Chrome? chrome;
+
+ // Pass 'true' for debugging.
+ _configureLogging(false);
+
+ Future<ChromeTab?> getTab(String url) => chrome!.chromeConnection.getTab(
+ (t) => t.url.contains(url),
+ retryFor: const Duration(seconds: 5),
+ );
+
+ Future<List<ChromeTab>?> getTabs() => chrome!.chromeConnection.getTabs(
+ retryFor: const Duration(seconds: 5),
+ );
+
+ Future<WipConnection> connectToTab(String url) async {
+ final tab = await getTab(url);
+ expect(tab, isNotNull);
+ return tab!.connect();
+ }
+
+ Future<HttpClientResponse> openTab(String url) =>
+ chrome!.chromeConnection.getUrl(_openTabUrl(url));
+
+ Future<void> launchChromeWithDebugPort({
+ int port = 0,
+ String? userDataDir,
+ bool signIn = false,
+ bool headless = false,
+ }) async {
+ chrome = await Chrome.startWithDebugPort(
+ [_googleUrl],
+ debugPort: port,
+ userDataDir: userDataDir,
+ signIn: signIn,
+ headless: headless,
+ );
+ }
+
+ Future<void> launchChrome({bool headless = false}) async {
+ await Chrome.start([_googleUrl], args: [if (headless) '--headless']);
+ }
+
+ final headlessModes = [
+ true,
+ if (!headlessOnlyEnvironment) false,
+ ];
+
+ for (var headless in headlessModes) {
+ group('(headless: $headless)', () {
+ group('chrome with temp data dir', () {
+ tearDown(() async {
+ await chrome?.close();
+ chrome = null;
+ });
+
+ test('can launch chrome', () async {
+ await launchChrome(headless: headless);
+ expect(chrome, isNull);
+ });
+
+ test('can launch chrome with debug port', () async {
+ await launchChromeWithDebugPort(headless: headless);
+ expect(chrome, isNotNull);
+ });
+
+ test('has a working debugger', () async {
+ await launchChromeWithDebugPort(headless: headless);
+ final tabs = await getTabs();
+ expect(
+ tabs,
+ contains(
+ const TypeMatcher<ChromeTab>()
+ .having((t) => t.url, 'url', _googleUrl),
+ ),
+ );
+ });
+
+ test('uses open debug port if provided port is 0', () async {
+ await launchChromeWithDebugPort(headless: headless);
+ expect(chrome!.debugPort, isNot(equals(0)));
+ });
+
+ test('can provide a specific debug port', () async {
+ final port = await findUnusedPort();
+ await launchChromeWithDebugPort(port: port, headless: headless);
+ expect(chrome!.debugPort, port);
+ });
+ });
+
+ group('chrome with user data dir', () {
+ late Directory dataDir;
+ const waitMilliseconds = Duration(milliseconds: 100);
+
+ for (var signIn in [false, true]) {
+ group('and signIn = $signIn', () {
+ setUp(() {
+ dataDir = Directory.systemTemp.createTempSync(_userDataDirName);
+ });
+
+ tearDown(() async {
+ await chrome?.close();
+ chrome = null;
+
+ var attempts = 0;
+ while (true) {
+ try {
+ attempts++;
+ await Future<dynamic>.delayed(waitMilliseconds);
+ dataDir.deleteSync(recursive: true);
+ break;
+ } catch (_) {
+ if (attempts > 3) rethrow;
+ }
+ }
+ });
+
+ test('can launch with debug port', () async {
+ await launchChromeWithDebugPort(
+ userDataDir: dataDir.path,
+ signIn: signIn,
+ headless: headless,
+ );
+ expect(chrome, isNotNull);
+ });
+
+ test('has a working debugger', () async {
+ await launchChromeWithDebugPort(
+ userDataDir: dataDir.path,
+ signIn: signIn,
+ headless: headless,
+ );
+ final tabs = await getTabs();
+ expect(
+ tabs,
+ contains(
+ const TypeMatcher<ChromeTab>()
+ .having((t) => t.url, 'url', _googleUrl),
+ ),
+ );
+ });
+
+ test(
+ 'has correct profile path',
+ () async {
+ await launchChromeWithDebugPort(
+ userDataDir: dataDir.path,
+ signIn: signIn,
+ headless: headless,
+ );
+ await openTab(_chromeVersionUrl);
+ final wipConnection = await connectToTab(_chromeVersionUrl);
+ await wipConnection.debugger.enable();
+ await wipConnection.runtime.enable();
+ final result = await _evaluate(
+ wipConnection.page,
+ "document.getElementById('profile_path').textContent",
+ );
+ expect(result, contains(_userDataDirName));
+ },
+ // Note: When re-enabling, skip for headless mode because headless
+ // mode does not allow chrome: urls.
+ skip: 'https://github.com/dart-lang/sdk/issues/52357',
+ );
+ });
+ }
+ });
+ });
+ }
+}
+
+String _openTabUrl(String url) => '/json/new?$url';
+
+Future<String?> _evaluate(WipPage page, String expression) async {
+ String? result;
+ const stopInSeconds = Duration(seconds: 5);
+ const waitMilliseconds = Duration(milliseconds: 100);
+ final stopTime = DateTime.now().add(stopInSeconds);
+
+ while (result == null && DateTime.now().isBefore(stopTime)) {
+ await Future<dynamic>.delayed(waitMilliseconds);
+ try {
+ final wipResponse = await page.sendCommand(
+ 'Runtime.evaluate',
+ params: {'expression': expression},
+ );
+ final response = wipResponse.json['result'] as Map<String, dynamic>;
+ final value = (response['result'] as Map<String, dynamic>)['value'];
+ result = value?.toString();
+ } catch (_) {
+ return null;
+ }
+ }
+ return result;
+}
+
+const _googleUrl = 'https://www.google.com/';
+const _chromeVersionUrl = 'chrome://version/';
+const _userDataDirName = 'data dir';
diff --git a/pkgs/cli_config/.gitignore b/pkgs/cli_config/.gitignore
new file mode 100644
index 0000000..58e48f3
--- /dev/null
+++ b/pkgs/cli_config/.gitignore
@@ -0,0 +1,9 @@
+# https://dart.dev/guides/libraries/private-files
+# Created by `dart pub`
+.dart_tool/
+
+# Avoid committing pubspec.lock for library packages; see
+# https://dart.dev/guides/libraries/private-files#pubspeclock.
+pubspec.lock
+
+coverage/
diff --git a/pkgs/cli_config/CHANGELOG.md b/pkgs/cli_config/CHANGELOG.md
new file mode 100644
index 0000000..55fcd2d
--- /dev/null
+++ b/pkgs/cli_config/CHANGELOG.md
@@ -0,0 +1,22 @@
+## 0.2.1-wip
+
+- Require Dart 3.4.
+
+## 0.2.0
+
+- **Breaking Change** Rename `Config.fromArgs` to `Config.fromArguments`.
+- Add `Config.fromArgumentsSync`.
+
+## 0.1.2
+
+- Add usage docs to the readme.
+- Require Dart 3.0.
+
+## 0.1.1
+
+- Support non-String map keys in YAML configuration files.
+- Support null values in YAML configuration files.
+
+## 0.1.0
+
+- Initial version.
diff --git a/pkgs/cli_config/LICENSE b/pkgs/cli_config/LICENSE
new file mode 100644
index 0000000..ac90031
--- /dev/null
+++ b/pkgs/cli_config/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2023, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/pkgs/cli_config/README.md b/pkgs/cli_config/README.md
new file mode 100644
index 0000000..54c08e4
--- /dev/null
+++ b/pkgs/cli_config/README.md
@@ -0,0 +1,71 @@
+[](https://github.com/dart-lang/tools/actions/workflows/cli_config.yml)
+[](https://coveralls.io/github/dart-lang/tools?branch=main)
+[](https://pub.dev/packages/cli_config)
+[](https://pub.dev/packages/cli_config/publisher)
+
+A library to take config values from configuration files, CLI arguments, and
+environment variables.
+
+## Usage
+
+Configuration can be provided from commandline arguments, environment variables,
+and configuration files. This library makes these accessible via a uniform API.
+
+Configuration can be provided via the three sources as follows:
+1. commandline argument defines as `-Dsome_key=some_value`,
+2. environment variables as `SOME_KEY=some_value`, and
+3. config files as JSON or YAML as `{'some_key': 'some_value'}`.
+
+The default lookup behavior is that commandline argument defines take precedence
+over environment variables, which take precedence over the configuration file.
+
+If a single value is requested from this configuration, the first source that
+can provide the value will provide it. For example
+`config.string('some_key')` with `{'some_key': 'file_value'}` in the config file
+and `-Dsome_key=cli_value` as commandline argument returns
+`'cli_value'`. The implication is that you can not remove keys from the
+configuration file, only overwrite or append them.
+
+If a list value is requested from this configuration, the values provided by the
+various sources can be combined or not. For example
+`config.optionalStringList('some_key', combineAllConfigs: true)` returns
+`['cli_value', 'file_value']`.
+
+The config is hierarchical in nature, using `.` as the hierarchy separator for
+lookup and commandline defines. The hierarchy should be materialized in the JSON
+or YAML configuration file. For environment variables `__` is used as hierarchy
+separator.
+
+Hierarchical configuration can be provided via the three sources as follows:
+1. commandline argument defines as `-Dsome_key.some_nested_key=some_value`,
+2. environment variables as `SOME_KEY__SOME_NESTED_KEY=some_value`, and
+3. config files as JSON or YAML as
+ ```yaml
+ some_key:
+ some_nested_key:
+ some_value
+ ```
+
+The config is opinionated on the format of the keys in the sources.
+* Command-line argument keys should be lower-cased alphanumeric
+ characters or underscores, with `.` for hierarchy.
+* Environment variables keys should be upper-cased alphanumeric
+ characters or underscores, with `__` for hierarchy.
+* Config files keys should be lower-cased alphanumeric
+ characters or underscores.
+
+In the API they are made available lower-cased and with underscores, and
+`.` as hierarchy separator.
+
+## Example usage
+
+This example creates a configuration which first looks for command-line defines
+in the `arguments` list then looks in `Platform.environment`, then looks in any
+local configuration file.
+
+```dart
+final config = await Config.fromArguments(arguments: arguments);
+final pathValue =
+ config.optionalPath('my_path', resolveUri: true, mustExist: false);
+print(pathValue?.toFilePath());
+```
diff --git a/pkgs/cli_config/analysis_options.yaml b/pkgs/cli_config/analysis_options.yaml
new file mode 100644
index 0000000..dd3dcda
--- /dev/null
+++ b/pkgs/cli_config/analysis_options.yaml
@@ -0,0 +1,12 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-raw-types: true
+
+linter:
+ rules:
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_in_for_each
+ - prefer_final_locals
diff --git a/pkgs/cli_config/example/bin/cli_config_example.dart b/pkgs/cli_config/example/bin/cli_config_example.dart
new file mode 100644
index 0000000..1256bd7
--- /dev/null
+++ b/pkgs/cli_config/example/bin/cli_config_example.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:cli_config/cli_config.dart';
+
+Future<void> main(List<String> args) async {
+ final config = await Config.fromArguments(arguments: args);
+ final myPath =
+ config.optionalPath('my_path', resolveUri: true, mustExist: false);
+ print(myPath?.toFilePath());
+}
diff --git a/pkgs/cli_config/example/pubspec.yaml b/pkgs/cli_config/example/pubspec.yaml
new file mode 100644
index 0000000..cec900a
--- /dev/null
+++ b/pkgs/cli_config/example/pubspec.yaml
@@ -0,0 +1,11 @@
+name: cli_config_example
+description: An example for cli_config.
+
+publish_to: none
+
+environment:
+ sdk: ">=2.19.3 <4.0.0"
+
+dependencies:
+ cli_config:
+ path: ../
diff --git a/pkgs/cli_config/lib/cli_config.dart b/pkgs/cli_config/lib/cli_config.dart
new file mode 100644
index 0000000..51df312
--- /dev/null
+++ b/pkgs/cli_config/lib/cli_config.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A library to take config values from configuration files, CLI arguments,
+/// and environment variables.
+library;
+
+export 'src/config.dart';
diff --git a/pkgs/cli_config/lib/src/cli_parser.dart b/pkgs/cli_config/lib/src/cli_parser.dart
new file mode 100644
index 0000000..9396a7a
--- /dev/null
+++ b/pkgs/cli_config/lib/src/cli_parser.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:args/args.dart';
+
+class CliParser {
+ final ArgParser parser = () {
+ final parser = ArgParser();
+ parser.addFlag(
+ 'help',
+ abbr: 'h',
+ help: 'Show this help.',
+ );
+ parser.addMultiOption(
+ 'define',
+ abbr: 'D',
+ help: '''Define or override a config property from command line.
+The same option can be passed multiple times.
+Keys should only contain lower-case alphanumeric characters, underscores,
+and '.'s''',
+ );
+ parser.addOption(
+ 'config',
+ abbr: 'c',
+ help: '''Path to JSON or YAML config file.
+Keys should only contain lower-case alphanumeric characters, and underscores.
+Hierarchies should be maps.''',
+ );
+ return parser;
+ }();
+
+ ArgResults parse(List<String> args) => parser.parse(args);
+}
+
+class DefinesParser {
+ static final _defineRegex = RegExp('([a-z_.]+)=(.+)');
+
+ Map<String, List<String>> parse(List<String> args) {
+ final defines = <String, List<String>>{};
+ for (final arg in args) {
+ final match = _defineRegex.matchAsPrefix(arg);
+ if (match == null || match.group(0) != arg) {
+ throw FormatException("Define '$arg' does not match expected pattern "
+ "'${_defineRegex.pattern}'.");
+ }
+ final key = match.group(1)!;
+ final value = match.group(2)!;
+ defines[key] = (defines[key] ?? [])..add(value);
+ }
+ return defines;
+ }
+}
diff --git a/pkgs/cli_config/lib/src/cli_source.dart b/pkgs/cli_config/lib/src/cli_source.dart
new file mode 100644
index 0000000..20e662c
--- /dev/null
+++ b/pkgs/cli_config/lib/src/cli_source.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'config.dart';
+import 'source.dart';
+
+class CliSource extends Source {
+ /// Configuration options passed in via CLI arguments.
+ ///
+ /// Options can be passed multiple times, so the values here are a list.
+ ///
+ /// Stored as a flat non-hierarchical structure, keys contain `.`.
+ final Map<String, List<String>> _cli;
+
+ /// If provided, used to resolve paths within [_cli].
+ ///
+ /// Typically the current working directory at application start.
+ @override
+ final Uri? baseUri;
+
+ CliSource(this._cli, this.baseUri);
+
+ @override
+ String? optionalString(String key) {
+ final value = _cli[key];
+ if (value == null) {
+ return null;
+ }
+ if (value.length > 1) {
+ throw FormatException(
+ "More than one value was passed for '$key' in the CLI defines."
+ ' Values passed: $value');
+ }
+ return value.single;
+ }
+
+ @override
+ List<String>? optionalStringList(
+ String key, {
+ String? splitPattern,
+ }) {
+ final cliValue = _cli[key];
+ if (cliValue == null) {
+ return null;
+ }
+ if (splitPattern != null) {
+ return [for (final value in cliValue) ...value.split(splitPattern)];
+ }
+ return cliValue;
+ }
+
+ @override
+ bool? optionalBool(String key) {
+ final stringValue = optionalString(key);
+ if (stringValue != null) {
+ Source.throwIfUnexpectedValue(key, stringValue, Config.boolStrings.keys);
+ return Config.boolStrings[stringValue]!;
+ }
+ return null;
+ }
+
+ @override
+ int? optionalInt(String key) {
+ final stringValue = optionalString(key);
+ if (stringValue != null) {
+ try {
+ return int.parse(stringValue);
+ } on FormatException catch (e) {
+ throw FormatException(
+ "Unexpected value '$stringValue' for key '$key'. Expected an int."
+ ' ${e.message}');
+ }
+ }
+ return null;
+ }
+
+ @override
+ double? optionalDouble(String key) {
+ final stringValue = optionalString(key);
+ if (stringValue != null) {
+ try {
+ return double.parse(stringValue);
+ } on FormatException catch (e) {
+ throw FormatException(
+ "Unexpected value '$stringValue' for key '$key'. Expected a double."
+ ' ${e.message}');
+ }
+ }
+ return null;
+ }
+
+ @override
+ String toString() => 'CliSource($_cli)';
+}
diff --git a/pkgs/cli_config/lib/src/config.dart b/pkgs/cli_config/lib/src/config.dart
new file mode 100644
index 0000000..85e2c0c
--- /dev/null
+++ b/pkgs/cli_config/lib/src/config.dart
@@ -0,0 +1,650 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core' as core show bool, double, int;
+import 'dart:core' hide bool, double, int;
+import 'dart:io';
+
+import 'cli_parser.dart';
+import 'cli_source.dart';
+import 'environment_parser.dart';
+import 'environment_source.dart';
+import 'file_parser.dart';
+import 'file_source.dart';
+import 'source.dart';
+
+/// A hierarchical configuration.
+///
+/// Configuration can be provided from three sources: commandline arguments,
+/// environment variables and configuration files. This configuration makes
+/// these accessible via a uniform API.
+///
+/// Configuration can be provided via the three sources as follows:
+/// 1. commandline argument defines as `-Dsome_key=some_value`,
+/// 2. environment variables as `SOME_KEY=some_value`, and
+/// 3. config files as JSON or YAML as `{'some_key': 'some_value'}`.
+///
+/// The default lookup behavior is that commandline argument defines take
+/// precedence over environment variables, which take precedence over the
+/// configuration file.
+///
+/// If a single value is requested from this configuration, the first source
+/// that can provide the value will provide it. For example
+/// `config.string('some_key')` with `{'some_key': 'file_value'}` in the
+/// config file and `-Dsome_key=cli_value` as commandline argument returns
+/// `'cli_value'`. The implication is that you can not remove keys from the
+/// configuration file, only overwrite or append them.
+///
+/// If a list value is requested from this configuration, the values provided
+/// by the various sources can be combined or not. For example
+/// `config.optionalStringList('some_key', combineAllConfigs: true)` returns
+/// `['cli_value', 'file_value']`.
+///
+/// The config is hierarchical in nature, using `.` as the hierarchy separator
+/// for lookup and commandline defines. The hierarchy should be materialized in
+/// the JSON or YAML configuration file. For environment variables `__` is used
+/// as hierarchy separator.
+///
+/// Hierarchical configuration can be provided via the three sources as follows:
+/// 1. commandline argument defines as `-Dsome_key.some_nested_key=some_value`,
+/// 2. environment variables as `SOME_KEY__SOME_NESTED_KEY=some_value`, and
+/// 3. config files as JSON or YAML as
+/// ```yaml
+/// some_key:
+/// some_nested_key:
+/// some_value
+/// ```
+///
+/// The config is opinionated on the format of the keys in the sources.
+/// * Command-line argument keys should be lower-cased alphanumeric
+/// characters or underscores, with `.` for hierarchy.
+/// * Environment variables keys should be upper-cased alphanumeric
+/// characters or underscores, with `__` for hierarchy.
+/// * Config files keys should be lower-cased alphanumeric
+/// characters or underscores.
+///
+/// In the API they are made available lower-cased and with underscores, and
+/// `.` as hierarchy separator.
+class Config {
+ final CliSource _cliSource;
+ final EnvironmentSource _environmentSource;
+ final FileSource _fileSource;
+
+ /// Config sources, ordered by precedence.
+ late final _sources = [_cliSource, _environmentSource, _fileSource];
+
+ Config._(
+ this._cliSource,
+ this._environmentSource,
+ this._fileSource,
+ );
+
+ /// Constructs a config by parsing the three sources.
+ ///
+ /// If provided, [commandLineDefines] must be a list of `<key>=<value>`.
+ ///
+ /// If provided, [workingDirectory] is used to resolves paths inside
+ /// [commandLineDefines].
+ ///
+ /// If provided, [environment] must be a map containing environment variables.
+ ///
+ /// If provided, [fileParsed] must be valid parsed YSON or YAML (maps, lists,
+ /// strings, integers, and booleans).
+ ///
+ /// If provided [fileSourceUri] is used to resolve paths inside
+ /// [fileParsed] and to provide better error messages on parsing the
+ /// configuration file.
+ factory Config({
+ List<String> commandLineDefines = const [],
+ Uri? workingDirectory,
+ Map<String, String> environment = const {},
+ Map<String, dynamic> fileParsed = const {},
+ Uri? fileSourceUri,
+ }) {
+ // Parse config file.
+ final fileConfig = FileParser().parseToplevelMap(fileParsed);
+
+ // Parse CLI argument defines.
+ final cliConfig = DefinesParser().parse(commandLineDefines);
+
+ // Parse environment.
+ final environmentConfig = EnvironmentParser().parse(environment);
+
+ return Config._(
+ CliSource(cliConfig, workingDirectory?.normalizePath()),
+ EnvironmentSource(environmentConfig),
+ FileSource(fileConfig, fileSourceUri?.normalizePath()),
+ );
+ }
+
+ /// Constructs a config by parsing the three sources.
+ ///
+ /// If provided, [commandLineDefines] must be a list of `<key>=<value>`.
+ ///
+ /// If provided, [workingDirectory] is used to resolves paths inside
+ /// [commandLineDefines].
+ ///
+ /// If provided, [environment] must be a map containing environment variables.
+ ///
+ /// If provided, [fileContents] must be valid JSON or YAML.
+ ///
+ /// If provided [fileSourceUri] is used to resolve paths inside
+ /// [fileContents] and to provide better error messages on parsing the
+ /// configuration file.
+ factory Config.fromConfigFileContents({
+ List<String> commandLineDefines = const [],
+ Uri? workingDirectory,
+ Map<String, String> environment = const {},
+ String? fileContents,
+ Uri? fileSourceUri,
+ }) {
+ // Parse config file.
+ final Map<String, dynamic> fileConfig;
+ if (fileContents != null) {
+ fileConfig = FileParser().parse(
+ fileContents,
+ sourceUrl: fileSourceUri,
+ );
+ } else {
+ fileConfig = {};
+ }
+
+ // Parse CLI argument defines.
+ final cliConfig = DefinesParser().parse(commandLineDefines);
+
+ // Parse environment.
+ final environmentConfig = EnvironmentParser().parse(environment);
+
+ return Config._(
+ CliSource(cliConfig, workingDirectory),
+ EnvironmentSource(environmentConfig),
+ FileSource(fileConfig, fileSourceUri),
+ );
+ }
+
+ /// Constructs a config by parsing CLI arguments and loading the config file.
+ ///
+ /// The [arguments] must be commandline arguments.
+ ///
+ /// If provided, [environment] must be a map containing environment variables.
+ /// If not provided, [environment] defaults to [Platform.environment].
+ ///
+ /// If provided, [workingDirectory] is used to resolves paths inside
+ /// [environment].
+ /// If not provided, [workingDirectory] defaults to [Directory.current].
+ ///
+ /// This async constructor is intended to be used directly in CLI files.
+ static Future<Config> fromArguments({
+ required List<String> arguments,
+ Map<String, String>? environment,
+ Uri? workingDirectory,
+ }) async {
+ final results = CliParser().parse(arguments);
+
+ // Load config file.
+ final configFile = results['config'] as String?;
+ String? fileContents;
+ Uri? fileSourceUri;
+ if (configFile != null) {
+ fileContents = await File(configFile).readAsString();
+ fileSourceUri = Uri.file(configFile);
+ }
+
+ return Config.fromConfigFileContents(
+ commandLineDefines: results['define'] as List<String>,
+ workingDirectory: workingDirectory ?? Directory.current.uri,
+ environment: environment ?? Platform.environment,
+ fileContents: fileContents,
+ fileSourceUri: fileSourceUri,
+ );
+ }
+
+ /// Constructs a config by parsing CLI arguments and loading the config file.
+ ///
+ /// The [arguments] must be commandline arguments.
+ ///
+ /// If provided, [environment] must be a map containing environment variables.
+ /// If not provided, [environment] defaults to [Platform.environment].
+ ///
+ /// If provided, [workingDirectory] is used to resolves paths inside
+ /// [environment].
+ /// If not provided, [workingDirectory] defaults to [Directory.current].
+ ///
+ /// This synchronous constructor is intended to be used directly in CLI files.
+ static Config fromArgumentsSync({
+ required List<String> arguments,
+ Map<String, String>? environment,
+ Uri? workingDirectory,
+ }) {
+ final results = CliParser().parse(arguments);
+
+ // Load config file.
+ final configFile = results['config'] as String?;
+ String? fileContents;
+ Uri? fileSourceUri;
+ if (configFile != null) {
+ fileContents = File(configFile).readAsStringSync();
+ fileSourceUri = Uri.file(configFile);
+ }
+
+ return Config.fromConfigFileContents(
+ commandLineDefines: results['define'] as List<String>,
+ workingDirectory: workingDirectory ?? Directory.current.uri,
+ environment: environment ?? Platform.environment,
+ fileContents: fileContents,
+ fileSourceUri: fileSourceUri,
+ );
+ }
+
+ /// Lookup a string value in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// Throws if one of the configs does not contain the expected value type.
+ ///
+ /// If [validValues] is provided, throws if an unxpected value is provided.
+ String string(String key, {Iterable<String>? validValues}) {
+ final value = optionalString(key, validValues: validValues);
+ _throwIfNull(key, value);
+ return value!;
+ }
+
+ /// Lookup an optional string value in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// If [validValues] is provided, throws if an unxpected value is provided.
+ String? optionalString(String key, {Iterable<String>? validValues}) {
+ String? value;
+ for (final source in _sources) {
+ value ??= source.optionalString(key);
+ }
+ if (value != null && validValues != null) {
+ Source.throwIfUnexpectedValue(key, value, validValues);
+ }
+ return value;
+ }
+
+ /// Lookup an optional string list in this config.
+ ///
+ /// If none of the sources provide a list, lookup will fail.
+ /// If an empty list is provided by one of the sources, lookup wil succeed.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// If [combineAllConfigs] combines results from cli, environment, and
+ /// config file. Otherwise, precedence rules apply.
+ ///
+ /// If provided, [splitCliPattern] splits cli defines.
+ /// For example: `-Dfoo=bar;baz` can be split on `;`.
+ /// If not provided, a list can still be provided with multiple cli defines.
+ /// For example: `-Dfoo=bar -Dfoo=baz`.
+ ///
+ /// If provided, [splitEnvironmentPattern] splits environment values.
+ List<String> stringList(
+ String key, {
+ core.bool combineAllConfigs = true,
+ String? splitCliPattern,
+ String? splitEnvironmentPattern,
+ }) {
+ final value = optionalStringList(
+ key,
+ combineAllConfigs: combineAllConfigs,
+ splitCliPattern: splitCliPattern,
+ splitEnvironmentPattern: splitEnvironmentPattern,
+ );
+ _throwIfNull(key, value);
+ return value!;
+ }
+
+ /// Lookup an optional string list in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// If [combineAllConfigs] combines results from cli, environment, and
+ /// config file. Otherwise, precedence rules apply.
+ ///
+ /// If provided, [splitCliPattern] splits cli defines.
+ /// For example: `-Dfoo=bar;baz` can be split on `;`.
+ /// If not provided, a list can still be provided with multiple cli defines.
+ /// For example: `-Dfoo=bar -Dfoo=baz`.
+ ///
+ /// If provided, [splitEnvironmentPattern] splits environment values.
+ List<String>? optionalStringList(
+ String key, {
+ core.bool combineAllConfigs = true,
+ String? splitCliPattern,
+ String? splitEnvironmentPattern,
+ }) {
+ List<String>? result;
+ for (final entry in {
+ _cliSource: splitCliPattern,
+ _environmentSource: splitEnvironmentPattern,
+ _fileSource: null
+ }.entries) {
+ final source = entry.key;
+ final splitPattern = entry.value;
+ final value = source.optionalStringList(key, splitPattern: splitPattern);
+ if (value != null) {
+ if (combineAllConfigs) {
+ (result ??= []).addAll(value);
+ } else {
+ return value;
+ }
+ }
+ }
+ return result;
+ }
+
+ static const boolStrings = {
+ '0': false,
+ '1': true,
+ 'false': false,
+ 'FALSE': false,
+ 'no': false,
+ 'NO': false,
+ 'true': true,
+ 'TRUE': true,
+ 'yes': true,
+ 'YES': true,
+ };
+
+ /// Lookup a boolean value in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// For cli defines and environment variables, the value must be one of
+ /// [boolStrings].
+ /// For the config file, it must be a boolean.
+ ///
+ /// Throws if one of the configs does not contain the expected value type.
+ core.bool bool(String key) {
+ final value = optionalBool(key);
+ _throwIfNull(key, value);
+ return value!;
+ }
+
+ /// Lookup an optional boolean value in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// For cli defines and environment variables, the value must be one of
+ /// [boolStrings].
+ /// For the config file, it must be a boolean or null.
+ core.bool? optionalBool(String key) {
+ core.bool? value;
+ for (final source in _sources) {
+ value ??= source.optionalBool(key);
+ }
+ return value;
+ }
+
+ /// Lookup an integer value in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// For cli defines and environment variables, the value must be parseble
+ /// by [core.int.parse].
+ /// For the config file, it must be an integer.
+ core.int int(String key) {
+ final value = optionalInt(key);
+ _throwIfNull(key, value);
+ return value!;
+ }
+
+ /// Lookup an optional integer value in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// For cli defines and environment variables, the value must be parseble
+ /// by [core.int.parse].
+ /// For the config file, it must be an integer or null.
+ core.int? optionalInt(String key) {
+ core.int? value;
+ for (final source in _sources) {
+ value ??= source.optionalInt(key);
+ }
+ return value;
+ }
+
+ /// Lookup an double value in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// For cli defines and environment variables, the value must be parseble
+ /// by [core.double.parse].
+ /// For the config file, it must be an double.
+ core.double double(String key) {
+ final value = optionalDouble(key);
+ _throwIfNull(key, value);
+ return value!;
+ }
+
+ /// Lookup an optional double value in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// For cli defines and environment variables, the value must be parseble
+ /// by [core.double.parse].
+ /// For the config file, it must be an double or null.
+ core.double? optionalDouble(String key) {
+ core.double? value;
+ for (final source in _sources) {
+ value ??= source.optionalDouble(key);
+ }
+ return value;
+ }
+
+ /// Lookup a path in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// Throws if one of the configs does not contain the expected value type.
+ ///
+ /// If [resolveUri], resolves the paths in a source relative to the base
+ /// uri of that source. The base uri for the config file is the path of the
+ /// file. The base uri for environment values is the current working
+ /// directory.
+ ///
+ /// If [mustExist], throws if the path doesn't resolve to a file or directory
+ /// on the file system.
+ ///
+ /// Throws if one of the configs does not contain the expected value type.
+ Uri path(
+ String key, {
+ core.bool resolveUri = true,
+ core.bool mustExist = false,
+ }) {
+ final value =
+ optionalPath(key, resolveUri: resolveUri, mustExist: mustExist);
+ _throwIfNull(key, value);
+ return value!;
+ }
+
+ /// Lookup an optional path in this config.
+ ///
+ /// First tries CLI argument defines, then environment variables, and
+ /// finally the config file.
+ ///
+ /// Throws if one of the configs does not contain the expected value type.
+ ///
+ /// If [resolveUri], resolves the paths in a source relative to the base
+ /// uri of that source. The base uri for the config file is the path of the
+ /// file. The base uri for environment values is the current working
+ /// directory.
+ ///
+ /// If [mustExist], throws if the path doesn't resolve to a file or directory
+ /// on the file system.
+ Uri? optionalPath(
+ String key, {
+ core.bool resolveUri = true,
+ core.bool mustExist = false,
+ }) {
+ for (final source in _sources) {
+ final path = source.optionalString(key);
+ if (path != null) {
+ final value = _pathToUri(
+ path,
+ resolveUri: resolveUri,
+ baseUri: source.baseUri,
+ );
+ if (mustExist) {
+ _throwIfNotExists(key, value);
+ }
+ return value;
+ }
+ }
+ return null;
+ }
+
+ Uri _pathToUri(
+ String path, {
+ required core.bool resolveUri,
+ required Uri? baseUri,
+ }) {
+ final uri = Source.fileSystemPathToUri(path);
+ if (resolveUri && baseUri != null) {
+ return baseUri.resolveUri(uri);
+ }
+ return uri;
+ }
+
+ /// Lookup a list of paths in this config.
+ ///
+ /// If none of the sources provide a path, lookup will fail.
+ /// If an empty list is provided by one of the sources, lookup wil succeed.
+ ///
+ /// If [combineAllConfigs] combines results from cli, environment, and
+ /// config file. Otherwise, precedence rules apply.
+ ///
+ /// If provided, [splitCliPattern] splits cli defines.
+ ///
+ /// If provided, [splitEnvironmentPattern] splits environment values.
+ ///
+ /// If [resolveUri], resolves the paths in a source relative to the base
+ /// uri of that source. The base uri for the config file is the path of the
+ /// file. The base uri for environment values is the current working
+ /// directory.
+ List<Uri> pathList(
+ String key, {
+ core.bool combineAllConfigs = true,
+ String? splitCliPattern,
+ String? splitEnvironmentPattern,
+ core.bool resolveUri = true,
+ }) {
+ final value = optionalPathList(
+ key,
+ combineAllConfigs: combineAllConfigs,
+ splitCliPattern: splitCliPattern,
+ splitEnvironmentPattern: splitEnvironmentPattern,
+ resolveUri: resolveUri,
+ );
+ _throwIfNull(key, value);
+ return value!;
+ }
+
+ /// Lookup an optional list of paths in this config.
+ ///
+ /// If [combineAllConfigs] combines results from cli, environment, and
+ /// config file. Otherwise, precedence rules apply.
+ ///
+ /// If provided, [splitCliPattern] splits cli defines.
+ ///
+ /// If provided, [splitEnvironmentPattern] splits environment values.
+ ///
+ /// If [resolveUri], resolves the paths in a source relative to the base
+ /// uri of that source. The base uri for the config file is the path of the
+ /// file. The base uri for environment values is the current working
+ /// directory.
+ List<Uri>? optionalPathList(
+ String key, {
+ core.bool combineAllConfigs = true,
+ String? splitCliPattern,
+ String? splitEnvironmentPattern,
+ core.bool resolveUri = true,
+ }) {
+ List<Uri>? result;
+ for (final entry in {
+ _cliSource: splitCliPattern,
+ _environmentSource: splitEnvironmentPattern,
+ _fileSource: null
+ }.entries) {
+ final source = entry.key;
+ final splitPattern = entry.value;
+ final paths = source.optionalStringList(
+ key,
+ splitPattern: splitPattern,
+ );
+ if (paths != null) {
+ final value = [
+ for (final path in paths)
+ _pathToUri(
+ path,
+ resolveUri: resolveUri,
+ baseUri: source.baseUri,
+ )
+ ];
+ if (combineAllConfigs) {
+ (result ??= []).addAll(value);
+ } else {
+ return value;
+ }
+ }
+ }
+ return result;
+ }
+
+ /// Lookup a value of type [T] in this configuration.
+ ///
+ /// Does not support specialized options such as `splitPattern`. One must
+ /// use the specialized methods such as [optionalStringList] for that.
+ ///
+ /// If sources cannot lookup type [T], they return null.
+ T valueOf<T>(String key) {
+ T? value;
+ for (final source in _sources) {
+ value ??= source.optionalValueOf<T>(key);
+ }
+ if (null is! T) {
+ _throwIfNull(key, value);
+ }
+ return value as T;
+ }
+
+ void _throwIfNull(String key, Object? value) {
+ if (value == null) {
+ throw FormatException('No value was provided for required key: $key');
+ }
+ }
+
+ void _throwIfNotExists(String key, Uri value) {
+ final fileSystemEntity = value.fileSystemEntity;
+ if (!fileSystemEntity.existsSync()) {
+ throw FormatException("Path '$value' for key '$key' doesn't exist.");
+ }
+ }
+
+ @override
+ String toString() => 'Config($_sources)';
+}
+
+extension on Uri {
+ FileSystemEntity get fileSystemEntity {
+ if (path.endsWith(Platform.pathSeparator) || path.endsWith('/')) {
+ return Directory.fromUri(this);
+ }
+ return File.fromUri(this);
+ }
+}
diff --git a/pkgs/cli_config/lib/src/environment_parser.dart b/pkgs/cli_config/lib/src/environment_parser.dart
new file mode 100644
index 0000000..d91b8fa
--- /dev/null
+++ b/pkgs/cli_config/lib/src/environment_parser.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class EnvironmentParser {
+ /// Parses an environment key into an config key.
+ ///
+ /// Environment keys can only contain alphanumeric characters and underscores.
+ /// Treats `__` as hierarchy separator, and replaces it with `.`.
+ ///
+ /// Often, environment variables are uppercased.
+ /// Replaces all uppercase characters with lowercase characters.
+ String parseKey(String key) => key.replaceAll('__', '.').toLowerCase();
+
+ Map<String, String> parse(Map<String, String> environment) => {
+ for (final entry in environment.entries)
+ parseKey(entry.key): entry.value,
+ };
+}
diff --git a/pkgs/cli_config/lib/src/environment_source.dart b/pkgs/cli_config/lib/src/environment_source.dart
new file mode 100644
index 0000000..9cff18f
--- /dev/null
+++ b/pkgs/cli_config/lib/src/environment_source.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'config.dart';
+import 'source.dart';
+
+class EnvironmentSource extends Source {
+ /// Configuration options passed in via the [Platform.environment].
+ ///
+ /// The keys have been transformed by `EnvironmentParser.parseKey`.
+ ///
+ /// Environment values are left intact.
+ ///
+ /// Stored as a flat non-hierarchical structure, keys contain `.`.
+ final Map<String, String> _environment;
+
+ EnvironmentSource(this._environment);
+
+ @override
+ String? optionalString(String key) => _environment[key];
+
+ @override
+ List<String>? optionalStringList(
+ String key, {
+ String? splitPattern,
+ }) {
+ final envValue = _environment[key];
+ if (envValue == null) {
+ return null;
+ }
+ if (splitPattern != null) {
+ return envValue.split(splitPattern);
+ }
+ return [envValue];
+ }
+
+ @override
+ bool? optionalBool(String key) {
+ final stringValue = optionalString(key);
+ if (stringValue != null) {
+ Source.throwIfUnexpectedValue(key, stringValue, Config.boolStrings.keys);
+ return Config.boolStrings[stringValue]!;
+ }
+ return null;
+ }
+
+ @override
+ int? optionalInt(String key) {
+ final stringValue = optionalString(key);
+ if (stringValue != null) {
+ try {
+ return int.parse(stringValue);
+ } on FormatException catch (e) {
+ throw FormatException(
+ "Unexpected value '$stringValue' for key '$key'. Expected an int."
+ ' ${e.message}');
+ }
+ }
+ return null;
+ }
+
+ @override
+ double? optionalDouble(String key) {
+ final stringValue = optionalString(key);
+ if (stringValue != null) {
+ try {
+ return double.parse(stringValue);
+ } on FormatException catch (e) {
+ throw FormatException(
+ "Unexpected value '$stringValue' for key '$key'. Expected a double."
+ ' ${e.message}');
+ }
+ }
+ return null;
+ }
+
+ @override
+ String toString() => 'EnvironmentSource($_environment)';
+
+ /// Environment path are not resolved.
+ @override
+ Uri? get baseUri => null;
+}
diff --git a/pkgs/cli_config/lib/src/file_parser.dart b/pkgs/cli_config/lib/src/file_parser.dart
new file mode 100644
index 0000000..2a647e5
--- /dev/null
+++ b/pkgs/cli_config/lib/src/file_parser.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:yaml/yaml.dart';
+
+class FileParser {
+ Map<String, Object?> parse(
+ String fileContents, {
+ Uri? sourceUrl,
+ }) {
+ final parsedYaml = loadYaml(
+ fileContents,
+ sourceUrl: sourceUrl,
+ );
+ if (parsedYaml is! Map) {
+ throw const FormatException(
+ 'YAML config must be set of key value pairs.');
+ }
+ return parseToplevelMap(parsedYaml);
+ }
+
+ Map<String, Object?> parseToplevelMap(Map<dynamic, dynamic> input) {
+ final result = <String, Object?>{};
+ for (final entry in input.entries) {
+ final key = parseToplevelKey(entry.key);
+ final value = entry.value as Object?;
+ result[key] = value;
+ }
+ return result;
+ }
+
+ static final _keyRegex = RegExp('([a-z-_]+)');
+
+ String parseToplevelKey(Object? key) {
+ if (key is! String) {
+ throw FormatException("Key '$key' is not a String.");
+ }
+ final match = _keyRegex.matchAsPrefix(key);
+ if (match == null || match.group(0) != key) {
+ throw FormatException("Define '$key' does not match expected pattern "
+ "'${_keyRegex.pattern}'.");
+ }
+ return key.replaceAll('-', '_');
+ }
+}
diff --git a/pkgs/cli_config/lib/src/file_source.dart b/pkgs/cli_config/lib/src/file_source.dart
new file mode 100644
index 0000000..d0594c6
--- /dev/null
+++ b/pkgs/cli_config/lib/src/file_source.dart
@@ -0,0 +1,68 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'source.dart';
+
+class FileSource extends Source {
+ /// Configuration options passed in via a JSON or YAML configuration file.
+ ///
+ /// Stored as a partial hierarchical data structure. The values can be maps
+ /// in which subsequent parts of a key after a `.` can be resolved.
+ final Map<String, dynamic> _file;
+
+ /// If provided, used to resolve paths within [_file].
+ @override
+ final Uri? baseUri;
+
+ FileSource(this._file, this.baseUri);
+
+ @override
+ String? optionalString(String key) => optionalValueOf<String>(key);
+
+ @override
+ List<String>? optionalStringList(
+ String key, {
+ String? splitPattern,
+ }) {
+ assert(splitPattern == null);
+ return optionalValueOf<List<dynamic>>(key)?.cast<String>();
+ }
+
+ @override
+ bool? optionalBool(String key) => optionalValueOf<bool>(key);
+
+ @override
+ int? optionalInt(String key) => optionalValueOf<int>(key);
+
+ @override
+ double? optionalDouble(String key) => optionalValueOf<double>(key);
+
+ @override
+ T? optionalValueOf<T>(String key) {
+ Object? cursor = _file;
+ var current = '';
+ for (final keyPart in key.split('.')) {
+ if (cursor == null) {
+ return null;
+ }
+ if (cursor is! Map) {
+ throw FormatException(
+ "Unexpected value '$cursor' for key '$current' in config file. "
+ 'Expected a Map.');
+ } else {
+ cursor = cursor[keyPart];
+ }
+ current += '.$keyPart';
+ }
+ if (cursor is! T?) {
+ throw FormatException(
+ "Unexpected value '$cursor' for key '$current' in config file. "
+ 'Expected a $T.');
+ }
+ return cursor;
+ }
+
+ @override
+ String toString() => 'FileSource(file: $_file, fileUri: $baseUri)';
+}
diff --git a/pkgs/cli_config/lib/src/source.dart b/pkgs/cli_config/lib/src/source.dart
new file mode 100644
index 0000000..14c7965
--- /dev/null
+++ b/pkgs/cli_config/lib/src/source.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+abstract class Source {
+ /// If provided, the uri used for resolving paths.
+ Uri? get baseUri;
+
+ /// Lookup a nullable string value.
+ String? optionalString(String key);
+
+ /// Lookup a nullable string list.
+ ///
+ /// If provided, [splitPattern] splits config.
+ List<String>? optionalStringList(
+ String key, {
+ String? splitPattern,
+ });
+
+ /// Lookup an optional boolean value.
+ bool? optionalBool(String key);
+
+ /// Lookup an optional int value.
+ int? optionalInt(String key);
+
+ /// Lookup an optional int value.
+ double? optionalDouble(String key);
+
+ /// Lookup an optional value of type [T].
+ ///
+ /// Does not support specialized options such as `splitPattern`. One must
+ /// use the specialized methods such as [optionalStringList] for that.
+ ///
+ /// Returns `null` if the source cannot provide a value of type [T].
+ T? optionalValueOf<T>(String key) {
+ if (T == bool) {
+ return optionalBool(key) as T?;
+ }
+ if (T == String) {
+ return optionalString(key) as T?;
+ }
+ if (T == List<String>) {
+ return optionalStringList(key) as T?;
+ }
+ return null;
+ }
+
+ static void throwIfUnexpectedValue<T>(
+ String key, T value, Iterable<T> validValues) {
+ if (!validValues.contains(value)) {
+ throw FormatException(
+ "Unexpected value '$value' for key '$key'. Expected one of: "
+ "${validValues.map((e) => "'$e'").join(', ')}.");
+ }
+ }
+
+ static Uri fileSystemPathToUri(String path) {
+ if (path.endsWith(Platform.pathSeparator)) {
+ return Uri.directory(path);
+ }
+ return Uri.file(path);
+ }
+}
diff --git a/pkgs/cli_config/pubspec.yaml b/pkgs/cli_config/pubspec.yaml
new file mode 100644
index 0000000..54a5363
--- /dev/null
+++ b/pkgs/cli_config/pubspec.yaml
@@ -0,0 +1,18 @@
+name: cli_config
+description: >-
+ A library to take config values from configuration files, CLI arguments, and
+ environment variables.
+version: 0.2.1-wip
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/cli_config
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acli_config
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ args: ^2.4.0
+ yaml: ^3.1.1
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.21.0
diff --git a/pkgs/cli_config/test/cli_config_example_test.dart b/pkgs/cli_config/test/cli_config_example_test.dart
new file mode 100644
index 0000000..43ed7b9
--- /dev/null
+++ b/pkgs/cli_config/test/cli_config_example_test.dart
@@ -0,0 +1,106 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:test/test.dart';
+
+import 'helpers.dart';
+
+void main() {
+ test('resolve command line paths relative to working directory', () async {
+ await inTempDir((tempUri) async {
+ final rootUri = Directory.current.uri.normalizePath();
+ final examplePackageUri =
+ rootUri.resolve('example${Platform.pathSeparator}');
+ final entryPoint = 'bin${Platform.pathSeparator}cli_config_example.dart';
+ const pubSpec = 'pubspec.yaml';
+ for (final filename in [entryPoint, pubSpec]) {
+ final targetUri = tempUri.resolve(filename);
+ await File.fromUri(targetUri).create(recursive: true);
+ await File.fromUri(examplePackageUri.resolve(filename))
+ .copy(targetUri.toFilePath());
+ }
+ final pubspecFile = File.fromUri(tempUri.resolve(pubSpec));
+ await pubspecFile.writeAsString(
+ (await pubspecFile.readAsString())
+ .replaceAll('path: ../', 'path: ${rootUri.toFilePath()}'),
+ );
+
+ final pubGetResult = await runProcess(
+ executable: Uri.file(Platform.resolvedExecutable),
+ arguments: ['pub', 'get'],
+ workingDirectory: tempUri,
+ );
+ expect(pubGetResult.exitCode, 0);
+
+ {
+ final commandLinePath = Uri.file(
+ 'a${Platform.pathSeparator}b${Platform.pathSeparator}d.ext');
+ final result = await runProcess(
+ executable: Uri.file(Platform.resolvedExecutable),
+ arguments: [
+ tempUri.resolve(entryPoint).toFilePath(),
+ '-Dmy_path=${commandLinePath.toFilePath()}'
+ ],
+ workingDirectory: rootUri,
+ );
+ final stdout = (result.stdout as String).trim();
+ final resolvedPath = Uri.file(stdout);
+ expect(resolvedPath, rootUri.resolveUri(commandLinePath));
+ }
+
+ {
+ final commandLinePath = Uri.file(
+ 'a${Platform.pathSeparator}b${Platform.pathSeparator}d.ext');
+ final result = await runProcess(
+ executable: Uri.file(Platform.resolvedExecutable),
+ arguments: [
+ tempUri.resolve(entryPoint).toFilePath(),
+ '-Dmy_path=${commandLinePath.toFilePath()}'
+ ],
+ workingDirectory: tempUri,
+ );
+ final stdout = (result.stdout as String).trim();
+ final resolvedPath = Uri.file(stdout);
+ expect(resolvedPath, tempUri.resolveUri(commandLinePath));
+ }
+
+ final pathInFile =
+ Uri.file('a${Platform.pathSeparator}b${Platform.pathSeparator}d.ext');
+ final configUri = tempUri.resolve('config.yaml');
+ await File.fromUri(configUri).writeAsString('''
+my_path: ${pathInFile.toFilePath()}
+''');
+
+ {
+ final result = await runProcess(
+ executable: Uri.file(Platform.resolvedExecutable),
+ arguments: [
+ tempUri.resolve(entryPoint).toFilePath(),
+ '--config=${configUri.toFilePath()}'
+ ],
+ workingDirectory: tempUri,
+ );
+ final stdout = (result.stdout as String).trim();
+ final resolvedPath = Uri.file(stdout);
+ expect(resolvedPath, tempUri.resolveUri(pathInFile));
+ }
+
+ {
+ final result = await runProcess(
+ executable: Uri.file(Platform.resolvedExecutable),
+ arguments: [
+ tempUri.resolve(entryPoint).toFilePath(),
+ '--config=${configUri.toFilePath()}'
+ ],
+ workingDirectory: rootUri,
+ );
+ final stdout = (result.stdout as String).trim();
+ final resolvedPath = Uri.file(stdout);
+ expect(resolvedPath, tempUri.resolveUri(pathInFile));
+ }
+ });
+ });
+}
diff --git a/pkgs/cli_config/test/cli_config_test.dart b/pkgs/cli_config/test/cli_config_test.dart
new file mode 100644
index 0000000..073002c
--- /dev/null
+++ b/pkgs/cli_config/test/cli_config_test.dart
@@ -0,0 +1,567 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:cli_config/cli_config.dart';
+import 'package:test/test.dart';
+
+import 'helpers.dart';
+
+void main() {
+ test('optionalStringList', () {
+ const path1 = 'path/in/cli_arguments/';
+ const path2 = 'path/in/cli_arguments_2/';
+ const path3 = 'path/in/environment/';
+ const path4 = 'path/in/environment_2/';
+ const path5 = 'path/in/config_file/';
+ const path6 = 'path/in/config_file_2/';
+ final config = Config.fromConfigFileContents(
+ commandLineDefines: [
+ 'build.out_dir=$path1',
+ 'build.out_dir=$path2',
+ ],
+ environment: {
+ 'BUILD__OUT_DIR': '$path3:$path4',
+ },
+ fileContents: jsonEncode(
+ {
+ 'build': {
+ 'out_dir': [
+ path5,
+ path6,
+ ],
+ }
+ },
+ ),
+ );
+
+ {
+ final result = config.optionalStringList(
+ 'build.out_dir',
+ combineAllConfigs: true,
+ splitEnvironmentPattern: ':',
+ );
+ expect(result, [path1, path2, path3, path4, path5, path6]);
+ }
+
+ {
+ final result = config.optionalStringList(
+ 'build.out_dir',
+ combineAllConfigs: false,
+ splitEnvironmentPattern: ':',
+ );
+ expect(result, [path1, path2]);
+ }
+ });
+
+ test('optionalString cli precedence', () {
+ const path1 = 'path/in/cli_arguments/';
+ const path2 = 'path/in/environment/';
+ const path3 = 'path/in/config_file/';
+ final config = Config.fromConfigFileContents(
+ commandLineDefines: [
+ 'build.out_dir=$path1',
+ ],
+ environment: {
+ 'BUILD__OUT_DIR': path2,
+ },
+ fileContents: jsonEncode(
+ {
+ 'build': {
+ 'out_dir': path3,
+ }
+ },
+ ),
+ );
+
+ final result = config.optionalString(
+ 'build.out_dir',
+ );
+ expect(result, path1);
+ });
+
+ test('optionalString environment precedence', () {
+ const path2 = 'path/in/environment/';
+ const path3 = 'path/in/config_file/';
+ final config = Config.fromConfigFileContents(
+ commandLineDefines: [],
+ environment: {
+ 'BUILD__OUT_DIR': path2,
+ },
+ fileContents: jsonEncode(
+ {
+ 'build': {
+ 'out_dir': path3,
+ }
+ },
+ ),
+ );
+
+ final result = config.optionalString(
+ 'build.out_dir',
+ );
+ expect(result, path2);
+ });
+
+ test('optionalString config file', () {
+ const path3 = 'path/in/config_file/';
+ final config = Config.fromConfigFileContents(
+ commandLineDefines: [],
+ environment: {},
+ fileContents: jsonEncode(
+ {
+ 'build': {
+ 'out_dir': path3,
+ }
+ },
+ ),
+ );
+
+ final result = config.optionalString(
+ 'build.out_dir',
+ );
+ expect(result, path3);
+ });
+
+ test('optionalBool define', () {
+ final config = Config(
+ commandLineDefines: ['my_bool=true'],
+ );
+
+ expect(config.optionalBool('my_bool'), true);
+ });
+
+ test('optionalBool environment', () {
+ final config = Config(
+ environment: {
+ 'MY_BOOL': 'true',
+ },
+ );
+
+ expect(config.optionalBool('my_bool'), true);
+ });
+
+ test('optionalBool file', () {
+ final config = Config.fromConfigFileContents(
+ fileContents: jsonEncode(
+ {'my_bool': true},
+ ),
+ );
+
+ expect(config.optionalBool('my_bool'), true);
+ });
+
+ test('Read file and parse CLI args', () async {
+ final temp = await Directory.systemTemp.createTemp();
+ final configFile = File.fromUri(temp.uri.resolve('config.yaml'));
+ await configFile.writeAsString(jsonEncode(
+ {
+ 'build': {
+ 'out_dir': 'path/in/config_file/',
+ }
+ },
+ ));
+ final config = await Config.fromArguments(
+ arguments: [
+ '--config',
+ configFile.path,
+ '-Dbuild.out_dir=path/in/cli_arguments/',
+ ],
+ environment: {
+ 'BUILD__OUT_DIR': 'path/in/environment',
+ },
+ );
+
+ final result = config.optionalString('build.out_dir');
+ expect(result, 'path/in/cli_arguments/');
+ });
+
+ test('Resolve config file path relative to config file', () async {
+ final temp = await Directory.systemTemp.createTemp();
+ final tempUri = temp.uri;
+ final configUri = tempUri.resolve('config.yaml');
+ final configFile = File.fromUri(configUri);
+ const relativePath = 'path/in/config_file/';
+ final resolvedPath = configUri.resolve(relativePath);
+
+ await configFile.writeAsString(jsonEncode(
+ {
+ 'build': {
+ 'out_dir': relativePath,
+ }
+ },
+ ));
+
+ final config = await Config.fromArguments(
+ arguments: [
+ '--config',
+ configFile.path,
+ ],
+ );
+ final result = config.optionalPath('build.out_dir');
+ expect(result!.path, resolvedPath.path);
+
+ final configSync = Config.fromArgumentsSync(
+ arguments: [
+ '--config',
+ configFile.path,
+ ],
+ );
+ final resultSync = configSync.optionalPath('build.out_dir');
+ expect(resultSync!.path, resolvedPath.path);
+ });
+
+ test('provide pre-parsed config', () {
+ const path3 = 'path/in/config_file/';
+ final config = Config(
+ commandLineDefines: [],
+ environment: {},
+ fileParsed: {
+ 'build': {
+ 'out_dir': path3,
+ }
+ },
+ );
+
+ final result = config.optionalString('build.out_dir');
+ expect(result, path3);
+ });
+
+ test('path exists', () async {
+ await inTempDir((tempUri) async {
+ final tempFileUri = tempUri.resolve('file.ext');
+ await File.fromUri(tempFileUri).create();
+ final nonExistUri = tempUri.resolve('foo.ext');
+ final config = Config(
+ commandLineDefines: [],
+ environment: {},
+ fileParsed: {
+ 'build': {
+ 'out_dir': tempUri.toFilePath(),
+ 'file': tempFileUri.toFilePath(),
+ 'non_exist': nonExistUri.toFilePath(),
+ }
+ },
+ );
+
+ final result = config.optionalPath('build.out_dir', mustExist: true);
+ expect(result, tempUri);
+ final result2 = config.optionalPath('build.file', mustExist: true);
+ expect(result2, tempFileUri);
+ expect(
+ () => config.optionalPath('build.non_exist', mustExist: true),
+ throwsFormatException,
+ );
+ });
+ });
+
+ test('wrong CLI key format', () {
+ expect(
+ () => Config(commandLineDefines: ['CAPITALIZED=value']),
+ throwsFormatException,
+ );
+ });
+
+ test('CLI two values when expecting one', () {
+ final config = Config(commandLineDefines: ['key=value', 'key=value2']);
+ expect(
+ () => config.string('key'),
+ throwsFormatException,
+ );
+ });
+
+ test('CLI split optionalStringList', () {
+ final config = Config(commandLineDefines: ['key=value;value2']);
+ final value = config.optionalStringList('key', splitCliPattern: ';');
+ expect(value, ['value', 'value2']);
+ });
+
+ test('CLI path', () {
+ final uri = Uri.file('some/path.ext');
+ final config = Config(commandLineDefines: ['key=${uri.path}']);
+ final value = config.optionalPath('key');
+ expect(value, uri);
+ });
+
+ test('CLI path list', () {
+ final uri = Uri.file('some/path.ext');
+ final uri2 = Uri.file('some/directory/');
+ final config = Config(commandLineDefines: ['key=${uri.path}:${uri2.path}']);
+ final value = config.optionalPathList('key', splitCliPattern: ':');
+ expect(value, [uri, uri2]);
+ });
+
+ test('toString', () {
+ final config = Config(
+ commandLineDefines: ['key=foo'],
+ environment: {'key': 'bar'},
+ fileParsed: {'key': 'baz'},
+ );
+ config.toString();
+ });
+
+ test('Missing nonullable throws FormatException', () {
+ final config = Config.fromConfigFileContents();
+ expect(() => config.bool('key'), throwsFormatException);
+ expect(() => config.string('key'), throwsFormatException);
+ expect(() => config.path('key'), throwsFormatException);
+ });
+
+ test('string not validValue throws FormatException', () {
+ final config = Config(environment: {'foo': 'bar'});
+ expect(
+ () => config.string('foo', validValues: ['not_bar']),
+ throwsFormatException,
+ );
+ });
+
+ test('optionalString validValues', () {
+ final config = Config();
+ expect(config.optionalString('foo', validValues: ['bar']), isNull);
+ });
+
+ test('valueOf file source', () {
+ final config = Config(fileParsed: {
+ 'key': {'some': 'map'}
+ });
+ final value = config.valueOf<Map<dynamic, dynamic>>('key');
+ expect(value, {'some': 'map'});
+ });
+
+ test('valueOf command line source', () {
+ final config = Config(commandLineDefines: [
+ 'string_key=value',
+ 'bool_key=true',
+ 'string_list_key=value1',
+ 'string_list_key=value2',
+ ]);
+ expect(config.valueOf<String>('string_key'), 'value');
+ expect(config.valueOf<bool>('bool_key'), true);
+ expect(
+ config.valueOf<List<String>>('string_list_key'),
+ ['value1', 'value2'],
+ );
+ });
+
+ test('environment split optionalStringList', () {
+ final config = Config(environment: {'key': 'value;value2'});
+ final value =
+ config.optionalStringList('key', splitEnvironmentPattern: ';');
+ expect(value, ['value', 'value2']);
+ });
+
+ test('environment non split optionalStringList', () {
+ final config = Config(environment: {'key': 'value'});
+ final value = config.optionalStringList('key');
+ expect(value, ['value']);
+ });
+
+ test('environment path', () {
+ final uri = Uri.file('some/path.ext');
+ final config = Config(environment: {'key': uri.path});
+ final value = config.optionalPath('key');
+ expect(value, uri);
+ });
+
+ test('environment path list', () {
+ final uri = Uri.file('some/path.ext');
+ final uri2 = Uri.file('some/directory/');
+ final config = Config(environment: {'key': '${uri.path}:${uri2.path}'});
+ final value = config.optionalPathList('key', splitEnvironmentPattern: ':');
+ expect(value, [uri, uri2]);
+ });
+
+ test('Unexpected config file contents', () {
+ expect(() => Config.fromConfigFileContents(fileContents: 'asdf'),
+ throwsFormatException);
+ expect(() => Config.fromConfigFileContents(fileContents: "['asdf']"),
+ throwsFormatException);
+ expect(
+ () => Config.fromConfigFileContents(
+ fileContents: '''
+WRONGKEY:
+ 1
+'''
+ .trim()),
+ throwsFormatException,
+ );
+ expect(
+ () => Config.fromConfigFileContents(
+ fileContents: '''
+1: 'asdf'
+'''
+ .trim()),
+ throwsFormatException,
+ );
+ });
+
+ test('file config try to access object as wrong type', () {
+ final config = Config.fromConfigFileContents(fileContents: '''foo:
+ bar:
+ true
+''');
+ expect(config.bool('foo.bar'), true);
+ expect(() => config.bool('foo.bar.baz'), throwsFormatException);
+ expect(() => config.string('foo.bar'), throwsFormatException);
+ });
+
+ test('file config path list unresolved', () {
+ final uri = Uri.file('some/path.ext');
+ final uri2 = Uri.file('some/directory/');
+ final config = Config(fileParsed: {
+ 'key': [uri.path, uri2.path]
+ });
+ final value = config.optionalPathList('key', resolveUri: false);
+ expect(value, [uri, uri2]);
+ });
+
+ test('file config path list resolved', () {
+ final configUri = Uri.file('path/to/config.json');
+ final uri = Uri.file('some/path.ext');
+ final uri2 = Uri.file('some/directory/');
+ final config = Config(
+ fileSourceUri: configUri,
+ fileParsed: {
+ 'key': [uri.path, uri2.path]
+ },
+ );
+ final value = config.optionalPathList('key', resolveUri: true);
+ expect(value, [configUri.resolveUri(uri), configUri.resolveUri(uri2)]);
+ });
+
+ test('resolveUri in working directory', () {
+ final systemTemp = Directory.systemTemp.uri;
+ final tempUri = systemTemp.resolve('x/y/z/');
+
+ final relativePath = Uri.file('a/b/c/d.ext');
+ final absolutePath = tempUri.resolveUri(relativePath);
+ final config = Config(
+ commandLineDefines: ['path=${relativePath.path}'],
+ workingDirectory: tempUri,
+ );
+
+ expect(config.optionalPath('path', mustExist: false, resolveUri: true),
+ absolutePath);
+ });
+
+ test('ints', () {
+ final config = Config(
+ commandLineDefines: ['cl=1', 'not_parsable=asdf'],
+ environment: {
+ 'env': '2',
+ 'not_parsable2': 'asfd',
+ },
+ fileParsed: {'file': 3},
+ );
+
+ expect(config.int('cl'), 1);
+ expect(config.optionalInt('env'), 2);
+ expect(config.optionalInt('file'), 3);
+ expect(config.optionalInt('nothing'), null);
+ expect(() => config.optionalInt('not_parsable'), throwsFormatException);
+ expect(() => config.optionalInt('not_parsable2'), throwsFormatException);
+ });
+
+ test('doubles', () {
+ final config = Config(
+ commandLineDefines: ['cl=1.1', 'not_parsable=asdf'],
+ environment: {
+ 'env': '2.2',
+ 'not_parsable2': 'asfd',
+ },
+ fileParsed: {'file': 3.3},
+ );
+
+ expect(config.double('cl'), 1.1);
+ expect(config.optionalDouble('env'), 2.2);
+ expect(config.optionalDouble('file'), 3.3);
+ expect(config.optionalDouble('nothing'), null);
+ expect(() => config.optionalDouble('not_parsable'), throwsFormatException);
+ expect(() => config.optionalDouble('not_parsable2'), throwsFormatException);
+ });
+
+ test('stringList and optionalStringList', () {
+ {
+ final config = Config(
+ fileParsed: {},
+ );
+
+ expect(config.optionalStringList('my_list'), null);
+ expect(() => config.stringList('my_list'), throwsFormatException);
+ }
+
+ {
+ final config = Config(
+ fileParsed: {'my_list': <String>[]},
+ );
+
+ expect(config.optionalStringList('my_list'), <String>[]);
+ expect(config.stringList('my_list'), <String>[]);
+ }
+ });
+
+ test('pathList and optionalPathList', () {
+ {
+ final config = Config(
+ fileParsed: {},
+ );
+
+ expect(config.optionalPathList('my_list'), null);
+ expect(() => config.pathList('my_list'), throwsFormatException);
+ }
+
+ {
+ final config = Config(
+ fileParsed: {'my_list': <String>[]},
+ );
+
+ expect(config.optionalPathList('my_list'), <String>[]);
+ expect(config.pathList('my_list'), <String>[]);
+ }
+ });
+
+ test('non-string key maps', () {
+ // This is valid in YAML (not in JSON).
+ //
+ // Such values cannot be accessed with our hierarchical keys, but they can
+ // be accessed with [Config.valueOf].
+ final config = Config(
+ fileParsed: {
+ 'my_non_string_key_map': {
+ 1: 'asdf',
+ 2: 'foo',
+ },
+ },
+ );
+
+ expect(
+ config.valueOf<Map<Object, Object?>>('my_non_string_key_map'),
+ {
+ 1: 'asdf',
+ 2: 'foo',
+ },
+ );
+ });
+
+ test('null values in maps', () {
+ final config = Config(
+ fileParsed: {
+ 'my_non_string_key_map': {
+ 'x': null,
+ 'y': 42,
+ },
+ },
+ );
+
+ expect(
+ config.valueOf<Map<Object, Object?>>('my_non_string_key_map'),
+ {
+ 'x': null,
+ 'y': 42,
+ },
+ );
+ });
+}
diff --git a/pkgs/cli_config/test/cli_config_windows_test.dart b/pkgs/cli_config/test/cli_config_windows_test.dart
new file mode 100644
index 0000000..2c401f2
--- /dev/null
+++ b/pkgs/cli_config/test/cli_config_windows_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('windows')
+library;
+
+import 'package:cli_config/cli_config.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('path resolving windows', () {
+ const path = 'C:\\foo\\bar\\';
+ final workingDirectory = Uri.parse('file:///C:/baz/baf/');
+
+ final config = Config(
+ commandLineDefines: ['key=$path'],
+ workingDirectory: workingDirectory,
+ );
+ final value = config.path('key', resolveUri: true);
+ expect(value.toFilePath(), path);
+ });
+}
diff --git a/pkgs/cli_config/test/helpers.dart b/pkgs/cli_config/test/helpers.dart
new file mode 100644
index 0000000..d9fb40e
--- /dev/null
+++ b/pkgs/cli_config/test/helpers.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+const keepTempKey = 'KEEP_TEMPORARY_DIRECTORIES';
+
+Future<void> inTempDir(
+ Future<void> Function(Uri tempUri) fun, {
+ String? prefix,
+}) async {
+ final tempDir = await Directory.systemTemp.createTemp(prefix);
+ // Deal with Windows temp folder aliases.
+ final tempUri =
+ Directory(await tempDir.resolveSymbolicLinks()).uri.normalizePath();
+ try {
+ await fun(tempUri);
+ } finally {
+ if (!Platform.environment.containsKey(keepTempKey) ||
+ Platform.environment[keepTempKey]!.isEmpty) {
+ await tempDir.delete(recursive: true);
+ }
+ }
+}
+
+Future<ProcessResult> runProcess({
+ required Uri executable,
+ List<String> arguments = const [],
+ required Uri workingDirectory,
+}) async {
+ final result = await Process.run(
+ executable.toFilePath(),
+ arguments,
+ workingDirectory: workingDirectory.toFilePath(),
+ );
+ if (result.exitCode != 0) {
+ print(result.stdout);
+ print(result.stderr);
+ print(result.exitCode);
+ }
+ return result;
+}
diff --git a/pkgs/cli_util/.gitignore b/pkgs/cli_util/.gitignore
new file mode 100644
index 0000000..49ce72d
--- /dev/null
+++ b/pkgs/cli_util/.gitignore
@@ -0,0 +1,3 @@
+.dart_tool/
+.packages
+pubspec.lock
diff --git a/pkgs/cli_util/AUTHORS b/pkgs/cli_util/AUTHORS
new file mode 100644
index 0000000..7a6d1d9
--- /dev/null
+++ b/pkgs/cli_util/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the cli_util project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/cli_util/CHANGELOG.md b/pkgs/cli_util/CHANGELOG.md
new file mode 100644
index 0000000..9e77b8f
--- /dev/null
+++ b/pkgs/cli_util/CHANGELOG.md
@@ -0,0 +1,105 @@
+## 0.4.2
+
+- Add `sdkPath` getter, deprecate `getSdkPath` function.
+* Move to `dart-lang/tools` monorepo.
+
+## 0.4.1
+
+- Fix a broken link in the readme.
+- Require Dart 3.0.
+
+## 0.4.0
+
+- Remove the deprecated method `getSdkDir()` (instead, use `getSdkPath()`).
+- Require Dart 2.19.
+
+## 0.3.5
+- Make `applicationConfigHome` throw an `Exception` when it fails to find a
+ configuration folder.
+
+## 0.3.4
+
+- Introduce `applicationConfigHome` for making it easy to consistently find the
+ user-specific application configuration folder.
+
+## 0.3.3
+
+- Reverted `meta` constraint to `^1.3.0`.
+
+## 0.3.2
+
+- Update `meta` constraint to `>=1.3.0 <3.0.0`.
+
+## 0.3.1
+
+- Fix a bug in `AnsiProgress` where the spinning character doesn't every update.
+
+## 0.3.0
+
+- Stable null safety release.
+
+## 0.3.0-nullsafety.0
+
+- Updated to support 2.12.0 and null safety.
+
+## 0.2.1
+
+## 0.2.0
+
+- Add `Logger.write` and `Logger.writeCharCode` methods which write without
+ printing a trailing newline.
+
+## 0.1.4
+
+- Add `Ansi.reversed` getter.
+
+## 0.1.3+2
+
+- Update Dart SDK constraint to < 3.0.0.
+
+## 0.1.3+1
+
+- Update Dart SDK to 2.0.0-dev.
+
+## 0.1.3
+
+- In verbose mode, instead of printing the diff from the last log message,
+ print the total time since the tool started
+- Change to not buffer the last log message sent in verbose logging mode
+- Expose more classes from the logging library
+
+## 0.1.2+1
+
+- Remove unneeded change to Dart SDK constraint.
+
+## 0.1.2
+
+- Fix a bug in `getSdkDir` (#21)
+
+## 0.1.1
+
+- Updated to the output for indeterminate progress
+- Exposed a `Logger.isVerbose` getter
+
+## 0.1.0
+
+- Added a new `getSdkPath()` method to get the location of the SDK (this uses the new
+ `Platform.resolvedExecutable` API to locate the SDK)
+- Deprecated `getSdkDir()` in favor of `getSdkPath()`
+- Add the `cli_logging.dart` library - utilities to display output and progress
+
+## 0.0.1+3
+
+- Find SDK properly when invoked from inside SDK tests.
+
+## 0.0.1+2
+
+- Support an executable in a symlinked directory.
+
+## 0.0.1+1
+
+- Fix for when the dart executable can't be found by `which`.
+
+## 0.0.1
+
+- Initial version
diff --git a/pkgs/cli_util/LICENSE b/pkgs/cli_util/LICENSE
new file mode 100644
index 0000000..dbd2843
--- /dev/null
+++ b/pkgs/cli_util/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2015, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/cli_util/README.md b/pkgs/cli_util/README.md
new file mode 100644
index 0000000..b86e8c0
--- /dev/null
+++ b/pkgs/cli_util/README.md
@@ -0,0 +1,68 @@
+[](https://github.com/dart-lang/tools/actions/workflows/cli_util.yaml)
+[](https://pub.dev/packages/cli_util)
+[](https://pub.dev/packages/cli_util/publisher)
+
+A package to help in building Dart command-line apps.
+
+## What's this?
+
+`package:cli_util` provides:
+- utilities to find the Dart SDK directory (`sdkPath`)
+- utilities to find the settings directory for a tool (`applicationConfigHome()`)
+- utilities to aid in showing rich CLI output and progress information (`cli_logging.dart`)
+
+## Locating the Dart SDK
+
+```dart
+import 'dart:io';
+
+import 'package:cli_util/cli_util.dart';
+import 'package:path/path.dart' as path;
+
+main(args) {
+ // Get SDK directory from cli_util.
+ var sdkDir = sdkPath;
+
+ // Do stuff... For example, print version string
+ var versionFile = File(path.join(sdkDir, 'version'));
+ print(versionFile.readAsStringSync());
+}
+```
+
+## Displaying output and progress
+
+`package:cli_util` can also be used to help CLI tools display output and progress.
+It has a logging mechanism which can help differentiate between regular tool
+output and error messages, and can facilitate having a more verbose (`-v`) mode for
+output.
+
+In addition, it can display an indeterminate progress spinner for longer running
+tasks, and optionally display the elapsed time when finished:
+
+```dart
+import 'package:cli_util/cli_logging.dart';
+
+void main(List<String> args) async {
+ var verbose = args.contains('-v');
+ var logger = verbose ? Logger.verbose() : Logger.standard();
+
+ logger.stdout('Hello world!');
+ logger.trace('message 1');
+ await Future.delayed(Duration(milliseconds: 200));
+ logger.trace('message 2');
+ logger.trace('message 3');
+
+ var progress = logger.progress('doing some work');
+ await Future.delayed(Duration(seconds: 2));
+ progress.finish(showTiming: true);
+
+ logger.stdout('All ${logger.ansi.emphasized('done')}.');
+ logger.flush();
+}
+```
+
+## Features and bugs
+
+Please file feature requests and bugs at the [issue tracker][tracker].
+
+[tracker]: https://github.com/dart-lang/tools/issues
diff --git a/pkgs/cli_util/analysis_options.yaml b/pkgs/cli_util/analysis_options.yaml
new file mode 100644
index 0000000..a30462e
--- /dev/null
+++ b/pkgs/cli_util/analysis_options.yaml
@@ -0,0 +1,32 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_classes_with_only_static_members
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_returning_this
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - join_return_with_assignment
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - no_runtimeType_toString
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - unnecessary_await_in_return
+ - unnecessary_raw_strings
+ - use_if_null_to_convert_nulls_to_bools
+ - use_raw_strings
+ - use_string_buffers
diff --git a/pkgs/cli_util/example/main.dart b/pkgs/cli_util/example/main.dart
new file mode 100644
index 0000000..3bae827
--- /dev/null
+++ b/pkgs/cli_util/example/main.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:cli_util/cli_logging.dart';
+
+Future<void> main(List<String> args) async {
+ final verbose = args.contains('-v');
+ final logger = verbose ? Logger.verbose() : Logger.standard();
+
+ logger.stdout('Hello world!');
+ logger.trace('message 1');
+ await Future<void>.delayed(const Duration(milliseconds: 200));
+ logger.trace('message 2');
+ logger.trace('message 3');
+
+ final progress = logger.progress('doing some work');
+ await Future<void>.delayed(const Duration(seconds: 2));
+ progress.finish(showTiming: true);
+
+ logger.stdout('All ${logger.ansi.emphasized('done')}.');
+}
diff --git a/pkgs/cli_util/lib/cli_logging.dart b/pkgs/cli_util/lib/cli_logging.dart
new file mode 100644
index 0000000..dda287b
--- /dev/null
+++ b/pkgs/cli_util/lib/cli_logging.dart
@@ -0,0 +1,316 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library contains functionality to help command-line utilities to easily
+/// create aesthetic output.
+library;
+
+import 'dart:async';
+import 'dart:io' as io;
+
+/// A small utility class to make it easier to work with common ANSI escape
+/// sequences.
+class Ansi {
+ /// Return whether the current stdout terminal supports ANSI escape sequences.
+ static bool get terminalSupportsAnsi =>
+ io.stdout.supportsAnsiEscapes &&
+ io.stdioType(io.stdout) == io.StdioType.terminal;
+
+ final bool useAnsi;
+
+ Ansi(this.useAnsi);
+
+ String get cyan => _code('\u001b[36m');
+
+ String get green => _code('\u001b[32m');
+
+ String get magenta => _code('\u001b[35m');
+
+ String get red => _code('\u001b[31m');
+
+ String get yellow => _code('\u001b[33m');
+
+ String get blue => _code('\u001b[34m');
+
+ String get gray => _code('\u001b[1;30m');
+
+ String get noColor => _code('\u001b[39m');
+
+ String get none => _code('\u001b[0m');
+
+ String get bold => _code('\u001b[1m');
+
+ String get reversed => _code('\u001b[7m');
+
+ String get backspace => '\b';
+
+ String get bullet => io.stdout.supportsAnsiEscapes ? '•' : '-';
+
+ /// Display [message] in an emphasized format.
+ String emphasized(String message) => '$bold$message$none';
+
+ /// Display [message] in an subtle (gray) format.
+ String subtle(String message) => '$gray$message$none';
+
+ /// Display [message] in an error (red) format.
+ String error(String message) => '$red$message$none';
+
+ String _code(String ansiCode) => useAnsi ? ansiCode : '';
+}
+
+/// An abstract representation of a [Logger] - used to pretty print errors,
+/// standard status messages, trace level output, and indeterminate progress.
+abstract class Logger {
+ /// Create a normal [Logger]; this logger will not display trace level output.
+ factory Logger.standard({Ansi? ansi}) => StandardLogger(ansi: ansi);
+
+ /// Create a [Logger] that will display trace level output.
+ ///
+ /// If [logTime] is `true`, this logger will display the time of the message.
+ factory Logger.verbose({Ansi? ansi, bool logTime = true}) =>
+ VerboseLogger(ansi: ansi, logTime: logTime);
+
+ Ansi get ansi;
+
+ bool get isVerbose;
+
+ /// Print an error message.
+ void stderr(String message);
+
+ /// Print a standard status message.
+ void stdout(String message);
+
+ /// Print trace output.
+ void trace(String message);
+
+ /// Print text to stdout, without a trailing newline.
+ void write(String message);
+
+ /// Print a character code to stdout, without a trailing newline.
+ void writeCharCode(int charCode);
+
+ /// Start an indeterminate progress display.
+ Progress progress(String message);
+
+ /// Flush any un-written output.
+ @Deprecated('This method will be removed in the future')
+ void flush();
+}
+
+/// A handle to an indeterminate progress display.
+abstract class Progress {
+ final String message;
+ final Stopwatch _stopwatch;
+
+ Progress(this.message) : _stopwatch = Stopwatch()..start();
+
+ Duration get elapsed => _stopwatch.elapsed;
+
+ /// Finish the indeterminate progress display.
+ void finish({String? message, bool showTiming = false});
+
+ /// Cancel the indeterminate progress display.
+ void cancel();
+}
+
+class StandardLogger implements Logger {
+ @override
+ Ansi ansi;
+
+ StandardLogger({Ansi? ansi}) : ansi = ansi ?? Ansi(Ansi.terminalSupportsAnsi);
+
+ @override
+ bool get isVerbose => false;
+
+ Progress? _currentProgress;
+
+ @override
+ void stderr(String message) {
+ _cancelProgress();
+
+ io.stderr.writeln(message);
+ }
+
+ @override
+ void stdout(String message) {
+ _cancelProgress();
+
+ print(message);
+ }
+
+ @override
+ void trace(String message) {}
+
+ @override
+ void write(String message) {
+ _cancelProgress();
+
+ io.stdout.write(message);
+ }
+
+ @override
+ void writeCharCode(int charCode) {
+ _cancelProgress();
+
+ io.stdout.writeCharCode(charCode);
+ }
+
+ void _cancelProgress() {
+ final progress = _currentProgress;
+ if (progress != null) {
+ _currentProgress = null;
+ progress.cancel();
+ }
+ }
+
+ @override
+ Progress progress(String message) {
+ _cancelProgress();
+
+ final progress = ansi.useAnsi
+ ? AnsiProgress(ansi, message)
+ : SimpleProgress(this, message);
+ _currentProgress = progress;
+ return progress;
+ }
+
+ @override
+ @Deprecated('This method will be removed in the future')
+ void flush() {}
+}
+
+class SimpleProgress extends Progress {
+ final Logger logger;
+
+ SimpleProgress(this.logger, String message) : super(message) {
+ logger.stdout('$message...');
+ }
+
+ @override
+ void cancel() {}
+
+ @override
+ void finish({String? message, bool showTiming = false}) {}
+}
+
+class AnsiProgress extends Progress {
+ static const List<String> kAnimationItems = ['/', '-', r'\', '|'];
+
+ final Ansi ansi;
+
+ late final Timer _timer;
+
+ AnsiProgress(this.ansi, String message) : super(message) {
+ _timer = Timer.periodic(const Duration(milliseconds: 80), (t) {
+ _updateDisplay();
+ });
+ io.stdout.write('$message... '.padRight(40));
+ _updateDisplay();
+ }
+
+ @override
+ void cancel() {
+ if (_timer.isActive) {
+ _timer.cancel();
+ _updateDisplay(cancelled: true);
+ }
+ }
+
+ @override
+ void finish({String? message, bool showTiming = false}) {
+ if (_timer.isActive) {
+ _timer.cancel();
+ _updateDisplay(isFinal: true, message: message, showTiming: showTiming);
+ }
+ }
+
+ void _updateDisplay(
+ {bool isFinal = false,
+ bool cancelled = false,
+ String? message,
+ bool showTiming = false}) {
+ var char = kAnimationItems[_timer.tick % kAnimationItems.length];
+ if (isFinal || cancelled) {
+ char = '';
+ }
+ io.stdout.write('${ansi.backspace}$char');
+ if (isFinal || cancelled) {
+ if (message != null) {
+ io.stdout.write(message.isEmpty ? ' ' : message);
+ } else if (showTiming) {
+ final time = (elapsed.inMilliseconds / 1000.0).toStringAsFixed(1);
+ io.stdout.write('${time}s');
+ } else {
+ io.stdout.write(' ');
+ }
+ io.stdout.writeln();
+ }
+ }
+}
+
+class VerboseLogger implements Logger {
+ @override
+ Ansi ansi;
+ bool logTime;
+ final _timer = Stopwatch()..start();
+
+ VerboseLogger({Ansi? ansi, this.logTime = false})
+ : ansi = ansi ?? Ansi(Ansi.terminalSupportsAnsi);
+
+ @override
+ bool get isVerbose => true;
+
+ @override
+ void stdout(String message) {
+ io.stdout.writeln('${_createPrefix()}$message');
+ }
+
+ @override
+ void stderr(String message) {
+ io.stderr.writeln('${_createPrefix()}${ansi.red}$message${ansi.none}');
+ }
+
+ @override
+ void trace(String message) {
+ io.stdout.writeln('${_createPrefix()}${ansi.gray}$message${ansi.none}');
+ }
+
+ @override
+ void write(String message) {
+ io.stdout.write(message);
+ }
+
+ @override
+ void writeCharCode(int charCode) {
+ io.stdout.writeCharCode(charCode);
+ }
+
+ @override
+ Progress progress(String message) => SimpleProgress(this, message);
+
+ @override
+ @Deprecated('This method will be removed in the future')
+ void flush() {}
+
+ String _createPrefix() {
+ if (!logTime) {
+ return '';
+ }
+
+ var seconds = _timer.elapsedMilliseconds / 1000.0;
+ final minutes = seconds ~/ 60;
+ seconds -= minutes * 60.0;
+
+ final buf = StringBuffer();
+ if (minutes > 0) {
+ buf.write(minutes % 60);
+ buf.write('m ');
+ }
+
+ buf.write(seconds.toStringAsFixed(3).padLeft(minutes > 0 ? 6 : 1, '0'));
+ buf.write('s');
+
+ return '[${buf.toString().padLeft(11)}] ';
+ }
+}
diff --git a/pkgs/cli_util/lib/cli_util.dart b/pkgs/cli_util/lib/cli_util.dart
new file mode 100644
index 0000000..e497d68
--- /dev/null
+++ b/pkgs/cli_util/lib/cli_util.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utilities to locate the Dart SDK.
+library;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+
+/// The path to the current Dart SDK.
+String get sdkPath => path.dirname(path.dirname(Platform.resolvedExecutable));
+
+/// Returns the path to the current Dart SDK.
+@Deprecated("Use 'sdkPath' instead")
+String getSdkPath() => sdkPath;
+
+/// The user-specific application configuration folder for the current platform.
+///
+/// This is a location appropriate for storing application specific
+/// configuration for the current user. The [productName] should be unique to
+/// avoid clashes with other applications on the same machine. This method won't
+/// actually create the folder, merely return the recommended location for
+/// storing user-specific application configuration.
+///
+/// The folder location depends on the platform:
+/// * `%APPDATA%\<productName>` on **Windows**,
+/// * `$HOME/Library/Application Support/<productName>` on **Mac OS**,
+/// * `$XDG_CONFIG_HOME/<productName>` on **Linux**
+/// (if `$XDG_CONFIG_HOME` is defined), and,
+/// * `$HOME/.config/<productName>` otherwise.
+///
+/// The chosen location aims to follow best practices for each platform,
+/// honoring the [XDG Base Directory Specification][1] on Linux and
+/// [File System Basics][2] on Mac OS.
+///
+/// Throws an [EnvironmentNotFoundException] if an environment entry,
+/// `%APPDATA%` or `$HOME`, is needed and not available.
+///
+/// [1]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+/// [2]: https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW1
+String applicationConfigHome(String productName) =>
+ path.join(_configHome, productName);
+
+String get _configHome {
+ if (Platform.isWindows) {
+ return _requireEnv('APPDATA');
+ }
+
+ if (Platform.isMacOS) {
+ return path.join(_requireEnv('HOME'), 'Library', 'Application Support');
+ }
+
+ if (Platform.isLinux) {
+ final xdgConfigHome = _env['XDG_CONFIG_HOME'];
+ if (xdgConfigHome != null) {
+ return xdgConfigHome;
+ }
+ // XDG Base Directory Specification says to use $HOME/.config/ when
+ // $XDG_CONFIG_HOME isn't defined.
+ return path.join(_requireEnv('HOME'), '.config');
+ }
+
+ // We have no guidelines, perhaps we should just do: $HOME/.config/
+ // same as XDG specification would specify as fallback.
+ return path.join(_requireEnv('HOME'), '.config');
+}
+
+String _requireEnv(String name) =>
+ _env[name] ?? (throw EnvironmentNotFoundException(name));
+
+/// Exception thrown if a required environment entry does not exist.
+///
+/// Thrown by [applicationConfigHome] if an expected and required
+/// platform specific environment entry is not available.
+class EnvironmentNotFoundException implements Exception {
+ /// Name of environment entry which was needed, but not found.
+ final String entryName;
+ String get message => 'Environment variable \'$entryName\' is not defined!';
+ EnvironmentNotFoundException(this.entryName);
+ @override
+ String toString() => message;
+}
+
+// This zone override exists solely for testing (see lib/cli_util_test.dart).
+Map<String, String> get _env =>
+ (Zone.current[#environmentOverrides] as Map<String, String>?) ??
+ Platform.environment;
diff --git a/pkgs/cli_util/pubspec.yaml b/pkgs/cli_util/pubspec.yaml
new file mode 100644
index 0000000..ab879db
--- /dev/null
+++ b/pkgs/cli_util/pubspec.yaml
@@ -0,0 +1,16 @@
+name: cli_util
+version: 0.4.2
+description: A library to help in building Dart command-line apps.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/cli_util
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acli_util
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ meta: ^1.7.0
+ path: ^1.8.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.20.0
diff --git a/pkgs/cli_util/test/cli_util_test.dart b/pkgs/cli_util/test/cli_util_test.dart
new file mode 100644
index 0000000..e16bc59
--- /dev/null
+++ b/pkgs/cli_util/test/cli_util_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:cli_util/cli_util.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+
+void main() {
+ group('sdkPath', () {
+ test('sdkPath', () {
+ expect(sdkPath, isNotNull);
+ });
+ });
+
+ group('applicationConfigHome', () {
+ test('returns a non-empty string', () {
+ expect(applicationConfigHome('dart'), isNotEmpty);
+ });
+
+ test('has an ancestor folder that exists', () {
+ final path = p.split(applicationConfigHome('dart'));
+ // We expect that first two segments of the path exist. This is really
+ // just a dummy check that some part of the path exists.
+ expect(Directory(p.joinAll(path.take(2))).existsSync(), isTrue);
+ });
+
+ test('empty environment throws exception', () async {
+ expect(() {
+ runZoned(() => applicationConfigHome('dart'), zoneValues: {
+ #environmentOverrides: <String, String>{},
+ });
+ }, throwsA(isA<EnvironmentNotFoundException>()));
+ });
+ });
+}
diff --git a/pkgs/clock/.gitignore b/pkgs/clock/.gitignore
new file mode 100644
index 0000000..63fe85d
--- /dev/null
+++ b/pkgs/clock/.gitignore
@@ -0,0 +1,5 @@
+.packages
+.pub/
+.dart_tool/
+build/
+pubspec.lock
diff --git a/pkgs/clock/AUTHORS b/pkgs/clock/AUTHORS
new file mode 100644
index 0000000..e8063a8
--- /dev/null
+++ b/pkgs/clock/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/clock/CHANGELOG.md b/pkgs/clock/CHANGELOG.md
new file mode 100644
index 0000000..f372ada
--- /dev/null
+++ b/pkgs/clock/CHANGELOG.md
@@ -0,0 +1,52 @@
+## 1.1.2
+
+* Require Dart 3.4
+* Move to `dart-lang/tools` monorepo.
+
+## 1.1.1
+
+* Switch to using `package:lints`.
+* Populate the pubspec `repository` field.
+
+## 1.1.0
+
+* Update SDK constraints to `>=2.12.0 <3.0.0`.
+* Update to null safety.
+
+## 1.0.1
+
+* Update to lowercase Dart core library constants.
+
+## 1.0.0
+
+This release contains the `Clock` class that was defined in [`quiver`][]. It's
+backwards-compatible with the `quiver` version, and *mostly*
+backwards-compatible with the old version of the `clock` package.
+
+[`quiver`]: https://pub.dartlang.org/packages/quiver
+
+### New Features
+
+* A top-level `clock` field has been added that provides a default `Clock`
+ implementation. It can be controlled by the `withClock()` function. It should
+ generally be used in preference to manual dependency-injection, since it will
+ work with the [`fake_async`][] package.
+
+* A `Clock.stopwatch()` method has been added that creates a `Stopwatch` that
+ uses the clock as its source of time.
+
+[`fake_async`]: https://pub.dartlang.org/packages/fake_async
+
+### Changes Relative to `clock` 0.1
+
+* The top-level `new` getter and `getStopwatch()` methods are deprecated.
+ `clock.new()` and `clock.stopwatch()` should be used instead.
+
+* `Clock.getStopwatch()` is deprecated. `Clock.stopwatch()` should be used instead.
+
+* The `isFinal` argument to `withClock()` is deprecated.
+
+* `new Clock()` now takes an optional positional argument that returns the
+ current time as a `DateTime` instead of its old arguments.
+
+* `Clock.now()` is now a method rather than a getter.
diff --git a/pkgs/clock/LICENSE b/pkgs/clock/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/pkgs/clock/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/pkgs/clock/README.md b/pkgs/clock/README.md
new file mode 100644
index 0000000..dccdc07
--- /dev/null
+++ b/pkgs/clock/README.md
@@ -0,0 +1,52 @@
+[](https://github.com/dart-lang/tools/actions/workflows/clock.yaml)
+[](https://pub.dev/packages/clock)
+[](https://pub.dev/packages/clock/publisher)
+
+This package provides a [`Clock`][] class which encapsulates the notion of the
+"current time" and provides easy access to points relative to the current time.
+Different `Clock`s can have a different notion of the current time, and the
+default top-level [`clock`][]'s notion can be swapped out to reliably test
+timing-dependent code.
+
+[`Clock`]: https://pub.dev/documentation/clock/latest/clock/Clock-class.html
+[`clock`]: https://pub.dev/documentation/clock/latest/clock/clock.html
+
+For example, you can use `clock` in your libraries like this:
+
+```dart
+// run_with_timing.dart
+import 'package:clock/clock.dart';
+
+/// Runs [callback] and prints how long it took.
+T runWithTiming<T>(T Function() callback) {
+ var stopwatch = clock.stopwatch()..start();
+ var result = callback();
+ print('It took ${stopwatch.elapsed}!');
+ return result;
+}
+```
+
+...and then test your code using the [`fake_async`][] package, which
+automatically overrides the current clock:
+
+[`fake_async`]: https://pub.dartlang.org/packages/fake_async
+
+```dart
+// run_with_timing_test.dart
+import 'run_with_timing.dart';
+
+import 'package:fake_async/fake_async.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('runWithTiming() prints the elapsed time', () {
+ FakeAsync().run((async) {
+ expect(() {
+ runWithTiming(() {
+ async.elapse(Duration(seconds: 10));
+ });
+ }, prints('It took 0:00:10.000000!'));
+ });
+ });
+}
+```
diff --git a/pkgs/clock/analysis_options.yaml b/pkgs/clock/analysis_options.yaml
new file mode 100644
index 0000000..9ee7c2b
--- /dev/null
+++ b/pkgs/clock/analysis_options.yaml
@@ -0,0 +1,14 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - use_super_parameters
diff --git a/pkgs/clock/lib/clock.dart b/pkgs/clock/lib/clock.dart
new file mode 100644
index 0000000..755789e
--- /dev/null
+++ b/pkgs/clock/lib/clock.dart
@@ -0,0 +1,34 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'src/default.dart';
+
+export 'src/clock.dart';
+export 'src/default.dart';
+
+/// Returns current time.
+@Deprecated('Pass around an instance of Clock instead.')
+typedef TimeFunction = DateTime Function();
+
+/// Returns the current system time.
+@Deprecated('Use new DateTime.now() instead.')
+DateTime systemTime() => DateTime.now();
+
+/// Returns the current time as reported by [clock].
+@Deprecated('Use clock.now() instead.')
+DateTime get now => clock.now();
+
+/// Returns a stopwatch that uses the current time as reported by [clock].
+@Deprecated('Use clock.stopwatch() instead.')
+Stopwatch getStopwatch() => clock.stopwatch();
diff --git a/pkgs/clock/lib/src/clock.dart b/pkgs/clock/lib/src/clock.dart
new file mode 100644
index 0000000..f6f47de
--- /dev/null
+++ b/pkgs/clock/lib/src/clock.dart
@@ -0,0 +1,182 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import '../clock.dart';
+import 'stopwatch.dart';
+import 'utils.dart';
+
+/// A provider for the "current time" and points relative to the current time.
+///
+/// This class is designed with testability in mind. The current point in time
+/// (or [now()]) is defined by a function that returns a [DateTime]. By
+/// supplying your own time function or using [Clock.fixed], you can control
+/// exactly what time a [Clock] returns and base your test expectations on that.
+///
+/// Most users should use the top-level [clock] field, which provides access to
+/// a default implementation of [Clock] which can be overridden using
+/// [withClock].
+class Clock {
+ /// The function that's called to determine this clock's notion of the current
+ /// time.
+ final DateTime Function() _time;
+
+ /// Creates a clock based on the given [currentTime], or on the system clock
+ /// by default.
+ // ignore: deprecated_member_use_from_same_package
+ const Clock([DateTime Function() currentTime = systemTime])
+ : _time = currentTime;
+
+ /// Creates [Clock] that always considers the current time to be [time].
+ Clock.fixed(DateTime time) : _time = (() => time);
+
+ /// Returns current time.
+ DateTime now() => _time();
+
+ /// Returns the point in time [Duration] amount of time ago.
+ DateTime agoBy(Duration duration) => now().subtract(duration);
+
+ /// Returns the point in time [Duration] amount of time from now.
+ DateTime fromNowBy(Duration duration) => now().add(duration);
+
+ /// Returns the point in time that's given amount of time ago.
+ ///
+ /// The amount of time is the sum of the individual parts.
+ DateTime ago(
+ {int days = 0,
+ int hours = 0,
+ int minutes = 0,
+ int seconds = 0,
+ int milliseconds = 0,
+ int microseconds = 0}) =>
+ agoBy(Duration(
+ days: days,
+ hours: hours,
+ minutes: minutes,
+ seconds: seconds,
+ milliseconds: milliseconds,
+ microseconds: microseconds));
+
+ /// Returns the point in time that's given amount of time from now.
+ ///
+ /// The amount of time is the sum of the individual parts.
+ DateTime fromNow(
+ {int days = 0,
+ int hours = 0,
+ int minutes = 0,
+ int seconds = 0,
+ int milliseconds = 0,
+ int microseconds = 0}) =>
+ fromNowBy(Duration(
+ days: days,
+ hours: hours,
+ minutes: minutes,
+ seconds: seconds,
+ milliseconds: milliseconds,
+ microseconds: microseconds));
+
+ /// Return the point in time [microseconds] ago.
+ DateTime microsAgo(int microseconds) => ago(microseconds: microseconds);
+
+ /// Return the point in time [microseconds] from now.
+ DateTime microsFromNow(int microseconds) =>
+ fromNow(microseconds: microseconds);
+
+ /// Return the point in time [milliseconds] ago.
+ DateTime millisAgo(int milliseconds) => ago(milliseconds: milliseconds);
+
+ /// Return the point in time [milliseconds] from now.
+ DateTime millisFromNow(int milliseconds) =>
+ fromNow(milliseconds: milliseconds);
+
+ /// Return the point in time [seconds] ago.
+ DateTime secondsAgo(int seconds) => ago(seconds: seconds);
+
+ /// Return the point in time [seconds] from now.
+ DateTime secondsFromNow(int seconds) => fromNow(seconds: seconds);
+
+ /// Return the point in time [minutes] ago.
+ DateTime minutesAgo(int minutes) => ago(minutes: minutes);
+
+ /// Return the point in time [minutes] from now.
+ DateTime minutesFromNow(int minutes) => fromNow(minutes: minutes);
+
+ /// Return the point in time [hours] ago.
+ DateTime hoursAgo(int hours) => ago(hours: hours);
+
+ /// Return the point in time [hours] from now.
+ DateTime hoursFromNow(int hours) => fromNow(hours: hours);
+
+ /// Return the point in time [days] ago.
+ DateTime daysAgo(int days) => ago(days: days);
+
+ /// Return the point in time [days] from now.
+ DateTime daysFromNow(int days) => fromNow(days: days);
+
+ /// Return the point in time [weeks] ago.
+ DateTime weeksAgo(int weeks) => ago(days: 7 * weeks);
+
+ /// Return the point in time [weeks] from now.
+ DateTime weeksFromNow(int weeks) => fromNow(days: 7 * weeks);
+
+ /// Return the point in time [months] ago on the same date.
+ ///
+ /// If the current day of the month isn't valid in the new month, the nearest
+ /// valid day in the new month will be used.
+ DateTime monthsAgo(int months) {
+ var time = now();
+ var month = (time.month - months - 1) % 12 + 1;
+ var year = time.year - (months + 12 - time.month) ~/ 12;
+ var day = clampDayOfMonth(year: year, month: month, day: time.day);
+ return DateTime(year, month, day, time.hour, time.minute, time.second,
+ time.millisecond);
+ }
+
+ /// Return the point in time [months] from now on the same date.
+ ///
+ /// If the current day of the month isn't valid in the new month, the nearest
+ /// valid day in the new month will be used.
+ DateTime monthsFromNow(int months) {
+ var time = now();
+ var month = (time.month + months - 1) % 12 + 1;
+ var year = time.year + (months + time.month - 1) ~/ 12;
+ var day = clampDayOfMonth(year: year, month: month, day: time.day);
+ return DateTime(year, month, day, time.hour, time.minute, time.second,
+ time.millisecond);
+ }
+
+ /// Return the point in time [years] ago on the same date.
+ ///
+ /// If the current day of the month isn't valid in the new year, the nearest
+ /// valid day in the original month will be used.
+ DateTime yearsAgo(int years) {
+ var time = now();
+ var year = time.year - years;
+ var day = clampDayOfMonth(year: year, month: time.month, day: time.day);
+ return DateTime(year, time.month, day, time.hour, time.minute, time.second,
+ time.millisecond);
+ }
+
+ /// Return the point in time [years] from now on the same date.
+ ///
+ /// If the current day of the month isn't valid in the new year, the nearest
+ /// valid day in the original month will be used.
+ DateTime yearsFromNow(int years) => yearsAgo(-years);
+
+ /// Returns a new stopwatch that uses the current time as reported by `this`.
+ Stopwatch stopwatch() => ClockStopwatch(this);
+
+ /// Returns a new stopwatch that uses the current time as reported by `this`.
+ @Deprecated('Use stopwatch() instead.')
+ Stopwatch getStopwatch() => stopwatch();
+}
diff --git a/pkgs/clock/lib/src/default.dart b/pkgs/clock/lib/src/default.dart
new file mode 100644
index 0000000..2a46b9f
--- /dev/null
+++ b/pkgs/clock/lib/src/default.dart
@@ -0,0 +1,54 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'dart:async';
+
+import 'clock.dart';
+
+/// The key for the [Zone] value that controls the current implementation of
+/// [clock].
+final _clockKey = Object();
+
+/// The key for the [Zone] value that controls whether nested zones can override
+/// [clock].
+final _isFinalKey = Object();
+
+/// The default implementation of [clock] for the current [Zone].
+///
+/// This defaults to the system clock. It can be set within a zone using
+/// [withClock].
+Clock get clock => Zone.current[_clockKey] as Clock? ?? const Clock();
+
+/// Runs [callback] with the given value for the top-level [clock] field.
+///
+/// This is [Zone]-scoped, so asynchronous callbacks spawned within [callback]
+/// will also use the new value for [clock].
+///
+// ignore: deprecated_member_use_from_same_package
+/// If [isFinal] is `true`, calls to [withClock] within [callback] will throw a
+/// [StateError]. However, this parameter is deprecated and should be avoided.
+T withClock<T>(
+ Clock clock,
+ T Function() callback, {
+ @Deprecated('This parameter is deprecated and should be avoided')
+ bool isFinal = false,
+}) {
+ if ((Zone.current[_isFinalKey] ?? false) == true) {
+ throw StateError(
+ 'Cannot call withClock() within a call to withClock(isFinal = true).');
+ }
+
+ return runZoned(callback,
+ zoneValues: {_clockKey: clock, _isFinalKey: isFinal});
+}
diff --git a/pkgs/clock/lib/src/stopwatch.dart b/pkgs/clock/lib/src/stopwatch.dart
new file mode 100644
index 0000000..93fe1ab
--- /dev/null
+++ b/pkgs/clock/lib/src/stopwatch.dart
@@ -0,0 +1,73 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'clock.dart';
+
+/// The system's timer frequency in Hz.
+///
+/// We can't really know how frequently the clock is updated, and that may not
+/// even make sense for some implementations, so we just pretend we follow the
+/// system's frequency.
+final _frequency = Stopwatch().frequency;
+
+/// A stopwatch that gets its notion of the current time from a [Clock].
+class ClockStopwatch implements Stopwatch {
+ /// The provider for this stopwatch's notion of the current time.
+ final Clock _clock;
+
+ /// The number of elapsed microseconds that have been recorded from previous
+ /// runs of this stopwatch.
+ ///
+ /// This doesn't include the time between [_start] and the current time.
+ var _elapsed = 0;
+
+ /// The point at which [start] was called most recently, or `null` if this
+ /// isn't active.
+ DateTime? _start;
+
+ ClockStopwatch(this._clock);
+
+ @override
+ int get frequency => _frequency;
+ @override
+ int get elapsedTicks => (elapsedMicroseconds * frequency) ~/ 1000000;
+ @override
+ Duration get elapsed => Duration(microseconds: elapsedMicroseconds);
+ @override
+ int get elapsedMilliseconds => elapsedMicroseconds ~/ 1000;
+ @override
+ bool get isRunning => _start != null;
+
+ @override
+ int get elapsedMicroseconds =>
+ _elapsed +
+ (_start == null ? 0 : _clock.now().difference(_start!).inMicroseconds);
+
+ @override
+ void start() {
+ _start ??= _clock.now();
+ }
+
+ @override
+ void stop() {
+ _elapsed = elapsedMicroseconds;
+ _start = null;
+ }
+
+ @override
+ void reset() {
+ _elapsed = 0;
+ if (_start != null) _start = _clock.now();
+ }
+}
diff --git a/pkgs/clock/lib/src/utils.dart b/pkgs/clock/lib/src/utils.dart
new file mode 100644
index 0000000..4301b09
--- /dev/null
+++ b/pkgs/clock/lib/src/utils.dart
@@ -0,0 +1,59 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This code is copied from quiver. We don't take on an explicit dependency
+// because quiver is very large and the amount of code we use from it is very
+// small.
+
+/// The number of days in each month.
+///
+/// This array uses 1-based month numbers, i.e. January is the 1-st element in
+/// the array, not the 0-th.
+const _daysInMonth = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+
+/// Returns the number of days in the specified month.
+///
+/// This function assumes the use of the Gregorian calendar or the proleptic
+/// Gregorian calendar.
+int daysInMonth(int year, int month) =>
+ (month == DateTime.february && isLeapYear(year)) ? 29 : _daysInMonth[month];
+
+/// Returns true if [year] is a leap year.
+///
+/// This implements the Gregorian calendar leap year rules wherein a year is
+/// considered to be a leap year if it is divisible by 4, excepting years
+/// divisible by 100, but including years divisible by 400.
+///
+/// This function assumes the use of the Gregorian calendar or the proleptic
+/// Gregorian calendar.
+bool isLeapYear(int year) =>
+ year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
+
+/// Takes a `date` that may be outside the allowed range of dates for a given
+/// [month] in a given [year] and returns the closest date that is within the
+/// allowed range.
+///
+/// For example:
+///
+/// February 31, 2013 => February 28, 2013
+///
+/// When jumping from month to month or from leap year to common year we may
+/// end up in a month that has fewer days than the month we are jumping from.
+/// In that case it is impossible to preserve the exact date. So we "clamp" the
+/// date value to fit within the month. For example, jumping from March 31 one
+/// month back takes us to February 28 (or 29 during a leap year), as February
+/// doesn't have 31-st date.
+int clampDayOfMonth(
+ {required int year, required int month, required int day}) =>
+ day.clamp(1, daysInMonth(year, month));
diff --git a/pkgs/clock/pubspec.yaml b/pkgs/clock/pubspec.yaml
new file mode 100644
index 0000000..605aa09
--- /dev/null
+++ b/pkgs/clock/pubspec.yaml
@@ -0,0 +1,12 @@
+name: clock
+version: 1.1.2
+description: A fakeable wrapper for dart:core clock APIs.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/clock
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aclock
+
+environment:
+ sdk: ^3.4.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.6
diff --git a/pkgs/clock/test/clock_test.dart b/pkgs/clock/test/clock_test.dart
new file mode 100644
index 0000000..c457153
--- /dev/null
+++ b/pkgs/clock/test/clock_test.dart
@@ -0,0 +1,210 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'package:clock/clock.dart';
+
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ late Clock clock;
+ setUp(() {
+ clock = Clock.fixed(date(2013));
+ });
+
+ test('should return a non-null value from system clock', () {
+ expect(const Clock().now(), isNotNull);
+ });
+
+ // This test may be flaky on certain systems. I ran it over 10 million
+ // cycles on my machine without any failures, but that's no guarantee.
+ test('should be close enough to system clock', () {
+ // At 10ms the test doesn't seem to be flaky.
+ var epsilon = 10;
+ expect(DateTime.now().difference(const Clock().now()).inMilliseconds.abs(),
+ lessThan(epsilon));
+ expect(DateTime.now().difference(const Clock().now()).inMilliseconds.abs(),
+ lessThan(epsilon));
+ });
+
+ test('should return time provided by a custom function', () {
+ var time = date(2013);
+ var fixedClock = Clock(() => time);
+ expect(fixedClock.now(), date(2013));
+
+ time = date(2014);
+ expect(fixedClock.now(), date(2014));
+ });
+
+ test('should return fixed time', () {
+ expect(Clock.fixed(date(2013)).now(), date(2013));
+ });
+
+ test('should return time Duration ago', () {
+ expect(clock.agoBy(const Duration(days: 366)), date(2012));
+ });
+
+ test('should return time Duration from now', () {
+ expect(clock.fromNowBy(const Duration(days: 365)), date(2014));
+ });
+
+ test('should return time parts ago', () {
+ expect(
+ clock.ago(
+ days: 1,
+ hours: 1,
+ minutes: 1,
+ seconds: 1,
+ milliseconds: 1,
+ microseconds: 1000),
+ DateTime(2012, 12, 30, 22, 58, 58, 998));
+ });
+
+ test('should return time parts from now', () {
+ expect(
+ clock.fromNow(
+ days: 1,
+ hours: 1,
+ minutes: 1,
+ seconds: 1,
+ milliseconds: 1,
+ microseconds: 1000),
+ DateTime(2013, 1, 2, 1, 1, 1, 2));
+ });
+
+ test('should return time micros ago', () {
+ expect(clock.microsAgo(1000), DateTime(2012, 12, 31, 23, 59, 59, 999));
+ });
+
+ test('should return time micros from now', () {
+ expect(clock.microsFromNow(1000), DateTime(2013, 1, 1, 0, 0, 0, 1));
+ });
+
+ test('should return time millis ago', () {
+ expect(clock.millisAgo(1000), DateTime(2012, 12, 31, 23, 59, 59));
+ });
+
+ test('should return time millis from now', () {
+ expect(clock.millisFromNow(3), DateTime(2013, 1, 1, 0, 0, 0, 3));
+ });
+
+ test('should return time seconds ago', () {
+ expect(clock.secondsAgo(10), DateTime(2012, 12, 31, 23, 59, 50));
+ });
+
+ test('should return time seconds from now', () {
+ expect(clock.secondsFromNow(3), DateTime(2013, 1, 1, 0, 0, 3));
+ });
+
+ test('should return time minutes ago', () {
+ expect(clock.minutesAgo(10), DateTime(2012, 12, 31, 23, 50));
+ });
+
+ test('should return time minutes from now', () {
+ expect(clock.minutesFromNow(3), DateTime(2013, 1, 1, 0, 3));
+ });
+
+ test('should return time hours ago', () {
+ expect(clock.hoursAgo(10), DateTime(2012, 12, 31, 14));
+ });
+
+ test('should return time hours from now', () {
+ expect(clock.hoursFromNow(3), DateTime(2013, 1, 1, 3));
+ });
+
+ test('should return time days ago', () {
+ expect(clock.daysAgo(10), date(2012, 12, 22));
+ });
+
+ test('should return time days from now', () {
+ expect(clock.daysFromNow(3), date(2013, 1, 4));
+ });
+
+ test('should return time months ago on the same date', () {
+ expect(clock.monthsAgo(1), date(2012, 12, 1));
+ expect(clock.monthsAgo(2), date(2012, 11, 1));
+ expect(clock.monthsAgo(3), date(2012, 10, 1));
+ expect(clock.monthsAgo(4), date(2012, 9, 1));
+ });
+
+ test('should return time months from now on the same date', () {
+ expect(clock.monthsFromNow(1), date(2013, 2, 1));
+ expect(clock.monthsFromNow(2), date(2013, 3, 1));
+ expect(clock.monthsFromNow(3), date(2013, 4, 1));
+ expect(clock.monthsFromNow(4), date(2013, 5, 1));
+ });
+
+ test('should go from 2013-05-31 to 2012-11-30', () {
+ expect(fixed(2013, 5, 31).monthsAgo(6), date(2012, 11, 30));
+ });
+
+ test('should go from 2013-03-31 to 2013-02-28 (common year)', () {
+ expect(fixed(2013, 3, 31).monthsAgo(1), date(2013, 2, 28));
+ });
+
+ test('should go from 2013-05-31 to 2013-02-28 (common year)', () {
+ expect(fixed(2013, 5, 31).monthsAgo(3), date(2013, 2, 28));
+ });
+
+ test('should go from 2004-03-31 to 2004-02-29 (leap year)', () {
+ expect(fixed(2004, 3, 31).monthsAgo(1), date(2004, 2, 29));
+ });
+
+ test('should go from 2013-03-31 to 2013-06-30', () {
+ expect(fixed(2013, 3, 31).monthsFromNow(3), date(2013, 6, 30));
+ });
+
+ test('should go from 2003-12-31 to 2004-02-29 (common to leap)', () {
+ expect(fixed(2003, 12, 31).monthsFromNow(2), date(2004, 2, 29));
+ });
+
+ test('should go from 2004-02-29 to 2003-02-28 by year', () {
+ expect(fixed(2004, 2, 29).yearsAgo(1), date(2003, 2, 28));
+ });
+
+ test('should go from 2004-02-29 to 2003-02-28 by month', () {
+ expect(fixed(2004, 2, 29).monthsAgo(12), date(2003, 2, 28));
+ });
+
+ test('should go from 2004-02-29 to 2005-02-28 by year', () {
+ expect(fixed(2004, 2, 29).yearsFromNow(1), date(2005, 2, 28));
+ });
+
+ test('should go from 2004-02-29 to 2005-02-28 by month', () {
+ expect(fixed(2004, 2, 29).monthsFromNow(12), date(2005, 2, 28));
+ });
+
+ test('should return time years ago on the same date', () {
+ expect(clock.yearsAgo(1), date(2012, 1, 1)); // leap year
+ expect(clock.yearsAgo(2), date(2011, 1, 1));
+ expect(clock.yearsAgo(3), date(2010, 1, 1));
+ expect(clock.yearsAgo(4), date(2009, 1, 1));
+ expect(clock.yearsAgo(5), date(2008, 1, 1)); // leap year
+ expect(clock.yearsAgo(6), date(2007, 1, 1));
+ expect(clock.yearsAgo(30), date(1983, 1, 1));
+ expect(clock.yearsAgo(2013), date(0, 1, 1));
+ });
+
+ test('should return time years from now on the same date', () {
+ expect(clock.yearsFromNow(1), date(2014, 1, 1));
+ expect(clock.yearsFromNow(2), date(2015, 1, 1));
+ expect(clock.yearsFromNow(3), date(2016, 1, 1));
+ expect(clock.yearsFromNow(4), date(2017, 1, 1));
+ expect(clock.yearsFromNow(5), date(2018, 1, 1));
+ expect(clock.yearsFromNow(6), date(2019, 1, 1));
+ expect(clock.yearsFromNow(30), date(2043, 1, 1));
+ expect(clock.yearsFromNow(1000), date(3013, 1, 1));
+ });
+}
diff --git a/pkgs/clock/test/default_test.dart b/pkgs/clock/test/default_test.dart
new file mode 100644
index 0000000..80acd15
--- /dev/null
+++ b/pkgs/clock/test/default_test.dart
@@ -0,0 +1,84 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'package:clock/clock.dart';
+
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ test('the default clock returns the system time', () {
+ expect(DateTime.now().difference(clock.now()).inMilliseconds.abs(),
+ lessThan(100));
+ });
+
+ group('withClock()', () {
+ group('overrides the clock', () {
+ test('synchronously', () {
+ var time = date(1990, 11, 8);
+ withClock(Clock(() => time), () {
+ expect(clock.now(), equals(time));
+ time = date(2016, 6, 26);
+ expect(clock.now(), equals(time));
+ });
+ });
+
+ test('asynchronously', () {
+ var time = date(1990, 11, 8);
+ withClock(Clock.fixed(time), () {
+ expect(Future(() async {
+ expect(clock.now(), equals(time));
+ }), completes);
+ });
+ });
+
+ test('within another withClock() call', () {
+ var outerTime = date(1990, 11, 8);
+ withClock(Clock.fixed(outerTime), () {
+ expect(clock.now(), equals(outerTime));
+
+ var innerTime = date(2016, 11, 8);
+ withClock(Clock.fixed(innerTime), () {
+ expect(clock.now(), equals(innerTime));
+ expect(Future(() async {
+ expect(clock.now(), equals(innerTime));
+ }), completes);
+ });
+
+ expect(clock.now(), equals(outerTime));
+ });
+ });
+ });
+
+ test("with isFinal: true doesn't allow nested calls", () {
+ var outerTime = date(1990, 11, 8);
+ withClock(Clock.fixed(outerTime), () {
+ expect(clock.now(), equals(outerTime));
+
+ expect(() => withClock(fixed(2016, 11, 8), neverCalledVoid),
+ throwsStateError);
+
+ expect(clock.now(), equals(outerTime));
+ // ignore: deprecated_member_use_from_same_package
+ }, isFinal: true);
+ });
+ });
+}
+
+/// A wrapper for [neverCalled] that works around sdk#33015.
+void Function() get neverCalledVoid {
+ var function = neverCalled;
+ return () => function();
+}
diff --git a/pkgs/clock/test/stopwatch_test.dart b/pkgs/clock/test/stopwatch_test.dart
new file mode 100644
index 0000000..e96c0f7
--- /dev/null
+++ b/pkgs/clock/test/stopwatch_test.dart
@@ -0,0 +1,171 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'package:clock/clock.dart';
+
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ test('returns the system frequency', () {
+ expect(fixed(1990, 11, 8).stopwatch().frequency,
+ equals(Stopwatch().frequency));
+ });
+
+ group('before it starts', () {
+ late Stopwatch stopwatch;
+ setUp(() {
+ stopwatch = clock.stopwatch();
+ });
+
+ test('is not running', () => expect(stopwatch.isRunning, isFalse));
+
+ test('stop() does nothing', () {
+ stopwatch.stop();
+ expect(stopwatch.isRunning, isFalse);
+ expect(stopwatch.elapsed, equals(Duration.zero));
+ });
+
+ group('reports no elapsed', () {
+ test('duration', () => expect(stopwatch.elapsed, equals(Duration.zero)));
+ test('ticks', () => expect(stopwatch.elapsedTicks, isZero));
+ test('microseconds', () => expect(stopwatch.elapsedMicroseconds, isZero));
+ test('milliseconds', () => expect(stopwatch.elapsedMilliseconds, isZero));
+ });
+ });
+
+ group('when 12345μs have elapsed', () {
+ late DateTime time;
+ late Clock clock;
+ late Stopwatch stopwatch;
+ setUp(() {
+ time = date(1990, 11, 8);
+ clock = Clock(() => time);
+ stopwatch = clock.stopwatch()..start();
+ time = clock.microsFromNow(12345);
+ });
+
+ group('and the stopwatch is active', () {
+ test('is running', () {
+ expect(stopwatch.isRunning, isTrue);
+ });
+
+ test('reports more elapsed time', () {
+ time = clock.microsFromNow(54321);
+ expect(stopwatch.elapsedMicroseconds, equals(66666));
+ });
+
+ test('start does nothing', () {
+ stopwatch.start();
+ expect(stopwatch.isRunning, isTrue);
+ expect(stopwatch.elapsedMicroseconds, equals(12345));
+ });
+
+ group('reset()', () {
+ setUp(() {
+ stopwatch.reset();
+ });
+
+ test('sets the elapsed time to zero', () {
+ expect(stopwatch.elapsed, equals(Duration.zero));
+ });
+
+ test('reports more elapsed time', () {
+ time = clock.microsFromNow(54321);
+ expect(stopwatch.elapsedMicroseconds, equals(54321));
+ });
+ });
+
+ group('reports elapsed', () {
+ test('duration', () {
+ expect(
+ stopwatch.elapsed, equals(const Duration(microseconds: 12345)));
+ });
+
+ test('ticks', () {
+ expect(stopwatch.elapsedTicks,
+ equals((Stopwatch().frequency * 12345) ~/ 1000000));
+ });
+
+ test('microseconds', () {
+ expect(stopwatch.elapsedMicroseconds, equals(12345));
+ });
+
+ test('milliseconds', () {
+ expect(stopwatch.elapsedMilliseconds, equals(12));
+ });
+ });
+ });
+
+ group('and the stopwatch is inactive, reports that as', () {
+ setUp(() {
+ stopwatch.stop();
+ });
+
+ test('is not running', () {
+ expect(stopwatch.isRunning, isFalse);
+ });
+
+ test("doesn't report more elapsed time", () {
+ time = clock.microsFromNow(54321);
+ expect(stopwatch.elapsedMicroseconds, equals(12345));
+ });
+
+ test('start starts reporting more elapsed time', () {
+ stopwatch.start();
+ expect(stopwatch.isRunning, isTrue);
+ time = clock.microsFromNow(54321);
+ expect(stopwatch.elapsedMicroseconds, equals(66666));
+ });
+
+ group('reset()', () {
+ setUp(() {
+ stopwatch.reset();
+ });
+
+ test('sets the elapsed time to zero', () {
+ expect(stopwatch.elapsed, equals(Duration.zero));
+ });
+
+ test("doesn't report more elapsed time", () {
+ time = clock.microsFromNow(54321);
+ expect(stopwatch.elapsed, equals(Duration.zero));
+ });
+ });
+
+ group('reports elapsed', () {
+ test('duration', () {
+ expect(
+ stopwatch.elapsed, equals(const Duration(microseconds: 12345)));
+ });
+
+ test('ticks', () {
+ expect(stopwatch.elapsedTicks,
+ equals((Stopwatch().frequency * 12345) ~/ 1000000));
+ });
+
+ test('microseconds', () {
+ expect(stopwatch.elapsedMicroseconds, equals(12345));
+ });
+
+ test('milliseconds', () {
+ expect(stopwatch.elapsedMilliseconds, equals(12));
+ });
+ });
+ });
+ }, onPlatform: {
+ 'js': const Skip('Web does not have enough precision'),
+ });
+}
diff --git a/pkgs/clock/test/utils.dart b/pkgs/clock/test/utils.dart
new file mode 100644
index 0000000..ea4b1df
--- /dev/null
+++ b/pkgs/clock/test/utils.dart
@@ -0,0 +1,25 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'package:clock/clock.dart';
+
+/// A utility function for tersely constructing a [DateTime] with no time
+/// component.
+DateTime date(int year, [int? month, int? day]) =>
+ DateTime(year, month ?? 1, day ?? 1);
+
+/// Returns a clock that always returns a date with the given [year], [month],
+/// and [day].
+Clock fixed(int year, [int? month, int? day]) =>
+ Clock.fixed(date(year, month, day));
diff --git a/pkgs/code_builder/.gitignore b/pkgs/code_builder/.gitignore
new file mode 100644
index 0000000..feb089d
--- /dev/null
+++ b/pkgs/code_builder/.gitignore
@@ -0,0 +1,5 @@
+# Files and directories created by pub
+.dart_tool
+.packages
+.pub
+pubspec.lock
diff --git a/pkgs/code_builder/AUTHORS b/pkgs/code_builder/AUTHORS
new file mode 100644
index 0000000..a904f0c
--- /dev/null
+++ b/pkgs/code_builder/AUTHORS
@@ -0,0 +1,7 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Nikolas Rimikis <rimikis.nikolas@gmail.com>
+Google Inc.
diff --git a/pkgs/code_builder/CHANGELOG.md b/pkgs/code_builder/CHANGELOG.md
new file mode 100644
index 0000000..5e5521c
--- /dev/null
+++ b/pkgs/code_builder/CHANGELOG.md
@@ -0,0 +1,857 @@
+## 4.10.1
+
+* Require Dart `^3.5.0`
+* Upgrade to `dart_style` 2.3.7.
+* Move to `dart-lang/tools` monorepo.
+
+## 4.10.0
+
+* Add `Library.docs` to support emitting doc comments on libraries.
+* Export `RepresentationDeclaration` and `RepresentationDeclarationBuilder` so
+ they can be used when generating extension types.
+* Upgrade to `dart_style` 2.3.4.
+
+## 4.9.0
+
+* Add `Library.generatedByComment` to support emitting 'generated by' comments.
+* Support emitting an unnamed library with annotations.
+
+## 4.8.0
+
+* Add `Expression.operatorSubtract`
+* Deprecate `Expression.operatorSubstract`
+* Add `Expression.operatorIntDivide`
+* Add `Expression.operatorUnaryPrefixIncrement`
+* Add `Expression.operatorUnaryPostfixIncrement`
+* Add `Expression.operatorUnaryMinus`
+* Add `Expression.operatorUnaryPrefixDecrement`
+* Add `Expression.operatorUnaryPostfixDecrement`
+* Add `Expression.operatorBitwiseAnd`
+* Add `Expression.operatorBitwiseOr`
+* Add `Expression.operatorBitwiseXor`
+* Add `Expression.operatorUnaryBitwiseComplement`
+* Add `Expression.operatorShiftLeft`
+* Add `Expression.operatorShiftRight`
+* Add `Expression.operatorShiftRightUnsigned`
+* Add `Expression.addAssign`
+* Add `Expression.subtractAssign`
+* Add `Expression.multiplyAssign`
+* Add `Expression.divideAssign`
+* Add `Expression.intDivideAssign`
+* Add `Expression.euclideanModuloAssign`
+* Add `Expression.shiftLeftAssign`
+* Add `Expression.shiftRightAssign`
+* Add `Expression.shiftRightUnsignedAssign`
+* Add `Expression.bitwiseAndAssign`
+* Add `Expression.bitwiseXorAssign`
+* Add `Expression.bitwiseOrAssign`
+* Allow passing an `Expression` through `literal` without an exception.
+* Add support for extension types.
+* Update SDK version constraints to `>=3.0.0`.
+
+## 4.7.0
+
+* Add a newline after lambdas.
+
+## 4.6.0
+
+* Add support for named arguments in `enum` classes
+* Add support for external keyword on fields.
+* Add `Expression.parenthesized` to manually wrap an expression in parenthesis.
+
+## 4.5.0
+
+* Require Dart 2.19
+* Add support for emitting type parameters for typedefs.
+* Add support for class modifiers.
+* Add support for records (both types and record literals).
+* Add `literalSpread` and `literalNullSafeSpread` to support adding spreads to
+ `literalMap`.
+
+```dart
+void main() {
+ // Creates a map
+ // {
+ // ...one,
+ // 2: two,
+ // ...?three,
+ // }
+ final map = literalMap({
+ literalSpread(): refer('one'),
+ 2: refer('two'),
+ literalNullSafeSpread(): refer('three'),
+ });
+}
+```
+
+## 4.4.0
+
+* Mention how the `allocator` argument relates to imports in the `DartEmitter`
+ constructor doc.
+* Add support for emitting typedefs.
+* Add support for emitting leading line comments for libraries.
+* Add support for emitting `ignore_for_file` analyzer directive comments.
+
+## 4.3.0
+
+* Add support for adding more implementation in `enum` classes.
+* Only emit `late` keyword when using null safety syntax.
+* Use implicit `const` when assigning to a `declareConst` variable.
+* Deprecate `assignVar`, `assignConst`, and `assignFinal`.
+* Add trailing commas to any parameter list, argument list, or collection
+ literal which has more than one element.
+
+## 4.2.0
+
+* Add an ignore for a lint from the `package:lints` recommended set. The lint,
+ `no_leading_underscores_for_library_prefixes` is most useful for hand edited
+ code where the appearance of a private name that is already not visible
+ outside the library is confusing.
+* Fix the docs for `Expression.assign`, `ifNullThen`, and `assignNullAware`
+ which had the argument and receiver flipped.
+* Add `declareConst`, `declareFinal`, and `declareVar` to replace
+ `Expression.assignConst`, `assignFinal`, and `assignVar`. Add support for late
+ variables with the `declare*` utilities.
+* Add `ParameterBuilder.toSuper` so support super formal parameters language
+ feature.
+
+## 4.1.0
+
+* Add `Expression.spread` for the spread operator `...`.
+* Add support 'late' field modifier.
+* Add support for `Expression.nullChecked` to add a null assertion operator.
+* Add support for creating `mixin`s.
+* Add `Expression.nullSafeSpread` for the null aware spread operator `...?`.
+* A `Library` can now be annotated.
+
+## 4.0.0
+
+* Migrate to null safety.
+* Changed the `DartEmitter` constructor to use named optional parameters.
+* Add `ParenthesizedExpression` and
+ `ExpressionVisitor.visitParenthesizedExpression.`
+
+## 3.7.0
+
+* Add support for converting a Method to a generic closure, with
+ `Method.genericClosure`.
+
+## 3.6.0
+
+* Add support for creating `extension` methods.
+* Expand constraint on `built_value` to allow null safe migrated version.
+
+## 3.5.0
+
+* Add support for defining enums.
+* Fix keyword ordering for `const factory` constructors.
+
+## 3.4.1
+
+* Fix confusing mismatch description from `equalsDart`.
+ https://github.com/dart-lang/code_builder/issues/293
+
+## 3.4.0
+
+* Introduce `Expression.thrown` for throwing an expression.
+* Introduce `FunctionType.isNullable`.
+* Update SDK requirement to `>=2.7.0 <3.0.0`.
+
+## 3.3.0
+
+* Add `??` null-aware operator.
+* Add `..` cascade assignment operator.
+* Add `part` directive.
+* Introduce `TypeReference.isNullable`.
+* Add an option in `DartEmitter` to emit nullable types with trailing `?`
+ characters.
+
+## 3.2.2
+
+* Require minimum Dart SDK of `2.6.0`.
+
+## 3.2.1
+
+* Escape newlines in String literals.
+* Introduce `Expression.or` for boolean OR.
+* Introduce `Expression.negate` for boolean NOT.
+* No longer emits redundant `,`s in `FunctionType`s.
+* Added support for `literalSet` and `literalConstSet`.
+* Depend on the latest `package:built_value`.
+
+## 3.2.0
+
+* Emit `=` instead of `:` for named parameter default values.
+* The `new` keyword will not be used in generated code.
+* The `const` keyword will be omitted when it can be inferred.
+* Add an option in `DartEmitter` to order directives.
+* `DartEmitter` added a `startConstCode` function to track the creation of
+ constant expression trees.
+* `BinaryExpression` added the `final bool isConst` field.
+
+## 3.1.3
+
+* Bump dependency on built_collection to include v4.0.0.
+
+## 3.1.2
+
+* Set max SDK version to `<3.0.0`.
+
+## 3.1.1
+
+* `Expression.asA` is now wrapped with parenthesis so that further calls may be
+ made on it as an expression.
+
+
+## 3.1.0
+
+* Added `Expression.asA` for creating explicit casts:
+
+```dart
+void main() {
+ test('should emit an explicit cast', () {
+ expect(
+ refer('foo').asA(refer('String')),
+ equalsDart('foo as String'),
+ );
+ });
+}
+```
+
+## 3.0.3
+
+* Fix a bug that caused all downstream users of `code_builder` to crash due to
+ `build_runner` trying to import our private builder (in `tool/`). Sorry for
+ the inconvenience.
+
+## 3.0.2
+
+* Require `source_gen: ^0.7.5`.
+
+## 3.0.1
+
+* Upgrade to `built_value` 5.1.0.
+* Export the `literalNum` function.
+* **BUG FIX**: `literal` supports a `Map`.
+
+## 3.0.0
+
+* Also infer `Constructor.lambda` for `factory` constructors.
+
+## 3.0.0-alpha
+
+* Using `equalsDart` no longer formats automatically with `dartfmt`.
+
+* Removed deprecated `Annotation` and `File` classes.
+
+* `Method.lambda` is inferred based on `Method.body` where possible and now
+ defaults to `null`.
+
+## 2.4.0
+
+* Add `equalTo`, `notEqualTo`, `greaterThan`, `lessThan`, `greateOrEqualTo`, and
+ `lessOrEqualTo` to `Expression`.
+
+## 2.3.0
+
+* Using `equalsDart` and expecting `dartfmt` by default is *deprecated*. This
+ requires this package to have a direct dependency on specific versions of
+ `dart_style` (and transitively `analyzer`), which is problematic just for
+ testing infrastructure. To future proof, we've exposed the `EqualsDart` class
+ with a `format` override:
+
+```dart
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:dart_style/dart_style.dart';
+
+final DartFormatter _dartfmt = new DartFormatter();
+String _format(String source) {
+ try {
+ return _dartfmt.format(source);
+ } on FormatException catch (_) {
+ return _dartfmt.formatStatement(source);
+ }
+}
+
+/// Should be invoked in `main()` of every test in `test/**_test.dart`.
+void useDartfmt() => EqualsDart.format = _format;
+```
+
+* Added `Expression.isA` and `Expression.isNotA`:
+
+```dart
+void main() {
+ test('should emit an is check', () {
+ expect(
+ refer('foo').isA(refer('String')),
+ equalsDart('foo is String'),
+ );
+ });
+}
+```
+
+* Deprecated `Annotation`. It is now legal to simply pass any `Expression` as
+ a metadata annotation to `Class`, `Method`, `Field,` and `Parameter`. In
+ `3.0.0`, the `Annotation` class will be completely removed:
+
+```dart
+void main() {
+ test('should create a class with a annotated constructor', () {
+ expect(
+ new Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(
+ new Constructor((b) => b..annotations.add(refer('deprecated'))))),
+ equalsDart(r'''
+ class Foo {
+ @deprecated
+ Foo();
+ }
+ '''),
+ );
+ });
+}
+```
+
+* Added inference support for `Method.lambda` and `Constructor.lambda`. If not
+ explicitly provided and the body of the function originated from an
+ `Expression` then `lambda` is inferred to be true. This is not a breaking
+ change yet, as it requires an explicit `null` value. In `3.0.0` this will be
+ the default:
+
+```dart
+void main() {
+ final animal = new Class((b) => b
+ ..name = 'Animal'
+ ..extend = refer('Organism')
+ ..methods.add(new Method.returnsVoid((b) => b
+ ..name = 'eat'
+ // In 3.0.0, this may be omitted and still is inferred.
+ ..lambda = null
+ ..body = refer('print').call([literalString('Yum!')]).code)));
+ final emitter = new DartEmitter();
+ print(new DartFormatter().format('${animal.accept(emitter)}'));
+}
+```
+
+* Added `nullSafeProperty` to `Expression` to access properties with `?.`
+* Added `conditional` to `Expression` to use the ternary operator `? : `
+* Methods taking `positionalArguments` accept `Iterable<Expression>`
+* **BUG FIX**: Parameters can take a `FunctionType` as a `type`.
+ `Reference.type` now returns a `Reference`. Note that this change is
+ technically breaking but should not impacts most clients.
+
+## 2.2.0
+
+* Imports are prefixed with `_i1` rather than `_1` which satisfies the lint
+ `lowercase_with_underscores`. While not a strictly breaking change you may
+ have to fix/regenerate golden file-like tests. We added documentation that
+ the specific prefix is not considered stable.
+
+* Added `Expression.index` for accessing the `[]` operator:
+
+```dart
+void main() {
+ test('should emit an index operator', () {
+ expect(
+ refer('bar').index(literalTrue).assignVar('foo').statement,
+ equalsDart('var foo = bar[true];'),
+ );
+ });
+
+ test('should emit an index operator set', () {
+ expect(
+ refer('bar')
+ .index(literalTrue)
+ .assign(literalFalse)
+ .assignVar('foo')
+ .statement,
+ equalsDart('var foo = bar[true] = false;'),
+ );
+ });
+}
+```
+
+* `literalList` accepts an `Iterable` argument.
+
+* Fixed an NPE when a method had a return type of a `FunctionType`:
+
+```dart
+void main() {
+ test('should create a method with a function type return type', () {
+ expect(
+ new Method((b) => b
+ ..name = 'foo'
+ ..returns = new FunctionType((b) => b
+ ..returnType = refer('String')
+ ..requiredParameters.addAll([
+ refer('int'),
+ ]))),
+ equalsDart(r'''
+ String Function(int) foo();
+ '''),
+ );
+ });
+}
+```
+
+## 2.1.0
+
+We now require the Dart 2.0-dev branch SDK (`>= 2.0.0-dev`).
+
+* Added support for raw `String` literals.
+* Automatically escapes single quotes in now-raw `String` literals.
+* Deprecated `File`, which is now a redirect to the preferred class, `Library`.
+
+This helps avoid symbol clashes when used with `dart:io`, a popular library. It
+is now safe to do the following and get full access to the `code_builder` API:
+
+```dart
+import 'dart:io';
+
+import 'package:code_builder/code_builder.dart' hide File;
+```
+
+We will remove `File` in `3.0.0`, so use `Library` instead.
+
+## 2.0.0
+
+Re-released without a direct dependency on `package:analyzer`!
+
+For users of the `1.x` branch of `code_builder`, this is a pretty big breaking
+change but ultimately is for the better - it's easier to evolve this library
+now and even add your own builders on top of the library.
+
+```dart
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:dart_style/dart_style.dart';
+
+void main() {
+ final animal = new Class((b) => b
+ ..name = 'Animal'
+ ..extend = refer('Organism')
+ ..methods.add(new Method.returnsVoid((b) => b
+ ..name = 'eat'
+ ..lambda = true
+ ..body = const Code('print(\'Yum\')'))));
+ final emitter = new DartEmitter();
+ print(new DartFormatter().format('${animal.accept(emitter)}'));
+}
+```
+
+...outputs...
+
+```dart
+class Animal extends Organism {
+ void eat() => print('Yum!');
+}
+```
+
+**Major changes**:
+
+* Builders now use `built_value`, and have a more consistent, friendly API.
+* Builders are now consistent - they don't perform work work until code is
+ emitted.
+* It's possible to overwrite the built-in code emitting, formatting, etc by
+ providing your own visitors. See `DartEmitter` as an example of the built-in
+ visitor/emitter.
+* Most of the expression and statement-level helpers were removed; in practice,
+ they were difficult to write and maintain, and many users commonly asked for
+ opt-out type APIs. See the `Code` example below:
+
+```dart
+void main() {
+ var code = new Code('x + y = z');
+ code.expression;
+ code.statement;
+}
+```
+
+See the commit log, examples, and tests for full details. While we want to try
+and avoid breaking changes, suggestions, new features, and incremental updates
+are welcome!
+
+## 2.0.0-beta
+
+* Added `lazySpec` and `lazyCode` to lazily create code on visit [#145](https://github.com/dart-lang/code_builder/issues/145).
+
+* **BUG FIX**: `equalsDart` emits the failing source code [#147](https://github.com/dart-lang/code_builder/issues/147).
+* **BUG FIX**: Top-level `lambda` `Method`s no longer emit invalid code [#146](https://github.com/dart-lang/code_builder/issues/146).
+
+## 2.0.0-alpha+3
+
+* Added `Expression.annotation` and `Expression.annotationNamed`.
+* Added `Method.closure` to create an `Expression`.
+* Added `FunctionType`.
+* Added `{new|const}InstanceNamed` to `Expression` [#135](https://github.com/dart-lang/code_builder/issues/135).
+ * Also added a `typeArguments` option to all invocations.
+* Added `assign{...}` variants to `Expression` [#137](https://github.com/dart-lang/code_builder/issues/137).
+* Added `.awaited` and `.returned` to `Expression` [#138](https://github.com/dart-lang/code_builder/issues/138).
+
+* **BUG FIX**: `Block` now implements `Code` [#136](https://github.com/dart-lang/code_builder/issues/136).
+* **BUG FIX**: `new DartEmitter.scoped()` applies prefixing [#139](https://github.com/dart-lang/code_builder/issues/139).
+
+* Renamed many of the `.asFoo(...)` and `.toFoo(...)` methods to single getter:
+ * `asCode()` to `code`
+ * `asStatement()` to `statement`
+ * `toExpression()` to `expression`
+
+* Moved `{new|const}Instance{[Named]}` from `Expression` to `Reference`.
+
+## 2.0.0-alpha+2
+
+* Upgraded `build_runner` from `^0.3.0` to `>=0.4.0 <0.6.0`.
+* Upgraded `build_value{_generator}` from `^1.0.0` to `>=2.0.0 <5.0.0`.
+* Upgraded `source_gen` from `>=0.5.0 <0.7.0` to `^0.7.0`.
+
+* Added `MethodModifier` to allow emit a `Method` with `async|async*|sync*`.
+* Added `show|hide` to `Directive`.
+* Added `Directive.importDeferredAs`.
+* Added a new line character after emitting some types (class, method, etc).
+* Added `refer` as a short-hand for `new Reference(...)`.
+ * `Reference` now implements `Expression`.
+
+* Added many classes/methods for writing bodies of `Code` fluently:
+ * `Expression`
+ * `LiteralExpression`
+ * `literal`
+ * `literalNull`
+ * `literalBool`
+ * `literalTrue`
+ * `literalFalse`
+ * `literalNum`
+ * `literalString`
+ * `literalList` and `literalConstList`
+ * `literalMap` and `literalConstMap`
+ * `const Code(staticString)`
+ * `const Code.scope((allocate) => '')`
+
+* Removed `SimpleSpecVisitor` (it was unused).
+* Removed `implements Reference` from `Method` and `Field`; not a lot of value.
+
+* `SpecVisitor<T>`'s methods all have an optional `[T context]` parameter now.
+ * This makes it much easier to avoid allocating extra `StringBuffer`s.
+* `equalsDart` removes insignificant white space before comparing results.
+
+## 2.0.0-alpha+1
+
+* Removed `Reference.localScope`. Just use `Reference(symbol)` now.
+* Allow `Reference` instead of an explicit `TypeReference` in most APIs.
+ * `toType()` is performed for you as part the emitter process
+
+```dart
+final animal = new Class((b) => b
+ ..name = 'Animal'
+ // Used to need a suffix of .toType().
+ ..extend = const Reference('Organism')
+ ..methods.add(new Method.returnsVoid((b) => b
+ ..name = 'eat'
+ ..lambda = true
+ ..body = new Code((b) => b..code = 'print(\'Yum\')'))));
+```
+
+* We now support the Dart 2.0 pre-release SDKs (`<2.0.0-dev.infinity`)
+* Removed the ability to treat `Class` as a `TypeReference`.
+ * Was required for compilation to `dart2js`, which is now tested on travis.
+
+## 2.0.0-alpha
+
+* Complete re-write to not use `package:analyzer`.
+* Code generation now properly uses the _builder_ pattern (via `built_value`).
+* See examples and tests for details.
+
+## 1.0.4
+
+* Added `isInstanceOf` to `ExpressionBuilder`, which performs an `is` check:
+
+```dart
+expect(
+ reference('foo').isInstanceOf(_barType),
+ equalsSource('foo is Bar'),
+);
+```
+
+## 1.0.3
+
+* Support latest `pkg/analyzer` and `pkg/func`.
+
+## 1.0.2
+
+* Update internals to use newer analyzer API
+
+## 1.0.1
+
+* Support the latest version of `package:dart_style`.
+
+## 1.0.0
+
+First full release. At this point, all changes until `2.0.0` will be backward
+compatible (new features) or bug fixes that are not breaking. This doesn't mean
+that the entire Dart language is buildable with our API, though.
+
+**Contributions are welcome.**
+
+- Exposed `uri` in `ImportBuilder`, `ExportBuilder`, and `Part[Of]Builder`.
+
+## 1.0.0-beta+7
+
+- Added `ExpressionBuilder#ternary`.
+
+## 1.0.0-beta+6
+
+- Added `TypeDefBuilder`.
+- Added `FunctionParameterBuilder`.
+- Added `asAbstract` to various `MethodBuilder` constructors.
+
+## 1.0.0-beta+5
+
+- Re-published the package without merge conflicts.
+
+## 1.0.0-beta+4
+
+- Renamed `PartBuilder` to `PartOfBuilder`.
+- Added a new class, `PartBuilder`, to represent `part '...dart'` directives.
+- Added the `HasAnnotations` interface to all library/part/directive builders.
+- Added `asFactory` and `asConst` to `ConstructorBuilder`.
+- Added `ConstructorBuilder.redirectTo` for a redirecting factory constructor.
+- Added a `name` getter to `ReferenceBuilder`.
+- Supplying an empty constructor name (`''`) is equivalent to `null` (default).
+- Automatically encodes string literals with multiple lines as `'''`.
+- Added `asThrow` to `ExpressionBuilder`.
+- Fixed a bug that prevented `FieldBuilder` from being used at the top-level.
+
+## 1.0.0-beta+3
+
+- Added support for `genericTypes` parameter for `ExpressionBuilder#invoke`:
+
+```dart
+expect(
+ explicitThis.invoke('doThing', [literal(true)], genericTypes: [
+ lib$core.bool,
+ ]),
+ equalsSource(r'''
+ this.doThing<bool>(true)
+ '''),
+);
+```
+
+- Added a `castAs` method to `ExpressionBuilder`:
+
+```dart
+expect(
+ literal(1.0).castAs(lib$core.num),
+ equalsSource(r'''
+ 1.0 as num
+ '''),
+);
+```
+
+### BREAKING CHANGES
+
+- Removed `namedNewInstance` and `namedConstInstance`, replaced with `constructor: `:
+
+```dart
+expect(
+ reference('Foo').newInstance([], constructor: 'other'),
+ equalsSource(r'''
+ new Foo.other()
+ '''),
+);
+```
+
+- Renamed `named` parameter to `namedArguments`:
+
+```dart
+expect(
+ reference('doThing').call(
+ [literal(true)],
+ namedArguments: {
+ 'otherFlag': literal(false),
+ },
+ ),
+ equalsSource(r'''
+ doThing(true, otherFlag: false)
+ '''),
+);
+```
+
+## 1.0.0-beta+2
+
+### BREAKING CHANGES
+
+Avoid creating symbols that can collide with the Dart language:
+
+- `MethodModifier.async` -> `MethodModifier.asAsync`
+- `MethodModifier.asyncStar` -> `MethodModifier.asAsyncStar`
+- `MethodModifier.syncStar` -> `MethodModifier.asSyncStar`
+
+## 1.0.0-beta+1
+
+- Add support for `switch` statements
+- Add support for a raw expression and statement
+ - `new ExpressionBuilder.raw(...)`
+ - `new StatemnetBuilder.raw(...)`
+
+This should help cover any cases not covered with builders today.
+
+- Allow referring to a `ClassBuilder` and `TypeBuilder` as an expression
+- Add support for accessing the index `[]` operator on an expression
+
+### BREAKING CHANGES
+
+- Changed `ExpressionBuilder.asAssign` to always take an `ExpressionBuilder` as
+ target and removed the `value` property. Most changes are pretty simple, and
+ involve just using `reference(...)`. For example:
+
+```dart
+literal(true).asAssign(reference('flag'))
+```
+
+... emits `flag = true`.
+
+## 1.0.0-beta
+
+- Add support for `async`, `sync`, `sync*` functions
+- Add support for expression `asAwait`, `asYield`, `asYieldStar`
+- Add `toExportBuilder` and `toImportBuilder` to types and references
+- Fix an import scoping bug in `return` statements and named constructor invocations.
+- Added constructor initializer support
+- Add `while` and `do {} while` loop support
+- Add `for` and `for-in` support
+- Added a `name` getter for `ParameterBuilder`
+
+## 1.0.0-alpha+7
+
+- Make use of the new analyzer APIs in preparation for analyzer version 0.30.
+
+## 1.0.0-alpha+6
+
+- `MethodBuilder.closure` emits properly as a top-level function
+
+## 1.0.0-alpha+5
+
+- MethodBuilder with no statements will create an empty block instead of
+ a semicolon.
+
+```dart
+// main() {}
+method('main')
+```
+
+- Fix lambdas and closures to not include a trailing semicolon when used
+ as an expression.
+
+```dart
+ // () => false
+ new MethodBuilder.closure(returns: literal(false));
+```
+
+## 1.0.0-alpha+4
+
+- Add support for the latest `pkg/analyzer`.
+
+## 1.0.0-alpha+3
+
+- BREAKING CHANGE: Added generics support to `TypeBuilder`:
+
+`importFrom` becomes a _named_, not a positional argument, and the named
+argument `genericTypes` is added (`Iterable<TypeBuilder>`).
+
+```dart
+// List<String>
+new TypeBuilder('List', genericTypes: [reference('String')])
+```
+
+- Added generic support to `ReferenceBuilder`:
+
+```dart
+// List<String>
+reference('List').toTyped([reference('String')])
+```
+
+- Fixed a bug where `ReferenceBuilder.buildAst` was not implemented
+- Added `and` and `or` methods to `ExpressionBuilder`:
+
+```dart
+// true || false
+literal(true).or(literal(false));
+
+// true && false
+literal(true).and(literal(false));
+```
+
+- Added support for creating closures - `MethodBuilder.closure`:
+
+```dart
+// () => true
+new MethodBuilder.closure(
+ returns: literal(true),
+ returnType: lib$core.bool,
+)
+```
+
+## 1.0.0-alpha+2
+
+- Added `returnVoid` to well, `return;`
+- Added support for top-level field assignments:
+
+```dart
+new LibraryBuilder()..addMember(literal(false).asConst('foo'))
+```
+
+- Added support for specifying a `target` when using `asAssign`:
+
+```dart
+// Outputs bank.bar = goldBar
+reference('goldBar').asAssign('bar', target: reference('bank'))
+```
+
+- Added support for the cascade operator:
+
+```dart
+// Outputs foo..doThis()..doThat()
+reference('foo').cascade((c) => <ExpressionBuilder> [
+ c.invoke('doThis', []),
+ c.invoke('doThat', []),
+]);
+```
+
+- Added support for accessing a property
+
+```dart
+// foo.bar
+reference('foo').property('bar');
+```
+
+## 1.0.0-alpha+1
+
+- Slight updates to confusing documentation.
+- Added support for null-aware assignments.
+- Added `show` and `hide` support to `ImportBuilder`
+- Added `deferred` support to `ImportBuilder`
+- Added `ExportBuilder`
+- Added `list` and `map` literals that support generic types
+
+## 1.0.0-alpha
+
+- Large refactor that makes the library more feature complete.
+
+## 0.1.1
+
+- Add the concept of `Scope` and change `toAst` to support it
+
+Now your entire AST tree can be scoped and import directives
+automatically added to a `LibraryBuilder` for you if you use
+`LibraryBuilder.scope`.
+
+## 0.1.0
+
+- Initial version
diff --git a/pkgs/code_builder/LICENSE b/pkgs/code_builder/LICENSE
new file mode 100644
index 0000000..2372431
--- /dev/null
+++ b/pkgs/code_builder/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2016, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/code_builder/README.md b/pkgs/code_builder/README.md
new file mode 100644
index 0000000..86decb5
--- /dev/null
+++ b/pkgs/code_builder/README.md
@@ -0,0 +1,114 @@
+[](https://github.com/dart-lang/tools/actions/workflows/code_builder.yaml)
+[](https://pub.dev/packages/code_builder)
+[](https://pub.dev/packages/code_builder/publisher)
+[](https://gitter.im/dart-lang/build)
+
+A fluent, builder-based library for generating valid Dart code.
+
+## Usage
+
+`code_builder` has a narrow and user-friendly API.
+
+See the `example` and `test` folders for additional examples.
+
+For example creating a class with a method:
+
+```dart
+import 'package:code_builder/code_builder.dart';
+import 'package:dart_style/dart_style.dart';
+
+void main() {
+ final animal = Class((b) => b
+ ..name = 'Animal'
+ ..extend = refer('Organism')
+ ..methods.add(Method.returnsVoid((b) => b
+ ..name = 'eat'
+ ..body = const Code("print('Yum!');"))));
+ final emitter = DartEmitter();
+ print(
+ DartFormatter(languageVersion: DartFormatter.latestLanguageVersion)
+ .format('${animal.accept(emitter)}'),
+ );
+}
+```
+
+Outputs:
+
+```dart
+class Animal extends Organism {
+ void eat() => print('Yum!');
+}
+```
+
+Have a complicated set of dependencies for your generated code? `code_builder`
+supports automatic scoping of your ASTs to automatically use prefixes to avoid
+symbol conflicts:
+
+```dart
+import 'package:code_builder/code_builder.dart';
+import 'package:dart_style/dart_style.dart';
+
+void main() {
+ final library = Library((b) => b.body.addAll([
+ Method((b) => b
+ ..body = const Code('')
+ ..name = 'doThing'
+ ..returns = refer('Thing', 'package:a/a.dart')),
+ Method((b) => b
+ ..body = const Code('')
+ ..name = 'doOther'
+ ..returns = refer('Other', 'package:b/b.dart')),
+ ]));
+ final emitter = DartEmitter.scoped();
+ print(
+ DartFormatter(languageVersion: DartFormatter.latestLanguageVersion)
+ .format('${library.accept(emitter)}'),
+ );
+}
+```
+
+Outputs:
+
+```dart
+import 'package:a/a.dart' as _i1;
+import 'package:b/b.dart' as _i2;
+
+_i1.Thing doThing() {}
+_i2.Other doOther() {}
+```
+
+## Contributing
+
+- Read and help us document common patterns over [in the docs][docs].
+- Is there a _bug_ in the code? [File an issue][issue].
+
+If a feature is missing (the Dart language is always evolving) or you'd like an
+easier or better way to do something, consider [opening a pull request][pull].
+You can always [file an issue][issue], but generally speaking, feature requests
+will be on a best-effort basis.
+
+> **NOTE**: Due to the evolving Dart SDK the local `dartfmt` must be used to
+> format this repository. You can run it simply from the command-line:
+>
+> ```sh
+> $ dart run dart_style:format -w .
+> ```
+
+[issue]: https://github.com/dart-lang/tools/issues
+[pull]: https://github.com/dart-lang/tools/pulls
+
+### Updating generated (`.g.dart`) files
+
+> **NOTE**: There is currently a limitation in `build_runner` that requires a
+> workaround for developing this package since it is a dependency of the build
+> system.
+
+Make a snapshot of the generated [`build_runner`][build_runner] build script and
+run from the snapshot instead of from source to avoid problems with deleted
+files. These steps must be run without deleting the source files.
+
+```bash
+./tool/regenerate.sh
+```
+
+[build_runner]: https://pub.dev/packages/build_runner
diff --git a/pkgs/code_builder/analysis_options.yaml b/pkgs/code_builder/analysis_options.yaml
new file mode 100644
index 0000000..d052c68
--- /dev/null
+++ b/pkgs/code_builder/analysis_options.yaml
@@ -0,0 +1,25 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_unused_constructor_parameters
+ - cancel_subscriptions
+ - cascade_invocations
+ - join_return_with_assignment
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - no_runtimeType_toString
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - unnecessary_await_in_return
+ - use_string_buffers
diff --git a/pkgs/code_builder/doc/Getting-Started.md b/pkgs/code_builder/doc/Getting-Started.md
new file mode 100644
index 0000000..b82da6c
--- /dev/null
+++ b/pkgs/code_builder/doc/Getting-Started.md
@@ -0,0 +1,35 @@
+# Common patterns
+
+## Classes
+
+### Creating a simple class
+
+> ```dart
+> class Animal {}
+> ```
+
+```dart
+new ClassBuilder(
+ 'Animal',
+)
+```
+
+### Creating an abstract class with a method
+
+> ```dart
+> abstract class Animal {
+> void eat();
+> }
+> ```
+
+```dart
+new ClassBuilder(
+ 'Animal',
+ asAbstract: true,
+)..addMethod(
+ new MethodBuilder.returnVoid(
+ 'eat',
+ asAbstract: true,
+ ),
+)
+```
\ No newline at end of file
diff --git a/pkgs/code_builder/doc/Home.md b/pkgs/code_builder/doc/Home.md
new file mode 100644
index 0000000..72e87a8
--- /dev/null
+++ b/pkgs/code_builder/doc/Home.md
@@ -0,0 +1,6 @@
+The [`code_builder`][code_builder] package helps generate valid [Dart][] source code programmatically, usually as part of a build process or generation step. Most of the API currently takes a little exploring to get used to, it's recommended to read the [API documentation][docs], or read the [getting started][] guide.
+
+[code_builder]: pub.dartlang.org/packages/code_builder
+[Dart]: https://www.dartlang.org/
+[docs]: https://www.dartdocs.org/documentation/code_builder/latest
+[getting started]: Getting-Started
diff --git a/pkgs/code_builder/example/example.dart b/pkgs/code_builder/example/example.dart
new file mode 100644
index 0000000..6f73598
--- /dev/null
+++ b/pkgs/code_builder/example/example.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:dart_style/dart_style.dart';
+
+final _dartfmt = DartFormatter(
+ languageVersion: DartFormatter.latestLanguageVersion,
+);
+
+void main() {
+ print('animalClass():\n${'=' * 40}\n${animalClass()}');
+ print('scopedLibrary():\n${'=' * 40}\n${scopedLibrary()}');
+ print('jsonEnum():\n${'=' * 40}\n${jsonEnum()}');
+}
+
+/// Outputs:
+///
+/// ```dart
+/// class Animal extends Organism {
+/// void eat() => print('Yum!');
+/// }
+/// ```
+String animalClass() {
+ final animal = Class((b) => b
+ ..name = 'Animal'
+ ..extend = refer('Organism')
+ ..methods.add(Method.returnsVoid((b) => b
+ ..name = 'eat'
+ ..body = refer('print').call([literalString('Yum!')]).code)));
+ return _dartfmt.format('${animal.accept(DartEmitter())}');
+}
+
+/// Outputs:
+///
+/// ```dart
+/// import 'package:a/a.dart' as _i1;
+/// import 'package:b/b.dart' as _i2;
+///
+/// _i1.Thing doThing() {}
+/// _i2.Other doOther() {}
+/// ```
+String scopedLibrary() {
+ final methods = [
+ Method((b) => b
+ ..body = const Code('')
+ ..name = 'doThing'
+ ..returns = refer('Thing', 'package:a/a.dart')),
+ Method((b) => b
+ ..body = const Code('')
+ ..name = 'doOther'
+ ..returns = refer('Other', 'package:b/b.dart')),
+ ];
+ final library = Library((b) => b.body.addAll(methods));
+ return _dartfmt.format('${library.accept(DartEmitter.scoped())}');
+}
+
+/// Outputs:
+///
+/// ```dart
+/// enum Unit {
+/// @JsonKey('m')
+/// metric,
+/// @JsonKey('i')
+/// imperial
+/// }
+/// ```
+String jsonEnum() {
+ final values = <EnumValue>[
+ EnumValue((b) => b
+ ..name = 'metric'
+ ..annotations.addAll([
+ refer('JsonKey').call([literalString('m')])
+ ])),
+ EnumValue((b) => b
+ ..name = 'imperial'
+ ..annotations.addAll([
+ refer('JsonKey').call([literalString('i')])
+ ])),
+ ];
+ final e = Enum((b) => b
+ ..name = 'Unit'
+ ..values.addAll(values));
+ return _dartfmt.format('${e.accept(DartEmitter())}');
+}
diff --git a/pkgs/code_builder/lib/code_builder.dart b/pkgs/code_builder/lib/code_builder.dart
new file mode 100644
index 0000000..9cd15b9
--- /dev/null
+++ b/pkgs/code_builder/lib/code_builder.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/allocator.dart' show Allocator;
+export 'src/base.dart' show Spec, lazySpec;
+export 'src/emitter.dart' show DartEmitter;
+export 'src/matchers.dart' show EqualsDart, equalsDart;
+export 'src/specs/class.dart' show Class, ClassBuilder, ClassModifier;
+export 'src/specs/code.dart'
+ show Block, BlockBuilder, Code, ScopedCode, StaticCode, lazyCode;
+export 'src/specs/constructor.dart' show Constructor, ConstructorBuilder;
+export 'src/specs/directive.dart'
+ show Directive, DirectiveBuilder, DirectiveType;
+export 'src/specs/enum.dart'
+ show Enum, EnumBuilder, EnumValue, EnumValueBuilder;
+export 'src/specs/expression.dart'
+ show
+ BinaryExpression,
+ CodeExpression,
+ Expression,
+ ExpressionEmitter,
+ ExpressionVisitor,
+ InvokeExpression,
+ InvokeExpressionType,
+ LiteralExpression,
+ LiteralListExpression,
+ ParenthesizedExpression,
+ ToCodeExpression,
+ declareConst,
+ declareFinal,
+ declareVar,
+ literal,
+ literalBool,
+ literalConstList,
+ literalConstMap,
+ literalConstRecord,
+ literalConstSet,
+ literalFalse,
+ literalList,
+ literalMap,
+ literalNull,
+ literalNullSafeSpread,
+ literalNum,
+ literalRecord,
+ literalSet,
+ literalSpread,
+ literalString,
+ literalTrue;
+export 'src/specs/extension.dart' show Extension, ExtensionBuilder;
+export 'src/specs/extension_type.dart'
+ show
+ ExtensionType,
+ ExtensionTypeBuilder,
+ RepresentationDeclaration,
+ RepresentationDeclarationBuilder;
+export 'src/specs/field.dart' show Field, FieldBuilder, FieldModifier;
+export 'src/specs/library.dart' show Library, LibraryBuilder;
+export 'src/specs/method.dart'
+ show
+ Method,
+ MethodBuilder,
+ MethodModifier,
+ MethodType,
+ Parameter,
+ ParameterBuilder;
+export 'src/specs/mixin.dart' show Mixin, MixinBuilder;
+export 'src/specs/reference.dart' show Reference, refer;
+export 'src/specs/type_function.dart' show FunctionType, FunctionTypeBuilder;
+export 'src/specs/type_record.dart' show RecordType, RecordTypeBuilder;
+export 'src/specs/type_reference.dart' show TypeReference, TypeReferenceBuilder;
+export 'src/specs/typedef.dart' show TypeDef, TypeDefBuilder;
diff --git a/pkgs/code_builder/lib/src/allocator.dart b/pkgs/code_builder/lib/src/allocator.dart
new file mode 100644
index 0000000..18d2d8c
--- /dev/null
+++ b/pkgs/code_builder/lib/src/allocator.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'specs/directive.dart';
+import 'specs/reference.dart';
+
+/// Collects references and automatically allocates prefixes and imports.
+///
+/// `Allocator` takes out the manual work of deciding whether a symbol will
+/// clash with other imports in your generated code, or what imports are needed
+/// to resolve all symbols in your generated code.
+abstract class Allocator {
+ /// An allocator that does not prefix symbols nor collects imports.
+ static const Allocator none = _NullAllocator();
+
+ /// Creates a new default allocator that applies no prefixing.
+ factory Allocator() = _Allocator;
+
+ /// Creates a new allocator that applies naive prefixing to avoid conflicts.
+ ///
+ /// This implementation is not optimized for any particular code generation
+ /// style and instead takes a conservative approach of prefixing _every_
+ /// import except references to `dart:core` (which are considered always
+ /// imported).
+ ///
+ /// The prefixes are not guaranteed to be stable and cannot be expected to
+ /// have any particular value.
+ factory Allocator.simplePrefixing() = _PrefixedAllocator;
+
+ /// Returns a reference string given a [reference] object.
+ ///
+ /// For example, a no-op implementation:
+ /// ```dart
+ /// allocate(const Reference('List', 'dart:core')); // Returns 'List'.
+ /// ```
+ ///
+ /// Where-as an implementation that prefixes imports might output:
+ /// ```dart
+ /// allocate(const Reference('Foo', 'package:foo')); // Returns '_i1.Foo'.
+ /// ```
+ String allocate(Reference reference);
+
+ /// All imports that have so far been added implicitly via [allocate].
+ Iterable<Directive> get imports;
+}
+
+class _Allocator implements Allocator {
+ final _imports = <String>{};
+
+ @override
+ String allocate(Reference reference) {
+ final url = reference.url;
+ if (url != null) {
+ _imports.add(url);
+ }
+ return reference.symbol!;
+ }
+
+ @override
+ Iterable<Directive> get imports => _imports.map(Directive.import);
+}
+
+class _NullAllocator implements Allocator {
+ const _NullAllocator();
+
+ @override
+ String allocate(Reference reference) => reference.symbol!;
+
+ @override
+ Iterable<Directive> get imports => const [];
+}
+
+class _PrefixedAllocator implements Allocator {
+ static const _doNotPrefix = ['dart:core'];
+
+ final _imports = <String, int>{};
+ var _keys = 1;
+
+ @override
+ String allocate(Reference reference) {
+ final symbol = reference.symbol;
+ final url = reference.url;
+ if (url == null || _doNotPrefix.contains(url)) {
+ return symbol!;
+ }
+ return '_i${_imports.putIfAbsent(url, _nextKey)}.$symbol';
+ }
+
+ int _nextKey() => _keys++;
+
+ @override
+ Iterable<Directive> get imports => _imports.keys.map(
+ (u) => Directive.import(u, as: '_i${_imports[u]}'),
+ );
+}
diff --git a/pkgs/code_builder/lib/src/base.dart b/pkgs/code_builder/lib/src/base.dart
new file mode 100644
index 0000000..216b9a9
--- /dev/null
+++ b/pkgs/code_builder/lib/src/base.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'visitors.dart';
+
+abstract class Spec {
+ R accept<R>(SpecVisitor<R> visitor, [R? context]);
+}
+
+/// Returns a generic [Spec] that is lazily generated when visited.
+Spec lazySpec(Spec Function() generate) => _LazySpec(generate);
+
+class _LazySpec implements Spec {
+ final Spec Function() generate;
+
+ const _LazySpec(this.generate);
+
+ @override
+ R accept<R>(SpecVisitor<R> visitor, [R? context]) =>
+ generate().accept(visitor, context);
+}
diff --git a/pkgs/code_builder/lib/src/emitter.dart b/pkgs/code_builder/lib/src/emitter.dart
new file mode 100644
index 0000000..12109cc
--- /dev/null
+++ b/pkgs/code_builder/lib/src/emitter.dart
@@ -0,0 +1,944 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'allocator.dart';
+import 'base.dart';
+import 'specs/class.dart';
+import 'specs/code.dart';
+import 'specs/constructor.dart';
+import 'specs/directive.dart';
+import 'specs/enum.dart';
+import 'specs/expression.dart';
+import 'specs/extension.dart';
+import 'specs/extension_type.dart';
+import 'specs/field.dart';
+import 'specs/library.dart';
+import 'specs/method.dart';
+import 'specs/mixin.dart';
+import 'specs/reference.dart';
+import 'specs/type_function.dart';
+import 'specs/type_record.dart';
+import 'specs/type_reference.dart';
+import 'specs/typedef.dart';
+import 'visitors.dart';
+
+/// Helper method improving on [StringSink.writeAll].
+///
+/// For every `Spec` in [elements], executing [visit].
+///
+/// If [elements] is at least 2 elements, inserts [separator] delimiting them.
+StringSink visitAll<T>(
+ Iterable<T> elements,
+ StringSink output,
+ void Function(T) visit, [
+ String separator = ', ',
+]) {
+ // Basically, this whole method is an improvement on
+ // output.writeAll(specs.map((s) => s.accept(visitor));
+ //
+ // ... which would allocate more StringBuffer(s) for a one-time use.
+ if (elements.isEmpty) {
+ return output;
+ }
+ final iterator = elements.iterator..moveNext();
+ visit(iterator.current);
+ while (iterator.moveNext()) {
+ output.write(separator);
+ visit(iterator.current);
+ }
+ return output;
+}
+
+class DartEmitter extends Object
+ with CodeEmitter, ExpressionEmitter
+ implements SpecVisitor<StringSink> {
+ @override
+ final Allocator allocator;
+
+ /// If directives should be ordered while emitting.
+ ///
+ /// Ordering rules follow the guidance in
+ /// [Effective Dart](https://dart.dev/guides/language/effective-dart/style#ordering)
+ /// and the
+ /// [directives_ordering](https://dart-lang.github.io/linter/lints/directives_ordering.html)
+ /// lint.
+ final bool orderDirectives;
+
+ /// If nullable types should be emitted with the nullable suffix ("?").
+ ///
+ /// Null safety syntax should only be enabled if the output will be used with
+ /// a Dart language version which supports it.
+ final bool _useNullSafetySyntax;
+
+ /// Creates a new instance of [DartEmitter].
+ ///
+ /// May specify an [Allocator] to use for references and imports,
+ /// otherwise uses [Allocator.none] which never prefixes references and will
+ /// not automatically emit import directives.
+ DartEmitter(
+ {this.allocator = Allocator.none,
+ this.orderDirectives = false,
+ bool useNullSafetySyntax = false})
+ : _useNullSafetySyntax = useNullSafetySyntax;
+
+ /// Creates a new instance of [DartEmitter] with simple automatic imports.
+ factory DartEmitter.scoped(
+ {bool orderDirectives = false, bool useNullSafetySyntax = false}) =>
+ DartEmitter(
+ allocator: Allocator.simplePrefixing(),
+ orderDirectives: orderDirectives,
+ useNullSafetySyntax: useNullSafetySyntax);
+
+ static bool _isLambdaBody(Code? code) =>
+ code is ToCodeExpression && !code.isStatement;
+
+ /// Whether the provided [method] is considered a lambda method.
+ static bool _isLambdaMethod(Method method) =>
+ method.lambda ?? _isLambdaBody(method.body);
+
+ /// Whether the provided [constructor] is considered a lambda method.
+ static bool _isLambdaConstructor(Constructor constructor) =>
+ constructor.lambda ??
+ constructor.factory && _isLambdaBody(constructor.body);
+
+ @override
+ StringSink visitAnnotation(Expression spec, [StringSink? output]) {
+ (output ??= StringBuffer()).write('@');
+ spec.accept(this, output);
+ output.write(' ');
+ return output;
+ }
+
+ @override
+ StringSink visitClass(Class spec, [StringSink? output]) {
+ final out = output ??= StringBuffer();
+ spec.docs.forEach(out.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, out);
+ }
+
+ void writeModifier() {
+ if (spec.modifier != null) {
+ out.write('${spec.modifier!.name} ');
+ }
+ }
+
+ if (spec.sealed) {
+ out.write('sealed ');
+ } else {
+ if (spec.abstract) {
+ out.write('abstract ');
+ }
+ writeModifier();
+ if (spec.mixin) {
+ out.write('mixin ');
+ }
+ }
+ out.write('class ${spec.name}');
+ visitTypeParameters(spec.types.map((r) => r.type), out);
+ if (spec.extend != null) {
+ out.write(' extends ');
+ spec.extend!.type.accept(this, out);
+ }
+ if (spec.mixins.isNotEmpty) {
+ out
+ ..write(' with ')
+ ..writeAll(
+ spec.mixins.map<StringSink>((m) => m.type.accept(this)), ',');
+ }
+ if (spec.implements.isNotEmpty) {
+ out
+ ..write(' implements ')
+ ..writeAll(
+ spec.implements.map<StringSink>((m) => m.type.accept(this)), ',');
+ }
+ out.write(' {');
+ for (var c in spec.constructors) {
+ visitConstructor(c, spec.name, out);
+ out.writeln();
+ }
+ for (var f in spec.fields) {
+ visitField(f, out);
+ out.writeln();
+ }
+ for (var m in spec.methods) {
+ visitMethod(m, out);
+ if (_isLambdaMethod(m)) {
+ out.writeln(';');
+ }
+ out.writeln();
+ }
+ out.writeln(' }');
+ return out;
+ }
+
+ @override
+ StringSink visitMixin(Mixin spec, [StringSink? output]) {
+ final out = output ??= StringBuffer();
+ spec.docs.forEach(out.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, out);
+ }
+
+ if (spec.base) {
+ out.write('base ');
+ }
+ out.write('mixin ${spec.name}');
+ visitTypeParameters(spec.types.map((r) => r.type), out);
+ if (spec.on != null) {
+ out.write(' on ');
+ spec.on!.type.accept(this, out);
+ }
+ if (spec.implements.isNotEmpty) {
+ out
+ ..write(' implements ')
+ ..writeAll(
+ spec.implements.map<StringSink>((m) => m.type.accept(this)), ',');
+ }
+ out.write(' {');
+ for (var f in spec.fields) {
+ visitField(f, out);
+ out.writeln();
+ }
+ for (var m in spec.methods) {
+ visitMethod(m, out);
+ if (_isLambdaMethod(m)) {
+ out.write(';');
+ }
+ out.writeln();
+ }
+ out.write(' }');
+ return out;
+ }
+
+ @override
+ StringSink visitConstructor(Constructor spec, String clazz,
+ [StringSink? output]) {
+ output ??= StringBuffer();
+ spec.docs.forEach(output.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, output);
+ }
+ if (spec.external) {
+ output.write('external ');
+ }
+ if (spec.constant) {
+ output.write('const ');
+ }
+ if (spec.factory) {
+ output.write('factory ');
+ }
+ output.write(clazz);
+ if (spec.name != null) {
+ output
+ ..write('.')
+ ..write(spec.name);
+ }
+ output.write('(');
+ final hasMultipleParameters =
+ spec.requiredParameters.length + spec.optionalParameters.length > 1;
+ if (spec.requiredParameters.isNotEmpty) {
+ var count = 0;
+ for (final p in spec.requiredParameters) {
+ count++;
+ _visitParameter(p, output);
+ if (hasMultipleParameters ||
+ spec.requiredParameters.length != count ||
+ spec.optionalParameters.isNotEmpty) {
+ output.write(', ');
+ }
+ }
+ }
+ if (spec.optionalParameters.isNotEmpty) {
+ final named = spec.optionalParameters.any((p) => p.named);
+ if (named) {
+ output.write('{');
+ } else {
+ output.write('[');
+ }
+ var count = 0;
+ for (final p in spec.optionalParameters) {
+ count++;
+ _visitParameter(p, output, optional: true, named: named);
+ if (hasMultipleParameters || spec.optionalParameters.length != count) {
+ output.write(', ');
+ }
+ }
+ if (named) {
+ output.write('}');
+ } else {
+ output.write(']');
+ }
+ }
+ output.write(')');
+ if (spec.initializers.isNotEmpty) {
+ output.write(' : ');
+ var count = 0;
+ for (final initializer in spec.initializers) {
+ count++;
+ initializer.accept(this, output);
+ if (count != spec.initializers.length) {
+ output.write(', ');
+ }
+ }
+ }
+ if (spec.redirect != null) {
+ output.write(' = ');
+ spec.redirect!.type.accept(this, output);
+ output.write(';');
+ } else if (spec.body != null) {
+ if (_isLambdaConstructor(spec)) {
+ output.write(' => ');
+ spec.body!.accept(this, output);
+ output.write(';');
+ } else {
+ output.write(' { ');
+ spec.body!.accept(this, output);
+ output.write(' }');
+ }
+ } else {
+ output.write(';');
+ }
+ output.writeln();
+ return output;
+ }
+
+ @override
+ StringSink visitExtension(Extension spec, [StringSink? output]) {
+ final out = output ??= StringBuffer();
+ spec.docs.forEach(out.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, out);
+ }
+
+ out.write('extension');
+ if (spec.name != null) {
+ out.write(' ${spec.name}');
+ }
+ visitTypeParameters(spec.types.map((r) => r.type), out);
+ if (spec.on != null) {
+ out.write(' on ');
+ spec.on!.type.accept(this, out);
+ }
+ out.write(' {');
+ for (var f in spec.fields) {
+ visitField(f, out);
+ out.writeln();
+ }
+ for (var m in spec.methods) {
+ visitMethod(m, out);
+ if (_isLambdaMethod(m)) {
+ out.write(';');
+ }
+ out.writeln();
+ }
+ out.writeln(' }');
+ return out;
+ }
+
+ @override
+ StringSink visitExtensionType(ExtensionType spec, [StringSink? output]) {
+ final out = output ??= StringBuffer();
+ spec.docs.forEach(out.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, out);
+ }
+
+ out.write('extension type ');
+ if (spec.constant) out.write('const ');
+ out.write(spec.name);
+ visitTypeParameters(spec.types.map((r) => r.type), out);
+ if (spec.primaryConstructorName.isNotEmpty) {
+ out.write('.${spec.primaryConstructorName}');
+ }
+ out.write('(');
+ _visitRepresentationDeclaration(spec.representationDeclaration, out);
+ out.write(')');
+
+ if (spec.implements.isNotEmpty) {
+ out
+ ..write(' implements ')
+ ..writeAll(
+ spec.implements.map<StringSink>((m) => m.type.accept(this)), ',');
+ }
+
+ out.writeln(' {');
+ for (var c in spec.constructors) {
+ visitConstructor(c, spec.name, out);
+ out.writeln();
+ }
+ for (var f in spec.fields) {
+ visitField(f, out);
+ out.writeln();
+ }
+ for (var m in spec.methods) {
+ visitMethod(m, out);
+ if (_isLambdaMethod(m)) {
+ out.writeln(';');
+ }
+ out.writeln();
+ }
+ out.writeln('}');
+ return out;
+ }
+
+ void _visitRepresentationDeclaration(
+ RepresentationDeclaration spec, StringSink out) {
+ spec.docs.forEach(out.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, out);
+ }
+ spec.declaredRepresentationType.accept(this, out);
+ out.write(' ${spec.name}');
+ }
+
+ @override
+ StringSink visitDirective(Directive spec, [StringSink? output]) {
+ output ??= StringBuffer();
+ switch (spec.type) {
+ case DirectiveType.import:
+ output.write('import ');
+ break;
+ case DirectiveType.export:
+ output.write('export ');
+ break;
+ case DirectiveType.part:
+ output.write('part ');
+ break;
+ case DirectiveType.partOf:
+ output.write('part of ');
+ break;
+ }
+ output.write("'${spec.url}'");
+ if (spec.as != null) {
+ if (spec.deferred) {
+ output.write(' deferred ');
+ }
+ output.write(' as ${spec.as}');
+ }
+ if (spec.show.isNotEmpty) {
+ output
+ ..write(' show ')
+ ..writeAll(spec.show, ', ');
+ } else if (spec.hide.isNotEmpty) {
+ output
+ ..write(' hide ')
+ ..writeAll(spec.hide, ', ');
+ }
+ output.write(';');
+ return output;
+ }
+
+ @override
+ StringSink visitField(Field spec, [StringSink? output]) {
+ output ??= StringBuffer();
+ spec.docs.forEach(output.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, output);
+ }
+ if (spec.static) {
+ output.write('static ');
+ }
+ if (spec.late && _useNullSafetySyntax) {
+ output.write('late ');
+ }
+ if (spec.external) {
+ output.write('external ');
+ }
+ switch (spec.modifier) {
+ case FieldModifier.var$:
+ if (spec.type == null) {
+ output.write('var ');
+ }
+ break;
+ case FieldModifier.final$:
+ output.write('final ');
+ break;
+ case FieldModifier.constant:
+ output.write('const ');
+ break;
+ }
+ if (spec.type != null) {
+ spec.type!.type.accept(this, output);
+ output.write(' ');
+ }
+ output.write(spec.name);
+ if (spec.assignment != null) {
+ output.write(' = ');
+ startConstCode(spec.modifier == FieldModifier.constant, () {
+ spec.assignment!.accept(this, output);
+ });
+ }
+ output.writeln(';');
+ return output;
+ }
+
+ @override
+ StringSink visitLibrary(Library spec, [StringSink? output]) {
+ output ??= StringBuffer();
+
+ if (spec.comments.isNotEmpty) {
+ spec.comments.map((line) => '// $line').forEach(output.writeln);
+ output.writeln();
+ }
+
+ if (spec.generatedByComment != null) {
+ output
+ ..writeln('// ${spec.generatedByComment}')
+ ..writeln();
+ }
+
+ if (spec.ignoreForFile.isNotEmpty) {
+ final ignores = spec.ignoreForFile.toList()..sort();
+ final lines = ['// ignore_for_file: ${ignores.first}'];
+ for (var ignore in ignores.skip(1)) {
+ if (lines.last.length + 2 + ignore.length > 80) {
+ lines.add('// ignore_for_file: $ignore');
+ } else {
+ lines[lines.length - 1] = '${lines.last}, $ignore';
+ }
+ }
+ lines.forEach(output.writeln);
+ output.writeln();
+ }
+
+ // Process the body first in order to prime the allocators.
+ final body = StringBuffer();
+ for (final spec in spec.body) {
+ spec.accept(this, body);
+ if (spec is Method && _isLambdaMethod(spec)) {
+ body.write(';');
+ }
+ }
+
+ spec.docs.forEach(output.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, output);
+ }
+ if (spec.name != null) {
+ output.write('library ${spec.name!};');
+ } else if (spec.annotations.isNotEmpty || spec.docs.isNotEmpty) {
+ // An explicit _unnamed_ library directive is only required if there are
+ // annotations or doc comments on the library.
+ output.write('library;');
+ }
+
+ final directives = <Directive>[...allocator.imports, ...spec.directives];
+
+ if (orderDirectives) {
+ directives.sort();
+ }
+
+ Directive? previous;
+ if (directives.any((d) => d.as?.startsWith('_') ?? false)) {
+ output.writeln(
+ '// ignore_for_file: no_leading_underscores_for_library_prefixes');
+ }
+ for (final directive in directives) {
+ if (_newLineBetween(orderDirectives, previous, directive)) {
+ // Note: dartfmt handles creating new lines between directives.
+ // 2 lines are written here. The first one comes after the previous
+ // directive `;`, the second is the empty line.
+ output
+ ..writeln()
+ ..writeln();
+ }
+ directive.accept(this, output);
+ previous = directive;
+ }
+ output.write(body);
+ return output;
+ }
+
+ @override
+ StringSink visitFunctionType(FunctionType spec, [StringSink? output]) {
+ final out = output ??= StringBuffer();
+ if (spec.returnType != null) {
+ spec.returnType!.accept(this, out);
+ out.write(' ');
+ }
+ out.write('Function');
+ if (spec.types.isNotEmpty) {
+ out.write('<');
+ visitAll<Reference>(spec.types, out, (spec) {
+ spec.accept(this, out);
+ });
+ out.write('>');
+ }
+ out.write('(');
+ final needsTrailingComma = spec.requiredParameters.length +
+ spec.optionalParameters.length +
+ spec.namedRequiredParameters.length +
+ spec.namedParameters.length >
+ 1;
+ visitAll<Reference>(spec.requiredParameters, out, (spec) {
+ spec.accept(this, out);
+ });
+ final hasNamedParameters = spec.namedRequiredParameters.isNotEmpty ||
+ spec.namedParameters.isNotEmpty;
+ if (spec.requiredParameters.isNotEmpty &&
+ (needsTrailingComma ||
+ spec.optionalParameters.isNotEmpty ||
+ hasNamedParameters)) {
+ out.write(', ');
+ }
+ if (spec.optionalParameters.isNotEmpty) {
+ out.write('[');
+ visitAll<Reference>(spec.optionalParameters, out, (spec) {
+ spec.accept(this, out);
+ });
+ if (needsTrailingComma) {
+ out.write(', ');
+ }
+ out.write(']');
+ } else if (hasNamedParameters) {
+ out.write('{');
+ visitAll<String>(spec.namedRequiredParameters.keys, out, (name) {
+ out.write('required ');
+ spec.namedRequiredParameters[name]!.accept(this, out);
+ out
+ ..write(' ')
+ ..write(name);
+ });
+ if (spec.namedRequiredParameters.isNotEmpty &&
+ spec.namedParameters.isNotEmpty) {
+ out.write(', ');
+ }
+ visitAll<String>(spec.namedParameters.keys, out, (name) {
+ spec.namedParameters[name]!.accept(this, out);
+ out
+ ..write(' ')
+ ..write(name);
+ });
+ if (needsTrailingComma) {
+ out.write(', ');
+ }
+ out.write('}');
+ }
+ out.write(')');
+ if (_useNullSafetySyntax && (spec.isNullable ?? false)) {
+ out.write('?');
+ }
+ return out;
+ }
+
+ @override
+ StringSink visitRecordType(RecordType spec, [StringSink? output]) {
+ final out = (output ??= StringBuffer())..write('(');
+ visitAll<Reference>(spec.positionalFieldTypes, out, (spec) {
+ spec.accept(this, out);
+ });
+ if (spec.namedFieldTypes.isNotEmpty) {
+ if (spec.positionalFieldTypes.isNotEmpty) {
+ out.write(', ');
+ }
+ out.write('{');
+ visitAll<MapEntry<String, Reference>>(spec.namedFieldTypes.entries, out,
+ (entry) {
+ entry.value.accept(this, out);
+ out.write(' ${entry.key}');
+ });
+ out.write('}');
+ } else if (spec.positionalFieldTypes.length == 1) {
+ out.write(',');
+ }
+ out.write(')');
+ // It doesn't really make sense to use records without
+ // `_useNullSafetySyntax`, but since code_builder is generally very
+ // permissive, follow it here too.
+ if (_useNullSafetySyntax && (spec.isNullable ?? false)) {
+ out.write('?');
+ }
+ return out;
+ }
+
+ @override
+ StringSink visitTypeDef(TypeDef spec, [StringSink? output]) {
+ final out = output ??= StringBuffer();
+ spec.docs.forEach(out.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, out);
+ }
+ out.write('typedef ${spec.name}');
+ visitTypeParameters(spec.types.map((r) => r.type), out);
+ out.write(' = ');
+ spec.definition.accept(this, out);
+ out.writeln(';');
+ return out;
+ }
+
+ @override
+ StringSink visitMethod(Method spec, [StringSink? output]) {
+ output ??= StringBuffer();
+ spec.docs.forEach(output.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, output);
+ }
+ if (spec.external) {
+ output.write('external ');
+ }
+ if (spec.static) {
+ output.write('static ');
+ }
+ if (spec.returns != null) {
+ spec.returns!.accept(this, output);
+ output.write(' ');
+ }
+ if (spec.type == MethodType.getter) {
+ output
+ ..write('get ')
+ ..write(spec.name);
+ } else {
+ if (spec.type == MethodType.setter) {
+ output.write('set ');
+ }
+ if (spec.name != null) {
+ output.write(spec.name);
+ }
+ visitTypeParameters(spec.types.map((r) => r.type), output);
+ output.write('(');
+ final hasMultipleParameters =
+ spec.requiredParameters.length + spec.optionalParameters.length > 1;
+ if (spec.requiredParameters.isNotEmpty) {
+ var count = 0;
+ for (final p in spec.requiredParameters) {
+ count++;
+ _visitParameter(p, output);
+ if (hasMultipleParameters ||
+ spec.requiredParameters.length != count ||
+ spec.optionalParameters.isNotEmpty) {
+ output.write(', ');
+ }
+ }
+ }
+ if (spec.optionalParameters.isNotEmpty) {
+ final named = spec.optionalParameters.any((p) => p.named);
+ if (named) {
+ output.write('{');
+ } else {
+ output.write('[');
+ }
+ var count = 0;
+ for (final p in spec.optionalParameters) {
+ count++;
+ _visitParameter(p, output, optional: true, named: named);
+ if (hasMultipleParameters ||
+ spec.optionalParameters.length != count) {
+ output.write(', ');
+ }
+ }
+ if (named) {
+ output.write('}');
+ } else {
+ output.write(']');
+ }
+ }
+ output.write(')');
+ }
+ if (spec.body != null) {
+ if (spec.modifier != null) {
+ switch (spec.modifier!) {
+ case MethodModifier.async:
+ output.write(' async ');
+ break;
+ case MethodModifier.asyncStar:
+ output.write(' async* ');
+ break;
+ case MethodModifier.syncStar:
+ output.write(' sync* ');
+ break;
+ }
+ }
+ if (_isLambdaMethod(spec)) {
+ output.write(' => ');
+ } else {
+ output.write(' { ');
+ }
+ spec.body!.accept(this, output);
+ if (!_isLambdaMethod(spec)) {
+ output.write(' } ');
+ }
+ } else {
+ output.write(';');
+ }
+ return output;
+ }
+
+ // Expose as a first-class visit function only if needed.
+ void _visitParameter(
+ Parameter spec,
+ StringSink output, {
+ bool optional = false,
+ bool named = false,
+ }) {
+ spec.docs.forEach(output.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, output);
+ }
+ // The `required` keyword must precede the `covariant` keyword.
+ if (spec.required) {
+ output.write('required ');
+ }
+ if (spec.covariant) {
+ output.write('covariant ');
+ }
+ if (spec.type != null) {
+ spec.type!.type.accept(this, output);
+ output.write(' ');
+ }
+ if (spec.toThis) {
+ output.write('this.');
+ }
+ if (spec.toSuper) {
+ output.write('super.');
+ }
+ output.write(spec.name);
+ if (optional && spec.defaultTo != null) {
+ output.write(' = ');
+ spec.defaultTo!.accept(this, output);
+ }
+ }
+
+ @override
+ StringSink visitReference(Reference spec, [StringSink? output]) =>
+ (output ??= StringBuffer())..write(allocator.allocate(spec));
+
+ @override
+ StringSink visitSpec(Spec spec, [StringSink? output]) =>
+ spec.accept(this, output);
+
+ @override
+ StringSink visitType(TypeReference spec, [StringSink? output]) {
+ output ??= StringBuffer();
+ // Intentionally not .accept to avoid stack overflow.
+ visitReference(spec, output);
+ if (spec.bound != null) {
+ output.write(' extends ');
+ spec.bound!.type.accept(this, output);
+ }
+ visitTypeParameters(spec.types.map((r) => r.type), output);
+ if (_useNullSafetySyntax && (spec.isNullable ?? false)) {
+ output.write('?');
+ }
+ return output;
+ }
+
+ @override
+ StringSink visitTypeParameters(Iterable<Reference> specs,
+ [StringSink? output]) {
+ output ??= StringBuffer();
+ if (specs.isNotEmpty) {
+ output
+ ..write('<')
+ ..writeAll(specs.map<StringSink>((s) => s.accept(this)), ',')
+ ..write('>');
+ }
+ return output;
+ }
+
+ @override
+ StringSink visitEnum(Enum spec, [StringSink? output]) {
+ final out = output ??= StringBuffer();
+ spec.docs.forEach(out.writeln);
+ for (var a in spec.annotations) {
+ visitAnnotation(a, out);
+ }
+ out.write('enum ${spec.name}');
+ visitTypeParameters(spec.types.map((r) => r.type), out);
+ if (spec.mixins.isNotEmpty) {
+ out
+ ..write(' with ')
+ ..writeAll(
+ spec.mixins.map<StringSink>((m) => m.type.accept(this)), ', ');
+ }
+ if (spec.implements.isNotEmpty) {
+ out
+ ..write(' implements ')
+ ..writeAll(
+ spec.implements.map<StringSink>((m) => m.type.accept(this)), ', ');
+ }
+ out.write(' { ');
+ for (var v in spec.values) {
+ v.docs.forEach(out.writeln);
+ for (var a in v.annotations) {
+ visitAnnotation(a, out);
+ }
+ out.write(v.name);
+ if (v.constructorName != null) {
+ out.write('.${v.constructorName}');
+ }
+ visitTypeParameters(v.types.map((r) => r.type), out);
+ final takesArguments = v.constructorName != null ||
+ v.arguments.isNotEmpty ||
+ v.namedArguments.isNotEmpty;
+ if (takesArguments) {
+ out.write('(');
+ }
+ if (v.arguments.isNotEmpty) {
+ out.writeAll(
+ v.arguments.map<StringSink>((arg) => arg.accept(this)), ', ');
+ }
+ if (v.arguments.isNotEmpty && v.namedArguments.isNotEmpty) {
+ out.write(', ');
+ }
+ visitAll<String>(v.namedArguments.keys, out, (name) {
+ out
+ ..write(name)
+ ..write(': ');
+ v.namedArguments[name]!.accept(this, out);
+ });
+ if (takesArguments) {
+ out.write(')');
+ }
+ if (v != spec.values.last) {
+ out.writeln(',');
+ } else if (spec.constructors.isNotEmpty ||
+ spec.fields.isNotEmpty ||
+ spec.methods.isNotEmpty) {
+ out.writeln(';');
+ }
+ }
+ for (var c in spec.constructors) {
+ visitConstructor(c, spec.name, out);
+ out.writeln();
+ }
+ for (var f in spec.fields) {
+ visitField(f, out);
+ out.writeln();
+ }
+ for (var m in spec.methods) {
+ visitMethod(m, out);
+ if (_isLambdaMethod(m)) {
+ out.write(';');
+ }
+ out.writeln();
+ }
+ out.writeln(' }');
+ return out;
+ }
+}
+
+/// Returns `true` if:
+///
+/// * [ordered] is `true`
+/// * [a] is non-`null`
+/// * If there should be an empty line before [b] if it's emitted after [a].
+bool _newLineBetween(bool ordered, Directive? a, Directive? b) {
+ if (!ordered) return false;
+ if (a == null) return false;
+
+ assert(b != null);
+
+ // Put a line between imports and exports
+ if (a.type != b!.type) return true;
+
+ // Within exports, don't put in extra blank lines
+ if (a.type == DirectiveType.export) {
+ assert(b.type == DirectiveType.export);
+ return false;
+ }
+
+ // Return `true` if the schemes for [a] and [b] are different
+ return !Uri.parse(a.url).isScheme(Uri.parse(b.url).scheme);
+}
diff --git a/pkgs/code_builder/lib/src/matchers.dart b/pkgs/code_builder/lib/src/matchers.dart
new file mode 100644
index 0000000..0cdf739
--- /dev/null
+++ b/pkgs/code_builder/lib/src/matchers.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:matcher/matcher.dart';
+
+import 'base.dart';
+import 'emitter.dart';
+
+/// Encodes [spec] as Dart source code.
+String _dart(Spec spec, DartEmitter emitter) =>
+ EqualsDart._format(spec.accept<StringSink>(emitter).toString());
+
+/// Returns a matcher for [Spec] objects that emit code matching [source].
+///
+/// Both [source] and the result emitted from the compared [Spec] are formatted
+/// with [EqualsDart.format]. A plain [DartEmitter] is used by default and may
+/// be overridden with [emitter].
+Matcher equalsDart(
+ String source, [
+ DartEmitter? emitter,
+]) =>
+ EqualsDart._(EqualsDart._format(source), emitter ?? DartEmitter());
+
+/// Implementation detail of using the [equalsDart] matcher.
+///
+/// See [EqualsDart.format] to specify the default source code formatter.
+class EqualsDart extends Matcher {
+ /// May override to provide a function to format Dart on [equalsDart].
+ ///
+ /// By default, uses [collapseWhitespace], but it is recommended to instead
+ /// use `dart_style` (dartfmt) where possible. See `test/common.dart` for an
+ /// example.
+ static String Function(String) format = collapseWhitespace;
+
+ static String _format(String source) {
+ try {
+ return format(source).trim();
+ } catch (_) {
+ // Ignored on purpose, probably not exactly valid Dart code.
+ return collapseWhitespace(source).trim();
+ }
+ }
+
+ final DartEmitter _emitter;
+ final String _expectedSource;
+
+ const EqualsDart._(this._expectedSource, this._emitter);
+
+ @override
+ Description describe(Description description) =>
+ description.add(_expectedSource);
+
+ @override
+ Description describeMismatch(
+ covariant Spec item,
+ Description mismatchDescription,
+ Map<dynamic, dynamic> matchState,
+ bool verbose,
+ ) {
+ final actualSource = _dart(item, _emitter);
+ return equals(_expectedSource).describeMismatch(
+ actualSource,
+ mismatchDescription,
+ matchState,
+ verbose,
+ );
+ }
+
+ @override
+ bool matches(covariant Spec item, Object? matchState) =>
+ _dart(item, _emitter) == _expectedSource;
+}
diff --git a/pkgs/code_builder/lib/src/mixins/annotations.dart b/pkgs/code_builder/lib/src/mixins/annotations.dart
new file mode 100644
index 0000000..7ce6a20
--- /dev/null
+++ b/pkgs/code_builder/lib/src/mixins/annotations.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+
+import '../specs/expression.dart';
+
+/// A type of AST node that can have metadata [annotations].
+abstract mixin class HasAnnotations {
+ /// Annotations as metadata on the node.
+ BuiltList<Expression> get annotations;
+}
+
+/// Compliment to the [HasAnnotations] mixin for metadata [annotations].
+abstract mixin class HasAnnotationsBuilder {
+ /// Annotations as metadata on the node.
+ abstract ListBuilder<Expression> annotations;
+}
diff --git a/pkgs/code_builder/lib/src/mixins/dartdoc.dart b/pkgs/code_builder/lib/src/mixins/dartdoc.dart
new file mode 100644
index 0000000..78144f6
--- /dev/null
+++ b/pkgs/code_builder/lib/src/mixins/dartdoc.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+
+abstract mixin class HasDartDocs {
+ /// Dart docs.
+ BuiltList<String> get docs;
+}
+
+abstract mixin class HasDartDocsBuilder {
+ /// Dart docs.
+ abstract ListBuilder<String> docs;
+}
diff --git a/pkgs/code_builder/lib/src/mixins/generics.dart b/pkgs/code_builder/lib/src/mixins/generics.dart
new file mode 100644
index 0000000..b18a858
--- /dev/null
+++ b/pkgs/code_builder/lib/src/mixins/generics.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+
+import '../specs/reference.dart';
+
+abstract mixin class HasGenerics {
+ /// Generic type parameters.
+ BuiltList<Reference> get types;
+}
+
+abstract mixin class HasGenericsBuilder {
+ /// Generic type parameters.
+ abstract ListBuilder<Reference> types;
+}
diff --git a/pkgs/code_builder/lib/src/specs/class.dart b/pkgs/code_builder/lib/src/specs/class.dart
new file mode 100644
index 0000000..4c1915e
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/class.dart
@@ -0,0 +1,128 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'constructor.dart';
+import 'expression.dart';
+import 'field.dart';
+import 'method.dart';
+import 'reference.dart';
+
+part 'class.g.dart';
+
+@immutable
+abstract class Class extends Object
+ with HasAnnotations, HasDartDocs, HasGenerics
+ implements Built<Class, ClassBuilder>, Spec {
+ factory Class([void Function(ClassBuilder) updates]) = _$Class;
+
+ Class._();
+
+ /// Whether the class is `abstract`.
+ bool get abstract;
+
+ /// Whether the class is `sealed`.
+ bool get sealed;
+
+ /// Whether the class is a `mixin class`.
+ bool get mixin;
+
+ /// The class modifier, i.e. `base`, `final`, `interface`.
+ ClassModifier? get modifier;
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ Reference? get extend;
+
+ BuiltList<Reference> get implements;
+
+ BuiltList<Reference> get mixins;
+
+ @override
+ BuiltList<Reference> get types;
+
+ BuiltList<Constructor> get constructors;
+ BuiltList<Method> get methods;
+ BuiltList<Field> get fields;
+
+ /// Name of the class.
+ String get name;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitClass(this, context);
+}
+
+enum ClassModifier {
+ base,
+ final$,
+ interface;
+
+ String get name => switch (this) {
+ ClassModifier.base => 'base',
+ ClassModifier.final$ => 'final',
+ ClassModifier.interface => 'interface'
+ };
+}
+
+abstract class ClassBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
+ implements Builder<Class, ClassBuilder> {
+ factory ClassBuilder() = _$ClassBuilder;
+
+ ClassBuilder._();
+
+ @override
+ void update(void Function(ClassBuilder)? updates) {
+ updates?.call(this);
+ }
+
+ /// Whether the class is `abstract`.
+ bool abstract = false;
+
+ /// Whether the class is `sealed`.
+ bool sealed = false;
+
+ /// Whether the class is a `mixin class`.
+ bool mixin = false;
+
+ /// The class modifier, i.e. `base`, `final`, `interface`.
+ ClassModifier? modifier;
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ Reference? extend;
+
+ ListBuilder<Reference> implements = ListBuilder<Reference>();
+ ListBuilder<Reference> mixins = ListBuilder<Reference>();
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ ListBuilder<Constructor> constructors = ListBuilder<Constructor>();
+ ListBuilder<Method> methods = ListBuilder<Method>();
+ ListBuilder<Field> fields = ListBuilder<Field>();
+
+ /// Name of the class.
+ String? name;
+}
diff --git a/pkgs/code_builder/lib/src/specs/class.g.dart b/pkgs/code_builder/lib/src/specs/class.g.dart
new file mode 100644
index 0000000..423f576
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/class.g.dart
@@ -0,0 +1,405 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'class.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Class extends Class {
+ @override
+ final bool abstract;
+ @override
+ final bool sealed;
+ @override
+ final bool mixin;
+ @override
+ final ClassModifier? modifier;
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final Reference? extend;
+ @override
+ final BuiltList<Reference> implements;
+ @override
+ final BuiltList<Reference> mixins;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final BuiltList<Constructor> constructors;
+ @override
+ final BuiltList<Method> methods;
+ @override
+ final BuiltList<Field> fields;
+ @override
+ final String name;
+
+ factory _$Class([void Function(ClassBuilder)? updates]) =>
+ (new ClassBuilder()..update(updates)).build() as _$Class;
+
+ _$Class._(
+ {required this.abstract,
+ required this.sealed,
+ required this.mixin,
+ this.modifier,
+ required this.annotations,
+ required this.docs,
+ this.extend,
+ required this.implements,
+ required this.mixins,
+ required this.types,
+ required this.constructors,
+ required this.methods,
+ required this.fields,
+ required this.name})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(abstract, r'Class', 'abstract');
+ BuiltValueNullFieldError.checkNotNull(sealed, r'Class', 'sealed');
+ BuiltValueNullFieldError.checkNotNull(mixin, r'Class', 'mixin');
+ BuiltValueNullFieldError.checkNotNull(annotations, r'Class', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Class', 'docs');
+ BuiltValueNullFieldError.checkNotNull(implements, r'Class', 'implements');
+ BuiltValueNullFieldError.checkNotNull(mixins, r'Class', 'mixins');
+ BuiltValueNullFieldError.checkNotNull(types, r'Class', 'types');
+ BuiltValueNullFieldError.checkNotNull(
+ constructors, r'Class', 'constructors');
+ BuiltValueNullFieldError.checkNotNull(methods, r'Class', 'methods');
+ BuiltValueNullFieldError.checkNotNull(fields, r'Class', 'fields');
+ BuiltValueNullFieldError.checkNotNull(name, r'Class', 'name');
+ }
+
+ @override
+ Class rebuild(void Function(ClassBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$ClassBuilder toBuilder() => new _$ClassBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Class &&
+ abstract == other.abstract &&
+ sealed == other.sealed &&
+ mixin == other.mixin &&
+ modifier == other.modifier &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ extend == other.extend &&
+ implements == other.implements &&
+ mixins == other.mixins &&
+ types == other.types &&
+ constructors == other.constructors &&
+ methods == other.methods &&
+ fields == other.fields &&
+ name == other.name;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, abstract.hashCode);
+ _$hash = $jc(_$hash, sealed.hashCode);
+ _$hash = $jc(_$hash, mixin.hashCode);
+ _$hash = $jc(_$hash, modifier.hashCode);
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, extend.hashCode);
+ _$hash = $jc(_$hash, implements.hashCode);
+ _$hash = $jc(_$hash, mixins.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, constructors.hashCode);
+ _$hash = $jc(_$hash, methods.hashCode);
+ _$hash = $jc(_$hash, fields.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Class')
+ ..add('abstract', abstract)
+ ..add('sealed', sealed)
+ ..add('mixin', mixin)
+ ..add('modifier', modifier)
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('extend', extend)
+ ..add('implements', implements)
+ ..add('mixins', mixins)
+ ..add('types', types)
+ ..add('constructors', constructors)
+ ..add('methods', methods)
+ ..add('fields', fields)
+ ..add('name', name))
+ .toString();
+ }
+}
+
+class _$ClassBuilder extends ClassBuilder {
+ _$Class? _$v;
+
+ @override
+ bool get abstract {
+ _$this;
+ return super.abstract;
+ }
+
+ @override
+ set abstract(bool abstract) {
+ _$this;
+ super.abstract = abstract;
+ }
+
+ @override
+ bool get sealed {
+ _$this;
+ return super.sealed;
+ }
+
+ @override
+ set sealed(bool sealed) {
+ _$this;
+ super.sealed = sealed;
+ }
+
+ @override
+ bool get mixin {
+ _$this;
+ return super.mixin;
+ }
+
+ @override
+ set mixin(bool mixin) {
+ _$this;
+ super.mixin = mixin;
+ }
+
+ @override
+ ClassModifier? get modifier {
+ _$this;
+ return super.modifier;
+ }
+
+ @override
+ set modifier(ClassModifier? modifier) {
+ _$this;
+ super.modifier = modifier;
+ }
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ Reference? get extend {
+ _$this;
+ return super.extend;
+ }
+
+ @override
+ set extend(Reference? extend) {
+ _$this;
+ super.extend = extend;
+ }
+
+ @override
+ ListBuilder<Reference> get implements {
+ _$this;
+ return super.implements;
+ }
+
+ @override
+ set implements(ListBuilder<Reference> implements) {
+ _$this;
+ super.implements = implements;
+ }
+
+ @override
+ ListBuilder<Reference> get mixins {
+ _$this;
+ return super.mixins;
+ }
+
+ @override
+ set mixins(ListBuilder<Reference> mixins) {
+ _$this;
+ super.mixins = mixins;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ ListBuilder<Constructor> get constructors {
+ _$this;
+ return super.constructors;
+ }
+
+ @override
+ set constructors(ListBuilder<Constructor> constructors) {
+ _$this;
+ super.constructors = constructors;
+ }
+
+ @override
+ ListBuilder<Method> get methods {
+ _$this;
+ return super.methods;
+ }
+
+ @override
+ set methods(ListBuilder<Method> methods) {
+ _$this;
+ super.methods = methods;
+ }
+
+ @override
+ ListBuilder<Field> get fields {
+ _$this;
+ return super.fields;
+ }
+
+ @override
+ set fields(ListBuilder<Field> fields) {
+ _$this;
+ super.fields = fields;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ _$ClassBuilder() : super._();
+
+ ClassBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.abstract = $v.abstract;
+ super.sealed = $v.sealed;
+ super.mixin = $v.mixin;
+ super.modifier = $v.modifier;
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.extend = $v.extend;
+ super.implements = $v.implements.toBuilder();
+ super.mixins = $v.mixins.toBuilder();
+ super.types = $v.types.toBuilder();
+ super.constructors = $v.constructors.toBuilder();
+ super.methods = $v.methods.toBuilder();
+ super.fields = $v.fields.toBuilder();
+ super.name = $v.name;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Class other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Class;
+ }
+
+ @override
+ void update(void Function(ClassBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Class build() => _build();
+
+ _$Class _build() {
+ _$Class _$result;
+ try {
+ _$result = _$v ??
+ new _$Class._(
+ abstract: BuiltValueNullFieldError.checkNotNull(
+ abstract, r'Class', 'abstract'),
+ sealed: BuiltValueNullFieldError.checkNotNull(
+ sealed, r'Class', 'sealed'),
+ mixin: BuiltValueNullFieldError.checkNotNull(
+ mixin, r'Class', 'mixin'),
+ modifier: modifier,
+ annotations: annotations.build(),
+ docs: docs.build(),
+ extend: extend,
+ implements: implements.build(),
+ mixins: mixins.build(),
+ types: types.build(),
+ constructors: constructors.build(),
+ methods: methods.build(),
+ fields: fields.build(),
+ name: BuiltValueNullFieldError.checkNotNull(
+ name, r'Class', 'name'));
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+
+ _$failedField = 'implements';
+ implements.build();
+ _$failedField = 'mixins';
+ mixins.build();
+ _$failedField = 'types';
+ types.build();
+ _$failedField = 'constructors';
+ constructors.build();
+ _$failedField = 'methods';
+ methods.build();
+ _$failedField = 'fields';
+ fields.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Class', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/code.dart b/pkgs/code_builder/lib/src/specs/code.dart
new file mode 100644
index 0000000..521eb1f
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/code.dart
@@ -0,0 +1,165 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../allocator.dart';
+import '../base.dart';
+import '../emitter.dart';
+import '../visitors.dart';
+import 'expression.dart';
+import 'reference.dart';
+
+part 'code.g.dart';
+
+/// Returns a scoped symbol to [Reference], with an import prefix if needed.
+///
+/// This is short-hand for [Allocator.allocate] in most implementations.
+typedef Allocate = String Function(Reference);
+
+/// Represents arbitrary Dart code (either expressions or statements).
+///
+/// See the various constructors for details.
+abstract class Code implements Spec {
+ /// Create a simple code body based on a static string.
+ const factory Code(String code) = StaticCode._;
+
+ /// Create a code based that may use a provided [Allocator] for scoping:
+ ///
+ /// ```dart
+ /// // Emits `_i123.FooType()`, where `_i123` is the import prefix.
+ ///
+ /// Code.scope((a) {
+ /// return '${a.allocate(fooType)}()'
+ /// });
+ /// ```
+ const factory Code.scope(
+ String Function(Allocate) scope,
+ ) = ScopedCode._;
+
+ @override
+ R accept<R>(covariant CodeVisitor<R> visitor, [R? context]);
+}
+
+/// Represents blocks of statements of Dart code.
+abstract class Block implements Built<Block, BlockBuilder>, Code, Spec {
+ factory Block([void Function(BlockBuilder) updates]) = _$Block;
+
+ factory Block.of(Iterable<Code> statements) =>
+ Block((b) => b..statements.addAll(statements));
+
+ Block._();
+
+ @override
+ R accept<R>(covariant CodeVisitor<R> visitor, [R? context]) =>
+ visitor.visitBlock(this, context);
+
+ BuiltList<Code> get statements;
+}
+
+abstract class BlockBuilder implements Builder<Block, BlockBuilder> {
+ factory BlockBuilder() = _$BlockBuilder;
+
+ BlockBuilder._();
+
+ /// Adds an [expression] to [statements].
+ ///
+ /// **NOTE**: Not all expressions are _useful_ statements.
+ void addExpression(Expression expression) {
+ statements.add(expression.statement);
+ }
+
+ ListBuilder<Code> statements = ListBuilder<Code>();
+}
+
+/// Knowledge of different types of blocks of code in Dart.
+///
+/// **INTERNAL ONLY**.
+abstract class CodeVisitor<T> implements SpecVisitor<T> {
+ T visitBlock(Block code, [T? context]);
+
+ T visitStaticCode(StaticCode code, [T? context]);
+
+ T visitScopedCode(ScopedCode code, [T? context]);
+}
+
+/// Knowledge of how to write valid Dart code from [CodeVisitor].
+abstract mixin class CodeEmitter implements CodeVisitor<StringSink> {
+ @protected
+ Allocator get allocator;
+
+ @override
+ StringSink visitBlock(Block block, [StringSink? output]) {
+ output ??= StringBuffer();
+ return visitAll<Code>(block.statements, output, (statement) {
+ statement.accept(this, output);
+ }, '\n');
+ }
+
+ @override
+ StringSink visitStaticCode(StaticCode code, [StringSink? output]) {
+ output ??= StringBuffer();
+ return output..write(code.code);
+ }
+
+ @override
+ StringSink visitScopedCode(ScopedCode code, [StringSink? output]) {
+ output ??= StringBuffer();
+ return output..write(code.code(allocator.allocate));
+ }
+}
+
+/// Represents a code block that requires lazy visiting.
+class LazyCode implements Code {
+ final Spec Function(SpecVisitor) generate;
+
+ const LazyCode._(this.generate);
+
+ @override
+ R accept<R>(CodeVisitor<R> visitor, [R? context]) =>
+ generate(visitor).accept(visitor, context);
+}
+
+/// Returns a generic [Code] that is lazily generated when visited.
+Code lazyCode(Code Function() generate) => _LazyCode(generate);
+
+class _LazyCode implements Code {
+ final Code Function() generate;
+
+ const _LazyCode(this.generate);
+
+ @override
+ R accept<R>(CodeVisitor<R> visitor, [R? context]) =>
+ generate().accept(visitor, context);
+}
+
+/// Represents a simple, literal code block to be inserted as-is.
+class StaticCode implements Code {
+ final String code;
+
+ const StaticCode._(this.code);
+
+ @override
+ R accept<R>(CodeVisitor<R> visitor, [R? context]) =>
+ visitor.visitStaticCode(this, context);
+
+ @override
+ String toString() => code;
+}
+
+/// Represents a code block that may require scoping.
+class ScopedCode implements Code {
+ final String Function(Allocate) code;
+
+ const ScopedCode._(this.code);
+
+ @override
+ R accept<R>(CodeVisitor<R> visitor, [R? context]) =>
+ visitor.visitScopedCode(this, context);
+
+ @override
+ String toString() => code((ref) => ref.symbol!);
+}
diff --git a/pkgs/code_builder/lib/src/specs/code.g.dart b/pkgs/code_builder/lib/src/specs/code.g.dart
new file mode 100644
index 0000000..7b5ba78
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/code.g.dart
@@ -0,0 +1,109 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'code.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Block extends Block {
+ @override
+ final BuiltList<Code> statements;
+
+ factory _$Block([void Function(BlockBuilder)? updates]) =>
+ (new BlockBuilder()..update(updates)).build() as _$Block;
+
+ _$Block._({required this.statements}) : super._() {
+ BuiltValueNullFieldError.checkNotNull(statements, r'Block', 'statements');
+ }
+
+ @override
+ Block rebuild(void Function(BlockBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$BlockBuilder toBuilder() => new _$BlockBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Block && statements == other.statements;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, statements.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Block')
+ ..add('statements', statements))
+ .toString();
+ }
+}
+
+class _$BlockBuilder extends BlockBuilder {
+ _$Block? _$v;
+
+ @override
+ ListBuilder<Code> get statements {
+ _$this;
+ return super.statements;
+ }
+
+ @override
+ set statements(ListBuilder<Code> statements) {
+ _$this;
+ super.statements = statements;
+ }
+
+ _$BlockBuilder() : super._();
+
+ BlockBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.statements = $v.statements.toBuilder();
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Block other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Block;
+ }
+
+ @override
+ void update(void Function(BlockBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Block build() => _build();
+
+ _$Block _build() {
+ _$Block _$result;
+ try {
+ _$result = _$v ?? new _$Block._(statements: statements.build());
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'statements';
+ statements.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Block', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/constructor.dart b/pkgs/code_builder/lib/src/specs/constructor.dart
new file mode 100644
index 0000000..1c98eb5
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/constructor.dart
@@ -0,0 +1,106 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import 'code.dart';
+import 'expression.dart';
+import 'method.dart';
+import 'reference.dart';
+
+part 'constructor.g.dart';
+
+@immutable
+abstract class Constructor extends Object
+ with HasAnnotations, HasDartDocs
+ implements Built<Constructor, ConstructorBuilder> {
+ factory Constructor([void Function(ConstructorBuilder) updates]) =
+ _$Constructor;
+
+ Constructor._();
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ /// Optional parameters.
+ BuiltList<Parameter> get optionalParameters;
+
+ /// Required parameters.
+ BuiltList<Parameter> get requiredParameters;
+
+ /// Constructor initializer statements.
+ BuiltList<Code> get initializers;
+
+ /// Body of the method.
+ Code? get body;
+
+ /// Whether the constructor should be prefixed with `external`.
+ bool get external;
+
+ /// Whether the constructor should be prefixed with `const`.
+ bool get constant;
+
+ /// Whether this constructor should be prefixed with `factory`.
+ bool get factory;
+
+ /// Whether this constructor is a simple lambda expression.
+ bool? get lambda;
+
+ /// Name of the constructor - optional.
+ String? get name;
+
+ /// If non-null, redirect to this constructor.
+ Reference? get redirect;
+}
+
+abstract class ConstructorBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder
+ implements Builder<Constructor, ConstructorBuilder> {
+ factory ConstructorBuilder() = _$ConstructorBuilder;
+
+ ConstructorBuilder._();
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ /// Optional parameters.
+ ListBuilder<Parameter> optionalParameters = ListBuilder<Parameter>();
+
+ /// Required parameters.
+ ListBuilder<Parameter> requiredParameters = ListBuilder<Parameter>();
+
+ /// Constructor initializer statements.
+ ListBuilder<Code> initializers = ListBuilder<Code>();
+
+ /// Body of the constructor.
+ Code? body;
+
+ /// Whether the constructor should be prefixed with `const`.
+ bool constant = false;
+
+ /// Whether the constructor should be prefixed with `external`.
+ bool external = false;
+
+ /// Whether this constructor should be prefixed with `factory`.
+ bool factory = false;
+
+ /// Whether this constructor is a simple lambda expression.
+ bool? lambda;
+
+ /// Name of the constructor - optional.
+ String? name;
+
+ /// If non-null, redirect to this constructor.
+ Reference? redirect;
+}
diff --git a/pkgs/code_builder/lib/src/specs/constructor.g.dart b/pkgs/code_builder/lib/src/specs/constructor.g.dart
new file mode 100644
index 0000000..3f06932
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/constructor.g.dart
@@ -0,0 +1,356 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'constructor.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Constructor extends Constructor {
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final BuiltList<Parameter> optionalParameters;
+ @override
+ final BuiltList<Parameter> requiredParameters;
+ @override
+ final BuiltList<Code> initializers;
+ @override
+ final Code? body;
+ @override
+ final bool external;
+ @override
+ final bool constant;
+ @override
+ final bool factory;
+ @override
+ final bool? lambda;
+ @override
+ final String? name;
+ @override
+ final Reference? redirect;
+
+ factory _$Constructor([void Function(ConstructorBuilder)? updates]) =>
+ (new ConstructorBuilder()..update(updates)).build() as _$Constructor;
+
+ _$Constructor._(
+ {required this.annotations,
+ required this.docs,
+ required this.optionalParameters,
+ required this.requiredParameters,
+ required this.initializers,
+ this.body,
+ required this.external,
+ required this.constant,
+ required this.factory,
+ this.lambda,
+ this.name,
+ this.redirect})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'Constructor', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Constructor', 'docs');
+ BuiltValueNullFieldError.checkNotNull(
+ optionalParameters, r'Constructor', 'optionalParameters');
+ BuiltValueNullFieldError.checkNotNull(
+ requiredParameters, r'Constructor', 'requiredParameters');
+ BuiltValueNullFieldError.checkNotNull(
+ initializers, r'Constructor', 'initializers');
+ BuiltValueNullFieldError.checkNotNull(external, r'Constructor', 'external');
+ BuiltValueNullFieldError.checkNotNull(constant, r'Constructor', 'constant');
+ BuiltValueNullFieldError.checkNotNull(factory, r'Constructor', 'factory');
+ }
+
+ @override
+ Constructor rebuild(void Function(ConstructorBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$ConstructorBuilder toBuilder() => new _$ConstructorBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Constructor &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ optionalParameters == other.optionalParameters &&
+ requiredParameters == other.requiredParameters &&
+ initializers == other.initializers &&
+ body == other.body &&
+ external == other.external &&
+ constant == other.constant &&
+ factory == other.factory &&
+ lambda == other.lambda &&
+ name == other.name &&
+ redirect == other.redirect;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, optionalParameters.hashCode);
+ _$hash = $jc(_$hash, requiredParameters.hashCode);
+ _$hash = $jc(_$hash, initializers.hashCode);
+ _$hash = $jc(_$hash, body.hashCode);
+ _$hash = $jc(_$hash, external.hashCode);
+ _$hash = $jc(_$hash, constant.hashCode);
+ _$hash = $jc(_$hash, factory.hashCode);
+ _$hash = $jc(_$hash, lambda.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jc(_$hash, redirect.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Constructor')
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('optionalParameters', optionalParameters)
+ ..add('requiredParameters', requiredParameters)
+ ..add('initializers', initializers)
+ ..add('body', body)
+ ..add('external', external)
+ ..add('constant', constant)
+ ..add('factory', factory)
+ ..add('lambda', lambda)
+ ..add('name', name)
+ ..add('redirect', redirect))
+ .toString();
+ }
+}
+
+class _$ConstructorBuilder extends ConstructorBuilder {
+ _$Constructor? _$v;
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ ListBuilder<Parameter> get optionalParameters {
+ _$this;
+ return super.optionalParameters;
+ }
+
+ @override
+ set optionalParameters(ListBuilder<Parameter> optionalParameters) {
+ _$this;
+ super.optionalParameters = optionalParameters;
+ }
+
+ @override
+ ListBuilder<Parameter> get requiredParameters {
+ _$this;
+ return super.requiredParameters;
+ }
+
+ @override
+ set requiredParameters(ListBuilder<Parameter> requiredParameters) {
+ _$this;
+ super.requiredParameters = requiredParameters;
+ }
+
+ @override
+ ListBuilder<Code> get initializers {
+ _$this;
+ return super.initializers;
+ }
+
+ @override
+ set initializers(ListBuilder<Code> initializers) {
+ _$this;
+ super.initializers = initializers;
+ }
+
+ @override
+ Code? get body {
+ _$this;
+ return super.body;
+ }
+
+ @override
+ set body(Code? body) {
+ _$this;
+ super.body = body;
+ }
+
+ @override
+ bool get external {
+ _$this;
+ return super.external;
+ }
+
+ @override
+ set external(bool external) {
+ _$this;
+ super.external = external;
+ }
+
+ @override
+ bool get constant {
+ _$this;
+ return super.constant;
+ }
+
+ @override
+ set constant(bool constant) {
+ _$this;
+ super.constant = constant;
+ }
+
+ @override
+ bool get factory {
+ _$this;
+ return super.factory;
+ }
+
+ @override
+ set factory(bool factory) {
+ _$this;
+ super.factory = factory;
+ }
+
+ @override
+ bool? get lambda {
+ _$this;
+ return super.lambda;
+ }
+
+ @override
+ set lambda(bool? lambda) {
+ _$this;
+ super.lambda = lambda;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ @override
+ Reference? get redirect {
+ _$this;
+ return super.redirect;
+ }
+
+ @override
+ set redirect(Reference? redirect) {
+ _$this;
+ super.redirect = redirect;
+ }
+
+ _$ConstructorBuilder() : super._();
+
+ ConstructorBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.optionalParameters = $v.optionalParameters.toBuilder();
+ super.requiredParameters = $v.requiredParameters.toBuilder();
+ super.initializers = $v.initializers.toBuilder();
+ super.body = $v.body;
+ super.external = $v.external;
+ super.constant = $v.constant;
+ super.factory = $v.factory;
+ super.lambda = $v.lambda;
+ super.name = $v.name;
+ super.redirect = $v.redirect;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Constructor other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Constructor;
+ }
+
+ @override
+ void update(void Function(ConstructorBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Constructor build() => _build();
+
+ _$Constructor _build() {
+ _$Constructor _$result;
+ try {
+ _$result = _$v ??
+ new _$Constructor._(
+ annotations: annotations.build(),
+ docs: docs.build(),
+ optionalParameters: optionalParameters.build(),
+ requiredParameters: requiredParameters.build(),
+ initializers: initializers.build(),
+ body: body,
+ external: BuiltValueNullFieldError.checkNotNull(
+ external, r'Constructor', 'external'),
+ constant: BuiltValueNullFieldError.checkNotNull(
+ constant, r'Constructor', 'constant'),
+ factory: BuiltValueNullFieldError.checkNotNull(
+ factory, r'Constructor', 'factory'),
+ lambda: lambda,
+ name: name,
+ redirect: redirect);
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+ _$failedField = 'optionalParameters';
+ optionalParameters.build();
+ _$failedField = 'requiredParameters';
+ requiredParameters.build();
+ _$failedField = 'initializers';
+ initializers.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Constructor', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/directive.dart b/pkgs/code_builder/lib/src/specs/directive.dart
new file mode 100644
index 0000000..e10c0ea
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/directive.dart
@@ -0,0 +1,158 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_value/built_value.dart';
+import 'package:collection/collection.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../visitors.dart';
+
+part 'directive.g.dart';
+
+@immutable
+abstract class Directive
+ implements Built<Directive, DirectiveBuilder>, Spec, Comparable<Directive> {
+ factory Directive([void Function(DirectiveBuilder) updates]) = _$Directive;
+
+ factory Directive.import(
+ String url, {
+ String? as,
+ List<String> show = const [],
+ List<String> hide = const [],
+ }) =>
+ Directive((builder) => builder
+ ..as = as
+ ..type = DirectiveType.import
+ ..url = url
+ ..show.addAll(show)
+ ..hide.addAll(hide));
+
+ factory Directive.importDeferredAs(
+ String url,
+ String as, {
+ List<String> show = const [],
+ List<String> hide = const [],
+ }) =>
+ Directive((builder) => builder
+ ..as = as
+ ..type = DirectiveType.import
+ ..url = url
+ ..deferred = true
+ ..show.addAll(show)
+ ..hide.addAll(hide));
+
+ factory Directive.export(
+ String url, {
+ List<String> show = const [],
+ List<String> hide = const [],
+ }) =>
+ Directive((builder) => builder
+ ..type = DirectiveType.export
+ ..url = url
+ ..show.addAll(show)
+ ..hide.addAll(hide));
+
+ factory Directive.part(String url) => Directive((builder) => builder
+ ..type = DirectiveType.part
+ ..url = url);
+
+ factory Directive.partOf(String url) => Directive((builder) => builder
+ ..type = DirectiveType.partOf
+ ..url = url);
+
+ Directive._();
+
+ String? get as;
+
+ String get url;
+
+ DirectiveType get type;
+
+ List<String> get show;
+
+ List<String> get hide;
+
+ bool get deferred;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitDirective(this, context);
+
+ @override
+ int compareTo(Directive other) => _compareDirectives(this, other);
+}
+
+abstract class DirectiveBuilder
+ implements Builder<Directive, DirectiveBuilder> {
+ factory DirectiveBuilder() = _$DirectiveBuilder;
+
+ DirectiveBuilder._();
+
+ bool deferred = false;
+
+ String? as;
+
+ String? url;
+
+ List<String> show = <String>[];
+
+ List<String> hide = <String>[];
+
+ DirectiveType? type;
+}
+
+enum DirectiveType {
+ import,
+ export,
+ part,
+ partOf,
+}
+
+/// Sort import URIs represented by [a] and [b] to honor the
+/// "Effective Dart" ordering rules which are enforced by the
+/// `directives_ordering` lint.
+///
+/// 1. `import`s before `export`s
+/// 2. `dart:`
+/// 3. `package:`
+/// 4. relative
+/// 5. `part`s
+int _compareDirectives(Directive a, Directive b) {
+ // NOTE: using the fact that `import` is before `export` in the
+ // `DirectiveType` enum – which allows us to compare using `indexOf`.
+ var value = DirectiveType.values
+ .indexOf(a.type)
+ .compareTo(DirectiveType.values.indexOf(b.type));
+
+ if (value == 0) {
+ final uriA = Uri.parse(a.url);
+ final uriB = Uri.parse(b.url);
+
+ if (uriA.hasScheme) {
+ if (uriB.hasScheme) {
+ // If both import URIs have schemes, compare them based on scheme
+ // `dart` will sort before `package` which is what we want
+ // schemes are case-insensitive, so compare accordingly
+ value = compareAsciiLowerCase(uriA.scheme, uriB.scheme);
+ } else {
+ value = -1;
+ }
+ } else if (uriB.hasScheme) {
+ value = 1;
+ }
+
+ // If both schemes are the same, compare based on path
+ if (value == 0) {
+ value = compareAsciiLowerCase(uriA.path, uriB.path);
+ }
+
+ assert((value == 0) == (a.url == b.url));
+ }
+
+ return value;
+}
diff --git a/pkgs/code_builder/lib/src/specs/directive.g.dart b/pkgs/code_builder/lib/src/specs/directive.g.dart
new file mode 100644
index 0000000..b28158e
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/directive.g.dart
@@ -0,0 +1,210 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'directive.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Directive extends Directive {
+ @override
+ final String? as;
+ @override
+ final String url;
+ @override
+ final DirectiveType type;
+ @override
+ final List<String> show;
+ @override
+ final List<String> hide;
+ @override
+ final bool deferred;
+
+ factory _$Directive([void Function(DirectiveBuilder)? updates]) =>
+ (new DirectiveBuilder()..update(updates)).build() as _$Directive;
+
+ _$Directive._(
+ {this.as,
+ required this.url,
+ required this.type,
+ required this.show,
+ required this.hide,
+ required this.deferred})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(url, r'Directive', 'url');
+ BuiltValueNullFieldError.checkNotNull(type, r'Directive', 'type');
+ BuiltValueNullFieldError.checkNotNull(show, r'Directive', 'show');
+ BuiltValueNullFieldError.checkNotNull(hide, r'Directive', 'hide');
+ BuiltValueNullFieldError.checkNotNull(deferred, r'Directive', 'deferred');
+ }
+
+ @override
+ Directive rebuild(void Function(DirectiveBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$DirectiveBuilder toBuilder() => new _$DirectiveBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Directive &&
+ as == other.as &&
+ url == other.url &&
+ type == other.type &&
+ show == other.show &&
+ hide == other.hide &&
+ deferred == other.deferred;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, as.hashCode);
+ _$hash = $jc(_$hash, url.hashCode);
+ _$hash = $jc(_$hash, type.hashCode);
+ _$hash = $jc(_$hash, show.hashCode);
+ _$hash = $jc(_$hash, hide.hashCode);
+ _$hash = $jc(_$hash, deferred.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Directive')
+ ..add('as', as)
+ ..add('url', url)
+ ..add('type', type)
+ ..add('show', show)
+ ..add('hide', hide)
+ ..add('deferred', deferred))
+ .toString();
+ }
+}
+
+class _$DirectiveBuilder extends DirectiveBuilder {
+ _$Directive? _$v;
+
+ @override
+ String? get as {
+ _$this;
+ return super.as;
+ }
+
+ @override
+ set as(String? as) {
+ _$this;
+ super.as = as;
+ }
+
+ @override
+ String? get url {
+ _$this;
+ return super.url;
+ }
+
+ @override
+ set url(String? url) {
+ _$this;
+ super.url = url;
+ }
+
+ @override
+ DirectiveType? get type {
+ _$this;
+ return super.type;
+ }
+
+ @override
+ set type(DirectiveType? type) {
+ _$this;
+ super.type = type;
+ }
+
+ @override
+ List<String> get show {
+ _$this;
+ return super.show;
+ }
+
+ @override
+ set show(List<String> show) {
+ _$this;
+ super.show = show;
+ }
+
+ @override
+ List<String> get hide {
+ _$this;
+ return super.hide;
+ }
+
+ @override
+ set hide(List<String> hide) {
+ _$this;
+ super.hide = hide;
+ }
+
+ @override
+ bool get deferred {
+ _$this;
+ return super.deferred;
+ }
+
+ @override
+ set deferred(bool deferred) {
+ _$this;
+ super.deferred = deferred;
+ }
+
+ _$DirectiveBuilder() : super._();
+
+ DirectiveBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.as = $v.as;
+ super.url = $v.url;
+ super.type = $v.type;
+ super.show = $v.show;
+ super.hide = $v.hide;
+ super.deferred = $v.deferred;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Directive other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Directive;
+ }
+
+ @override
+ void update(void Function(DirectiveBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Directive build() => _build();
+
+ _$Directive _build() {
+ final _$result = _$v ??
+ new _$Directive._(
+ as: as,
+ url:
+ BuiltValueNullFieldError.checkNotNull(url, r'Directive', 'url'),
+ type: BuiltValueNullFieldError.checkNotNull(
+ type, r'Directive', 'type'),
+ show: BuiltValueNullFieldError.checkNotNull(
+ show, r'Directive', 'show'),
+ hide: BuiltValueNullFieldError.checkNotNull(
+ hide, r'Directive', 'hide'),
+ deferred: BuiltValueNullFieldError.checkNotNull(
+ deferred, r'Directive', 'deferred'));
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/enum.dart b/pkgs/code_builder/lib/src/specs/enum.dart
new file mode 100644
index 0000000..c58f92c
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/enum.dart
@@ -0,0 +1,139 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../../code_builder.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+
+part 'enum.g.dart';
+
+@immutable
+abstract class Enum extends Object
+ with HasAnnotations, HasDartDocs, HasGenerics
+ implements Built<Enum, EnumBuilder>, Spec {
+ factory Enum([void Function(EnumBuilder) updates]) = _$Enum;
+
+ Enum._();
+
+ String get name;
+
+ BuiltList<EnumValue> get values;
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ BuiltList<Reference> get implements;
+
+ BuiltList<Reference> get mixins;
+
+ @override
+ BuiltList<Reference> get types;
+
+ BuiltList<Constructor> get constructors;
+ BuiltList<Method> get methods;
+ BuiltList<Field> get fields;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitEnum(this, context);
+}
+
+abstract class EnumBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
+ implements Builder<Enum, EnumBuilder> {
+ factory EnumBuilder() = _$EnumBuilder;
+
+ EnumBuilder._();
+
+ String? name;
+
+ ListBuilder<EnumValue> values = ListBuilder<EnumValue>();
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ ListBuilder<Reference> implements = ListBuilder<Reference>();
+ ListBuilder<Reference> mixins = ListBuilder<Reference>();
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ ListBuilder<Constructor> constructors = ListBuilder<Constructor>();
+ ListBuilder<Method> methods = ListBuilder<Method>();
+ ListBuilder<Field> fields = ListBuilder<Field>();
+}
+
+@immutable
+abstract class EnumValue extends Object
+ with HasAnnotations, HasDartDocs, HasGenerics
+ implements Built<EnumValue, EnumValueBuilder> {
+ factory EnumValue([void Function(EnumValueBuilder) updates]) = _$EnumValue;
+
+ EnumValue._();
+
+ String get name;
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ /// The name of the constructor to target.
+ ///
+ /// If `null` uses the unnamed constructor.
+ String? get constructorName;
+
+ @override
+ BuiltList<Reference> get types;
+
+ /// Arguments to the constructor.
+ BuiltList<Expression> get arguments;
+
+ /// Named arguments to the constructor.
+ BuiltMap<String, Expression> get namedArguments;
+}
+
+abstract class EnumValueBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
+ implements Builder<EnumValue, EnumValueBuilder> {
+ factory EnumValueBuilder() = _$EnumValueBuilder;
+
+ EnumValueBuilder._();
+
+ String? name;
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ /// The name of the constructor to target.
+ String? constructorName;
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ /// Arguments to the constructor.
+ ListBuilder<Expression> arguments = ListBuilder();
+
+ /// Named arguments to the constructor.
+ MapBuilder<String, Expression> namedArguments = MapBuilder();
+}
diff --git a/pkgs/code_builder/lib/src/specs/enum.g.dart b/pkgs/code_builder/lib/src/specs/enum.g.dart
new file mode 100644
index 0000000..651cc61
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/enum.g.dart
@@ -0,0 +1,563 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'enum.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Enum extends Enum {
+ @override
+ final String name;
+ @override
+ final BuiltList<EnumValue> values;
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final BuiltList<Reference> implements;
+ @override
+ final BuiltList<Reference> mixins;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final BuiltList<Constructor> constructors;
+ @override
+ final BuiltList<Method> methods;
+ @override
+ final BuiltList<Field> fields;
+
+ factory _$Enum([void Function(EnumBuilder)? updates]) =>
+ (new EnumBuilder()..update(updates)).build() as _$Enum;
+
+ _$Enum._(
+ {required this.name,
+ required this.values,
+ required this.annotations,
+ required this.docs,
+ required this.implements,
+ required this.mixins,
+ required this.types,
+ required this.constructors,
+ required this.methods,
+ required this.fields})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(name, r'Enum', 'name');
+ BuiltValueNullFieldError.checkNotNull(values, r'Enum', 'values');
+ BuiltValueNullFieldError.checkNotNull(annotations, r'Enum', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Enum', 'docs');
+ BuiltValueNullFieldError.checkNotNull(implements, r'Enum', 'implements');
+ BuiltValueNullFieldError.checkNotNull(mixins, r'Enum', 'mixins');
+ BuiltValueNullFieldError.checkNotNull(types, r'Enum', 'types');
+ BuiltValueNullFieldError.checkNotNull(
+ constructors, r'Enum', 'constructors');
+ BuiltValueNullFieldError.checkNotNull(methods, r'Enum', 'methods');
+ BuiltValueNullFieldError.checkNotNull(fields, r'Enum', 'fields');
+ }
+
+ @override
+ Enum rebuild(void Function(EnumBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$EnumBuilder toBuilder() => new _$EnumBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Enum &&
+ name == other.name &&
+ values == other.values &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ implements == other.implements &&
+ mixins == other.mixins &&
+ types == other.types &&
+ constructors == other.constructors &&
+ methods == other.methods &&
+ fields == other.fields;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jc(_$hash, values.hashCode);
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, implements.hashCode);
+ _$hash = $jc(_$hash, mixins.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, constructors.hashCode);
+ _$hash = $jc(_$hash, methods.hashCode);
+ _$hash = $jc(_$hash, fields.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Enum')
+ ..add('name', name)
+ ..add('values', values)
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('implements', implements)
+ ..add('mixins', mixins)
+ ..add('types', types)
+ ..add('constructors', constructors)
+ ..add('methods', methods)
+ ..add('fields', fields))
+ .toString();
+ }
+}
+
+class _$EnumBuilder extends EnumBuilder {
+ _$Enum? _$v;
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ @override
+ ListBuilder<EnumValue> get values {
+ _$this;
+ return super.values;
+ }
+
+ @override
+ set values(ListBuilder<EnumValue> values) {
+ _$this;
+ super.values = values;
+ }
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ ListBuilder<Reference> get implements {
+ _$this;
+ return super.implements;
+ }
+
+ @override
+ set implements(ListBuilder<Reference> implements) {
+ _$this;
+ super.implements = implements;
+ }
+
+ @override
+ ListBuilder<Reference> get mixins {
+ _$this;
+ return super.mixins;
+ }
+
+ @override
+ set mixins(ListBuilder<Reference> mixins) {
+ _$this;
+ super.mixins = mixins;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ ListBuilder<Constructor> get constructors {
+ _$this;
+ return super.constructors;
+ }
+
+ @override
+ set constructors(ListBuilder<Constructor> constructors) {
+ _$this;
+ super.constructors = constructors;
+ }
+
+ @override
+ ListBuilder<Method> get methods {
+ _$this;
+ return super.methods;
+ }
+
+ @override
+ set methods(ListBuilder<Method> methods) {
+ _$this;
+ super.methods = methods;
+ }
+
+ @override
+ ListBuilder<Field> get fields {
+ _$this;
+ return super.fields;
+ }
+
+ @override
+ set fields(ListBuilder<Field> fields) {
+ _$this;
+ super.fields = fields;
+ }
+
+ _$EnumBuilder() : super._();
+
+ EnumBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.name = $v.name;
+ super.values = $v.values.toBuilder();
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.implements = $v.implements.toBuilder();
+ super.mixins = $v.mixins.toBuilder();
+ super.types = $v.types.toBuilder();
+ super.constructors = $v.constructors.toBuilder();
+ super.methods = $v.methods.toBuilder();
+ super.fields = $v.fields.toBuilder();
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Enum other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Enum;
+ }
+
+ @override
+ void update(void Function(EnumBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Enum build() => _build();
+
+ _$Enum _build() {
+ _$Enum _$result;
+ try {
+ _$result = _$v ??
+ new _$Enum._(
+ name:
+ BuiltValueNullFieldError.checkNotNull(name, r'Enum', 'name'),
+ values: values.build(),
+ annotations: annotations.build(),
+ docs: docs.build(),
+ implements: implements.build(),
+ mixins: mixins.build(),
+ types: types.build(),
+ constructors: constructors.build(),
+ methods: methods.build(),
+ fields: fields.build());
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'values';
+ values.build();
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+ _$failedField = 'implements';
+ implements.build();
+ _$failedField = 'mixins';
+ mixins.build();
+ _$failedField = 'types';
+ types.build();
+ _$failedField = 'constructors';
+ constructors.build();
+ _$failedField = 'methods';
+ methods.build();
+ _$failedField = 'fields';
+ fields.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Enum', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+class _$EnumValue extends EnumValue {
+ @override
+ final String name;
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final String? constructorName;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final BuiltList<Expression> arguments;
+ @override
+ final BuiltMap<String, Expression> namedArguments;
+
+ factory _$EnumValue([void Function(EnumValueBuilder)? updates]) =>
+ (new EnumValueBuilder()..update(updates)).build() as _$EnumValue;
+
+ _$EnumValue._(
+ {required this.name,
+ required this.annotations,
+ required this.docs,
+ this.constructorName,
+ required this.types,
+ required this.arguments,
+ required this.namedArguments})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(name, r'EnumValue', 'name');
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'EnumValue', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'EnumValue', 'docs');
+ BuiltValueNullFieldError.checkNotNull(types, r'EnumValue', 'types');
+ BuiltValueNullFieldError.checkNotNull(arguments, r'EnumValue', 'arguments');
+ BuiltValueNullFieldError.checkNotNull(
+ namedArguments, r'EnumValue', 'namedArguments');
+ }
+
+ @override
+ EnumValue rebuild(void Function(EnumValueBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$EnumValueBuilder toBuilder() => new _$EnumValueBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is EnumValue &&
+ name == other.name &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ constructorName == other.constructorName &&
+ types == other.types &&
+ arguments == other.arguments &&
+ namedArguments == other.namedArguments;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, constructorName.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, arguments.hashCode);
+ _$hash = $jc(_$hash, namedArguments.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'EnumValue')
+ ..add('name', name)
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('constructorName', constructorName)
+ ..add('types', types)
+ ..add('arguments', arguments)
+ ..add('namedArguments', namedArguments))
+ .toString();
+ }
+}
+
+class _$EnumValueBuilder extends EnumValueBuilder {
+ _$EnumValue? _$v;
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ String? get constructorName {
+ _$this;
+ return super.constructorName;
+ }
+
+ @override
+ set constructorName(String? constructorName) {
+ _$this;
+ super.constructorName = constructorName;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ ListBuilder<Expression> get arguments {
+ _$this;
+ return super.arguments;
+ }
+
+ @override
+ set arguments(ListBuilder<Expression> arguments) {
+ _$this;
+ super.arguments = arguments;
+ }
+
+ @override
+ MapBuilder<String, Expression> get namedArguments {
+ _$this;
+ return super.namedArguments;
+ }
+
+ @override
+ set namedArguments(MapBuilder<String, Expression> namedArguments) {
+ _$this;
+ super.namedArguments = namedArguments;
+ }
+
+ _$EnumValueBuilder() : super._();
+
+ EnumValueBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.name = $v.name;
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.constructorName = $v.constructorName;
+ super.types = $v.types.toBuilder();
+ super.arguments = $v.arguments.toBuilder();
+ super.namedArguments = $v.namedArguments.toBuilder();
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(EnumValue other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$EnumValue;
+ }
+
+ @override
+ void update(void Function(EnumValueBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ EnumValue build() => _build();
+
+ _$EnumValue _build() {
+ _$EnumValue _$result;
+ try {
+ _$result = _$v ??
+ new _$EnumValue._(
+ name: BuiltValueNullFieldError.checkNotNull(
+ name, r'EnumValue', 'name'),
+ annotations: annotations.build(),
+ docs: docs.build(),
+ constructorName: constructorName,
+ types: types.build(),
+ arguments: arguments.build(),
+ namedArguments: namedArguments.build());
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+
+ _$failedField = 'types';
+ types.build();
+ _$failedField = 'arguments';
+ arguments.build();
+ _$failedField = 'namedArguments';
+ namedArguments.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'EnumValue', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/expression.dart b/pkgs/code_builder/lib/src/specs/expression.dart
new file mode 100644
index 0000000..b9193e6
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/expression.dart
@@ -0,0 +1,793 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../emitter.dart';
+import '../visitors.dart';
+import 'code.dart';
+import 'method.dart';
+import 'reference.dart';
+import 'type_function.dart';
+
+part 'expression/binary.dart';
+part 'expression/closure.dart';
+part 'expression/code.dart';
+part 'expression/invoke.dart';
+part 'expression/literal.dart';
+part 'expression/parenthesized.dart';
+
+/// Represents a [code] block that wraps an [Expression].
+
+/// Represents a Dart expression.
+///
+/// See various concrete implementations for details.
+abstract class Expression implements Spec {
+ const Expression();
+
+ /// An empty expression.
+ static const _empty = CodeExpression(Code(''));
+
+ /// Whether this expression implies a const context for sub expressions.
+ ///
+ /// Collection literals that are const imply const for all values.
+ /// Assignment to a const variable implies a const value.
+ /// Invoking a const constructor implies const for all arguments.
+ ///
+ /// The implied const context is used to omit redundant `const` keywords.
+ /// A value of `false` does not imply that the expression cannot be used in a
+ /// const context.
+ bool get isConst => false;
+
+ @override
+ R accept<R>(covariant ExpressionVisitor<R> visitor, [R? context]);
+
+ /// The expression as a valid [Code] block.
+ ///
+ /// Also see [statement].
+ Code get code => ToCodeExpression(this);
+
+ /// The expression as a valid [Code] block with a trailing `;`.
+ Code get statement => ToCodeExpression(this, true);
+
+ /// Returns the result of `this` `&&` [other].
+ Expression and(Expression other) =>
+ BinaryExpression._(expression, other, '&&');
+
+ /// Returns the result of `this` `||` [other].
+ Expression or(Expression other) =>
+ BinaryExpression._(expression, other, '||');
+
+ /// Returns the result of `!this`.
+ Expression negate() =>
+ BinaryExpression._(_empty, expression, '!', addSpace: false);
+
+ /// Returns the result of `this` `as` [other].
+ Expression asA(Expression other) =>
+ ParenthesizedExpression._(BinaryExpression._(
+ expression,
+ other,
+ 'as',
+ ));
+
+ /// Returns accessing the index operator (`[]`) on `this`.
+ Expression index(Expression index) => BinaryExpression._(
+ expression,
+ CodeExpression(Block.of([
+ const Code('['),
+ index.code,
+ const Code(']'),
+ ])),
+ '',
+ );
+
+ /// Returns the result of `this` `is` [other].
+ Expression isA(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ 'is',
+ );
+
+ /// Returns the result of `this` `is!` [other].
+ Expression isNotA(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ 'is!',
+ );
+
+ /// Returns the result of `this` `==` [other].
+ Expression equalTo(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '==',
+ );
+
+ /// Returns the result of `this` `!=` [other].
+ Expression notEqualTo(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '!=',
+ );
+
+ /// Returns the result of `this` `>` [other].
+ Expression greaterThan(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '>',
+ );
+
+ /// Returns the result of `this` `<` [other].
+ Expression lessThan(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '<',
+ );
+
+ /// Returns the result of `this` `>=` [other].
+ Expression greaterOrEqualTo(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '>=',
+ );
+
+ /// Returns the result of `this` `<=` [other].
+ Expression lessOrEqualTo(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '<=',
+ );
+
+ /// Returns the result of `this` `+` [other].
+ Expression operatorAdd(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '+',
+ );
+
+ /// Returns the result of `this` `-` [other].
+ Expression operatorSubtract(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '-',
+ );
+
+ @Deprecated('Use `operatorSubtract` instead')
+ Expression operatorSubstract(Expression other) => operatorSubtract(other);
+
+ /// Returns the result of `this` `/` [other].
+ Expression operatorDivide(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '/',
+ );
+
+ /// Returns the result of `this` `*` [other].
+ Expression operatorMultiply(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '*',
+ );
+
+ /// Returns the result of `this` `%` [other].
+ Expression operatorEuclideanModulo(Expression other) => BinaryExpression._(
+ expression,
+ other,
+ '%',
+ );
+
+ /// Returns the result of `this` `~/` [other].
+ Expression operatorIntDivide(Expression other) =>
+ BinaryExpression._(expression, other, '~/');
+
+ Expression conditional(Expression whenTrue, Expression whenFalse) =>
+ BinaryExpression._(
+ expression,
+ BinaryExpression._(whenTrue, whenFalse, ':'),
+ '?',
+ );
+
+ /// This expression preceded by `await`.
+ Expression get awaited => BinaryExpression._(
+ _empty,
+ this,
+ 'await',
+ );
+
+ /// Returns the result of `++this`.
+ Expression operatorUnaryPrefixIncrement() =>
+ BinaryExpression._(_empty, expression, '++', addSpace: false);
+
+ /// Return the result of `this++`.
+ Expression operatorUnaryPostfixIncrement() =>
+ BinaryExpression._(expression, _empty, '++', addSpace: false);
+
+ /// Returns the result of `-this`.
+ Expression operatorUnaryMinus() =>
+ BinaryExpression._(_empty, expression, '-', addSpace: false);
+
+ /// Returns the result of `--this`.
+ Expression operatorUnaryPrefixDecrement() =>
+ BinaryExpression._(_empty, expression, '--', addSpace: false);
+
+ /// Return the result of `this--`.
+ Expression operatorUnaryPostfixDecrement() =>
+ BinaryExpression._(expression, _empty, '--', addSpace: false);
+
+ /// Returns the result of `this` `&` [other].
+ Expression operatorBitwiseAnd(Expression other) =>
+ BinaryExpression._(expression, other, '&');
+
+ /// Returns the result of `this` `|` [other].
+ Expression operatorBitwiseOr(Expression other) =>
+ BinaryExpression._(expression, other, '|');
+
+ /// Returns the result of `this` `^` [other].
+ Expression operatorBitwiseXor(Expression other) =>
+ BinaryExpression._(expression, other, '^');
+
+ /// Returns the result of `~this`.
+ Expression operatorUnaryBitwiseComplement() =>
+ BinaryExpression._(_empty, expression, '~', addSpace: false);
+
+ /// Returns the result of `this` `<<` [other].
+ Expression operatorShiftLeft(Expression other) =>
+ BinaryExpression._(expression, other, '<<');
+
+ /// Returns the result of `this` `>>` [other].
+ Expression operatorShiftRight(Expression other) =>
+ BinaryExpression._(expression, other, '>>');
+
+ /// Returns the result of `this` `>>>` [other].
+ Expression operatorShiftRightUnsigned(Expression other) =>
+ BinaryExpression._(expression, other, '>>>');
+
+ /// Return `{this} = {other}`.
+ Expression assign(Expression other) =>
+ BinaryExpression._(this, other, '=', isConst: isConst);
+
+ /// Return `this` += [other].
+ Expression addAssign(Expression other) =>
+ BinaryExpression._(this, other, '+=');
+
+ /// Return `this` -= [other].
+ Expression subtractAssign(Expression other) =>
+ BinaryExpression._(this, other, '-=');
+
+ /// Return `this` *= [other].
+ Expression multiplyAssign(Expression other) =>
+ BinaryExpression._(this, other, '*=');
+
+ /// Return `this` /= [other].
+ Expression divideAssign(Expression other) =>
+ BinaryExpression._(this, other, '/=');
+
+ /// Return `this` ~/= [other].
+ Expression intDivideAssign(Expression other) =>
+ BinaryExpression._(this, other, '~/=');
+
+ /// Return `this` %= [other].
+ Expression euclideanModuloAssign(Expression other) =>
+ BinaryExpression._(this, other, '%=');
+
+ /// Return `this` <<= [other].
+ Expression shiftLeftAssign(Expression other) =>
+ BinaryExpression._(this, other, '<<=');
+
+ /// Return `this` >>= [other].
+ Expression shiftRightAssign(Expression other) =>
+ BinaryExpression._(this, other, '>>=');
+
+ /// Return `this` >>>= [other].
+ Expression shiftRightUnsignedAssign(Expression other) =>
+ BinaryExpression._(this, other, '>>>=');
+
+ /// Return `this` &= [other].
+ Expression bitwiseAndAssign(Expression other) =>
+ BinaryExpression._(this, other, '&=');
+
+ /// Return `this` ^= [other].
+ Expression bitwiseXorAssign(Expression other) =>
+ BinaryExpression._(this, other, '^=');
+
+ /// Return `this` |= [other].
+ Expression bitwiseOrAssign(Expression other) =>
+ BinaryExpression._(this, other, '|=');
+
+ /// Return `{this} ?? {other}`.
+ Expression ifNullThen(Expression other) => BinaryExpression._(
+ this,
+ other,
+ '??',
+ );
+
+ /// Return `{this} ??= {other}`.
+ Expression assignNullAware(Expression other) => BinaryExpression._(
+ this,
+ other,
+ '??=',
+ );
+
+ /// Return `var {name} = {this}`.
+ @Deprecated('Use `declareVar(name).assign(expression)`')
+ Expression assignVar(String name, [Reference? type]) => BinaryExpression._(
+ type == null
+ ? LiteralExpression._('var $name')
+ : BinaryExpression._(
+ type.expression,
+ LiteralExpression._(name),
+ '',
+ ),
+ this,
+ '=',
+ );
+
+ /// Return `final {name} = {this}`.
+ @Deprecated('Use `declareFinal(name).assign(expression)`')
+ Expression assignFinal(String name, [Reference? type]) => BinaryExpression._(
+ type == null
+ ? const LiteralExpression._('final')
+ : BinaryExpression._(
+ const LiteralExpression._('final'),
+ type.expression,
+ '',
+ ),
+ this,
+ '$name =',
+ );
+
+ /// Return `const {name} = {this}`.
+ @Deprecated('Use `declareConst(name).assign(expression)`')
+ Expression assignConst(String name, [Reference? type]) => BinaryExpression._(
+ type == null
+ ? const LiteralExpression._('const')
+ : BinaryExpression._(
+ const LiteralExpression._('const'),
+ type.expression,
+ '',
+ ),
+ this,
+ '$name =',
+ isConst: true,
+ );
+
+ /// Call this expression as a method.
+ Expression call(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression._(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ );
+
+ /// Returns an expression accessing `.<name>` on this expression.
+ Expression property(String name) => BinaryExpression._(
+ this,
+ LiteralExpression._(name),
+ '.',
+ addSpace: false,
+ );
+
+ /// Returns an expression accessing `..<name>` on this expression.
+ Expression cascade(String name) => BinaryExpression._(
+ this,
+ LiteralExpression._(name),
+ '..',
+ addSpace: false,
+ );
+
+ /// Returns an expression accessing `?.<name>` on this expression.
+ Expression nullSafeProperty(String name) => BinaryExpression._(
+ this,
+ LiteralExpression._(name),
+ '?.',
+ addSpace: false,
+ );
+
+ /// Applies the null check operator on this expression, returning `this` `!`.
+ ///
+ /// Please note that this is only valid when emitting code with the null
+ /// safety syntax enabled.
+ Expression get nullChecked => BinaryExpression._(
+ this,
+ const LiteralExpression._('!'),
+ '',
+ addSpace: false,
+ );
+
+ /// This expression preceded by `return`.
+ Expression get returned => BinaryExpression._(
+ const LiteralExpression._('return'),
+ this,
+ '',
+ );
+
+ /// This expression preceded by the spread operator `...`.
+ Expression get spread => BinaryExpression._(
+ const LiteralExpression._('...'),
+ this,
+ '',
+ addSpace: false,
+ );
+
+ /// This expression preceded by the null safe spread operator `?...`.
+ Expression get nullSafeSpread => BinaryExpression._(
+ const LiteralExpression._('...?'),
+ this,
+ '',
+ addSpace: false,
+ );
+
+ /// This expression preceded by `throw`.
+ Expression get thrown => BinaryExpression._(
+ const LiteralExpression._('throw'),
+ this,
+ '',
+ );
+
+ /// May be overridden to support other types implementing [Expression].
+ @visibleForOverriding
+ Expression get expression => this;
+
+ /// Returns this expression wrapped in parenthesis.
+ ParenthesizedExpression get parenthesized => ParenthesizedExpression._(this);
+}
+
+/// Declare a const variable named [variableName].
+///
+/// Returns `const {variableName}`, or `const {type} {variableName}`.
+Expression declareConst(String variableName, {Reference? type}) =>
+ BinaryExpression._(
+ const LiteralExpression._('const'),
+ type == null
+ ? LiteralExpression._(variableName)
+ : _typedVar(variableName, type),
+ '',
+ isConst: true);
+
+/// Declare a final variable named [variableName].
+///
+/// Returns `final {variableName}`, or `final {type} {variableName}`.
+/// If [late] is true the declaration is prefixed with `late`.
+Expression declareFinal(String variableName,
+ {Reference? type, bool late = false}) =>
+ _late(
+ late,
+ type == null
+ ? LiteralExpression._('final $variableName')
+ : BinaryExpression._(const LiteralExpression._('final'),
+ _typedVar(variableName, type), ''));
+
+/// Declare a variable named [variableName].
+///
+/// Returns `var {variableName}`, or `{type} {variableName}`.
+/// If [late] is true the declaration is prefixed with `late`.
+Expression declareVar(String variableName,
+ {Reference? type, bool late = false}) =>
+ _late(
+ late,
+ type == null
+ ? LiteralExpression._('var $variableName')
+ : _typedVar(variableName, type));
+
+Expression _typedVar(String variableName, Reference type) =>
+ BinaryExpression._(type.expression, LiteralExpression._(variableName), '');
+
+Expression _late(bool late, Expression expression) => late
+ ? BinaryExpression._(const LiteralExpression._('late'), expression, '')
+ : expression;
+
+/// Creates `typedef {name} =`.
+Code createTypeDef(String name, FunctionType type) => BinaryExpression._(
+ LiteralExpression._('typedef $name'), type.expression, '=')
+ .statement;
+
+class ToCodeExpression implements Code {
+ final Expression code;
+
+ /// Whether this code should be considered a _statement_.
+ final bool isStatement;
+
+ @visibleForTesting
+ const ToCodeExpression(this.code, [this.isStatement = false]);
+
+ @override
+ R accept<R>(CodeVisitor<R> visitor, [R? context]) =>
+ (visitor as ExpressionVisitor<R>).visitToCodeExpression(this, context);
+
+ @override
+ String toString() => code.toString();
+}
+
+/// Knowledge of different types of expressions in Dart.
+///
+/// **INTERNAL ONLY**.
+abstract class ExpressionVisitor<T> implements SpecVisitor<T> {
+ T visitToCodeExpression(ToCodeExpression code, [T? context]);
+ T visitBinaryExpression(BinaryExpression expression, [T? context]);
+ T visitClosureExpression(ClosureExpression expression, [T? context]);
+ T visitCodeExpression(CodeExpression expression, [T? context]);
+ T visitInvokeExpression(InvokeExpression expression, [T? context]);
+ T visitLiteralExpression(LiteralExpression expression, [T? context]);
+ T visitLiteralListExpression(LiteralListExpression expression, [T? context]);
+ T visitLiteralSetExpression(LiteralSetExpression expression, [T? context]);
+ T visitLiteralMapExpression(LiteralMapExpression expression, [T? context]);
+ T visitLiteralRecordExpression(LiteralRecordExpression expression,
+ [T? context]);
+ T visitParenthesizedExpression(ParenthesizedExpression expression,
+ [T? context]);
+}
+
+/// Knowledge of how to write valid Dart code from [ExpressionVisitor].
+///
+/// **INTERNAL ONLY**.
+abstract mixin class ExpressionEmitter
+ implements ExpressionVisitor<StringSink> {
+ @override
+ StringSink visitToCodeExpression(ToCodeExpression expression,
+ [StringSink? output]) {
+ output ??= StringBuffer();
+ expression.code.accept(this, output);
+ if (expression.isStatement) {
+ output.write(';');
+ }
+ return output;
+ }
+
+ @override
+ StringSink visitBinaryExpression(BinaryExpression expression,
+ [StringSink? output]) {
+ output ??= StringBuffer();
+ expression.left.accept(this, output);
+ if (expression.addSpace) {
+ output.write(' ');
+ }
+ output.write(expression.operator);
+ if (expression.addSpace) {
+ output.write(' ');
+ }
+ startConstCode(expression.isConst, () {
+ expression.right.accept(this, output);
+ });
+ return output;
+ }
+
+ @override
+ StringSink visitClosureExpression(ClosureExpression expression,
+ [StringSink? output]) {
+ output ??= StringBuffer();
+ return expression.method.accept(this, output);
+ }
+
+ @override
+ StringSink visitCodeExpression(CodeExpression expression,
+ [StringSink? output]) {
+ output ??= StringBuffer();
+ final visitor = this as CodeVisitor<StringSink>;
+ return expression.code.accept(visitor, output);
+ }
+
+ @override
+ StringSink visitInvokeExpression(InvokeExpression expression,
+ [StringSink? output]) {
+ final out = output ??= StringBuffer();
+ return _writeConstExpression(out, expression.isConst, () {
+ expression.target.accept(this, out);
+ if (expression.name != null) {
+ out
+ ..write('.')
+ ..write(expression.name);
+ }
+ if (expression.typeArguments.isNotEmpty) {
+ out.write('<');
+ visitAll<Reference>(expression.typeArguments, out, (type) {
+ type.accept(this, out);
+ });
+ out.write('>');
+ }
+ out.write('(');
+ visitAll<Spec>(expression.positionalArguments, out, (spec) {
+ spec.accept(this, out);
+ });
+ if (expression.positionalArguments.isNotEmpty &&
+ expression.namedArguments.isNotEmpty) {
+ out.write(', ');
+ }
+ visitAll<String>(expression.namedArguments.keys, out, (name) {
+ out
+ ..write(name)
+ ..write(': ');
+ expression.namedArguments[name]!.accept(this, out);
+ });
+ final argumentCount = expression.positionalArguments.length +
+ expression.namedArguments.length;
+ if (argumentCount > 1) {
+ out.write(', ');
+ }
+ return out..write(')');
+ });
+ }
+
+ @override
+ StringSink visitLiteralExpression(LiteralExpression expression,
+ [StringSink? output]) {
+ output ??= StringBuffer();
+ return output..write(expression.literal);
+ }
+
+ void _acceptLiteral(Object? literalOrSpec, StringSink output) {
+ if (literalOrSpec is Spec) {
+ literalOrSpec.accept(this, output);
+ return;
+ }
+ literal(literalOrSpec).accept(this, output);
+ }
+
+ bool _withInConstExpression = false;
+
+ @override
+ StringSink visitLiteralListExpression(
+ LiteralListExpression expression, [
+ StringSink? output,
+ ]) {
+ final out = output ??= StringBuffer();
+
+ return _writeConstExpression(output, expression.isConst, () {
+ if (expression.type != null) {
+ out.write('<');
+ expression.type!.accept(this, output);
+ out.write('>');
+ }
+ out.write('[');
+ visitAll<Object?>(expression.values, out, (value) {
+ _acceptLiteral(value, out);
+ });
+ if (expression.values.length > 1) {
+ out.write(', ');
+ }
+ return out..write(']');
+ });
+ }
+
+ @override
+ StringSink visitLiteralSetExpression(
+ LiteralSetExpression expression, [
+ StringSink? output,
+ ]) {
+ final out = output ??= StringBuffer();
+
+ return _writeConstExpression(output, expression.isConst, () {
+ if (expression.type != null) {
+ out.write('<');
+ expression.type!.accept(this, output);
+ out.write('>');
+ }
+ out.write('{');
+ visitAll<Object?>(expression.values, out, (value) {
+ _acceptLiteral(value, out);
+ });
+ if (expression.values.length > 1) {
+ out.write(', ');
+ }
+ return out..write('}');
+ });
+ }
+
+ @override
+ StringSink visitLiteralMapExpression(
+ LiteralMapExpression expression, [
+ StringSink? output,
+ ]) {
+ final out = output ??= StringBuffer();
+ return _writeConstExpression(out, expression.isConst, () {
+ if (expression.keyType != null) {
+ out.write('<');
+ expression.keyType!.accept(this, out);
+ out.write(', ');
+ if (expression.valueType == null) {
+ const Reference('dynamic', 'dart:core').accept(this, out);
+ } else {
+ expression.valueType!.accept(this, out);
+ }
+ out.write('>');
+ }
+ out.write('{');
+ visitAll<Object?>(expression.values.keys, out, (key) {
+ final value = expression.values[key];
+ _acceptLiteral(key, out);
+ if (key is! LiteralSpreadExpression) {
+ out.write(': ');
+ }
+ _acceptLiteral(value, out);
+ });
+ if (expression.values.length > 1) {
+ out.write(', ');
+ }
+ return out..write('}');
+ });
+ }
+
+ @override
+ StringSink visitLiteralRecordExpression(
+ LiteralRecordExpression expression, [
+ StringSink? output,
+ ]) {
+ final out = output ??= StringBuffer();
+ return _writeConstExpression(out, expression.isConst, () {
+ out.write('(');
+ visitAll<Object?>(expression.positionalFieldValues, out, (value) {
+ _acceptLiteral(value, out);
+ });
+ if (expression.namedFieldValues.isNotEmpty) {
+ if (expression.positionalFieldValues.isNotEmpty) {
+ out.write(', ');
+ }
+ } else if (expression.positionalFieldValues.length == 1) {
+ out.write(',');
+ }
+ visitAll<MapEntry<String, Object?>>(
+ expression.namedFieldValues.entries, out, (entry) {
+ out.write('${entry.key}: ');
+ _acceptLiteral(entry.value, out);
+ });
+ return out..write(')');
+ });
+ }
+
+ @override
+ StringSink visitParenthesizedExpression(
+ ParenthesizedExpression expression, [
+ StringSink? output,
+ ]) {
+ output ??= StringBuffer();
+ output.write('(');
+ expression.inner.accept(this, output);
+ output.write(')');
+ return output;
+ }
+
+ /// Executes [visit] within a context which may alter the output if [isConst]
+ /// is `true`.
+ ///
+ /// This allows constant expressions to omit the `const` keyword if they
+ /// are already within a constant expression.
+ void startConstCode(
+ bool isConst,
+ Null Function() visit,
+ ) {
+ final previousConstContext = _withInConstExpression;
+ if (isConst) {
+ _withInConstExpression = true;
+ }
+
+ visit();
+ _withInConstExpression = previousConstContext;
+ }
+
+ /// Similar to [startConstCode], but handles writing `"const "` if [isConst]
+ /// is `true` and the invocation is not nested under other invocations where
+ /// [isConst] is true.
+ StringSink _writeConstExpression(
+ StringSink sink,
+ bool isConst,
+ StringSink Function() visitExpression,
+ ) {
+ final previousConstContext = _withInConstExpression;
+ if (isConst) {
+ if (!_withInConstExpression) {
+ sink.write('const ');
+ }
+ _withInConstExpression = true;
+ }
+
+ final returnedSink = visitExpression();
+ assert(identical(returnedSink, sink));
+ _withInConstExpression = previousConstContext;
+ return sink;
+ }
+}
diff --git a/pkgs/code_builder/lib/src/specs/expression/binary.dart b/pkgs/code_builder/lib/src/specs/expression/binary.dart
new file mode 100644
index 0000000..d02a2a6
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/expression/binary.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../expression.dart';
+
+/// Represents two expressions ([left] and [right]) and an [operator].
+class BinaryExpression extends Expression {
+ final Expression left;
+ final Expression right;
+ final String operator;
+ final bool addSpace;
+ @override
+ final bool isConst;
+
+ const BinaryExpression._(
+ this.left,
+ this.right,
+ this.operator, {
+ this.addSpace = true,
+ this.isConst = false,
+ });
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitBinaryExpression(this, context);
+}
diff --git a/pkgs/code_builder/lib/src/specs/expression/closure.dart b/pkgs/code_builder/lib/src/specs/expression/closure.dart
new file mode 100644
index 0000000..706600c
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/expression/closure.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../expression.dart';
+
+/// Returns [method] as closure, removing its return type and type parameters.
+Expression toClosure(Method method) {
+ final withoutTypes = method.rebuild((b) {
+ b.returns = null;
+ b.types.clear();
+ });
+ return ClosureExpression._(withoutTypes);
+}
+
+/// Returns [method] as a (possibly) generic closure, removing its return type.
+Expression toGenericClosure(Method method) {
+ final withoutReturnType = method.rebuild((b) {
+ b.returns = null;
+ });
+ return ClosureExpression._(withoutReturnType);
+}
+
+class ClosureExpression extends Expression {
+ final Method method;
+
+ const ClosureExpression._(this.method);
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitClosureExpression(this, context);
+}
diff --git a/pkgs/code_builder/lib/src/specs/expression/code.dart b/pkgs/code_builder/lib/src/specs/expression/code.dart
new file mode 100644
index 0000000..1529edb
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/expression/code.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../expression.dart';
+
+/// Represents a [Code] block as an [Expression].
+class CodeExpression extends Expression {
+ @override
+ final Code code;
+
+ /// **INTERNAL ONLY**: Used to wrap [Code] as an [Expression].
+ const CodeExpression(this.code);
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitCodeExpression(this, context);
+}
diff --git a/pkgs/code_builder/lib/src/specs/expression/invoke.dart b/pkgs/code_builder/lib/src/specs/expression/invoke.dart
new file mode 100644
index 0000000..f54dc0e
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/expression/invoke.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: deprecated_member_use_from_same_package
+
+part of '../expression.dart';
+
+/// Represents invoking [target] as a method with arguments.
+class InvokeExpression extends Expression {
+ /// Target of the method invocation.
+ final Expression target;
+
+ /// Optional; type of invocation.
+ @Deprecated('Use isConst instead')
+ final InvokeExpressionType? type;
+
+ @override
+ final bool isConst;
+
+ final List<Expression> positionalArguments;
+ final Map<String, Expression> namedArguments;
+ final List<Reference> typeArguments;
+ final String? name;
+
+ const InvokeExpression._(
+ this.target,
+ this.positionalArguments,
+ this.namedArguments,
+ this.typeArguments,
+ ) : name = null,
+ type = null,
+ isConst = false;
+
+ const InvokeExpression.newOf(
+ this.target,
+ this.positionalArguments, [
+ this.namedArguments = const {},
+ this.typeArguments = const [],
+ this.name,
+ ]) : type = InvokeExpressionType.newInstance,
+ isConst = false;
+
+ const InvokeExpression.constOf(
+ this.target,
+ this.positionalArguments, [
+ this.namedArguments = const {},
+ this.typeArguments = const [],
+ this.name,
+ ]) : type = InvokeExpressionType.constInstance,
+ isConst = true;
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitInvokeExpression(this, context);
+
+ @override
+ String toString() =>
+ '${type ?? ''} $target($positionalArguments, $namedArguments)';
+}
+
+enum InvokeExpressionType {
+ newInstance,
+ constInstance,
+}
diff --git a/pkgs/code_builder/lib/src/specs/expression/literal.dart b/pkgs/code_builder/lib/src/specs/expression/literal.dart
new file mode 100644
index 0000000..ced6cf9
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/expression/literal.dart
@@ -0,0 +1,218 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../expression.dart';
+
+/// Converts a runtime Dart [literal] value into an [Expression].
+///
+/// Supported Dart types are translated into literal expressions.
+/// If the [literal] is already an [Expression] it is returned without change to
+/// allow operating on a collection of mixed simple literals and more complex
+/// expressions.
+/// Unsupported inputs invoke the [onError] callback.
+Expression literal(Object? literal, {Expression Function(Object)? onError}) {
+ if (literal is Expression) return literal;
+ if (literal is bool) return literalBool(literal);
+ if (literal is num) return literalNum(literal);
+ if (literal is String) return literalString(literal);
+ if (literal is List) return literalList(literal);
+ if (literal is Set) return literalSet(literal);
+ if (literal is Map) return literalMap(literal);
+ if (literal == null) return literalNull;
+ if (onError != null) return onError(literal);
+ throw UnsupportedError('Not a supported literal type: $literal.');
+}
+
+/// Represents the literal value `true`.
+const Expression literalTrue = LiteralExpression._('true');
+
+/// Represents the literal value `false`.
+const Expression literalFalse = LiteralExpression._('false');
+
+/// Create a literal expression from a boolean [value].
+Expression literalBool(bool value) => value ? literalTrue : literalFalse;
+
+/// Represents the literal value `null`.
+const Expression literalNull = LiteralExpression._('null');
+
+/// Create a literal expression from a number [value].
+Expression literalNum(num value) => LiteralExpression._('$value');
+
+/// Create a literal expression from a string [value].
+///
+/// **NOTE**: The string is always formatted `'<value>'`.
+///
+/// If [raw] is `true`, creates a raw String formatted `r'<value>'` and the
+/// value may not contain a single quote.
+/// Escapes single quotes and newlines in the value.
+Expression literalString(String value, {bool raw = false}) {
+ if (raw && value.contains('\'')) {
+ throw ArgumentError('Cannot include a single quote in a raw string');
+ }
+ final escaped = value.replaceAll('\'', '\\\'').replaceAll('\n', '\\n');
+ return LiteralExpression._("${raw ? 'r' : ''}'$escaped'");
+}
+
+/// Create a literal `...` operator for use when creating a Map literal.
+///
+/// *NOTE* This is used as a sentinel when constructing a `literalMap` or a
+/// or `literalConstMap` to signify that the value should be spread. Do NOT
+/// reuse the value when creating a Map with multiple spreads.
+Expression literalSpread() => LiteralSpreadExpression._(false);
+
+/// Create a literal `...?` operator for use when creating a Map literal.
+///
+/// *NOTE* This is used as a sentinel when constructing a `literalMap` or a
+/// or `literalConstMap` to signify that the value should be spread. Do NOT
+/// reuse the value when creating a Map with multiple spreads.
+Expression literalNullSafeSpread() => LiteralSpreadExpression._(true);
+
+/// Creates a literal list expression from [values].
+LiteralListExpression literalList(Iterable<Object?> values,
+ [Reference? type]) =>
+ LiteralListExpression._(false, values.toList(), type);
+
+/// Creates a literal `const` list expression from [values].
+LiteralListExpression literalConstList(List<Object?> values,
+ [Reference? type]) =>
+ LiteralListExpression._(true, values, type);
+
+/// Creates a literal set expression from [values].
+LiteralSetExpression literalSet(Iterable<Object?> values, [Reference? type]) =>
+ LiteralSetExpression._(false, values.toSet(), type);
+
+/// Creates a literal `const` set expression from [values].
+LiteralSetExpression literalConstSet(Set<Object?> values, [Reference? type]) =>
+ LiteralSetExpression._(true, values, type);
+
+/// Create a literal map expression from [values].
+LiteralMapExpression literalMap(
+ Map<Object?, Object?> values, [
+ Reference? keyType,
+ Reference? valueType,
+]) =>
+ LiteralMapExpression._(false, values, keyType, valueType);
+
+/// Create a literal `const` map expression from [values].
+LiteralMapExpression literalConstMap(
+ Map<Object?, Object?> values, [
+ Reference? keyType,
+ Reference? valueType,
+]) =>
+ LiteralMapExpression._(true, values, keyType, valueType);
+
+/// Create a literal record expression from [positionalFieldValues] and
+/// [namedFieldValues].
+LiteralRecordExpression literalRecord(List<Object?> positionalFieldValues,
+ Map<String, Object?> namedFieldValues) =>
+ LiteralRecordExpression._(false, positionalFieldValues, namedFieldValues);
+
+/// Create a literal `const` record expression from [positionalFieldValues] and
+/// [namedFieldValues].
+LiteralRecordExpression literalConstRecord(List<Object?> positionalFieldValues,
+ Map<String, Object?> namedFieldValues) =>
+ LiteralRecordExpression._(true, positionalFieldValues, namedFieldValues);
+
+/// Represents a literal value in Dart source code.
+///
+/// For example, `LiteralExpression('null')` should emit `null`.
+///
+/// Some common literals and helpers are available as methods/fields:
+/// * [literal]
+/// * [literalBool] and [literalTrue], [literalFalse]
+/// * [literalNull]
+/// * [literalList] and [literalConstList]
+/// * [literalSet] and [literalConstSet]
+class LiteralExpression extends Expression {
+ final String literal;
+
+ const LiteralExpression._(this.literal);
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitLiteralExpression(this, context);
+
+ @override
+ String toString() => literal;
+}
+
+class LiteralSpreadExpression extends LiteralExpression {
+ LiteralSpreadExpression._(bool nullAware)
+ : super._('...${nullAware ? '?' : ''}');
+}
+
+class LiteralListExpression extends Expression {
+ @override
+ final bool isConst;
+ final List<Object?> values;
+ final Reference? type;
+
+ const LiteralListExpression._(this.isConst, this.values, this.type);
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitLiteralListExpression(this, context);
+
+ @override
+ String toString() => '[${values.map(literal).join(', ')}]';
+}
+
+class LiteralSetExpression extends Expression {
+ @override
+ final bool isConst;
+ final Set<Object?> values;
+ final Reference? type;
+
+ const LiteralSetExpression._(this.isConst, this.values, this.type);
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitLiteralSetExpression(this, context);
+
+ @override
+ String toString() => '{${values.map(literal).join(', ')}}';
+}
+
+class LiteralMapExpression extends Expression {
+ @override
+ final bool isConst;
+ final Map<Object?, Object?> values;
+ final Reference? keyType;
+ final Reference? valueType;
+
+ const LiteralMapExpression._(
+ this.isConst,
+ this.values,
+ this.keyType,
+ this.valueType,
+ );
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitLiteralMapExpression(this, context);
+
+ @override
+ String toString() => '{$values}';
+}
+
+class LiteralRecordExpression extends Expression {
+ @override
+ final bool isConst;
+ final List<Object?> positionalFieldValues;
+ final Map<String, Object?> namedFieldValues;
+
+ const LiteralRecordExpression._(
+ this.isConst, this.positionalFieldValues, this.namedFieldValues);
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitLiteralRecordExpression(this, context);
+
+ @override
+ String toString() {
+ final allFields = positionalFieldValues.map((v) => v.toString()).followedBy(
+ namedFieldValues.entries.map((e) => '${e.key}: ${e.value}'));
+ return '(${allFields.join(', ')})';
+ }
+}
diff --git a/pkgs/code_builder/lib/src/specs/expression/parenthesized.dart b/pkgs/code_builder/lib/src/specs/expression/parenthesized.dart
new file mode 100644
index 0000000..ea34ae8
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/expression/parenthesized.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../expression.dart';
+
+/// An [Expression] wrapped with parenthesis.
+class ParenthesizedExpression extends Expression {
+ final Expression inner;
+
+ const ParenthesizedExpression._(this.inner);
+
+ @override
+ R accept<R>(ExpressionVisitor<R> visitor, [R? context]) =>
+ visitor.visitParenthesizedExpression(this, context);
+}
diff --git a/pkgs/code_builder/lib/src/specs/extension.dart b/pkgs/code_builder/lib/src/specs/extension.dart
new file mode 100644
index 0000000..395994f
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/extension.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'expression.dart';
+import 'field.dart';
+import 'method.dart';
+import 'reference.dart';
+
+part 'extension.g.dart';
+
+@immutable
+abstract class Extension extends Object
+ with HasAnnotations, HasDartDocs, HasGenerics
+ implements Built<Extension, ExtensionBuilder>, Spec {
+ factory Extension([void Function(ExtensionBuilder b) updates]) = _$Extension;
+
+ Extension._();
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ Reference? get on;
+
+ @override
+ BuiltList<Reference> get types;
+
+ BuiltList<Method> get methods;
+
+ BuiltList<Field> get fields;
+
+ /// Name of the extension - optional.
+ String? get name;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitExtension(this, context);
+}
+
+abstract class ExtensionBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
+ implements Builder<Extension, ExtensionBuilder> {
+ factory ExtensionBuilder() = _$ExtensionBuilder;
+
+ ExtensionBuilder._();
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ Reference? on;
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ ListBuilder<Method> methods = ListBuilder<Method>();
+ ListBuilder<Field> fields = ListBuilder<Field>();
+
+ /// Name of the extension - optional.
+ String? name;
+}
diff --git a/pkgs/code_builder/lib/src/specs/extension.g.dart b/pkgs/code_builder/lib/src/specs/extension.g.dart
new file mode 100644
index 0000000..83de176
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/extension.g.dart
@@ -0,0 +1,248 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'extension.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Extension extends Extension {
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final Reference? on;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final BuiltList<Method> methods;
+ @override
+ final BuiltList<Field> fields;
+ @override
+ final String? name;
+
+ factory _$Extension([void Function(ExtensionBuilder)? updates]) =>
+ (new ExtensionBuilder()..update(updates)).build() as _$Extension;
+
+ _$Extension._(
+ {required this.annotations,
+ required this.docs,
+ this.on,
+ required this.types,
+ required this.methods,
+ required this.fields,
+ this.name})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'Extension', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Extension', 'docs');
+ BuiltValueNullFieldError.checkNotNull(types, r'Extension', 'types');
+ BuiltValueNullFieldError.checkNotNull(methods, r'Extension', 'methods');
+ BuiltValueNullFieldError.checkNotNull(fields, r'Extension', 'fields');
+ }
+
+ @override
+ Extension rebuild(void Function(ExtensionBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$ExtensionBuilder toBuilder() => new _$ExtensionBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Extension &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ on == other.on &&
+ types == other.types &&
+ methods == other.methods &&
+ fields == other.fields &&
+ name == other.name;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, on.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, methods.hashCode);
+ _$hash = $jc(_$hash, fields.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Extension')
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('on', on)
+ ..add('types', types)
+ ..add('methods', methods)
+ ..add('fields', fields)
+ ..add('name', name))
+ .toString();
+ }
+}
+
+class _$ExtensionBuilder extends ExtensionBuilder {
+ _$Extension? _$v;
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ Reference? get on {
+ _$this;
+ return super.on;
+ }
+
+ @override
+ set on(Reference? on) {
+ _$this;
+ super.on = on;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ ListBuilder<Method> get methods {
+ _$this;
+ return super.methods;
+ }
+
+ @override
+ set methods(ListBuilder<Method> methods) {
+ _$this;
+ super.methods = methods;
+ }
+
+ @override
+ ListBuilder<Field> get fields {
+ _$this;
+ return super.fields;
+ }
+
+ @override
+ set fields(ListBuilder<Field> fields) {
+ _$this;
+ super.fields = fields;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ _$ExtensionBuilder() : super._();
+
+ ExtensionBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.on = $v.on;
+ super.types = $v.types.toBuilder();
+ super.methods = $v.methods.toBuilder();
+ super.fields = $v.fields.toBuilder();
+ super.name = $v.name;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Extension other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Extension;
+ }
+
+ @override
+ void update(void Function(ExtensionBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Extension build() => _build();
+
+ _$Extension _build() {
+ _$Extension _$result;
+ try {
+ _$result = _$v ??
+ new _$Extension._(
+ annotations: annotations.build(),
+ docs: docs.build(),
+ on: on,
+ types: types.build(),
+ methods: methods.build(),
+ fields: fields.build(),
+ name: name);
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+
+ _$failedField = 'types';
+ types.build();
+ _$failedField = 'methods';
+ methods.build();
+ _$failedField = 'fields';
+ fields.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Extension', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/extension_type.dart b/pkgs/code_builder/lib/src/specs/extension_type.dart
new file mode 100644
index 0000000..ec3bd33
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/extension_type.dart
@@ -0,0 +1,152 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'constructor.dart';
+import 'expression.dart';
+import 'field.dart';
+import 'method.dart';
+import 'reference.dart';
+
+part 'extension_type.g.dart';
+
+@immutable
+abstract class ExtensionType extends Object
+ with HasAnnotations, HasDartDocs, HasGenerics
+ implements Built<ExtensionType, ExtensionTypeBuilder>, Spec {
+ factory ExtensionType([void Function(ExtensionTypeBuilder)? updates]) =
+ _$ExtensionType;
+
+ ExtensionType._();
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ /// Whether this extension type is declared as `const`.
+ bool get constant;
+
+ String get name;
+
+ @override
+ BuiltList<Reference> get types;
+
+ /// Name of the extension type's primary constructor. An empty string
+ /// will make it unnamed.
+ String get primaryConstructorName;
+
+ RepresentationDeclaration get representationDeclaration;
+
+ BuiltList<Reference> get implements;
+
+ BuiltList<Constructor> get constructors;
+
+ BuiltList<Field> get fields;
+
+ BuiltList<Method> get methods;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitExtensionType(this, context);
+}
+
+abstract class ExtensionTypeBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
+ implements Builder<ExtensionType, ExtensionTypeBuilder> {
+ factory ExtensionTypeBuilder() = _$ExtensionTypeBuilder;
+
+ ExtensionTypeBuilder._();
+
+ @override
+ void update(void Function(ExtensionTypeBuilder)? updates) {
+ updates?.call(this);
+ }
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ /// Whether this extension type is declared as `const`.
+ bool constant = false;
+
+ String? name;
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ /// Name of the extension type's primary constructor. An empty string
+ /// will make it unnamed.
+ String primaryConstructorName = '';
+
+ RepresentationDeclaration? representationDeclaration;
+
+ ListBuilder<Reference> implements = ListBuilder<Reference>();
+
+ ListBuilder<Constructor> constructors = ListBuilder<Constructor>();
+
+ ListBuilder<Field> fields = ListBuilder<Field>();
+
+ ListBuilder<Method> methods = ListBuilder<Method>();
+}
+
+abstract class RepresentationDeclaration extends Object
+ with HasAnnotations, HasDartDocs
+ implements
+ Built<RepresentationDeclaration, RepresentationDeclarationBuilder> {
+ factory RepresentationDeclaration(
+ [void Function(RepresentationDeclarationBuilder)? updates]) =
+ _$RepresentationDeclaration;
+
+ RepresentationDeclaration._();
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ Reference get declaredRepresentationType;
+
+ String get name;
+}
+
+abstract class RepresentationDeclarationBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder
+ implements
+ Builder<RepresentationDeclaration, RepresentationDeclarationBuilder> {
+ factory RepresentationDeclarationBuilder() =
+ _$RepresentationDeclarationBuilder;
+
+ RepresentationDeclarationBuilder._();
+
+ @override
+ void update(void Function(RepresentationDeclarationBuilder)? updates) {
+ updates?.call(this);
+ }
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ Reference? declaredRepresentationType;
+
+ String? name;
+}
diff --git a/pkgs/code_builder/lib/src/specs/extension_type.g.dart b/pkgs/code_builder/lib/src/specs/extension_type.g.dart
new file mode 100644
index 0000000..5769840
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/extension_type.g.dart
@@ -0,0 +1,537 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'extension_type.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$ExtensionType extends ExtensionType {
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final bool constant;
+ @override
+ final String name;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final String primaryConstructorName;
+ @override
+ final RepresentationDeclaration representationDeclaration;
+ @override
+ final BuiltList<Reference> implements;
+ @override
+ final BuiltList<Constructor> constructors;
+ @override
+ final BuiltList<Field> fields;
+ @override
+ final BuiltList<Method> methods;
+
+ factory _$ExtensionType([void Function(ExtensionTypeBuilder)? updates]) =>
+ (new ExtensionTypeBuilder()..update(updates)).build() as _$ExtensionType;
+
+ _$ExtensionType._(
+ {required this.annotations,
+ required this.docs,
+ required this.constant,
+ required this.name,
+ required this.types,
+ required this.primaryConstructorName,
+ required this.representationDeclaration,
+ required this.implements,
+ required this.constructors,
+ required this.fields,
+ required this.methods})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'ExtensionType', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'ExtensionType', 'docs');
+ BuiltValueNullFieldError.checkNotNull(
+ constant, r'ExtensionType', 'constant');
+ BuiltValueNullFieldError.checkNotNull(name, r'ExtensionType', 'name');
+ BuiltValueNullFieldError.checkNotNull(types, r'ExtensionType', 'types');
+ BuiltValueNullFieldError.checkNotNull(
+ primaryConstructorName, r'ExtensionType', 'primaryConstructorName');
+ BuiltValueNullFieldError.checkNotNull(representationDeclaration,
+ r'ExtensionType', 'representationDeclaration');
+ BuiltValueNullFieldError.checkNotNull(
+ implements, r'ExtensionType', 'implements');
+ BuiltValueNullFieldError.checkNotNull(
+ constructors, r'ExtensionType', 'constructors');
+ BuiltValueNullFieldError.checkNotNull(fields, r'ExtensionType', 'fields');
+ BuiltValueNullFieldError.checkNotNull(methods, r'ExtensionType', 'methods');
+ }
+
+ @override
+ ExtensionType rebuild(void Function(ExtensionTypeBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$ExtensionTypeBuilder toBuilder() =>
+ new _$ExtensionTypeBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is ExtensionType &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ constant == other.constant &&
+ name == other.name &&
+ types == other.types &&
+ primaryConstructorName == other.primaryConstructorName &&
+ representationDeclaration == other.representationDeclaration &&
+ implements == other.implements &&
+ constructors == other.constructors &&
+ fields == other.fields &&
+ methods == other.methods;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, constant.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, primaryConstructorName.hashCode);
+ _$hash = $jc(_$hash, representationDeclaration.hashCode);
+ _$hash = $jc(_$hash, implements.hashCode);
+ _$hash = $jc(_$hash, constructors.hashCode);
+ _$hash = $jc(_$hash, fields.hashCode);
+ _$hash = $jc(_$hash, methods.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'ExtensionType')
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('constant', constant)
+ ..add('name', name)
+ ..add('types', types)
+ ..add('primaryConstructorName', primaryConstructorName)
+ ..add('representationDeclaration', representationDeclaration)
+ ..add('implements', implements)
+ ..add('constructors', constructors)
+ ..add('fields', fields)
+ ..add('methods', methods))
+ .toString();
+ }
+}
+
+class _$ExtensionTypeBuilder extends ExtensionTypeBuilder {
+ _$ExtensionType? _$v;
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ bool get constant {
+ _$this;
+ return super.constant;
+ }
+
+ @override
+ set constant(bool constant) {
+ _$this;
+ super.constant = constant;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ String get primaryConstructorName {
+ _$this;
+ return super.primaryConstructorName;
+ }
+
+ @override
+ set primaryConstructorName(String primaryConstructorName) {
+ _$this;
+ super.primaryConstructorName = primaryConstructorName;
+ }
+
+ @override
+ RepresentationDeclaration? get representationDeclaration {
+ _$this;
+ return super.representationDeclaration;
+ }
+
+ @override
+ set representationDeclaration(
+ RepresentationDeclaration? representationDeclaration) {
+ _$this;
+ super.representationDeclaration = representationDeclaration;
+ }
+
+ @override
+ ListBuilder<Reference> get implements {
+ _$this;
+ return super.implements;
+ }
+
+ @override
+ set implements(ListBuilder<Reference> implements) {
+ _$this;
+ super.implements = implements;
+ }
+
+ @override
+ ListBuilder<Constructor> get constructors {
+ _$this;
+ return super.constructors;
+ }
+
+ @override
+ set constructors(ListBuilder<Constructor> constructors) {
+ _$this;
+ super.constructors = constructors;
+ }
+
+ @override
+ ListBuilder<Field> get fields {
+ _$this;
+ return super.fields;
+ }
+
+ @override
+ set fields(ListBuilder<Field> fields) {
+ _$this;
+ super.fields = fields;
+ }
+
+ @override
+ ListBuilder<Method> get methods {
+ _$this;
+ return super.methods;
+ }
+
+ @override
+ set methods(ListBuilder<Method> methods) {
+ _$this;
+ super.methods = methods;
+ }
+
+ _$ExtensionTypeBuilder() : super._();
+
+ ExtensionTypeBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.constant = $v.constant;
+ super.name = $v.name;
+ super.types = $v.types.toBuilder();
+ super.primaryConstructorName = $v.primaryConstructorName;
+ super.representationDeclaration = $v.representationDeclaration;
+ super.implements = $v.implements.toBuilder();
+ super.constructors = $v.constructors.toBuilder();
+ super.fields = $v.fields.toBuilder();
+ super.methods = $v.methods.toBuilder();
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(ExtensionType other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$ExtensionType;
+ }
+
+ @override
+ void update(void Function(ExtensionTypeBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ ExtensionType build() => _build();
+
+ _$ExtensionType _build() {
+ _$ExtensionType _$result;
+ try {
+ _$result = _$v ??
+ new _$ExtensionType._(
+ annotations: annotations.build(),
+ docs: docs.build(),
+ constant: BuiltValueNullFieldError.checkNotNull(
+ constant, r'ExtensionType', 'constant'),
+ name: BuiltValueNullFieldError.checkNotNull(
+ name, r'ExtensionType', 'name'),
+ types: types.build(),
+ primaryConstructorName: BuiltValueNullFieldError.checkNotNull(
+ primaryConstructorName,
+ r'ExtensionType',
+ 'primaryConstructorName'),
+ representationDeclaration: BuiltValueNullFieldError.checkNotNull(
+ representationDeclaration,
+ r'ExtensionType',
+ 'representationDeclaration'),
+ implements: implements.build(),
+ constructors: constructors.build(),
+ fields: fields.build(),
+ methods: methods.build());
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+
+ _$failedField = 'types';
+ types.build();
+
+ _$failedField = 'implements';
+ implements.build();
+ _$failedField = 'constructors';
+ constructors.build();
+ _$failedField = 'fields';
+ fields.build();
+ _$failedField = 'methods';
+ methods.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'ExtensionType', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+class _$RepresentationDeclaration extends RepresentationDeclaration {
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final Reference declaredRepresentationType;
+ @override
+ final String name;
+
+ factory _$RepresentationDeclaration(
+ [void Function(RepresentationDeclarationBuilder)? updates]) =>
+ (new RepresentationDeclarationBuilder()..update(updates)).build()
+ as _$RepresentationDeclaration;
+
+ _$RepresentationDeclaration._(
+ {required this.annotations,
+ required this.docs,
+ required this.declaredRepresentationType,
+ required this.name})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'RepresentationDeclaration', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(
+ docs, r'RepresentationDeclaration', 'docs');
+ BuiltValueNullFieldError.checkNotNull(declaredRepresentationType,
+ r'RepresentationDeclaration', 'declaredRepresentationType');
+ BuiltValueNullFieldError.checkNotNull(
+ name, r'RepresentationDeclaration', 'name');
+ }
+
+ @override
+ RepresentationDeclaration rebuild(
+ void Function(RepresentationDeclarationBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$RepresentationDeclarationBuilder toBuilder() =>
+ new _$RepresentationDeclarationBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is RepresentationDeclaration &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ declaredRepresentationType == other.declaredRepresentationType &&
+ name == other.name;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, declaredRepresentationType.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'RepresentationDeclaration')
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('declaredRepresentationType', declaredRepresentationType)
+ ..add('name', name))
+ .toString();
+ }
+}
+
+class _$RepresentationDeclarationBuilder
+ extends RepresentationDeclarationBuilder {
+ _$RepresentationDeclaration? _$v;
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ Reference? get declaredRepresentationType {
+ _$this;
+ return super.declaredRepresentationType;
+ }
+
+ @override
+ set declaredRepresentationType(Reference? declaredRepresentationType) {
+ _$this;
+ super.declaredRepresentationType = declaredRepresentationType;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ _$RepresentationDeclarationBuilder() : super._();
+
+ RepresentationDeclarationBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.declaredRepresentationType = $v.declaredRepresentationType;
+ super.name = $v.name;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(RepresentationDeclaration other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$RepresentationDeclaration;
+ }
+
+ @override
+ void update(void Function(RepresentationDeclarationBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ RepresentationDeclaration build() => _build();
+
+ _$RepresentationDeclaration _build() {
+ _$RepresentationDeclaration _$result;
+ try {
+ _$result = _$v ??
+ new _$RepresentationDeclaration._(
+ annotations: annotations.build(),
+ docs: docs.build(),
+ declaredRepresentationType: BuiltValueNullFieldError.checkNotNull(
+ declaredRepresentationType,
+ r'RepresentationDeclaration',
+ 'declaredRepresentationType'),
+ name: BuiltValueNullFieldError.checkNotNull(
+ name, r'RepresentationDeclaration', 'name'));
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'RepresentationDeclaration', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/field.dart b/pkgs/code_builder/lib/src/specs/field.dart
new file mode 100644
index 0000000..7930bf6
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/field.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../visitors.dart';
+import 'code.dart';
+import 'expression.dart';
+import 'reference.dart';
+
+part 'field.g.dart';
+
+@immutable
+abstract class Field extends Object
+ with HasAnnotations, HasDartDocs
+ implements Built<Field, FieldBuilder>, Spec {
+ factory Field([void Function(FieldBuilder) updates]) = _$Field;
+
+ Field._();
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ /// Field assignment, if any.
+ Code? get assignment;
+
+ /// Whether this field should be prefixed with `static`.
+ ///
+ /// This is only valid within classes.
+ bool get static;
+
+ /// Whether this field should be prefixed with `late`.
+ bool get late;
+
+ /// Whether the field should be prefixed with `external`.
+ bool get external;
+
+ /// Name of the field.
+ String get name;
+
+ Reference? get type;
+
+ FieldModifier get modifier;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitField(this, context);
+}
+
+enum FieldModifier {
+ var$,
+ final$,
+ constant,
+}
+
+abstract class FieldBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder
+ implements Builder<Field, FieldBuilder> {
+ factory FieldBuilder() = _$FieldBuilder;
+
+ FieldBuilder._();
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ /// Field assignment, if any.
+ Code? assignment;
+
+ /// Whether this field should be prefixed with `static`.
+ ///
+ /// This is only valid within classes.
+ bool static = false;
+
+ /// Whether this field should be prefixed with `late`.
+ bool late = false;
+
+ /// Whether the field should be prefixed with `external`.
+ bool external = false;
+
+ /// Name of the field.
+ String? name;
+
+ Reference? type;
+
+ FieldModifier modifier = FieldModifier.var$;
+}
diff --git a/pkgs/code_builder/lib/src/specs/field.g.dart b/pkgs/code_builder/lib/src/specs/field.g.dart
new file mode 100644
index 0000000..d15f1c7
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/field.g.dart
@@ -0,0 +1,287 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'field.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Field extends Field {
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final Code? assignment;
+ @override
+ final bool static;
+ @override
+ final bool late;
+ @override
+ final bool external;
+ @override
+ final String name;
+ @override
+ final Reference? type;
+ @override
+ final FieldModifier modifier;
+
+ factory _$Field([void Function(FieldBuilder)? updates]) =>
+ (new FieldBuilder()..update(updates)).build() as _$Field;
+
+ _$Field._(
+ {required this.annotations,
+ required this.docs,
+ this.assignment,
+ required this.static,
+ required this.late,
+ required this.external,
+ required this.name,
+ this.type,
+ required this.modifier})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(annotations, r'Field', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Field', 'docs');
+ BuiltValueNullFieldError.checkNotNull(static, r'Field', 'static');
+ BuiltValueNullFieldError.checkNotNull(late, r'Field', 'late');
+ BuiltValueNullFieldError.checkNotNull(external, r'Field', 'external');
+ BuiltValueNullFieldError.checkNotNull(name, r'Field', 'name');
+ BuiltValueNullFieldError.checkNotNull(modifier, r'Field', 'modifier');
+ }
+
+ @override
+ Field rebuild(void Function(FieldBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$FieldBuilder toBuilder() => new _$FieldBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Field &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ assignment == other.assignment &&
+ static == other.static &&
+ late == other.late &&
+ external == other.external &&
+ name == other.name &&
+ type == other.type &&
+ modifier == other.modifier;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, assignment.hashCode);
+ _$hash = $jc(_$hash, static.hashCode);
+ _$hash = $jc(_$hash, late.hashCode);
+ _$hash = $jc(_$hash, external.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jc(_$hash, type.hashCode);
+ _$hash = $jc(_$hash, modifier.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Field')
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('assignment', assignment)
+ ..add('static', static)
+ ..add('late', late)
+ ..add('external', external)
+ ..add('name', name)
+ ..add('type', type)
+ ..add('modifier', modifier))
+ .toString();
+ }
+}
+
+class _$FieldBuilder extends FieldBuilder {
+ _$Field? _$v;
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ Code? get assignment {
+ _$this;
+ return super.assignment;
+ }
+
+ @override
+ set assignment(Code? assignment) {
+ _$this;
+ super.assignment = assignment;
+ }
+
+ @override
+ bool get static {
+ _$this;
+ return super.static;
+ }
+
+ @override
+ set static(bool static) {
+ _$this;
+ super.static = static;
+ }
+
+ @override
+ bool get late {
+ _$this;
+ return super.late;
+ }
+
+ @override
+ set late(bool late) {
+ _$this;
+ super.late = late;
+ }
+
+ @override
+ bool get external {
+ _$this;
+ return super.external;
+ }
+
+ @override
+ set external(bool external) {
+ _$this;
+ super.external = external;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ @override
+ Reference? get type {
+ _$this;
+ return super.type;
+ }
+
+ @override
+ set type(Reference? type) {
+ _$this;
+ super.type = type;
+ }
+
+ @override
+ FieldModifier get modifier {
+ _$this;
+ return super.modifier;
+ }
+
+ @override
+ set modifier(FieldModifier modifier) {
+ _$this;
+ super.modifier = modifier;
+ }
+
+ _$FieldBuilder() : super._();
+
+ FieldBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.assignment = $v.assignment;
+ super.static = $v.static;
+ super.late = $v.late;
+ super.external = $v.external;
+ super.name = $v.name;
+ super.type = $v.type;
+ super.modifier = $v.modifier;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Field other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Field;
+ }
+
+ @override
+ void update(void Function(FieldBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Field build() => _build();
+
+ _$Field _build() {
+ _$Field _$result;
+ try {
+ _$result = _$v ??
+ new _$Field._(
+ annotations: annotations.build(),
+ docs: docs.build(),
+ assignment: assignment,
+ static: BuiltValueNullFieldError.checkNotNull(
+ static, r'Field', 'static'),
+ late:
+ BuiltValueNullFieldError.checkNotNull(late, r'Field', 'late'),
+ external: BuiltValueNullFieldError.checkNotNull(
+ external, r'Field', 'external'),
+ name:
+ BuiltValueNullFieldError.checkNotNull(name, r'Field', 'name'),
+ type: type,
+ modifier: BuiltValueNullFieldError.checkNotNull(
+ modifier, r'Field', 'modifier'));
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Field', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/library.dart b/pkgs/code_builder/lib/src/specs/library.dart
new file mode 100644
index 0000000..bbfbf3f
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/library.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../visitors.dart';
+import 'directive.dart';
+import 'expression.dart';
+
+part 'library.g.dart';
+
+@immutable
+abstract class Library
+ with HasAnnotations, HasDartDocs
+ implements Built<Library, LibraryBuilder>, Spec {
+ factory Library([void Function(LibraryBuilder) updates]) = _$Library;
+ Library._();
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ BuiltList<Directive> get directives;
+ BuiltList<Spec> get body;
+
+ /// Line comments to place at the start of the library.
+ BuiltList<String> get comments;
+
+ /// A comment indicating the tool this library was generated by.
+ ///
+ /// This is typically of the form `Generated by xxx.`; it should exclude
+ /// leading line comment characters.
+ String? get generatedByComment;
+
+ /// A list of analysis issues to ignore (`ignore_for_file: ...`).
+ BuiltList<String> get ignoreForFile;
+
+ /// Name of the library.
+ ///
+ /// May be `null` when no [annotations] are specified.
+ String? get name;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitLibrary(this, context);
+}
+
+abstract class LibraryBuilder
+ with HasAnnotationsBuilder, HasDartDocsBuilder
+ implements Builder<Library, LibraryBuilder> {
+ factory LibraryBuilder() = _$LibraryBuilder;
+ LibraryBuilder._();
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ ListBuilder<Spec> body = ListBuilder<Spec>();
+ ListBuilder<Directive> directives = ListBuilder<Directive>();
+
+ ListBuilder<String> comments = ListBuilder<String>();
+ String? generatedByComment;
+ ListBuilder<String> ignoreForFile = ListBuilder<String>();
+
+ String? name;
+}
diff --git a/pkgs/code_builder/lib/src/specs/library.g.dart b/pkgs/code_builder/lib/src/specs/library.g.dart
new file mode 100644
index 0000000..63cfc20
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/library.g.dart
@@ -0,0 +1,272 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'library.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Library extends Library {
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final BuiltList<Directive> directives;
+ @override
+ final BuiltList<Spec> body;
+ @override
+ final BuiltList<String> comments;
+ @override
+ final String? generatedByComment;
+ @override
+ final BuiltList<String> ignoreForFile;
+ @override
+ final String? name;
+
+ factory _$Library([void Function(LibraryBuilder)? updates]) =>
+ (new LibraryBuilder()..update(updates)).build() as _$Library;
+
+ _$Library._(
+ {required this.annotations,
+ required this.docs,
+ required this.directives,
+ required this.body,
+ required this.comments,
+ this.generatedByComment,
+ required this.ignoreForFile,
+ this.name})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'Library', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Library', 'docs');
+ BuiltValueNullFieldError.checkNotNull(directives, r'Library', 'directives');
+ BuiltValueNullFieldError.checkNotNull(body, r'Library', 'body');
+ BuiltValueNullFieldError.checkNotNull(comments, r'Library', 'comments');
+ BuiltValueNullFieldError.checkNotNull(
+ ignoreForFile, r'Library', 'ignoreForFile');
+ }
+
+ @override
+ Library rebuild(void Function(LibraryBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$LibraryBuilder toBuilder() => new _$LibraryBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Library &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ directives == other.directives &&
+ body == other.body &&
+ comments == other.comments &&
+ generatedByComment == other.generatedByComment &&
+ ignoreForFile == other.ignoreForFile &&
+ name == other.name;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, directives.hashCode);
+ _$hash = $jc(_$hash, body.hashCode);
+ _$hash = $jc(_$hash, comments.hashCode);
+ _$hash = $jc(_$hash, generatedByComment.hashCode);
+ _$hash = $jc(_$hash, ignoreForFile.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Library')
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('directives', directives)
+ ..add('body', body)
+ ..add('comments', comments)
+ ..add('generatedByComment', generatedByComment)
+ ..add('ignoreForFile', ignoreForFile)
+ ..add('name', name))
+ .toString();
+ }
+}
+
+class _$LibraryBuilder extends LibraryBuilder {
+ _$Library? _$v;
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ ListBuilder<Directive> get directives {
+ _$this;
+ return super.directives;
+ }
+
+ @override
+ set directives(ListBuilder<Directive> directives) {
+ _$this;
+ super.directives = directives;
+ }
+
+ @override
+ ListBuilder<Spec> get body {
+ _$this;
+ return super.body;
+ }
+
+ @override
+ set body(ListBuilder<Spec> body) {
+ _$this;
+ super.body = body;
+ }
+
+ @override
+ ListBuilder<String> get comments {
+ _$this;
+ return super.comments;
+ }
+
+ @override
+ set comments(ListBuilder<String> comments) {
+ _$this;
+ super.comments = comments;
+ }
+
+ @override
+ String? get generatedByComment {
+ _$this;
+ return super.generatedByComment;
+ }
+
+ @override
+ set generatedByComment(String? generatedByComment) {
+ _$this;
+ super.generatedByComment = generatedByComment;
+ }
+
+ @override
+ ListBuilder<String> get ignoreForFile {
+ _$this;
+ return super.ignoreForFile;
+ }
+
+ @override
+ set ignoreForFile(ListBuilder<String> ignoreForFile) {
+ _$this;
+ super.ignoreForFile = ignoreForFile;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ _$LibraryBuilder() : super._();
+
+ LibraryBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.directives = $v.directives.toBuilder();
+ super.body = $v.body.toBuilder();
+ super.comments = $v.comments.toBuilder();
+ super.generatedByComment = $v.generatedByComment;
+ super.ignoreForFile = $v.ignoreForFile.toBuilder();
+ super.name = $v.name;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Library other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Library;
+ }
+
+ @override
+ void update(void Function(LibraryBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Library build() => _build();
+
+ _$Library _build() {
+ _$Library _$result;
+ try {
+ _$result = _$v ??
+ new _$Library._(
+ annotations: annotations.build(),
+ docs: docs.build(),
+ directives: directives.build(),
+ body: body.build(),
+ comments: comments.build(),
+ generatedByComment: generatedByComment,
+ ignoreForFile: ignoreForFile.build(),
+ name: name);
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+ _$failedField = 'directives';
+ directives.build();
+ _$failedField = 'body';
+ body.build();
+ _$failedField = 'comments';
+ comments.build();
+
+ _$failedField = 'ignoreForFile';
+ ignoreForFile.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Library', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/method.dart b/pkgs/code_builder/lib/src/specs/method.dart
new file mode 100644
index 0000000..2c0a645
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/method.dart
@@ -0,0 +1,271 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'code.dart';
+import 'expression.dart';
+import 'reference.dart';
+
+part 'method.g.dart';
+
+const _$void = Reference('void');
+
+@immutable
+abstract class Method extends Object
+ with HasAnnotations, HasGenerics, HasDartDocs
+ implements Built<Method, MethodBuilder>, Spec {
+ factory Method([void Function(MethodBuilder) updates]) = _$Method;
+
+ factory Method.returnsVoid([void Function(MethodBuilder)? updates]) =>
+ Method((b) {
+ if (updates != null) {
+ updates(b);
+ }
+ b.returns = _$void;
+ });
+
+ Method._();
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ @override
+ BuiltList<Reference> get types;
+
+ /// Optional parameters.
+ BuiltList<Parameter> get optionalParameters;
+
+ /// Required parameters.
+ BuiltList<Parameter> get requiredParameters;
+
+ /// Body of the method.
+ Code? get body;
+
+ /// Whether the method should be prefixed with `external`.
+ bool get external;
+
+ /// Whether this method is a simple lambda expression.
+ ///
+ /// May be `null` to be inferred based on the value of [body].
+ bool? get lambda;
+
+ /// Whether this method should be prefixed with `static`.
+ ///
+ /// This is only valid within classes.
+ bool get static;
+
+ /// Name of the method or function.
+ ///
+ /// May be `null` when being used as a [closure].
+ String? get name;
+
+ /// Whether this is a getter or setter.
+ MethodType? get type;
+
+ /// Whether this method is `async`, `async*`, or `sync*`.
+ MethodModifier? get modifier;
+
+ Reference? get returns;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitMethod(this, context);
+
+ /// This method as a closure.
+ Expression get closure => toClosure(this);
+
+ /// This method as a (possibly) generic closure.
+ Expression get genericClosure => toGenericClosure(this);
+}
+
+abstract class MethodBuilder extends Object
+ with HasAnnotationsBuilder, HasGenericsBuilder, HasDartDocsBuilder
+ implements Builder<Method, MethodBuilder> {
+ factory MethodBuilder() = _$MethodBuilder;
+
+ MethodBuilder._();
+
+ @override
+ void update(void Function(MethodBuilder)? updates) {
+ updates?.call(this);
+ }
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ /// Optional parameters.
+ ListBuilder<Parameter> optionalParameters = ListBuilder<Parameter>();
+
+ /// Required parameters.
+ ListBuilder<Parameter> requiredParameters = ListBuilder<Parameter>();
+
+ /// Body of the method.
+ Code? body;
+
+ /// Whether the method should be prefixed with `external`.
+ bool external = false;
+
+ /// Whether this method is a simple lambda expression.
+ ///
+ /// If not specified this is inferred from the [body].
+ bool? lambda;
+
+ /// Whether this method should be prefixed with `static`.
+ ///
+ /// This is only valid within classes.
+ bool static = false;
+
+ /// Name of the method or function.
+ String? name;
+
+ /// Whether this is a getter or setter.
+ MethodType? type;
+
+ /// Whether this method is `async`, `async*`, or `sync*`.
+ MethodModifier? modifier;
+
+ Reference? returns;
+}
+
+enum MethodType {
+ getter,
+ setter,
+}
+
+enum MethodModifier {
+ async,
+ asyncStar,
+ syncStar,
+}
+
+abstract class Parameter extends Object
+ with HasAnnotations, HasGenerics, HasDartDocs
+ implements Built<Parameter, ParameterBuilder> {
+ factory Parameter([void Function(ParameterBuilder) updates]) = _$Parameter;
+
+ Parameter._();
+
+ /// If not `null`, a default assignment if the parameter is optional.
+ Code? get defaultTo;
+
+ /// Name of the parameter.
+ String get name;
+
+ /// Whether this parameter should be named, if optional.
+ bool get named;
+
+ /// Whether this parameter should be field formal (i.e. `this.`).
+ ///
+ /// This is only valid on constructors;
+ bool get toThis;
+
+ /// Whether this parameter should be passed to super\
+ /// constructor (i.e. `super.`).
+ ///
+ /// This is only valid on constructors;
+ bool get toSuper;
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ @override
+ BuiltList<Reference> get types;
+
+ /// Type of the parameter;
+ Reference? get type;
+
+ /// Whether this parameter should be annotated with the `required` keyword.
+ ///
+ /// This is only valid on named parameters.
+ ///
+ /// This is only valid when the output is targeting a Dart language version
+ /// that supports null safety.
+ bool get required;
+
+ /// Whether this parameter should be annotated with the `covariant` keyword.
+ ///
+ /// This is only valid on instance methods.
+ bool get covariant;
+}
+
+abstract class ParameterBuilder extends Object
+ with HasAnnotationsBuilder, HasGenericsBuilder, HasDartDocsBuilder
+ implements Builder<Parameter, ParameterBuilder> {
+ factory ParameterBuilder() = _$ParameterBuilder;
+
+ ParameterBuilder._();
+
+ @override
+ void update(void Function(ParameterBuilder)? updates) {
+ updates?.call(this);
+ }
+
+ /// If not `null`, a default assignment if the parameter is optional.
+ Code? defaultTo;
+
+ /// Name of the parameter.
+ late final String name;
+
+ /// Whether this parameter should be named, if optional.
+ bool named = false;
+
+ /// Whether this parameter should be field formal (i.e. `this.`).
+ ///
+ /// This is only valid on constructors;
+ bool toThis = false;
+
+ /// Whether this parameter should be passed to super\
+ /// constructor (i.e. `super.`).
+ ///
+ /// This is only valid on constructors;
+ bool toSuper = false;
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ /// Type of the parameter;
+ Reference? type;
+
+ /// Whether this parameter should be annotated with the `required` keyword.
+ ///
+ /// This is only valid on named parameters.
+ ///
+ /// This is only valid when the output is targeting a Dart language version
+ /// that supports null safety.
+ bool required = false;
+
+ /// Whether this parameter should be annotated with the `covariant` keyword.
+ ///
+ /// This is only valid on instance methods.
+ bool covariant = false;
+}
diff --git a/pkgs/code_builder/lib/src/specs/method.g.dart b/pkgs/code_builder/lib/src/specs/method.g.dart
new file mode 100644
index 0000000..214f6b2
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/method.g.dart
@@ -0,0 +1,697 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'method.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Method extends Method {
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final BuiltList<Parameter> optionalParameters;
+ @override
+ final BuiltList<Parameter> requiredParameters;
+ @override
+ final Code? body;
+ @override
+ final bool external;
+ @override
+ final bool? lambda;
+ @override
+ final bool static;
+ @override
+ final String? name;
+ @override
+ final MethodType? type;
+ @override
+ final MethodModifier? modifier;
+ @override
+ final Reference? returns;
+
+ factory _$Method([void Function(MethodBuilder)? updates]) =>
+ (new MethodBuilder()..update(updates)).build() as _$Method;
+
+ _$Method._(
+ {required this.annotations,
+ required this.docs,
+ required this.types,
+ required this.optionalParameters,
+ required this.requiredParameters,
+ this.body,
+ required this.external,
+ this.lambda,
+ required this.static,
+ this.name,
+ this.type,
+ this.modifier,
+ this.returns})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'Method', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Method', 'docs');
+ BuiltValueNullFieldError.checkNotNull(types, r'Method', 'types');
+ BuiltValueNullFieldError.checkNotNull(
+ optionalParameters, r'Method', 'optionalParameters');
+ BuiltValueNullFieldError.checkNotNull(
+ requiredParameters, r'Method', 'requiredParameters');
+ BuiltValueNullFieldError.checkNotNull(external, r'Method', 'external');
+ BuiltValueNullFieldError.checkNotNull(static, r'Method', 'static');
+ }
+
+ @override
+ Method rebuild(void Function(MethodBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$MethodBuilder toBuilder() => new _$MethodBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Method &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ types == other.types &&
+ optionalParameters == other.optionalParameters &&
+ requiredParameters == other.requiredParameters &&
+ body == other.body &&
+ external == other.external &&
+ lambda == other.lambda &&
+ static == other.static &&
+ name == other.name &&
+ type == other.type &&
+ modifier == other.modifier &&
+ returns == other.returns;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, optionalParameters.hashCode);
+ _$hash = $jc(_$hash, requiredParameters.hashCode);
+ _$hash = $jc(_$hash, body.hashCode);
+ _$hash = $jc(_$hash, external.hashCode);
+ _$hash = $jc(_$hash, lambda.hashCode);
+ _$hash = $jc(_$hash, static.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jc(_$hash, type.hashCode);
+ _$hash = $jc(_$hash, modifier.hashCode);
+ _$hash = $jc(_$hash, returns.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Method')
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('types', types)
+ ..add('optionalParameters', optionalParameters)
+ ..add('requiredParameters', requiredParameters)
+ ..add('body', body)
+ ..add('external', external)
+ ..add('lambda', lambda)
+ ..add('static', static)
+ ..add('name', name)
+ ..add('type', type)
+ ..add('modifier', modifier)
+ ..add('returns', returns))
+ .toString();
+ }
+}
+
+class _$MethodBuilder extends MethodBuilder {
+ _$Method? _$v;
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ ListBuilder<Parameter> get optionalParameters {
+ _$this;
+ return super.optionalParameters;
+ }
+
+ @override
+ set optionalParameters(ListBuilder<Parameter> optionalParameters) {
+ _$this;
+ super.optionalParameters = optionalParameters;
+ }
+
+ @override
+ ListBuilder<Parameter> get requiredParameters {
+ _$this;
+ return super.requiredParameters;
+ }
+
+ @override
+ set requiredParameters(ListBuilder<Parameter> requiredParameters) {
+ _$this;
+ super.requiredParameters = requiredParameters;
+ }
+
+ @override
+ Code? get body {
+ _$this;
+ return super.body;
+ }
+
+ @override
+ set body(Code? body) {
+ _$this;
+ super.body = body;
+ }
+
+ @override
+ bool get external {
+ _$this;
+ return super.external;
+ }
+
+ @override
+ set external(bool external) {
+ _$this;
+ super.external = external;
+ }
+
+ @override
+ bool? get lambda {
+ _$this;
+ return super.lambda;
+ }
+
+ @override
+ set lambda(bool? lambda) {
+ _$this;
+ super.lambda = lambda;
+ }
+
+ @override
+ bool get static {
+ _$this;
+ return super.static;
+ }
+
+ @override
+ set static(bool static) {
+ _$this;
+ super.static = static;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ @override
+ MethodType? get type {
+ _$this;
+ return super.type;
+ }
+
+ @override
+ set type(MethodType? type) {
+ _$this;
+ super.type = type;
+ }
+
+ @override
+ MethodModifier? get modifier {
+ _$this;
+ return super.modifier;
+ }
+
+ @override
+ set modifier(MethodModifier? modifier) {
+ _$this;
+ super.modifier = modifier;
+ }
+
+ @override
+ Reference? get returns {
+ _$this;
+ return super.returns;
+ }
+
+ @override
+ set returns(Reference? returns) {
+ _$this;
+ super.returns = returns;
+ }
+
+ _$MethodBuilder() : super._();
+
+ MethodBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.types = $v.types.toBuilder();
+ super.optionalParameters = $v.optionalParameters.toBuilder();
+ super.requiredParameters = $v.requiredParameters.toBuilder();
+ super.body = $v.body;
+ super.external = $v.external;
+ super.lambda = $v.lambda;
+ super.static = $v.static;
+ super.name = $v.name;
+ super.type = $v.type;
+ super.modifier = $v.modifier;
+ super.returns = $v.returns;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Method other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Method;
+ }
+
+ @override
+ void update(void Function(MethodBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Method build() => _build();
+
+ _$Method _build() {
+ _$Method _$result;
+ try {
+ _$result = _$v ??
+ new _$Method._(
+ annotations: annotations.build(),
+ docs: docs.build(),
+ types: types.build(),
+ optionalParameters: optionalParameters.build(),
+ requiredParameters: requiredParameters.build(),
+ body: body,
+ external: BuiltValueNullFieldError.checkNotNull(
+ external, r'Method', 'external'),
+ lambda: lambda,
+ static: BuiltValueNullFieldError.checkNotNull(
+ static, r'Method', 'static'),
+ name: name,
+ type: type,
+ modifier: modifier,
+ returns: returns);
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+ _$failedField = 'types';
+ types.build();
+ _$failedField = 'optionalParameters';
+ optionalParameters.build();
+ _$failedField = 'requiredParameters';
+ requiredParameters.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Method', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+class _$Parameter extends Parameter {
+ @override
+ final Code? defaultTo;
+ @override
+ final String name;
+ @override
+ final bool named;
+ @override
+ final bool toThis;
+ @override
+ final bool toSuper;
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final Reference? type;
+ @override
+ final bool required;
+ @override
+ final bool covariant;
+
+ factory _$Parameter([void Function(ParameterBuilder)? updates]) =>
+ (new ParameterBuilder()..update(updates)).build() as _$Parameter;
+
+ _$Parameter._(
+ {this.defaultTo,
+ required this.name,
+ required this.named,
+ required this.toThis,
+ required this.toSuper,
+ required this.annotations,
+ required this.docs,
+ required this.types,
+ this.type,
+ required this.required,
+ required this.covariant})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(name, r'Parameter', 'name');
+ BuiltValueNullFieldError.checkNotNull(named, r'Parameter', 'named');
+ BuiltValueNullFieldError.checkNotNull(toThis, r'Parameter', 'toThis');
+ BuiltValueNullFieldError.checkNotNull(toSuper, r'Parameter', 'toSuper');
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'Parameter', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Parameter', 'docs');
+ BuiltValueNullFieldError.checkNotNull(types, r'Parameter', 'types');
+ BuiltValueNullFieldError.checkNotNull(required, r'Parameter', 'required');
+ BuiltValueNullFieldError.checkNotNull(covariant, r'Parameter', 'covariant');
+ }
+
+ @override
+ Parameter rebuild(void Function(ParameterBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$ParameterBuilder toBuilder() => new _$ParameterBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Parameter &&
+ defaultTo == other.defaultTo &&
+ name == other.name &&
+ named == other.named &&
+ toThis == other.toThis &&
+ toSuper == other.toSuper &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ types == other.types &&
+ type == other.type &&
+ required == other.required &&
+ covariant == other.covariant;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, defaultTo.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jc(_$hash, named.hashCode);
+ _$hash = $jc(_$hash, toThis.hashCode);
+ _$hash = $jc(_$hash, toSuper.hashCode);
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, type.hashCode);
+ _$hash = $jc(_$hash, required.hashCode);
+ _$hash = $jc(_$hash, covariant.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Parameter')
+ ..add('defaultTo', defaultTo)
+ ..add('name', name)
+ ..add('named', named)
+ ..add('toThis', toThis)
+ ..add('toSuper', toSuper)
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('types', types)
+ ..add('type', type)
+ ..add('required', required)
+ ..add('covariant', covariant))
+ .toString();
+ }
+}
+
+class _$ParameterBuilder extends ParameterBuilder {
+ _$Parameter? _$v;
+
+ @override
+ Code? get defaultTo {
+ _$this;
+ return super.defaultTo;
+ }
+
+ @override
+ set defaultTo(Code? defaultTo) {
+ _$this;
+ super.defaultTo = defaultTo;
+ }
+
+ @override
+ String get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String name) {
+ _$this;
+ super.name = name;
+ }
+
+ @override
+ bool get named {
+ _$this;
+ return super.named;
+ }
+
+ @override
+ set named(bool named) {
+ _$this;
+ super.named = named;
+ }
+
+ @override
+ bool get toThis {
+ _$this;
+ return super.toThis;
+ }
+
+ @override
+ set toThis(bool toThis) {
+ _$this;
+ super.toThis = toThis;
+ }
+
+ @override
+ bool get toSuper {
+ _$this;
+ return super.toSuper;
+ }
+
+ @override
+ set toSuper(bool toSuper) {
+ _$this;
+ super.toSuper = toSuper;
+ }
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ Reference? get type {
+ _$this;
+ return super.type;
+ }
+
+ @override
+ set type(Reference? type) {
+ _$this;
+ super.type = type;
+ }
+
+ @override
+ bool get required {
+ _$this;
+ return super.required;
+ }
+
+ @override
+ set required(bool required) {
+ _$this;
+ super.required = required;
+ }
+
+ @override
+ bool get covariant {
+ _$this;
+ return super.covariant;
+ }
+
+ @override
+ set covariant(bool covariant) {
+ _$this;
+ super.covariant = covariant;
+ }
+
+ _$ParameterBuilder() : super._();
+
+ ParameterBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.defaultTo = $v.defaultTo;
+ super.name = $v.name;
+ super.named = $v.named;
+ super.toThis = $v.toThis;
+ super.toSuper = $v.toSuper;
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.types = $v.types.toBuilder();
+ super.type = $v.type;
+ super.required = $v.required;
+ super.covariant = $v.covariant;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Parameter other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Parameter;
+ }
+
+ @override
+ void update(void Function(ParameterBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Parameter build() => _build();
+
+ _$Parameter _build() {
+ _$Parameter _$result;
+ try {
+ _$result = _$v ??
+ new _$Parameter._(
+ defaultTo: defaultTo,
+ name: BuiltValueNullFieldError.checkNotNull(
+ name, r'Parameter', 'name'),
+ named: BuiltValueNullFieldError.checkNotNull(
+ named, r'Parameter', 'named'),
+ toThis: BuiltValueNullFieldError.checkNotNull(
+ toThis, r'Parameter', 'toThis'),
+ toSuper: BuiltValueNullFieldError.checkNotNull(
+ toSuper, r'Parameter', 'toSuper'),
+ annotations: annotations.build(),
+ docs: docs.build(),
+ types: types.build(),
+ type: type,
+ required: BuiltValueNullFieldError.checkNotNull(
+ required, r'Parameter', 'required'),
+ covariant: BuiltValueNullFieldError.checkNotNull(
+ covariant, r'Parameter', 'covariant'));
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+ _$failedField = 'types';
+ types.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Parameter', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/mixin.dart b/pkgs/code_builder/lib/src/specs/mixin.dart
new file mode 100644
index 0000000..e666bdd
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/mixin.dart
@@ -0,0 +1,88 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'expression.dart';
+import 'field.dart';
+import 'method.dart';
+import 'reference.dart';
+
+part 'mixin.g.dart';
+
+@immutable
+abstract class Mixin extends Object
+ with HasAnnotations, HasDartDocs, HasGenerics
+ implements Built<Mixin, MixinBuilder>, Spec {
+ factory Mixin([void Function(MixinBuilder b) updates]) = _$Mixin;
+
+ Mixin._();
+
+ /// Whether the mixin is a `base mixin`.
+ bool get base;
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ Reference? get on;
+
+ BuiltList<Reference> get implements;
+
+ @override
+ BuiltList<Reference> get types;
+
+ BuiltList<Method> get methods;
+ BuiltList<Field> get fields;
+
+ /// Name of the mixin.
+ String get name;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitMixin(this, context);
+}
+
+abstract class MixinBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
+ implements Builder<Mixin, MixinBuilder> {
+ factory MixinBuilder() = _$MixinBuilder;
+
+ MixinBuilder._();
+
+ /// Whether the mixin is a `base mixin`.
+ bool base = false;
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ Reference? on;
+
+ ListBuilder<Reference> implements = ListBuilder<Reference>();
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ ListBuilder<Method> methods = ListBuilder<Method>();
+
+ ListBuilder<Field> fields = ListBuilder<Field>();
+
+ /// Name of the mixin.
+ String? name;
+}
diff --git a/pkgs/code_builder/lib/src/specs/mixin.g.dart b/pkgs/code_builder/lib/src/specs/mixin.g.dart
new file mode 100644
index 0000000..28c7356
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/mixin.g.dart
@@ -0,0 +1,294 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'mixin.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Mixin extends Mixin {
+ @override
+ final bool base;
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final Reference? on;
+ @override
+ final BuiltList<Reference> implements;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final BuiltList<Method> methods;
+ @override
+ final BuiltList<Field> fields;
+ @override
+ final String name;
+
+ factory _$Mixin([void Function(MixinBuilder)? updates]) =>
+ (new MixinBuilder()..update(updates)).build() as _$Mixin;
+
+ _$Mixin._(
+ {required this.base,
+ required this.annotations,
+ required this.docs,
+ this.on,
+ required this.implements,
+ required this.types,
+ required this.methods,
+ required this.fields,
+ required this.name})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(base, r'Mixin', 'base');
+ BuiltValueNullFieldError.checkNotNull(annotations, r'Mixin', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'Mixin', 'docs');
+ BuiltValueNullFieldError.checkNotNull(implements, r'Mixin', 'implements');
+ BuiltValueNullFieldError.checkNotNull(types, r'Mixin', 'types');
+ BuiltValueNullFieldError.checkNotNull(methods, r'Mixin', 'methods');
+ BuiltValueNullFieldError.checkNotNull(fields, r'Mixin', 'fields');
+ BuiltValueNullFieldError.checkNotNull(name, r'Mixin', 'name');
+ }
+
+ @override
+ Mixin rebuild(void Function(MixinBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$MixinBuilder toBuilder() => new _$MixinBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Mixin &&
+ base == other.base &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ on == other.on &&
+ implements == other.implements &&
+ types == other.types &&
+ methods == other.methods &&
+ fields == other.fields &&
+ name == other.name;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, base.hashCode);
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, on.hashCode);
+ _$hash = $jc(_$hash, implements.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, methods.hashCode);
+ _$hash = $jc(_$hash, fields.hashCode);
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'Mixin')
+ ..add('base', base)
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('on', on)
+ ..add('implements', implements)
+ ..add('types', types)
+ ..add('methods', methods)
+ ..add('fields', fields)
+ ..add('name', name))
+ .toString();
+ }
+}
+
+class _$MixinBuilder extends MixinBuilder {
+ _$Mixin? _$v;
+
+ @override
+ bool get base {
+ _$this;
+ return super.base;
+ }
+
+ @override
+ set base(bool base) {
+ _$this;
+ super.base = base;
+ }
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ Reference? get on {
+ _$this;
+ return super.on;
+ }
+
+ @override
+ set on(Reference? on) {
+ _$this;
+ super.on = on;
+ }
+
+ @override
+ ListBuilder<Reference> get implements {
+ _$this;
+ return super.implements;
+ }
+
+ @override
+ set implements(ListBuilder<Reference> implements) {
+ _$this;
+ super.implements = implements;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ ListBuilder<Method> get methods {
+ _$this;
+ return super.methods;
+ }
+
+ @override
+ set methods(ListBuilder<Method> methods) {
+ _$this;
+ super.methods = methods;
+ }
+
+ @override
+ ListBuilder<Field> get fields {
+ _$this;
+ return super.fields;
+ }
+
+ @override
+ set fields(ListBuilder<Field> fields) {
+ _$this;
+ super.fields = fields;
+ }
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ _$MixinBuilder() : super._();
+
+ MixinBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.base = $v.base;
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.on = $v.on;
+ super.implements = $v.implements.toBuilder();
+ super.types = $v.types.toBuilder();
+ super.methods = $v.methods.toBuilder();
+ super.fields = $v.fields.toBuilder();
+ super.name = $v.name;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Mixin other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$Mixin;
+ }
+
+ @override
+ void update(void Function(MixinBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ Mixin build() => _build();
+
+ _$Mixin _build() {
+ _$Mixin _$result;
+ try {
+ _$result = _$v ??
+ new _$Mixin._(
+ base:
+ BuiltValueNullFieldError.checkNotNull(base, r'Mixin', 'base'),
+ annotations: annotations.build(),
+ docs: docs.build(),
+ on: on,
+ implements: implements.build(),
+ types: types.build(),
+ methods: methods.build(),
+ fields: fields.build(),
+ name: BuiltValueNullFieldError.checkNotNull(
+ name, r'Mixin', 'name'));
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+
+ _$failedField = 'implements';
+ implements.build();
+ _$failedField = 'types';
+ types.build();
+ _$failedField = 'methods';
+ methods.build();
+ _$failedField = 'fields';
+ fields.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'Mixin', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/reference.dart b/pkgs/code_builder/lib/src/specs/reference.dart
new file mode 100644
index 0000000..06032ad
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/reference.dart
@@ -0,0 +1,120 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../visitors.dart';
+import 'code.dart';
+import 'expression.dart';
+import 'type_reference.dart';
+
+/// Short-hand for `Reference(symbol, url)`.
+Reference refer(String symbol, [String? url]) => Reference(symbol, url);
+
+/// A reference to [symbol], such as a class, or top-level method or field.
+///
+/// References can be collected and collated in order to automatically generate
+/// `import` statements for all used symbols.
+@immutable
+class Reference extends Expression implements Spec {
+ /// Relative, `package:` or `dart:` URL of the library.
+ ///
+ /// May be omitted (`null`) in order to express "same library".
+ final String? url;
+
+ /// Name of the class, method, or field.
+ ///
+ /// May be `null` for references without symbols, for instance a function type
+ /// has no symbol.
+ final String? symbol;
+
+ /// Create a reference to [symbol] in [url].
+ const Reference(this.symbol, [this.url]);
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitReference(this, context);
+
+ @override
+ int get hashCode => '$url#$symbol'.hashCode;
+
+ @override
+ bool operator ==(Object other) =>
+ other is Reference && other.url == url && other.symbol == symbol;
+
+ /// Returns a new instance of this expression.
+ Expression newInstance(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression.newOf(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ );
+
+ /// Returns a new instance of this expression with a named constructor.
+ Expression newInstanceNamed(
+ String name,
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression.newOf(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ name,
+ );
+
+ /// Returns a const instance of this expression.
+ Expression constInstance(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression.constOf(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ );
+
+ /// Returns a const instance of this expression with a named constructor.
+ Expression constInstanceNamed(
+ String name,
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression.constOf(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ name,
+ );
+
+ @override
+ Expression get expression => CodeExpression(Code.scope((a) => a(this)));
+
+ @override
+ String toString() => (newBuiltValueToStringHelper('Reference')
+ ..add('url', url)
+ ..add('symbol', symbol))
+ .toString();
+
+ /// Returns as a [TypeReference], which allows adding generic type parameters.
+ Reference get type => TypeReference((b) => b
+ ..url = url
+ ..symbol = symbol);
+}
diff --git a/pkgs/code_builder/lib/src/specs/type_function.dart b/pkgs/code_builder/lib/src/specs/type_function.dart
new file mode 100644
index 0000000..be7c3ea
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/type_function.dart
@@ -0,0 +1,133 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'code.dart';
+import 'expression.dart';
+import 'reference.dart';
+
+part 'type_function.g.dart';
+
+@immutable
+abstract class FunctionType extends Expression
+ with HasGenerics
+ implements Built<FunctionType, FunctionTypeBuilder>, Reference, Spec {
+ factory FunctionType([
+ void Function(FunctionTypeBuilder) updates,
+ ]) = _$FunctionType;
+
+ FunctionType._();
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitFunctionType(this, context);
+
+ /// Return type.
+ Reference? get returnType;
+
+ @override
+ BuiltList<Reference> get types;
+
+ /// Required positional parameters of this function type.
+ BuiltList<Reference> get requiredParameters;
+
+ /// Optional positional parameters of this function type.
+ BuiltList<Reference> get optionalParameters;
+
+ /// Named optional parameters of this function type.
+ BuiltMap<String, Reference> get namedParameters;
+
+ /// Named required parameters of this function type.
+ BuiltMap<String, Reference> get namedRequiredParameters;
+
+ @override
+ String? get url => null;
+
+ @override
+ String? get symbol => null;
+
+ @override
+ Reference get type => this;
+
+ /// Optional nullability.
+ ///
+ /// An emitter may ignore this if the output is not targeting a Dart language
+ /// version that supports null safety.
+ bool? get isNullable;
+
+ @override
+ Expression newInstance(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ throw UnsupportedError('Cannot instantiate a function type.');
+
+ @override
+ Expression newInstanceNamed(
+ String name,
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ throw UnsupportedError('Cannot instantiate a function type.');
+
+ @override
+ Expression constInstance(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ throw UnsupportedError('Cannot "const" a function type.');
+
+ @override
+ Expression constInstanceNamed(
+ String name,
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ throw UnsupportedError('Cannot "const" a function type.');
+
+ /// A typedef assignment to this type.
+ Code toTypeDef(String name) => createTypeDef(name, this);
+}
+
+abstract class FunctionTypeBuilder extends Object
+ with HasGenericsBuilder
+ implements Builder<FunctionType, FunctionTypeBuilder> {
+ factory FunctionTypeBuilder() = _$FunctionTypeBuilder;
+
+ FunctionTypeBuilder._();
+
+ Reference? returnType;
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ ListBuilder<Reference> requiredParameters = ListBuilder<Reference>();
+
+ ListBuilder<Reference> optionalParameters = ListBuilder<Reference>();
+
+ MapBuilder<String, Reference> namedParameters =
+ MapBuilder<String, Reference>();
+
+ MapBuilder<String, Reference> namedRequiredParameters =
+ MapBuilder<String, Reference>();
+
+ bool? isNullable;
+
+ String? url;
+
+ String? symbol;
+}
diff --git a/pkgs/code_builder/lib/src/specs/type_function.g.dart b/pkgs/code_builder/lib/src/specs/type_function.g.dart
new file mode 100644
index 0000000..d09f59b
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/type_function.g.dart
@@ -0,0 +1,252 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'type_function.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$FunctionType extends FunctionType {
+ @override
+ final Reference? returnType;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final BuiltList<Reference> requiredParameters;
+ @override
+ final BuiltList<Reference> optionalParameters;
+ @override
+ final BuiltMap<String, Reference> namedParameters;
+ @override
+ final BuiltMap<String, Reference> namedRequiredParameters;
+ @override
+ final bool? isNullable;
+
+ factory _$FunctionType([void Function(FunctionTypeBuilder)? updates]) =>
+ (new FunctionTypeBuilder()..update(updates)).build() as _$FunctionType;
+
+ _$FunctionType._(
+ {this.returnType,
+ required this.types,
+ required this.requiredParameters,
+ required this.optionalParameters,
+ required this.namedParameters,
+ required this.namedRequiredParameters,
+ this.isNullable})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(types, r'FunctionType', 'types');
+ BuiltValueNullFieldError.checkNotNull(
+ requiredParameters, r'FunctionType', 'requiredParameters');
+ BuiltValueNullFieldError.checkNotNull(
+ optionalParameters, r'FunctionType', 'optionalParameters');
+ BuiltValueNullFieldError.checkNotNull(
+ namedParameters, r'FunctionType', 'namedParameters');
+ BuiltValueNullFieldError.checkNotNull(
+ namedRequiredParameters, r'FunctionType', 'namedRequiredParameters');
+ }
+
+ @override
+ FunctionType rebuild(void Function(FunctionTypeBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$FunctionTypeBuilder toBuilder() =>
+ new _$FunctionTypeBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is FunctionType &&
+ returnType == other.returnType &&
+ types == other.types &&
+ requiredParameters == other.requiredParameters &&
+ optionalParameters == other.optionalParameters &&
+ namedParameters == other.namedParameters &&
+ namedRequiredParameters == other.namedRequiredParameters &&
+ isNullable == other.isNullable;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, returnType.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, requiredParameters.hashCode);
+ _$hash = $jc(_$hash, optionalParameters.hashCode);
+ _$hash = $jc(_$hash, namedParameters.hashCode);
+ _$hash = $jc(_$hash, namedRequiredParameters.hashCode);
+ _$hash = $jc(_$hash, isNullable.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'FunctionType')
+ ..add('returnType', returnType)
+ ..add('types', types)
+ ..add('requiredParameters', requiredParameters)
+ ..add('optionalParameters', optionalParameters)
+ ..add('namedParameters', namedParameters)
+ ..add('namedRequiredParameters', namedRequiredParameters)
+ ..add('isNullable', isNullable))
+ .toString();
+ }
+}
+
+class _$FunctionTypeBuilder extends FunctionTypeBuilder {
+ _$FunctionType? _$v;
+
+ @override
+ Reference? get returnType {
+ _$this;
+ return super.returnType;
+ }
+
+ @override
+ set returnType(Reference? returnType) {
+ _$this;
+ super.returnType = returnType;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ ListBuilder<Reference> get requiredParameters {
+ _$this;
+ return super.requiredParameters;
+ }
+
+ @override
+ set requiredParameters(ListBuilder<Reference> requiredParameters) {
+ _$this;
+ super.requiredParameters = requiredParameters;
+ }
+
+ @override
+ ListBuilder<Reference> get optionalParameters {
+ _$this;
+ return super.optionalParameters;
+ }
+
+ @override
+ set optionalParameters(ListBuilder<Reference> optionalParameters) {
+ _$this;
+ super.optionalParameters = optionalParameters;
+ }
+
+ @override
+ MapBuilder<String, Reference> get namedParameters {
+ _$this;
+ return super.namedParameters;
+ }
+
+ @override
+ set namedParameters(MapBuilder<String, Reference> namedParameters) {
+ _$this;
+ super.namedParameters = namedParameters;
+ }
+
+ @override
+ MapBuilder<String, Reference> get namedRequiredParameters {
+ _$this;
+ return super.namedRequiredParameters;
+ }
+
+ @override
+ set namedRequiredParameters(
+ MapBuilder<String, Reference> namedRequiredParameters) {
+ _$this;
+ super.namedRequiredParameters = namedRequiredParameters;
+ }
+
+ @override
+ bool? get isNullable {
+ _$this;
+ return super.isNullable;
+ }
+
+ @override
+ set isNullable(bool? isNullable) {
+ _$this;
+ super.isNullable = isNullable;
+ }
+
+ _$FunctionTypeBuilder() : super._();
+
+ FunctionTypeBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.returnType = $v.returnType;
+ super.types = $v.types.toBuilder();
+ super.requiredParameters = $v.requiredParameters.toBuilder();
+ super.optionalParameters = $v.optionalParameters.toBuilder();
+ super.namedParameters = $v.namedParameters.toBuilder();
+ super.namedRequiredParameters = $v.namedRequiredParameters.toBuilder();
+ super.isNullable = $v.isNullable;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(FunctionType other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$FunctionType;
+ }
+
+ @override
+ void update(void Function(FunctionTypeBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ FunctionType build() => _build();
+
+ _$FunctionType _build() {
+ _$FunctionType _$result;
+ try {
+ _$result = _$v ??
+ new _$FunctionType._(
+ returnType: returnType,
+ types: types.build(),
+ requiredParameters: requiredParameters.build(),
+ optionalParameters: optionalParameters.build(),
+ namedParameters: namedParameters.build(),
+ namedRequiredParameters: namedRequiredParameters.build(),
+ isNullable: isNullable);
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'types';
+ types.build();
+ _$failedField = 'requiredParameters';
+ requiredParameters.build();
+ _$failedField = 'optionalParameters';
+ optionalParameters.build();
+ _$failedField = 'namedParameters';
+ namedParameters.build();
+ _$failedField = 'namedRequiredParameters';
+ namedRequiredParameters.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'FunctionType', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/type_record.dart b/pkgs/code_builder/lib/src/specs/type_record.dart
new file mode 100644
index 0000000..2f0594c
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/type_record.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../visitors.dart';
+import 'expression.dart';
+import 'reference.dart';
+
+part 'type_record.g.dart';
+
+@immutable
+abstract class RecordType extends Expression
+ implements Built<RecordType, RecordTypeBuilder>, Reference, Spec {
+ factory RecordType([
+ void Function(RecordTypeBuilder) updates,
+ ]) = _$RecordType;
+
+ RecordType._();
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitRecordType(this, context);
+
+ BuiltList<Reference> get positionalFieldTypes;
+
+ BuiltMap<String, Reference> get namedFieldTypes;
+
+ @override
+ String? get url => null;
+
+ @override
+ String? get symbol => null;
+
+ @override
+ Reference get type => this;
+
+ /// Optional nullability.
+ bool? get isNullable;
+
+ @override
+ Expression newInstance(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ throw UnsupportedError('Cannot instantiate a record type.');
+
+ @override
+ Expression newInstanceNamed(
+ String name,
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ throw UnsupportedError('Cannot instantiate a record type.');
+
+ @override
+ Expression constInstance(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ throw UnsupportedError('Cannot "const" a record type.');
+
+ @override
+ Expression constInstanceNamed(
+ String name,
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ throw UnsupportedError('Cannot "const" a record type.');
+}
+
+abstract class RecordTypeBuilder extends Object
+ implements Builder<RecordType, RecordTypeBuilder> {
+ factory RecordTypeBuilder() = _$RecordTypeBuilder;
+
+ RecordTypeBuilder._();
+
+ ListBuilder<Reference> positionalFieldTypes = ListBuilder<Reference>();
+
+ MapBuilder<String, Reference> namedFieldTypes =
+ MapBuilder<String, Reference>();
+
+ bool? isNullable;
+
+ String? url;
+
+ String? symbol;
+}
diff --git a/pkgs/code_builder/lib/src/specs/type_record.g.dart b/pkgs/code_builder/lib/src/specs/type_record.g.dart
new file mode 100644
index 0000000..b1d47df
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/type_record.g.dart
@@ -0,0 +1,159 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'type_record.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$RecordType extends RecordType {
+ @override
+ final BuiltList<Reference> positionalFieldTypes;
+ @override
+ final BuiltMap<String, Reference> namedFieldTypes;
+ @override
+ final bool? isNullable;
+
+ factory _$RecordType([void Function(RecordTypeBuilder)? updates]) =>
+ (new RecordTypeBuilder()..update(updates)).build() as _$RecordType;
+
+ _$RecordType._(
+ {required this.positionalFieldTypes,
+ required this.namedFieldTypes,
+ this.isNullable})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(
+ positionalFieldTypes, r'RecordType', 'positionalFieldTypes');
+ BuiltValueNullFieldError.checkNotNull(
+ namedFieldTypes, r'RecordType', 'namedFieldTypes');
+ }
+
+ @override
+ RecordType rebuild(void Function(RecordTypeBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$RecordTypeBuilder toBuilder() => new _$RecordTypeBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is RecordType &&
+ positionalFieldTypes == other.positionalFieldTypes &&
+ namedFieldTypes == other.namedFieldTypes &&
+ isNullable == other.isNullable;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, positionalFieldTypes.hashCode);
+ _$hash = $jc(_$hash, namedFieldTypes.hashCode);
+ _$hash = $jc(_$hash, isNullable.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'RecordType')
+ ..add('positionalFieldTypes', positionalFieldTypes)
+ ..add('namedFieldTypes', namedFieldTypes)
+ ..add('isNullable', isNullable))
+ .toString();
+ }
+}
+
+class _$RecordTypeBuilder extends RecordTypeBuilder {
+ _$RecordType? _$v;
+
+ @override
+ ListBuilder<Reference> get positionalFieldTypes {
+ _$this;
+ return super.positionalFieldTypes;
+ }
+
+ @override
+ set positionalFieldTypes(ListBuilder<Reference> positionalFieldTypes) {
+ _$this;
+ super.positionalFieldTypes = positionalFieldTypes;
+ }
+
+ @override
+ MapBuilder<String, Reference> get namedFieldTypes {
+ _$this;
+ return super.namedFieldTypes;
+ }
+
+ @override
+ set namedFieldTypes(MapBuilder<String, Reference> namedFieldTypes) {
+ _$this;
+ super.namedFieldTypes = namedFieldTypes;
+ }
+
+ @override
+ bool? get isNullable {
+ _$this;
+ return super.isNullable;
+ }
+
+ @override
+ set isNullable(bool? isNullable) {
+ _$this;
+ super.isNullable = isNullable;
+ }
+
+ _$RecordTypeBuilder() : super._();
+
+ RecordTypeBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.positionalFieldTypes = $v.positionalFieldTypes.toBuilder();
+ super.namedFieldTypes = $v.namedFieldTypes.toBuilder();
+ super.isNullable = $v.isNullable;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(RecordType other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$RecordType;
+ }
+
+ @override
+ void update(void Function(RecordTypeBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ RecordType build() => _build();
+
+ _$RecordType _build() {
+ _$RecordType _$result;
+ try {
+ _$result = _$v ??
+ new _$RecordType._(
+ positionalFieldTypes: positionalFieldTypes.build(),
+ namedFieldTypes: namedFieldTypes.build(),
+ isNullable: isNullable);
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'positionalFieldTypes';
+ positionalFieldTypes.build();
+ _$failedField = 'namedFieldTypes';
+ namedFieldTypes.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'RecordType', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/type_reference.dart b/pkgs/code_builder/lib/src/specs/type_reference.dart
new file mode 100644
index 0000000..74c7840
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/type_reference.dart
@@ -0,0 +1,138 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'code.dart';
+import 'expression.dart';
+import 'reference.dart';
+
+part 'type_reference.g.dart';
+
+@immutable
+abstract class TypeReference extends Expression
+ with HasGenerics
+ implements Built<TypeReference, TypeReferenceBuilder>, Reference, Spec {
+ factory TypeReference([
+ void Function(TypeReferenceBuilder) updates,
+ ]) = _$TypeReference;
+
+ TypeReference._();
+
+ @override
+ String get symbol;
+
+ @override
+ String? get url;
+
+ /// Optional bound generic.
+ Reference? get bound;
+
+ @override
+ BuiltList<Reference> get types;
+
+ /// Optional nullability.
+ ///
+ /// An emitter may ignore this if the output is not targeting a Dart language
+ /// version that supports null safety.
+ bool? get isNullable;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitType(this, context);
+
+ @override
+ Expression get expression => CodeExpression(Code.scope((a) => a(this)));
+
+ @override
+ TypeReference get type => this;
+
+ @override
+ Expression newInstance(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression.newOf(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ );
+
+ @override
+ Expression newInstanceNamed(
+ String name,
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression.newOf(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ name,
+ );
+
+ @override
+ Expression constInstance(
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression.constOf(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ );
+
+ @override
+ Expression constInstanceNamed(
+ String name,
+ Iterable<Expression> positionalArguments, [
+ Map<String, Expression> namedArguments = const {},
+ List<Reference> typeArguments = const [],
+ ]) =>
+ InvokeExpression.constOf(
+ this,
+ positionalArguments.toList(),
+ namedArguments,
+ typeArguments,
+ name,
+ );
+}
+
+abstract class TypeReferenceBuilder extends Object
+ with HasGenericsBuilder
+ implements Builder<TypeReference, TypeReferenceBuilder> {
+ factory TypeReferenceBuilder() = _$TypeReferenceBuilder;
+
+ TypeReferenceBuilder._();
+
+ String? symbol;
+
+ String? url;
+
+ /// Optional bound generic.
+ Reference? bound;
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ /// Optional nullability.
+ ///
+ /// An emitter may ignore this if the output is not targeting a Dart language
+ /// version that supports null safety.
+ bool? isNullable;
+}
diff --git a/pkgs/code_builder/lib/src/specs/type_reference.g.dart b/pkgs/code_builder/lib/src/specs/type_reference.g.dart
new file mode 100644
index 0000000..124e8b4
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/type_reference.g.dart
@@ -0,0 +1,197 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'type_reference.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$TypeReference extends TypeReference {
+ @override
+ final String symbol;
+ @override
+ final String? url;
+ @override
+ final Reference? bound;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final bool? isNullable;
+
+ factory _$TypeReference([void Function(TypeReferenceBuilder)? updates]) =>
+ (new TypeReferenceBuilder()..update(updates)).build() as _$TypeReference;
+
+ _$TypeReference._(
+ {required this.symbol,
+ this.url,
+ this.bound,
+ required this.types,
+ this.isNullable})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(symbol, r'TypeReference', 'symbol');
+ BuiltValueNullFieldError.checkNotNull(types, r'TypeReference', 'types');
+ }
+
+ @override
+ TypeReference rebuild(void Function(TypeReferenceBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$TypeReferenceBuilder toBuilder() =>
+ new _$TypeReferenceBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is TypeReference &&
+ symbol == other.symbol &&
+ url == other.url &&
+ bound == other.bound &&
+ types == other.types &&
+ isNullable == other.isNullable;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, symbol.hashCode);
+ _$hash = $jc(_$hash, url.hashCode);
+ _$hash = $jc(_$hash, bound.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jc(_$hash, isNullable.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'TypeReference')
+ ..add('symbol', symbol)
+ ..add('url', url)
+ ..add('bound', bound)
+ ..add('types', types)
+ ..add('isNullable', isNullable))
+ .toString();
+ }
+}
+
+class _$TypeReferenceBuilder extends TypeReferenceBuilder {
+ _$TypeReference? _$v;
+
+ @override
+ String? get symbol {
+ _$this;
+ return super.symbol;
+ }
+
+ @override
+ set symbol(String? symbol) {
+ _$this;
+ super.symbol = symbol;
+ }
+
+ @override
+ String? get url {
+ _$this;
+ return super.url;
+ }
+
+ @override
+ set url(String? url) {
+ _$this;
+ super.url = url;
+ }
+
+ @override
+ Reference? get bound {
+ _$this;
+ return super.bound;
+ }
+
+ @override
+ set bound(Reference? bound) {
+ _$this;
+ super.bound = bound;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ bool? get isNullable {
+ _$this;
+ return super.isNullable;
+ }
+
+ @override
+ set isNullable(bool? isNullable) {
+ _$this;
+ super.isNullable = isNullable;
+ }
+
+ _$TypeReferenceBuilder() : super._();
+
+ TypeReferenceBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.symbol = $v.symbol;
+ super.url = $v.url;
+ super.bound = $v.bound;
+ super.types = $v.types.toBuilder();
+ super.isNullable = $v.isNullable;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(TypeReference other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$TypeReference;
+ }
+
+ @override
+ void update(void Function(TypeReferenceBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ TypeReference build() => _build();
+
+ _$TypeReference _build() {
+ _$TypeReference _$result;
+ try {
+ _$result = _$v ??
+ new _$TypeReference._(
+ symbol: BuiltValueNullFieldError.checkNotNull(
+ symbol, r'TypeReference', 'symbol'),
+ url: url,
+ bound: bound,
+ types: types.build(),
+ isNullable: isNullable);
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'types';
+ types.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'TypeReference', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/specs/typedef.dart b/pkgs/code_builder/lib/src/specs/typedef.dart
new file mode 100644
index 0000000..fe5d8f1
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/typedef.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_collection/built_collection.dart';
+import 'package:built_value/built_value.dart';
+import 'package:meta/meta.dart';
+
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'expression.dart';
+import 'reference.dart';
+
+part 'typedef.g.dart';
+
+@immutable
+abstract class TypeDef extends Object
+ with HasAnnotations, HasDartDocs, HasGenerics
+ implements Built<TypeDef, TypeDefBuilder>, Spec {
+ factory TypeDef([void Function(TypeDefBuilder)? updates]) = _$TypeDef;
+
+ TypeDef._();
+
+ /// Name of the typedef.
+ String get name;
+
+ /// The right hand side of the typedef.
+ ///
+ /// Typically a reference to a type, or a Function type.
+ Expression get definition;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R? context,
+ ]) =>
+ visitor.visitTypeDef(this, context);
+}
+
+abstract class TypeDefBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
+ implements Builder<TypeDef, TypeDefBuilder> {
+ factory TypeDefBuilder() = _$TypeDefBuilder;
+
+ TypeDefBuilder._();
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ String? name;
+
+ Expression? definition;
+}
diff --git a/pkgs/code_builder/lib/src/specs/typedef.g.dart b/pkgs/code_builder/lib/src/specs/typedef.g.dart
new file mode 100644
index 0000000..8c2a16c
--- /dev/null
+++ b/pkgs/code_builder/lib/src/specs/typedef.g.dart
@@ -0,0 +1,205 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'typedef.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$TypeDef extends TypeDef {
+ @override
+ final String name;
+ @override
+ final Expression definition;
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final BuiltList<Reference> types;
+
+ factory _$TypeDef([void Function(TypeDefBuilder)? updates]) =>
+ (new TypeDefBuilder()..update(updates)).build() as _$TypeDef;
+
+ _$TypeDef._(
+ {required this.name,
+ required this.definition,
+ required this.annotations,
+ required this.docs,
+ required this.types})
+ : super._() {
+ BuiltValueNullFieldError.checkNotNull(name, r'TypeDef', 'name');
+ BuiltValueNullFieldError.checkNotNull(definition, r'TypeDef', 'definition');
+ BuiltValueNullFieldError.checkNotNull(
+ annotations, r'TypeDef', 'annotations');
+ BuiltValueNullFieldError.checkNotNull(docs, r'TypeDef', 'docs');
+ BuiltValueNullFieldError.checkNotNull(types, r'TypeDef', 'types');
+ }
+
+ @override
+ TypeDef rebuild(void Function(TypeDefBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$TypeDefBuilder toBuilder() => new _$TypeDefBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is TypeDef &&
+ name == other.name &&
+ definition == other.definition &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ types == other.types;
+ }
+
+ @override
+ int get hashCode {
+ var _$hash = 0;
+ _$hash = $jc(_$hash, name.hashCode);
+ _$hash = $jc(_$hash, definition.hashCode);
+ _$hash = $jc(_$hash, annotations.hashCode);
+ _$hash = $jc(_$hash, docs.hashCode);
+ _$hash = $jc(_$hash, types.hashCode);
+ _$hash = $jf(_$hash);
+ return _$hash;
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper(r'TypeDef')
+ ..add('name', name)
+ ..add('definition', definition)
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('types', types))
+ .toString();
+ }
+}
+
+class _$TypeDefBuilder extends TypeDefBuilder {
+ _$TypeDef? _$v;
+
+ @override
+ String? get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String? name) {
+ _$this;
+ super.name = name;
+ }
+
+ @override
+ Expression? get definition {
+ _$this;
+ return super.definition;
+ }
+
+ @override
+ set definition(Expression? definition) {
+ _$this;
+ super.definition = definition;
+ }
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations;
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs;
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types;
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ _$TypeDefBuilder() : super._();
+
+ TypeDefBuilder get _$this {
+ final $v = _$v;
+ if ($v != null) {
+ super.name = $v.name;
+ super.definition = $v.definition;
+ super.annotations = $v.annotations.toBuilder();
+ super.docs = $v.docs.toBuilder();
+ super.types = $v.types.toBuilder();
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(TypeDef other) {
+ ArgumentError.checkNotNull(other, 'other');
+ _$v = other as _$TypeDef;
+ }
+
+ @override
+ void update(void Function(TypeDefBuilder)? updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ TypeDef build() => _build();
+
+ _$TypeDef _build() {
+ _$TypeDef _$result;
+ try {
+ _$result = _$v ??
+ new _$TypeDef._(
+ name: BuiltValueNullFieldError.checkNotNull(
+ name, r'TypeDef', 'name'),
+ definition: BuiltValueNullFieldError.checkNotNull(
+ definition, r'TypeDef', 'definition'),
+ annotations: annotations.build(),
+ docs: docs.build(),
+ types: types.build());
+ } catch (_) {
+ late String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+ _$failedField = 'types';
+ types.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ r'TypeDef', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: deprecated_member_use_from_same_package,type=lint
diff --git a/pkgs/code_builder/lib/src/visitors.dart b/pkgs/code_builder/lib/src/visitors.dart
new file mode 100644
index 0000000..10fe0d8
--- /dev/null
+++ b/pkgs/code_builder/lib/src/visitors.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:meta/meta.dart';
+
+import 'base.dart';
+import 'specs/class.dart';
+import 'specs/constructor.dart';
+import 'specs/directive.dart';
+import 'specs/enum.dart';
+import 'specs/expression.dart';
+import 'specs/extension.dart';
+import 'specs/extension_type.dart';
+import 'specs/field.dart';
+import 'specs/library.dart';
+import 'specs/method.dart';
+import 'specs/mixin.dart';
+import 'specs/reference.dart';
+import 'specs/type_function.dart';
+import 'specs/type_record.dart';
+import 'specs/type_reference.dart';
+import 'specs/typedef.dart';
+
+@optionalTypeArgs
+abstract class SpecVisitor<T> {
+ const SpecVisitor._();
+
+ T visitAnnotation(Expression spec, [T? context]);
+
+ T visitClass(Class spec, [T? context]);
+
+ T visitMixin(Mixin spec, [T? context]);
+
+ T visitExtension(Extension spec, [T? context]);
+
+ T visitExtensionType(ExtensionType spec, [T? context]);
+
+ T visitEnum(Enum spec, [T? context]);
+
+ T visitConstructor(Constructor spec, String clazz, [T? context]);
+
+ T visitDirective(Directive spec, [T? context]);
+
+ T visitField(Field spec, [T? context]);
+
+ T visitLibrary(Library spec, [T? context]);
+
+ T visitFunctionType(FunctionType spec, [T? context]);
+
+ T visitTypeDef(TypeDef spec, [T? context]);
+
+ T visitMethod(Method spec, [T? context]);
+
+ T visitRecordType(RecordType spec, [T? context]);
+
+ T visitReference(Reference spec, [T? context]);
+
+ T visitSpec(Spec spec, [T? context]);
+
+ T visitType(TypeReference spec, [T? context]);
+
+ T visitTypeParameters(Iterable<Reference> specs, [T? context]);
+}
diff --git a/pkgs/code_builder/pubspec.yaml b/pkgs/code_builder/pubspec.yaml
new file mode 100644
index 0000000..9fb58cc
--- /dev/null
+++ b/pkgs/code_builder/pubspec.yaml
@@ -0,0 +1,24 @@
+name: code_builder
+version: 4.10.1
+description: A fluent, builder-based library for generating valid Dart code.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/code_builder
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acode_builder
+
+environment:
+ sdk: ^3.5.0
+
+dependencies:
+ built_collection: ^5.0.0
+ built_value: ^8.0.0
+ collection: ^1.15.0
+ matcher: ^0.12.10
+ meta: ^1.3.0
+
+dev_dependencies:
+ build: ^2.0.0
+ build_runner: ^2.0.3
+ built_value_generator: ^8.0.0
+ dart_flutter_team_lints: ^3.0.0
+ dart_style: ^2.3.7
+ source_gen: ^1.0.0
+ test: ^1.16.0
diff --git a/pkgs/code_builder/test/allocator_test.dart b/pkgs/code_builder/test/allocator_test.dart
new file mode 100644
index 0000000..09f135c
--- /dev/null
+++ b/pkgs/code_builder/test/allocator_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import 'common.dart';
+
+void main() {
+ useDartfmt();
+
+ group('Allocator', () {
+ Allocator allocator;
+
+ test('should return the exact (non-prefixed) symbol', () {
+ allocator = Allocator();
+ expect(allocator.allocate(refer('Foo', 'package:foo')), 'Foo');
+ });
+
+ test('should collect import URLs', () {
+ allocator = Allocator()
+ ..allocate(refer('List', 'dart:core'))
+ ..allocate(refer('LinkedHashMap', 'dart:collection'))
+ ..allocate(refer('someSymbol'));
+ expect(allocator.imports.map((d) => d.url), [
+ 'dart:core',
+ 'dart:collection',
+ ]);
+ });
+
+ test('.none should do nothing', () {
+ allocator = Allocator.none;
+ expect(allocator.allocate(refer('Foo', 'package:foo')), 'Foo');
+ expect(allocator.imports, isEmpty);
+ });
+
+ test('.simplePrefixing should add import prefixes', () {
+ allocator = Allocator.simplePrefixing();
+ expect(
+ allocator.allocate(refer('List', 'dart:core')),
+ 'List',
+ );
+ expect(
+ allocator.allocate(refer('LinkedHashMap', 'dart:collection')),
+ '_i1.LinkedHashMap',
+ );
+ expect(allocator.imports.map((d) => '${d.url} as ${d.as}'), [
+ 'dart:collection as _i1',
+ ]);
+ });
+ });
+}
diff --git a/pkgs/code_builder/test/common.dart b/pkgs/code_builder/test/common.dart
new file mode 100644
index 0000000..b1db8d0
--- /dev/null
+++ b/pkgs/code_builder/test/common.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:dart_style/dart_style.dart';
+
+String _format(String source) {
+ final formatter = DartFormatter(
+ languageVersion: DartFormatter.latestLanguageVersion,
+ );
+
+ try {
+ return formatter.format(source);
+ } on FormatterException catch (_) {
+ return formatter.formatStatement(source);
+ }
+}
+
+/// Should be invoked in `main()` of every test in `test/**_test.dart`.
+void useDartfmt() => EqualsDart.format = _format;
diff --git a/pkgs/code_builder/test/const_test.dart b/pkgs/code_builder/test/const_test.dart
new file mode 100644
index 0000000..c4d69c6
--- /dev/null
+++ b/pkgs/code_builder/test/const_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import 'common.dart';
+
+void main() {
+ useDartfmt();
+
+ final constMap = literalConstMap({
+ 'list': literalConstList([]),
+ 'duration': refer('Duration').constInstance([]),
+ });
+
+ test('expression', () {
+ expect(constMap, equalsDart(r'''
+ const {'list': [], 'duration': Duration(), }'''));
+ });
+
+ test('assignConst', () {
+ expect(
+ // ignore: deprecated_member_use_from_same_package
+ constMap.assignConst('constField'),
+ equalsDart(r'''
+ const constField = {'list': [], 'duration': Duration(), }''',
+ DartEmitter.scoped()),
+ );
+ });
+
+ test('assign to declared constant', () {
+ expect(
+ declareConst('constField').assign(constMap),
+ equalsDart(r'''
+ const constField = {'list': [], 'duration': Duration(), }''',
+ DartEmitter.scoped()),
+ );
+ });
+
+ test('assign to declared non-constant', () {
+ expect(
+ declareVar('varField').assign(constMap),
+ equalsDart(r'''
+ var varField = const {'list': [], 'duration': Duration(), }''',
+ DartEmitter.scoped()));
+ });
+
+ final library = Library((b) => b
+ ..body.add(Field((b) => b
+ ..name = 'val1'
+ ..modifier = FieldModifier.constant
+ ..assignment = refer('ConstClass').constInstance([]).code))
+ ..body.add(Field((b) => b
+ ..name = 'val2'
+ ..modifier = FieldModifier.constant
+ ..assignment =
+ refer('ConstClass').constInstanceNamed('other', []).code)));
+
+ test('should emit a source file with imports in defined order', () {
+ expect(
+ library,
+ equalsDart(r'''
+ const val1 = ConstClass();
+ const val2 = ConstClass.other();'''),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/directive_test.dart b/pkgs/code_builder/test/directive_test.dart
new file mode 100644
index 0000000..0aee6ae
--- /dev/null
+++ b/pkgs/code_builder/test/directive_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import 'common.dart';
+
+void main() {
+ useDartfmt();
+
+ final $LinkedHashMap = refer('LinkedHashMap', 'dart:collection');
+
+ final library = Library((b) => b
+ ..directives.add(Directive.export('../relative.dart'))
+ ..directives.add(Directive.export('package:foo/foo.dart'))
+ ..directives.add(Directive.part('lib.g.dart'))
+ ..body.add(Field((b) => b
+ ..name = 'relativeRef'
+ ..modifier = FieldModifier.final$
+ ..assignment =
+ refer('Relative', '../relative.dart').newInstance([]).code))
+ ..body.add(Field((b) => b
+ ..name = 'pkgRefFoo'
+ ..modifier = FieldModifier.final$
+ ..assignment = refer('Foo', 'package:foo/foo.dart').newInstance([]).code))
+ ..body.add(Field((b) => b
+ ..name = 'pkgRefBar'
+ ..modifier = FieldModifier.final$
+ ..assignment = refer('Bar', 'package:foo/bar.dart').newInstance([]).code))
+ ..body.add(Field((b) => b
+ ..name = 'collectionRef'
+ ..modifier = FieldModifier.final$
+ ..assignment = $LinkedHashMap.newInstance([]).code)));
+
+ test('should emit a source file with imports in defined order', () {
+ expect(
+ library,
+ equalsDart(r'''
+ // ignore_for_file: no_leading_underscores_for_library_prefixes
+ import '../relative.dart' as _i1;
+ import 'package:foo/foo.dart' as _i2;
+ import 'package:foo/bar.dart' as _i3;
+ import 'dart:collection' as _i4;
+ export '../relative.dart';
+ export 'package:foo/foo.dart';
+ part 'lib.g.dart';
+
+ final relativeRef = _i1.Relative();
+ final pkgRefFoo = _i2.Foo();
+ final pkgRefBar = _i3.Bar();
+ final collectionRef = _i4.LinkedHashMap();''', DartEmitter.scoped()),
+ );
+ });
+
+ test('should emit a source file with ordered', () {
+ expect(
+ library,
+ equalsDart(r'''
+ // ignore_for_file: no_leading_underscores_for_library_prefixes
+ import 'dart:collection' as _i4;
+
+ import 'package:foo/bar.dart' as _i3;
+ import 'package:foo/foo.dart' as _i2;
+
+ import '../relative.dart' as _i1;
+
+ export 'package:foo/foo.dart';
+ export '../relative.dart';
+
+ part 'lib.g.dart';
+
+ final relativeRef = _i1.Relative();
+ final pkgRefFoo = _i2.Foo();
+ final pkgRefBar = _i3.Bar();
+ final collectionRef = _i4.LinkedHashMap();''',
+ DartEmitter.scoped(orderDirectives: true)),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/e2e/injection_test.dart b/pkgs/code_builder/test/e2e/injection_test.dart
new file mode 100644
index 0000000..129f02c
--- /dev/null
+++ b/pkgs/code_builder/test/e2e/injection_test.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should generate a complex generated file', () {
+ // Imports from an existing Dart library.
+ final $App = refer('App', 'package:app/app.dart');
+ final $Module = refer('Module', 'package:app/module.dart');
+ final $Thing = refer('Thing', 'package:app/thing.dart');
+
+ final clazz = ClassBuilder()
+ ..name = 'Injector'
+ ..implements.add($App)
+ ..fields.add(Field((b) => b
+ ..modifier = FieldModifier.final$
+ ..name = '_module'
+ ..type = $Module.type))
+ ..constructors.add(Constructor((b) => b
+ ..requiredParameters.add(Parameter((b) => b
+ ..name = '_module'
+ ..toThis = true))))
+ ..methods.add(Method((b) => b
+ ..name = 'getThing'
+ ..body = $Thing.newInstance([
+ refer('_module').property('get1').call([]),
+ refer('_module').property('get2').call([]),
+ ]).code
+ ..returns = $Thing
+ ..annotations.add(refer('override'))));
+
+ expect(
+ clazz.build(),
+ equalsDart(r'''
+ class Injector implements App {
+ Injector(this._module);
+
+ final Module _module;
+
+ @override
+ Thing getThing() => Thing(_module.get1(), _module.get2(), );
+ }
+ '''),
+ );
+
+ expect(
+ clazz.build(),
+ equalsDart(r'''
+ class Injector implements _i1.App {
+ Injector(this._module);
+
+ final _i2.Module _module;
+
+ @override
+ _i3.Thing getThing() => _i3.Thing(_module.get1(), _module.get2(), );
+ }
+ ''', DartEmitter(allocator: Allocator.simplePrefixing())),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/matcher_test.dart b/pkgs/code_builder/test/matcher_test.dart
new file mode 100644
index 0000000..c9475a8
--- /dev/null
+++ b/pkgs/code_builder/test/matcher_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('describes mismatches', () {
+ const actual = Code('final x=1;');
+ equalsDart('final y=2;').expectMismatch(actual, '''
+ Expected: final y=2;
+ Actual: StaticCode:<final x=1;>
+ Which: is different.
+ Expected: final y=2;
+ Actual: final x=1;
+ ^
+ Differ at offset 6
+''');
+ });
+}
+
+extension on Matcher {
+ void expectMismatch(dynamic actual, String mismatch) {
+ expect(
+ () => expect(actual, this),
+ throwsA(isA<TestFailure>().having(
+ (e) => e.message, 'message', equalsIgnoringWhitespace(mismatch))));
+ }
+}
diff --git a/pkgs/code_builder/test/specs/class_test.dart b/pkgs/code_builder/test/specs/class_test.dart
new file mode 100644
index 0000000..562bca4
--- /dev/null
+++ b/pkgs/code_builder/test/specs/class_test.dart
@@ -0,0 +1,484 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should create a class', () {
+ expect(
+ Class((b) => b..name = 'Foo'),
+ equalsDart(r'''
+ class Foo {}
+ '''),
+ );
+ });
+
+ test('should create an abstract class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..abstract = true),
+ equalsDart(r'''
+ abstract class Foo {}
+ '''),
+ );
+ });
+
+ test('should create an abstract base class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..abstract = true
+ ..modifier = ClassModifier.base),
+ equalsDart(r'''
+ abstract base class Foo {}
+ '''),
+ );
+ });
+
+ test('should create a final class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..modifier = ClassModifier.final$),
+ equalsDart(r'''
+ final class Foo {}
+ '''),
+ );
+ });
+
+ test('should create a sealed class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..sealed = true),
+ equalsDart(r'''
+ sealed class Foo {}
+ '''),
+ );
+ });
+
+ test('should create an abstract interface class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..abstract = true
+ ..modifier = ClassModifier.interface),
+ equalsDart(r'''
+ abstract interface class Foo {}
+ '''),
+ );
+ });
+
+ test('should create a mixin class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..mixin = true),
+ equalsDart(r'''
+ mixin class Foo {}
+ '''),
+ );
+ });
+
+ test('should create an abstract mixin class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..abstract = true
+ ..mixin = true),
+ equalsDart(r'''
+ abstract mixin class Foo {}
+ '''),
+ );
+ });
+
+ test('should create a base mixin class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..mixin = true
+ ..modifier = ClassModifier.base),
+ equalsDart(r'''
+ base mixin class Foo {}
+ '''),
+ );
+ });
+
+ test('should create an abstract base mixin class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..abstract = true
+ ..mixin = true
+ ..modifier = ClassModifier.base),
+ equalsDart(r'''
+ abstract base mixin class Foo {}
+ '''),
+ );
+ });
+
+ test('should create a class with documentations', () {
+ expect(
+ Class(
+ (b) => b
+ ..name = 'Foo'
+ ..docs.addAll(
+ const [
+ '/// My favorite class.',
+ ],
+ ),
+ ),
+ equalsDart(r'''
+ /// My favorite class.
+ class Foo {}
+ '''),
+ );
+ });
+
+ test('should create a class with annotations', () {
+ expect(
+ Class(
+ (b) => b
+ ..name = 'Foo'
+ ..annotations.addAll([
+ refer('deprecated'),
+ refer('Deprecated').call([literalString('This is an old class')])
+ ]),
+ ),
+ equalsDart(r'''
+ @deprecated
+ @Deprecated('This is an old class')
+ class Foo {}
+ '''),
+ );
+ });
+
+ test('should create a class with a generic type', () {
+ expect(
+ Class((b) => b
+ ..name = 'List'
+ ..types.add(refer('T'))),
+ equalsDart(r'''
+ class List<T> {}
+ '''),
+ );
+ });
+
+ test('should create a class with multiple generic types', () {
+ expect(
+ Class(
+ (b) => b
+ ..name = 'Map'
+ ..types.addAll([
+ refer('K'),
+ refer('V'),
+ ]),
+ ),
+ equalsDart(r'''
+ class Map<K, V> {}
+ '''),
+ );
+ });
+
+ test('should create a class with a bound generic type', () {
+ expect(
+ Class((b) => b
+ ..name = 'Comparable'
+ ..types.add(TypeReference((b) => b
+ ..symbol = 'T'
+ ..bound = TypeReference((b) => b
+ ..symbol = 'Comparable'
+ ..types.add(refer('T').type))))),
+ equalsDart(r'''
+ class Comparable<T extends Comparable<T>> {}
+ '''),
+ );
+ });
+
+ test('should create a class extending another class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..extend = TypeReference((b) => b.symbol = 'Bar')),
+ equalsDart(r'''
+ class Foo extends Bar {}
+ '''),
+ );
+ });
+
+ test('should create a class mixing in another class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..extend = TypeReference((b) => b.symbol = 'Bar')
+ ..mixins.add(TypeReference((b) => b.symbol = 'Foo'))),
+ equalsDart(r'''
+ class Foo extends Bar with Foo {}
+ '''),
+ );
+ });
+
+ test('should create a class implementing another class', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..extend = TypeReference((b) => b.symbol = 'Bar')
+ ..implements.add(TypeReference((b) => b.symbol = 'Foo'))),
+ equalsDart(r'''
+ class Foo extends Bar implements Foo {}
+ '''),
+ );
+ });
+
+ test('should create a class with a constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor())),
+ equalsDart(r'''
+ class Foo {
+ Foo();
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a constructor with initializers', () {
+ expect(
+ Class(
+ (b) => b
+ ..name = 'Foo'
+ ..constructors.add(
+ Constructor(
+ (b) => b
+ ..initializers.addAll([
+ const Code('a = 5'),
+ const Code('super()'),
+ ]),
+ ),
+ ),
+ ),
+ equalsDart(r'''
+ class Foo {
+ Foo() : a = 5, super();
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a annotated constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors
+ .add(Constructor((b) => b..annotations.add(refer('deprecated'))))),
+ equalsDart(r'''
+ class Foo {
+ @deprecated
+ Foo();
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a named constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b..name = 'named'))),
+ equalsDart(r'''
+ class Foo {
+ Foo.named();
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a const constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b..constant = true))),
+ equalsDart(r'''
+ class Foo {
+ const Foo();
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with an external constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b..external = true))),
+ equalsDart(r'''
+ class Foo {
+ external Foo();
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a factory constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b
+ ..factory = true
+ ..redirect = refer('_Foo')))),
+ equalsDart(r'''
+ class Foo {
+ factory Foo() = _Foo;
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a const factory constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b
+ ..factory = true
+ ..constant = true
+ ..redirect = refer('_Foo')))),
+ equalsDart(r'''
+ class Foo {
+ const factory Foo() = _Foo;
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a factory lambda constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b
+ ..factory = true
+ ..lambda = true
+ ..body = const Code('_Foo()')))),
+ equalsDart(r'''
+ class Foo {
+ factory Foo() => _Foo();
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with an implicit factory lambda constructor', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b
+ ..factory = true
+ ..body = refer('_Foo').newInstance([]).code))),
+ equalsDart(r'''
+ class Foo {
+ factory Foo() => _Foo();
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a constructor with a body', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b
+ ..factory = true
+ ..body = const Code('return _Foo();')))),
+ equalsDart(r'''
+ class Foo {
+ factory Foo() {
+ return _Foo();
+ }
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a constructor with parameters', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b
+ ..requiredParameters.addAll([
+ Parameter((b) => b..name = 'a'),
+ Parameter((b) => b..name = 'b'),
+ ])
+ ..optionalParameters.addAll([
+ Parameter((b) => b
+ ..name = 'c'
+ ..named = true),
+ ])))),
+ equalsDart(r'''
+ class Foo {
+ Foo(a, b, {c, });
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a constructor+field-formal parameters', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b
+ ..requiredParameters.addAll([
+ Parameter((b) => b
+ ..name = 'a'
+ ..toThis = true),
+ Parameter((b) => b
+ ..name = 'b'
+ ..toThis = true),
+ ])
+ ..optionalParameters.addAll([
+ Parameter((b) => b
+ ..name = 'c'
+ ..named = true
+ ..toThis = true),
+ ])))),
+ equalsDart(r'''
+ class Foo {
+ Foo(this.a, this.b, {this.c, });
+ }
+ '''),
+ );
+ });
+
+ test('should create a class with a constructor+super-formal parameters', () {
+ expect(
+ Class((b) => b
+ ..name = 'Foo'
+ ..constructors.add(Constructor((b) => b
+ ..requiredParameters.addAll([
+ Parameter((b) => b
+ ..name = 'a'
+ ..toSuper = true),
+ Parameter((b) => b
+ ..name = 'b'
+ ..toSuper = true),
+ ])
+ ..optionalParameters.addAll([
+ Parameter((b) => b
+ ..name = 'c'
+ ..named = true
+ ..toSuper = true),
+ ])))),
+ equalsDart(r'''
+ class Foo {
+ Foo(super.a, super.b, {super.c, });
+ }
+ '''),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/specs/code/expression_test.dart b/pkgs/code_builder/test/specs/code/expression_test.dart
new file mode 100644
index 0000000..4ce9eba
--- /dev/null
+++ b/pkgs/code_builder/test/specs/code/expression_test.dart
@@ -0,0 +1,955 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should emit a simple expression', () {
+ expect(literalNull, equalsDart('null'));
+ });
+
+ group('literal', () {
+ test('forwards values that are already expressions', () {
+ expect(literal(refer('foo')), equalsDart('foo'));
+ expect(literal([refer('foo')]), equalsDart('[foo]'));
+ });
+ group('wraps', () {
+ test('bool values', () {
+ expect(literal(true), equalsDart('true'));
+ });
+ test('numeric values', () {
+ expect(literal(1), equalsDart('1'));
+ expect(literal(1.0), equalsDart('1.0'));
+ });
+ test('string values', () {
+ expect(literal('foo'), equalsDart("'foo'"));
+ });
+ test('list values', () {
+ expect(literal([1]), equalsDart('[1]'));
+ });
+ test('set values', () {
+ expect(literal({1}), equalsDart('{1}'));
+ });
+ test('map values', () {
+ expect(literal({'foo': 1}), equalsDart("{'foo': 1}"));
+ });
+ test('null', () {
+ expect(literal(null), equalsDart('null'));
+ });
+ });
+ test('uses `onError` for unhandled types', () {
+ expect(
+ literal(Uri.https('google.com'), onError: (value) {
+ if (value is Uri) {
+ return refer('Uri')
+ .newInstanceNamed('parse', [literalString(value.toString())]);
+ }
+ throw UnsupportedError('Not supported: $value');
+ }),
+ equalsDart("Uri.parse('https://google.com')"));
+ });
+ });
+
+ test('should emit a String', () {
+ expect(literalString(r'$monkey'), equalsDart(r"'$monkey'"));
+ });
+
+ test('should emit a raw String', () {
+ expect(literalString(r'$monkey', raw: true), equalsDart(r"r'$monkey'"));
+ });
+
+ test('should escape single quotes in a String', () {
+ expect(literalString(r"don't"), equalsDart(r"'don\'t'"));
+ });
+
+ test('does not allow single quote in raw string', () {
+ expect(() => literalString(r"don't", raw: true), throwsArgumentError);
+ });
+
+ test('should escape a newline in a string', () {
+ expect(literalString('some\nthing'), equalsDart(r"'some\nthing'"));
+ });
+
+ test('should emit a && expression', () {
+ expect(literalTrue.and(literalFalse), equalsDart('true && false'));
+ });
+
+ test('should emit a || expression', () {
+ expect(literalTrue.or(literalFalse), equalsDart('true || false'));
+ });
+
+ test('should emit a ! expression', () {
+ expect(literalTrue.negate(), equalsDart('!true'));
+ });
+
+ test('should emit a list', () {
+ expect(literalList([]), equalsDart('[]'));
+ });
+
+ test('should emit a const list', () {
+ expect(literalConstList([]), equalsDart('const []'));
+ });
+
+ test('should emit an explicitly typed list', () {
+ expect(literalList([], refer('int')), equalsDart('<int>[]'));
+ });
+
+ test('should emit a set', () {
+ // ignore: prefer_collection_literals
+ expect(literalSet(Set()), equalsDart('{}'));
+ });
+
+ test('should emit a const set', () {
+ // ignore: prefer_collection_literals
+ expect(literalConstSet(Set()), equalsDart('const {}'));
+ });
+
+ test('should emit an explicitly typed set', () {
+ // ignore: prefer_collection_literals
+ expect(literalSet(Set(), refer('int')), equalsDart('<int>{}'));
+ });
+
+ test('should emit a map', () {
+ expect(literalMap({}), equalsDart('{}'));
+ });
+
+ test('should emit a const map', () {
+ expect(literalConstMap({}), equalsDart('const {}'));
+ });
+
+ test('should emit an explicitly typed map', () {
+ expect(
+ literalMap({}, refer('int'), refer('bool')),
+ equalsDart('<int, bool>{}'),
+ );
+ });
+
+ test('should emit a map of other literals and expressions', () {
+ expect(
+ literalMap({
+ 1: 'one',
+ 2: refer('two'),
+ refer('three'): 3,
+ refer('Map').newInstance([]): null,
+ }),
+ equalsDart(r"{1: 'one', 2: two, three: 3, Map(): null, }"),
+ );
+ });
+
+ test('should emit a map with spreads', () {
+ expect(
+ literalMap({
+ literalSpread(): refer('one'),
+ 2: refer('two'),
+ literalNullSafeSpread(): refer('three'),
+ refer('Map').newInstance([]): null,
+ }),
+ equalsDart('{...one, 2: two, ...?three, Map(): null, }'),
+ );
+ });
+
+ test('should emit a list of other literals and expressions', () {
+ expect(
+ literalList([
+ <dynamic>[],
+ // ignore: prefer_collection_literals
+ Set<dynamic>(),
+ true,
+ null,
+ refer('Map').newInstance([])
+ ]),
+ equalsDart('[[], {}, true, null, Map(), ]'),
+ );
+ });
+
+ test('can toString a list literal with an expression as a value', () {
+ expect(literalList([refer('foo')]).toString, isNot(throwsA(anything)));
+ });
+
+ test('should emit a set of other literals and expressions', () {
+ expect(
+ // ignore: prefer_collection_literals
+ literalSet([
+ <dynamic>[],
+ // ignore: prefer_collection_literals
+ Set<dynamic>(),
+ true,
+ null,
+ refer('Map').newInstance([])
+ ]),
+ equalsDart('{[], {}, true, null, Map(), }'),
+ );
+ });
+
+ test('should emit an empty record', () {
+ expect(literalRecord([], {}), equalsDart('()'));
+ });
+
+ test('should emit a const empty record', () {
+ expect(literalConstRecord([], {}), equalsDart('const ()'));
+ });
+
+ test('should emit a record with only positional fields', () {
+ expect(literalRecord([1, ''], {}), equalsDart("(1, '')"));
+ });
+
+ test('should correctly emit a record with a single positional field', () {
+ expect(literalRecord([1], {}), equalsDart('(1,)'));
+ });
+
+ test('should emit a record with only named fields', () {
+ expect(literalRecord([], {'named': 1, 'other': []}),
+ equalsDart('(named: 1, other: [])'));
+ });
+
+ test('should emit a record with both positional and named fields', () {
+ expect(literalRecord([0], {'x': true, 'y': 0}),
+ equalsDart('(0, x: true, y: 0)'));
+ });
+
+ test('should emit a record of other literals and expressions', () {
+ expect(
+ literalRecord([
+ 1,
+ refer('one'),
+ 'one'
+ ], {
+ 'named': refer('Foo').newInstance([literalNum(1)])
+ }),
+ equalsDart("(1, one, 'one', named: Foo(1))"));
+ });
+
+ test('should emit a type as an expression', () {
+ expect(refer('Map'), equalsDart('Map'));
+ });
+
+ test('should emit a scoped type as an expression', () {
+ expect(
+ refer('Foo', 'package:foo/foo.dart'),
+ equalsDart(
+ '_i1.Foo', DartEmitter(allocator: Allocator.simplePrefixing())),
+ );
+ });
+
+ test('should emit invoking Type()', () {
+ expect(
+ refer('Map').newInstance([]),
+ equalsDart('Map()'),
+ );
+ });
+
+ test('should emit invoking named constructor', () {
+ expect(
+ refer('Foo').newInstanceNamed('bar', []),
+ equalsDart('Foo.bar()'),
+ );
+ });
+
+ test('should emit invoking const Type()', () {
+ expect(
+ refer('Object').constInstance([]),
+ equalsDart('const Object()'),
+ );
+ });
+
+ test('should emit invoking a property accessor', () {
+ expect(refer('foo').property('bar'), equalsDart('foo.bar'));
+ });
+
+ test('should emit invoking a cascade property accessor', () {
+ expect(refer('foo').cascade('bar'), equalsDart('foo..bar'));
+ });
+
+ test('should emit invoking a null safe property accessor', () {
+ expect(refer('foo').nullSafeProperty('bar'), equalsDart('foo?.bar'));
+ });
+
+ test('should emit invoking a method with a single positional argument', () {
+ expect(
+ refer('foo').call([
+ literal(1),
+ ]),
+ equalsDart('foo(1)'),
+ );
+ });
+
+ test('should emit invoking a method with positional arguments', () {
+ expect(
+ refer('foo').call([
+ literal(1),
+ literal(2),
+ literal(3),
+ ]),
+ equalsDart('foo(1, 2, 3, )'),
+ );
+ });
+
+ test('should emit invoking a method with a single named argument', () {
+ expect(
+ refer('foo').call([], {
+ 'bar': literal(1),
+ }),
+ equalsDart('foo(bar: 1)'),
+ );
+ });
+
+ test('should emit invoking a method with named arguments', () {
+ expect(
+ refer('foo').call([], {
+ 'bar': literal(1),
+ 'baz': literal(2),
+ }),
+ equalsDart('foo(bar: 1, baz: 2, )'),
+ );
+ });
+
+ test('should emit invoking a method with positional and named arguments', () {
+ expect(
+ refer('foo').call([
+ literal(1)
+ ], {
+ 'bar': literal(2),
+ 'baz': literal(3),
+ }),
+ equalsDart('foo(1, bar: 2, baz: 3, )'),
+ );
+ });
+
+ test('should emit invoking a method with a single type argument', () {
+ expect(
+ refer('foo').call(
+ [],
+ {},
+ [
+ refer('String'),
+ ],
+ ),
+ equalsDart('foo<String>()'),
+ );
+ });
+
+ test('should emit invoking a method with type arguments', () {
+ expect(
+ refer('foo').call(
+ [],
+ {},
+ [
+ refer('String'),
+ refer('int'),
+ ],
+ ),
+ equalsDart('foo<String, int>()'),
+ );
+ });
+
+ test('should emit a function type', () {
+ expect(
+ FunctionType((b) => b.returnType = refer('void')),
+ equalsDart('void Function()'),
+ );
+ });
+
+ test('should emit a typedef statement', () {
+ expect(
+ FunctionType((b) => b.returnType = refer('void')).toTypeDef('Void0'),
+ equalsDart('typedef Void0 = void Function();'),
+ );
+ });
+
+ test('should emit a function type with type parameters', () {
+ expect(
+ FunctionType((b) => b
+ ..returnType = refer('T')
+ ..types.add(refer('T'))),
+ equalsDart('T Function<T>()'),
+ );
+ });
+
+ test('should emit a function type a single parameter', () {
+ expect(
+ FunctionType((b) => b..requiredParameters.add(refer('String'))),
+ equalsDart('Function(String)'),
+ );
+ });
+
+ test('should emit a function type with parameters', () {
+ expect(
+ FunctionType((b) => b
+ ..requiredParameters.add(refer('String'))
+ ..optionalParameters.add(refer('int'))),
+ equalsDart('Function(String, [int, ])'),
+ );
+ });
+
+ test('should emit a function type with named parameters', () {
+ expect(
+ FunctionType((b) => b
+ ..namedParameters.addAll({
+ 'x': refer('int'),
+ 'y': refer('int'),
+ })),
+ equalsDart('Function({int x, int y, })'),
+ );
+ });
+
+ test(
+ 'should emit a function type with named required and optional parameters',
+ () {
+ expect(
+ FunctionType((b) => b
+ ..namedRequiredParameters.addAll({
+ 'x': refer('int'),
+ })
+ ..namedParameters.addAll({
+ 'y': refer('int'),
+ })),
+ equalsDart('Function({required int x, int y, })'),
+ );
+ });
+
+ test('should emit a function type with named required parameters', () {
+ expect(
+ FunctionType((b) => b
+ ..namedRequiredParameters.addAll({
+ 'x': refer('int'),
+ 'y': refer('int'),
+ })),
+ equalsDart('Function({required int x, required int y, })'),
+ );
+ });
+
+ test('should emit a nullable function type in a Null Safety library', () {
+ final emitter = DartEmitter.scoped(useNullSafetySyntax: true);
+ expect(
+ FunctionType((b) => b
+ ..requiredParameters.add(refer('String'))
+ ..isNullable = true),
+ equalsDart('Function(String)?', emitter),
+ );
+ });
+
+ test('should emit a nullable function type in pre-Null Safety library', () {
+ expect(
+ FunctionType((b) => b
+ ..requiredParameters.add(refer('String'))
+ ..isNullable = true),
+ equalsDart('Function(String)'),
+ );
+ });
+
+ test('should emit a non-nullable function type in a Null Safety library', () {
+ final emitter = DartEmitter.scoped(useNullSafetySyntax: true);
+ expect(
+ FunctionType((b) => b
+ ..requiredParameters.add(refer('String'))
+ ..isNullable = false),
+ equalsDart('Function(String)', emitter),
+ );
+ });
+
+ test('should emit a non-nullable function type in pre-Null Safety library',
+ () {
+ expect(
+ FunctionType((b) => b
+ ..requiredParameters.add(refer('String'))
+ ..isNullable = false),
+ equalsDart('Function(String)'),
+ );
+ });
+
+ test('should emit a closure', () {
+ expect(
+ refer('map').property('putIfAbsent').call([
+ literalString('foo'),
+ Method((b) => b..body = literalTrue.code).closure,
+ ]),
+ equalsDart("map.putIfAbsent('foo', () => true, )"),
+ );
+ });
+
+ test('should emit a generic closure', () {
+ expect(
+ refer('map').property('putIfAbsent').call([
+ literalString('foo'),
+ Method((b) => b
+ ..types.add(refer('T'))
+ ..body = literalTrue.code).genericClosure,
+ ]),
+ equalsDart("map.putIfAbsent('foo', <T>() => true, )"),
+ );
+ });
+
+ test('should emit an assignment', () {
+ expect(
+ refer('foo').assign(literalTrue),
+ equalsDart('foo = true'),
+ );
+ });
+
+ test('should emit an if null assignment', () {
+ expect(
+ refer('foo').ifNullThen(literalTrue),
+ equalsDart('foo ?? true'),
+ );
+ });
+
+ test('should emit a null check', () {
+ expect(refer('foo').nullChecked, equalsDart('foo!'));
+ });
+
+ test('should emit an if null index operator set', () {
+ expect(
+ refer('bar')
+ .index(literalTrue)
+ .ifNullThen(literalFalse)
+ // ignore: deprecated_member_use_from_same_package
+ .assignVar('foo')
+ .statement,
+ equalsDart('var foo = bar[true] ?? false;'),
+ );
+ });
+
+ test('should emit a null-aware assignment', () {
+ expect(
+ refer('foo').assignNullAware(literalTrue),
+ equalsDart('foo ??= true'),
+ );
+ });
+
+ test('should emit an index operator', () {
+ expect(
+ // ignore: deprecated_member_use_from_same_package
+ refer('bar').index(literalString('key')).assignVar('foo').statement,
+ equalsDart("var foo = bar['key'];"),
+ );
+ });
+
+ test('should emit an index operator set', () {
+ expect(
+ refer('bar')
+ .index(literalString('key'))
+ .assign(literalFalse)
+ // ignore: deprecated_member_use_from_same_package
+ .assignVar('foo')
+ .statement,
+ equalsDart("var foo = bar['key'] = false;"),
+ );
+ });
+
+ test('should emit a null-aware index operator set', () {
+ expect(
+ refer('bar')
+ .index(literalTrue)
+ .assignNullAware(literalFalse)
+ // ignore: deprecated_member_use_from_same_package
+ .assignVar('foo')
+ .statement,
+ equalsDart('var foo = bar[true] ??= false;'),
+ );
+ });
+
+ test('should emit assigning to a var', () {
+ expect(
+ // ignore: deprecated_member_use_from_same_package
+ literalTrue.assignVar('foo'),
+ equalsDart('var foo = true'),
+ );
+ });
+
+ test('should emit assigning to a type', () {
+ expect(
+ // ignore: deprecated_member_use_from_same_package
+ literalTrue.assignVar('foo', refer('bool')),
+ equalsDart('bool foo = true'),
+ );
+ });
+
+ test('should emit assigning to a final', () {
+ expect(
+ // ignore: deprecated_member_use_from_same_package
+ literalTrue.assignFinal('foo'),
+ equalsDart('final foo = true'),
+ );
+ });
+
+ test('should emit assigning to a const', () {
+ expect(
+ // ignore: deprecated_member_use_from_same_package
+ literalTrue.assignConst('foo'),
+ equalsDart('const foo = true'),
+ );
+ });
+
+ test('should emit await', () {
+ expect(
+ refer('future').awaited,
+ equalsDart('await future'),
+ );
+ });
+
+ test('should emit return', () {
+ expect(
+ literalNull.returned,
+ equalsDart('return null'),
+ );
+ });
+
+ test('should emit spread', () {
+ expect(
+ refer('foo').spread,
+ equalsDart('...foo'),
+ );
+ });
+
+ test('should emit null safe spread', () {
+ expect(
+ refer('foo').nullSafeSpread,
+ equalsDart('...?foo'),
+ );
+ });
+
+ test('should emit throw', () {
+ expect(
+ literalNull.thrown,
+ equalsDart('throw null'),
+ );
+ });
+
+ test('should emit an explicit cast', () {
+ expect(
+ refer('foo').asA(refer('String')).property('length'),
+ equalsDart('(foo as String).length'),
+ );
+ });
+
+ test('should emit an is check', () {
+ expect(
+ refer('foo').isA(refer('String')),
+ equalsDart('foo is String'),
+ );
+ });
+
+ test('should emit an is! check', () {
+ expect(
+ refer('foo').isNotA(refer('String')),
+ equalsDart('foo is! String'),
+ );
+ });
+
+ test('should emit an equality check', () {
+ expect(
+ refer('foo').equalTo(literalString('bar')),
+ equalsDart("foo == 'bar'"),
+ );
+ });
+
+ test('should emit an inequality check', () {
+ expect(
+ refer('foo').notEqualTo(literalString('bar')),
+ equalsDart("foo != 'bar'"),
+ );
+ });
+
+ test('should emit an greater than check', () {
+ expect(
+ refer('foo').greaterThan(literalString('bar')),
+ equalsDart("foo > 'bar'"),
+ );
+ });
+
+ test('should emit an less than check', () {
+ expect(
+ refer('foo').lessThan(literalString('bar')),
+ equalsDart("foo < 'bar'"),
+ );
+ });
+
+ test('should emit an greater or equals check', () {
+ expect(
+ refer('foo').greaterOrEqualTo(literalString('bar')),
+ equalsDart("foo >= 'bar'"),
+ );
+ });
+
+ test('should emit an less or equals check', () {
+ expect(
+ refer('foo').lessOrEqualTo(literalString('bar')),
+ equalsDart("foo <= 'bar'"),
+ );
+ });
+
+ test('should emit a conditional', () {
+ expect(
+ refer('foo').conditional(literal(1), literal(2)),
+ equalsDart('foo ? 1 : 2'),
+ );
+ });
+
+ test('should emit an operator add call', () {
+ expect(refer('foo').operatorAdd(refer('foo2')), equalsDart('foo + foo2'));
+ });
+
+ test('should emit an operator subtract call', () {
+ // ignore: deprecated_member_use_from_same_package
+ expect(refer('foo').operatorSubstract(refer('foo2')),
+ equalsDart('foo - foo2'));
+
+ expect(
+ refer('foo').operatorSubtract(refer('foo2')),
+ equalsDart('foo - foo2'),
+ );
+ });
+
+ test('should emit an operator divide call', () {
+ expect(
+ refer('foo').operatorDivide(refer('foo2')), equalsDart('foo / foo2'));
+ });
+
+ test('should emit an operator multiply call', () {
+ expect(
+ refer('foo').operatorMultiply(refer('foo2')), equalsDart('foo * foo2'));
+ });
+
+ test('should emit an euclidean modulo operator call', () {
+ expect(refer('foo').operatorEuclideanModulo(refer('foo2')),
+ equalsDart('foo % foo2'));
+ });
+
+ test('should emit an operator int divide call', () {
+ expect(
+ refer('foo').operatorIntDivide(refer('foo2')),
+ equalsDart('foo ~/ foo2'),
+ );
+ });
+
+ test('should emit a unary prefix increment operator call', () {
+ expect(refer('foo').operatorUnaryPrefixIncrement(), equalsDart('++foo'));
+ });
+
+ test('should emit a unary postfix increment operator call', () {
+ expect(refer('foo').operatorUnaryPostfixIncrement(), equalsDart('foo++'));
+ });
+
+ test('should emit a unary prefix minus operator call', () {
+ expect(refer('foo').operatorUnaryMinus(), equalsDart('-foo'));
+ });
+
+ test('should emit a unary prefix decrement operator call', () {
+ expect(refer('foo').operatorUnaryPrefixDecrement(), equalsDart('--foo'));
+ });
+
+ test('should emit a unary postfix decrement operator call', () {
+ expect(refer('foo').operatorUnaryPostfixDecrement(), equalsDart('foo--'));
+ });
+
+ test('should emit a bitwise AND operator call', () {
+ expect(
+ refer('foo').operatorBitwiseAnd(refer('foo2')),
+ equalsDart('foo & foo2'),
+ );
+ });
+
+ test('should emit a bitwise OR operator call', () {
+ expect(
+ refer('foo').operatorBitwiseOr(refer('foo2')),
+ equalsDart('foo | foo2'),
+ );
+ });
+
+ test('should emit a bitwise XOR operator call', () {
+ expect(
+ refer('foo').operatorBitwiseXor(refer('foo2')),
+ equalsDart('foo ^ foo2'),
+ );
+ });
+
+ test('should emit a unary bitwise complement operator call', () {
+ expect(
+ refer('foo').operatorUnaryBitwiseComplement(),
+ equalsDart('~foo'),
+ );
+ });
+
+ test('should emit a shift left operator call', () {
+ expect(
+ refer('foo').operatorShiftLeft(refer('foo2')),
+ equalsDart('foo << foo2'),
+ );
+ });
+
+ test('should emit a shift right operator call', () {
+ expect(
+ refer('foo').operatorShiftRight(refer('foo2')),
+ equalsDart('foo >> foo2'),
+ );
+ });
+
+ test('should emit a shift right unsigned operator call', () {
+ expect(
+ refer('foo').operatorShiftRightUnsigned(refer('foo2')),
+ equalsDart('foo >>> foo2'),
+ );
+ });
+
+ test('should emit a const variable declaration', () {
+ expect(declareConst('foo').assign(refer('bar')),
+ equalsDart('const foo = bar'));
+ });
+
+ test('should emit a typed const variable declaration', () {
+ expect(declareConst('foo', type: refer('String')).assign(refer('bar')),
+ equalsDart('const String foo = bar'));
+ });
+
+ test('should emit a final variable declaration', () {
+ expect(declareFinal('foo').assign(refer('bar')),
+ equalsDart('final foo = bar'));
+ });
+
+ test('should emit a typed final variable declaration', () {
+ expect(declareFinal('foo', type: refer('String')).assign(refer('bar')),
+ equalsDart('final String foo = bar'));
+ });
+
+ test('should emit a nullable typed final variable declaration', () {
+ final emitter = DartEmitter.scoped(useNullSafetySyntax: true);
+ expect(
+ declareFinal('foo',
+ type: TypeReference((b) => b
+ ..symbol = 'String'
+ ..isNullable = true)).assign(refer('bar')),
+ equalsDart('final String? foo = bar', emitter));
+ }, skip: 'https://github.com/dart-lang/code_builder/issues/315');
+
+ test('should emit a late final variable declaration', () {
+ expect(declareFinal('foo', late: true).assign(refer('bar')),
+ equalsDart('late final foo = bar'));
+ });
+
+ test('should emit a late typed final variable declaration', () {
+ expect(
+ declareFinal('foo', type: refer('String'), late: true)
+ .assign(refer('bar')),
+ equalsDart('late final String foo = bar'));
+ });
+
+ test('should emit a variable declaration', () {
+ expect(declareVar('foo').assign(refer('bar')), equalsDart('var foo = bar'));
+ });
+
+ test('should emit a typed variable declaration', () {
+ expect(declareVar('foo', type: refer('String')).assign(refer('bar')),
+ equalsDart('String foo = bar'));
+ });
+
+ test('should emit a late variable declaration', () {
+ expect(declareVar('foo', late: true).assign(refer('bar')),
+ equalsDart('late var foo = bar'));
+ });
+
+ test('should emit a late typed variable declaration', () {
+ expect(
+ declareVar('foo', type: refer('String'), late: true)
+ .assign(refer('bar')),
+ equalsDart('late String foo = bar'));
+ });
+
+ test('should emit a perenthesized epression', () {
+ expect(
+ refer('foo').ifNullThen(refer('FormatException')
+ .newInstance([literalString('missing foo')])
+ .thrown
+ .parenthesized),
+ equalsDart('foo ?? (throw FormatException(\'missing foo\'))'));
+ });
+
+ test('should emit an addition assigment expression', () {
+ expect(
+ refer('foo').addAssign(refer('bar')),
+ equalsDart('foo += bar'),
+ );
+ });
+
+ test('should emit a subtraction assigment expression', () {
+ expect(
+ refer('foo').subtractAssign(refer('bar')),
+ equalsDart('foo -= bar'),
+ );
+ });
+
+ test('should emit a multiplication assigment expression', () {
+ expect(
+ refer('foo').multiplyAssign(refer('bar')),
+ equalsDart('foo *= bar'),
+ );
+ });
+
+ test('should emit a division assigment expression', () {
+ expect(
+ refer('foo').divideAssign(refer('bar')),
+ equalsDart('foo /= bar'),
+ );
+ });
+
+ test('should emit an int division assigment expression', () {
+ expect(
+ refer('foo').intDivideAssign(refer('bar')),
+ equalsDart('foo ~/= bar'),
+ );
+ });
+
+ test('should emit a euclidean modulo assigment expression', () {
+ expect(
+ refer('foo').euclideanModuloAssign(refer('bar')),
+ equalsDart('foo %= bar'),
+ );
+ });
+
+ test('should emit a shift left assigment expression', () {
+ expect(
+ refer('foo').shiftLeftAssign(refer('bar')),
+ equalsDart('foo <<= bar'),
+ );
+ });
+
+ test('should emit a shift right assigment expression', () {
+ expect(
+ refer('foo').shiftRightAssign(refer('bar')),
+ equalsDart('foo >>= bar'),
+ );
+ });
+
+ test('should emit a shift right unsigned assigment expression', () {
+ expect(
+ refer('foo').shiftRightUnsignedAssign(refer('bar')),
+ equalsDart('foo >>>= bar'),
+ );
+ });
+
+ test('should emit a bitwise AND assigment expression', () {
+ expect(
+ refer('foo').bitwiseAndAssign(refer('bar')),
+ equalsDart('foo &= bar'),
+ );
+ });
+
+ test('should emit a bitwise XOR assigment expression', () {
+ expect(
+ refer('foo').bitwiseXorAssign(refer('bar')),
+ equalsDart('foo ^= bar'),
+ );
+ });
+
+ test('should emit a bitwise OR assigment expression', () {
+ expect(
+ refer('foo').bitwiseOrAssign(refer('bar')),
+ equalsDart('foo |= bar'),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/specs/code/statement_test.dart b/pkgs/code_builder/test/specs/code/statement_test.dart
new file mode 100644
index 0000000..cd3d53a
--- /dev/null
+++ b/pkgs/code_builder/test/specs/code/statement_test.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should emit a block of code', () {
+ expect(
+ Block.of([
+ const Code('if (foo) {'),
+ const Code(' print(true);'),
+ const Code('}'),
+ ]),
+ equalsDart(r'''
+ if (foo) {
+ print(true);
+ }
+ '''),
+ );
+ });
+
+ test('should emit a block of code including expressions', () {
+ expect(
+ Block.of([
+ const Code('if (foo) {'),
+ refer('print')([literalTrue]).statement,
+ const Code('}'),
+ ]),
+ equalsDart(r'''
+ if (foo) {
+ print(true);
+ }
+ '''),
+ );
+ });
+
+ test('should emit a block of code with lazily invoked generators', () {
+ expect(
+ Method((b) => b
+ ..name = 'main'
+ ..body = Block.of([
+ const Code('if ('),
+ lazyCode(() => refer('foo').code),
+ const Code(') {'),
+ refer('print')([literalTrue]).statement,
+ const Code('}'),
+ ])),
+ equalsDart(r'''
+ main() {
+ if (foo) {
+ print(true);
+ }
+ }
+ '''),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/specs/enum_test.dart b/pkgs/code_builder/test/specs/enum_test.dart
new file mode 100644
index 0000000..5a0b19a
--- /dev/null
+++ b/pkgs/code_builder/test/specs/enum_test.dart
@@ -0,0 +1,442 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should create an enum', () {
+ expect(
+ Enum((b) => b
+ ..name = 'E'
+ ..values.addAll([
+ EnumValue((b) => b..name = 'a'),
+ EnumValue((b) => b..name = 'b'),
+ ])),
+ equalsDart(r'''
+ enum E {
+ a,
+ b
+ }
+ '''));
+ });
+
+ test('should create an enum with annotations', () {
+ expect(
+ Enum((b) => b
+ ..annotations.addAll([
+ refer('deprecated'),
+ refer('Deprecated').call([literalString('This is an old enum')])
+ ])
+ ..name = 'V'
+ ..values.addAll([
+ EnumValue((b) => b..name = 'x'),
+ ])),
+ equalsDart(r'''
+ @deprecated
+ @Deprecated('This is an old enum')
+ enum V {
+ x
+ }
+ '''));
+ });
+
+ test('should create an enum with annotated values', () {
+ expect(
+ Enum((b) => b
+ ..name = 'Status'
+ ..values.addAll([
+ EnumValue((b) => b
+ ..name = 'okay'
+ ..annotations.addAll([
+ refer('deprecated'),
+ refer('Deprecated').call([literalString('use Good instead')]),
+ ])),
+ EnumValue((b) => b
+ ..name = 'good'
+ ..annotations.addAll([
+ refer('JsonKey').call([literalString('good')])
+ ])),
+ ])),
+ equalsDart(r'''
+ enum Status {
+ @deprecated
+ @Deprecated('use Good instead')
+ okay,
+ @JsonKey('good')
+ good
+ }
+ '''));
+ });
+
+ test('should create an enum which mixes in and implements specs', () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..implements.addAll(const [
+ Reference('InterfaceA'),
+ Reference('InterfaceB'),
+ ])
+ ..mixins.addAll(const [
+ Reference('Mixin1'),
+ Reference('Mixin2'),
+ ])
+ ..values.addAll([
+ EnumValue((v) => v..name = 'a'),
+ EnumValue((v) => v..name = 'b'),
+ EnumValue((v) => v..name = 'c'),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum with Mixin1, Mixin2 implements InterfaceA, InterfaceB {
+ a,
+ b,
+ c
+ }
+ '''));
+ });
+
+ test('should create an enum which targets a named constructor', () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..constructors.addAll([
+ Constructor((c) => c..constant = true),
+ Constructor((c) => c
+ ..constant = true
+ ..name = 'named'),
+ ])
+ ..values.addAll([
+ EnumValue((v) => v..name = 'a'),
+ EnumValue((v) => v
+ ..name = 'b'
+ ..constructorName = 'named'),
+ EnumValue((v) => v..name = 'c'),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum {
+ a,
+ b.named(),
+ c;
+
+ const MyEnum();
+
+ const MyEnum.named();
+ }
+ '''));
+ });
+
+ test('should create an enum which targets a redirecting constructor', () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..constructors.addAll([
+ Constructor((c) => c..constant = true),
+ Constructor((c) => c
+ ..constant = true
+ ..name = 'redirect'
+ ..initializers.add(
+ refer('this').call([]).code,
+ )),
+ ])
+ ..values.addAll([
+ EnumValue((v) => v..name = 'a'),
+ EnumValue((v) => v
+ ..name = 'b'
+ ..constructorName = 'redirect'),
+ EnumValue((v) => v..name = 'c'),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum {
+ a,
+ b.redirect(),
+ c;
+
+ const MyEnum();
+
+ const MyEnum.redirect() : this();
+ }
+ '''));
+ });
+
+ test('should create an enum which targets a redirecting factory constructor',
+ () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..constructors.addAll([
+ Constructor((c) => c..constant = true),
+ Constructor((c) => c
+ ..constant = true
+ ..factory = true
+ ..name = 'redirect'
+ ..redirect = refer('MyOtherEnum.named')
+ ..optionalParameters.addAll([
+ Parameter((p) => p
+ ..type = refer('int?')
+ ..name = 'myInt'),
+ Parameter((p) => p
+ ..type = refer('String?')
+ ..name = 'myString')
+ ]))
+ ])
+ ..values.addAll([
+ EnumValue((v) => v..name = 'a'),
+ EnumValue((v) => v
+ ..name = 'b'
+ ..constructorName = 'redirect'
+ ..arguments.addAll([
+ literalNum(1),
+ literalString('abc'),
+ ])),
+ EnumValue((v) => v
+ ..name = 'c'
+ ..constructorName = 'redirect'),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum {
+ a,
+ b.redirect(1, 'abc'),
+ c.redirect();
+
+ const MyEnum();
+
+ const factory MyEnum.redirect([
+ int? myInt,
+ String? myString,
+ ]) = MyOtherEnum.named;
+ }
+ '''));
+ });
+
+ test('should create an enum which targets an unnamed constructor', () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..constructors.add(Constructor((c) => c
+ ..constant = true
+ ..optionalParameters.addAll([
+ Parameter((p) => p
+ ..toThis = true
+ ..name = 'myInt'),
+ Parameter((p) => p
+ ..toThis = true
+ ..name = 'myString')
+ ])))
+ ..fields.addAll([
+ Field((f) => f
+ ..modifier = FieldModifier.final$
+ ..type = refer('int?')
+ ..name = 'myInt'),
+ Field((f) => f
+ ..modifier = FieldModifier.final$
+ ..type = refer('String?')
+ ..name = 'myString')
+ ])
+ ..values.addAll([
+ EnumValue((v) => v..name = 'a'),
+ EnumValue((v) => v
+ ..name = 'b'
+ ..arguments.addAll([
+ literalNum(1),
+ literalString('abc'),
+ ])),
+ EnumValue((v) => v..name = 'c'),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum {
+ a,
+ b(1, 'abc'),
+ c;
+
+ const MyEnum([
+ this.myInt,
+ this.myString,
+ ]);
+
+ final int? myInt;
+
+ final String? myString;
+ }
+ '''));
+ });
+
+ test('should create an enum with generics', () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..types.add(const Reference('T'))
+ ..constructors.add(Constructor((c) => c
+ ..constant = true
+ ..requiredParameters.add(Parameter((p) => p
+ ..toThis = true
+ ..name = 'value'))))
+ ..fields.add(
+ Field((f) => f
+ ..modifier = FieldModifier.final$
+ ..type = refer('T')
+ ..name = 'value'),
+ )
+ ..values.addAll([
+ EnumValue((v) => v
+ ..name = 'a'
+ ..types.add(const Reference('int'))
+ ..arguments.add(literalNum(123))),
+ EnumValue((v) => v
+ ..name = 'b'
+ ..types.add(const Reference('String'))
+ ..arguments.add(literalString('abc'))),
+ EnumValue((v) => v
+ ..name = 'c'
+ ..types.add(const Reference('MyEnum'))
+ ..arguments.add(refer('MyEnum').property('a'))),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum<T> {
+ a<int>(123),
+ b<String>('abc'),
+ c<MyEnum>(MyEnum.a);
+
+ const MyEnum(this.value);
+
+ final T value;
+ }
+ '''));
+ });
+
+ test('should create an enum with fields', () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..constructors.add(Constructor((c) => c
+ ..constant = true
+ ..optionalParameters.add(Parameter((p) => p
+ ..toThis = true
+ ..name = 'myInt'))))
+ ..fields.addAll([
+ Field((f) => f
+ ..modifier = FieldModifier.final$
+ ..type = refer('int?')
+ ..name = 'myInt'),
+ Field((f) => f
+ ..static = true
+ ..modifier = FieldModifier.constant
+ ..type = refer('String')
+ ..name = 'myString'
+ ..assignment = literalString('abc').code),
+ ])
+ ..values.addAll([
+ EnumValue((v) => v..name = 'a'),
+ EnumValue((v) => v..name = 'b'),
+ EnumValue((v) => v..name = 'c'),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum {
+ a,
+ b,
+ c;
+
+ const MyEnum([this.myInt]);
+
+ final int? myInt;
+
+ static const String myString = 'abc';
+ }
+ '''));
+ });
+
+ test('should create an enum with methods', () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..methods.addAll([
+ Method((m) => m
+ ..returns = refer('int')
+ ..type = MethodType.getter
+ ..name = 'myInt'
+ ..body = literalNum(123).code),
+ Method((m) => m
+ ..returns = refer('Iterable<String>')
+ ..name = 'myStrings'
+ ..modifier = MethodModifier.syncStar
+ ..body = Block.of(const [
+ Code("yield 'a';"),
+ Code("yield 'b';"),
+ Code("yield 'c';"),
+ ]))
+ ])
+ ..values.addAll([
+ EnumValue((v) => v..name = 'a'),
+ EnumValue((v) => v..name = 'b'),
+ EnumValue((v) => v..name = 'c'),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum {
+ a,
+ b,
+ c;
+
+ int get myInt => 123;
+ Iterable<String> myStrings() sync* {
+ yield 'a';
+ yield 'b';
+ yield 'c';
+ }
+ }
+ '''));
+ });
+
+ test('should create an enum which named and unnamed constructor parameters',
+ () {
+ final myEnum = Enum((b) => b
+ ..name = 'MyEnum'
+ ..constructors.add(Constructor((c) => c
+ ..constant = true
+ ..requiredParameters.addAll([
+ Parameter((p) => p
+ ..toThis = true
+ ..name = 'myInt')
+ ])
+ ..optionalParameters.addAll([
+ Parameter((p) => p
+ ..toThis = true
+ ..named = true
+ ..required = true
+ ..name = 'myString')
+ ])))
+ ..fields.addAll([
+ Field((f) => f
+ ..modifier = FieldModifier.final$
+ ..type = refer('int?')
+ ..name = 'myInt'),
+ Field((f) => f
+ ..modifier = FieldModifier.final$
+ ..type = refer('String?')
+ ..name = 'myString')
+ ])
+ ..values.addAll([
+ EnumValue((v) => v..name = 'a'),
+ EnumValue((v) => v
+ ..name = 'b'
+ ..arguments.addAll([
+ literalNum(1),
+ ])
+ ..namedArguments.addAll({
+ 'myString': literalString('abc'),
+ })),
+ EnumValue((v) => v..name = 'c'),
+ ]));
+ expect(myEnum, equalsDart('''
+ enum MyEnum {
+ a,
+ b(1, myString: 'abc'),
+ c;
+
+ const MyEnum(
+ this.myInt,
+ {required this.myString, }
+ );
+
+ final int? myInt;
+
+ final String? myString;
+ }
+ '''));
+ });
+}
diff --git a/pkgs/code_builder/test/specs/extension_test.dart b/pkgs/code_builder/test/specs/extension_test.dart
new file mode 100644
index 0000000..b45fa65
--- /dev/null
+++ b/pkgs/code_builder/test/specs/extension_test.dart
@@ -0,0 +1,137 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should create an extension', () {
+ expect(
+ Extension((b) => b
+ ..name = 'Foo'
+ ..on = TypeReference((b) => b.symbol = 'Bar')),
+ equalsDart(r'''
+ extension Foo on Bar {}
+ '''),
+ );
+ });
+
+ test('should create an extension without an identifier', () {
+ expect(
+ Extension((b) => b..on = TypeReference((b) => b.symbol = 'Bar')),
+ equalsDart(r'''
+ extension on Bar {}
+ '''),
+ );
+ });
+
+ test('should create an extension with documentation', () {
+ expect(
+ Extension(
+ (b) => b
+ ..name = 'Foo'
+ ..on = TypeReference((b) => b.symbol = 'Bar')
+ ..docs.addAll(
+ const [
+ '/// My favorite extension.',
+ ],
+ ),
+ ),
+ equalsDart(r'''
+ /// My favorite extension.
+ extension Foo on Bar {}
+ '''),
+ );
+ });
+
+ test('should create an extension with annotations', () {
+ expect(
+ Extension(
+ (b) => b
+ ..name = 'Foo'
+ ..on = TypeReference((b) => b.symbol = 'Bar')
+ ..annotations.addAll([
+ refer('deprecated'),
+ refer('Deprecated')
+ .call([literalString('This is an old extension')])
+ ]),
+ ),
+ equalsDart(r'''
+ @deprecated
+ @Deprecated('This is an old extension')
+ extension Foo on Bar {}
+ '''),
+ );
+ });
+
+ test('should create an extension with a generic type', () {
+ expect(
+ Extension((b) => b
+ ..name = 'Foo'
+ ..on = TypeReference((b) => b.symbol = 'Bar')
+ ..types.add(refer('T'))),
+ equalsDart(r'''
+ extension Foo<T> on Bar {}
+ '''),
+ );
+ });
+
+ test('should create an extension with multiple generic types', () {
+ expect(
+ Extension(
+ (b) => b
+ ..name = 'Map'
+ ..on = TypeReference((b) => b.symbol = 'Bar')
+ ..types.addAll([
+ refer('K'),
+ refer('V'),
+ ]),
+ ),
+ equalsDart(r'''
+ extension Map<K, V> on Bar {}
+ '''),
+ );
+ });
+
+ test('should create an extension with a bound generic type', () {
+ expect(
+ Extension((b) => b
+ ..name = 'Foo'
+ ..on = TypeReference((b) => b.symbol = 'Bar')
+ ..types.add(TypeReference((b) => b
+ ..symbol = 'T'
+ ..bound = TypeReference((b) => b
+ ..symbol = 'Comparable'
+ ..types.add(refer('T').type))))),
+ equalsDart(r'''
+ extension Foo<T extends Comparable<T>> on Bar {}
+ '''),
+ );
+ });
+
+ test('should create an extension with a method', () {
+ expect(
+ Extension((b) => b
+ ..name = 'Foo'
+ ..on = TypeReference((b) => b.symbol = 'Bar')
+ ..methods.add(Method((b) => b
+ ..name = 'parseInt'
+ ..returns = refer('int')
+ ..body = Code.scope(
+ (a) => 'return int.parse(this);',
+ )))),
+ equalsDart(r'''
+ extension Foo on Bar {
+ int parseInt() {
+ return int.parse(this);
+ }
+ }
+ '''),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/specs/extension_type_test.dart b/pkgs/code_builder/test/specs/extension_type_test.dart
new file mode 100644
index 0000000..cc51046
--- /dev/null
+++ b/pkgs/code_builder/test/specs/extension_type_test.dart
@@ -0,0 +1,244 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('minimum extension type', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')),
+ equalsDart(r'''
+ extension type Foo(int bar) { }
+ '''),
+ );
+ });
+
+ test('const extension type', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..constant = true
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')),
+ equalsDart(r'''
+ extension type const Foo(int bar) { }
+ '''),
+ );
+ });
+
+ test('extension type with metadata', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')
+ ..docs.add(
+ '/// My favorite extension type.',
+ )
+ ..annotations.addAll([
+ refer('deprecated'),
+ refer('Deprecated')
+ .call([literalString('This is an old extension type')])
+ ])),
+ equalsDart(r'''
+ /// My favorite extension type.
+ @deprecated
+ @Deprecated('This is an old extension type')
+ extension type Foo(int bar) { }
+ '''),
+ );
+ });
+
+ test('extension type with generics', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..types.addAll([
+ TypeReference((b) => b..symbol = 'T'),
+ TypeReference((b) => b..symbol = 'U')
+ ])
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'T')
+ ..name = 'bar')),
+ equalsDart(r'''
+ extension type Foo<T,U>(T bar) { }
+ '''),
+ );
+ });
+
+ test('extension type with generics bound', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..types.add(TypeReference((b) => b
+ ..symbol = 'T'
+ ..bound = TypeReference((b) => b..symbol = 'num')))
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'T')
+ ..name = 'bar')),
+ equalsDart(r'''
+ extension type Foo<T extends num>(T bar) { }
+ '''),
+ );
+ });
+
+ test('extension type with named primary constructor', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..primaryConstructorName = 'named'
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')),
+ equalsDart(r'''
+ extension type Foo.named(int bar) { }
+ '''),
+ );
+ });
+
+ test('extension type with metadata on field', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar'
+ ..docs.add(
+ '/// My favorite representation declaration.',
+ )
+ ..annotations.addAll([
+ refer('deprecated'),
+ refer('Deprecated').call(
+ [literalString('This is an old representation declaration')])
+ ]))),
+ equalsDart(r'''
+ extension type Foo(/// My favorite representation declaration.
+ @deprecated
+ @Deprecated('This is an old representation declaration')
+ int bar) { }
+ '''),
+ );
+ });
+
+ test('extension type with implements', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..implements.add(TypeReference((b) => b.symbol = 'num'))
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')),
+ equalsDart(r'''
+ extension type Foo(int bar) implements num { }
+ '''),
+ );
+ });
+
+ test('extension type with multiple implements', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..implements.addAll([
+ TypeReference((b) => b.symbol = 'num'),
+ TypeReference((b) => b.symbol = 'Object')
+ ])
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')),
+ equalsDart(r'''
+ extension type Foo(int bar) implements num,Object { }
+ '''),
+ );
+ });
+
+ test('extension type with constructors', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..primaryConstructorName = '_'
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')
+ ..constructors.addAll([
+ Constructor((b) => b.requiredParameters.add(Parameter((b) => b
+ ..toThis = true
+ ..name = 'bar'))),
+ Constructor((b) => b
+ ..name = 'named'
+ ..factory = true
+ ..requiredParameters.add(Parameter((b) => b
+ ..type = TypeReference((b) => b.symbol = 'int')
+ ..name = 'baz'))
+ ..body = const Code('return Foo(baz);'))
+ ])),
+ equalsDart(r'''
+ extension type Foo._(int bar) {
+ Foo(this.bar);
+
+ factory Foo.named(int baz) {
+ return Foo(baz);
+ }
+ }
+ '''),
+ );
+ });
+
+ test('extension type with external field', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')
+ ..fields.add(Field((b) => b
+ ..external = true
+ ..type = TypeReference((b) => b.symbol = 'int')
+ ..name = 'property'))),
+ equalsDart(r'''
+ extension type Foo(int bar) {
+ external int property;
+ }
+ '''),
+ );
+ });
+
+ test('extension type with methods', () {
+ expect(
+ ExtensionType((b) => b
+ ..name = 'Foo'
+ ..representationDeclaration = RepresentationDeclaration((b) => b
+ ..declaredRepresentationType = TypeReference((b) => b.symbol = 'int')
+ ..name = 'bar')
+ ..methods.addAll([
+ Method((b) => b
+ ..type = MethodType.getter
+ ..returns = TypeReference((b) => b.symbol = 'int')
+ ..name = 'value'
+ ..body = const Code('return this.bar;')),
+ Method((b) => b
+ ..returns = TypeReference((b) => b.symbol = 'int')
+ ..name = 'getValue'
+ ..lambda = true
+ ..body = const Code('this.bar'))
+ ])),
+ equalsDart(r'''
+ extension type Foo(int bar) {
+ int get value { return this.bar; }
+ int getValue() => this.bar;
+ }
+ '''),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/specs/field_test.dart b/pkgs/code_builder/test/specs/field_test.dart
new file mode 100644
index 0000000..3d53687
--- /dev/null
+++ b/pkgs/code_builder/test/specs/field_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should create a field', () {
+ expect(
+ Field((b) => b..name = 'foo'),
+ equalsDart(r'''
+ var foo;
+ '''),
+ );
+ });
+
+ test('should create a typed field', () {
+ expect(
+ Field((b) => b
+ ..name = 'foo'
+ ..type = refer('String')),
+ equalsDart(r'''
+ String foo;
+ '''),
+ );
+ });
+
+ test('should create a final field', () {
+ expect(
+ Field((b) => b
+ ..name = 'foo'
+ ..modifier = FieldModifier.final$),
+ equalsDart(r'''
+ final foo;
+ '''),
+ );
+ });
+
+ test('should create a constant field', () {
+ expect(
+ Field((b) => b
+ ..name = 'foo'
+ ..modifier = FieldModifier.constant),
+ equalsDart(r'''
+ const foo;
+ '''),
+ );
+ });
+
+ test('should create a late field if using null-safety', () {
+ expect(
+ Field((b) => b
+ ..late = true
+ ..name = 'foo'),
+ equalsDart(r'''
+ late var foo;
+ ''', DartEmitter(useNullSafetySyntax: true)),
+ );
+ });
+
+ test('should not create a late field if not using null-safety', () {
+ expect(
+ Field((b) => b
+ ..late = true
+ ..name = 'foo'),
+ equalsDart(r'''
+ var foo;
+ '''),
+ );
+ });
+
+ test('should create a static late field', () {
+ expect(
+ Field((b) => b
+ ..static = true
+ ..late = true
+ ..name = 'foo'),
+ equalsDart(r'''
+ static late var foo;
+ ''', DartEmitter(useNullSafetySyntax: true)),
+ );
+ });
+
+ test('should create a field with an assignment', () {
+ expect(
+ Field((b) => b
+ ..name = 'foo'
+ ..assignment = const Code('1')),
+ equalsDart(r'''
+ var foo = 1;
+ '''),
+ );
+ });
+
+ test('should create a external field', () {
+ expect(
+ Field((b) => b
+ ..name = 'value'
+ ..external = true
+ ..type = refer('double')
+ ..annotations.addAll([refer('Float').call([])])),
+ equalsDart(r'''
+ @Float()
+ external double value;
+ '''),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/specs/library_test.dart b/pkgs/code_builder/test/specs/library_test.dart
new file mode 100644
index 0000000..8ea4c58
--- /dev/null
+++ b/pkgs/code_builder/test/specs/library_test.dart
@@ -0,0 +1,313 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ group('File', () {
+ final $LinkedHashMap = refer('LinkedHashMap', 'dart:collection');
+
+ test('should emit a source file with leading line comments', () {
+ expect(
+ Library(
+ (b) => b
+ ..comments.add('Generated by foo.')
+ ..body.add(
+ Class((b) => b..name = 'Foo'),
+ ),
+ ),
+ equalsDart(r'''
+ // Generated by foo.
+
+ class Foo { }
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit a source file with multiple leading comments', () {
+ expect(
+ Library(
+ (b) => b
+ ..comments.addAll([
+ 'Generated by foo!',
+ '',
+ 'Avoid editing by hand.',
+ ])
+ ..body.add(
+ Class((b) => b..name = 'Foo'),
+ ),
+ ),
+ equalsDart(r'''
+ // Generated by foo!
+ //
+ // Avoid editing by hand.
+
+ class Foo { }
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit a source file with a generated-by comment', () {
+ expect(
+ Library(
+ (b) => b
+ ..generatedByComment = 'Generated by fooBar.'
+ ..body.add(
+ Class((b) => b..name = 'Foo'),
+ ),
+ ),
+ equalsDart(r'''
+ // Generated by fooBar.
+
+ class Foo { }
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit a source file with ignore comments', () {
+ expect(
+ Library(
+ (b) => b
+ ..ignoreForFile.add('sort_constructors_first')
+ ..body.add(
+ Class((b) => b..name = 'Foo'),
+ ),
+ ),
+ equalsDart(r'''
+ // ignore_for_file: sort_constructors_first
+
+ class Foo { }
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit a source file with multiple, sorted ignore comments', () {
+ expect(
+ Library(
+ (b) => b
+ ..ignoreForFile.addAll([
+ 'type=lint',
+ 'sort_constructors_first',
+ 'implementation_imports',
+ 'file_names',
+ ])
+ ..body.add(
+ Class((b) => b..name = 'Foo'),
+ ),
+ ),
+ equalsDart(r'''
+ // ignore_for_file: file_names, implementation_imports, sort_constructors_first
+ // ignore_for_file: type=lint
+
+ class Foo { }
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit with line comments, generated-by, and ignore-for-file',
+ () {
+ expect(
+ Library(
+ (b) => b
+ ..comments.add('Generic copyright statement.')
+ ..generatedByComment = 'Generated by fooBar.'
+ ..ignoreForFile.add('sort_constructors_first')
+ ..body.add(
+ Class((b) => b..name = 'Foo'),
+ ),
+ ),
+ equalsDart(r'''
+ // Generic copyright statement.
+
+ // Generated by fooBar.
+
+ // ignore_for_file: sort_constructors_first
+
+ class Foo { }
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit a source file with manual imports', () {
+ expect(
+ Library((b) => b
+ ..directives.add(Directive.import('dart:collection'))
+ ..body.add(Field((b) => b
+ ..name = 'test'
+ ..modifier = FieldModifier.final$
+ ..assignment = $LinkedHashMap.newInstance([]).code))),
+ equalsDart(r'''
+ import 'dart:collection';
+
+ final test = LinkedHashMap();
+ ''', DartEmitter()),
+ );
+ });
+
+ test('should emit a source file with a deferred import', () {
+ expect(
+ Library(
+ (b) => b
+ ..directives.add(
+ Directive.importDeferredAs(
+ 'package:foo/foo.dart',
+ 'foo',
+ ),
+ ),
+ ),
+ equalsDart(r'''
+ import 'package:foo/foo.dart' deferred as foo;
+ '''),
+ );
+ });
+
+ test('should emit a source file with a "show" combinator', () {
+ expect(
+ Library(
+ (b) => b
+ ..directives.add(
+ Directive.import(
+ 'package:foo/foo.dart',
+ show: ['Foo', 'Bar'],
+ ),
+ ),
+ ),
+ equalsDart(r'''
+ import 'package:foo/foo.dart' show Foo, Bar;
+ '''),
+ );
+ });
+
+ test('should emit a source file with a "hide" combinator', () {
+ expect(
+ Library(
+ (b) => b
+ ..directives.add(
+ Directive.import(
+ 'package:foo/foo.dart',
+ hide: ['Foo', 'Bar'],
+ ),
+ ),
+ ),
+ equalsDart(r'''
+ import 'package:foo/foo.dart' hide Foo, Bar;
+ '''),
+ );
+ });
+
+ test('should emit a source file with allocation', () {
+ expect(
+ Library((b) => b
+ ..body.add(Field((b) => b
+ ..name = 'test'
+ ..modifier = FieldModifier.final$
+ ..assignment = Code.scope((a) => '${a($LinkedHashMap)}()')))),
+ equalsDart(r'''
+ import 'dart:collection';
+
+ final test = LinkedHashMap();
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit a source file with allocation + prefixing', () {
+ expect(
+ Library((b) => b
+ ..body.add(Field((b) => b
+ ..name = 'test'
+ ..modifier = FieldModifier.final$
+ ..assignment = Code.scope((a) => '${a($LinkedHashMap)}()')))),
+ equalsDart(r'''
+ // ignore_for_file: no_leading_underscores_for_library_prefixes
+ import 'dart:collection' as _i1;
+
+ final test = _i1.LinkedHashMap();
+ ''', DartEmitter(allocator: Allocator.simplePrefixing())),
+ );
+ });
+
+ test('should emit a source file with part directives', () {
+ expect(
+ Library(
+ (b) => b
+ ..directives.add(
+ Directive.part('test.g.dart'),
+ ),
+ ),
+ equalsDart(r'''
+ part 'test.g.dart';
+ ''', DartEmitter()),
+ );
+ });
+
+ test('should emit a source file with part of directives', () {
+ expect(
+ Library(
+ (b) => b
+ ..directives.add(
+ Directive.partOf('test.dart'),
+ ),
+ ),
+ equalsDart(r'''
+ part of 'test.dart';
+ ''', DartEmitter()),
+ );
+ });
+
+ test('should emit a source file with annotations', () {
+ expect(
+ Library(
+ (b) => b
+ ..name = 'js_interop'
+ ..annotations.add(
+ refer('JS', 'package:js/js.dart').call([]),
+ ),
+ ),
+ equalsDart(r'''
+ @JS()
+ library js_interop;
+ import 'package:js/js.dart';
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit an unnamed library source file with annotations', () {
+ expect(
+ Library(
+ (b) => b
+ ..annotations.add(
+ refer('JS', 'package:js/js.dart').call([]),
+ ),
+ ),
+ equalsDart(r'''
+ @JS()
+ library;
+ import 'package:js/js.dart';
+ ''', DartEmitter(allocator: Allocator())),
+ );
+ });
+
+ test('should emit an unnamed library source file with documentation', () {
+ expect(
+ Library(
+ (b) => b
+ ..docs.addAll(
+ const [
+ '/// My favorite library.',
+ ],
+ ),
+ ),
+ equalsDart(r'''
+ /// My favorite library.
+ library;
+ '''),
+ );
+ });
+ });
+}
diff --git a/pkgs/code_builder/test/specs/method_test.dart b/pkgs/code_builder/test/specs/method_test.dart
new file mode 100644
index 0000000..5621bc5
--- /dev/null
+++ b/pkgs/code_builder/test/specs/method_test.dart
@@ -0,0 +1,632 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should create a method', () {
+ expect(
+ Method((b) => b..name = 'foo'),
+ equalsDart(r'''
+ foo();
+ '''),
+ );
+ });
+
+ test('should create an async method', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..modifier = MethodModifier.async
+ ..body = literalNull.code),
+ equalsDart(r'''
+ foo() async => null
+ '''),
+ );
+ });
+
+ test('should create an async* method', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..modifier = MethodModifier.asyncStar
+ ..body = literalNull.code),
+ equalsDart(r'''
+ foo() async* => null
+ '''),
+ );
+ });
+
+ test('should create an sync* method', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..modifier = MethodModifier.syncStar
+ ..body = literalNull.code),
+ equalsDart(r'''
+ foo() sync* => null
+ '''),
+ );
+ });
+
+ test('should create a lambda method implicitly', () {
+ expect(
+ Method((b) => b
+ ..name = 'returnsTrue'
+ ..returns = refer('bool')
+ ..body = literalTrue.code),
+ equalsDart(r'''
+ bool returnsTrue() => true
+ '''),
+ );
+ });
+
+ test('should create a lambda method if the value is cast', () {
+ expect(
+ Method((b) => b
+ ..name = 'returnsCastedValue'
+ ..returns = refer('Foo')
+ ..body = refer('bar').asA(refer('Foo')).code),
+ equalsDart(r'''
+ Foo returnsCastedValue() => (bar as Foo)
+ '''),
+ );
+ });
+
+ test('should create a normal method implicitly', () {
+ expect(
+ Method.returnsVoid((b) => b
+ ..name = 'assignTrue'
+ ..body = refer('topLevelFoo').assign(literalTrue).statement),
+ equalsDart(r'''
+ void assignTrue() {
+ topLevelFoo = true;
+ }
+ '''),
+ );
+ });
+
+ test('should create a getter', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..external = true
+ ..type = MethodType.getter),
+ equalsDart(r'''
+ external get foo;
+ '''),
+ );
+ });
+
+ test('should create a setter', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..external = true
+ ..requiredParameters.add(Parameter((b) => b..name = 'foo'))
+ ..type = MethodType.setter),
+ equalsDart(r'''
+ external set foo(foo);
+ '''),
+ );
+ });
+
+ test('should create a method with a return type', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..returns = refer('String')),
+ equalsDart(r'''
+ String foo();
+ '''),
+ );
+ });
+
+ test('should create a method with a void return type', () {
+ expect(
+ Method.returnsVoid((b) => b..name = 'foo'),
+ equalsDart(r'''
+ void foo();
+ '''),
+ );
+ });
+
+ test('should create a method with a function type return type', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..returns = FunctionType((b) => b
+ ..returnType = refer('String')
+ ..requiredParameters.addAll([
+ refer('int'),
+ ]))),
+ equalsDart(r'''
+ String Function(int) foo();
+ '''),
+ );
+ });
+
+ test('should create a function type with an optional positional parameter',
+ () {
+ expect(
+ FunctionType((b) => b
+ ..returnType = refer('String')
+ ..optionalParameters.add(refer('int'))),
+ equalsDart(r'''
+ String Function([int])
+ '''),
+ );
+ });
+
+ test(
+ 'should create a function type with a required '
+ 'and an optional positional parameter', () {
+ expect(
+ FunctionType((b) => b
+ ..returnType = refer('String')
+ ..requiredParameters.add(refer('int'))
+ ..optionalParameters.add(refer('int'))),
+ equalsDart(r'''
+ String Function(int, [int, ])
+ '''),
+ );
+ });
+
+ test('should create a function type without parameters', () {
+ expect(
+ FunctionType((b) => b..returnType = refer('String')),
+ equalsDart(r'''
+ String Function()
+ '''),
+ );
+ });
+
+ test('should create a function type with an optional named parameter', () {
+ expect(
+ FunctionType((b) => b
+ ..returnType = refer('String')
+ ..namedParameters['named'] = refer('int')),
+ equalsDart(r'''
+ String Function({int named})
+ '''),
+ );
+ });
+
+ test(
+ 'should create a function type with a required '
+ 'and an optional named parameter', () {
+ expect(
+ FunctionType((b) => b
+ ..returnType = refer('String')
+ ..requiredParameters.add(refer('int'))
+ ..namedParameters['named'] = refer('int')),
+ equalsDart(r'''
+ String Function(int, {int named, })
+ '''),
+ );
+ });
+
+ test('should create a function type with a required named parameter', () {
+ expect(
+ FunctionType((b) => b
+ ..returnType = refer('String')
+ ..namedRequiredParameters['named'] = refer('int')),
+ equalsDart(r'''
+ String Function({required int named})
+ '''),
+ );
+ });
+
+ test(
+ 'should create a function type with a required named and an optional '
+ 'named parameter', () {
+ expect(
+ FunctionType((b) => b
+ ..returnType = refer('String')
+ ..namedRequiredParameters['named'] = refer('int')
+ ..namedParameters['optional'] = refer('int')),
+ equalsDart(r'''
+ String Function({required int named, int optional, })
+ '''),
+ );
+ });
+
+ test('should create a typedef to a reference', () {
+ expect(
+ TypeDef((b) => b
+ ..name = 'i32'
+ ..definition = const Reference('int')),
+ equalsDart(r'''
+ typedef i32 = int;
+ '''),
+ );
+ });
+
+ test('should create a typedef to a function type', () {
+ expect(
+ TypeDef((b) => b
+ ..name = 'MyMapper'
+ ..definition = FunctionType((b) => b
+ ..returnType = refer('String')
+ ..optionalParameters.add(refer('int')))),
+ equalsDart(r'''
+ typedef MyMapper = String Function([int]);
+ '''),
+ );
+ });
+
+ test('should create a method with a nested function type return type', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..returns = FunctionType((b) => b
+ ..returnType = FunctionType((b) => b
+ ..returnType = refer('String')
+ ..requiredParameters.add(refer('String')))
+ ..requiredParameters.addAll([
+ refer('int'),
+ ]))),
+ equalsDart(r'''
+ String Function(String) Function(int) foo();
+ '''),
+ );
+ });
+
+ test('should create a method with a function type argument', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..requiredParameters.add(Parameter((b) => b
+ ..type = FunctionType((b) => b
+ ..returnType = refer('String')
+ ..requiredParameters.add(refer('int')))
+ ..name = 'argument'))),
+ equalsDart(r'''
+ foo(String Function(int) argument);
+ '''));
+ });
+
+ test('should create a method with a nested function type argument', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..requiredParameters.add(Parameter((b) => b
+ ..type = FunctionType((b) => b
+ ..returnType = FunctionType((b) => b
+ ..returnType = refer('String')
+ ..requiredParameters.add(refer('String')))
+ ..requiredParameters.add(refer('int')))
+ ..name = 'argument'))),
+ equalsDart(r'''
+ foo(String Function(String) Function(int) argument);
+ '''));
+ });
+
+ test('should create a method with generic types', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..types.add(refer('T'))),
+ equalsDart(r'''
+ foo<T>();
+ '''),
+ );
+ });
+
+ test('should create an external method', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..external = true),
+ equalsDart(r'''
+ external foo();
+ '''),
+ );
+ });
+
+ test('should create a method with a body', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..body = const Code('return 1+ 2;')),
+ equalsDart(r'''
+ foo() {
+ return 1 + 2;
+ }
+ '''),
+ );
+ });
+
+ test('should create a lambda method (explicitly)', () {
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..lambda = true
+ ..body = const Code('1 + 2')),
+ equalsDart(r'''
+ foo() => 1 + 2
+ '''),
+ );
+ });
+
+ test('should create a method with a body with references', () {
+ final $LinkedHashMap = refer('LinkedHashMap', 'dart:collection');
+ expect(
+ Method((b) => b
+ ..name = 'foo'
+ ..body = Code.scope(
+ (a) => 'return ${a($LinkedHashMap)}();',
+ )),
+ equalsDart(r'''
+ foo() {
+ return LinkedHashMap();
+ }
+ '''),
+ );
+ });
+
+ test('should create a method with a parameter', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..requiredParameters.add(
+ Parameter((b) => b.name = 'i'),
+ ),
+ ),
+ equalsDart(r'''
+ fib(i);
+ '''),
+ );
+ });
+
+ test('should create a method with an annotated parameter', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..requiredParameters.add(
+ Parameter((b) => b
+ ..name = 'i'
+ ..annotations.add(refer('deprecated'))),
+ ),
+ ),
+ equalsDart(r'''
+ fib(@deprecated i);
+ '''),
+ );
+ });
+
+ test('should create a method with a parameter with a type', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..requiredParameters.add(
+ Parameter(
+ (b) => b
+ ..name = 'i'
+ ..type = refer('int').type,
+ ),
+ ),
+ ),
+ equalsDart(r'''
+ fib(int i);
+ '''),
+ );
+ });
+
+ test('should create a method with a covariant parameter with a type', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..requiredParameters.add(
+ Parameter(
+ (b) => b
+ ..name = 'i'
+ ..covariant = true
+ ..type = refer('int').type,
+ ),
+ ),
+ ),
+ equalsDart(r'''
+ fib(covariant int i);
+ '''),
+ );
+ });
+
+ test('should create a method with a parameter with a generic type', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'foo'
+ ..types.add(TypeReference((b) => b
+ ..symbol = 'T'
+ ..bound = refer('Iterable')))
+ ..requiredParameters.addAll([
+ Parameter(
+ (b) => b
+ ..name = 't'
+ ..type = refer('T'),
+ ),
+ Parameter((b) => b
+ ..name = 'x'
+ ..type = TypeReference((b) => b
+ ..symbol = 'X'
+ ..types.add(refer('T')))),
+ ]),
+ ),
+ equalsDart(r'''
+ foo<T extends Iterable>(T t, X<T> x, );
+ '''),
+ );
+ });
+
+ test('should create a method with an optional parameter', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..optionalParameters.add(
+ Parameter((b) => b.name = 'i'),
+ ),
+ ),
+ equalsDart(r'''
+ fib([i]);
+ '''),
+ );
+ });
+
+ test('should create a method with multiple optional parameters', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'foo'
+ ..optionalParameters.addAll([
+ Parameter((b) => b.name = 'a'),
+ Parameter((b) => b.name = 'b'),
+ ]),
+ ),
+ equalsDart(r'''
+ foo([a, b, ]);
+ '''),
+ );
+ });
+
+ test('should create a method with an optional parameter with a value', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..optionalParameters.add(
+ Parameter((b) => b
+ ..name = 'i'
+ ..defaultTo = const Code('0')),
+ ),
+ ),
+ equalsDart(r'''
+ fib([i = 0]);
+ '''),
+ );
+ });
+
+ test('should create a method with a named required parameter', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..optionalParameters.add(
+ Parameter(
+ (b) => b
+ ..name = 'i'
+ ..named = true
+ ..required = true
+ ..type = refer('int').type,
+ ),
+ ),
+ ),
+ equalsDart(r'''
+ fib({required int i});
+ '''),
+ );
+ });
+
+ test('should create a method with a named required covariant parameter', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..optionalParameters.add(
+ Parameter(
+ (b) => b
+ ..name = 'i'
+ ..named = true
+ ..required = true
+ ..covariant = true
+ ..type = refer('int').type,
+ ),
+ ),
+ ),
+ equalsDart(r'''
+ fib({required covariant int i});
+ '''),
+ );
+ });
+
+ test('should create a method with a named optional parameter', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..optionalParameters.add(
+ Parameter((b) => b
+ ..named = true
+ ..name = 'i'),
+ ),
+ ),
+ equalsDart(r'''
+ fib({i});
+ '''),
+ );
+ });
+
+ test('should create a method with a named optional parameter with value', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'fib'
+ ..optionalParameters.add(
+ Parameter((b) => b
+ ..named = true
+ ..name = 'i'
+ ..defaultTo = const Code('0')),
+ ),
+ ),
+ equalsDart(r'''
+ fib({i = 0});
+ '''),
+ );
+ });
+
+ test('should create a method with a mix of parameters', () {
+ expect(
+ Method(
+ (b) => b
+ ..name = 'foo'
+ ..requiredParameters.add(
+ Parameter((b) => b..name = 'a'),
+ )
+ ..optionalParameters.add(
+ Parameter((b) => b
+ ..named = true
+ ..name = 'b'),
+ ),
+ ),
+ equalsDart(r'''
+ foo(a, {b, });
+ '''),
+ );
+ });
+
+ test('should create a method as a closure', () {
+ expect(
+ Method(
+ (b) => b
+ ..requiredParameters.add(
+ Parameter((b) => b..name = 'a'),
+ )
+ ..body = const Code(''),
+ ).closure,
+ equalsDart(r'''
+ (a) { }
+ '''),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/specs/mixin_test.dart b/pkgs/code_builder/test/specs/mixin_test.dart
new file mode 100644
index 0000000..e167d02
--- /dev/null
+++ b/pkgs/code_builder/test/specs/mixin_test.dart
@@ -0,0 +1,150 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should create a mixin', () {
+ expect(
+ Mixin((b) => b..name = 'Foo'),
+ equalsDart(r'''
+ mixin Foo {}
+ '''),
+ );
+ });
+
+ test('should create a base mixin', () {
+ expect(
+ Mixin((b) => b
+ ..name = 'Foo'
+ ..base = true),
+ equalsDart(r'''
+ base mixin Foo {}
+ '''),
+ );
+ });
+
+ test('should create a mixin with documentations', () {
+ expect(
+ Mixin(
+ (b) => b
+ ..name = 'Foo'
+ ..docs.addAll(
+ const [
+ '/// My favorite mixin.',
+ ],
+ ),
+ ),
+ equalsDart(r'''
+ /// My favorite mixin.
+ mixin Foo {}
+ '''),
+ );
+ });
+
+ test('should create a mixin with annotations', () {
+ expect(
+ Mixin(
+ (b) => b
+ ..name = 'Foo'
+ ..annotations.addAll([
+ refer('deprecated'),
+ refer('Deprecated').call([literalString('This is an old mixin')])
+ ]),
+ ),
+ equalsDart(r'''
+ @deprecated
+ @Deprecated('This is an old mixin')
+ mixin Foo {}
+ '''),
+ );
+ });
+
+ test('should create a mixin with a generic type', () {
+ expect(
+ Mixin((b) => b
+ ..name = 'List'
+ ..types.add(refer('T'))),
+ equalsDart(r'''
+ mixin List<T> {}
+ '''),
+ );
+ });
+
+ test('should create a mixin with multiple generic types', () {
+ expect(
+ Mixin(
+ (b) => b
+ ..name = 'Map'
+ ..types.addAll([
+ refer('K'),
+ refer('V'),
+ ]),
+ ),
+ equalsDart(r'''
+ mixin Map<K, V> {}
+ '''),
+ );
+ });
+
+ test('should create a mixin with a bound generic type', () {
+ expect(
+ Mixin((b) => b
+ ..name = 'Comparable'
+ ..types.add(TypeReference((b) => b
+ ..symbol = 'T'
+ ..bound = TypeReference((b) => b
+ ..symbol = 'Comparable'
+ ..types.add(refer('T').type))))),
+ equalsDart(r'''
+ mixin Comparable<T extends Comparable<T>> {}
+ '''),
+ );
+ });
+
+ test('should create a mixin on another mixin', () {
+ expect(
+ Mixin((b) => b
+ ..name = 'Foo'
+ ..on = TypeReference((b) => b.symbol = 'Bar')),
+ equalsDart(r'''
+ mixin Foo on Bar {}
+ '''),
+ );
+ });
+
+ test('should create a mixin implementing another mixin', () {
+ expect(
+ Mixin((b) => b
+ ..name = 'Foo'
+ ..on = TypeReference((b) => b.symbol = 'Bar')
+ ..implements.add(TypeReference((b) => b.symbol = 'Foo'))),
+ equalsDart(r'''
+ mixin Foo on Bar implements Foo {}
+ '''),
+ );
+ });
+
+ test('should create a mixin with a method', () {
+ expect(
+ Mixin((b) => b
+ ..name = 'Foo'
+ ..methods.add(Method((b) => b
+ ..name = 'foo'
+ ..body = const Code('return 1+ 2;')))),
+ equalsDart(r'''
+ mixin Foo {
+ foo() {
+ return 1 + 2;
+ }
+ }
+ '''),
+ );
+ });
+}
diff --git a/pkgs/code_builder/test/specs/record_type_test.dart b/pkgs/code_builder/test/specs/record_type_test.dart
new file mode 100644
index 0000000..0084c50
--- /dev/null
+++ b/pkgs/code_builder/test/specs/record_type_test.dart
@@ -0,0 +1,68 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ late DartEmitter emitter;
+
+ useDartfmt();
+
+ setUp(() => emitter = DartEmitter.scoped(useNullSafetySyntax: true));
+
+ final intRef = TypeReference((b) => b.symbol = 'int');
+ TypeReference listRef(TypeReference argType) => TypeReference((b) => b
+ ..symbol = 'List'
+ ..types.add(argType));
+
+ test('should create an empty record type', () {
+ expect(RecordType(), equalsDart('()', emitter));
+ });
+
+ test('should create a record type with positional fields', () {
+ expect(
+ RecordType((b) => b
+ ..positionalFieldTypes.addAll(
+ [intRef, listRef(intRef).rebuild((b) => b..isNullable = true)])
+ ..isNullable = true),
+ equalsDart('(int, List<int>?)?', emitter),
+ );
+ });
+
+ test('should create a record type with one positional field', () {
+ expect(RecordType((b) => b..positionalFieldTypes.add(intRef)),
+ equalsDart('(int,)', emitter));
+ });
+
+ test('should create a record type with named fields', () {
+ expect(
+ RecordType((b) => b
+ ..namedFieldTypes.addAll({
+ 'named': intRef,
+ 'other': listRef(intRef),
+ })),
+ equalsDart('({int named, List<int> other})', emitter));
+ });
+
+ test('should create a record type with both positional and named fields', () {
+ expect(
+ RecordType((b) => b
+ ..positionalFieldTypes.add(listRef(intRef))
+ ..namedFieldTypes.addAll({'named': intRef})
+ ..isNullable = true),
+ equalsDart('(List<int>, {int named})?', emitter));
+ });
+
+ test('should create a nested record type', () {
+ expect(
+ RecordType((b) => b
+ ..positionalFieldTypes.add(RecordType((b) => b
+ ..namedFieldTypes.addAll({'named': intRef, 'other': intRef})
+ ..isNullable = true))),
+ equalsDart('(({int named, int other})?,)', emitter));
+ });
+}
diff --git a/pkgs/code_builder/test/specs/type_reference_test.dart b/pkgs/code_builder/test/specs/type_reference_test.dart
new file mode 100644
index 0000000..35365cb
--- /dev/null
+++ b/pkgs/code_builder/test/specs/type_reference_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:code_builder/code_builder.dart';
+import 'package:test/test.dart';
+
+import '../common.dart';
+
+void main() {
+ useDartfmt();
+
+ test('should create a nullable type in a pre-Null Safety library', () {
+ expect(
+ TypeReference((b) => b
+ ..symbol = 'Foo'
+ ..isNullable = true),
+ equalsDart(r'''
+ Foo
+ '''),
+ );
+ });
+
+ group('in a Null Safety library', () {
+ late DartEmitter emitter;
+
+ setUp(() => emitter = DartEmitter.scoped(useNullSafetySyntax: true));
+
+ test('should create a nullable type', () {
+ expect(
+ TypeReference((b) => b
+ ..symbol = 'Foo'
+ ..isNullable = true),
+ equalsDart(r'Foo?', emitter),
+ );
+ });
+
+ test('should create a non-nullable type', () {
+ expect(
+ TypeReference((b) => b.symbol = 'Foo'),
+ equalsDart(r'Foo', emitter),
+ );
+ });
+
+ test('should create a type with nullable type arguments', () {
+ expect(
+ TypeReference((b) => b
+ ..symbol = 'List'
+ ..types.add(TypeReference((b) => b
+ ..symbol = 'int'
+ ..isNullable = true))),
+ equalsDart(r'List<int?>', emitter),
+ );
+ });
+ });
+}
diff --git a/pkgs/code_builder/tool/regenerate.sh b/pkgs/code_builder/tool/regenerate.sh
new file mode 100755
index 0000000..722e98a
--- /dev/null
+++ b/pkgs/code_builder/tool/regenerate.sh
@@ -0,0 +1,7 @@
+# Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+dart run build_runner generate-build-script
+dart compile kernel .dart_tool/build/entrypoint/build.dart
+dart .dart_tool/build/entrypoint/build.dill build --delete-conflicting-outputs
diff --git a/pkgs/coverage/.gitignore b/pkgs/coverage/.gitignore
new file mode 100644
index 0000000..1a25097
--- /dev/null
+++ b/pkgs/coverage/.gitignore
@@ -0,0 +1,18 @@
+# Pub
+packages
+pubspec.lock
+build
+.dart_tool/
+.pub
+.packages
+
+# IDEs
+.project
+.settings
+.idea
+*.iml
+
+# Temp files
+*~
+coverage/
+var/
diff --git a/pkgs/coverage/AUTHORS b/pkgs/coverage/AUTHORS
new file mode 100644
index 0000000..7513829
--- /dev/null
+++ b/pkgs/coverage/AUTHORS
@@ -0,0 +1,12 @@
+# Below is a list of people and organizations that have contributed
+# to the coverage project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
+Achilleas Anagnostopoulos <achilleas.imap.mbox@gmail.com>
+Adam Singer <adammichaelsinger@gmail.com>
+Cédric Belin <cedxbelin@gmail.com>
+Evan Weible <ekweible@gmail.com>
+Günter Zöchbauer <guenter@gzoechbauer.com>
+Will Drach <will.drach@gmail.com>
diff --git a/pkgs/coverage/CHANGELOG.md b/pkgs/coverage/CHANGELOG.md
new file mode 100644
index 0000000..685c1c0
--- /dev/null
+++ b/pkgs/coverage/CHANGELOG.md
@@ -0,0 +1,507 @@
+## 1.11.1
+
+- Update `package:vm_service` constraints to '>=12.0.0 <16.0.0'.
+
+## 1.11.0
+
+- Fix a [bug](https://github.com/dart-lang/tools/issues/685) where the tool
+ would occasionally try to resume an isolate after the VM service had been
+ disposed.
+
+## 1.10.0
+
+- Fix a [bug](https://github.com/dart-lang/tools/issues/520) where tests
+ involving multiple isolates never finish.
+
+## 1.9.2
+
+- Fix repository link in pubspec.
+
+## 1.9.1
+
+- Remove outdated VM service version checks.
+- Move to `dart-lang/tools`.
+
+## 1.9.0
+
+- Require Dart ^3.4
+- Fix bug where some ranges were able to bypass the `--scope-output` filters.
+- Add --ignore-files option allowing to exclude files from coverage reports using glob patterns
+
+## 1.8.0
+
+- Copy collect_coverage's `--scope-output` flag to test_with_coverage.
+
+## 1.7.2
+
+- Update `package:vm_service` constraints to '>=12.0.0 <15.0.0'.
+
+## 1.7.1
+
+- Update `package:vm_service` constraints to '>=12.0.0 <14.0.0'.
+
+## 1.7.0
+
+- Require Dart 3.0.0
+- Update `package:vm_service` constraints to '^12.0.0'.
+- Add `coverableLineCache` parameter to `collect`. This allows the set of
+ coverable lines to be cached between calls to `collect`, avoiding the need to
+ force compile the same libraries repeatedly. This is only useful when running
+ multiple coverage collections over the same libraries.
+
+## 1.6.4
+
+- allow omitting space between `//` and `coverage` in coverage ignore comments
+- allow text after coverage ignore comments
+- throw FormatException when encountering unbalanced ignore comments instead of silently erroring
+- Update `package:vm_service` constraints to '>= 9.4.0 <12.0.0'.
+
+## 1.6.3
+
+- Require Dart 2.18
+- Update `package:vm_service` constraints to '>=9.4.0 <12.0.0'.
+
+## 1.6.2
+
+- Update `package:vm_service` constraints to '>=9.4.0 <11.0.0'.
+
+## 1.6.1
+
+- Handle SentinelExceptions thrown by vm_service.
+
+## 1.6.0
+
+- Update to vm_service 9.4.0.
+- Use IsolateRef.isolateGroupId to speed up coverage collection.
+- Ignore uncoverable abstract methods.
+- Fix bug where 'ingore-line' comments etc are applied even if they're inside
+ string literals.
+- Change the LICENSE file to the standard Dart BSD license.
+
+## 1.5.0
+
+- Support passing extra arguments to `test_with_coverage` which are then passed
+ to `package:test`.
+
+ Example: `dart run coverage:test_with_coverage -- --preset CI`
+
+## 1.4.0
+
+- Added `HitMap.parseJsonSync` which takes a cache of ignored lines which can
+ speedup calls when `checkIgnoredLines` is true and the function is called
+ several times with overlapping files in the input json.
+- Bump the version of vm_service to 9.0.0.
+
+## 1.3.2
+
+- Fix test_with_coverage listening to an unsupported signal on windows.
+- Fix `--reportOn` on windows using incorrect path separators.
+
+## 1.3.1
+
+- Fix running `dart pub global run coverage:test_with_coverage` or
+ `dart run coverage:test_with_coverage`
+
+## 1.3.0
+
+- Bump the minimum Dart SDK version to 2.15.0
+- Add a `--package` flag, which takes the package's root directory, instead of
+ the .package file. Deprecate the `--packages` flag.
+- Deprecate the packagesPath parameter and add packagePath instead, in
+ `HitMap.parseJson`, `HitMap.parseFiles`, `createHitmap`, and `parseCoverage`.
+- Add a new executable to the package, `test_with_coverage`. This simplifies the
+ most common use case of coverage, running all the tests for a package, and
+ generating an lcov.info file.
+- Use the `libraryFilters` option in `getSourceReport` to speed up coverage runs
+ that use `scopedOutput`.
+
+## 1.2.0
+
+- Support branch level coverage information, when running tests in the Dart VM.
+ This is not supported for web tests yet.
+- Add flag `--branch-coverage` (abbr `-b`) to collect_coverage that collects
+ branch coverage information. The VM must also be run with the
+ `--branch-coverage` flag.
+- Add flag `--pretty-print-branch` to format_coverage that works similarly to
+ pretty print, but outputs branch level coverage, rather than line level.
+- Update `--lcov` (abbr `-l`) in format_coverage to output branch level
+ coverage, in addition to line level.
+- Add an optional bool flag to `collect` that controls whether branch coverage
+ is collected.
+- Add a `branchHits` field to `HitMap`.
+- Add support for scraping the service URI from the new Dart VM service message.
+- Correctly parse package_config files on Windows when the root URI is relative.
+
+## 1.1.0
+
+- Support function level coverage information, when running tests in the Dart
+ VM. This is not supported for web tests yet.
+- Add flag `--function-coverage` (abbr `-f`) to collect_coverage that collects
+ function coverage information.
+- Add flag `--pretty-print-func` (abbr `-f`) to format_coverage that works
+ similarly to pretty print, but outputs function level coverage, rather than
+ line level.
+- Update `--lcov` (abbr `-l`) in format_coverage to output function level
+ coverage, in addition to line level.
+- Add an optional bool flag to `collect` that controls whether function coverage
+ is collected.
+- Added `HitMap.parseJson`, `FileHitMaps.merge`, `HitMap.parseFiles`,
+ `HitMap.toJson`, `FileHitMapsFormatter.formatLcov`, and
+ `FileHitMapsFormatter.prettyPrint` that switch from using `Map<int, int>` to
+ represent line coverage to using `HitMap` (which contains both line and
+ function coverage). Document the old versions of these functions as
+ deprecated. We will delete the old functions when we update to coverage
+ version 2.0.0.
+- Ensure `createHitmap` returns a sorted hitmap. This fixes a potential issue
+ with ignore line annotations.
+- Use the `reportLines` flag in `vm_service`'s `getSourceReport` RPC. This
+ typically halves the number of RPCs that the coverage collector needs to run.
+- Require Dart `>=2.14.0`
+
+## 1.0.4
+
+- Updated dependency on `vm_service` package from `>=6.1.0 <8.0.0`to
+ `>=8.1.0 <9.0.0`.
+
+## 1.0.3
+
+- Updated dependency on `vm_service` package from `^6.1.0` to `>=6.1.0 <8.0.0`.
+
+## 1.0.2
+
+- Fix an issue where the `--packages` argument wasn't passed to
+ `format_coverage`.
+
+## 1.0.1
+
+- Allow the chrome `sourceUriProvider` to return `null`.
+
+## 1.0.0
+
+- Migrate to null safety.
+- Removed support for SDK `1.x.x`.
+
+## 0.15.2
+
+- Update `args`, `logging`, and `package_config` deps to allow the latest stable
+ releases.
+
+## 0.15.1
+
+- Updated dependency on `vm_service` package from `>=1.0.0 < 5.0.0` to
+ `>=1.0.0 <7.0.0`.
+
+## 0.15.0
+
+- BREAKING CHANGE: Eliminate the `--package-root` option from
+ `bin/run_and_collect.dart` and `bin/format_coverage.dart` as well as from
+ `runAndCollect` and the `Resolver` constructor.
+
+## 0.14.2
+
+- Fix an issue where `--wait-paused` with `collect` would attempt to collect
+ coverage if no isolates have started.
+
+## 0.14.1
+
+- Updated dependency on `vm_service` package from `>=1.0.0 < 5.0.0` to
+ `>=1.0.0 <6.0.0`.
+
+## 0.14.0
+
+- Add flag `--check-ignore` that is used to ignore lines from coverage depending
+ on the comments.
+
+ Use // coverage:ignore-line to ignore one line. Use // coverage:ignore-start
+ and // coverage:ignore-end to ignore range of lines inclusive. Use //
+ coverage:ignore-file to ignore the whole file.
+
+## 0.13.11
+
+- Revert breaking change in 13.10
+
+## 0.13.10
+
+- Add flag `--check-ignore` that is used to ignore lines from coverage depending
+ on the comments.
+
+ Use // coverage:ignore-line to ignore one line. Use // coverage:ignore-start
+ and // coverage:ignore-end to ignore range of lines inclusive. Use //
+ coverage:ignore-file to ignore the whole file.
+
+## 0.13.9
+
+- Don't crash on empty JSON input files.
+- Loosen the dependency on the `vm_service` package from `>=1.0.0 <4.0.0` to
+ `>=1.0.0 <5.0.0`.
+
+## 0.13.8
+
+- Update to package_config `1.9.0` which supports package_config.json files and
+ should be forwards compatible with `2.0.0`.
+- Deprecate the `packageRoot` argument on `Resolver`.
+
+## 0.13.7
+
+- Loosen the dependency on the `vm_service` package from `>=1.0.0 <3.0.0` to
+ `>=1.0.0 <4.0.0`.
+
+## 0.13.6
+
+- Now consider all `.json` files for the `format_coverage` command.
+
+## 0.13.5
+
+- Update `parseChromeCoverage` to merge coverage information for a given line.
+- Handle source map parse errors in `parseChromeCoverage`. Coverage will not be
+ considered for Dart files that have corresponding invalid source maps.
+
+## 0.13.4
+
+- Add `parseChromeCoverage` for creating a Dart based coverage report from a
+ Chrome coverage report.
+
+## 0.13.3+3 - 2019-12-03
+
+- Re-loosen the dependency on the `vm_service` package from `>=1.0.0 < 2.1.2` to
+ `>=1.0.0 <3.0.0` now that breakage introduced in version `2.1.2` has been
+ resolved. Fixed in:
+ https://github.com/dart-lang/sdk/commit/7a911ce3f1e945f2cbd1967c6109127e3acbab5a.
+
+## 0.13.3+2 - 2019-12-02
+
+- Tighten the dependency on the `vm_service` package from `>=1.0.0 <3.0.0` down
+ to `>=1.0.0 <2.1.2` in order to exclude version `2.1.2` which is broken on the
+ current stable Dart VM due to a missing SDK constraint in its pubspec.yaml.
+ The breakage was introduced in:
+ https://github.com/dart-lang/sdk/commit/9e636b5ab4de850fb19bc262e0686fdf14bfbfc0.
+
+## 0.13.3+1 - 2019-10-10
+
+- Loosen the dependency on the `vm_service` package from `^1.0.0` to
+ `>=1.0.0 <3.0.0`. Ensures dependency version range compatibility with the
+ latest versions of package `test`.
+
+## 0.13.3
+
+- Adds a new named argument to `collect` to filter coverage results by a set of
+ VM isolate IDs.
+- Migrates implementation of VM service protocol library from
+ `package:vm_service_lib`, which is no longer maintained, to
+ `package:vm_service`, which is.
+
+## 0.13.2
+
+- Add new multi-flag option `--scope-output` which restricts coverage output so
+ that only scripts that start with the provided path are considered.
+
+## 0.13.1
+
+- Handle scenario where the VM returns empty coverage information for a range.
+
+## 0.13.0
+
+- BREAKING CHANGE: Skips collecting coverage for `dart:` libraries by default,
+ which provides a significant performance boost. To restore the previous
+ behaviour and collect coverage for these libraries, use the `--include-dart`
+ flag.
+- Disables WebSocket compression for coverage collection. Since almost all
+ coverage collection runs happen over the loopback interface to localhost, this
+ improves performance and reduces CPU usage.
+- Migrates implementation of VM service protocol library from
+ `package:vm_service_client`, which is no longer maintained, to
+ `package:vm_service_lib`, which is.
+
+## 0.12.4
+
+- `collect()` now immediately throws `ArgumentError` if a null URI is passed in
+ the `serviceUri` parameter to avoid a less-easily debuggable null dereference
+ later. See dart-lang/coverage#240 for details.
+
+## 0.12.3
+
+- Fixed dart-lang/coverage#194. During collection, we now track each script by
+ its (unique) VMScriptRef. This ensures we look up the correct script when
+ computing the affected line for each hit token. The hitmap remains URI based,
+ since in the end, we want a single, unified set of line to hitCount mappings
+ per script.
+
+## 0.12.2
+
+- Dart SDK upper bound raised to <3.0.0.
+
+## 0.12.1
+
+- Minor type, dartfmt fixes.
+- Require package:args >= 1.4.0.
+
+## 0.12.0
+
+- BREAKING CHANGE: This version requires Dart SDK 2.0.0-dev.64.1 or later.
+- Strong mode fixes as of Dart SDK 2.0.0-dev.64.1.
+
+## 0.11.0
+
+- BREAKING CHANGE: This version requires Dart SDK 2.0.0-dev.30 or later.
+- Updated to Dart 2.0 constants from dart:convert.
+
+## 0.10.0
+
+- BREAKING CHANGE: `createHitmap` and `mergeHitmaps` now specify generic types
+ (`Map<String, Map<int, int>>`) on their hit map parameter/return value.
+- Updated package:args dependency to 1.0.0.
+
+## 0.9.3
+
+- Strong mode fixes as of Dart SDK 1.24.0.
+- Restrict the SDK lower version constraint to `>=1.21.0`. Required for method
+ generics.
+- Eliminate dependency on package:async.
+
+## 0.9.2
+
+- Strong mode fixes as of Dart SDK 1.22.0.
+
+## 0.9.1
+
+- Temporarily add back support for the `--host` and `--port` options to
+ `collect_coverage`. This is a temporary measure for backwards-compatibility
+ that may stop working on Dart SDKs >= 1.22. See the related
+ [breaking change note](https://groups.google.com/a/dartlang.org/forum/#!msg/announce/VxSw-V5tx8k/wPV0GfX7BwAJ)
+ for the Dart VM service protocol.
+
+## 0.9.0
+
+- BREAKING CHANGE: `collect` no longer supports the `host` and `port`
+ parameters. These are replaced with a `serviceUri` parameter. As of Dart SDK
+ 1.22, the Dart VM will emit Observatory URIs that include an authentication
+ token for security reasons. Automated tools will need to scrape stdout for
+ this URI and pass it to `collect_coverage`.
+- BREAKING CHANGE: `collect_coverage`: the `--host` and `--port` options have
+ been replaced with a `--uri` option. See the above change for details.
+- BREAKING CHANGE: `runAndCollect` now defaults to running in checked mode.
+- Added `extractObservatoryUri`: scrapes an input string for an Observatory URI.
+ Potentially useful for automated tooling after Dart SDK 1.22.
+
+## 0.8.1
+
+- Added optional `checked` parameter to `runAndCollect` to run in checked mode.
+
+## 0.8.0+2
+
+- Strong mode fixes as of Dart SDK 1.20.1.
+
+## 0.8.0+1
+
+- Make strong mode clean.
+
+## 0.8.0
+
+- Moved `Formatter.format` parameters `reportOn` and `basePath` to constructor.
+ Eliminated `pathFilter` parameter.
+
+## 0.7.9
+
+- `format_coverage`: add `--base-directory` option. Source paths in
+ LCOV/pretty-print output are relative to this directory, or absolute if
+ unspecified.
+
+## 0.7.8
+
+- `format_coverage`: support `--packages` option for package specs.
+
+## 0.7.7
+
+- Add fallback URI resolution for Bazel http(s) URIs that don't contain a
+ `packages` path component.
+
+## 0.7.6
+
+- Add [Bazel](http://bazel.io) support to `format_coverage`.
+
+## 0.7.5
+
+- Bugfix in `collect_coverage`: prevent hang if initial VM service connection is
+ slow.
+- Workaround for VM behaviour in which `evaluate:source` ranges may appear in
+ the returned source report manifesting in a crash in `collect_coverage`. These
+ generally correspond to source evaluations in the debugger and add little
+ value to line coverage.
+- `format_coverage`: may be slower for large sets of coverage JSON input files.
+ Unlikely to be an issue due to elimination of `--coverage-dir` VM flag.
+
+## 0.7.4
+
+- Require at least Dart SDK 1.16.0.
+
+- Bugfix in format_coverage: if `--report-on` is not specified, emit all
+ coverage, rather than none.
+
+## 0.7.3
+
+- Added support for the latest Dart SDK.
+
+## 0.7.2
+
+- `Formatter.format` added two optional arguments: `reportOn` and `pathFilter`.
+ They can be used independently to limit the files which are included in the
+ output.
+
+- Added `runAndCollect` API to library.
+
+## 0.7.1
+
+- Added `collect` top-level method.
+
+- Updated support for latest `0.11.0` dev build.
+
+- Replaced `ServiceEvent.eventType` with `ServiceEvent.kind`.
+ - `ServiceEvent.eventType` is deprecated and will be removed in `0.8`.
+
+## 0.7.0
+
+- `format_coverage` no longer emits SDK coverage unless --sdk-root is set
+ explicitly.
+
+- Removed support for collecting coverage from old (<1.9.0) Dart SDKs.
+
+- Removed deprecated `Resolver.pkgRoot`.
+
+## 0.6.5
+
+- Fixed early collection bug when --wait-paused is set.
+
+## 0.6.4
+
+- Optimized formatters and fixed return value of `format` methods.
+
+- Added `Resolver.packageRoot` – deprecated `Resolver.pkgRoot`.
+
+## 0.6.3
+
+- Support the latest release of `args` package.
+
+- Support the latest release of `logging` package.
+
+- Fixed error when trying to access invalid paths.
+
+- Require at least Dart SDK v1.9.0.
+
+## 0.6.2
+
+- Support observatory protocol changes for VM >= 1.11.0.
+
+## 0.6.1
+
+- Support observatory protocol changes for VM >= 1.10.0.
+
+## 0.6.0+1
+
+- Add support for `pub global run`.
+
+## 0.6.0
+
+- Add support for SDK versions >= 1.9.0. For Dartium/content-shell versions past
+ 1.9.0, coverage collection is no longer done over the remote debugging port,
+ but via the observatory port emitted on stdout. Backward compatibility with
+ SDKs back to 1.5.x is provided.
diff --git a/pkgs/coverage/LICENSE b/pkgs/coverage/LICENSE
new file mode 100644
index 0000000..000cd7b
--- /dev/null
+++ b/pkgs/coverage/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/coverage/PATENTS b/pkgs/coverage/PATENTS
new file mode 100644
index 0000000..6954196
--- /dev/null
+++ b/pkgs/coverage/PATENTS
@@ -0,0 +1,23 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Dart Project.
+
+Google hereby grants to you a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this
+section) patent license to make, have made, use, offer to sell, sell,
+import, transfer, and otherwise run, modify and propagate the contents
+of this implementation of Dart, where such license applies only to
+those patent claims, both currently owned by Google and acquired in
+the future, licensable by Google that are necessarily infringed by
+this implementation of Dart. This grant does not include claims that
+would be infringed only as a consequence of further modification of
+this implementation. If you or your agent or exclusive licensee
+institute or order or agree to the institution of patent litigation
+against any entity (including a cross-claim or counterclaim in a
+lawsuit) alleging that this implementation of Dart or any code
+incorporated within this implementation of Dart constitutes direct or
+contributory patent infringement, or inducement of patent
+infringement, then any patent rights granted to you under this License
+for this implementation of Dart shall terminate as of the date such
+litigation is filed.
diff --git a/pkgs/coverage/README.md b/pkgs/coverage/README.md
new file mode 100644
index 0000000..81736a4
--- /dev/null
+++ b/pkgs/coverage/README.md
@@ -0,0 +1,123 @@
+Coverage provides coverage data collection, manipulation, and formatting for
+Dart.
+
+[](https://github.com/dart-lang/tools/actions/workflows/coverage.yml)
+[](https://coveralls.io/github/dart-lang/tools?branch=main)
+[](https://pub.dev/packages/coverage)
+
+## Tools
+
+`collect_coverage` collects coverage JSON from the Dart VM Service.
+`format_coverage` formats JSON coverage data into either
+[LCOV](https://github.com/linux-test-project/lcov) or pretty-printed format.
+
+#### Install coverage
+
+ dart pub global activate coverage
+
+Consider adding the `dart pub global run` executables directory to your path.
+See
+[Running a script from your PATH](https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path)
+for more details.
+
+#### Running tests with coverage
+
+For the common use case where you just want to run all your tests, and generate
+an lcov.info file, you can use the test_with_coverage script:
+
+```
+dart pub global run coverage:test_with_coverage
+```
+
+By default, this script assumes it's being run from the root directory of a
+package, and outputs a coverage.json and lcov.info file to ./coverage/
+
+This script is essentially the same as running:
+
+```
+dart run --pause-isolates-on-exit --disable-service-auth-codes --enable-vm-service=8181 test &
+dart pub global run coverage:collect_coverage --wait-paused --uri=http://127.0.0.1:8181/ -o coverage/coverage.json --resume-isolates --scope-output=foo
+dart pub global run coverage:format_coverage --packages=.dart_tool/package_config.json --lcov -i coverage/coverage.json -o coverage/lcov.info
+```
+
+For more complicated use cases, where you want to control each of these stages,
+see the sections below.
+
+#### Collecting coverage from the VM
+
+```
+dart --pause-isolates-on-exit --disable-service-auth-codes --enable-vm-service=NNNN script.dart
+dart pub global run coverage:collect_coverage --uri=http://... -o coverage.json --resume-isolates
+```
+
+or if the `dart pub global run` executables are on your PATH,
+
+```
+collect_coverage --uri=http://... -o coverage.json --resume-isolates
+```
+
+where `--uri` specifies the Dart VM Service URI emitted by the VM.
+
+If `collect_coverage` is invoked before the script from which coverage is to be
+collected, it will wait until it detects a VM observatory to which it can
+connect. An optional `--connect-timeout` may be specified (in seconds). The
+`--wait-paused` flag may be enabled, causing `collect_coverage` to wait until
+all isolates are paused before collecting coverage.
+
+#### Formatting coverage data
+
+```
+dart pub global run coverage:format_coverage --package=app_package -i coverage.json
+```
+
+or if the `dart pub global run` exectuables are on your PATH,
+
+```
+format_coverage --package=app_package -i coverage.json
+```
+
+where `app_package` is the path to the package whose coverage is being collected
+(defaults to the current working directory). If `--sdk-root` is set, Dart SDK
+coverage will also be output.
+
+#### Ignore lines from coverage
+
+- `// coverage:ignore-line` to ignore one line.
+- `// coverage:ignore-start` and `// coverage:ignore-end` to ignore range of
+ lines inclusive.
+- `// coverage:ignore-file` to ignore the whole file.
+
+Then pass `--check-ignore` to `format_coverage`.
+
+#### Function and branch coverage
+
+To gather function level coverage information, pass `--function-coverage` to
+collect_coverage:
+
+```
+dart --pause-isolates-on-exit --disable-service-auth-codes --enable-vm-service=NNNN script.dart
+dart pub global run coverage:collect_coverage --uri=http://... -o coverage.json --resume-isolates --function-coverage
+```
+
+To gather branch level coverage information, pass `--branch-coverage` to _both_
+collect_coverage and the Dart command you're gathering coverage from:
+
+```
+dart --pause-isolates-on-exit --disable-service-auth-codes --enable-vm-service=NNNN --branch-coverage script.dart
+dart pub global run coverage:collect_coverage --uri=http://... -o coverage.json --resume-isolates --branch-coverage
+```
+
+Branch coverage requires Dart VM 2.17.0, with service API v3.56. Function,
+branch, and line coverage can all be gathered at the same time, by combining
+those flags:
+
+```
+dart --pause-isolates-on-exit --disable-service-auth-codes --enable-vm-service=NNNN --branch-coverage script.dart
+dart pub global run coverage:collect_coverage --uri=http://... -o coverage.json --resume-isolates --function-coverage --branch-coverage
+```
+
+These flags can also be passed to test_with_coverage:
+
+```
+pub global run coverage:test_with_coverage --branch-coverage --function-coverage
+```
diff --git a/pkgs/coverage/analysis_options.yaml b/pkgs/coverage/analysis_options.yaml
new file mode 100644
index 0000000..82ce5e0
--- /dev/null
+++ b/pkgs/coverage/analysis_options.yaml
@@ -0,0 +1,22 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+
+ exclude:
+ - var/**
+
+linter:
+ rules:
+ - always_declare_return_types
+ - avoid_slow_async_io
+ - cancel_subscriptions
+ - comment_references
+ - literal_only_boolean_expressions
+ - prefer_final_locals
+ - sort_constructors_first
+ - sort_unnamed_constructors_first
+ - test_types_in_equals
+ - throw_in_finally
+ - type_annotate_public_apis
diff --git a/pkgs/coverage/benchmark/.gitignore b/pkgs/coverage/benchmark/.gitignore
new file mode 100644
index 0000000..1269488
--- /dev/null
+++ b/pkgs/coverage/benchmark/.gitignore
@@ -0,0 +1 @@
+data
diff --git a/pkgs/coverage/benchmark/many_isolates.dart b/pkgs/coverage/benchmark/many_isolates.dart
new file mode 100644
index 0000000..185576a
--- /dev/null
+++ b/pkgs/coverage/benchmark/many_isolates.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:isolate';
+import 'dart:math';
+
+Future<void> main(List<String> args, dynamic message) async {
+ if (message == null) {
+ // If there is no message, it means this instance was created by
+ // run_benchmarks.dart. In that case, this is the parent instance that
+ // spawns all the others.
+ var sum = 0;
+ for (var i = 0; i < 10; ++i) {
+ final port = ReceivePort();
+ final isolate =
+ Isolate.spawnUri(Uri.file('many_isolates.dart'), [], port.sendPort);
+ sum += await port.first as int;
+ await isolate;
+ }
+ print('sum = $sum');
+ } else {
+ // If there is a message, it means this instance is one of the child
+ // instances. The message is the port that this instance replies on.
+ (message as SendPort).send(Random().nextInt(1000));
+ }
+}
diff --git a/pkgs/coverage/benchmark/run_benchmarks.dart b/pkgs/coverage/benchmark/run_benchmarks.dart
new file mode 100644
index 0000000..1bd2990
--- /dev/null
+++ b/pkgs/coverage/benchmark/run_benchmarks.dart
@@ -0,0 +1,143 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+
+import '../bin/collect_coverage.dart' as collect_coverage;
+import '../bin/format_coverage.dart' as format_coverage;
+
+// Runs a test script with various different coverage configurations.
+class CoverageBenchmark extends AsyncBenchmarkBase {
+ CoverageBenchmark(
+ ScoreEmitter emitter,
+ super.name,
+ this.script, {
+ this.gatherCoverage = false,
+ this.functionCoverage = false,
+ this.branchCoverage = false,
+ }) : super(emitter: emitter);
+
+ final String script;
+ final bool gatherCoverage;
+ final bool functionCoverage;
+ final bool branchCoverage;
+ int iteration = 0;
+
+ @override
+ Future<void> run() async {
+ print('Running $name...');
+ final covFile = 'data/$name $iteration coverage.json';
+ final lcovFile = 'data/$name $iteration lcov.info';
+ ++iteration;
+
+ await Process.start(
+ Platform.executable,
+ [
+ if (branchCoverage) '--branch-coverage',
+ 'run',
+ if (gatherCoverage) ...[
+ '--pause-isolates-on-exit',
+ '--disable-service-auth-codes',
+ '--enable-vm-service=1234',
+ ],
+ script,
+ ],
+ mode: ProcessStartMode.detached,
+ );
+ if (gatherCoverage) {
+ await collect_coverage.main([
+ '--wait-paused',
+ '--resume-isolates',
+ '--uri=http://127.0.0.1:1234/',
+ if (branchCoverage) '--branch-coverage',
+ if (functionCoverage) '--function-coverage',
+ '-o',
+ covFile,
+ ]);
+
+ await format_coverage.main([
+ '--lcov',
+ '--check-ignore',
+ '-i',
+ covFile,
+ '-o',
+ lcovFile,
+ ]);
+ }
+ }
+}
+
+// Emitter that just captures the value.
+class CaptureEmitter implements ScoreEmitter {
+ late double capturedValue;
+
+ @override
+ void emit(String testName, double value) {
+ capturedValue = value;
+ }
+}
+
+// Prints a JSON representation of the benchmark results, in a format compatible
+// with the github benchmark action.
+class JsonEmitter implements ScoreEmitter {
+ JsonEmitter(this._baseline);
+
+ final double _baseline;
+ final _results = <String, double>{};
+
+ @override
+ void emit(String testName, double value) {
+ _results[testName] = value;
+ }
+
+ String write() => '[${_results.entries.map((entry) => """{
+ "name": "${entry.key}",
+ "unit": "times slower",
+ "value": ${(entry.value / _baseline).toStringAsFixed(2)}
+}""").join(',\n')}]';
+}
+
+Future<void> runBenchmark(CoverageBenchmark benchmark) async {
+ for (var i = 0; i < 3; ++i) {
+ try {
+ await benchmark.report().timeout(const Duration(minutes: 2));
+ return;
+ } on TimeoutException {
+ print('Timed out');
+ }
+ }
+ print('Timed out too many times. Giving up.');
+ exit(127);
+}
+
+Future<String> runBenchmarkSet(String name, String script) async {
+ final captureEmitter = CaptureEmitter();
+ await runBenchmark(
+ CoverageBenchmark(captureEmitter, '$name - no coverage', script));
+ final benchmarkBaseline = captureEmitter.capturedValue;
+
+ final emitter = JsonEmitter(benchmarkBaseline);
+ await runBenchmark(CoverageBenchmark(
+ emitter, '$name - basic coverage', script,
+ gatherCoverage: true));
+ await runBenchmark(CoverageBenchmark(
+ emitter, '$name - function coverage', script,
+ gatherCoverage: true, functionCoverage: true));
+ await runBenchmark(CoverageBenchmark(
+ emitter, '$name - branch coverage', script,
+ gatherCoverage: true, branchCoverage: true));
+ return emitter.write();
+}
+
+Future<void> main() async {
+ // Assume this script was started from the root coverage directory. Change to
+ // the benchmark directory.
+ Directory.current = 'benchmark';
+ final result = await runBenchmarkSet('Many isolates', 'many_isolates.dart');
+ await File('data/benchmark_result.json').writeAsString(result);
+ exit(0);
+}
diff --git a/pkgs/coverage/bin/collect_coverage.dart b/pkgs/coverage/bin/collect_coverage.dart
new file mode 100644
index 0000000..b02ac21
--- /dev/null
+++ b/pkgs/coverage/bin/collect_coverage.dart
@@ -0,0 +1,149 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert' show json;
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:coverage/src/collect.dart';
+import 'package:logging/logging.dart';
+import 'package:stack_trace/stack_trace.dart';
+
+Future<void> main(List<String> arguments) async {
+ Logger.root.level = Level.WARNING;
+ Logger.root.onRecord.listen((LogRecord rec) {
+ print('${rec.level.name}: ${rec.time}: ${rec.message}');
+ });
+
+ final options = _parseArgs(arguments);
+ await Chain.capture(() async {
+ final coverage = await collect(options.serviceUri, options.resume,
+ options.waitPaused, options.includeDart, options.scopedOutput,
+ timeout: options.timeout,
+ functionCoverage: options.functionCoverage,
+ branchCoverage: options.branchCoverage);
+ options.out.write(json.encode(coverage));
+ await options.out.close();
+ }, onError: (dynamic error, Chain chain) {
+ stderr.writeln(error);
+ stderr.writeln(chain.terse);
+ // See http://www.retro11.de/ouxr/211bsd/usr/include/sysexits.h.html
+ // EX_SOFTWARE
+ exit(70);
+ });
+}
+
+class Options {
+ Options(
+ this.serviceUri,
+ this.out,
+ this.timeout,
+ this.waitPaused,
+ this.resume,
+ this.includeDart,
+ this.functionCoverage,
+ this.branchCoverage,
+ this.scopedOutput);
+
+ final Uri serviceUri;
+ final IOSink out;
+ final Duration? timeout;
+ final bool waitPaused;
+ final bool resume;
+ final bool includeDart;
+ final bool functionCoverage;
+ final bool branchCoverage;
+ final Set<String> scopedOutput;
+}
+
+Options _parseArgs(List<String> arguments) {
+ final parser = ArgParser()
+ ..addOption('host',
+ abbr: 'H',
+ help: 'remote VM host. DEPRECATED: use --uri',
+ defaultsTo: '127.0.0.1')
+ ..addOption('port',
+ abbr: 'p',
+ help: 'remote VM port. DEPRECATED: use --uri',
+ defaultsTo: '8181')
+ ..addOption('uri', abbr: 'u', help: 'VM observatory service URI')
+ ..addOption('out',
+ abbr: 'o', defaultsTo: 'stdout', help: 'output: may be file or stdout')
+ ..addOption('connect-timeout',
+ abbr: 't', help: 'connect timeout in seconds')
+ ..addMultiOption('scope-output',
+ help: 'restrict coverage results so that only scripts that start with '
+ 'the provided package path are considered')
+ ..addFlag('wait-paused',
+ abbr: 'w',
+ defaultsTo: false,
+ help: 'wait for all isolates to be paused before collecting coverage')
+ ..addFlag('resume-isolates',
+ abbr: 'r', defaultsTo: false, help: 'resume all isolates on exit')
+ ..addFlag('include-dart',
+ abbr: 'd', defaultsTo: false, help: 'include "dart:" libraries')
+ ..addFlag('function-coverage',
+ abbr: 'f', defaultsTo: false, help: 'Collect function coverage info')
+ ..addFlag('branch-coverage',
+ abbr: 'b',
+ defaultsTo: false,
+ help: 'Collect branch coverage info (Dart VM must also be run with '
+ '--branch-coverage for this to work)')
+ ..addFlag('help', abbr: 'h', negatable: false, help: 'show this help');
+
+ final args = parser.parse(arguments);
+
+ void printUsage() {
+ print('Usage: dart collect_coverage.dart --uri=http://... [OPTION...]\n');
+ print(parser.usage);
+ }
+
+ Never fail(String message) {
+ print('Error: $message\n');
+ printUsage();
+ exit(1);
+ }
+
+ if (args['help'] as bool) {
+ printUsage();
+ exit(0);
+ }
+
+ Uri serviceUri;
+ if (args['uri'] == null) {
+ // TODO(cbracken) eliminate --host and --port support when VM defaults to
+ // requiring an auth token. Estimated for Dart SDK 1.22.
+ serviceUri = Uri.parse('http://${args['host']}:${args['port']}/');
+ } else {
+ try {
+ serviceUri = Uri.parse(args['uri'] as String);
+ } on FormatException {
+ fail('Invalid service URI specified: ${args['uri']}');
+ }
+ }
+
+ final scopedOutput = args['scope-output'] as List<String>;
+ IOSink out;
+ if (args['out'] == 'stdout') {
+ out = stdout;
+ } else {
+ final outfile = File(args['out'] as String)..createSync(recursive: true);
+ out = outfile.openWrite();
+ }
+ final timeout = (args['connect-timeout'] == null)
+ ? null
+ : Duration(seconds: int.parse(args['connect-timeout'] as String));
+ return Options(
+ serviceUri,
+ out,
+ timeout,
+ args['wait-paused'] as bool,
+ args['resume-isolates'] as bool,
+ args['include-dart'] as bool,
+ args['function-coverage'] as bool,
+ args['branch-coverage'] as bool,
+ scopedOutput.toSet(),
+ );
+}
diff --git a/pkgs/coverage/bin/format_coverage.dart b/pkgs/coverage/bin/format_coverage.dart
new file mode 100644
index 0000000..d24f60d
--- /dev/null
+++ b/pkgs/coverage/bin/format_coverage.dart
@@ -0,0 +1,310 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:coverage/coverage.dart';
+import 'package:glob/glob.dart';
+import 'package:path/path.dart' as p;
+
+/// [Environment] stores gathered arguments information.
+class Environment {
+ Environment({
+ required this.baseDirectory,
+ required this.bazel,
+ required this.bazelWorkspace,
+ required this.checkIgnore,
+ required this.input,
+ required this.lcov,
+ required this.output,
+ required this.packagesPath,
+ required this.packagePath,
+ required this.prettyPrint,
+ required this.prettyPrintFunc,
+ required this.prettyPrintBranch,
+ required this.reportOn,
+ required this.ignoreFiles,
+ required this.sdkRoot,
+ required this.verbose,
+ required this.workers,
+ });
+
+ String? baseDirectory;
+ bool bazel;
+ String bazelWorkspace;
+ bool checkIgnore;
+ String input;
+ bool lcov;
+ IOSink output;
+ String? packagesPath;
+ String packagePath;
+ bool prettyPrint;
+ bool prettyPrintFunc;
+ bool prettyPrintBranch;
+ List<String>? reportOn;
+ List<String>? ignoreFiles;
+ String? sdkRoot;
+ bool verbose;
+ int workers;
+}
+
+Future<void> main(List<String> arguments) async {
+ final env = parseArgs(arguments);
+
+ final files = filesToProcess(env.input);
+ if (env.verbose) {
+ print('Environment:');
+ print(' # files: ${files.length}');
+ print(' # workers: ${env.workers}');
+ print(' sdk-root: ${env.sdkRoot}');
+ print(' package-path: ${env.packagePath}');
+ print(' packages-path: ${env.packagesPath}');
+ print(' report-on: ${env.reportOn}');
+ print(' check-ignore: ${env.checkIgnore}');
+ }
+
+ final clock = Stopwatch()..start();
+ final hitmap = await HitMap.parseFiles(
+ files,
+ checkIgnoredLines: env.checkIgnore,
+ // ignore: deprecated_member_use_from_same_package
+ packagesPath: env.packagesPath,
+ packagePath: env.packagePath,
+ );
+
+ // All workers are done. Process the data.
+ if (env.verbose) {
+ print('Done creating global hitmap. Took ${clock.elapsedMilliseconds} ms.');
+ }
+
+ final ignoreGlobs = env.ignoreFiles?.map(Glob.new).toSet();
+
+ String output;
+ final resolver = env.bazel
+ ? BazelResolver(workspacePath: env.bazelWorkspace)
+ : await Resolver.create(
+ packagesPath: env.packagesPath,
+ packagePath: env.packagePath,
+ sdkRoot: env.sdkRoot,
+ );
+ final loader = Loader();
+ if (env.prettyPrint) {
+ output = await hitmap.prettyPrint(resolver, loader,
+ reportOn: env.reportOn,
+ ignoreGlobs: ignoreGlobs,
+ reportFuncs: env.prettyPrintFunc,
+ reportBranches: env.prettyPrintBranch);
+ } else {
+ assert(env.lcov);
+ output = hitmap.formatLcov(resolver,
+ reportOn: env.reportOn,
+ ignoreGlobs: ignoreGlobs,
+ basePath: env.baseDirectory);
+ }
+
+ env.output.write(output);
+ await env.output.flush();
+ if (env.verbose) {
+ print('Done flushing output. Took ${clock.elapsedMilliseconds} ms.');
+ }
+
+ if (env.verbose) {
+ if (resolver.failed.isNotEmpty) {
+ print('Failed to resolve:');
+ for (var error in resolver.failed.toSet()) {
+ print(' $error');
+ }
+ }
+ if (loader.failed.isNotEmpty) {
+ print('Failed to load:');
+ for (var error in loader.failed.toSet()) {
+ print(' $error');
+ }
+ }
+ }
+ await env.output.close();
+}
+
+/// Checks the validity of the provided arguments. Does not initialize actual
+/// processing.
+Environment parseArgs(List<String> arguments) {
+ final parser = ArgParser();
+
+ parser
+ ..addOption('sdk-root', abbr: 's', help: 'path to the SDK root')
+ ..addOption('packages', help: '[DEPRECATED] path to the package spec file')
+ ..addOption('package',
+ help: 'root directory of the package', defaultsTo: '.')
+ ..addOption('in', abbr: 'i', help: 'input(s): may be file or directory')
+ ..addOption('out',
+ abbr: 'o', defaultsTo: 'stdout', help: 'output: may be file or stdout')
+ ..addMultiOption('report-on',
+ help: 'which directories or files to report coverage on')
+ ..addOption('workers',
+ abbr: 'j', defaultsTo: '1', help: 'number of workers')
+ ..addOption('bazel-workspace',
+ defaultsTo: '', help: 'Bazel workspace directory')
+ ..addOption('base-directory',
+ abbr: 'b',
+ help: 'the base directory relative to which source paths are output')
+ ..addFlag('bazel',
+ defaultsTo: false, help: 'use Bazel-style path resolution')
+ ..addFlag('pretty-print',
+ abbr: 'r',
+ negatable: false,
+ help: 'convert line coverage data to pretty print format')
+ ..addFlag('pretty-print-func',
+ abbr: 'f',
+ negatable: false,
+ help: 'convert function coverage data to pretty print format')
+ ..addFlag('pretty-print-branch',
+ negatable: false,
+ help: 'convert branch coverage data to pretty print format')
+ ..addFlag('lcov',
+ abbr: 'l',
+ negatable: false,
+ help: 'convert coverage data to lcov format')
+ ..addFlag('verbose', abbr: 'v', negatable: false, help: 'verbose output')
+ ..addFlag(
+ 'check-ignore',
+ abbr: 'c',
+ negatable: false,
+ help: 'check for coverage ignore comments.'
+ ' Not supported in web coverage.',
+ )
+ ..addMultiOption(
+ 'ignore-files',
+ defaultsTo: [],
+ help: 'Ignore files by glob patterns',
+ )
+ ..addFlag('help', abbr: 'h', negatable: false, help: 'show this help');
+
+ final args = parser.parse(arguments);
+
+ void printUsage() {
+ print('Usage: dart format_coverage.dart [OPTION...]\n');
+ print(parser.usage);
+ }
+
+ Never fail(String msg) {
+ print('\n$msg\n');
+ printUsage();
+ exit(1);
+ }
+
+ if (args['help'] as bool) {
+ printUsage();
+ exit(0);
+ }
+
+ var sdkRoot = args['sdk-root'] as String?;
+ if (sdkRoot != null) {
+ sdkRoot = p.normalize(p.join(p.absolute(sdkRoot), 'lib'));
+ if (!FileSystemEntity.isDirectorySync(sdkRoot)) {
+ fail('Provided SDK root "${args["sdk-root"]}" is not a valid SDK '
+ 'top-level directory');
+ }
+ }
+
+ final packagesPath = args['packages'] as String?;
+ if (packagesPath != null) {
+ if (!FileSystemEntity.isFileSync(packagesPath)) {
+ fail('Package spec "${args["packages"]}" not found, or not a file.');
+ }
+ }
+
+ final packagePath = args['package'] as String;
+ if (!FileSystemEntity.isDirectorySync(packagePath)) {
+ fail('Package spec "${args["package"]}" not found, or not a directory.');
+ }
+
+ if (args['in'] == null) fail('No input files given.');
+ final input = p.absolute(p.normalize(args['in'] as String));
+ if (!FileSystemEntity.isDirectorySync(input) &&
+ !FileSystemEntity.isFileSync(input)) {
+ fail('Provided input "${args["in"]}" is neither a directory nor a file.');
+ }
+
+ IOSink output;
+ if (args['out'] == 'stdout') {
+ output = stdout;
+ } else {
+ final outpath = p.absolute(p.normalize(args['out'] as String));
+ final outfile = File(outpath)..createSync(recursive: true);
+ output = outfile.openWrite();
+ }
+
+ final reportOnRaw = args['report-on'] as List<String>;
+ final reportOn = reportOnRaw.isNotEmpty ? reportOnRaw : null;
+
+ final bazel = args['bazel'] as bool;
+ final bazelWorkspace = args['bazel-workspace'] as String;
+ if (bazelWorkspace.isNotEmpty && !bazel) {
+ stderr.writeln('warning: ignoring --bazel-workspace: --bazel not set');
+ }
+
+ String? baseDirectory;
+ if (args['base-directory'] != null) {
+ baseDirectory = p.absolute(args['base-directory'] as String);
+ }
+
+ final lcov = args['lcov'] as bool;
+ var prettyPrint = args['pretty-print'] as bool;
+ final prettyPrintFunc = args['pretty-print-func'] as bool;
+ final prettyPrintBranch = args['pretty-print-branch'] as bool;
+ final numModesChosen = (prettyPrint ? 1 : 0) +
+ (prettyPrintFunc ? 1 : 0) +
+ (prettyPrintBranch ? 1 : 0) +
+ (lcov ? 1 : 0);
+ if (numModesChosen > 1) {
+ fail('Choose one of the pretty-print modes or lcov output');
+ }
+
+ // The pretty printer is used by all modes other than lcov.
+ if (!lcov) prettyPrint = true;
+
+ int workers;
+ try {
+ workers = int.parse('${args["workers"]}');
+ } catch (e) {
+ fail('Invalid worker count: $e');
+ }
+
+ final checkIgnore = args['check-ignore'] as bool;
+ final ignoredGlobs = args['ignore-files'] as List<String>;
+ final verbose = args['verbose'] as bool;
+ return Environment(
+ baseDirectory: baseDirectory,
+ bazel: bazel,
+ bazelWorkspace: bazelWorkspace,
+ checkIgnore: checkIgnore,
+ input: input,
+ lcov: lcov,
+ output: output,
+ packagesPath: packagesPath,
+ packagePath: packagePath,
+ prettyPrint: prettyPrint,
+ prettyPrintFunc: prettyPrintFunc,
+ prettyPrintBranch: prettyPrintBranch,
+ reportOn: reportOn,
+ ignoreFiles: ignoredGlobs,
+ sdkRoot: sdkRoot,
+ verbose: verbose,
+ workers: workers);
+}
+
+/// Given an absolute path absPath, this function returns a [List] of files
+/// are contained by it if it is a directory, or a [List] containing the file if
+/// it is a file.
+List<File> filesToProcess(String absPath) {
+ if (FileSystemEntity.isDirectorySync(absPath)) {
+ return Directory(absPath)
+ .listSync(recursive: true)
+ .whereType<File>()
+ .where((e) => e.path.endsWith('.json'))
+ .toList();
+ }
+ return <File>[File(absPath)];
+}
diff --git a/pkgs/coverage/bin/run_and_collect.dart b/pkgs/coverage/bin/run_and_collect.dart
new file mode 100644
index 0000000..c255d01
--- /dev/null
+++ b/pkgs/coverage/bin/run_and_collect.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:coverage/src/run_and_collect.dart';
+
+Future<void> main(List<String> args) async {
+ final Map results = await runAndCollect(args[0]);
+ print(results);
+}
diff --git a/pkgs/coverage/bin/test_with_coverage.dart b/pkgs/coverage/bin/test_with_coverage.dart
new file mode 100644
index 0000000..010e608
--- /dev/null
+++ b/pkgs/coverage/bin/test_with_coverage.dart
@@ -0,0 +1,229 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:coverage/src/util.dart'
+ show StandardOutExtension, extractVMServiceUri;
+import 'package:package_config/package_config.dart';
+import 'package:path/path.dart' as path;
+
+import 'collect_coverage.dart' as collect_coverage;
+import 'format_coverage.dart' as format_coverage;
+
+final _allProcesses = <Process>[];
+
+Future<void> _dartRun(List<String> args,
+ {void Function(String)? onStdout, String? workingDir}) async {
+ final process = await Process.start(
+ Platform.executable,
+ args,
+ workingDirectory: workingDir,
+ );
+ _allProcesses.add(process);
+ final broadStdout = process.stdout.asBroadcastStream();
+ broadStdout.listen(stdout.add);
+ if (onStdout != null) {
+ broadStdout.lines().listen(onStdout);
+ }
+ process.stderr.listen(stderr.add);
+ final result = await process.exitCode;
+ if (result != 0) {
+ throw ProcessException(Platform.executable, args, '', result);
+ }
+}
+
+Future<String?> _packageNameFromConfig(String packageDir) async {
+ final config = await findPackageConfig(Directory(packageDir));
+ return config?.packageOf(Uri.directory(packageDir))?.name;
+}
+
+void _watchExitSignal(ProcessSignal signal) {
+ signal.watch().listen((sig) {
+ for (final process in _allProcesses) {
+ process.kill(sig);
+ }
+ exit(1);
+ });
+}
+
+ArgParser _createArgParser() => ArgParser()
+ ..addOption(
+ 'package',
+ help: 'Root directory of the package to test.',
+ defaultsTo: '.',
+ )
+ ..addOption(
+ 'package-name',
+ help: 'Name of the package to test. '
+ 'Deduced from --package if not provided.',
+ )
+ ..addOption('port', help: 'VM service port.', defaultsTo: '8181')
+ ..addOption(
+ 'out',
+ abbr: 'o',
+ help: 'Output directory. Defaults to <package-dir>/coverage.',
+ )
+ ..addOption('test', help: 'Test script to run.', defaultsTo: 'test')
+ ..addFlag(
+ 'function-coverage',
+ abbr: 'f',
+ defaultsTo: false,
+ help: 'Collect function coverage info.',
+ )
+ ..addFlag(
+ 'branch-coverage',
+ abbr: 'b',
+ defaultsTo: false,
+ help: 'Collect branch coverage info.',
+ )
+ ..addMultiOption('scope-output',
+ help: 'restrict coverage results so that only scripts that start with '
+ 'the provided package path are considered. Defaults to the name of '
+ 'the package under test.')
+ ..addFlag('help', abbr: 'h', negatable: false, help: 'Show this help.');
+
+class Flags {
+ Flags(
+ this.packageDir,
+ this.packageName,
+ this.outDir,
+ this.port,
+ this.testScript,
+ this.functionCoverage,
+ this.branchCoverage,
+ this.scopeOutput, {
+ required this.rest,
+ });
+
+ final String packageDir;
+ final String packageName;
+ final String outDir;
+ final String port;
+ final String testScript;
+ final bool functionCoverage;
+ final bool branchCoverage;
+ final List<String> scopeOutput;
+ final List<String> rest;
+}
+
+Future<Flags> _parseArgs(List<String> arguments) async {
+ final parser = _createArgParser();
+ final args = parser.parse(arguments);
+
+ void printUsage() {
+ print('''
+Runs tests and collects coverage for a package.
+
+By default this script assumes it's being run from the root directory of a
+package, and outputs a coverage.json and lcov.info to ./coverage/
+
+Usage: test_with_coverage [OPTIONS...] [-- <test script OPTIONS>]
+
+${parser.usage}
+''');
+ }
+
+ Never fail(String msg) {
+ print('\n$msg\n');
+ printUsage();
+ exit(1);
+ }
+
+ if (args['help'] as bool) {
+ printUsage();
+ exit(0);
+ }
+
+ final packageDir = path.canonicalize(args['package'] as String);
+ if (!FileSystemEntity.isDirectorySync(packageDir)) {
+ fail('--package is not a valid directory.');
+ }
+
+ final packageName = (args['package-name'] as String?) ??
+ await _packageNameFromConfig(packageDir);
+ if (packageName == null) {
+ fail(
+ "Couldn't figure out package name from --package. Make sure this is a "
+ 'package directory, or try passing --package-name explicitly.',
+ );
+ }
+
+ return Flags(
+ packageDir,
+ packageName,
+ (args['out'] as String?) ?? path.join(packageDir, 'coverage'),
+ args['port'] as String,
+ args['test'] as String,
+ args['function-coverage'] as bool,
+ args['branch-coverage'] as bool,
+ args['scope-output'] as List<String>,
+ rest: args.rest,
+ );
+}
+
+Future<void> main(List<String> arguments) async {
+ final flags = await _parseArgs(arguments);
+ final outJson = path.join(flags.outDir, 'coverage.json');
+ final outLcov = path.join(flags.outDir, 'lcov.info');
+
+ if (!FileSystemEntity.isDirectorySync(flags.outDir)) {
+ await Directory(flags.outDir).create(recursive: true);
+ }
+
+ _watchExitSignal(ProcessSignal.sighup);
+ _watchExitSignal(ProcessSignal.sigint);
+ if (!Platform.isWindows) {
+ _watchExitSignal(ProcessSignal.sigterm);
+ }
+
+ final serviceUriCompleter = Completer<Uri>();
+ final testProcess = _dartRun(
+ [
+ if (flags.branchCoverage) '--branch-coverage',
+ 'run',
+ '--pause-isolates-on-exit',
+ '--disable-service-auth-codes',
+ '--enable-vm-service=${flags.port}',
+ flags.testScript,
+ ...flags.rest,
+ ],
+ onStdout: (line) {
+ if (!serviceUriCompleter.isCompleted) {
+ final uri = extractVMServiceUri(line);
+ if (uri != null) {
+ serviceUriCompleter.complete(uri);
+ }
+ }
+ },
+ );
+ final serviceUri = await serviceUriCompleter.future;
+
+ final scopes =
+ flags.scopeOutput.isEmpty ? [flags.packageName] : flags.scopeOutput;
+ await collect_coverage.main([
+ '--wait-paused',
+ '--resume-isolates',
+ '--uri=$serviceUri',
+ for (final scope in scopes) '--scope-output=$scope',
+ if (flags.branchCoverage) '--branch-coverage',
+ if (flags.functionCoverage) '--function-coverage',
+ '-o',
+ outJson,
+ ]);
+ await testProcess;
+
+ await format_coverage.main([
+ '--lcov',
+ '--check-ignore',
+ '--package=${flags.packageDir}',
+ '-i',
+ outJson,
+ '-o',
+ outLcov,
+ ]);
+ exit(0);
+}
diff --git a/pkgs/coverage/lib/coverage.dart b/pkgs/coverage/lib/coverage.dart
new file mode 100644
index 0000000..9cc81ab
--- /dev/null
+++ b/pkgs/coverage/lib/coverage.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/chrome.dart';
+export 'src/collect.dart';
+export 'src/formatter.dart';
+export 'src/hitmap.dart' hide hitmapToJson;
+export 'src/resolver.dart';
+export 'src/run_and_collect.dart';
diff --git a/pkgs/coverage/lib/src/chrome.dart b/pkgs/coverage/lib/src/chrome.dart
new file mode 100644
index 0000000..2a97696
--- /dev/null
+++ b/pkgs/coverage/lib/src/chrome.dart
@@ -0,0 +1,171 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_maps/parser.dart';
+
+import 'hitmap.dart';
+
+/// Returns a Dart based hit-map containing coverage report for the provided
+/// Chrome [preciseCoverage].
+///
+/// [sourceProvider] returns the source content for the Chrome scriptId, or null
+/// if not available.
+///
+/// [sourceMapProvider] returns the associated source map content for the Chrome
+/// scriptId, or null if not available.
+///
+/// [sourceUriProvider] returns the uri for the provided sourceUrl and
+/// associated scriptId, or null if not available.
+///
+/// Chrome coverage information for which the corresponding source map or source
+/// content is null will be ignored.
+Future<Map<String, dynamic>> parseChromeCoverage(
+ List<Map<String, dynamic>> preciseCoverage,
+ Future<String?> Function(String scriptId) sourceProvider,
+ Future<String?> Function(String scriptId) sourceMapProvider,
+ Future<Uri?> Function(String sourceUrl, String scriptId) sourceUriProvider,
+) async {
+ final coverageReport = <Uri, Map<int, bool>>{};
+ for (var entry in preciseCoverage) {
+ final scriptId = entry['scriptId'] as String;
+
+ final mapResponse = await sourceMapProvider(scriptId);
+ if (mapResponse == null) continue;
+
+ SingleMapping mapping;
+ try {
+ mapping = parse(mapResponse) as SingleMapping;
+ } on FormatException {
+ continue;
+ // ignore: avoid_catching_errors
+ } on ArgumentError {
+ continue;
+ }
+
+ final compiledSource = await sourceProvider(scriptId);
+ if (compiledSource == null) continue;
+
+ final coverageInfo = _coverageInfoFor(entry);
+ final offsetCoverage = _offsetCoverage(coverageInfo, compiledSource.length);
+ final coveredPositions = _coveredPositions(compiledSource, offsetCoverage);
+
+ for (var lineEntry in mapping.lines) {
+ for (var columnEntry in lineEntry.entries) {
+ final sourceUrlId = columnEntry.sourceUrlId;
+ if (sourceUrlId == null) continue;
+ final sourceUrl = mapping.urls[sourceUrlId];
+
+ // Ignore coverage information for the SDK.
+ if (sourceUrl.startsWith('org-dartlang-sdk:')) continue;
+
+ final uri = await sourceUriProvider(sourceUrl, scriptId);
+ if (uri == null) continue;
+ final coverage = coverageReport.putIfAbsent(uri, () => <int, bool>{});
+
+ final sourceLine = columnEntry.sourceLine!;
+ final current = coverage[sourceLine + 1] ?? false;
+ coverage[sourceLine + 1] = current ||
+ coveredPositions.contains(
+ _Position(lineEntry.line + 1, columnEntry.column + 1));
+ }
+ }
+ }
+
+ final coverageHitMaps = <Uri, HitMap>{};
+ coverageReport.forEach((uri, coverage) {
+ final hitMap = HitMap();
+ for (var line in coverage.keys.toList()..sort()) {
+ hitMap.lineHits[line] = coverage[line]! ? 1 : 0;
+ }
+ coverageHitMaps[uri] = hitMap;
+ });
+
+ final allCoverage = <Map<String, dynamic>>[];
+ coverageHitMaps.forEach((uri, hitMap) {
+ allCoverage.add(hitmapToJson(hitMap, uri));
+ });
+ return <String, dynamic>{'type': 'CodeCoverage', 'coverage': allCoverage};
+}
+
+/// Returns all covered positions in a provided source.
+Set<_Position> _coveredPositions(
+ String compiledSource, List<bool> offsetCoverage) {
+ final positions = <_Position>{};
+ // Line is 1 based.
+ var line = 1;
+ // Column is 1 based.
+ var column = 0;
+ for (var offset = 0; offset < compiledSource.length; offset++) {
+ if (compiledSource[offset] == '\n') {
+ line++;
+ column = 0;
+ } else {
+ column++;
+ }
+ if (offsetCoverage[offset]) positions.add(_Position(line, column));
+ }
+ return positions;
+}
+
+/// Returns coverage information for a Chrome entry.
+List<_CoverageInfo> _coverageInfoFor(Map<String, dynamic> entry) {
+ final result = <_CoverageInfo>[];
+ for (var functions
+ in (entry['functions'] as List).cast<Map<String, dynamic>>()) {
+ for (var range
+ in (functions['ranges'] as List).cast<Map<String, dynamic>>()) {
+ result.add(_CoverageInfo(
+ range['startOffset'] as int,
+ range['endOffset'] as int,
+ (range['count'] as int) > 0,
+ ));
+ }
+ }
+ return result;
+}
+
+/// Returns the coverage information for each offset.
+List<bool> _offsetCoverage(List<_CoverageInfo> coverageInfo, int sourceLength) {
+ final offsetCoverage = List.filled(sourceLength, false);
+
+ // Sort coverage information by their size.
+ // Coverage information takes granularity as precedence.
+ coverageInfo.sort((a, b) =>
+ (b.endOffset - b.startOffset).compareTo(a.endOffset - a.startOffset));
+
+ for (var range in coverageInfo) {
+ for (var i = range.startOffset; i < range.endOffset; i++) {
+ offsetCoverage[i] = range.isCovered;
+ }
+ }
+
+ return offsetCoverage;
+}
+
+class _CoverageInfo {
+ _CoverageInfo(this.startOffset, this.endOffset, this.isCovered);
+
+ /// 0 based byte offset.
+ final int startOffset;
+
+ /// 0 based byte offset.
+ final int endOffset;
+
+ final bool isCovered;
+}
+
+/// A covered position in a source file where [line] and [column] are 1 based.
+class _Position {
+ _Position(this.line, this.column);
+
+ final int line;
+ final int column;
+
+ @override
+ int get hashCode => Object.hash(line, column);
+
+ @override
+ bool operator ==(Object o) =>
+ o is _Position && o.line == line && o.column == column;
+}
diff --git a/pkgs/coverage/lib/src/collect.dart b/pkgs/coverage/lib/src/collect.dart
new file mode 100644
index 0000000..76227ba
--- /dev/null
+++ b/pkgs/coverage/lib/src/collect.dart
@@ -0,0 +1,447 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:vm_service/vm_service.dart';
+
+import 'hitmap.dart';
+import 'isolate_paused_listener.dart';
+import 'util.dart';
+
+const _retryInterval = Duration(milliseconds: 200);
+const _debugTokenPositions = bool.fromEnvironment('DEBUG_COVERAGE');
+
+/// Collects coverage for all isolates in the running VM.
+///
+/// Collects a hit-map containing merged coverage for all isolates in the Dart
+/// VM associated with the specified [serviceUri]. Returns a map suitable for
+/// input to the coverage formatters that ship with this package.
+///
+/// [serviceUri] must specify the http/https URI of the service port of a
+/// running Dart VM and must not be null.
+///
+/// If [resume] is true, all isolates will be resumed once coverage collection
+/// is complete.
+///
+/// If [waitPaused] is true, collection will not begin for an isolate until it
+/// is in the paused state.
+///
+/// If [includeDart] is true, code coverage for core `dart:*` libraries will be
+/// collected.
+///
+/// If [functionCoverage] is true, function coverage information will be
+/// collected.
+///
+/// If [branchCoverage] is true, branch coverage information will be collected.
+/// This will only work correctly if the target VM was run with the
+/// --branch-coverage flag.
+///
+/// If [scopedOutput] is non-empty, coverage will be restricted so that only
+/// scripts that start with any of the provided paths are considered.
+///
+/// If [isolateIds] is set, the coverage gathering will be restricted to only
+/// those VM isolates.
+///
+/// If [coverableLineCache] is set, the collector will avoid recompiling
+/// libraries it has already seen (see VmService.getSourceReport's
+/// librariesAlreadyCompiled parameter). This is only useful when doing more
+/// than one [collect] call over the same libraries. Pass an empty map to the
+/// first call, and then pass the same map to all subsequent calls.
+///
+/// [serviceOverrideForTesting] is for internal testing only, and should not be
+/// set by users.
+Future<Map<String, dynamic>> collect(Uri serviceUri, bool resume,
+ bool waitPaused, bool includeDart, Set<String>? scopedOutput,
+ {Set<String>? isolateIds,
+ Duration? timeout,
+ bool functionCoverage = false,
+ bool branchCoverage = false,
+ Map<String, Set<int>>? coverableLineCache,
+ VmService? serviceOverrideForTesting}) async {
+ scopedOutput ??= <String>{};
+
+ late VmService service;
+ if (serviceOverrideForTesting != null) {
+ service = serviceOverrideForTesting;
+ } else {
+ // Create websocket URI. Handle any trailing slashes.
+ final pathSegments =
+ serviceUri.pathSegments.where((c) => c.isNotEmpty).toList()..add('ws');
+ final uri = serviceUri.replace(scheme: 'ws', pathSegments: pathSegments);
+
+ await retry(() async {
+ try {
+ final options = const CompressionOptions(enabled: false);
+ final socket = await WebSocket.connect('$uri', compression: options);
+ final controller = StreamController<String>();
+ socket.listen((data) => controller.add(data as String), onDone: () {
+ controller.close();
+ service.dispose();
+ });
+ service = VmService(controller.stream, socket.add,
+ log: StdoutLog(), disposeHandler: socket.close);
+ await service.getVM().timeout(_retryInterval);
+ } on TimeoutException {
+ // The signature changed in vm_service version 6.0.0.
+ // ignore: await_only_futures
+ await service.dispose();
+ rethrow;
+ }
+ }, _retryInterval, timeout: timeout);
+ }
+
+ try {
+ return await _getAllCoverage(
+ service,
+ includeDart,
+ functionCoverage,
+ branchCoverage,
+ scopedOutput,
+ isolateIds,
+ coverableLineCache,
+ waitPaused);
+ } finally {
+ if (resume && !waitPaused) {
+ await _resumeIsolates(service);
+ }
+ // The signature changed in vm_service version 6.0.0.
+ // ignore: await_only_futures
+ await service.dispose();
+ }
+}
+
+Future<Map<String, dynamic>> _getAllCoverage(
+ VmService service,
+ bool includeDart,
+ bool functionCoverage,
+ bool branchCoverage,
+ Set<String> scopedOutput,
+ Set<String>? isolateIds,
+ Map<String, Set<int>>? coverableLineCache,
+ bool waitPaused) async {
+ final allCoverage = <Map<String, dynamic>>[];
+
+ final sourceReportKinds = [
+ SourceReportKind.kCoverage,
+ if (branchCoverage) SourceReportKind.kBranchCoverage,
+ ];
+
+ final librariesAlreadyCompiled = coverableLineCache?.keys.toList();
+
+ // Program counters are shared between isolates in the same group. So we need
+ // to make sure we're only gathering coverage data for one isolate in each
+ // group, otherwise we'll double count the hits.
+ final coveredIsolateGroups = <String>{};
+
+ Future<void> collectIsolate(IsolateRef isolateRef) async {
+ if (!(isolateIds?.contains(isolateRef.id) ?? true)) return;
+
+ // coveredIsolateGroups is only relevant for the !waitPaused flow. The
+ // waitPaused flow achieves the same once-per-group behavior using the
+ // isLastIsolateInGroup flag.
+ final isolateGroupId = isolateRef.isolateGroupId;
+ if (isolateGroupId != null) {
+ if (coveredIsolateGroups.contains(isolateGroupId)) return;
+ coveredIsolateGroups.add(isolateGroupId);
+ }
+
+ late final SourceReport isolateReport;
+ try {
+ isolateReport = await service.getSourceReport(
+ isolateRef.id!,
+ sourceReportKinds,
+ forceCompile: true,
+ reportLines: true,
+ libraryFilters: scopedOutput.isNotEmpty
+ ? List.from(scopedOutput.map((filter) => 'package:$filter/'))
+ : null,
+ librariesAlreadyCompiled: librariesAlreadyCompiled,
+ );
+ } on SentinelException {
+ return;
+ }
+
+ final coverage = await _processSourceReport(
+ service,
+ isolateRef,
+ isolateReport,
+ includeDart,
+ functionCoverage,
+ coverableLineCache,
+ scopedOutput);
+ allCoverage.addAll(coverage);
+ }
+
+ if (waitPaused) {
+ await IsolatePausedListener(service,
+ (IsolateRef isolateRef, bool isLastIsolateInGroup) async {
+ if (isLastIsolateInGroup) {
+ await collectIsolate(isolateRef);
+ }
+ }, stderr.writeln)
+ .waitUntilAllExited();
+ } else {
+ for (final isolateRef in await getAllIsolates(service)) {
+ await collectIsolate(isolateRef);
+ }
+ }
+
+ return <String, dynamic>{'type': 'CodeCoverage', 'coverage': allCoverage};
+}
+
+Future _resumeIsolates(VmService service) async {
+ final vm = await service.getVM();
+ final futures = <Future>[];
+ for (var isolateRef in vm.isolates!) {
+ // Guard against sync as well as async errors: sync - when we are writing
+ // message to the socket, the socket might be closed; async - when we are
+ // waiting for the response, the socket again closes.
+ futures.add(Future.sync(() async {
+ final isolate = await service.getIsolate(isolateRef.id!);
+ if (isolate.pauseEvent!.kind != EventKind.kResume) {
+ await service.resume(isolateRef.id!);
+ }
+ }));
+ }
+ try {
+ await Future.wait(futures);
+ } catch (_) {
+ // Ignore resume isolate failures
+ }
+}
+
+/// Returns the line number to which the specified token position maps.
+///
+/// Performs a binary search within the script's token position table to locate
+/// the line in question.
+int? _getLineFromTokenPos(Script script, int tokenPos) {
+ // TODO(cbracken): investigate whether caching this lookup results in
+ // significant performance gains.
+ var min = 0;
+ var max = script.tokenPosTable!.length;
+ while (min < max) {
+ final mid = min + ((max - min) >> 1);
+ final row = script.tokenPosTable![mid];
+ if (row[1] > tokenPos) {
+ max = mid;
+ } else {
+ for (var i = 1; i < row.length; i += 2) {
+ if (row[i] == tokenPos) return row.first;
+ }
+ min = mid + 1;
+ }
+ }
+ return null;
+}
+
+/// Returns a JSON coverage list backward-compatible with pre-1.16.0 SDKs.
+Future<List<Map<String, dynamic>>> _processSourceReport(
+ VmService service,
+ IsolateRef isolateRef,
+ SourceReport report,
+ bool includeDart,
+ bool functionCoverage,
+ Map<String, Set<int>>? coverableLineCache,
+ Set<String> scopedOutput) async {
+ final hitMaps = <Uri, HitMap>{};
+ final scripts = <ScriptRef, Script>{};
+ final libraries = <LibraryRef>{};
+ final needScripts = functionCoverage;
+
+ Future<Script?> getScript(ScriptRef? scriptRef) async {
+ if (scriptRef == null) {
+ return null;
+ }
+ if (!scripts.containsKey(scriptRef)) {
+ scripts[scriptRef] =
+ await service.getObject(isolateRef.id!, scriptRef.id!) as Script;
+ }
+ return scripts[scriptRef];
+ }
+
+ HitMap getHitMap(Uri scriptUri) => hitMaps.putIfAbsent(scriptUri, HitMap.new);
+
+ Future<void> processFunction(FuncRef funcRef) async {
+ final func = await service.getObject(isolateRef.id!, funcRef.id!) as Func;
+ if ((func.implicit ?? false) || (func.isAbstract ?? false)) {
+ return;
+ }
+ final location = func.location;
+ if (location == null) {
+ return;
+ }
+ final script = await getScript(location.script);
+ if (script == null) {
+ return;
+ }
+ final funcName = await _getFuncName(service, isolateRef, func);
+ // TODO(liama): Is this still necessary, or is location.line valid?
+ final tokenPos = location.tokenPos!;
+ final line = _getLineFromTokenPos(script, tokenPos);
+ if (line == null) {
+ if (_debugTokenPositions) {
+ stderr.writeln(
+ 'tokenPos $tokenPos in function ${funcRef.name} has no line '
+ 'mapping for script ${script.uri!}');
+ }
+ return;
+ }
+ final hits = getHitMap(Uri.parse(script.uri!));
+ hits.funcHits ??= <int, int>{};
+ (hits.funcNames ??= <int, String>{})[line] = funcName;
+ }
+
+ for (var range in report.ranges!) {
+ final scriptRef = report.scripts![range.scriptIndex!];
+ final scriptUriString = scriptRef.uri;
+ if (!scopedOutput.includesScript(scriptUriString)) {
+ // Sometimes a range's script can be different to the function's script
+ // (eg mixins), so we have to re-check the scope filter.
+ // See https://github.com/dart-lang/tools/issues/530
+ continue;
+ }
+ final scriptUri = Uri.parse(scriptUriString!);
+
+ // If we have a coverableLineCache, use it in the same way we use
+ // SourceReportCoverage.misses: to add zeros to the coverage result for all
+ // the lines that don't have a hit. Afterwards, add all the lines that were
+ // hit or missed to the cache, so that the next coverage collection won't
+ // need to compile this library.
+ final coverableLines =
+ coverableLineCache?.putIfAbsent(scriptUriString, () => <int>{});
+
+ // Not returned in scripts section of source report.
+ if (scriptUri.scheme == 'evaluate') continue;
+
+ // Skip scripts from dart:.
+ if (!includeDart && scriptUri.scheme == 'dart') continue;
+
+ // Look up the hit maps for this script (shared across isolates).
+ final hits = getHitMap(scriptUri);
+
+ Script? script;
+ if (needScripts) {
+ script = await getScript(scriptRef);
+ if (script == null) continue;
+ }
+
+ // If the script's library isn't loaded, load it then look up all its funcs.
+ final libRef = script?.library;
+ if (functionCoverage && libRef != null && !libraries.contains(libRef)) {
+ libraries.add(libRef);
+ final library =
+ await service.getObject(isolateRef.id!, libRef.id!) as Library;
+ if (library.functions != null) {
+ for (var funcRef in library.functions!) {
+ await processFunction(funcRef);
+ }
+ }
+ if (library.classes != null) {
+ for (var classRef in library.classes!) {
+ final clazz =
+ await service.getObject(isolateRef.id!, classRef.id!) as Class;
+ if (clazz.functions != null) {
+ for (var funcRef in clazz.functions!) {
+ await processFunction(funcRef);
+ }
+ }
+ }
+ }
+ }
+
+ // Collect hits and misses.
+ final coverage = range.coverage;
+
+ if (coverage == null) continue;
+
+ void forEachLine(List<int>? tokenPositions, void Function(int line) body) {
+ if (tokenPositions == null) return;
+ for (final line in tokenPositions) {
+ body(line);
+ }
+ }
+
+ if (coverableLines != null) {
+ for (final line in coverableLines) {
+ hits.lineHits.putIfAbsent(line, () => 0);
+ }
+ }
+
+ forEachLine(coverage.hits, (line) {
+ hits.lineHits.increment(line);
+ coverableLines?.add(line);
+ if (hits.funcNames != null && hits.funcNames!.containsKey(line)) {
+ hits.funcHits!.increment(line);
+ }
+ });
+ forEachLine(coverage.misses, (line) {
+ hits.lineHits.putIfAbsent(line, () => 0);
+ coverableLines?.add(line);
+ });
+ hits.funcNames?.forEach((line, funcName) {
+ hits.funcHits?.putIfAbsent(line, () => 0);
+ });
+
+ final branchCoverage = range.branchCoverage;
+ if (branchCoverage != null) {
+ hits.branchHits ??= <int, int>{};
+ forEachLine(branchCoverage.hits, (line) {
+ hits.branchHits!.increment(line);
+ });
+ forEachLine(branchCoverage.misses, (line) {
+ hits.branchHits!.putIfAbsent(line, () => 0);
+ });
+ }
+ }
+
+ // Output JSON
+ final coverage = <Map<String, dynamic>>[];
+ hitMaps.forEach((uri, hits) {
+ coverage.add(hitmapToJson(hits, uri));
+ });
+ return coverage;
+}
+
+extension _MapExtension<T> on Map<T, int> {
+ void increment(T key) => this[key] = (this[key] ?? 0) + 1;
+}
+
+Future<String> _getFuncName(
+ VmService service, IsolateRef isolateRef, Func func) async {
+ if (func.name == null) {
+ return '${func.type}:${func.location!.tokenPos}';
+ }
+ final owner = func.owner;
+ if (owner is ClassRef) {
+ final cls = await service.getObject(isolateRef.id!, owner.id!) as Class;
+ if (cls.name != null) return '${cls.name}.${func.name}';
+ }
+ return func.name!;
+}
+
+class StdoutLog extends Log {
+ @override
+ void warning(String message) => print(message);
+
+ @override
+ void severe(String message) => print(message);
+}
+
+extension _ScopedOutput on Set<String> {
+ bool includesScript(String? scriptUriString) {
+ if (scriptUriString == null) return false;
+
+ // If the set is empty, it means the user didn't specify a --scope-output
+ // flag, so allow everything.
+ if (isEmpty) return true;
+
+ final scriptUri = Uri.parse(scriptUriString);
+ if (scriptUri.scheme != 'package') return false;
+
+ final scope = scriptUri.pathSegments.first;
+ return contains(scope);
+ }
+}
diff --git a/pkgs/coverage/lib/src/formatter.dart b/pkgs/coverage/lib/src/formatter.dart
new file mode 100644
index 0000000..a37df73
--- /dev/null
+++ b/pkgs/coverage/lib/src/formatter.dart
@@ -0,0 +1,223 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:glob/glob.dart';
+import 'package:path/path.dart' as p;
+
+import 'hitmap.dart';
+import 'resolver.dart';
+
+@Deprecated('Migrate to FileHitMapsFormatter')
+abstract class Formatter {
+ /// Returns the formatted coverage data.
+ Future<String> format(Map<String, Map<int, int>> hitmap);
+}
+
+/// Converts the given hitmap to lcov format and appends the result to
+/// env.output.
+///
+/// Returns a [Future] that completes as soon as all map entries have been
+/// emitted.
+@Deprecated('Migrate to FileHitMapsFormatter.formatLcov')
+class LcovFormatter implements Formatter {
+ /// Creates a LCOV formatter.
+ ///
+ /// If [reportOn] is provided, coverage report output is limited to files
+ /// prefixed with one of the paths included. If [basePath] is provided, paths
+ /// are reported relative to that path.
+ LcovFormatter(this.resolver, {this.reportOn, this.basePath});
+
+ final Resolver resolver;
+ final String? basePath;
+ final List<String>? reportOn;
+
+ @override
+ Future<String> format(Map<String, Map<int, int>> hitmap) {
+ return Future.value(hitmap
+ .map((key, value) => MapEntry(key, HitMap(value)))
+ .formatLcov(resolver, basePath: basePath, reportOn: reportOn));
+ }
+}
+
+/// Converts the given hitmap to a pretty-print format and appends the result
+/// to env.output.
+///
+/// Returns a [Future] that completes as soon as all map entries have been
+/// emitted.
+@Deprecated('Migrate to FileHitMapsFormatter.prettyPrint')
+class PrettyPrintFormatter implements Formatter {
+ /// Creates a pretty-print formatter.
+ ///
+ /// If [reportOn] is provided, coverage report output is limited to files
+ /// prefixed with one of the paths included.
+ PrettyPrintFormatter(this.resolver, this.loader,
+ {this.reportOn, this.reportFuncs = false});
+
+ final Resolver resolver;
+ final Loader loader;
+ final List<String>? reportOn;
+ final bool reportFuncs;
+
+ @override
+ Future<String> format(Map<String, Map<int, int>> hitmap) {
+ return hitmap.map((key, value) => MapEntry(key, HitMap(value))).prettyPrint(
+ resolver, loader,
+ reportOn: reportOn, reportFuncs: reportFuncs);
+ }
+}
+
+extension FileHitMapsFormatter on Map<String, HitMap> {
+ /// Converts the given hitmap to lcov format.
+ ///
+ /// If [reportOn] is provided, coverage report output is limited to files
+ /// prefixed with one of the paths included. If [basePath] is provided, paths
+ /// are reported relative to that path.
+ String formatLcov(
+ Resolver resolver, {
+ String? basePath,
+ List<String>? reportOn,
+ Set<Glob>? ignoreGlobs,
+ }) {
+ final pathFilter = _getPathFilter(
+ reportOn: reportOn,
+ ignoreGlobs: ignoreGlobs,
+ );
+ final buf = StringBuffer();
+ for (final entry in entries) {
+ final v = entry.value;
+ final lineHits = v.lineHits;
+ final funcHits = v.funcHits;
+ final funcNames = v.funcNames;
+ final branchHits = v.branchHits;
+ var source = resolver.resolve(entry.key);
+ if (source == null) {
+ continue;
+ }
+
+ if (!pathFilter(source)) {
+ continue;
+ }
+
+ if (basePath != null) {
+ source = p.relative(source, from: basePath);
+ }
+
+ buf.write('SF:$source\n');
+ if (funcHits != null && funcNames != null) {
+ for (final k in funcNames.keys.toList()..sort()) {
+ buf.write('FN:$k,${funcNames[k]}\n');
+ }
+ for (final k in funcHits.keys.toList()..sort()) {
+ if (funcHits[k]! != 0) {
+ buf.write('FNDA:${funcHits[k]},${funcNames[k]}\n');
+ }
+ }
+ buf.write('FNF:${funcNames.length}\n');
+ buf.write('FNH:${funcHits.values.where((v) => v > 0).length}\n');
+ }
+ for (final k in lineHits.keys.toList()..sort()) {
+ buf.write('DA:$k,${lineHits[k]}\n');
+ }
+ buf.write('LF:${lineHits.length}\n');
+ buf.write('LH:${lineHits.values.where((v) => v > 0).length}\n');
+ if (branchHits != null) {
+ for (final k in branchHits.keys.toList()..sort()) {
+ buf.write('BRDA:$k,0,0,${branchHits[k]}\n');
+ }
+ }
+ buf.write('end_of_record\n');
+ }
+
+ return buf.toString();
+ }
+
+ /// Converts the given hitmap to a pretty-print format.
+ ///
+ /// If [reportOn] is provided, coverage report output is limited to files
+ /// prefixed with one of the paths included. If [reportFuncs] is provided,
+ /// only function coverage information will be shown.
+ Future<String> prettyPrint(
+ Resolver resolver,
+ Loader loader, {
+ List<String>? reportOn,
+ Set<Glob>? ignoreGlobs,
+ bool reportFuncs = false,
+ bool reportBranches = false,
+ }) async {
+ final pathFilter = _getPathFilter(
+ reportOn: reportOn,
+ ignoreGlobs: ignoreGlobs,
+ );
+ final buf = StringBuffer();
+ for (final entry in entries) {
+ final v = entry.value;
+ if (reportFuncs && v.funcHits == null) {
+ throw StateError(
+ 'Function coverage formatting was requested, but the hit map is '
+ 'missing function coverage information. Did you run '
+ 'collect_coverage with the --function-coverage flag?',
+ );
+ }
+ if (reportBranches && v.branchHits == null) {
+ throw StateError(
+ 'Branch coverage formatting was requested, but the hit map is '
+ 'missing branch coverage information. Did you run '
+ 'collect_coverage with the --branch-coverage flag?');
+ }
+ final hits = reportFuncs
+ ? v.funcHits!
+ : reportBranches
+ ? v.branchHits!
+ : v.lineHits;
+ final source = resolver.resolve(entry.key);
+ if (source == null) {
+ continue;
+ }
+
+ if (!pathFilter(source)) {
+ continue;
+ }
+
+ final lines = await loader.load(source);
+ if (lines == null) {
+ continue;
+ }
+ buf.writeln(source);
+ for (var line = 1; line <= lines.length; line++) {
+ var prefix = _prefix;
+ if (hits.containsKey(line)) {
+ prefix = hits[line].toString().padLeft(_prefix.length);
+ }
+ buf.writeln('$prefix|${lines[line - 1]}');
+ }
+ }
+
+ return buf.toString();
+ }
+}
+
+const _prefix = ' ';
+
+typedef _PathFilter = bool Function(String path);
+
+_PathFilter _getPathFilter({List<String>? reportOn, Set<Glob>? ignoreGlobs}) {
+ if (reportOn == null && ignoreGlobs == null) return (String path) => true;
+
+ final absolutePaths = reportOn?.map(p.canonicalize).toList();
+
+ return (String path) {
+ final canonicalizedPath = p.canonicalize(path);
+
+ if (absolutePaths != null &&
+ !absolutePaths.any(canonicalizedPath.startsWith)) {
+ return false;
+ }
+ if (ignoreGlobs != null &&
+ ignoreGlobs.any((glob) => glob.matches(canonicalizedPath))) {
+ return false;
+ }
+
+ return true;
+ };
+}
diff --git a/pkgs/coverage/lib/src/hitmap.dart b/pkgs/coverage/lib/src/hitmap.dart
new file mode 100644
index 0000000..4c3b468
--- /dev/null
+++ b/pkgs/coverage/lib/src/hitmap.dart
@@ -0,0 +1,386 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show json;
+import 'dart:io';
+
+import 'resolver.dart';
+import 'util.dart';
+
+/// Contains line and function hit information for a single script.
+class HitMap {
+ /// Constructs a HitMap.
+ HitMap([
+ Map<int, int>? lineHits,
+ this.funcHits,
+ this.funcNames,
+ this.branchHits,
+ ]) : lineHits = lineHits ?? {};
+
+ /// Map from line to hit count for that line.
+ final Map<int, int> lineHits;
+
+ /// Map from the first line of each function, to the hit count for that
+ /// function. Null if function coverage info was not gathered.
+ Map<int, int>? funcHits;
+
+ /// Map from the first line of each function, to the function name. Null if
+ /// function coverage info was not gathered.
+ Map<int, String>? funcNames;
+
+ /// Map from branch line, to the hit count for that branch. Null if branch
+ /// coverage info was not gathered.
+ Map<int, int>? branchHits;
+
+ /// Creates a single hitmap from a raw json object.
+ ///
+ /// Note that when [checkIgnoredLines] is `true` all files will be
+ /// read to get ignore comments. This will add some overhead.
+ /// To combat this when calling this function multiple times from the
+ /// same source (e.g. test runs of different files) a cache is taken
+ /// via [ignoredLinesInFilesCache]. If this cache contains the parsed
+ /// data for the specific file already, the file will not be read and
+ /// parsed again.
+ ///
+ /// Throws away all entries that are not resolvable.
+ static Map<String, HitMap> parseJsonSync(
+ List<Map<String, dynamic>> jsonResult, {
+ required bool checkIgnoredLines,
+ required Map<String, List<List<int>>?> ignoredLinesInFilesCache,
+ required Resolver resolver,
+ }) {
+ final loader = Loader();
+
+ // Map of source file to map of line to hit count for that line.
+ final globalHitMap = <String, HitMap>{};
+
+ for (var e in jsonResult) {
+ final source = e['source'] as String?;
+ if (source == null) {
+ // Couldn't resolve import, so skip this entry.
+ continue;
+ }
+
+ var ignoredLinesList = <List<int>>[];
+
+ if (checkIgnoredLines) {
+ if (ignoredLinesInFilesCache.containsKey(source)) {
+ final cacheHit = ignoredLinesInFilesCache[source];
+ if (cacheHit == null) {
+ // Null-entry indicates that the whole file was ignored.
+ continue;
+ }
+ ignoredLinesList = cacheHit;
+ } else {
+ final path = resolver.resolve(source);
+ if (path != null) {
+ final lines = loader.loadSync(path) ?? [];
+ ignoredLinesList = getIgnoredLines(path, lines);
+
+ // Ignore the whole file.
+ if (ignoredLinesList.length == 1 &&
+ ignoredLinesList[0][0] == 0 &&
+ ignoredLinesList[0][1] == lines.length) {
+ // Null-entry indicates that the whole file was ignored.
+ ignoredLinesInFilesCache[source] = null;
+ continue;
+ }
+ ignoredLinesInFilesCache[source] = ignoredLinesList;
+ } else {
+ // Couldn't resolve source. Allow cache to answer next time
+ // anyway.
+ ignoredLinesInFilesCache[source] = ignoredLinesList;
+ }
+ }
+ }
+
+ // Move to the first ignore range.
+ final ignoredLines = ignoredLinesList.iterator;
+ var hasCurrent = ignoredLines.moveNext();
+
+ bool shouldIgnoreLine(Iterator<List<int>> ignoredRanges, int line) {
+ if (!hasCurrent || ignoredRanges.current.isEmpty) {
+ return false;
+ }
+
+ if (line < ignoredRanges.current[0]) return false;
+
+ while (hasCurrent &&
+ ignoredRanges.current.isNotEmpty &&
+ ignoredRanges.current[1] < line) {
+ hasCurrent = ignoredRanges.moveNext();
+ }
+
+ if (hasCurrent &&
+ ignoredRanges.current.isNotEmpty &&
+ ignoredRanges.current[0] <= line &&
+ line <= ignoredRanges.current[1]) {
+ return true;
+ }
+
+ return false;
+ }
+
+ void addToMap(Map<int, int> map, int line, int count) {
+ final oldCount = map.putIfAbsent(line, () => 0);
+ map[line] = count + oldCount;
+ }
+
+ void fillHitMap(List hits, Map<int, int> hitMap) {
+ // Ignore line annotations require hits to be sorted.
+ hits = _sortHits(hits);
+ // hits is a flat array of the following format:
+ // [ <line|linerange>, <hitcount>,...]
+ // line: number.
+ // linerange: '<line>-<line>'.
+ for (var i = 0; i < hits.length; i += 2) {
+ final k = hits[i];
+ if (k is int) {
+ // Single line.
+ if (shouldIgnoreLine(ignoredLines, k)) continue;
+
+ addToMap(hitMap, k, hits[i + 1] as int);
+ } else if (k is String) {
+ // Linerange. We expand line ranges to actual lines at this point.
+ final splitPos = k.indexOf('-');
+ final start = int.parse(k.substring(0, splitPos));
+ final end = int.parse(k.substring(splitPos + 1));
+ for (var j = start; j <= end; j++) {
+ if (shouldIgnoreLine(ignoredLines, j)) continue;
+
+ addToMap(hitMap, j, hits[i + 1] as int);
+ }
+ } else {
+ throw StateError('Expected value of type int or String');
+ }
+ }
+ }
+
+ final sourceHitMap = globalHitMap.putIfAbsent(source, HitMap.new);
+ fillHitMap(e['hits'] as List, sourceHitMap.lineHits);
+ if (e.containsKey('funcHits')) {
+ sourceHitMap.funcHits ??= <int, int>{};
+ fillHitMap(e['funcHits'] as List, sourceHitMap.funcHits!);
+ }
+ if (e.containsKey('funcNames')) {
+ sourceHitMap.funcNames ??= <int, String>{};
+ final funcNames = e['funcNames'] as List;
+ for (var i = 0; i < funcNames.length; i += 2) {
+ sourceHitMap.funcNames![funcNames[i] as int] =
+ funcNames[i + 1] as String;
+ }
+ }
+ if (e.containsKey('branchHits')) {
+ sourceHitMap.branchHits ??= <int, int>{};
+ fillHitMap(e['branchHits'] as List, sourceHitMap.branchHits!);
+ }
+ }
+ return globalHitMap;
+ }
+
+ /// Creates a single hitmap from a raw json object.
+ ///
+ /// Throws away all entries that are not resolvable.
+ static Future<Map<String, HitMap>> parseJson(
+ List<Map<String, dynamic>> jsonResult, {
+ bool checkIgnoredLines = false,
+ @Deprecated('Use packagePath') String? packagesPath,
+ String? packagePath,
+ }) async {
+ final resolver = await Resolver.create(
+ packagesPath: packagesPath, packagePath: packagePath);
+ return parseJsonSync(jsonResult,
+ checkIgnoredLines: checkIgnoredLines,
+ ignoredLinesInFilesCache: {},
+ resolver: resolver);
+ }
+
+ /// Generates a merged hitmap from a set of coverage JSON files.
+ static Future<Map<String, HitMap>> parseFiles(
+ Iterable<File> files, {
+ bool checkIgnoredLines = false,
+ @Deprecated('Use packagePath') String? packagesPath,
+ String? packagePath,
+ }) async {
+ final globalHitmap = <String, HitMap>{};
+ for (var file in files) {
+ final contents = file.readAsStringSync();
+ final jsonMap = json.decode(contents) as Map<String, dynamic>;
+ if (jsonMap.containsKey('coverage')) {
+ final jsonResult = jsonMap['coverage'] as List;
+ globalHitmap.merge(await HitMap.parseJson(
+ jsonResult.cast<Map<String, dynamic>>(),
+ checkIgnoredLines: checkIgnoredLines,
+ // ignore: deprecated_member_use_from_same_package
+ packagesPath: packagesPath,
+ packagePath: packagePath,
+ ));
+ }
+ }
+ return globalHitmap;
+ }
+}
+
+extension FileHitMaps on Map<String, HitMap> {
+ /// Merges [newMap] into this one.
+ void merge(Map<String, HitMap> newMap) {
+ newMap.forEach((file, v) {
+ final fileResult = this[file];
+ if (fileResult != null) {
+ _mergeHitCounts(v.lineHits, fileResult.lineHits);
+ if (v.funcHits != null) {
+ fileResult.funcHits ??= <int, int>{};
+ _mergeHitCounts(v.funcHits!, fileResult.funcHits!);
+ }
+ if (v.funcNames != null) {
+ fileResult.funcNames ??= <int, String>{};
+ v.funcNames?.forEach((line, name) {
+ fileResult.funcNames![line] = name;
+ });
+ }
+ if (v.branchHits != null) {
+ fileResult.branchHits ??= <int, int>{};
+ _mergeHitCounts(v.branchHits!, fileResult.branchHits!);
+ }
+ } else {
+ this[file] = v;
+ }
+ });
+ }
+
+ static void _mergeHitCounts(Map<int, int> src, Map<int, int> dest) {
+ src.forEach((line, count) {
+ final lineFileResult = dest[line];
+ if (lineFileResult == null) {
+ dest[line] = count;
+ } else {
+ dest[line] = lineFileResult + count;
+ }
+ });
+ }
+}
+
+/// Class containing information about a coverage hit.
+class _HitInfo {
+ _HitInfo(this.firstLine, this.hitRange, this.hitCount);
+
+ /// The line number of the first line of this hit range.
+ final int firstLine;
+
+ /// A hit range is either a number (1 line) or a String of the form
+ /// "start-end" (multi-line range).
+ final dynamic hitRange;
+
+ /// How many times this hit range was executed.
+ final int hitCount;
+}
+
+/// Creates a single hitmap from a raw json object.
+///
+/// Throws away all entries that are not resolvable.
+@Deprecated('Migrate to HitMap.parseJson')
+Future<Map<String, Map<int, int>>> createHitmap(
+ List<Map<String, dynamic>> jsonResult, {
+ bool checkIgnoredLines = false,
+ @Deprecated('Use packagePath') String? packagesPath,
+ String? packagePath,
+}) async {
+ final result = await HitMap.parseJson(
+ jsonResult,
+ checkIgnoredLines: checkIgnoredLines,
+ packagesPath: packagesPath,
+ packagePath: packagePath,
+ );
+ return result.map((key, value) => MapEntry(key, value.lineHits));
+}
+
+/// Merges [newMap] into [result].
+@Deprecated('Migrate to FileHitMaps.merge')
+void mergeHitmaps(
+ Map<String, Map<int, int>> newMap, Map<String, Map<int, int>> result) {
+ newMap.forEach((file, v) {
+ final fileResult = result[file];
+ if (fileResult != null) {
+ v.forEach((line, count) {
+ final lineFileResult = fileResult[line];
+ if (lineFileResult == null) {
+ fileResult[line] = count;
+ } else {
+ fileResult[line] = lineFileResult + count;
+ }
+ });
+ } else {
+ result[file] = v;
+ }
+ });
+}
+
+/// Generates a merged hitmap from a set of coverage JSON files.
+@Deprecated('Migrate to HitMap.parseFiles')
+Future<Map<String, Map<int, int>>> parseCoverage(
+ Iterable<File> files,
+ int _, {
+ bool checkIgnoredLines = false,
+ @Deprecated('Use packagePath') String? packagesPath,
+ String? packagePath,
+}) async {
+ final result = await HitMap.parseFiles(files,
+ checkIgnoredLines: checkIgnoredLines,
+ packagesPath: packagesPath,
+ packagePath: packagePath);
+ return result.map((key, value) => MapEntry(key, value.lineHits));
+}
+
+/// Returns a JSON hit map backward-compatible with pre-1.16.0 SDKs.
+@Deprecated('Will be removed in 2.0.0')
+Map<String, dynamic> toScriptCoverageJson(Uri scriptUri, Map<int, int> hitMap) {
+ return hitmapToJson(HitMap(hitMap), scriptUri);
+}
+
+List<T> _flattenMap<T>(Map map) {
+ final kvs = <T>[];
+ map.forEach((k, v) {
+ kvs.add(k as T);
+ kvs.add(v as T);
+ });
+ return kvs;
+}
+
+/// Returns a JSON hit map backward-compatible with pre-1.16.0 SDKs.
+Map<String, dynamic> hitmapToJson(HitMap hitmap, Uri scriptUri) =>
+ <String, dynamic>{
+ 'source': '$scriptUri',
+ 'script': {
+ 'type': '@Script',
+ 'fixedId': true,
+ 'id':
+ 'libraries/1/scripts/${Uri.encodeComponent(scriptUri.toString())}',
+ 'uri': '$scriptUri',
+ '_kind': 'library',
+ },
+ 'hits': _flattenMap<int>(hitmap.lineHits),
+ if (hitmap.funcHits != null)
+ 'funcHits': _flattenMap<int>(hitmap.funcHits!),
+ if (hitmap.funcNames != null)
+ 'funcNames': _flattenMap<dynamic>(hitmap.funcNames!),
+ if (hitmap.branchHits != null)
+ 'branchHits': _flattenMap<int>(hitmap.branchHits!),
+ };
+
+/// Sorts the hits array based on the line numbers.
+List _sortHits(List hits) {
+ final structuredHits = <_HitInfo>[];
+ for (var i = 0; i < hits.length - 1; i += 2) {
+ final lineOrLineRange = hits[i];
+ final firstLineInRange = lineOrLineRange is int
+ ? lineOrLineRange
+ : int.parse((lineOrLineRange as String).split('-')[0]);
+ structuredHits.add(_HitInfo(firstLineInRange, hits[i], hits[i + 1] as int));
+ }
+ structuredHits.sort((a, b) => a.firstLine.compareTo(b.firstLine));
+ return structuredHits
+ .map((item) => [item.hitRange, item.hitCount])
+ .expand((item) => item)
+ .toList();
+}
diff --git a/pkgs/coverage/lib/src/isolate_paused_listener.dart b/pkgs/coverage/lib/src/isolate_paused_listener.dart
new file mode 100644
index 0000000..6f538a4
--- /dev/null
+++ b/pkgs/coverage/lib/src/isolate_paused_listener.dart
@@ -0,0 +1,281 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'package:meta/meta.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'util.dart';
+
+typedef SyncIsolateCallback = void Function(IsolateRef isolate);
+typedef AsyncIsolateCallback = Future<void> Function(IsolateRef isolate);
+typedef AsyncIsolatePausedCallback = Future<void> Function(
+ IsolateRef isolate, bool isLastIsolateInGroup);
+typedef AsyncVmServiceEventCallback = Future<void> Function(Event event);
+typedef SyncErrorLogger = void Function(String message);
+
+/// Calls onIsolatePaused whenever an isolate reaches the pause-on-exit state,
+/// and passes a flag stating whether that isolate is the last one in the group.
+class IsolatePausedListener {
+ IsolatePausedListener(this._service, this._onIsolatePaused, this._log);
+
+ final VmService _service;
+ final AsyncIsolatePausedCallback _onIsolatePaused;
+ final SyncErrorLogger _log;
+
+ final _isolateGroups = <String, IsolateGroupState>{};
+
+ int _numNonMainIsolates = 0;
+ final _allNonMainIsolatesExited = Completer<void>();
+ bool _finished = false;
+
+ IsolateRef? _mainIsolate;
+ final _mainIsolatePaused = Completer<bool>();
+
+ /// Starts listening and returns a future that completes when all isolates
+ /// have exited.
+ Future<void> waitUntilAllExited() async {
+ await listenToIsolateLifecycleEvents(_service, _onStart, _onPause, _onExit);
+
+ await _allNonMainIsolatesExited.future;
+
+ // Resume the main isolate.
+ try {
+ if (_mainIsolate != null) {
+ if (await _mainIsolatePaused.future) {
+ await _runCallbackAndResume(
+ _mainIsolate!, !_getGroup(_mainIsolate!).collected);
+ }
+ }
+ } finally {
+ _finished = true;
+ }
+ }
+
+ IsolateGroupState _getGroup(IsolateRef isolateRef) =>
+ _isolateGroups[isolateRef.isolateGroupId!] ??= IsolateGroupState();
+
+ void _onStart(IsolateRef isolateRef) {
+ if (_finished) return;
+ final group = _getGroup(isolateRef);
+ group.start(isolateRef.id!);
+ if (_mainIsolate == null && _isMainIsolate(isolateRef)) {
+ _mainIsolate = isolateRef;
+ } else {
+ ++_numNonMainIsolates;
+ }
+ }
+
+ Future<void> _onPause(IsolateRef isolateRef) async {
+ if (_finished) return;
+ final group = _getGroup(isolateRef);
+ group.pause(isolateRef.id!);
+ if (isolateRef.id! == _mainIsolate?.id) {
+ _mainIsolatePaused.complete(true);
+
+ // If the main isolate is the only isolate, then _allNonMainIsolatesExited
+ // will never be completed. So check that case here.
+ _checkCompleted();
+ } else {
+ await _runCallbackAndResume(isolateRef, group.noRunningIsolates);
+ }
+ }
+
+ Future<void> _runCallbackAndResume(
+ IsolateRef isolateRef, bool isLastIsolateInGroup) async {
+ if (isLastIsolateInGroup) {
+ _getGroup(isolateRef).collected = true;
+ }
+ try {
+ await _onIsolatePaused(isolateRef, isLastIsolateInGroup);
+ } finally {
+ await _service.resume(isolateRef.id!);
+ }
+ }
+
+ void _onExit(IsolateRef isolateRef) {
+ if (_finished) return;
+ final group = _getGroup(isolateRef);
+ group.exit(isolateRef.id!);
+ if (group.noLiveIsolates && !group.collected) {
+ _log('ERROR: An isolate exited without pausing, causing '
+ 'coverage data to be lost for group ${isolateRef.isolateGroupId!}.');
+ }
+ if (isolateRef.id! == _mainIsolate?.id) {
+ if (!_mainIsolatePaused.isCompleted) {
+ // Main isolate exited without pausing.
+ _mainIsolatePaused.complete(false);
+ }
+ } else {
+ --_numNonMainIsolates;
+ _checkCompleted();
+ }
+ }
+
+ bool get _mainRunning =>
+ _mainIsolate != null && !_mainIsolatePaused.isCompleted;
+
+ void _checkCompleted() {
+ if (_numNonMainIsolates == 0 &&
+ !_mainRunning &&
+ !_allNonMainIsolatesExited.isCompleted) {
+ _allNonMainIsolatesExited.complete();
+ }
+ }
+
+ static bool _isMainIsolate(IsolateRef isolateRef) {
+ // HACK: This should pretty reliably detect the main isolate, but it's not
+ // foolproof and relies on unstable features. The Dart standalone embedder
+ // and Flutter both call the main isolate "main", and they both also list
+ // this isolate first when querying isolates from the VM service. So
+ // selecting the first isolate named "main" combines these conditions and
+ // should be reliable enough for now, while we wait for a better test.
+ // TODO(https://github.com/dart-lang/sdk/issues/56732): Switch to more
+ // reliable test when it's available.
+ return isolateRef.name == 'main';
+ }
+}
+
+/// Listens to isolate start and pause events, and backfills events for isolates
+/// that existed before listening started.
+///
+/// Ensures that:
+/// - Every [onIsolatePaused] and [onIsolateExited] call will be preceeded by
+/// an [onIsolateStarted] call for the same isolate.
+/// - Not every [onIsolateExited] call will be preceeded by a [onIsolatePaused]
+/// call, but a [onIsolatePaused] will never follow a [onIsolateExited].
+/// - [onIsolateExited] will always run after [onIsolatePaused] completes, even
+/// if an exit event arrives while [onIsolatePaused] is being awaited.
+/// - Each callback will only be called once per isolate.
+Future<void> listenToIsolateLifecycleEvents(
+ VmService service,
+ SyncIsolateCallback onIsolateStarted,
+ AsyncIsolateCallback onIsolatePaused,
+ SyncIsolateCallback onIsolateExited) async {
+ final started = <String>{};
+ void onStart(IsolateRef isolateRef) {
+ if (started.add(isolateRef.id!)) onIsolateStarted(isolateRef);
+ }
+
+ final paused = <String, Future<void>>{};
+ Future<void> onPause(IsolateRef isolateRef) async {
+ try {
+ onStart(isolateRef);
+ } finally {
+ await (paused[isolateRef.id!] ??= onIsolatePaused(isolateRef));
+ }
+ }
+
+ final exited = <String>{};
+ Future<void> onExit(IsolateRef isolateRef) async {
+ onStart(isolateRef);
+ if (exited.add(isolateRef.id!)) {
+ try {
+ // Wait for in-progress pause callbacks, and prevent future pause
+ // callbacks from running.
+ await (paused[isolateRef.id!] ??= Future<void>.value());
+ } finally {
+ onIsolateExited(isolateRef);
+ }
+ }
+ }
+
+ final eventBuffer = IsolateEventBuffer((Event event) async {
+ switch (event.kind) {
+ case EventKind.kIsolateStart:
+ return onStart(event.isolate!);
+ case EventKind.kPauseExit:
+ return await onPause(event.isolate!);
+ case EventKind.kIsolateExit:
+ return await onExit(event.isolate!);
+ }
+ });
+
+ // Listen for isolate start/exit events.
+ service.onIsolateEvent.listen(eventBuffer.add);
+ await service.streamListen(EventStreams.kIsolate);
+
+ // Listen for isolate paused events.
+ service.onDebugEvent.listen(eventBuffer.add);
+ await service.streamListen(EventStreams.kDebug);
+
+ // Backfill. Add/pause isolates that existed before we subscribed.
+ for (final isolateRef in await getAllIsolates(service)) {
+ onStart(isolateRef);
+ final isolate = await service.getIsolate(isolateRef.id!);
+ if (isolate.pauseEvent?.kind == EventKind.kPauseExit) {
+ await onPause(isolateRef);
+ }
+ }
+
+ // Flush the buffered stream events, and the start processing them as they
+ // arrive.
+ await eventBuffer.flush();
+}
+
+/// Keeps track of isolates in an isolate group.
+class IsolateGroupState {
+ // IDs of the isolates running in this group.
+ @visibleForTesting
+ final running = <String>{};
+
+ // IDs of the isolates paused just before exiting in this group.
+ @visibleForTesting
+ final paused = <String>{};
+
+ bool collected = false;
+
+ bool get noRunningIsolates => running.isEmpty;
+ bool get noLiveIsolates => running.isEmpty && paused.isEmpty;
+
+ void start(String id) {
+ paused.remove(id);
+ running.add(id);
+ }
+
+ void pause(String id) {
+ running.remove(id);
+ paused.add(id);
+ }
+
+ void exit(String id) {
+ running.remove(id);
+ paused.remove(id);
+ }
+
+ @override
+ String toString() => '{running: $running, paused: $paused}';
+}
+
+/// Buffers VM service isolate [Event]s until [flush] is called.
+///
+/// [flush] passes each buffered event to the handler function. After that, any
+/// further events are immediately passed to the handler. [flush] returns a
+/// future that completes when all the events in the queue have been handled (as
+/// well as any events that arrive while flush is in progress).
+class IsolateEventBuffer {
+ IsolateEventBuffer(this._handler);
+
+ final AsyncVmServiceEventCallback _handler;
+ final _buffer = Queue<Event>();
+ var _flushed = false;
+
+ Future<void> add(Event event) async {
+ if (_flushed) {
+ await _handler(event);
+ } else {
+ _buffer.add(event);
+ }
+ }
+
+ Future<void> flush() async {
+ while (_buffer.isNotEmpty) {
+ final event = _buffer.removeFirst();
+ await _handler(event);
+ }
+ _flushed = true;
+ }
+}
diff --git a/pkgs/coverage/lib/src/resolver.dart b/pkgs/coverage/lib/src/resolver.dart
new file mode 100644
index 0000000..cb5b728
--- /dev/null
+++ b/pkgs/coverage/lib/src/resolver.dart
@@ -0,0 +1,216 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:package_config/package_config.dart';
+import 'package:path/path.dart' as p;
+
+/// [Resolver] resolves imports with respect to a given environment.
+class Resolver {
+ @Deprecated('Use Resolver.create')
+ Resolver({this.packagesPath, this.sdkRoot})
+ : _packages = packagesPath != null ? _parsePackages(packagesPath) : null,
+ packagePath = null;
+
+ Resolver._(
+ {this.packagesPath,
+ this.packagePath,
+ this.sdkRoot,
+ Map<String, Uri>? packages})
+ : _packages = packages;
+
+ static Future<Resolver> create({
+ String? packagesPath,
+ String? packagePath,
+ String? sdkRoot,
+ }) async {
+ return Resolver._(
+ packagesPath: packagesPath,
+ packagePath: packagePath,
+ sdkRoot: sdkRoot,
+ packages: packagesPath != null
+ ? _parsePackages(packagesPath)
+ : (packagePath != null ? await _parsePackage(packagePath) : null),
+ );
+ }
+
+ final String? packagesPath;
+ final String? packagePath;
+ final String? sdkRoot;
+ final List<String> failed = [];
+ final Map<String, Uri>? _packages;
+
+ /// Returns the absolute path wrt. to the given environment or null, if the
+ /// import could not be resolved.
+ String? resolve(String scriptUri) {
+ final uri = Uri.parse(scriptUri);
+ if (uri.scheme == 'dart') {
+ final sdkRoot = this.sdkRoot;
+ if (sdkRoot == null) {
+ // No sdk-root given, do not resolve dart: URIs.
+ return null;
+ }
+ String filePath;
+ if (uri.pathSegments.length > 1) {
+ var path = uri.pathSegments[0];
+ // Drop patch files, since we don't have their source in the compiled
+ // SDK.
+ if (path.endsWith('-patch')) {
+ failed.add('$uri');
+ return null;
+ }
+ // Canonicalize path. For instance: _collection-dev => _collection_dev.
+ path = path.replaceAll('-', '_');
+ final pathSegments = [
+ sdkRoot,
+ path,
+ ...uri.pathSegments.sublist(1),
+ ];
+ filePath = p.joinAll(pathSegments);
+ } else {
+ // Resolve 'dart:something' to be something/something.dart in the SDK.
+ final lib = uri.path;
+ filePath = p.join(sdkRoot, lib, '$lib.dart');
+ }
+ return resolveSymbolicLinks(filePath);
+ }
+ if (uri.scheme == 'package') {
+ final packages = _packages;
+ if (packages == null) {
+ return null;
+ }
+
+ final packageName = uri.pathSegments[0];
+ final packageUri = packages[packageName];
+ if (packageUri == null) {
+ failed.add('$uri');
+ return null;
+ }
+ final packagePath = p.fromUri(packageUri);
+ final pathInPackage = p.joinAll(uri.pathSegments.sublist(1));
+ return resolveSymbolicLinks(p.join(packagePath, pathInPackage));
+ }
+ if (uri.scheme == 'file') {
+ return resolveSymbolicLinks(p.fromUri(uri));
+ }
+ // We cannot deal with anything else.
+ failed.add('$uri');
+ return null;
+ }
+
+ /// Returns a canonicalized path, or `null` if the path cannot be resolved.
+ String? resolveSymbolicLinks(String path) {
+ final normalizedPath = p.normalize(path);
+ final type = FileSystemEntity.typeSync(normalizedPath, followLinks: true);
+ if (type == FileSystemEntityType.notFound) return null;
+ return File(normalizedPath).resolveSymbolicLinksSync();
+ }
+
+ static Map<String, Uri> _parsePackages(String packagesPath) {
+ final content = File(packagesPath).readAsStringSync();
+ final packagesUri = p.toUri(packagesPath);
+ final parsed =
+ PackageConfig.parseString(content, Uri.base.resolveUri(packagesUri));
+ return {
+ for (var package in parsed.packages) package.name: package.packageUriRoot
+ };
+ }
+
+ static Future<Map<String, Uri>?> _parsePackage(String packagePath) async {
+ final parsed = await findPackageConfig(Directory(packagePath));
+ if (parsed == null) return null;
+ return {
+ for (var package in parsed.packages) package.name: package.packageUriRoot
+ };
+ }
+}
+
+/// Bazel URI resolver.
+class BazelResolver extends Resolver {
+ /// Creates a Bazel resolver with the specified workspace path, if any.
+ BazelResolver({this.workspacePath = ''});
+
+ final String workspacePath;
+
+ /// Returns the absolute path wrt. to the given environment or null, if the
+ /// import could not be resolved.
+ @override
+ String? resolve(String scriptUri) {
+ final uri = Uri.parse(scriptUri);
+ if (uri.scheme == 'dart') {
+ // Ignore the SDK
+ return null;
+ }
+ if (uri.scheme == 'package') {
+ // TODO(cbracken) belongs in a Bazel package
+ return _resolveBazelPackage(uri.pathSegments);
+ }
+ if (uri.scheme == 'file') {
+ final runfilesPathSegment =
+ '.runfiles/$workspacePath'.replaceAll(RegExp(r'/*$'), '/');
+ final runfilesPos = uri.path.indexOf(runfilesPathSegment);
+ if (runfilesPos >= 0) {
+ final pathStart = runfilesPos + runfilesPathSegment.length;
+ return uri.path.substring(pathStart);
+ }
+ return null;
+ }
+ if (uri.scheme == 'https' || uri.scheme == 'http') {
+ return _extractHttpPath(uri);
+ }
+ // We cannot deal with anything else.
+ failed.add('$uri');
+ return null;
+ }
+
+ String _extractHttpPath(Uri uri) {
+ final packagesPos = uri.pathSegments.indexOf('packages');
+ if (packagesPos >= 0) {
+ final workspacePath = uri.pathSegments.sublist(packagesPos + 1);
+ return _resolveBazelPackage(workspacePath);
+ }
+ return uri.pathSegments.join('/');
+ }
+
+ String _resolveBazelPackage(List<String> pathSegments) {
+ // TODO(cbracken) belongs in a Bazel package
+ final packageName = pathSegments[0];
+ final pathInPackage = pathSegments.sublist(1).join('/');
+ final packagePath = packageName.contains('.')
+ ? packageName.replaceAll('.', '/')
+ : 'third_party/dart/$packageName';
+ return '$packagePath/lib/$pathInPackage';
+ }
+}
+
+/// Loads the lines of imported resources.
+class Loader {
+ final List<String> failed = [];
+
+ /// Loads an imported resource and returns a [Future] with a [List] of lines.
+ /// Returns `null` if the resource could not be loaded.
+ Future<List<String>?> load(String path) async {
+ try {
+ // Ensure `readAsLines` runs within the try block so errors are caught.
+ return await File(path).readAsLines();
+ } catch (_) {
+ failed.add(path);
+ return null;
+ }
+ }
+
+ /// Loads an imported resource and returns a [List] of lines.
+ /// Returns `null` if the resource could not be loaded.
+ List<String>? loadSync(String path) {
+ try {
+ // Ensure `readAsLinesSync` runs within the try block so errors are
+ // caught.
+ return File(path).readAsLinesSync();
+ } catch (_) {
+ failed.add(path);
+ return null;
+ }
+ }
+}
diff --git a/pkgs/coverage/lib/src/run_and_collect.dart b/pkgs/coverage/lib/src/run_and_collect.dart
new file mode 100644
index 0000000..f2a9cbc
--- /dev/null
+++ b/pkgs/coverage/lib/src/run_and_collect.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'collect.dart';
+import 'util.dart';
+
+Future<Map<String, dynamic>> runAndCollect(String scriptPath,
+ {List<String>? scriptArgs,
+ bool checked = false,
+ bool includeDart = false,
+ Duration? timeout}) async {
+ final dartArgs = [
+ '--enable-vm-service',
+ '--pause_isolates_on_exit',
+ if (checked) '--checked',
+ scriptPath,
+ ...?scriptArgs,
+ ];
+
+ final process = await Process.start(Platform.executable, dartArgs);
+
+ final serviceUri = await serviceUriFromProcess(process.stdout.lines());
+ Map<String, dynamic> coverage;
+ try {
+ coverage = await collect(
+ serviceUri,
+ true,
+ true,
+ includeDart,
+ <String>{},
+ timeout: timeout,
+ );
+ } finally {
+ await process.stderr.drain<void>();
+ }
+ final exitStatus = await process.exitCode;
+ if (exitStatus != 0) {
+ throw ProcessException(
+ Platform.executable,
+ dartArgs,
+ 'Process failed.',
+ exitStatus,
+ );
+ }
+ return coverage;
+}
diff --git a/pkgs/coverage/lib/src/util.dart b/pkgs/coverage/lib/src/util.dart
new file mode 100644
index 0000000..cc7f584
--- /dev/null
+++ b/pkgs/coverage/lib/src/util.dart
@@ -0,0 +1,186 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:vm_service/vm_service.dart';
+
+// TODO(cbracken) make generic
+/// Retries the specified function with the specified interval and returns
+/// the result on successful completion.
+Future<dynamic> retry(Future Function() f, Duration interval,
+ {Duration? timeout}) async {
+ var keepGoing = true;
+
+ Future<dynamic> withTimeout(Future Function() f, {Duration? duration}) {
+ if (duration == null) {
+ return f();
+ }
+
+ return f().timeout(duration, onTimeout: () {
+ keepGoing = false;
+ final msg = duration.inSeconds == 0
+ ? '${duration.inMilliseconds}ms'
+ : '${duration.inSeconds}s';
+ throw StateError('Failed to complete within $msg');
+ });
+ }
+
+ return withTimeout(() async {
+ while (keepGoing) {
+ try {
+ return await f();
+ } catch (_) {
+ if (keepGoing) {
+ await Future<dynamic>.delayed(interval);
+ }
+ }
+ }
+ }, duration: timeout);
+}
+
+/// Scrapes and returns the Dart VM service URI from a string, or null if not
+/// found.
+///
+/// Potentially useful as a means to extract it from log statements.
+Uri? extractVMServiceUri(String str) {
+ final listeningMessageRegExp = RegExp(
+ r'(?:Observatory|The Dart VM service is) listening on ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)',
+ );
+ final match = listeningMessageRegExp.firstMatch(str);
+ if (match != null) {
+ return Uri.parse(match[1]!);
+ }
+ return null;
+}
+
+/// Returns an open port by creating a temporary Socket
+Future<int> getOpenPort() async {
+ ServerSocket socket;
+
+ try {
+ socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
+ } catch (_) {
+ // try again v/ V6 only. Slight possibility that V4 is disabled
+ socket =
+ await ServerSocket.bind(InternetAddress.loopbackIPv6, 0, v6Only: true);
+ }
+
+ try {
+ return socket.port;
+ } finally {
+ await socket.close();
+ }
+}
+
+final muliLineIgnoreStart = RegExp(r'//\s*coverage:ignore-start[\w\d\s]*$');
+final muliLineIgnoreEnd = RegExp(r'//\s*coverage:ignore-end[\w\d\s]*$');
+final singleLineIgnore = RegExp(r'//\s*coverage:ignore-line[\w\d\s]*$');
+final ignoreFile = RegExp(r'//\s*coverage:ignore-file[\w\d\s]*$');
+
+/// Return list containing inclusive range of lines to be ignored by coverage.
+/// If there is a error in balancing the statements it will throw a
+/// [FormatException],
+/// unless `coverage:ignore-file` is found.
+/// Return [0, lines.length] if the whole file is ignored.
+///
+/// ```
+/// 1. final str = ''; // coverage:ignore-line
+/// 2. final str = '';
+/// 3. final str = ''; // coverage:ignore-start
+/// 4. final str = '';
+/// 5. final str = ''; // coverage:ignore-end
+/// ```
+///
+/// Returns
+/// ```
+/// [
+/// [1,1],
+/// [3,5],
+/// ]
+/// ```
+///
+List<List<int>> getIgnoredLines(String filePath, List<String>? lines) {
+ final ignoredLines = <List<int>>[];
+ if (lines == null) return ignoredLines;
+
+ final allLines = [
+ [0, lines.length]
+ ];
+
+ FormatException? err;
+ var i = 0;
+ while (i < lines.length) {
+ if (lines[i].contains(ignoreFile)) return allLines;
+
+ if (lines[i].contains(muliLineIgnoreEnd)) {
+ err ??= FormatException(
+ 'unmatched coverage:ignore-end found at $filePath:${i + 1}',
+ );
+ }
+
+ if (lines[i].contains(singleLineIgnore)) ignoredLines.add([i + 1, i + 1]);
+
+ if (lines[i].contains(muliLineIgnoreStart)) {
+ final start = i;
+ var isUnmatched = true;
+ ++i;
+ while (i < lines.length) {
+ if (lines[i].contains(ignoreFile)) return allLines;
+ if (lines[i].contains(muliLineIgnoreStart)) {
+ err ??= FormatException(
+ 'coverage:ignore-start found at $filePath:${i + 1}'
+ ' before previous coverage:ignore-start ended',
+ );
+ break;
+ }
+
+ if (lines[i].contains(muliLineIgnoreEnd)) {
+ ignoredLines.add([start + 1, i + 1]);
+ isUnmatched = false;
+ break;
+ }
+ ++i;
+ }
+
+ if (isUnmatched) {
+ err ??= FormatException(
+ 'coverage:ignore-start found at $filePath:${start + 1}'
+ ' has no matching coverage:ignore-end',
+ );
+ }
+ }
+ ++i;
+ }
+
+ if (err == null) {
+ return ignoredLines;
+ }
+
+ throw err;
+}
+
+extension StandardOutExtension on Stream<List<int>> {
+ Stream<String> lines() =>
+ transform(const SystemEncoding().decoder).transform(const LineSplitter());
+}
+
+Future<Uri> serviceUriFromProcess(Stream<String> procStdout) {
+ // Capture the VM service URI.
+ final serviceUriCompleter = Completer<Uri>();
+ procStdout.listen((line) {
+ if (!serviceUriCompleter.isCompleted) {
+ final serviceUri = extractVMServiceUri(line);
+ if (serviceUri != null) {
+ serviceUriCompleter.complete(serviceUri);
+ }
+ }
+ });
+ return serviceUriCompleter.future;
+}
+
+Future<List<IsolateRef>> getAllIsolates(VmService service) async =>
+ (await service.getVM()).isolates ?? [];
diff --git a/pkgs/coverage/pubspec.yaml b/pkgs/coverage/pubspec.yaml
new file mode 100644
index 0000000..2721626
--- /dev/null
+++ b/pkgs/coverage/pubspec.yaml
@@ -0,0 +1,33 @@
+name: coverage
+version: 1.11.1
+description: Coverage data manipulation and formatting
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/coverage
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acoverage
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ args: ^2.0.0
+ glob: ^2.1.2
+ logging: ^1.0.0
+ meta: ^1.0.2
+ package_config: ^2.0.0
+ path: ^1.8.0
+ source_maps: ^0.10.10
+ stack_trace: ^1.10.0
+ vm_service: '>=12.0.0 <16.0.0'
+
+dev_dependencies:
+ benchmark_harness: ^2.2.0
+ build_runner: ^2.3.1
+ dart_flutter_team_lints: ^3.0.0
+ mockito: ^5.4.4
+ test: ^1.24.7
+ test_descriptor: ^2.0.0
+ test_process: ^2.0.0
+
+executables:
+ collect_coverage:
+ format_coverage:
+ test_with_coverage:
diff --git a/pkgs/coverage/test/README.md b/pkgs/coverage/test/README.md
new file mode 100644
index 0000000..8fa00df
--- /dev/null
+++ b/pkgs/coverage/test/README.md
@@ -0,0 +1,9 @@
+## Regenerating mocks
+
+Some of the tests use a mock VmService that is automatically generated by
+Mockito. If the VmService changes, run this command in the root directory of
+this repo to regenerate that mock:
+
+```bash
+dart run build_runner build
+```
diff --git a/pkgs/coverage/test/chrome_test.dart b/pkgs/coverage/test/chrome_test.dart
new file mode 100644
index 0000000..50e7600
--- /dev/null
+++ b/pkgs/coverage/test/chrome_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(https://github.com/dart-lang/tools/issues/494): Fix and re-enable this.
+@TestOn('!windows')
+library;
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:coverage/coverage.dart';
+import 'package:test/test.dart';
+
+// The scriptId for the main_test.js in the sample report.
+const String mainScriptId = '31';
+
+Future<String> sourceMapProvider(String scriptId) async {
+ if (scriptId != mainScriptId) {
+ return 'something invalid!';
+ }
+ return File('test/test_files/main_test.js.map').readAsString();
+}
+
+Future<String?> sourceProvider(String scriptId) async {
+ if (scriptId != mainScriptId) return null;
+ return File('test/test_files/main_test.js').readAsString();
+}
+
+Future<Uri> sourceUriProvider(String sourceUrl, String scriptId) async =>
+ Uri.parse(sourceUrl);
+
+void main() {
+ test('reports correctly', () async {
+ final preciseCoverage = json.decode(
+ await File('test/test_files/chrome_precise_report.txt')
+ .readAsString()) as List;
+
+ final report = await parseChromeCoverage(
+ preciseCoverage.cast(),
+ sourceProvider,
+ sourceMapProvider,
+ sourceUriProvider,
+ );
+
+ final sourceReport =
+ (report['coverage'] as List<Map<String, dynamic>>).firstWhere(
+ (Map<String, dynamic> report) =>
+ report['source'].toString().contains('main_test.dart'),
+ );
+
+ final expectedHits = {
+ 7: 1,
+ 11: 1,
+ 13: 1,
+ 14: 1,
+ 17: 0,
+ 19: 0,
+ 20: 0,
+ 22: 1,
+ 23: 1,
+ 24: 1,
+ 25: 1,
+ 28: 1,
+ 30: 0,
+ 32: 1,
+ 34: 1,
+ 35: 1,
+ 36: 1,
+ };
+
+ final hitMap = sourceReport['hits'] as List<int>;
+ expect(hitMap.length, equals(expectedHits.keys.length * 2));
+ for (var i = 0; i < hitMap.length; i += 2) {
+ expect(expectedHits[hitMap[i]], equals(hitMap[i + 1]));
+ }
+ });
+}
diff --git a/pkgs/coverage/test/collect_coverage_api_test.dart b/pkgs/coverage/test/collect_coverage_api_test.dart
new file mode 100644
index 0000000..fd3de43
--- /dev/null
+++ b/pkgs/coverage/test/collect_coverage_api_test.dart
@@ -0,0 +1,157 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:coverage/coverage.dart';
+import 'package:coverage/src/util.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+
+import 'test_util.dart';
+
+final _isolateLibPath = p.join('test', 'test_files', 'test_app_isolate.dart');
+
+final _sampleAppFileUri = p.toUri(p.absolute(testAppPath)).toString();
+final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();
+
+void main() {
+ test('collect_coverage_api', () async {
+ final coverage = coverageDataFromJson(await _collectCoverage());
+ expect(coverage, isNotEmpty);
+
+ final sources = coverage.sources();
+
+ for (var sampleCoverageData in sources[_sampleAppFileUri]!) {
+ expect(sampleCoverageData['hits'], isNotEmpty);
+ }
+
+ for (var sampleCoverageData in sources[_isolateLibFileUri]!) {
+ expect(sampleCoverageData['hits'], isNotEmpty);
+ }
+ });
+
+ test('collect_coverage_api with scoped output', () async {
+ final coverage = coverageDataFromJson(
+ await _collectCoverage(scopedOutput: <String>{}..add('coverage')),
+ );
+ expect(coverage, isNotEmpty);
+
+ final sources = coverage.sources();
+
+ for (var key in sources.keys) {
+ final uri = Uri.parse(key);
+ expect(uri.path.startsWith('coverage'), isTrue);
+ }
+ });
+
+ test('collect_coverage_api with isolateIds', () async {
+ final coverage =
+ coverageDataFromJson(await _collectCoverage(isolateIds: true));
+ expect(coverage, isEmpty);
+ });
+
+ test('collect_coverage_api with function coverage', () async {
+ final coverage =
+ coverageDataFromJson(await _collectCoverage(functionCoverage: true));
+ expect(coverage, isNotEmpty);
+
+ final sources = coverage.sources();
+
+ final functionInfo = functionInfoFromSources(sources);
+
+ expect(
+ functionInfo[_sampleAppFileUri]!,
+ {
+ 'main': 1,
+ 'usedMethod': 1,
+ 'unusedMethod': 0,
+ },
+ );
+
+ expect(
+ functionInfo[_isolateLibFileUri]!,
+ {
+ 'BarClass.BarClass': 1,
+ 'fooAsync': 1,
+ 'fooSync': 1,
+ 'isolateTask': 1,
+ 'BarClass.baz': 1
+ },
+ );
+ });
+
+ test('collect_coverage_api with branch coverage', () async {
+ final coverage =
+ coverageDataFromJson(await _collectCoverage(branchCoverage: true));
+ expect(coverage, isNotEmpty);
+
+ final sources = coverage.sources();
+
+ // Dart VM versions before 2.17 don't support branch coverage.
+ expect(sources[_sampleAppFileUri],
+ everyElement(containsPair('branchHits', isNotEmpty)));
+ expect(sources[_isolateLibFileUri],
+ everyElement(containsPair('branchHits', isNotEmpty)));
+ });
+
+ test('collect_coverage_api with coverableLineCache', () async {
+ final coverableLineCache = <String, Set<int>>{};
+ final coverage =
+ await _collectCoverage(coverableLineCache: coverableLineCache);
+ final result = await HitMap.parseJson(
+ coverage['coverage'] as List<Map<String, dynamic>>);
+
+ expect(coverableLineCache, contains(_sampleAppFileUri));
+ expect(coverableLineCache, contains(_isolateLibFileUri));
+
+ // Expect that we have some missed lines.
+ expect(result[_sampleAppFileUri]!.lineHits.containsValue(0), isTrue);
+ expect(result[_isolateLibFileUri]!.lineHits.containsValue(0), isTrue);
+
+ // Clear _sampleAppFileUri's cache entry, then gather coverage again. We're
+ // doing this to verify that force compilation is disabled for these
+ // libraries. The result should be that _isolateLibFileUri should be the
+ // same, but _sampleAppFileUri should be missing all its missed lines.
+ coverableLineCache[_sampleAppFileUri] = {};
+ final coverage2 =
+ await _collectCoverage(coverableLineCache: coverableLineCache);
+ final result2 = await HitMap.parseJson(
+ coverage2['coverage'] as List<Map<String, dynamic>>);
+
+ // _isolateLibFileUri still has missed lines, but _sampleAppFileUri doesn't.
+ expect(result2[_sampleAppFileUri]!.lineHits.containsValue(0), isFalse);
+ expect(result2[_isolateLibFileUri]!.lineHits.containsValue(0), isTrue);
+
+ // _isolateLibFileUri is the same. _sampleAppFileUri is the same, but
+ // without all its missed lines.
+ expect(result2[_isolateLibFileUri]!.lineHits,
+ result[_isolateLibFileUri]!.lineHits);
+ result[_sampleAppFileUri]!.lineHits.removeWhere((line, hits) => hits == 0);
+ expect(result2[_sampleAppFileUri]!.lineHits,
+ result[_sampleAppFileUri]!.lineHits);
+ }, skip: !platformVersionCheck(3, 2));
+}
+
+Future<Map<String, dynamic>> _collectCoverage(
+ {Set<String> scopedOutput = const {},
+ bool isolateIds = false,
+ bool functionCoverage = false,
+ bool branchCoverage = false,
+ Map<String, Set<int>>? coverableLineCache}) async {
+ final openPort = await getOpenPort();
+
+ // run the sample app, with the right flags
+ final sampleProcess = await runTestApp(openPort);
+
+ final serviceUri = await serviceUriFromProcess(sampleProcess.stdoutStream());
+ final isolateIdSet = isolateIds ? <String>{} : null;
+
+ return collect(serviceUri, true, true, false, scopedOutput,
+ timeout: timeout,
+ isolateIds: isolateIdSet,
+ functionCoverage: functionCoverage,
+ branchCoverage: branchCoverage,
+ coverableLineCache: coverableLineCache);
+}
diff --git a/pkgs/coverage/test/collect_coverage_mock_test.dart b/pkgs/coverage/test/collect_coverage_mock_test.dart
new file mode 100644
index 0000000..372bd48
--- /dev/null
+++ b/pkgs/coverage/test/collect_coverage_mock_test.dart
@@ -0,0 +1,416 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:coverage/coverage.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'collect_coverage_mock_test.mocks.dart';
+
+@GenerateMocks([VmService])
+SourceReportRange _range(int scriptIndex, SourceReportCoverage coverage) =>
+ SourceReportRange(scriptIndex: scriptIndex, coverage: coverage);
+
+IsolateRef _isoRef(String id, String isoGroupId) =>
+ IsolateRef(id: id, isolateGroupId: isoGroupId);
+
+IsolateGroupRef _isoGroupRef(String id) => IsolateGroupRef(id: id);
+
+IsolateGroup _isoGroup(String id, List<IsolateRef> isolates) =>
+ IsolateGroup(id: id, isolates: isolates);
+
+class FakeSentinelException implements SentinelException {
+ @override
+ dynamic noSuchMethod(Invocation invocation) {}
+}
+
+MockVmService _mockService(
+ int majorVersion,
+ int minorVersion, {
+ Map<String, List<String>> isolateGroups = const {
+ 'isolateGroup': ['isolate'],
+ },
+}) {
+ final service = MockVmService();
+ final isoRefs = <IsolateRef>[];
+ final isoGroupRefs = <IsolateGroupRef>[];
+ final isoGroups = <IsolateGroup>[];
+ for (final group in isolateGroups.entries) {
+ isoGroupRefs.add(_isoGroupRef(group.key));
+ final isosOfGroup = <IsolateRef>[];
+ for (final isoId in group.value) {
+ isosOfGroup.add(_isoRef(isoId, group.key));
+ }
+ isoGroups.add(_isoGroup(group.key, isosOfGroup));
+ isoRefs.addAll(isosOfGroup);
+ }
+ when(service.getVM()).thenAnswer(
+ (_) async => VM(isolates: isoRefs, isolateGroups: isoGroupRefs));
+ for (final group in isoGroups) {
+ when(service.getIsolateGroup(group.id)).thenAnswer((_) async => group);
+ }
+ when(service.getVersion()).thenAnswer(
+ (_) async => Version(major: majorVersion, minor: minorVersion));
+ return service;
+}
+
+void main() {
+ group('Mock VM Service', () {
+ test('Collect coverage', () async {
+ final service = _mockService(4, 13);
+ when(service.getSourceReport(
+ 'isolate',
+ ['Coverage'],
+ forceCompile: true,
+ reportLines: true,
+ )).thenAnswer((_) async => SourceReport(
+ ranges: [
+ _range(
+ 0,
+ SourceReportCoverage(
+ hits: [12],
+ misses: [47],
+ ),
+ ),
+ _range(
+ 1,
+ SourceReportCoverage(
+ hits: [95],
+ misses: [52],
+ ),
+ ),
+ ],
+ scripts: [
+ ScriptRef(
+ uri: 'package:foo/foo.dart',
+ id: 'foo',
+ ),
+ ScriptRef(
+ uri: 'package:bar/bar.dart',
+ id: 'bar',
+ ),
+ ],
+ ));
+
+ final jsonResult = await collect(Uri(), false, false, false, null,
+ serviceOverrideForTesting: service);
+ final result = await HitMap.parseJson(
+ jsonResult['coverage'] as List<Map<String, dynamic>>);
+
+ expect(result.length, 2);
+ expect(result['package:foo/foo.dart']?.lineHits, {12: 1, 47: 0});
+ expect(result['package:bar/bar.dart']?.lineHits, {95: 1, 52: 0});
+ });
+
+ test('Collect coverage, scoped output', () async {
+ final service = _mockService(4, 13);
+ when(service.getSourceReport(
+ 'isolate',
+ ['Coverage'],
+ forceCompile: true,
+ reportLines: true,
+ libraryFilters: ['package:foo/'],
+ )).thenAnswer((_) async => SourceReport(
+ ranges: [
+ _range(
+ 0,
+ SourceReportCoverage(
+ hits: [12],
+ misses: [47],
+ ),
+ ),
+ ],
+ scripts: [
+ ScriptRef(
+ uri: 'package:foo/foo.dart',
+ id: 'foo',
+ ),
+ ],
+ ));
+
+ final jsonResult = await collect(Uri(), false, false, false, {'foo'},
+ serviceOverrideForTesting: service);
+ final result = await HitMap.parseJson(
+ jsonResult['coverage'] as List<Map<String, dynamic>>);
+
+ expect(result.length, 1);
+ expect(result['package:foo/foo.dart']?.lineHits, {12: 1, 47: 0});
+ });
+
+ test('Collect coverage, fast isolate group deduping', () async {
+ final service = _mockService(4, 13, isolateGroups: {
+ 'isolateGroupA': ['isolate1', 'isolate2'],
+ 'isolateGroupB': ['isolate3'],
+ });
+ when(service.getSourceReport(
+ 'isolate1',
+ ['Coverage'],
+ forceCompile: true,
+ reportLines: true,
+ )).thenAnswer((_) async => SourceReport(
+ ranges: [
+ _range(
+ 0,
+ SourceReportCoverage(
+ hits: [12],
+ misses: [47],
+ ),
+ ),
+ _range(
+ 1,
+ SourceReportCoverage(
+ hits: [95],
+ misses: [52],
+ ),
+ ),
+ ],
+ scripts: [
+ ScriptRef(
+ uri: 'package:foo/foo.dart',
+ id: 'foo',
+ ),
+ ScriptRef(
+ uri: 'package:bar/bar.dart',
+ id: 'bar',
+ ),
+ ],
+ ));
+ when(service.getSourceReport(
+ 'isolate3',
+ ['Coverage'],
+ forceCompile: true,
+ reportLines: true,
+ )).thenAnswer((_) async => SourceReport(
+ ranges: [
+ _range(
+ 0,
+ SourceReportCoverage(
+ hits: [34],
+ misses: [61],
+ ),
+ ),
+ ],
+ scripts: [
+ ScriptRef(
+ uri: 'package:baz/baz.dart',
+ id: 'baz',
+ ),
+ ],
+ ));
+
+ final jsonResult = await collect(Uri(), false, false, false, null,
+ serviceOverrideForTesting: service);
+ final result = await HitMap.parseJson(
+ jsonResult['coverage'] as List<Map<String, dynamic>>);
+
+ expect(result.length, 3);
+ expect(result['package:foo/foo.dart']?.lineHits, {12: 1, 47: 0});
+ expect(result['package:bar/bar.dart']?.lineHits, {95: 1, 52: 0});
+ expect(result['package:baz/baz.dart']?.lineHits, {34: 1, 61: 0});
+ verifyNever(service.getSourceReport('isolate2', ['Coverage'],
+ forceCompile: true, reportLines: true));
+ verifyNever(service.getIsolateGroup('isolateGroupA'));
+ verifyNever(service.getIsolateGroup('isolateGroupB'));
+ });
+
+ test(
+ 'Collect coverage, no scoped output, '
+ 'handles SentinelException from getSourceReport', () async {
+ final service = _mockService(4, 13);
+ when(service.getSourceReport(
+ 'isolate',
+ ['Coverage'],
+ forceCompile: true,
+ reportLines: true,
+ )).thenThrow(FakeSentinelException());
+
+ final jsonResult = await collect(Uri(), false, false, false, null,
+ serviceOverrideForTesting: service);
+ final result = await HitMap.parseJson(
+ jsonResult['coverage'] as List<Map<String, dynamic>>);
+
+ expect(result.length, 0);
+ });
+
+ test('Collect coverage, coverableLineCache', () async {
+ // Expect that on the first getSourceReport call, librariesAlreadyCompiled
+ // is empty.
+ final service = _mockService(4, 13);
+ when(service.getSourceReport(
+ 'isolate',
+ ['Coverage'],
+ forceCompile: true,
+ reportLines: true,
+ librariesAlreadyCompiled: [],
+ )).thenAnswer((_) async => SourceReport(
+ ranges: [
+ _range(
+ 0,
+ SourceReportCoverage(
+ hits: [12],
+ misses: [47],
+ ),
+ ),
+ _range(
+ 1,
+ SourceReportCoverage(
+ hits: [95],
+ misses: [52],
+ ),
+ ),
+ ],
+ scripts: [
+ ScriptRef(
+ uri: 'package:foo/foo.dart',
+ id: 'foo',
+ ),
+ ScriptRef(
+ uri: 'package:bar/bar.dart',
+ id: 'bar',
+ ),
+ ],
+ ));
+
+ final coverableLineCache = <String, Set<int>>{};
+ final jsonResult = await collect(Uri(), false, false, false, null,
+ coverableLineCache: coverableLineCache,
+ serviceOverrideForTesting: service);
+ final result = await HitMap.parseJson(
+ jsonResult['coverage'] as List<Map<String, dynamic>>);
+
+ expect(result.length, 2);
+ expect(result['package:foo/foo.dart']?.lineHits, {12: 1, 47: 0});
+ expect(result['package:bar/bar.dart']?.lineHits, {95: 1, 52: 0});
+
+ // The coverableLineCache should now be filled with all the lines that
+ // were hit or missed.
+ expect(coverableLineCache, {
+ 'package:foo/foo.dart': {12, 47},
+ 'package:bar/bar.dart': {95, 52},
+ });
+
+ // The second getSourceReport call should now list all the libraries we've
+ // seen. The response won't contain any misses for these libraries,
+ // because they won't be force compiled. We'll also return a 3rd library,
+ // which will contain misses, as it hasn't been compiled yet.
+ when(service.getSourceReport(
+ 'isolate',
+ ['Coverage'],
+ forceCompile: true,
+ reportLines: true,
+ librariesAlreadyCompiled: [
+ 'package:foo/foo.dart',
+ 'package:bar/bar.dart'
+ ],
+ )).thenAnswer((_) async => SourceReport(
+ ranges: [
+ _range(
+ 0,
+ SourceReportCoverage(
+ hits: [47],
+ ),
+ ),
+ _range(
+ 1,
+ SourceReportCoverage(
+ hits: [95],
+ ),
+ ),
+ _range(
+ 2,
+ SourceReportCoverage(
+ hits: [36],
+ misses: [81],
+ ),
+ ),
+ ],
+ scripts: [
+ ScriptRef(
+ uri: 'package:foo/foo.dart',
+ id: 'foo',
+ ),
+ ScriptRef(
+ uri: 'package:bar/bar.dart',
+ id: 'bar',
+ ),
+ ScriptRef(
+ uri: 'package:baz/baz.dart',
+ id: 'baz',
+ ),
+ ],
+ ));
+
+ final jsonResult2 = await collect(Uri(), false, false, false, null,
+ coverableLineCache: coverableLineCache,
+ serviceOverrideForTesting: service);
+ final result2 = await HitMap.parseJson(
+ jsonResult2['coverage'] as List<Map<String, dynamic>>);
+
+ // The missed lines still appear in foo and bar, even though they weren't
+ // returned in the response. They were read from the cache.
+ expect(result2.length, 3);
+ expect(result2['package:foo/foo.dart']?.lineHits, {12: 0, 47: 1});
+ expect(result2['package:bar/bar.dart']?.lineHits, {95: 1, 52: 0});
+ expect(result2['package:baz/baz.dart']?.lineHits, {36: 1, 81: 0});
+
+ // The coverableLineCache should now also contain the baz library.
+ expect(coverableLineCache, {
+ 'package:foo/foo.dart': {12, 47},
+ 'package:bar/bar.dart': {95, 52},
+ 'package:baz/baz.dart': {36, 81},
+ });
+ });
+
+ test(
+ 'Collect coverage, scoped output, '
+ 'handles SourceReports that contain unfiltered ranges', () async {
+ // Regression test for https://github.com/dart-lang/tools/issues/530
+ final service = _mockService(4, 13);
+ when(service.getSourceReport(
+ 'isolate',
+ ['Coverage'],
+ forceCompile: true,
+ reportLines: true,
+ libraryFilters: ['package:foo/'],
+ )).thenAnswer((_) async => SourceReport(
+ ranges: [
+ _range(
+ 0,
+ SourceReportCoverage(
+ hits: [12],
+ misses: [47],
+ ),
+ ),
+ _range(
+ 1,
+ SourceReportCoverage(
+ hits: [86],
+ misses: [91],
+ ),
+ ),
+ ],
+ scripts: [
+ ScriptRef(
+ uri: 'package:foo/foo.dart',
+ id: 'foo',
+ ),
+ ScriptRef(
+ uri: 'package:bar/bar.dart',
+ id: 'bar',
+ ),
+ ],
+ ));
+
+ final jsonResult = await collect(Uri(), false, false, false, {'foo'},
+ serviceOverrideForTesting: service);
+ final result = await HitMap.parseJson(
+ jsonResult['coverage'] as List<Map<String, dynamic>>);
+
+ expect(result.length, 1);
+ expect(result['package:foo/foo.dart']?.lineHits, {12: 1, 47: 0});
+ });
+ });
+}
diff --git a/pkgs/coverage/test/collect_coverage_mock_test.mocks.dart b/pkgs/coverage/test/collect_coverage_mock_test.mocks.dart
new file mode 100644
index 0000000..86f596a
--- /dev/null
+++ b/pkgs/coverage/test/collect_coverage_mock_test.mocks.dart
@@ -0,0 +1,2047 @@
+// Mocks generated by Mockito 5.4.4 from annotations
+// in coverage/test/collect_coverage_mock_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i3;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:mockito/src/dummies.dart' as _i4;
+import 'package:vm_service/src/vm_service.dart' as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: deprecated_member_use
+// ignore_for_file: deprecated_member_use_from_same_package
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeBreakpoint_0 extends _i1.SmartFake implements _i2.Breakpoint {
+ _FakeBreakpoint_0(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeSuccess_1 extends _i1.SmartFake implements _i2.Success {
+ _FakeSuccess_1(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeIdZone_2 extends _i1.SmartFake implements _i2.IdZone {
+ _FakeIdZone_2(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeResponse_3 extends _i1.SmartFake implements _i2.Response {
+ _FakeResponse_3(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeAllocationProfile_4 extends _i1.SmartFake
+ implements _i2.AllocationProfile {
+ _FakeAllocationProfile_4(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeCpuSamples_5 extends _i1.SmartFake implements _i2.CpuSamples {
+ _FakeCpuSamples_5(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeClassList_6 extends _i1.SmartFake implements _i2.ClassList {
+ _FakeClassList_6(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeFlagList_7 extends _i1.SmartFake implements _i2.FlagList {
+ _FakeFlagList_7(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeInboundReferences_8 extends _i1.SmartFake
+ implements _i2.InboundReferences {
+ _FakeInboundReferences_8(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeInstanceSet_9 extends _i1.SmartFake implements _i2.InstanceSet {
+ _FakeInstanceSet_9(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeInstanceRef_10 extends _i1.SmartFake implements _i2.InstanceRef {
+ _FakeInstanceRef_10(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeIsolate_11 extends _i1.SmartFake implements _i2.Isolate {
+ _FakeIsolate_11(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeIsolateGroup_12 extends _i1.SmartFake implements _i2.IsolateGroup {
+ _FakeIsolateGroup_12(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeEvent_13 extends _i1.SmartFake implements _i2.Event {
+ _FakeEvent_13(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeMemoryUsage_14 extends _i1.SmartFake implements _i2.MemoryUsage {
+ _FakeMemoryUsage_14(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeScriptList_15 extends _i1.SmartFake implements _i2.ScriptList {
+ _FakeScriptList_15(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeObj_16 extends _i1.SmartFake implements _i2.Obj {
+ _FakeObj_16(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakePerfettoCpuSamples_17 extends _i1.SmartFake
+ implements _i2.PerfettoCpuSamples {
+ _FakePerfettoCpuSamples_17(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakePerfettoTimeline_18 extends _i1.SmartFake
+ implements _i2.PerfettoTimeline {
+ _FakePerfettoTimeline_18(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakePortList_19 extends _i1.SmartFake implements _i2.PortList {
+ _FakePortList_19(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeRetainingPath_20 extends _i1.SmartFake implements _i2.RetainingPath {
+ _FakeRetainingPath_20(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeProcessMemoryUsage_21 extends _i1.SmartFake
+ implements _i2.ProcessMemoryUsage {
+ _FakeProcessMemoryUsage_21(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeStack_22 extends _i1.SmartFake implements _i2.Stack {
+ _FakeStack_22(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeProtocolList_23 extends _i1.SmartFake implements _i2.ProtocolList {
+ _FakeProtocolList_23(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeSourceReport_24 extends _i1.SmartFake implements _i2.SourceReport {
+ _FakeSourceReport_24(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeVersion_25 extends _i1.SmartFake implements _i2.Version {
+ _FakeVersion_25(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeVM_26 extends _i1.SmartFake implements _i2.VM {
+ _FakeVM_26(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeTimeline_27 extends _i1.SmartFake implements _i2.Timeline {
+ _FakeTimeline_27(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeTimelineFlags_28 extends _i1.SmartFake implements _i2.TimelineFlags {
+ _FakeTimelineFlags_28(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeTimestamp_29 extends _i1.SmartFake implements _i2.Timestamp {
+ _FakeTimestamp_29(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeUriList_30 extends _i1.SmartFake implements _i2.UriList {
+ _FakeUriList_30(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeReloadReport_31 extends _i1.SmartFake implements _i2.ReloadReport {
+ _FakeReloadReport_31(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeFuture_32<T1> extends _i1.SmartFake implements _i3.Future<T1> {
+ _FakeFuture_32(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+/// A class which mocks [VmService].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockVmService extends _i1.Mock implements _i2.VmService {
+ MockVmService() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i3.Stream<String> get onSend => (super.noSuchMethod(
+ Invocation.getter(#onSend),
+ returnValue: _i3.Stream<String>.empty(),
+ ) as _i3.Stream<String>);
+
+ @override
+ _i3.Stream<String> get onReceive => (super.noSuchMethod(
+ Invocation.getter(#onReceive),
+ returnValue: _i3.Stream<String>.empty(),
+ ) as _i3.Stream<String>);
+
+ @override
+ _i3.Future<void> get onDone => (super.noSuchMethod(
+ Invocation.getter(#onDone),
+ returnValue: _i3.Future<void>.value(),
+ ) as _i3.Future<void>);
+
+ @override
+ _i3.Stream<_i2.Event> get onVMEvent => (super.noSuchMethod(
+ Invocation.getter(#onVMEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onIsolateEvent => (super.noSuchMethod(
+ Invocation.getter(#onIsolateEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onDebugEvent => (super.noSuchMethod(
+ Invocation.getter(#onDebugEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onProfilerEvent => (super.noSuchMethod(
+ Invocation.getter(#onProfilerEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onGCEvent => (super.noSuchMethod(
+ Invocation.getter(#onGCEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onExtensionEvent => (super.noSuchMethod(
+ Invocation.getter(#onExtensionEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onTimelineEvent => (super.noSuchMethod(
+ Invocation.getter(#onTimelineEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onLoggingEvent => (super.noSuchMethod(
+ Invocation.getter(#onLoggingEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onServiceEvent => (super.noSuchMethod(
+ Invocation.getter(#onServiceEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onHeapSnapshotEvent => (super.noSuchMethod(
+ Invocation.getter(#onHeapSnapshotEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onStdoutEvent => (super.noSuchMethod(
+ Invocation.getter(#onStdoutEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> get onStderrEvent => (super.noSuchMethod(
+ Invocation.getter(#onStderrEvent),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Stream<_i2.Event> onEvent(String? streamId) => (super.noSuchMethod(
+ Invocation.method(
+ #onEvent,
+ [streamId],
+ ),
+ returnValue: _i3.Stream<_i2.Event>.empty(),
+ ) as _i3.Stream<_i2.Event>);
+
+ @override
+ _i3.Future<_i2.Breakpoint> addBreakpoint(
+ String? isolateId,
+ String? scriptId,
+ int? line, {
+ int? column,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #addBreakpoint,
+ [
+ isolateId,
+ scriptId,
+ line,
+ ],
+ {#column: column},
+ ),
+ returnValue: _i3.Future<_i2.Breakpoint>.value(_FakeBreakpoint_0(
+ this,
+ Invocation.method(
+ #addBreakpoint,
+ [
+ isolateId,
+ scriptId,
+ line,
+ ],
+ {#column: column},
+ ),
+ )),
+ ) as _i3.Future<_i2.Breakpoint>);
+
+ @override
+ _i3.Future<_i2.Breakpoint> addBreakpointWithScriptUri(
+ String? isolateId,
+ String? scriptUri,
+ int? line, {
+ int? column,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #addBreakpointWithScriptUri,
+ [
+ isolateId,
+ scriptUri,
+ line,
+ ],
+ {#column: column},
+ ),
+ returnValue: _i3.Future<_i2.Breakpoint>.value(_FakeBreakpoint_0(
+ this,
+ Invocation.method(
+ #addBreakpointWithScriptUri,
+ [
+ isolateId,
+ scriptUri,
+ line,
+ ],
+ {#column: column},
+ ),
+ )),
+ ) as _i3.Future<_i2.Breakpoint>);
+
+ @override
+ _i3.Future<_i2.Breakpoint> addBreakpointAtEntry(
+ String? isolateId,
+ String? functionId,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #addBreakpointAtEntry,
+ [
+ isolateId,
+ functionId,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Breakpoint>.value(_FakeBreakpoint_0(
+ this,
+ Invocation.method(
+ #addBreakpointAtEntry,
+ [
+ isolateId,
+ functionId,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Breakpoint>);
+
+ @override
+ _i3.Future<_i2.Success> clearCpuSamples(String? isolateId) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #clearCpuSamples,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #clearCpuSamples,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> clearVMTimeline() => (super.noSuchMethod(
+ Invocation.method(
+ #clearVMTimeline,
+ [],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #clearVMTimeline,
+ [],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.IdZone> createIdZone(
+ String? isolateId,
+ String? backingBufferKind,
+ String? idAssignmentPolicy, {
+ int? capacity,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #createIdZone,
+ [
+ isolateId,
+ backingBufferKind,
+ idAssignmentPolicy,
+ ],
+ {#capacity: capacity},
+ ),
+ returnValue: _i3.Future<_i2.IdZone>.value(_FakeIdZone_2(
+ this,
+ Invocation.method(
+ #createIdZone,
+ [
+ isolateId,
+ backingBufferKind,
+ idAssignmentPolicy,
+ ],
+ {#capacity: capacity},
+ ),
+ )),
+ ) as _i3.Future<_i2.IdZone>);
+
+ @override
+ _i3.Future<_i2.Success> deleteIdZone(
+ String? isolateId,
+ String? idZoneId,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #deleteIdZone,
+ [
+ isolateId,
+ idZoneId,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #deleteIdZone,
+ [
+ isolateId,
+ idZoneId,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> invalidateIdZone(
+ String? isolateId,
+ String? idZoneId,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #invalidateIdZone,
+ [
+ isolateId,
+ idZoneId,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #invalidateIdZone,
+ [
+ isolateId,
+ idZoneId,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Response> invoke(
+ String? isolateId,
+ String? targetId,
+ String? selector,
+ List<String>? argumentIds, {
+ bool? disableBreakpoints,
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #invoke,
+ [
+ isolateId,
+ targetId,
+ selector,
+ argumentIds,
+ ],
+ {
+ #disableBreakpoints: disableBreakpoints,
+ #idZoneId: idZoneId,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_3(
+ this,
+ Invocation.method(
+ #invoke,
+ [
+ isolateId,
+ targetId,
+ selector,
+ argumentIds,
+ ],
+ {
+ #disableBreakpoints: disableBreakpoints,
+ #idZoneId: idZoneId,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Response>);
+
+ @override
+ _i3.Future<_i2.Response> evaluate(
+ String? isolateId,
+ String? targetId,
+ String? expression, {
+ Map<String, String>? scope,
+ bool? disableBreakpoints,
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #evaluate,
+ [
+ isolateId,
+ targetId,
+ expression,
+ ],
+ {
+ #scope: scope,
+ #disableBreakpoints: disableBreakpoints,
+ #idZoneId: idZoneId,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_3(
+ this,
+ Invocation.method(
+ #evaluate,
+ [
+ isolateId,
+ targetId,
+ expression,
+ ],
+ {
+ #scope: scope,
+ #disableBreakpoints: disableBreakpoints,
+ #idZoneId: idZoneId,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Response>);
+
+ @override
+ _i3.Future<_i2.Response> evaluateInFrame(
+ String? isolateId,
+ int? frameIndex,
+ String? expression, {
+ Map<String, String>? scope,
+ bool? disableBreakpoints,
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #evaluateInFrame,
+ [
+ isolateId,
+ frameIndex,
+ expression,
+ ],
+ {
+ #scope: scope,
+ #disableBreakpoints: disableBreakpoints,
+ #idZoneId: idZoneId,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_3(
+ this,
+ Invocation.method(
+ #evaluateInFrame,
+ [
+ isolateId,
+ frameIndex,
+ expression,
+ ],
+ {
+ #scope: scope,
+ #disableBreakpoints: disableBreakpoints,
+ #idZoneId: idZoneId,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Response>);
+
+ @override
+ _i3.Future<_i2.AllocationProfile> getAllocationProfile(
+ String? isolateId, {
+ bool? reset,
+ bool? gc,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getAllocationProfile,
+ [isolateId],
+ {
+ #reset: reset,
+ #gc: gc,
+ },
+ ),
+ returnValue:
+ _i3.Future<_i2.AllocationProfile>.value(_FakeAllocationProfile_4(
+ this,
+ Invocation.method(
+ #getAllocationProfile,
+ [isolateId],
+ {
+ #reset: reset,
+ #gc: gc,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.AllocationProfile>);
+
+ @override
+ _i3.Future<_i2.CpuSamples> getAllocationTraces(
+ String? isolateId, {
+ int? timeOriginMicros,
+ int? timeExtentMicros,
+ String? classId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getAllocationTraces,
+ [isolateId],
+ {
+ #timeOriginMicros: timeOriginMicros,
+ #timeExtentMicros: timeExtentMicros,
+ #classId: classId,
+ },
+ ),
+ returnValue: _i3.Future<_i2.CpuSamples>.value(_FakeCpuSamples_5(
+ this,
+ Invocation.method(
+ #getAllocationTraces,
+ [isolateId],
+ {
+ #timeOriginMicros: timeOriginMicros,
+ #timeExtentMicros: timeExtentMicros,
+ #classId: classId,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.CpuSamples>);
+
+ @override
+ _i3.Future<_i2.ClassList> getClassList(String? isolateId) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getClassList,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.ClassList>.value(_FakeClassList_6(
+ this,
+ Invocation.method(
+ #getClassList,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.ClassList>);
+
+ @override
+ _i3.Future<_i2.CpuSamples> getCpuSamples(
+ String? isolateId,
+ int? timeOriginMicros,
+ int? timeExtentMicros,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getCpuSamples,
+ [
+ isolateId,
+ timeOriginMicros,
+ timeExtentMicros,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.CpuSamples>.value(_FakeCpuSamples_5(
+ this,
+ Invocation.method(
+ #getCpuSamples,
+ [
+ isolateId,
+ timeOriginMicros,
+ timeExtentMicros,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.CpuSamples>);
+
+ @override
+ _i3.Future<_i2.FlagList> getFlagList() => (super.noSuchMethod(
+ Invocation.method(
+ #getFlagList,
+ [],
+ ),
+ returnValue: _i3.Future<_i2.FlagList>.value(_FakeFlagList_7(
+ this,
+ Invocation.method(
+ #getFlagList,
+ [],
+ ),
+ )),
+ ) as _i3.Future<_i2.FlagList>);
+
+ @override
+ _i3.Future<_i2.InboundReferences> getInboundReferences(
+ String? isolateId,
+ String? targetId,
+ int? limit, {
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getInboundReferences,
+ [
+ isolateId,
+ targetId,
+ limit,
+ ],
+ {#idZoneId: idZoneId},
+ ),
+ returnValue:
+ _i3.Future<_i2.InboundReferences>.value(_FakeInboundReferences_8(
+ this,
+ Invocation.method(
+ #getInboundReferences,
+ [
+ isolateId,
+ targetId,
+ limit,
+ ],
+ {#idZoneId: idZoneId},
+ ),
+ )),
+ ) as _i3.Future<_i2.InboundReferences>);
+
+ @override
+ _i3.Future<_i2.InstanceSet> getInstances(
+ String? isolateId,
+ String? objectId,
+ int? limit, {
+ bool? includeSubclasses,
+ bool? includeImplementers,
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getInstances,
+ [
+ isolateId,
+ objectId,
+ limit,
+ ],
+ {
+ #includeSubclasses: includeSubclasses,
+ #includeImplementers: includeImplementers,
+ #idZoneId: idZoneId,
+ },
+ ),
+ returnValue: _i3.Future<_i2.InstanceSet>.value(_FakeInstanceSet_9(
+ this,
+ Invocation.method(
+ #getInstances,
+ [
+ isolateId,
+ objectId,
+ limit,
+ ],
+ {
+ #includeSubclasses: includeSubclasses,
+ #includeImplementers: includeImplementers,
+ #idZoneId: idZoneId,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.InstanceSet>);
+
+ @override
+ _i3.Future<_i2.InstanceRef> getInstancesAsList(
+ String? isolateId,
+ String? objectId, {
+ bool? includeSubclasses,
+ bool? includeImplementers,
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getInstancesAsList,
+ [
+ isolateId,
+ objectId,
+ ],
+ {
+ #includeSubclasses: includeSubclasses,
+ #includeImplementers: includeImplementers,
+ #idZoneId: idZoneId,
+ },
+ ),
+ returnValue: _i3.Future<_i2.InstanceRef>.value(_FakeInstanceRef_10(
+ this,
+ Invocation.method(
+ #getInstancesAsList,
+ [
+ isolateId,
+ objectId,
+ ],
+ {
+ #includeSubclasses: includeSubclasses,
+ #includeImplementers: includeImplementers,
+ #idZoneId: idZoneId,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.InstanceRef>);
+
+ @override
+ _i3.Future<_i2.Isolate> getIsolate(String? isolateId) => (super.noSuchMethod(
+ Invocation.method(
+ #getIsolate,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.Isolate>.value(_FakeIsolate_11(
+ this,
+ Invocation.method(
+ #getIsolate,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.Isolate>);
+
+ @override
+ _i3.Future<_i2.IsolateGroup> getIsolateGroup(String? isolateGroupId) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getIsolateGroup,
+ [isolateGroupId],
+ ),
+ returnValue: _i3.Future<_i2.IsolateGroup>.value(_FakeIsolateGroup_12(
+ this,
+ Invocation.method(
+ #getIsolateGroup,
+ [isolateGroupId],
+ ),
+ )),
+ ) as _i3.Future<_i2.IsolateGroup>);
+
+ @override
+ _i3.Future<_i2.Event> getIsolatePauseEvent(String? isolateId) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getIsolatePauseEvent,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.Event>.value(_FakeEvent_13(
+ this,
+ Invocation.method(
+ #getIsolatePauseEvent,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.Event>);
+
+ @override
+ _i3.Future<_i2.MemoryUsage> getMemoryUsage(String? isolateId) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getMemoryUsage,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.MemoryUsage>.value(_FakeMemoryUsage_14(
+ this,
+ Invocation.method(
+ #getMemoryUsage,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.MemoryUsage>);
+
+ @override
+ _i3.Future<_i2.MemoryUsage> getIsolateGroupMemoryUsage(
+ String? isolateGroupId) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getIsolateGroupMemoryUsage,
+ [isolateGroupId],
+ ),
+ returnValue: _i3.Future<_i2.MemoryUsage>.value(_FakeMemoryUsage_14(
+ this,
+ Invocation.method(
+ #getIsolateGroupMemoryUsage,
+ [isolateGroupId],
+ ),
+ )),
+ ) as _i3.Future<_i2.MemoryUsage>);
+
+ @override
+ _i3.Future<_i2.ScriptList> getScripts(String? isolateId) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getScripts,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.ScriptList>.value(_FakeScriptList_15(
+ this,
+ Invocation.method(
+ #getScripts,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.ScriptList>);
+
+ @override
+ _i3.Future<_i2.Obj> getObject(
+ String? isolateId,
+ String? objectId, {
+ int? offset,
+ int? count,
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getObject,
+ [
+ isolateId,
+ objectId,
+ ],
+ {
+ #offset: offset,
+ #count: count,
+ #idZoneId: idZoneId,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Obj>.value(_FakeObj_16(
+ this,
+ Invocation.method(
+ #getObject,
+ [
+ isolateId,
+ objectId,
+ ],
+ {
+ #offset: offset,
+ #count: count,
+ #idZoneId: idZoneId,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Obj>);
+
+ @override
+ _i3.Future<_i2.PerfettoCpuSamples> getPerfettoCpuSamples(
+ String? isolateId, {
+ int? timeOriginMicros,
+ int? timeExtentMicros,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getPerfettoCpuSamples,
+ [isolateId],
+ {
+ #timeOriginMicros: timeOriginMicros,
+ #timeExtentMicros: timeExtentMicros,
+ },
+ ),
+ returnValue:
+ _i3.Future<_i2.PerfettoCpuSamples>.value(_FakePerfettoCpuSamples_17(
+ this,
+ Invocation.method(
+ #getPerfettoCpuSamples,
+ [isolateId],
+ {
+ #timeOriginMicros: timeOriginMicros,
+ #timeExtentMicros: timeExtentMicros,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.PerfettoCpuSamples>);
+
+ @override
+ _i3.Future<_i2.PerfettoTimeline> getPerfettoVMTimeline({
+ int? timeOriginMicros,
+ int? timeExtentMicros,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getPerfettoVMTimeline,
+ [],
+ {
+ #timeOriginMicros: timeOriginMicros,
+ #timeExtentMicros: timeExtentMicros,
+ },
+ ),
+ returnValue:
+ _i3.Future<_i2.PerfettoTimeline>.value(_FakePerfettoTimeline_18(
+ this,
+ Invocation.method(
+ #getPerfettoVMTimeline,
+ [],
+ {
+ #timeOriginMicros: timeOriginMicros,
+ #timeExtentMicros: timeExtentMicros,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.PerfettoTimeline>);
+
+ @override
+ _i3.Future<_i2.PortList> getPorts(String? isolateId) => (super.noSuchMethod(
+ Invocation.method(
+ #getPorts,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.PortList>.value(_FakePortList_19(
+ this,
+ Invocation.method(
+ #getPorts,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.PortList>);
+
+ @override
+ _i3.Future<_i2.RetainingPath> getRetainingPath(
+ String? isolateId,
+ String? targetId,
+ int? limit, {
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getRetainingPath,
+ [
+ isolateId,
+ targetId,
+ limit,
+ ],
+ {#idZoneId: idZoneId},
+ ),
+ returnValue: _i3.Future<_i2.RetainingPath>.value(_FakeRetainingPath_20(
+ this,
+ Invocation.method(
+ #getRetainingPath,
+ [
+ isolateId,
+ targetId,
+ limit,
+ ],
+ {#idZoneId: idZoneId},
+ ),
+ )),
+ ) as _i3.Future<_i2.RetainingPath>);
+
+ @override
+ _i3.Future<_i2.ProcessMemoryUsage> getProcessMemoryUsage() =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getProcessMemoryUsage,
+ [],
+ ),
+ returnValue:
+ _i3.Future<_i2.ProcessMemoryUsage>.value(_FakeProcessMemoryUsage_21(
+ this,
+ Invocation.method(
+ #getProcessMemoryUsage,
+ [],
+ ),
+ )),
+ ) as _i3.Future<_i2.ProcessMemoryUsage>);
+
+ @override
+ _i3.Future<_i2.Stack> getStack(
+ String? isolateId, {
+ int? limit,
+ String? idZoneId,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getStack,
+ [isolateId],
+ {
+ #limit: limit,
+ #idZoneId: idZoneId,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Stack>.value(_FakeStack_22(
+ this,
+ Invocation.method(
+ #getStack,
+ [isolateId],
+ {
+ #limit: limit,
+ #idZoneId: idZoneId,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Stack>);
+
+ @override
+ _i3.Future<_i2.ProtocolList> getSupportedProtocols() => (super.noSuchMethod(
+ Invocation.method(
+ #getSupportedProtocols,
+ [],
+ ),
+ returnValue: _i3.Future<_i2.ProtocolList>.value(_FakeProtocolList_23(
+ this,
+ Invocation.method(
+ #getSupportedProtocols,
+ [],
+ ),
+ )),
+ ) as _i3.Future<_i2.ProtocolList>);
+
+ @override
+ _i3.Future<_i2.SourceReport> getSourceReport(
+ String? isolateId,
+ List<String>? reports, {
+ String? scriptId,
+ int? tokenPos,
+ int? endTokenPos,
+ bool? forceCompile,
+ bool? reportLines,
+ List<String>? libraryFilters,
+ List<String>? librariesAlreadyCompiled,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getSourceReport,
+ [
+ isolateId,
+ reports,
+ ],
+ {
+ #scriptId: scriptId,
+ #tokenPos: tokenPos,
+ #endTokenPos: endTokenPos,
+ #forceCompile: forceCompile,
+ #reportLines: reportLines,
+ #libraryFilters: libraryFilters,
+ #librariesAlreadyCompiled: librariesAlreadyCompiled,
+ },
+ ),
+ returnValue: _i3.Future<_i2.SourceReport>.value(_FakeSourceReport_24(
+ this,
+ Invocation.method(
+ #getSourceReport,
+ [
+ isolateId,
+ reports,
+ ],
+ {
+ #scriptId: scriptId,
+ #tokenPos: tokenPos,
+ #endTokenPos: endTokenPos,
+ #forceCompile: forceCompile,
+ #reportLines: reportLines,
+ #libraryFilters: libraryFilters,
+ #librariesAlreadyCompiled: librariesAlreadyCompiled,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.SourceReport>);
+
+ @override
+ _i3.Future<_i2.Version> getVersion() => (super.noSuchMethod(
+ Invocation.method(
+ #getVersion,
+ [],
+ ),
+ returnValue: _i3.Future<_i2.Version>.value(_FakeVersion_25(
+ this,
+ Invocation.method(
+ #getVersion,
+ [],
+ ),
+ )),
+ ) as _i3.Future<_i2.Version>);
+
+ @override
+ _i3.Future<_i2.VM> getVM() => (super.noSuchMethod(
+ Invocation.method(
+ #getVM,
+ [],
+ ),
+ returnValue: _i3.Future<_i2.VM>.value(_FakeVM_26(
+ this,
+ Invocation.method(
+ #getVM,
+ [],
+ ),
+ )),
+ ) as _i3.Future<_i2.VM>);
+
+ @override
+ _i3.Future<_i2.Timeline> getVMTimeline({
+ int? timeOriginMicros,
+ int? timeExtentMicros,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getVMTimeline,
+ [],
+ {
+ #timeOriginMicros: timeOriginMicros,
+ #timeExtentMicros: timeExtentMicros,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Timeline>.value(_FakeTimeline_27(
+ this,
+ Invocation.method(
+ #getVMTimeline,
+ [],
+ {
+ #timeOriginMicros: timeOriginMicros,
+ #timeExtentMicros: timeExtentMicros,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Timeline>);
+
+ @override
+ _i3.Future<_i2.TimelineFlags> getVMTimelineFlags() => (super.noSuchMethod(
+ Invocation.method(
+ #getVMTimelineFlags,
+ [],
+ ),
+ returnValue: _i3.Future<_i2.TimelineFlags>.value(_FakeTimelineFlags_28(
+ this,
+ Invocation.method(
+ #getVMTimelineFlags,
+ [],
+ ),
+ )),
+ ) as _i3.Future<_i2.TimelineFlags>);
+
+ @override
+ _i3.Future<_i2.Timestamp> getVMTimelineMicros() => (super.noSuchMethod(
+ Invocation.method(
+ #getVMTimelineMicros,
+ [],
+ ),
+ returnValue: _i3.Future<_i2.Timestamp>.value(_FakeTimestamp_29(
+ this,
+ Invocation.method(
+ #getVMTimelineMicros,
+ [],
+ ),
+ )),
+ ) as _i3.Future<_i2.Timestamp>);
+
+ @override
+ _i3.Future<_i2.Success> pause(String? isolateId) => (super.noSuchMethod(
+ Invocation.method(
+ #pause,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #pause,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> kill(String? isolateId) => (super.noSuchMethod(
+ Invocation.method(
+ #kill,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #kill,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.UriList> lookupResolvedPackageUris(
+ String? isolateId,
+ List<String>? uris, {
+ bool? local,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #lookupResolvedPackageUris,
+ [
+ isolateId,
+ uris,
+ ],
+ {#local: local},
+ ),
+ returnValue: _i3.Future<_i2.UriList>.value(_FakeUriList_30(
+ this,
+ Invocation.method(
+ #lookupResolvedPackageUris,
+ [
+ isolateId,
+ uris,
+ ],
+ {#local: local},
+ ),
+ )),
+ ) as _i3.Future<_i2.UriList>);
+
+ @override
+ _i3.Future<_i2.UriList> lookupPackageUris(
+ String? isolateId,
+ List<String>? uris,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #lookupPackageUris,
+ [
+ isolateId,
+ uris,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.UriList>.value(_FakeUriList_30(
+ this,
+ Invocation.method(
+ #lookupPackageUris,
+ [
+ isolateId,
+ uris,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.UriList>);
+
+ @override
+ _i3.Future<_i2.Success> registerService(
+ String? service,
+ String? alias,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #registerService,
+ [
+ service,
+ alias,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #registerService,
+ [
+ service,
+ alias,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.ReloadReport> reloadSources(
+ String? isolateId, {
+ bool? force,
+ bool? pause,
+ String? rootLibUri,
+ String? packagesUri,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #reloadSources,
+ [isolateId],
+ {
+ #force: force,
+ #pause: pause,
+ #rootLibUri: rootLibUri,
+ #packagesUri: packagesUri,
+ },
+ ),
+ returnValue: _i3.Future<_i2.ReloadReport>.value(_FakeReloadReport_31(
+ this,
+ Invocation.method(
+ #reloadSources,
+ [isolateId],
+ {
+ #force: force,
+ #pause: pause,
+ #rootLibUri: rootLibUri,
+ #packagesUri: packagesUri,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.ReloadReport>);
+
+ @override
+ _i3.Future<_i2.Success> removeBreakpoint(
+ String? isolateId,
+ String? breakpointId,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #removeBreakpoint,
+ [
+ isolateId,
+ breakpointId,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #removeBreakpoint,
+ [
+ isolateId,
+ breakpointId,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> requestHeapSnapshot(String? isolateId) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #requestHeapSnapshot,
+ [isolateId],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #requestHeapSnapshot,
+ [isolateId],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> resume(
+ String? isolateId, {
+ String? step,
+ int? frameIndex,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #resume,
+ [isolateId],
+ {
+ #step: step,
+ #frameIndex: frameIndex,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #resume,
+ [isolateId],
+ {
+ #step: step,
+ #frameIndex: frameIndex,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Breakpoint> setBreakpointState(
+ String? isolateId,
+ String? breakpointId,
+ bool? enable,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setBreakpointState,
+ [
+ isolateId,
+ breakpointId,
+ enable,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Breakpoint>.value(_FakeBreakpoint_0(
+ this,
+ Invocation.method(
+ #setBreakpointState,
+ [
+ isolateId,
+ breakpointId,
+ enable,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Breakpoint>);
+
+ @override
+ _i3.Future<_i2.Success> setExceptionPauseMode(
+ String? isolateId,
+ String? mode,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setExceptionPauseMode,
+ [
+ isolateId,
+ mode,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #setExceptionPauseMode,
+ [
+ isolateId,
+ mode,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> setIsolatePauseMode(
+ String? isolateId, {
+ String? exceptionPauseMode,
+ bool? shouldPauseOnExit,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setIsolatePauseMode,
+ [isolateId],
+ {
+ #exceptionPauseMode: exceptionPauseMode,
+ #shouldPauseOnExit: shouldPauseOnExit,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #setIsolatePauseMode,
+ [isolateId],
+ {
+ #exceptionPauseMode: exceptionPauseMode,
+ #shouldPauseOnExit: shouldPauseOnExit,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Response> setFlag(
+ String? name,
+ String? value,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setFlag,
+ [
+ name,
+ value,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_3(
+ this,
+ Invocation.method(
+ #setFlag,
+ [
+ name,
+ value,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Response>);
+
+ @override
+ _i3.Future<_i2.Success> setLibraryDebuggable(
+ String? isolateId,
+ String? libraryId,
+ bool? isDebuggable,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setLibraryDebuggable,
+ [
+ isolateId,
+ libraryId,
+ isDebuggable,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #setLibraryDebuggable,
+ [
+ isolateId,
+ libraryId,
+ isDebuggable,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> setName(
+ String? isolateId,
+ String? name,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setName,
+ [
+ isolateId,
+ name,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #setName,
+ [
+ isolateId,
+ name,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> setTraceClassAllocation(
+ String? isolateId,
+ String? classId,
+ bool? enable,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setTraceClassAllocation,
+ [
+ isolateId,
+ classId,
+ enable,
+ ],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #setTraceClassAllocation,
+ [
+ isolateId,
+ classId,
+ enable,
+ ],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> setVMName(String? name) => (super.noSuchMethod(
+ Invocation.method(
+ #setVMName,
+ [name],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #setVMName,
+ [name],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> setVMTimelineFlags(List<String>? recordedStreams) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setVMTimelineFlags,
+ [recordedStreams],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #setVMTimelineFlags,
+ [recordedStreams],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> streamCancel(String? streamId) => (super.noSuchMethod(
+ Invocation.method(
+ #streamCancel,
+ [streamId],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #streamCancel,
+ [streamId],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> streamCpuSamplesWithUserTag(List<String>? userTags) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #streamCpuSamplesWithUserTag,
+ [userTags],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #streamCpuSamplesWithUserTag,
+ [userTags],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Success> streamListen(String? streamId) => (super.noSuchMethod(
+ Invocation.method(
+ #streamListen,
+ [streamId],
+ ),
+ returnValue: _i3.Future<_i2.Success>.value(_FakeSuccess_1(
+ this,
+ Invocation.method(
+ #streamListen,
+ [streamId],
+ ),
+ )),
+ ) as _i3.Future<_i2.Success>);
+
+ @override
+ _i3.Future<_i2.Response> callMethod(
+ String? method, {
+ String? isolateId,
+ Map<String, dynamic>? args,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #callMethod,
+ [method],
+ {
+ #isolateId: isolateId,
+ #args: args,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_3(
+ this,
+ Invocation.method(
+ #callMethod,
+ [method],
+ {
+ #isolateId: isolateId,
+ #args: args,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Response>);
+
+ @override
+ _i3.Future<_i2.Response> callServiceExtension(
+ String? method, {
+ String? isolateId,
+ Map<String, dynamic>? args,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #callServiceExtension,
+ [method],
+ {
+ #isolateId: isolateId,
+ #args: args,
+ },
+ ),
+ returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_3(
+ this,
+ Invocation.method(
+ #callServiceExtension,
+ [method],
+ {
+ #isolateId: isolateId,
+ #args: args,
+ },
+ ),
+ )),
+ ) as _i3.Future<_i2.Response>);
+
+ @override
+ _i3.Future<void> dispose() => (super.noSuchMethod(
+ Invocation.method(
+ #dispose,
+ [],
+ ),
+ returnValue: _i3.Future<void>.value(),
+ returnValueForMissingStub: _i3.Future<void>.value(),
+ ) as _i3.Future<void>);
+
+ @override
+ _i3.Future<T> wrapFuture<T>(
+ String? name,
+ _i3.Future<T>? future,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #wrapFuture,
+ [
+ name,
+ future,
+ ],
+ ),
+ returnValue: _i4.ifNotNull(
+ _i4.dummyValueOrNull<T>(
+ this,
+ Invocation.method(
+ #wrapFuture,
+ [
+ name,
+ future,
+ ],
+ ),
+ ),
+ (T v) => _i3.Future<T>.value(v),
+ ) ??
+ _FakeFuture_32<T>(
+ this,
+ Invocation.method(
+ #wrapFuture,
+ [
+ name,
+ future,
+ ],
+ ),
+ ),
+ ) as _i3.Future<T>);
+
+ @override
+ void registerServiceCallback(
+ String? service,
+ _i2.ServiceCallback? cb,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #registerServiceCallback,
+ [
+ service,
+ cb,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+}
diff --git a/pkgs/coverage/test/collect_coverage_test.dart b/pkgs/coverage/test/collect_coverage_test.dart
new file mode 100644
index 0000000..7262757
--- /dev/null
+++ b/pkgs/coverage/test/collect_coverage_test.dart
@@ -0,0 +1,325 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Retry(3)
+library;
+
+import 'dart:async';
+import 'dart:convert' show json;
+import 'dart:io';
+
+import 'package:coverage/coverage.dart';
+import 'package:coverage/src/util.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test_process/test_process.dart';
+
+import 'test_util.dart';
+
+final _isolateLibPath = p.join('test', 'test_files', 'test_app_isolate.dart');
+final _collectAppPath = p.join('bin', 'collect_coverage.dart');
+
+final _sampleAppFileUri = p.toUri(p.absolute(testAppPath)).toString();
+final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();
+
+void main() {
+ test('collect_coverage', () async {
+ final resultString = await _getCoverageResult();
+
+ // analyze the output json
+ final coverage =
+ coverageDataFromJson(json.decode(resultString) as Map<String, dynamic>);
+
+ expect(coverage, isNotEmpty);
+
+ final sources = coverage.sources();
+
+ for (var sampleCoverageData in sources[_sampleAppFileUri]!) {
+ expect(sampleCoverageData['hits'], isNotNull);
+ }
+
+ for (var sampleCoverageData in sources[_isolateLibFileUri]!) {
+ expect(sampleCoverageData['hits'], isNotEmpty);
+ }
+ });
+
+ test('createHitmap returns a sorted hitmap', () async {
+ final coverage = [
+ {
+ 'source': 'foo',
+ 'script': '{type: @Script, fixedId: true, '
+ 'id: bar.dart, uri: bar.dart, _kind: library}',
+ 'hits': [
+ 45,
+ 1,
+ 46,
+ 1,
+ 49,
+ 0,
+ 50,
+ 0,
+ 15,
+ 1,
+ 16,
+ 2,
+ 17,
+ 2,
+ ]
+ }
+ ];
+ // ignore: deprecated_member_use_from_same_package
+ final hitMap = await createHitmap(
+ coverage.cast<Map<String, dynamic>>(),
+ );
+ final expectedHits = {15: 1, 16: 2, 17: 2, 45: 1, 46: 1, 49: 0, 50: 0};
+ expect(hitMap['foo'], expectedHits);
+ });
+
+ test('HitMap.parseJson returns a sorted hitmap', () async {
+ final coverage = [
+ {
+ 'source': 'foo',
+ 'script': '{type: @Script, fixedId: true, '
+ 'id: bar.dart, uri: bar.dart, _kind: library}',
+ 'hits': [
+ 45,
+ 1,
+ 46,
+ 1,
+ 49,
+ 0,
+ 50,
+ 0,
+ 15,
+ 1,
+ 16,
+ 2,
+ 17,
+ 2,
+ ]
+ }
+ ];
+ final hitMap = await HitMap.parseJson(
+ coverage.cast<Map<String, dynamic>>(),
+ );
+ final expectedHits = {15: 1, 16: 2, 17: 2, 45: 1, 46: 1, 49: 0, 50: 0};
+ expect(hitMap['foo']?.lineHits, expectedHits);
+ });
+
+ test('HitMap.parseJson', () async {
+ final resultString = await _collectCoverage(true, true);
+ final jsonResult = json.decode(resultString) as Map<String, dynamic>;
+ final coverage = jsonResult['coverage'] as List;
+ final hitMap = await HitMap.parseJson(
+ coverage.cast<Map<String, dynamic>>(),
+ );
+ expect(hitMap, contains(_sampleAppFileUri));
+
+ final isolateFile = hitMap[_isolateLibFileUri];
+ final expectedHits = {
+ 11: 1,
+ 12: 1,
+ 13: 1,
+ 15: 0,
+ 19: 1,
+ 23: 1,
+ 24: 2,
+ 28: 1,
+ 29: 1,
+ 30: 1,
+ 32: 0,
+ 38: 1,
+ 39: 1,
+ 41: 1,
+ 42: 4,
+ 43: 1,
+ 44: 3,
+ 45: 1,
+ 48: 1,
+ 49: 1,
+ 51: 1,
+ 54: 1,
+ 55: 1,
+ 56: 1,
+ 59: 1,
+ 60: 1,
+ 62: 1,
+ 63: 1,
+ 64: 1,
+ 66: 1,
+ 67: 1,
+ 68: 1,
+ 71: 3,
+ };
+ expect(isolateFile?.lineHits, expectedHits);
+ expect(isolateFile?.funcHits, {11: 1, 19: 1, 23: 1, 28: 1, 38: 1});
+ expect(isolateFile?.funcNames, {
+ 11: 'fooSync',
+ 19: 'BarClass.BarClass',
+ 23: 'BarClass.baz',
+ 28: 'fooAsync',
+ 38: 'isolateTask'
+ });
+ expect(
+ isolateFile?.branchHits,
+ {
+ 11: 1,
+ 12: 1,
+ 15: 0,
+ 19: 1,
+ 23: 1,
+ 28: 1,
+ 29: 1,
+ 32: 0,
+ 38: 1,
+ 42: 1,
+ 71: 1,
+ },
+ );
+ });
+
+ test('parseCoverage', () async {
+ final tempDir = await Directory.systemTemp.createTemp('coverage.test.');
+
+ try {
+ final outputFile = File(p.join(tempDir.path, 'coverage.json'));
+
+ final coverageResults = await _getCoverageResult();
+ await outputFile.writeAsString(coverageResults, flush: true);
+
+ // ignore: deprecated_member_use_from_same_package
+ final parsedResult = await parseCoverage([outputFile], 1);
+
+ expect(parsedResult, contains(_sampleAppFileUri));
+ expect(parsedResult, contains(_isolateLibFileUri));
+ } finally {
+ await tempDir.delete(recursive: true);
+ }
+ });
+
+ test('HitMap.parseFiles', () async {
+ final tempDir = await Directory.systemTemp.createTemp('coverage.test.');
+
+ try {
+ final outputFile = File(p.join(tempDir.path, 'coverage.json'));
+
+ final coverageResults = await _getCoverageResult();
+ await outputFile.writeAsString(coverageResults, flush: true);
+
+ final parsedResult = await HitMap.parseFiles([outputFile]);
+
+ expect(parsedResult, contains(_sampleAppFileUri));
+ expect(parsedResult, contains(_isolateLibFileUri));
+ } finally {
+ await tempDir.delete(recursive: true);
+ }
+ });
+
+ test('HitMap.parseFiles with packagesPath and checkIgnoredLines', () async {
+ final tempDir = await Directory.systemTemp.createTemp('coverage.test.');
+
+ try {
+ final outputFile = File(p.join(tempDir.path, 'coverage.json'));
+
+ final coverageResults = await _getCoverageResult();
+ await outputFile.writeAsString(coverageResults, flush: true);
+
+ final parsedResult = await HitMap.parseFiles([outputFile],
+ packagePath: '.', checkIgnoredLines: true);
+
+ // This file has ignore:coverage-file.
+ expect(parsedResult, isNot(contains(_sampleAppFileUri)));
+ expect(parsedResult, contains(_isolateLibFileUri));
+ } finally {
+ await tempDir.delete(recursive: true);
+ }
+ });
+
+ test('mergeHitmaps', () {
+ final resultMap = <String, Map<int, int>>{
+ 'foo.dart': {10: 2, 20: 0},
+ 'bar.dart': {10: 3, 20: 1, 30: 0},
+ };
+ final newMap = <String, Map<int, int>>{
+ 'bar.dart': {10: 2, 20: 0, 40: 3},
+ 'baz.dart': {10: 1, 20: 0, 30: 1},
+ };
+ // ignore: deprecated_member_use_from_same_package
+ mergeHitmaps(newMap, resultMap);
+ expect(resultMap, <String, Map<int, int>>{
+ 'foo.dart': {10: 2, 20: 0},
+ 'bar.dart': {10: 5, 20: 1, 30: 0, 40: 3},
+ 'baz.dart': {10: 1, 20: 0, 30: 1},
+ });
+ });
+
+ test('FileHitMaps.merge', () {
+ final resultMap = <String, HitMap>{
+ 'foo.dart':
+ HitMap({10: 2, 20: 0}, {15: 0, 25: 1}, {15: 'bobble', 25: 'cobble'}),
+ 'bar.dart': HitMap(
+ {10: 3, 20: 1, 30: 0}, {15: 5, 25: 0}, {15: 'gobble', 25: 'wobble'}),
+ };
+ final newMap = <String, HitMap>{
+ 'bar.dart': HitMap(
+ {10: 2, 20: 0, 40: 3}, {15: 1, 35: 4}, {15: 'gobble', 35: 'dobble'}),
+ 'baz.dart': HitMap(
+ {10: 1, 20: 0, 30: 1}, {15: 0, 25: 2}, {15: 'lobble', 25: 'zobble'}),
+ };
+ resultMap.merge(newMap);
+ expect(resultMap['foo.dart']?.lineHits, <int, int>{10: 2, 20: 0});
+ expect(resultMap['foo.dart']?.funcHits, <int, int>{15: 0, 25: 1});
+ expect(resultMap['foo.dart']?.funcNames,
+ <int, String>{15: 'bobble', 25: 'cobble'});
+ expect(resultMap['bar.dart']?.lineHits,
+ <int, int>{10: 5, 20: 1, 30: 0, 40: 3});
+ expect(resultMap['bar.dart']?.funcHits, <int, int>{15: 6, 25: 0, 35: 4});
+ expect(resultMap['bar.dart']?.funcNames,
+ <int, String>{15: 'gobble', 25: 'wobble', 35: 'dobble'});
+ expect(resultMap['baz.dart']?.lineHits, <int, int>{10: 1, 20: 0, 30: 1});
+ expect(resultMap['baz.dart']?.funcHits, <int, int>{15: 0, 25: 2});
+ expect(resultMap['baz.dart']?.funcNames,
+ <int, String>{15: 'lobble', 25: 'zobble'});
+ });
+}
+
+String? _coverageData;
+
+Future<String> _getCoverageResult() async =>
+ _coverageData ??= await _collectCoverage(false, false);
+
+Future<String> _collectCoverage(
+ bool functionCoverage, bool branchCoverage) async {
+ expect(FileSystemEntity.isFileSync(testAppPath), isTrue);
+
+ final openPort = await getOpenPort();
+
+ // Run the sample app with the right flags.
+ final sampleProcess = await runTestApp(openPort);
+
+ // Capture the VM service URI.
+ final serviceUri = await serviceUriFromProcess(sampleProcess.stdoutStream());
+
+ // Run the collection tool.
+ // TODO: need to get all of this functionality in the lib
+ final toolResult = await TestProcess.start(Platform.resolvedExecutable, [
+ _collectAppPath,
+ if (functionCoverage) '--function-coverage',
+ if (branchCoverage) '--branch-coverage',
+ '--uri',
+ '$serviceUri',
+ '--resume-isolates',
+ '--wait-paused'
+ ]);
+
+ await toolResult.shouldExit(0).timeout(
+ timeout,
+ onTimeout: () =>
+ throw StateError('We timed out waiting for the tool to finish.'),
+ );
+
+ await sampleProcess.shouldExit();
+
+ return toolResult.stdoutStream().join('\n');
+}
diff --git a/pkgs/coverage/test/format_coverage_test.dart b/pkgs/coverage/test/format_coverage_test.dart
new file mode 100644
index 0000000..85493f7
--- /dev/null
+++ b/pkgs/coverage/test/format_coverage_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+
+import '../bin/format_coverage.dart';
+
+void main() {
+ late Directory testDir;
+ setUp(() {
+ testDir = Directory.systemTemp.createTempSync('coverage_test_temp');
+ });
+
+ tearDown(() async {
+ if (testDir.existsSync()) testDir.deleteSync(recursive: true);
+ });
+
+ test('considers all json files', () async {
+ final fileA = File(p.join(testDir.path, 'coverage_a.json'));
+ fileA.createSync();
+ final fileB = File(p.join(testDir.path, 'coverage_b.json'));
+ fileB.createSync();
+ final fileC = File(p.join(testDir.path, 'not_coverage.foo'));
+ fileC.createSync();
+
+ final files = filesToProcess(testDir.path);
+ expect(files.length, equals(2));
+ expect(
+ files.map((f) => f.path),
+ containsAll(
+ [endsWith('coverage_a.json'), endsWith('coverage_b.json')]));
+ });
+}
diff --git a/pkgs/coverage/test/function_coverage_test.dart b/pkgs/coverage/test/function_coverage_test.dart
new file mode 100644
index 0000000..965d0d0
--- /dev/null
+++ b/pkgs/coverage/test/function_coverage_test.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert' show json;
+import 'dart:io';
+
+import 'package:coverage/coverage.dart';
+import 'package:coverage/src/util.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test_process/test_process.dart';
+
+import 'test_util.dart';
+
+final _collectAppPath = p.join('bin', 'collect_coverage.dart');
+final _funcCovApp = p.join('test', 'test_files', 'function_coverage_app.dart');
+final _sampleAppFileUri = p.toUri(p.absolute(_funcCovApp)).toString();
+
+void main() {
+ test('Function coverage', () async {
+ final resultString = await _collectCoverage();
+ final jsonResult = json.decode(resultString) as Map<String, dynamic>;
+ final coverage = jsonResult['coverage'] as List;
+ final hitMap = await HitMap.parseJson(
+ coverage.cast<Map<String, dynamic>>(),
+ );
+
+ // function_coverage_app.dart.
+ expect(hitMap, contains(_sampleAppFileUri));
+ final isolateFile = hitMap[_sampleAppFileUri]!;
+ expect(isolateFile.funcHits, {
+ 7: 1,
+ 16: 1,
+ 21: 1,
+ 25: 1,
+ 29: 1,
+ 36: 1,
+ 42: 1,
+ 47: 1,
+ });
+ expect(isolateFile.funcNames, {
+ 7: 'normalFunction',
+ 16: 'SomeClass.SomeClass',
+ 21: 'SomeClass.normalMethod',
+ 25: 'SomeClass.staticMethod',
+ 29: 'SomeClass.abstractMethod',
+ 36: 'SomeExtension.extensionMethod',
+ 42: 'OtherClass.otherMethod',
+ 47: 'main',
+ });
+
+ // test_library.dart.
+ final testLibraryPath =
+ p.absolute(p.join('test', 'test_files', 'test_library.dart'));
+ final testLibraryUri = p.toUri(testLibraryPath).toString();
+ expect(hitMap, contains(testLibraryUri));
+ final libraryfile = hitMap[testLibraryUri]!;
+ expect(libraryfile.funcHits, {7: 1});
+ expect(libraryfile.funcNames, {7: 'libraryFunction'});
+
+ // test_library_part.dart.
+ final testLibraryPartPath =
+ p.absolute(p.join('test', 'test_files', 'test_library_part.dart'));
+ final testLibraryPartUri = p.toUri(testLibraryPartPath).toString();
+ expect(hitMap, contains(testLibraryPartUri));
+ final libraryPartFile = hitMap[testLibraryPartUri]!;
+ expect(libraryPartFile.funcHits, {7: 1});
+ expect(libraryPartFile.funcNames, {7: 'otherLibraryFunction'});
+ });
+}
+
+Future<String> _collectCoverage() async {
+ expect(FileSystemEntity.isFileSync(_funcCovApp), isTrue);
+
+ final openPort = await getOpenPort();
+
+ // Run the sample app with the right flags.
+ final sampleProcess = await TestProcess.start(Platform.resolvedExecutable, [
+ '--enable-vm-service=$openPort',
+ '--pause_isolates_on_exit',
+ _funcCovApp
+ ]);
+
+ final serviceUri = await serviceUriFromProcess(sampleProcess.stdoutStream());
+
+ // Run the collection tool.
+ final toolResult = await TestProcess.start(Platform.resolvedExecutable, [
+ _collectAppPath,
+ '--function-coverage',
+ '--uri',
+ '$serviceUri',
+ '--resume-isolates',
+ '--wait-paused'
+ ]);
+
+ await toolResult.shouldExit(0).timeout(
+ timeout,
+ onTimeout: () =>
+ throw StateError('We timed out waiting for the tool to finish.'),
+ );
+
+ await sampleProcess.shouldExit();
+
+ return toolResult.stdoutStream().join('\n');
+}
diff --git a/pkgs/coverage/test/isolate_paused_listener_test.dart b/pkgs/coverage/test/isolate_paused_listener_test.dart
new file mode 100644
index 0000000..b6016ce
--- /dev/null
+++ b/pkgs/coverage/test/isolate_paused_listener_test.dart
@@ -0,0 +1,815 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:coverage/src/isolate_paused_listener.dart';
+import 'package:mockito/mockito.dart';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'collect_coverage_mock_test.mocks.dart';
+
+Event event(
+ String id, {
+ String? kind,
+ String? groupId,
+ String? name,
+}) =>
+ Event(
+ kind: kind,
+ isolate: IsolateRef(
+ isolateGroupId: groupId,
+ id: id,
+ name: name,
+ ));
+
+Isolate isolate(
+ String id, {
+ String? groupId,
+ String? name,
+ String? pauseKind,
+}) =>
+ Isolate(
+ isolateGroupId: groupId,
+ id: id,
+ name: name,
+ pauseEvent: pauseKind == null ? null : Event(kind: pauseKind),
+ );
+
+(MockVmService, StreamController<Event>) createServiceAndEventStreams() {
+ final service = MockVmService();
+ when(service.streamListen(any)).thenAnswer((_) async => Success());
+
+ // The VM service events we care about come in on 2 different streams,
+ // onIsolateEvent and onDebugEvent. We want to write tests that send sequences
+ // of events like [I1, D1, I2, D2, I3, D3], but since I and D go to separate
+ // streams, the listener may see them arrive like [I1, I2, I3, D1, D2, D3] or
+ // [D1, D2, D3, I1, I2, I3] or any other interleaving. So instead we send all
+ // the events through a single stream that gets split up. This emulates how
+ // the events work in reality, since they all come from a single web socket.
+ final allEvents = StreamController<Event>();
+ final isolateEvents = StreamController<Event>();
+ final debugEvents = StreamController<Event>();
+ allEvents.stream.listen((Event e) {
+ if (e.kind == EventKind.kIsolateStart ||
+ e.kind == EventKind.kIsolateStart) {
+ isolateEvents.add(e);
+ } else {
+ debugEvents.add(e);
+ }
+ });
+ when(service.onIsolateEvent).thenAnswer((_) => isolateEvents.stream);
+ when(service.onDebugEvent).thenAnswer((_) => debugEvents.stream);
+
+ return (service, allEvents);
+}
+
+void main() {
+ group('IsolateEventBuffer', () {
+ test('buffers events', () async {
+ final received = <String>[];
+ final eventBuffer = IsolateEventBuffer((Event event) async {
+ await Future<void>.delayed(Duration.zero);
+ received.add(event.isolate!.id!);
+ });
+
+ await eventBuffer.add(event('a'));
+ await eventBuffer.add(event('b'));
+ await eventBuffer.add(event('c'));
+ expect(received, <String>[]);
+
+ await eventBuffer.flush();
+ expect(received, ['a', 'b', 'c']);
+
+ await eventBuffer.flush();
+ expect(received, ['a', 'b', 'c']);
+
+ await eventBuffer.add(event('d'));
+ await eventBuffer.add(event('e'));
+ await eventBuffer.add(event('f'));
+ expect(received, ['a', 'b', 'c', 'd', 'e', 'f']);
+
+ await eventBuffer.flush();
+ expect(received, ['a', 'b', 'c', 'd', 'e', 'f']);
+ });
+
+ test('buffers events during flush', () async {
+ final received = <String>[];
+ final pause = Completer<void>();
+ final eventBuffer = IsolateEventBuffer((Event event) async {
+ await pause.future;
+ received.add(event.isolate!.id!);
+ });
+
+ await eventBuffer.add(event('a'));
+ await eventBuffer.add(event('b'));
+ await eventBuffer.add(event('c'));
+ expect(received, <String>[]);
+
+ final flushing = eventBuffer.flush();
+ expect(received, <String>[]);
+
+ await eventBuffer.add(event('d'));
+ await eventBuffer.add(event('e'));
+ await eventBuffer.add(event('f'));
+ expect(received, <String>[]);
+
+ pause.complete();
+ await flushing;
+ expect(received, ['a', 'b', 'c', 'd', 'e', 'f']);
+ });
+ });
+
+ test('IsolateEventBuffer', () {
+ final group = IsolateGroupState();
+ expect(group.running, isEmpty);
+ expect(group.paused, isEmpty);
+ expect(group.noRunningIsolates, isTrue);
+ expect(group.noLiveIsolates, isTrue);
+
+ group.start('a');
+ expect(group.running, unorderedEquals(['a']));
+ expect(group.paused, isEmpty);
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.start('a');
+ expect(group.running, unorderedEquals(['a']));
+ expect(group.paused, isEmpty);
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.start('b');
+ expect(group.running, unorderedEquals(['a', 'b']));
+ expect(group.paused, isEmpty);
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.pause('a');
+ expect(group.running, unorderedEquals(['b']));
+ expect(group.paused, unorderedEquals(['a']));
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.pause('a');
+ expect(group.running, unorderedEquals(['b']));
+ expect(group.paused, unorderedEquals(['a']));
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.pause('c');
+ expect(group.running, unorderedEquals(['b']));
+ expect(group.paused, unorderedEquals(['a', 'c']));
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.start('c');
+ expect(group.running, unorderedEquals(['b', 'c']));
+ expect(group.paused, unorderedEquals(['a']));
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.pause('c');
+ expect(group.running, unorderedEquals(['b']));
+ expect(group.paused, unorderedEquals(['a', 'c']));
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.exit('a');
+ expect(group.running, unorderedEquals(['b']));
+ expect(group.paused, unorderedEquals(['c']));
+ expect(group.noRunningIsolates, isFalse);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.pause('b');
+ expect(group.running, isEmpty);
+ expect(group.paused, unorderedEquals(['b', 'c']));
+ expect(group.noRunningIsolates, isTrue);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.exit('b');
+ expect(group.running, isEmpty);
+ expect(group.paused, unorderedEquals(['c']));
+ expect(group.noRunningIsolates, isTrue);
+ expect(group.noLiveIsolates, isFalse);
+
+ group.exit('c');
+ expect(group.running, isEmpty);
+ expect(group.paused, isEmpty);
+ expect(group.noRunningIsolates, isTrue);
+ expect(group.noLiveIsolates, isTrue);
+ });
+
+ group('listenToIsolateLifecycleEvents', () {
+ late MockVmService service;
+ late StreamController<Event> allEvents;
+ late Completer<List<Isolate>> isolates;
+ late Future<void> backfilled;
+ late Future<void> testEnded;
+
+ late List<String> received;
+ Future<void>? delayTheOnPauseCallback;
+
+ void startEvent(String id) =>
+ allEvents.add(event(id, kind: EventKind.kIsolateStart));
+ void exitEvent(String id) =>
+ allEvents.add(event(id, kind: EventKind.kIsolateExit));
+ void pauseEvent(String id) =>
+ allEvents.add(event(id, kind: EventKind.kPauseExit));
+ void otherEvent(String id, String kind) =>
+ allEvents.add(event(id, kind: kind));
+
+ Future<void> backfill(List<Isolate> isos) async {
+ isolates.complete(isos);
+ await backfilled;
+ }
+
+ // We end the test by sending an exit event with a specific ID.
+ const endTestEventId = 'END';
+ Future<void> endTest() {
+ exitEvent(endTestEventId);
+ return testEnded;
+ }
+
+ setUp(() {
+ (service, allEvents) = createServiceAndEventStreams();
+
+ isolates = Completer<List<Isolate>>();
+ when(service.getVM())
+ .thenAnswer((_) async => VM(isolates: await isolates.future));
+ when(service.getIsolate(any)).thenAnswer((invocation) async {
+ final id = invocation.positionalArguments[0];
+ return (await isolates.future).firstWhere((iso) => iso.id == id);
+ });
+
+ received = <String>[];
+ delayTheOnPauseCallback = null;
+ final testEnder = Completer<void>();
+ testEnded = testEnder.future;
+ backfilled = listenToIsolateLifecycleEvents(
+ service,
+ (iso) {
+ if (iso.id == endTestEventId) return;
+ received.add('Start ${iso.id}');
+ },
+ (iso) async {
+ received.add('Pause ${iso.id}');
+ if (delayTheOnPauseCallback != null) {
+ await delayTheOnPauseCallback;
+ received.add('Pause done ${iso.id}');
+ }
+ },
+ (iso) {
+ if (iso.id == endTestEventId) {
+ testEnder.complete();
+ } else {
+ received.add('Exit ${iso.id}');
+ }
+ },
+ );
+ });
+
+ test('ordinary flows', () async {
+ // Events sent before backfill.
+ startEvent('A');
+ startEvent('C');
+ startEvent('B');
+ pauseEvent('C');
+ pauseEvent('A');
+ startEvent('D');
+ pauseEvent('D');
+ exitEvent('A');
+
+ // Run backfill.
+ await backfill([
+ isolate('B'),
+ isolate('C', pauseKind: EventKind.kPauseExit),
+ isolate('D'),
+ isolate('E'),
+ isolate('F', pauseKind: EventKind.kPauseExit),
+ ]);
+
+ // All the backfill events happen before any of the real events.
+ expect(received, [
+ // Backfill events.
+ 'Start B',
+ 'Start C',
+ 'Pause C',
+ 'Start D',
+ 'Start E',
+ 'Start F',
+ 'Pause F',
+
+ // Real events from before backfill.
+ 'Start A',
+ 'Pause A',
+ 'Pause D',
+ 'Exit A',
+ ]);
+
+ // Events sent after backfill.
+ received.clear();
+ startEvent('G');
+ exitEvent('C');
+ exitEvent('B');
+ exitEvent('G');
+ exitEvent('D');
+ exitEvent('E');
+ exitEvent('F');
+
+ await endTest();
+ expect(received, [
+ 'Start G',
+ 'Exit C',
+ 'Exit B',
+ 'Exit G',
+ 'Exit D',
+ 'Exit E',
+ 'Exit F',
+ ]);
+
+ verify(service.streamListen(EventStreams.kIsolate)).called(1);
+ verify(service.streamListen(EventStreams.kDebug)).called(1);
+ });
+
+ test('pause and exit events without start', () async {
+ await backfill([]);
+
+ pauseEvent('A');
+ exitEvent('B');
+
+ await endTest();
+ expect(received, [
+ 'Start A',
+ 'Pause A',
+ 'Start B',
+ 'Exit B',
+ ]);
+ });
+
+ test('pause event after exit is ignored', () async {
+ await backfill([]);
+
+ exitEvent('A');
+ pauseEvent('A');
+
+ await endTest();
+ expect(received, [
+ 'Start A',
+ 'Exit A',
+ ]);
+ });
+
+ test('event deduping', () async {
+ startEvent('A');
+ startEvent('A');
+ pauseEvent('A');
+ pauseEvent('A');
+ exitEvent('A');
+ exitEvent('A');
+
+ pauseEvent('B');
+ startEvent('B');
+
+ exitEvent('C');
+ startEvent('C');
+
+ await backfill([]);
+ await endTest();
+ expect(received, [
+ 'Start A',
+ 'Pause A',
+ 'Exit A',
+ 'Start B',
+ 'Pause B',
+ 'Start C',
+ 'Exit C',
+ ]);
+ });
+
+ test('ignore other events', () async {
+ await backfill([]);
+
+ startEvent('A');
+ pauseEvent('A');
+ otherEvent('A', EventKind.kResume);
+ exitEvent('A');
+
+ startEvent('B');
+ otherEvent('B', EventKind.kPauseBreakpoint);
+ exitEvent('B');
+
+ otherEvent('C', EventKind.kInspect);
+
+ await endTest();
+ expect(received, [
+ 'Start A',
+ 'Pause A',
+ 'Exit A',
+ 'Start B',
+ 'Exit B',
+ ]);
+ });
+
+ test('exit event during pause callback', () async {
+ final delayingTheOnPauseCallback = Completer<void>();
+ delayTheOnPauseCallback = delayingTheOnPauseCallback.future;
+ await backfill([]);
+
+ startEvent('A');
+ pauseEvent('A');
+ exitEvent('A');
+
+ while (received.length < 2) {
+ await Future<void>.delayed(Duration.zero);
+ }
+
+ expect(received, [
+ 'Start A',
+ 'Pause A',
+ ]);
+
+ delayingTheOnPauseCallback.complete();
+ await endTest();
+ expect(received, [
+ 'Start A',
+ 'Pause A',
+ 'Pause done A',
+ 'Exit A',
+ ]);
+ });
+
+ test('exit event during pause callback, event deduping', () async {
+ final delayingTheOnPauseCallback = Completer<void>();
+ delayTheOnPauseCallback = delayingTheOnPauseCallback.future;
+ await backfill([]);
+
+ startEvent('A');
+ pauseEvent('A');
+ exitEvent('A');
+ pauseEvent('A');
+ pauseEvent('A');
+ exitEvent('A');
+ exitEvent('A');
+
+ while (received.length < 2) {
+ await Future<void>.delayed(Duration.zero);
+ }
+
+ expect(received, [
+ 'Start A',
+ 'Pause A',
+ ]);
+
+ delayingTheOnPauseCallback.complete();
+ await endTest();
+ expect(received, [
+ 'Start A',
+ 'Pause A',
+ 'Pause done A',
+ 'Exit A',
+ ]);
+ });
+ });
+
+ group('IsolatePausedListener', () {
+ late MockVmService service;
+ late StreamController<Event> allEvents;
+ late Future<void> allIsolatesExited;
+
+ late List<String> received;
+ late bool stopped;
+
+ void startEvent(String id, String groupId, [String? name]) =>
+ allEvents.add(event(
+ id,
+ kind: EventKind.kIsolateStart,
+ groupId: groupId,
+ name: name ?? id,
+ ));
+ void exitEvent(String id, String groupId, [String? name]) =>
+ allEvents.add(event(
+ id,
+ kind: EventKind.kIsolateExit,
+ groupId: groupId,
+ name: name ?? id,
+ ));
+ void pauseEvent(String id, String groupId, [String? name]) =>
+ allEvents.add(event(
+ id,
+ kind: EventKind.kPauseExit,
+ groupId: groupId,
+ name: name ?? id,
+ ));
+
+ Future<void> endTest() async {
+ await allIsolatesExited;
+ stopped = true;
+ }
+
+ setUp(() {
+ (service, allEvents) = createServiceAndEventStreams();
+
+ // Backfill was tested above, so this test does everything using events,
+ // for simplicity. No need to report any isolates.
+ when(service.getVM()).thenAnswer((_) async => VM());
+
+ received = <String>[];
+ when(service.resume(any)).thenAnswer((invocation) async {
+ final id = invocation.positionalArguments[0];
+ received.add('Resume $id');
+ return Success();
+ });
+
+ stopped = false;
+ allIsolatesExited = IsolatePausedListener(
+ service,
+ (iso, isLastIsolateInGroup) async {
+ expect(stopped, isFalse);
+ received.add('Pause ${iso.id}. Last in group ${iso.isolateGroupId}? '
+ '${isLastIsolateInGroup ? 'Yes' : 'No'}');
+ },
+ (message) => received.add(message),
+ ).waitUntilAllExited();
+ });
+
+ test('ordinary flows', () async {
+ startEvent('A', '1');
+ startEvent('B', '1');
+ pauseEvent('A', '1');
+ startEvent('C', '1');
+ pauseEvent('B', '1');
+ exitEvent('A', '1');
+ startEvent('D', '2');
+ startEvent('E', '2');
+ startEvent('F', '2');
+ pauseEvent('C', '1');
+ pauseEvent('F', '2');
+ pauseEvent('E', '2');
+ exitEvent('C', '1');
+ exitEvent('E', '2');
+ startEvent('G', '3');
+ exitEvent('F', '2');
+ startEvent('H', '3');
+ startEvent('I', '3');
+ pauseEvent('I', '3');
+ exitEvent('I', '3');
+ pauseEvent('H', '3');
+ exitEvent('H', '3');
+ pauseEvent('D', '2');
+ pauseEvent('G', '3');
+ exitEvent('D', '2');
+ exitEvent('G', '3');
+ exitEvent('B', '1');
+
+ await endTest();
+
+ // Events sent after waitUntilAllExited is finished do nothing.
+ startEvent('Z', '9');
+ pauseEvent('Z', '9');
+ exitEvent('Z', '9');
+
+ expect(received, [
+ 'Pause A. Last in group 1? No',
+ 'Resume A',
+ 'Pause B. Last in group 1? No',
+ 'Resume B',
+ 'Pause C. Last in group 1? Yes',
+ 'Resume C',
+ 'Pause F. Last in group 2? No',
+ 'Resume F',
+ 'Pause E. Last in group 2? No',
+ 'Resume E',
+ 'Pause I. Last in group 3? No',
+ 'Resume I',
+ 'Pause H. Last in group 3? No',
+ 'Resume H',
+ 'Pause D. Last in group 2? Yes',
+ 'Resume D',
+ 'Pause G. Last in group 3? Yes',
+ 'Resume G',
+ ]);
+ });
+
+ test('exit without pausing', () async {
+ // If an isolate exits without pausing, this may mess up coverage
+ // collection (if it happens to be the last isolate in the group, that
+ // group won't be collected). The best we can do is log an error, and make
+ // sure not to wait forever for pause events that aren't coming.
+ startEvent('A', '1');
+ startEvent('B', '1');
+ exitEvent('A', '1');
+ pauseEvent('B', '1');
+ startEvent('C', '2');
+ startEvent('D', '2');
+ pauseEvent('D', '2');
+ exitEvent('D', '2');
+ exitEvent('C', '2');
+ exitEvent('B', '1');
+
+ await endTest();
+
+ // B was paused correctly and was the last to exit isolate 1, so isolate 1
+ // was collected ok.
+ expect(received, [
+ 'Pause B. Last in group 1? Yes',
+ 'Resume B',
+ 'Pause D. Last in group 2? No',
+ 'Resume D',
+ 'ERROR: An isolate exited without pausing, causing coverage data to '
+ 'be lost for group 2.',
+ ]);
+ });
+
+ test('main isolate resumed last', () async {
+ startEvent('A', '1', 'main');
+ startEvent('B', '1', 'main'); // Second isolate named main, ignored.
+ pauseEvent('B', '1', 'main');
+ startEvent('C', '2', 'main'); // Third isolate named main, ignored.
+ pauseEvent('A', '1', 'main');
+ startEvent('D', '2');
+ pauseEvent('C', '2');
+ exitEvent('C', '2');
+ pauseEvent('D', '2');
+ exitEvent('D', '2');
+ exitEvent('B', '1');
+
+ await endTest();
+
+ expect(received, [
+ 'Pause B. Last in group 1? No',
+ 'Resume B',
+ 'Pause C. Last in group 2? No',
+ 'Resume C',
+ 'Pause D. Last in group 2? Yes',
+ 'Resume D',
+ 'Pause A. Last in group 1? Yes',
+ 'Resume A',
+ ]);
+ });
+
+ test('main isolate exits without pausing', () async {
+ startEvent('A', '1', 'main');
+ startEvent('B', '1');
+ pauseEvent('B', '1');
+ exitEvent('A', '1', 'main');
+ exitEvent('B', '1');
+
+ await endTest();
+
+ expect(received, [
+ 'Pause B. Last in group 1? No',
+ 'Resume B',
+ 'ERROR: An isolate exited without pausing, causing coverage data to '
+ 'be lost for group 1.',
+ ]);
+ });
+
+ test('main isolate is the only isolate', () async {
+ startEvent('A', '1', 'main');
+ pauseEvent('A', '1', 'main');
+
+ await endTest();
+
+ expect(received, [
+ 'Pause A. Last in group 1? Yes',
+ 'Resume A',
+ ]);
+ });
+
+ test('all other isolates exit before main isolate pauses', () async {
+ startEvent('A', '1', 'main');
+ startEvent('B', '1');
+ pauseEvent('B', '1');
+ exitEvent('B', '1');
+
+ await Future<void>.delayed(Duration.zero);
+
+ pauseEvent('A', '1', 'main');
+ exitEvent('A', '1', 'main');
+
+ await endTest();
+
+ expect(received, [
+ 'Pause B. Last in group 1? No',
+ 'Resume B',
+ 'Pause A. Last in group 1? Yes',
+ 'Resume A',
+ ]);
+ });
+
+ test(
+ 'all other isolates exit before main isolate pauses, then main '
+ 'starts another isolate, then pauses before they exit', () async {
+ startEvent('A', '1', 'main');
+ startEvent('B', '1');
+ pauseEvent('B', '1');
+ exitEvent('B', '1');
+
+ await Future<void>.delayed(Duration.zero);
+
+ startEvent('C', '1');
+ pauseEvent('C', '1');
+ pauseEvent('A', '1', 'main');
+ exitEvent('C', '1');
+
+ await Future<void>.delayed(Duration.zero);
+
+ exitEvent('A', '1', 'main');
+
+ await endTest();
+
+ expect(received, [
+ 'Pause B. Last in group 1? No',
+ 'Resume B',
+ 'Pause C. Last in group 1? No',
+ 'Resume C',
+ 'Pause A. Last in group 1? Yes',
+ 'Resume A',
+ ]);
+ });
+
+ test(
+ 'all other isolates exit before main isolate pauses, then main '
+ 'starts another isolate, then pauses before they pause', () async {
+ startEvent('A', '1', 'main');
+ startEvent('B', '1');
+ pauseEvent('B', '1');
+ exitEvent('B', '1');
+
+ await Future<void>.delayed(Duration.zero);
+
+ startEvent('C', '1');
+ pauseEvent('A', '1', 'main');
+ pauseEvent('C', '1');
+ exitEvent('C', '1');
+
+ await Future<void>.delayed(Duration.zero);
+
+ exitEvent('A', '1', 'main');
+
+ await endTest();
+
+ expect(received, [
+ 'Pause B. Last in group 1? No',
+ 'Resume B',
+ 'Pause C. Last in group 1? Yes',
+ 'Resume C',
+ 'Pause A. Last in group 1? No',
+ 'Resume A',
+ ]);
+ });
+
+ test('group reopened', () async {
+ // If an isolate is reported in a group after the group as believed to be
+ // closed, reopen the group. This double counts some coverage, but at
+ // least won't miss any.
+
+ startEvent('Z', '9'); // Separate isolate to keep the system alive until
+ pauseEvent('Z', '9'); // the test is complete.
+
+ startEvent('A', '1');
+ startEvent('B', '1');
+ pauseEvent('A', '1');
+ pauseEvent('B', '1');
+ exitEvent('B', '1');
+ exitEvent('A', '1');
+
+ startEvent('D', '2');
+ startEvent('E', '2');
+ pauseEvent('E', '2');
+ pauseEvent('D', '2');
+ exitEvent('E', '2');
+ exitEvent('D', '2');
+
+ startEvent('C', '1');
+ pauseEvent('F', '2');
+ pauseEvent('C', '1');
+ exitEvent('C', '1');
+ exitEvent('F', '2');
+
+ exitEvent('Z', '9');
+
+ await endTest();
+
+ expect(received, [
+ 'Pause Z. Last in group 9? Yes',
+ 'Resume Z',
+ 'Pause A. Last in group 1? No',
+ 'Resume A',
+ 'Pause B. Last in group 1? Yes',
+ 'Resume B',
+ 'Pause E. Last in group 2? No',
+ 'Resume E',
+ 'Pause D. Last in group 2? Yes',
+ 'Resume D',
+ 'Pause F. Last in group 2? Yes',
+ 'Resume F',
+ 'Pause C. Last in group 1? Yes',
+ 'Resume C',
+ ]);
+ });
+ });
+}
diff --git a/pkgs/coverage/test/lcov_test.dart b/pkgs/coverage/test/lcov_test.dart
new file mode 100644
index 0000000..ca62117
--- /dev/null
+++ b/pkgs/coverage/test/lcov_test.dart
@@ -0,0 +1,364 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:coverage/coverage.dart';
+import 'package:coverage/src/util.dart';
+import 'package:glob/glob.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test_process/test_process.dart';
+
+final _sampleAppPath = p.join('test', 'test_files', 'test_app.dart');
+final _sampleGeneratedPath = p.join('test', 'test_files', 'test_app.g.dart');
+final _isolateLibPath = p.join('test', 'test_files', 'test_app_isolate.dart');
+
+final _sampleAppFileUri = p.toUri(p.absolute(_sampleAppPath)).toString();
+final _sampleGeneratedFileUri =
+ p.toUri(p.absolute(_sampleGeneratedPath)).toString();
+final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();
+
+void main() {
+ test('validate hitMap', () async {
+ final hitmap = await _getHitMap();
+
+ expect(hitmap, contains(_sampleAppFileUri));
+ expect(hitmap, contains(_sampleGeneratedFileUri));
+ expect(hitmap, contains(_isolateLibFileUri));
+ expect(hitmap, contains('package:coverage/src/util.dart'));
+
+ final sampleAppHitMap = hitmap[_sampleAppFileUri];
+ final sampleAppHitLines = sampleAppHitMap?.lineHits;
+ final sampleAppHitFuncs = sampleAppHitMap?.funcHits;
+ final sampleAppFuncNames = sampleAppHitMap?.funcNames;
+ final sampleAppBranchHits = sampleAppHitMap?.branchHits;
+
+ expect(sampleAppHitLines, containsPair(53, greaterThanOrEqualTo(1)),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppHitLines, containsPair(57, 0),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppHitLines, isNot(contains(39)),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppHitFuncs, containsPair(52, 1),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppHitFuncs, containsPair(56, 0),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppFuncNames, containsPair(52, 'usedMethod'),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppBranchHits, containsPair(48, 1),
+ reason: 'be careful if you modify the test file');
+ });
+
+ test('validate hitMap, old VM without branch coverage', () async {
+ final hitmap = await _getHitMap();
+
+ expect(hitmap, contains(_sampleAppFileUri));
+ expect(hitmap, contains(_sampleGeneratedFileUri));
+ expect(hitmap, contains(_isolateLibFileUri));
+ expect(hitmap, contains('package:coverage/src/util.dart'));
+
+ final sampleAppHitMap = hitmap[_sampleAppFileUri];
+ final sampleAppHitLines = sampleAppHitMap?.lineHits;
+ final sampleAppHitFuncs = sampleAppHitMap?.funcHits;
+ final sampleAppFuncNames = sampleAppHitMap?.funcNames;
+
+ expect(sampleAppHitLines, containsPair(53, greaterThanOrEqualTo(1)),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppHitLines, containsPair(57, 0),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppHitLines, isNot(contains(39)),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppHitFuncs, containsPair(52, 1),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppHitFuncs, containsPair(56, 0),
+ reason: 'be careful if you modify the test file');
+ expect(sampleAppFuncNames, containsPair(52, 'usedMethod'),
+ reason: 'be careful if you modify the test file');
+ });
+
+ group('LcovFormatter', () {
+ test('format()', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ // ignore: deprecated_member_use_from_same_package
+ final formatter = LcovFormatter(resolver);
+
+ final res = await formatter
+ .format(hitmap.map((key, value) => MapEntry(key, value.lineHits)));
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, contains(p.absolute(_sampleGeneratedPath)));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+ });
+
+ test('formatLcov()', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = hitmap.formatLcov(resolver);
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, contains(p.absolute(_sampleGeneratedPath)));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+ });
+
+ test('formatLcov() includes files in reportOn list', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = hitmap.formatLcov(resolver, reportOn: ['lib/', 'test/']);
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, contains(p.absolute(_sampleGeneratedPath)));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+ });
+
+ test('formatLcov() excludes files not in reportOn list', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = hitmap.formatLcov(resolver, reportOn: ['lib/']);
+
+ expect(res, isNot(contains(p.absolute(_sampleAppPath))));
+ expect(res, isNot(contains(p.absolute(_sampleGeneratedPath))));
+ expect(res, isNot(contains(p.absolute(_isolateLibPath))));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+ });
+
+ test('formatLcov() excludes files matching glob patterns', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = hitmap.formatLcov(
+ resolver,
+ ignoreGlobs: {Glob('**/*.g.dart'), Glob('**/util.dart')},
+ );
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, isNot(contains(p.absolute(_sampleGeneratedPath))));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(
+ res,
+ isNot(contains(p.absolute(p.join('lib', 'src', 'util.dart')))),
+ );
+ });
+
+ test(
+ 'formatLcov() excludes files matching glob patterns regardless of their'
+ 'presence on reportOn list', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = hitmap.formatLcov(
+ resolver,
+ reportOn: ['test/'],
+ ignoreGlobs: {Glob('**/*.g.dart')},
+ );
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, isNot(contains(p.absolute(_sampleGeneratedPath))));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ });
+
+ test('formatLcov() uses paths relative to basePath', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = hitmap.formatLcov(resolver, basePath: p.absolute('lib'));
+
+ expect(
+ res, isNot(contains(p.absolute(p.join('lib', 'src', 'util.dart')))));
+ expect(res, contains(p.join('src', 'util.dart')));
+ });
+ });
+
+ group('PrettyPrintFormatter', () {
+ test('format()', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ // ignore: deprecated_member_use_from_same_package
+ final formatter = PrettyPrintFormatter(resolver, Loader());
+
+ final res = await formatter
+ .format(hitmap.map((key, value) => MapEntry(key, value.lineHits)));
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, contains(p.absolute(_sampleGeneratedPath)));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+
+ // be very careful if you change the test file
+ expect(res, contains(' 0| return a - b;'));
+
+ expect(res, contains('| return withTimeout(() async {'),
+ reason: 'be careful if you change lib/src/util.dart');
+
+ final hitLineRegexp = RegExp(r'\s+(\d+)\| return a \+ b;');
+ final match = hitLineRegexp.allMatches(res).single;
+
+ final hitCount = int.parse(match[1]!);
+ expect(hitCount, greaterThanOrEqualTo(1));
+ });
+
+ test('prettyPrint()', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = await hitmap.prettyPrint(resolver, Loader());
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, contains(p.absolute(_sampleGeneratedPath)));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+
+ // be very careful if you change the test file
+ expect(res, contains(' 0| return a - b;'));
+
+ expect(res, contains('| return withTimeout(() async {'),
+ reason: 'be careful if you change lib/src/util.dart');
+
+ final hitLineRegexp = RegExp(r'\s+(\d+)\| return a \+ b;');
+ final match = hitLineRegexp.allMatches(res).single;
+
+ final hitCount = int.parse(match[1]!);
+ expect(hitCount, greaterThanOrEqualTo(1));
+ });
+
+ test('prettyPrint() includes files in reportOn list', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = await hitmap
+ .prettyPrint(resolver, Loader(), reportOn: ['lib/', 'test/']);
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, contains(p.absolute(_sampleGeneratedPath)));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+ });
+
+ test('prettyPrint() excludes files not in reportOn list', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res =
+ await hitmap.prettyPrint(resolver, Loader(), reportOn: ['lib/']);
+
+ expect(res, isNot(contains(p.absolute(_sampleAppPath))));
+ expect(res, isNot(contains(p.absolute(_sampleGeneratedPath))));
+ expect(res, isNot(contains(p.absolute(_isolateLibPath))));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+ });
+
+ test('prettyPrint() excludes files matching glob patterns', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = await hitmap.prettyPrint(
+ resolver,
+ Loader(),
+ ignoreGlobs: {Glob('**/*.g.dart'), Glob('**/util.dart')},
+ );
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, isNot(contains(p.absolute(_sampleGeneratedPath))));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(
+ res,
+ isNot(contains(p.absolute(p.join('lib', 'src', 'util.dart')))),
+ );
+ });
+
+ test(
+ 'prettyPrint() excludes files matching glob patterns regardless of'
+ 'their presence on reportOn list', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res = await hitmap.prettyPrint(
+ resolver,
+ Loader(),
+ reportOn: ['test/'],
+ ignoreGlobs: {Glob('**/*.g.dart')},
+ );
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, isNot(contains(p.absolute(_sampleGeneratedPath))));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ });
+
+ test('prettyPrint() functions', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res =
+ await hitmap.prettyPrint(resolver, Loader(), reportFuncs: true);
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, contains(p.absolute(_sampleGeneratedPath)));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+
+ // be very careful if you change the test file
+ expect(res, contains(' 1|Future<void> main() async {'));
+ expect(res, contains(' 1|int usedMethod(int a, int b) {'));
+ expect(res, contains(' 0|int unusedMethod(int a, int b) {'));
+ expect(res, contains(' | return a + b;'));
+ });
+
+ test('prettyPrint() branches', () async {
+ final hitmap = await _getHitMap();
+
+ final resolver = await Resolver.create(packagePath: '.');
+ final res =
+ await hitmap.prettyPrint(resolver, Loader(), reportBranches: true);
+
+ expect(res, contains(p.absolute(_sampleAppPath)));
+ expect(res, contains(p.absolute(_sampleGeneratedPath)));
+ expect(res, contains(p.absolute(_isolateLibPath)));
+ expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
+
+ // be very careful if you change the test file
+ expect(res, contains(' 1| if (x == answer) {'));
+ expect(res, contains(' 0| while (i < lines.length) {'));
+ expect(res, contains(' | bar.baz();'));
+ });
+ });
+}
+
+Future<Map<String, HitMap>> _getHitMap() async {
+ expect(FileSystemEntity.isFileSync(_sampleAppPath), isTrue);
+
+ // select service port.
+ final port = await getOpenPort();
+
+ // start sample app.
+ final sampleAppArgs = [
+ '--pause-isolates-on-exit',
+ '--enable-vm-service=$port',
+ '--branch-coverage',
+ _sampleAppPath
+ ];
+ final sampleProcess =
+ await TestProcess.start(Platform.resolvedExecutable, sampleAppArgs);
+
+ final serviceUri = await serviceUriFromProcess(sampleProcess.stdoutStream());
+
+ // collect hit map.
+ final coverageJson = (await collect(serviceUri, true, true, false, <String>{},
+ functionCoverage: true,
+ branchCoverage: true))['coverage'] as List<Map<String, dynamic>>;
+ final hitMap = HitMap.parseJson(coverageJson);
+
+ await sampleProcess.shouldExit(0);
+
+ return hitMap;
+}
diff --git a/pkgs/coverage/test/resolver_test.dart b/pkgs/coverage/test/resolver_test.dart
new file mode 100644
index 0000000..1161aee
--- /dev/null
+++ b/pkgs/coverage/test/resolver_test.dart
@@ -0,0 +1,211 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:coverage/src/resolver.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
+
+void main() {
+ group('Default Resolver', () {
+ setUp(() async {
+ final sandboxUriPath = p.toUri(d.sandbox).toString();
+ await d.dir('bar', [
+ d.dir('lib', [
+ d.file('bar.dart', 'final fizz = "bar";'),
+ ])
+ ]).create();
+
+ await d.dir('foo', [
+ d.dir('.dart_tool', [
+ d.file('bad_package_config.json', 'thisIsntAPackageConfigFile!'),
+ d.file('package_config.json', '''
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "foo",
+ "rootUri": "../",
+ "packageUri": "lib/"
+ },
+ {
+ "name": "bar",
+ "rootUri": "$sandboxUriPath/bar",
+ "packageUri": "lib/"
+ }
+ ]
+}
+'''),
+ ]),
+ d.dir('lib', [
+ d.file('foo.dart', 'final foo = "bar";'),
+ ]),
+ ]).create();
+
+ await d.dir('sdk', [
+ d.dir('io', [
+ d.file('io.dart', 'final io = "hello";'),
+ ]),
+ d.dir('io_patch', [
+ d.file('io.dart', 'final patch = true;'),
+ ]),
+ d.dir('io_dev', [
+ d.file('io.dart', 'final dev = true;'),
+ ]),
+ ]).create();
+ });
+
+ test('can be created from a package_config.json', () async {
+ final resolver = await Resolver.create(
+ packagesPath:
+ p.join(d.sandbox, 'foo', '.dart_tool', 'package_config.json'));
+ expect(resolver.resolve('package:foo/foo.dart'),
+ p.join(d.sandbox, 'foo', 'lib', 'foo.dart'));
+ expect(resolver.resolve('package:bar/bar.dart'),
+ p.join(d.sandbox, 'bar', 'lib', 'bar.dart'));
+ });
+
+ test('can be created from a package directory', () async {
+ final resolver =
+ await Resolver.create(packagePath: p.join(d.sandbox, 'foo'));
+ expect(resolver.resolve('package:foo/foo.dart'),
+ p.join(d.sandbox, 'foo', 'lib', 'foo.dart'));
+ });
+
+ test('errors if the packagesFile is an unknown format', () async {
+ expect(
+ () async => await Resolver.create(
+ packagesPath: p.join(
+ d.sandbox, 'foo', '.dart_tool', 'bad_package_config.json')),
+ throwsA(isA<FormatException>()));
+ });
+
+ test('resolves dart: URIs', () async {
+ final resolver = await Resolver.create(
+ packagePath: p.join(d.sandbox, 'foo'),
+ sdkRoot: p.join(d.sandbox, 'sdk'));
+ expect(resolver.resolve('dart:io'),
+ p.join(d.sandbox, 'sdk', 'io', 'io.dart'));
+ expect(resolver.resolve('dart:io-patch/io.dart'), null);
+ expect(resolver.resolve('dart:io-dev/io.dart'),
+ p.join(d.sandbox, 'sdk', 'io_dev', 'io.dart'));
+ });
+
+ test('cannot resolve SDK URIs if sdkRoot is null', () async {
+ final resolver =
+ await Resolver.create(packagePath: p.join(d.sandbox, 'foo'));
+ expect(resolver.resolve('dart:convert'), null);
+ });
+
+ test('cannot resolve package URIs if packagePath is null', () async {
+ // ignore: deprecated_member_use_from_same_package
+ final resolver = Resolver();
+ expect(resolver.resolve('package:foo/foo.dart'), null);
+ });
+
+ test('cannot resolve package URIs if packagePath is not found', () async {
+ final resolver =
+ await Resolver.create(packagePath: p.join(d.sandbox, 'foo'));
+ expect(resolver.resolve('package:baz/baz.dart'), null);
+ });
+
+ test('cannot resolve unexpected URI schemes', () async {
+ final resolver =
+ await Resolver.create(packagePath: p.join(d.sandbox, 'foo'));
+ expect(resolver.resolve('thing:foo/foo.dart'), null);
+ });
+ });
+
+ group('Bazel resolver', () {
+ const workspace = 'foo';
+ final resolver = BazelResolver(workspacePath: workspace);
+
+ test('does not resolve SDK URIs', () {
+ expect(resolver.resolve('dart:convert'), null);
+ });
+
+ test('resolves third-party package URIs', () {
+ expect(resolver.resolve('package:foo/bar.dart'),
+ 'third_party/dart/foo/lib/bar.dart');
+ expect(resolver.resolve('package:foo/src/bar.dart'),
+ 'third_party/dart/foo/lib/src/bar.dart');
+ });
+
+ test('resolves non-third-party package URIs', () {
+ expect(
+ resolver.resolve('package:foo.bar/baz.dart'), 'foo/bar/lib/baz.dart');
+ expect(resolver.resolve('package:foo.bar/src/baz.dart'),
+ 'foo/bar/lib/src/baz.dart');
+ });
+
+ test('resolves file URIs', () {
+ expect(
+ resolver
+ .resolve('file://x/y/z.runfiles/$workspace/foo/bar/lib/baz.dart'),
+ 'foo/bar/lib/baz.dart');
+ expect(
+ resolver.resolve(
+ 'file://x/y/z.runfiles/$workspace/foo/bar/lib/src/baz.dart'),
+ 'foo/bar/lib/src/baz.dart');
+ });
+
+ test('resolves HTTPS URIs containing /packages/', () {
+ expect(resolver.resolve('https://host:8080/a/b/packages/foo/bar.dart'),
+ 'third_party/dart/foo/lib/bar.dart');
+ expect(
+ resolver.resolve('https://host:8080/a/b/packages/foo/src/bar.dart'),
+ 'third_party/dart/foo/lib/src/bar.dart');
+ expect(
+ resolver.resolve('https://host:8080/a/b/packages/foo.bar/baz.dart'),
+ 'foo/bar/lib/baz.dart');
+ expect(
+ resolver
+ .resolve('https://host:8080/a/b/packages/foo.bar/src/baz.dart'),
+ 'foo/bar/lib/src/baz.dart');
+ });
+
+ test('resolves HTTP URIs containing /packages/', () {
+ expect(resolver.resolve('http://host:8080/a/b/packages/foo/bar.dart'),
+ 'third_party/dart/foo/lib/bar.dart');
+ expect(resolver.resolve('http://host:8080/a/b/packages/foo/src/bar.dart'),
+ 'third_party/dart/foo/lib/src/bar.dart');
+ expect(resolver.resolve('http://host:8080/a/b/packages/foo.bar/baz.dart'),
+ 'foo/bar/lib/baz.dart');
+ expect(
+ resolver
+ .resolve('http://host:8080/a/b/packages/foo.bar/src/baz.dart'),
+ 'foo/bar/lib/src/baz.dart');
+ });
+
+ test('resolves HTTPS URIs without /packages/', () {
+ expect(
+ resolver
+ .resolve('https://host:8080/third_party/dart/foo/lib/bar.dart'),
+ 'third_party/dart/foo/lib/bar.dart');
+ expect(
+ resolver.resolve(
+ 'https://host:8080/third_party/dart/foo/lib/src/bar.dart'),
+ 'third_party/dart/foo/lib/src/bar.dart');
+ expect(resolver.resolve('https://host:8080/foo/lib/bar.dart'),
+ 'foo/lib/bar.dart');
+ expect(resolver.resolve('https://host:8080/foo/lib/src/bar.dart'),
+ 'foo/lib/src/bar.dart');
+ });
+
+ test('resolves HTTP URIs without /packages/', () {
+ expect(
+ resolver
+ .resolve('http://host:8080/third_party/dart/foo/lib/bar.dart'),
+ 'third_party/dart/foo/lib/bar.dart');
+ expect(
+ resolver.resolve(
+ 'http://host:8080/third_party/dart/foo/lib/src/bar.dart'),
+ 'third_party/dart/foo/lib/src/bar.dart');
+ expect(resolver.resolve('http://host:8080/foo/lib/bar.dart'),
+ 'foo/lib/bar.dart');
+ expect(resolver.resolve('http://host:8080/foo/lib/src/bar.dart'),
+ 'foo/lib/src/bar.dart');
+ });
+ });
+}
diff --git a/pkgs/coverage/test/run_and_collect_test.dart b/pkgs/coverage/test/run_and_collect_test.dart
new file mode 100644
index 0000000..e371f90
--- /dev/null
+++ b/pkgs/coverage/test/run_and_collect_test.dart
@@ -0,0 +1,128 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:coverage/coverage.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+
+import 'test_util.dart';
+
+final _isolateLibPath = p.join('test', 'test_files', 'test_app_isolate.dart');
+
+final _sampleAppFileUri = p.toUri(p.absolute(testAppPath)).toString();
+final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();
+
+void main() {
+ test('runAndCollect', () async {
+ // use runAndCollect and verify that the results match w/ running manually
+ final coverage = coverageDataFromJson(await runAndCollect(testAppPath));
+ expect(coverage, isNotEmpty);
+
+ final sources = coverage.sources();
+
+ for (var sampleCoverageData in sources[_sampleAppFileUri]!) {
+ expect(sampleCoverageData['hits'], isNotNull);
+ }
+
+ for (var sampleCoverageData in sources[_isolateLibFileUri]!) {
+ expect(sampleCoverageData['hits'], isNotEmpty);
+ }
+
+ final hitMap = await HitMap.parseJson(coverage, checkIgnoredLines: true);
+ checkHitmap(hitMap);
+ final resolver = await Resolver.create();
+ final ignoredLinesInFilesCache = <String, List<List<int>>?>{};
+ final hitMap2 = HitMap.parseJsonSync(coverage,
+ checkIgnoredLines: true,
+ ignoredLinesInFilesCache: ignoredLinesInFilesCache,
+ resolver: resolver);
+ checkHitmap(hitMap2);
+ checkIgnoredLinesInFilesCache(ignoredLinesInFilesCache);
+
+ // Asking again the cache should answer questions about ignored lines,
+ // so providing a resolver that throws when asked for files should be ok.
+ final hitMap3 = HitMap.parseJsonSync(coverage,
+ checkIgnoredLines: true,
+ ignoredLinesInFilesCache: ignoredLinesInFilesCache,
+ resolver: ThrowingResolver());
+ checkHitmap(hitMap3);
+ checkIgnoredLinesInFilesCache(ignoredLinesInFilesCache);
+ });
+}
+
+class ThrowingResolver implements Resolver {
+ @override
+ List<String> get failed => throw UnimplementedError();
+
+ @override
+ String? get packagePath => throw UnimplementedError();
+
+ @override
+ String? get packagesPath => throw UnimplementedError();
+
+ @override
+ String? resolve(String scriptUri) => throw UnimplementedError();
+
+ @override
+ String? resolveSymbolicLinks(String path) => throw UnimplementedError();
+
+ @override
+ String? get sdkRoot => throw UnimplementedError();
+}
+
+void checkIgnoredLinesInFilesCache(
+ Map<String, List<List<int>>?> ignoredLinesInFilesCache) {
+ final keys = ignoredLinesInFilesCache.keys.toList();
+ final testAppKey =
+ keys.where((element) => element.endsWith('test_app.dart')).single;
+ final testAppIsolateKey =
+ keys.where((element) => element.endsWith('test_app_isolate.dart')).single;
+ final packageUtilKey = keys
+ .where((element) => element.endsWith('package:coverage/src/util.dart'))
+ .single;
+ expect(ignoredLinesInFilesCache[packageUtilKey], isEmpty);
+ expect(ignoredLinesInFilesCache[testAppKey], null /* means whole file */);
+ expect(ignoredLinesInFilesCache[testAppIsolateKey], [
+ [51, 51],
+ [53, 57],
+ [62, 65],
+ [66, 72]
+ ]);
+}
+
+void checkHitmap(Map<String, HitMap> hitMap) {
+ expect(hitMap, isNot(contains(_sampleAppFileUri)));
+
+ final actualHitMap = hitMap[_isolateLibFileUri];
+ final actualLineHits = actualHitMap?.lineHits;
+ final expectedLineHits = {
+ 11: 1,
+ 12: 1,
+ 13: 1,
+ 15: 0,
+ 19: 1,
+ 23: 1,
+ 24: 2,
+ 28: 1,
+ 29: 1,
+ 30: 1,
+ 32: 0,
+ 38: 1,
+ 39: 1,
+ 41: 1,
+ 42: 4,
+ 43: 1,
+ 44: 3,
+ 45: 1,
+ 48: 1,
+ 49: 1,
+ 59: 1,
+ 60: 1
+ };
+
+ expect(actualLineHits, expectedLineHits);
+ expect(actualHitMap?.funcHits, isNull);
+ expect(actualHitMap?.funcNames, isNull);
+ expect(actualHitMap?.branchHits, isNull);
+}
diff --git a/pkgs/coverage/test/test_files/chrome_precise_report.txt b/pkgs/coverage/test/test_files/chrome_precise_report.txt
new file mode 100644
index 0000000..41a3e64
--- /dev/null
+++ b/pkgs/coverage/test/test_files/chrome_precise_report.txt
@@ -0,0 +1 @@
+[{"scriptId":"5","url":"http://localhost:33587/JvrQonmMf3ATS3rRCO76ZTlBfGvy%2Fj69/packages/test/src/runner/browser/static/host.dart.js","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":598832,"count":1}],"isBlockCoverage":true},{"functionName":"dartProgram","ranges":[{"startOffset":1228,"endOffset":598788,"count":1}],"isBlockCoverage":true},{"functionName":"copyProperties","ranges":[{"startOffset":1255,"endOffset":1430,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1465,"endOffset":2035,"count":1},{"startOffset":1646,"endOffset":1659,"count":0},{"startOffset":1822,"endOffset":1884,"count":0},{"startOffset":1886,"endOffset":1989,"count":0},{"startOffset":1995,"endOffset":2034,"count":0}],"isBlockCoverage":true},{"functionName":"cls","ranges":[{"startOffset":1492,"endOffset":1510,"count":1}],"isBlockCoverage":true},{"functionName":"setFunctionNamesIfNecessary","ranges":[{"startOffset":2041,"endOffset":2464,"count":1},{"startOffset":2168,"endOffset":2460,"count":0}],"isBlockCoverage":true},{"functionName":"t","ranges":[{"startOffset":2093,"endOffset":2113,"count":0}],"isBlockCoverage":false},{"functionName":"inherit","ranges":[{"startOffset":2467,"endOffset":2862,"count":1},{"startOffset":2710,"endOffset":2858,"count":0}],"isBlockCoverage":true},{"functionName":"inheritMany","ranges":[{"startOffset":2865,"endOffset":2982,"count":1}],"isBlockCoverage":true},{"functionName":"mixin","ranges":[{"startOffset":2985,"endOffset":3106,"count":1}],"isBlockCoverage":true},{"functionName":"lazy","ranges":[{"startOffset":3109,"endOffset":3858,"count":1}],"isBlockCoverage":true},{"functionName":"holder.<computed>","ranges":[{"startOffset":3271,"endOffset":3853,"count":1},{"startOffset":3606,"endOffset":3644,"count":0},{"startOffset":3716,"endOffset":3736,"count":0}],"isBlockCoverage":true},{"functionName":"holder.<computed>","ranges":[{"startOffset":3311,"endOffset":3364,"count":0}],"isBlockCoverage":false},{"functionName":"holder.<computed>","ranges":[{"startOffset":3766,"endOffset":3817,"count":1}],"isBlockCoverage":true},{"functionName":"makeConstList","ranges":[{"startOffset":3861,"endOffset":3976,"count":1}],"isBlockCoverage":true},{"functionName":"convertToFastObject","ranges":[{"startOffset":3979,"endOffset":4116,"count":1}],"isBlockCoverage":true},{"functionName":"t","ranges":[{"startOffset":4026,"endOffset":4046,"count":1}],"isBlockCoverage":true},{"functionName":"convertAllToFastObject","ranges":[{"startOffset":4119,"endOffset":4270,"count":1}],"isBlockCoverage":true},{"functionName":"tearOffGetter","ranges":[{"startOffset":4300,"endOffset":5215,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff","ranges":[{"startOffset":5218,"endOffset":5626,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":5357,"endOffset":5539,"count":1}],"isBlockCoverage":true},{"functionName":"installTearOff","ranges":[{"startOffset":5652,"endOffset":6582,"count":1}],"isBlockCoverage":true},{"functionName":"installStaticTearOff","ranges":[{"startOffset":6585,"endOffset":6908,"count":1}],"isBlockCoverage":true},{"functionName":"installInstanceTearOff","ranges":[{"startOffset":6911,"endOffset":7260,"count":1}],"isBlockCoverage":true},{"functionName":"setOrUpdateInterceptorsByTag","ranges":[{"startOffset":7263,"endOffset":7466,"count":1},{"startOffset":7427,"endOffset":7465,"count":0}],"isBlockCoverage":true},{"functionName":"setOrUpdateLeafTags","ranges":[{"startOffset":7469,"endOffset":7645,"count":1},{"startOffset":7606,"endOffset":7644,"count":0}],"isBlockCoverage":true},{"functionName":"updateTypes","ranges":[{"startOffset":7648,"endOffset":7801,"count":0}],"isBlockCoverage":false},{"functionName":"updateHolder","ranges":[{"startOffset":7804,"endOffset":7908,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":7929,"endOffset":9593,"count":1}],"isBlockCoverage":true},{"functionName":"mkInstance","ranges":[{"startOffset":7963,"endOffset":8325,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":8083,"endOffset":8316,"count":1}],"isBlockCoverage":true},{"functionName":"mkStatic","ranges":[{"startOffset":8344,"endOffset":8674,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":8449,"endOffset":8665,"count":1}],"isBlockCoverage":true},{"functionName":"initializeDeferredHunk","ranges":[{"startOffset":9599,"endOffset":9720,"count":0}],"isBlockCoverage":false},{"functionName":"getGlobalFromName","ranges":[{"startOffset":9723,"endOffset":9920,"count":0}],"isBlockCoverage":false},{"functionName":"JS_CONST","ranges":[{"startOffset":9952,"endOffset":9979,"count":0}],"isBlockCoverage":false},{"functionName":"hexDigitValue","ranges":[{"startOffset":10000,"endOffset":10228,"count":1},{"startOffset":10205,"endOffset":10227,"count":0}],"isBlockCoverage":true},{"functionName":"SubListIterable$","ranges":[{"startOffset":10252,"endOffset":10660,"count":0}],"isBlockCoverage":false},{"functionName":"MappedIterable_MappedIterable","ranges":[{"startOffset":10697,"endOffset":11098,"count":0}],"isBlockCoverage":false},{"functionName":"IterableElementError_noElement","ranges":[{"startOffset":11136,"endOffset":11199,"count":0}],"isBlockCoverage":false},{"functionName":"IterableElementError_tooFew","ranges":[{"startOffset":11234,"endOffset":11303,"count":0}],"isBlockCoverage":false},{"functionName":"CodeUnits","ranges":[{"startOffset":11320,"endOffset":11375,"count":0}],"isBlockCoverage":false},{"functionName":"EfficientLengthIterable","ranges":[{"startOffset":11406,"endOffset":11448,"count":0}],"isBlockCoverage":false},{"functionName":"ListIterable","ranges":[{"startOffset":11468,"endOffset":11499,"count":0}],"isBlockCoverage":false},{"functionName":"SubListIterable","ranges":[{"startOffset":11522,"endOffset":11702,"count":0}],"isBlockCoverage":false},{"functionName":"ListIterator","ranges":[{"startOffset":11722,"endOffset":11941,"count":0}],"isBlockCoverage":false},{"functionName":"MappedIterable","ranges":[{"startOffset":11963,"endOffset":12085,"count":0}],"isBlockCoverage":false},{"functionName":"EfficientLengthMappedIterable","ranges":[{"startOffset":12122,"endOffset":12259,"count":0}],"isBlockCoverage":false},{"functionName":"MappedIterator","ranges":[{"startOffset":12281,"endOffset":12439,"count":0}],"isBlockCoverage":false},{"functionName":"MappedListIterable","ranges":[{"startOffset":12465,"endOffset":12578,"count":0}],"isBlockCoverage":false},{"functionName":"WhereIterable","ranges":[{"startOffset":12599,"endOffset":12720,"count":0}],"isBlockCoverage":false},{"functionName":"WhereIterator","ranges":[{"startOffset":12741,"endOffset":12851,"count":0}],"isBlockCoverage":false},{"functionName":"ExpandIterable","ranges":[{"startOffset":12873,"endOffset":12995,"count":0}],"isBlockCoverage":false},{"functionName":"ExpandIterator","ranges":[{"startOffset":13017,"endOffset":13211,"count":0}],"isBlockCoverage":false},{"functionName":"SkipWhileIterable","ranges":[{"startOffset":13236,"endOffset":13361,"count":0}],"isBlockCoverage":false},{"functionName":"SkipWhileIterator","ranges":[{"startOffset":13386,"endOffset":13540,"count":0}],"isBlockCoverage":false},{"functionName":"EmptyIterator","ranges":[{"startOffset":13561,"endOffset":13616,"count":1}],"isBlockCoverage":true},{"functionName":"FixedLengthListMixin","ranges":[{"startOffset":13644,"endOffset":13683,"count":0}],"isBlockCoverage":false},{"functionName":"UnmodifiableListMixin","ranges":[{"startOffset":13712,"endOffset":13752,"count":0}],"isBlockCoverage":false},{"functionName":"UnmodifiableListBase","ranges":[{"startOffset":13780,"endOffset":13819,"count":0}],"isBlockCoverage":false},{"functionName":"ReversedListIterable","ranges":[{"startOffset":13847,"endOffset":13938,"count":0}],"isBlockCoverage":false},{"functionName":"Symbol","ranges":[{"startOffset":13952,"endOffset":14013,"count":1}],"isBlockCoverage":true},{"functionName":"ConstantMap__throwUnmodifiable","ranges":[{"startOffset":14051,"endOffset":14153,"count":0}],"isBlockCoverage":false},{"functionName":"instantiate1","ranges":[{"startOffset":14173,"endOffset":14345,"count":0}],"isBlockCoverage":false},{"functionName":"unminifyOrTag","ranges":[{"startOffset":14366,"endOffset":14570,"count":0}],"isBlockCoverage":false},{"functionName":"getType","ranges":[{"startOffset":14585,"endOffset":14656,"count":1}],"isBlockCoverage":true},{"functionName":"isJsIndexable","ranges":[{"startOffset":14677,"endOffset":14915,"count":0}],"isBlockCoverage":false},{"functionName":"S","ranges":[{"startOffset":14924,"endOffset":15426,"count":1},{"startOffset":15015,"endOffset":15425,"count":0}],"isBlockCoverage":true},{"functionName":"Primitives_objectHashCode","ranges":[{"startOffset":15459,"endOffset":15659,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_parseInt","ranges":[{"startOffset":15686,"endOffset":16847,"count":1},{"startOffset":15821,"endOffset":15869,"count":0},{"startOffset":15981,"endOffset":15988,"count":0},{"startOffset":16026,"endOffset":16051,"count":0},{"startOffset":16201,"endOffset":16328,"count":0},{"startOffset":16338,"endOffset":16456,"count":0},{"startOffset":16466,"endOffset":16539,"count":0},{"startOffset":16541,"endOffset":16846,"count":0}],"isBlockCoverage":true},{"functionName":"Primitives_objectTypeName","ranges":[{"startOffset":16880,"endOffset":17014,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives__objectClassName","ranges":[{"startOffset":17049,"endOffset":18437,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_currentUri","ranges":[{"startOffset":18466,"endOffset":18560,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives__fromCharCodeApply","ranges":[{"startOffset":18597,"endOffset":19022,"count":1},{"startOffset":18798,"endOffset":19021,"count":0}],"isBlockCoverage":true},{"functionName":"Primitives_stringFromCodePoints","ranges":[{"startOffset":19061,"endOffset":19851,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_stringFromCharCodes","ranges":[{"startOffset":19889,"endOffset":20367,"count":1},{"startOffset":20086,"endOffset":20133,"count":0},{"startOffset":20163,"endOffset":20210,"count":0},{"startOffset":20244,"endOffset":20296,"count":0}],"isBlockCoverage":true},{"functionName":"Primitives_stringFromNativeUint8List","ranges":[{"startOffset":20411,"endOffset":20838,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_stringFromCharCode","ranges":[{"startOffset":20875,"endOffset":21388,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_lazyAsJsDate","ranges":[{"startOffset":21419,"endOffset":21566,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getYear","ranges":[{"startOffset":21592,"endOffset":21708,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getMonth","ranges":[{"startOffset":21735,"endOffset":21848,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getDay","ranges":[{"startOffset":21873,"endOffset":21985,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getHours","ranges":[{"startOffset":22012,"endOffset":22125,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getMinutes","ranges":[{"startOffset":22154,"endOffset":22269,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getSeconds","ranges":[{"startOffset":22298,"endOffset":22413,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getMilliseconds","ranges":[{"startOffset":22447,"endOffset":22567,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_functionNoSuchMethod","ranges":[{"startOffset":22606,"endOffset":23376,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_applyFunction","ranges":[{"startOffset":23408,"endOffset":25001,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives__genericApplyFunction2","ranges":[{"startOffset":25042,"endOffset":28197,"count":0}],"isBlockCoverage":false},{"functionName":"iae","ranges":[{"startOffset":28208,"endOffset":28295,"count":0}],"isBlockCoverage":false},{"functionName":"ioore","ranges":[{"startOffset":28308,"endOffset":28473,"count":0}],"isBlockCoverage":false},{"functionName":"diagnoseIndexError","ranges":[{"startOffset":28499,"endOffset":29047,"count":0}],"isBlockCoverage":false},{"functionName":"diagnoseRangeError","ranges":[{"startOffset":29073,"endOffset":29430,"count":0}],"isBlockCoverage":false},{"functionName":"argumentErrorValue","ranges":[{"startOffset":29456,"endOffset":29540,"count":0}],"isBlockCoverage":false},{"functionName":"checkNum","ranges":[{"startOffset":29556,"endOffset":29696,"count":0}],"isBlockCoverage":false},{"functionName":"wrapException","ranges":[{"startOffset":29717,"endOffset":30104,"count":0}],"isBlockCoverage":false},{"functionName":"toStringWrapper","ranges":[{"startOffset":30127,"endOffset":30193,"count":0}],"isBlockCoverage":false},{"functionName":"throwExpression","ranges":[{"startOffset":30216,"endOffset":30269,"count":0}],"isBlockCoverage":false},{"functionName":"throwConcurrentModificationError","ranges":[{"startOffset":30309,"endOffset":30410,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorDecoder_extractPattern","ranges":[{"startOffset":30449,"endOffset":31458,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorDecoder_provokeCallErrorOn","ranges":[{"startOffset":31501,"endOffset":31745,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorDecoder_provokePropertyErrorOn","ranges":[{"startOffset":31792,"endOffset":31974,"count":0}],"isBlockCoverage":false},{"functionName":"NullError$","ranges":[{"startOffset":31992,"endOffset":32102,"count":0}],"isBlockCoverage":false},{"functionName":"JsNoSuchMethodError$","ranges":[{"startOffset":32130,"endOffset":32326,"count":0}],"isBlockCoverage":false},{"functionName":"unwrapException","ranges":[{"startOffset":32349,"endOffset":36809,"count":0}],"isBlockCoverage":false},{"functionName":"getTraceFromException","ranges":[{"startOffset":36838,"endOffset":37203,"count":0}],"isBlockCoverage":false},{"functionName":"fillLiteralMap","ranges":[{"startOffset":37225,"endOffset":37561,"count":0}],"isBlockCoverage":false},{"functionName":"invokeClosure","ranges":[{"startOffset":37582,"endOffset":38172,"count":1},{"startOffset":37758,"endOffset":37800,"count":0},{"startOffset":37864,"endOffset":37916,"count":0},{"startOffset":37925,"endOffset":37983,"count":0},{"startOffset":37992,"endOffset":38056,"count":0},{"startOffset":38064,"endOffset":38171,"count":0}],"isBlockCoverage":true},{"functionName":"convertDartClosureToJS","ranges":[{"startOffset":38202,"endOffset":38679,"count":1},{"startOffset":38314,"endOffset":38321,"count":0},{"startOffset":38390,"endOffset":38407,"count":0}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":38426,"endOffset":38578,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":38476,"endOffset":38569,"count":1}],"isBlockCoverage":true},{"functionName":"Closure_fromTearOff","ranges":[{"startOffset":38706,"endOffset":41471,"count":1},{"startOffset":39469,"endOffset":39486,"count":0},{"startOffset":40204,"endOffset":40709,"count":0}],"isBlockCoverage":true},{"functionName":"static_tear_off","ranges":[{"startOffset":39300,"endOffset":39368,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":40070,"endOffset":40176,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":40110,"endOffset":40165,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":40461,"endOffset":40599,"count":0}],"isBlockCoverage":false},{"functionName":"Closure_cspForwardCall","ranges":[{"startOffset":41501,"endOffset":42886,"count":1},{"startOffset":41627,"endOffset":41634,"count":0},{"startOffset":41646,"endOffset":41801,"count":0},{"startOffset":41810,"endOffset":41967,"count":0},{"startOffset":41976,"endOffset":42139,"count":0},{"startOffset":42148,"endOffset":42317,"count":0},{"startOffset":42326,"endOffset":42501,"count":0},{"startOffset":42510,"endOffset":42691,"count":0}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":41671,"endOffset":41781,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":41835,"endOffset":41947,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":42001,"endOffset":42119,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":42173,"endOffset":42297,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":42351,"endOffset":42481,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":42535,"endOffset":42671,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":42726,"endOffset":42851,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":42762,"endOffset":42838,"count":0}],"isBlockCoverage":false},{"functionName":"Closure_forwardCallTo","ranges":[{"startOffset":42915,"endOffset":44616,"count":1},{"startOffset":43278,"endOffset":43304,"count":0},{"startOffset":43569,"endOffset":43586,"count":0},{"startOffset":43798,"endOffset":43916,"count":0},{"startOffset":44191,"endOffset":44208,"count":0},{"startOffset":44406,"endOffset":44518,"count":0}],"isBlockCoverage":true},{"functionName":"Closure_cspForwardInterceptedCall","ranges":[{"startOffset":44657,"endOffset":46449,"count":1},{"startOffset":44855,"endOffset":44862,"count":0},{"startOffset":44874,"endOffset":44974,"count":0},{"startOffset":44983,"endOffset":45158,"count":0},{"startOffset":45167,"endOffset":45346,"count":0},{"startOffset":45355,"endOffset":45540,"count":0},{"startOffset":45549,"endOffset":45740,"count":0},{"startOffset":45749,"endOffset":45946,"count":0},{"startOffset":45955,"endOffset":46158,"count":0}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":45008,"endOffset":45128,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":45192,"endOffset":45316,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":45380,"endOffset":45510,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":45574,"endOffset":45710,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":45774,"endOffset":45916,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":45980,"endOffset":46128,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":46193,"endOffset":46401,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":46235,"endOffset":46388,"count":0}],"isBlockCoverage":false},{"functionName":"Closure_forwardInterceptedCallTo","ranges":[{"startOffset":46489,"endOffset":48059,"count":1},{"startOffset":47112,"endOffset":47138,"count":0},{"startOffset":47326,"endOffset":47636,"count":0},{"startOffset":47950,"endOffset":47967,"count":0}],"isBlockCoverage":true},{"functionName":"closureFromTearOff","ranges":[{"startOffset":48085,"endOffset":48339,"count":1}],"isBlockCoverage":true},{"functionName":"BoundClosure_selfOf","ranges":[{"startOffset":48366,"endOffset":48419,"count":0}],"isBlockCoverage":false},{"functionName":"BoundClosure_receiverOf","ranges":[{"startOffset":48450,"endOffset":48507,"count":0}],"isBlockCoverage":false},{"functionName":"BoundClosure_computeFieldNamed","ranges":[{"startOffset":48545,"endOffset":48918,"count":1}],"isBlockCoverage":true},{"functionName":"stringTypeCheck","ranges":[{"startOffset":48941,"endOffset":49144,"count":1},{"startOffset":48992,"endOffset":49005,"count":0},{"startOffset":49064,"endOffset":49143,"count":0}],"isBlockCoverage":true},{"functionName":"stringTypeCast","ranges":[{"startOffset":49166,"endOffset":49339,"count":1},{"startOffset":49220,"endOffset":49236,"count":0},{"startOffset":49259,"endOffset":49338,"count":0}],"isBlockCoverage":true},{"functionName":"doubleTypeCheck","ranges":[{"startOffset":49362,"endOffset":49565,"count":0}],"isBlockCoverage":false},{"functionName":"numTypeCheck","ranges":[{"startOffset":49585,"endOffset":49785,"count":0}],"isBlockCoverage":false},{"functionName":"boolTypeCheck","ranges":[{"startOffset":49806,"endOffset":50008,"count":0}],"isBlockCoverage":false},{"functionName":"intTypeCheck","ranges":[{"startOffset":50028,"endOffset":50259,"count":1},{"startOffset":50079,"endOffset":50092,"count":0},{"startOffset":50182,"endOffset":50258,"count":0}],"isBlockCoverage":true},{"functionName":"intTypeCast","ranges":[{"startOffset":50278,"endOffset":50479,"count":1},{"startOffset":50363,"endOffset":50379,"count":0},{"startOffset":50402,"endOffset":50478,"count":0}],"isBlockCoverage":true},{"functionName":"propertyTypeError","ranges":[{"startOffset":50504,"endOffset":50660,"count":0}],"isBlockCoverage":false},{"functionName":"interceptedTypeCheck","ranges":[{"startOffset":50688,"endOffset":50942,"count":1},{"startOffset":50800,"endOffset":50830,"count":0},{"startOffset":50892,"endOffset":50941,"count":0}],"isBlockCoverage":true},{"functionName":"stringSuperNativeTypeCheck","ranges":[{"startOffset":50976,"endOffset":51227,"count":0}],"isBlockCoverage":false},{"functionName":"listTypeCheck","ranges":[{"startOffset":51248,"endOffset":51467,"count":1},{"startOffset":51380,"endOffset":51466,"count":0}],"isBlockCoverage":true},{"functionName":"listSuperNativeTypeCheck","ranges":[{"startOffset":51499,"endOffset":51766,"count":0}],"isBlockCoverage":false},{"functionName":"extractFunctionTypeObjectFromInternal","ranges":[{"startOffset":51811,"endOffset":52082,"count":1},{"startOffset":52062,"endOffset":52081,"count":0}],"isBlockCoverage":true},{"functionName":"functionTypeTest","ranges":[{"startOffset":52106,"endOffset":52520,"count":1},{"startOffset":52204,"endOffset":52217,"count":0},{"startOffset":52417,"endOffset":52430,"count":0}],"isBlockCoverage":true},{"functionName":"functionTypeCheck","ranges":[{"startOffset":52545,"endOffset":53038,"count":1},{"startOffset":52686,"endOffset":52699,"count":0},{"startOffset":52824,"endOffset":52979,"count":0}],"isBlockCoverage":true},{"functionName":"futureOrCheck","ranges":[{"startOffset":53059,"endOffset":53270,"count":1},{"startOffset":53106,"endOffset":53153,"count":0},{"startOffset":53163,"endOffset":53248,"count":0}],"isBlockCoverage":true},{"functionName":"TypeErrorImplementation$","ranges":[{"startOffset":53302,"endOffset":53507,"count":0}],"isBlockCoverage":false},{"functionName":"CastErrorImplementation$","ranges":[{"startOffset":53539,"endOffset":53744,"count":0}],"isBlockCoverage":false},{"functionName":"_typeDescription","ranges":[{"startOffset":53768,"endOffset":54148,"count":0}],"isBlockCoverage":false},{"functionName":"throwCyclicInit","ranges":[{"startOffset":54171,"endOffset":54292,"count":0}],"isBlockCoverage":false},{"functionName":"RuntimeError$","ranges":[{"startOffset":54313,"endOffset":54380,"count":0}],"isBlockCoverage":false},{"functionName":"getIsolateAffinityTag","ranges":[{"startOffset":54409,"endOffset":54472,"count":1}],"isBlockCoverage":true},{"functionName":"setRuntimeTypeInfo","ranges":[{"startOffset":54498,"endOffset":54572,"count":1}],"isBlockCoverage":true},{"functionName":"getRuntimeTypeInfo","ranges":[{"startOffset":54598,"endOffset":54689,"count":1},{"startOffset":54651,"endOffset":54658,"count":0}],"isBlockCoverage":true},{"functionName":"getRuntimeTypeArguments","ranges":[{"startOffset":54720,"endOffset":54876,"count":0}],"isBlockCoverage":false},{"functionName":"getRuntimeTypeArgumentIntercepted","ranges":[{"startOffset":54917,"endOffset":55240,"count":1},{"startOffset":55207,"endOffset":55213,"count":0}],"isBlockCoverage":true},{"functionName":"getRuntimeTypeArgument","ranges":[{"startOffset":55270,"endOffset":55575,"count":1},{"startOffset":55542,"endOffset":55548,"count":0}],"isBlockCoverage":true},{"functionName":"getTypeArgumentByIndex","ranges":[{"startOffset":55605,"endOffset":55768,"count":1}],"isBlockCoverage":true},{"functionName":"runtimeTypeToString","ranges":[{"startOffset":55795,"endOffset":55864,"count":0}],"isBlockCoverage":false},{"functionName":"_runtimeTypeToString","ranges":[{"startOffset":55892,"endOffset":57053,"count":0}],"isBlockCoverage":false},{"functionName":"_functionRtiToString","ranges":[{"startOffset":57081,"endOffset":59945,"count":0}],"isBlockCoverage":false},{"functionName":"_joinArguments","ranges":[{"startOffset":59967,"endOffset":60636,"count":0}],"isBlockCoverage":false},{"functionName":"substitute","ranges":[{"startOffset":60654,"endOffset":61121,"count":1},{"startOffset":60849,"endOffset":60856,"count":0},{"startOffset":60992,"endOffset":61120,"count":0}],"isBlockCoverage":true},{"functionName":"checkSubtype","ranges":[{"startOffset":61141,"endOffset":61627,"count":1},{"startOffset":61512,"endOffset":61525,"count":0}],"isBlockCoverage":true},{"functionName":"assertSubtype","ranges":[{"startOffset":61648,"endOffset":62224,"count":1},{"startOffset":61923,"endOffset":62223,"count":0}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":61987,"endOffset":62115,"count":0}],"isBlockCoverage":false},{"functionName":"assertIsSubtype","ranges":[{"startOffset":62247,"endOffset":62611,"count":1},{"startOffset":62464,"endOffset":62605,"count":0}],"isBlockCoverage":true},{"functionName":"throwTypeError","ranges":[{"startOffset":62633,"endOffset":62746,"count":0}],"isBlockCoverage":false},{"functionName":"areSubtypes","ranges":[{"startOffset":62765,"endOffset":63196,"count":1},{"startOffset":62841,"endOffset":62853,"count":0},{"startOffset":62875,"endOffset":63042,"count":0},{"startOffset":63158,"endOffset":63171,"count":0}],"isBlockCoverage":true},{"functionName":"computeSignature","ranges":[{"startOffset":63220,"endOffset":63407,"count":0}],"isBlockCoverage":false},{"functionName":"isSupertypeOfNullRecursive","ranges":[{"startOffset":63441,"endOffset":63818,"count":0}],"isBlockCoverage":false},{"functionName":"checkSubtypeOfRuntimeType","ranges":[{"startOffset":63851,"endOffset":64616,"count":1},{"startOffset":63918,"endOffset":64038,"count":0},{"startOffset":64201,"endOffset":64290,"count":0}],"isBlockCoverage":true},{"functionName":"assertSubtypeOfRuntimeType","ranges":[{"startOffset":64650,"endOffset":64869,"count":1},{"startOffset":64755,"endOffset":64842,"count":0}],"isBlockCoverage":true},{"functionName":"_isSubtype","ranges":[{"startOffset":64887,"endOffset":67156,"count":1},{"startOffset":65190,"endOffset":65202,"count":0},{"startOffset":65318,"endOffset":65331,"count":0},{"startOffset":65421,"endOffset":65427,"count":0},{"startOffset":65435,"endOffset":65465,"count":0},{"startOffset":65507,"endOffset":65520,"count":0},{"startOffset":65562,"endOffset":65575,"count":0},{"startOffset":65945,"endOffset":65951,"count":0},{"startOffset":65992,"endOffset":66068,"count":0},{"startOffset":66152,"endOffset":66605,"count":0},{"startOffset":66860,"endOffset":66873,"count":0},{"startOffset":67044,"endOffset":67050,"count":0}],"isBlockCoverage":true},{"functionName":"_isFunctionSubtype","ranges":[{"startOffset":67182,"endOffset":69335,"count":1},{"startOffset":67490,"endOffset":67503,"count":0},{"startOffset":67571,"endOffset":67584,"count":0},{"startOffset":67698,"endOffset":67711,"count":0},{"startOffset":67752,"endOffset":67765,"count":0},{"startOffset":67825,"endOffset":67838,"count":0},{"startOffset":68299,"endOffset":68331,"count":0},{"startOffset":68388,"endOffset":68401,"count":0},{"startOffset":68503,"endOffset":68516,"count":0},{"startOffset":68659,"endOffset":68672,"count":0},{"startOffset":68848,"endOffset":68861,"count":0},{"startOffset":68938,"endOffset":69054,"count":0},{"startOffset":69179,"endOffset":69334,"count":0}],"isBlockCoverage":true},{"functionName":"namedParametersSubtypeCheck","ranges":[{"startOffset":69370,"endOffset":69743,"count":0}],"isBlockCoverage":false},{"functionName":"instantiatedGenericFunctionType","ranges":[{"startOffset":69782,"endOffset":69981,"count":0}],"isBlockCoverage":false},{"functionName":"finishBindInstantiatedFunctionType","ranges":[{"startOffset":70023,"endOffset":70893,"count":0}],"isBlockCoverage":false},{"functionName":"bindInstantiatedType","ranges":[{"startOffset":70921,"endOffset":71830,"count":0}],"isBlockCoverage":false},{"functionName":"bindInstantiatedTypes","ranges":[{"startOffset":71859,"endOffset":72120,"count":0}],"isBlockCoverage":false},{"functionName":"JsLinkedHashMap_JsLinkedHashMap$es6","ranges":[{"startOffset":72163,"endOffset":72233,"count":1}],"isBlockCoverage":true},{"functionName":"defineProperty","ranges":[{"startOffset":72255,"endOffset":72427,"count":0}],"isBlockCoverage":false},{"functionName":"lookupAndCacheInterceptor","ranges":[{"startOffset":72460,"endOffset":74952,"count":0}],"isBlockCoverage":false},{"functionName":"patchInteriorProto","ranges":[{"startOffset":74978,"endOffset":75265,"count":0}],"isBlockCoverage":false},{"functionName":"makeLeafDispatchRecord","ranges":[{"startOffset":75295,"endOffset":75430,"count":1}],"isBlockCoverage":true},{"functionName":"makeDefaultDispatchRecord","ranges":[{"startOffset":75463,"endOffset":75734,"count":1}],"isBlockCoverage":true},{"functionName":"initNativeDispatch","ranges":[{"startOffset":75760,"endOffset":75916,"count":1},{"startOffset":75826,"endOffset":75833,"count":0}],"isBlockCoverage":true},{"functionName":"initNativeDispatchContinue","ranges":[{"startOffset":75950,"endOffset":77230,"count":1}],"isBlockCoverage":true},{"functionName":"fun","ranges":[{"startOffset":76329,"endOffset":76351,"count":0}],"isBlockCoverage":false},{"functionName":"initHooks","ranges":[{"startOffset":77247,"endOffset":78506,"count":1},{"startOffset":77761,"endOffset":78174,"count":0}],"isBlockCoverage":true},{"functionName":"applyHooksTransformer","ranges":[{"startOffset":78535,"endOffset":78613,"count":1}],"isBlockCoverage":true},{"functionName":"JSSyntaxRegExp_makeNative","ranges":[{"startOffset":78646,"endOffset":79188,"count":0}],"isBlockCoverage":false},{"functionName":"stringContainsUnchecked","ranges":[{"startOffset":79219,"endOffset":79767,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceFirstRE","ranges":[{"startOffset":79795,"endOffset":80070,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceAllUnchecked","ranges":[{"startOffset":80103,"endOffset":81120,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceFirstUnchecked","ranges":[{"startOffset":81155,"endOffset":82205,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceRangeUnchecked","ranges":[{"startOffset":82240,"endOffset":82446,"count":0}],"isBlockCoverage":false},{"functionName":"ConstantMapView","ranges":[{"startOffset":82469,"endOffset":82552,"count":0}],"isBlockCoverage":false},{"functionName":"ConstantMap","ranges":[{"startOffset":82571,"endOffset":82601,"count":0}],"isBlockCoverage":false},{"functionName":"ConstantStringMap","ranges":[{"startOffset":82626,"endOffset":82792,"count":1}],"isBlockCoverage":true},{"functionName":"Instantiation","ranges":[{"startOffset":82813,"endOffset":82845,"count":0}],"isBlockCoverage":false},{"functionName":"Instantiation1","ranges":[{"startOffset":82867,"endOffset":82960,"count":0}],"isBlockCoverage":false},{"functionName":"JSInvocationMirror","ranges":[{"startOffset":82986,"endOffset":83199,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_functionNoSuchMethod_closure","ranges":[{"startOffset":83246,"endOffset":83401,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorDecoder","ranges":[{"startOffset":83425,"endOffset":83645,"count":0}],"isBlockCoverage":false},{"functionName":"NullError","ranges":[{"startOffset":83662,"endOffset":83747,"count":0}],"isBlockCoverage":false},{"functionName":"JsNoSuchMethodError","ranges":[{"startOffset":83774,"endOffset":83900,"count":0}],"isBlockCoverage":false},{"functionName":"UnknownJsTypeError","ranges":[{"startOffset":83926,"endOffset":83991,"count":0}],"isBlockCoverage":false},{"functionName":"ExceptionAndStackTrace","ranges":[{"startOffset":84021,"endOffset":84127,"count":0}],"isBlockCoverage":false},{"functionName":"unwrapException_saveStackTrace","ranges":[{"startOffset":84165,"endOffset":84236,"count":0}],"isBlockCoverage":false},{"functionName":"_StackTrace","ranges":[{"startOffset":84255,"endOffset":84353,"count":0}],"isBlockCoverage":false},{"functionName":"Closure","ranges":[{"startOffset":84368,"endOffset":84394,"count":0}],"isBlockCoverage":false},{"functionName":"TearOffClosure","ranges":[{"startOffset":84416,"endOffset":84449,"count":0}],"isBlockCoverage":false},{"functionName":"StaticClosure","ranges":[{"startOffset":84470,"endOffset":84502,"count":1}],"isBlockCoverage":true},{"functionName":"BoundClosure","ranges":[{"startOffset":84522,"endOffset":84673,"count":1}],"isBlockCoverage":true},{"functionName":"TypeErrorImplementation","ranges":[{"startOffset":84704,"endOffset":84773,"count":0}],"isBlockCoverage":false},{"functionName":"CastErrorImplementation","ranges":[{"startOffset":84804,"endOffset":84873,"count":0}],"isBlockCoverage":false},{"functionName":"RuntimeError","ranges":[{"startOffset":84893,"endOffset":84951,"count":0}],"isBlockCoverage":false},{"functionName":"TypeImpl","ranges":[{"startOffset":84967,"endOffset":85065,"count":0}],"isBlockCoverage":false},{"functionName":"JsLinkedHashMap","ranges":[{"startOffset":85088,"endOffset":85289,"count":1}],"isBlockCoverage":true},{"functionName":"JsLinkedHashMap_values_closure","ranges":[{"startOffset":85327,"endOffset":85401,"count":0}],"isBlockCoverage":false},{"functionName":"LinkedHashMapCell","ranges":[{"startOffset":85426,"endOffset":85584,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashMapKeyIterable","ranges":[{"startOffset":85616,"endOffset":85720,"count":0}],"isBlockCoverage":false},{"functionName":"LinkedHashMapKeyIterator","ranges":[{"startOffset":85752,"endOffset":85950,"count":0}],"isBlockCoverage":false},{"functionName":"initHooks_closure","ranges":[{"startOffset":85975,"endOffset":86037,"count":1}],"isBlockCoverage":true},{"functionName":"initHooks_closure0","ranges":[{"startOffset":86063,"endOffset":86133,"count":1}],"isBlockCoverage":true},{"functionName":"initHooks_closure1","ranges":[{"startOffset":86159,"endOffset":86231,"count":1}],"isBlockCoverage":true},{"functionName":"JSSyntaxRegExp","ranges":[{"startOffset":86253,"endOffset":86424,"count":0}],"isBlockCoverage":false},{"functionName":"_MatchImplementation","ranges":[{"startOffset":86452,"endOffset":86517,"count":0}],"isBlockCoverage":false},{"functionName":"_AllMatchesIterable","ranges":[{"startOffset":86544,"endOffset":86674,"count":0}],"isBlockCoverage":false},{"functionName":"_AllMatchesIterator","ranges":[{"startOffset":86701,"endOffset":86887,"count":0}],"isBlockCoverage":false},{"functionName":"StringMatch","ranges":[{"startOffset":86906,"endOffset":86990,"count":0}],"isBlockCoverage":false},{"functionName":"_StringAllMatchesIterable","ranges":[{"startOffset":87023,"endOffset":87163,"count":0}],"isBlockCoverage":false},{"functionName":"_StringAllMatchesIterator","ranges":[{"startOffset":87196,"endOffset":87384,"count":0}],"isBlockCoverage":false},{"functionName":"_ensureNativeList","ranges":[{"startOffset":87409,"endOffset":87450,"count":0}],"isBlockCoverage":false},{"functionName":"NativeInt8List__create1","ranges":[{"startOffset":87481,"endOffset":87535,"count":0}],"isBlockCoverage":false},{"functionName":"_checkValidIndex","ranges":[{"startOffset":87559,"endOffset":87716,"count":1},{"startOffset":87653,"endOffset":87710,"count":0}],"isBlockCoverage":true},{"functionName":"_checkValidRange","ranges":[{"startOffset":87740,"endOffset":88027,"count":0}],"isBlockCoverage":false},{"functionName":"NativeByteBuffer","ranges":[{"startOffset":88051,"endOffset":88086,"count":0}],"isBlockCoverage":false},{"functionName":"NativeTypedData","ranges":[{"startOffset":88109,"endOffset":88143,"count":0}],"isBlockCoverage":false},{"functionName":"NativeTypedArray","ranges":[{"startOffset":88167,"endOffset":88202,"count":0}],"isBlockCoverage":false},{"functionName":"NativeTypedArrayOfDouble","ranges":[{"startOffset":88234,"endOffset":88277,"count":0}],"isBlockCoverage":false},{"functionName":"NativeTypedArrayOfInt","ranges":[{"startOffset":88306,"endOffset":88346,"count":0}],"isBlockCoverage":false},{"functionName":"NativeInt16List","ranges":[{"startOffset":88369,"endOffset":88403,"count":0}],"isBlockCoverage":false},{"functionName":"NativeInt32List","ranges":[{"startOffset":88426,"endOffset":88460,"count":0}],"isBlockCoverage":false},{"functionName":"NativeInt8List","ranges":[{"startOffset":88482,"endOffset":88515,"count":0}],"isBlockCoverage":false},{"functionName":"NativeUint16List","ranges":[{"startOffset":88539,"endOffset":88574,"count":0}],"isBlockCoverage":false},{"functionName":"NativeUint32List","ranges":[{"startOffset":88598,"endOffset":88633,"count":0}],"isBlockCoverage":false},{"functionName":"NativeUint8ClampedList","ranges":[{"startOffset":88663,"endOffset":88704,"count":0}],"isBlockCoverage":false},{"functionName":"NativeUint8List","ranges":[{"startOffset":88727,"endOffset":88761,"count":0}],"isBlockCoverage":false},{"functionName":"_NativeTypedArrayOfDouble_NativeTypedArray_ListMixin","ranges":[{"startOffset":88821,"endOffset":88892,"count":0}],"isBlockCoverage":false},{"functionName":"_NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin","ranges":[{"startOffset":88973,"endOffset":89065,"count":0}],"isBlockCoverage":false},{"functionName":"_NativeTypedArrayOfInt_NativeTypedArray_ListMixin","ranges":[{"startOffset":89122,"endOffset":89190,"count":0}],"isBlockCoverage":false},{"functionName":"_NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin","ranges":[{"startOffset":89268,"endOffset":89357,"count":0}],"isBlockCoverage":false},{"functionName":"extractKeys","ranges":[{"startOffset":89376,"endOffset":89483,"count":0}],"isBlockCoverage":false},{"functionName":"printString","ranges":[{"startOffset":89502,"endOffset":89949,"count":0}],"isBlockCoverage":false},{"functionName":"makeDispatchRecord","ranges":[{"startOffset":89987,"endOffset":90120,"count":1}],"isBlockCoverage":true},{"functionName":"getNativeInterceptor","ranges":[{"startOffset":90148,"endOffset":91834,"count":1},{"startOffset":90602,"endOffset":90616,"count":0},{"startOffset":90731,"endOffset":90881,"count":0},{"startOffset":90889,"endOffset":90978,"count":0},{"startOffset":90979,"endOffset":91030,"count":0},{"startOffset":91071,"endOffset":91833,"count":0}],"isBlockCoverage":true},{"functionName":"JSArray_JSArray$fixed","ranges":[{"startOffset":91863,"endOffset":92096,"count":0}],"isBlockCoverage":false},{"functionName":"JSArray_JSArray$markFixed","ranges":[{"startOffset":92129,"endOffset":92239,"count":0}],"isBlockCoverage":false},{"functionName":"JSArray_markFixedList","ranges":[{"startOffset":92268,"endOffset":92371,"count":1}],"isBlockCoverage":true},{"functionName":"JSArray_markUnmodifiableList","ranges":[{"startOffset":92407,"endOffset":92516,"count":0}],"isBlockCoverage":false},{"functionName":"JSString__isWhitespace","ranges":[{"startOffset":92546,"endOffset":93301,"count":0}],"isBlockCoverage":false},{"functionName":"JSString__skipLeadingWhitespace","ranges":[{"startOffset":93340,"endOffset":93658,"count":0}],"isBlockCoverage":false},{"functionName":"JSString__skipTrailingWhitespace","ranges":[{"startOffset":93698,"endOffset":94027,"count":0}],"isBlockCoverage":false},{"functionName":"getInterceptor$","ranges":[{"startOffset":94050,"endOffset":94813,"count":1},{"startOffset":94193,"endOffset":94238,"count":0},{"startOffset":94426,"endOffset":94452,"count":0},{"startOffset":94569,"endOffset":94695,"count":0}],"isBlockCoverage":true},{"functionName":"getInterceptor$ansx","ranges":[{"startOffset":94840,"endOffset":95426,"count":0}],"isBlockCoverage":false},{"functionName":"getInterceptor$asx","ranges":[{"startOffset":95452,"endOffset":95962,"count":1},{"startOffset":95520,"endOffset":95548,"count":0},{"startOffset":95585,"endOffset":95601,"count":0},{"startOffset":95718,"endOffset":95844,"count":0},{"startOffset":95909,"endOffset":95961,"count":0}],"isBlockCoverage":true},{"functionName":"getInterceptor$ax","ranges":[{"startOffset":95987,"endOffset":96421,"count":1},{"startOffset":96044,"endOffset":96060,"count":0},{"startOffset":96177,"endOffset":96303,"count":0},{"startOffset":96368,"endOffset":96420,"count":0}],"isBlockCoverage":true},{"functionName":"getInterceptor$n","ranges":[{"startOffset":96445,"endOffset":96718,"count":0}],"isBlockCoverage":false},{"functionName":"getInterceptor$s","ranges":[{"startOffset":96742,"endOffset":97015,"count":1},{"startOffset":96838,"endOffset":97014,"count":0}],"isBlockCoverage":true},{"functionName":"getInterceptor$x","ranges":[{"startOffset":97039,"endOffset":97396,"count":1},{"startOffset":97096,"endOffset":97112,"count":0},{"startOffset":97152,"endOffset":97278,"count":0}],"isBlockCoverage":true},{"functionName":"get$hashCode$","ranges":[{"startOffset":97417,"endOffset":97508,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator$ax","ranges":[{"startOffset":97531,"endOffset":97624,"count":0}],"isBlockCoverage":false},{"functionName":"get$length$asx","ranges":[{"startOffset":97646,"endOffset":97738,"count":1}],"isBlockCoverage":true},{"functionName":"get$onClick$x","ranges":[{"startOffset":97759,"endOffset":97850,"count":1}],"isBlockCoverage":true},{"functionName":"$add$ansx","ranges":[{"startOffset":97867,"endOffset":98056,"count":0}],"isBlockCoverage":false},{"functionName":"$eq$","ranges":[{"startOffset":98068,"endOffset":98298,"count":1},{"startOffset":98129,"endOffset":98147,"count":0},{"startOffset":98232,"endOffset":98297,"count":0}],"isBlockCoverage":true},{"functionName":"$gt$n","ranges":[{"startOffset":98311,"endOffset":98496,"count":1},{"startOffset":98429,"endOffset":98495,"count":0}],"isBlockCoverage":true},{"functionName":"$index$asx","ranges":[{"startOffset":98514,"endOffset":98872,"count":1},{"startOffset":98581,"endOffset":98800,"count":0}],"isBlockCoverage":true},{"functionName":"$indexSet$ax","ranges":[{"startOffset":98892,"endOffset":98998,"count":1}],"isBlockCoverage":true},{"functionName":"_codeUnitAt$1$s","ranges":[{"startOffset":99021,"endOffset":99122,"count":1}],"isBlockCoverage":true},{"functionName":"_removeChild$1$x","ranges":[{"startOffset":99146,"endOffset":99248,"count":0}],"isBlockCoverage":false},{"functionName":"_removeEventListener$3$x","ranges":[{"startOffset":99280,"endOffset":99406,"count":0}],"isBlockCoverage":false},{"functionName":"addEventListener$3$x","ranges":[{"startOffset":99434,"endOffset":99556,"count":1}],"isBlockCoverage":true},{"functionName":"codeUnitAt$1$s","ranges":[{"startOffset":99578,"endOffset":99678,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1$asx","ranges":[{"startOffset":99700,"endOffset":99800,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1$ax","ranges":[{"startOffset":99822,"endOffset":99922,"count":0}],"isBlockCoverage":false},{"functionName":"endsWith$1$s","ranges":[{"startOffset":99942,"endOffset":100040,"count":0}],"isBlockCoverage":false},{"functionName":"fillRange$3$x","ranges":[{"startOffset":100061,"endOffset":100176,"count":1}],"isBlockCoverage":true},{"functionName":"indexOf$2$s","ranges":[{"startOffset":100195,"endOffset":100300,"count":0}],"isBlockCoverage":false},{"functionName":"matchAsPrefix$2$s","ranges":[{"startOffset":100325,"endOffset":100436,"count":0}],"isBlockCoverage":false},{"functionName":"noSuchMethod$1$","ranges":[{"startOffset":100459,"endOffset":100560,"count":0}],"isBlockCoverage":false},{"functionName":"padRight$1$s","ranges":[{"startOffset":100580,"endOffset":100678,"count":0}],"isBlockCoverage":false},{"functionName":"postMessage$3$x","ranges":[{"startOffset":100701,"endOffset":100818,"count":1}],"isBlockCoverage":true},{"functionName":"replaceFirst$2$s","ranges":[{"startOffset":100842,"endOffset":100952,"count":0}],"isBlockCoverage":false},{"functionName":"replaceRange$3$asx","ranges":[{"startOffset":100978,"endOffset":101098,"count":0}],"isBlockCoverage":false},{"functionName":"startsWith$1$s","ranges":[{"startOffset":101120,"endOffset":101220,"count":0}],"isBlockCoverage":false},{"functionName":"startsWith$2$s","ranges":[{"startOffset":101242,"endOffset":101350,"count":0}],"isBlockCoverage":false},{"functionName":"substring$1$s","ranges":[{"startOffset":101371,"endOffset":101470,"count":0}],"isBlockCoverage":false},{"functionName":"substring$2$s","ranges":[{"startOffset":101491,"endOffset":101598,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0$","ranges":[{"startOffset":101617,"endOffset":101706,"count":0}],"isBlockCoverage":false},{"functionName":"trim$0$s","ranges":[{"startOffset":101722,"endOffset":101808,"count":0}],"isBlockCoverage":false},{"functionName":"waitUntilDone$0$x","ranges":[{"startOffset":101833,"endOffset":101928,"count":0}],"isBlockCoverage":false},{"functionName":"Interceptor","ranges":[{"startOffset":101947,"endOffset":101977,"count":0}],"isBlockCoverage":false},{"functionName":"JSBool","ranges":[{"startOffset":101991,"endOffset":102016,"count":0}],"isBlockCoverage":false},{"functionName":"JSNull","ranges":[{"startOffset":102030,"endOffset":102055,"count":0}],"isBlockCoverage":false},{"functionName":"JavaScriptObject","ranges":[{"startOffset":102079,"endOffset":102114,"count":0}],"isBlockCoverage":false},{"functionName":"PlainJavaScriptObject","ranges":[{"startOffset":102143,"endOffset":102183,"count":0}],"isBlockCoverage":false},{"functionName":"UnknownJavaScriptObject","ranges":[{"startOffset":102214,"endOffset":102256,"count":0}],"isBlockCoverage":false},{"functionName":"JavaScriptFunction","ranges":[{"startOffset":102282,"endOffset":102319,"count":0}],"isBlockCoverage":false},{"functionName":"JSArray","ranges":[{"startOffset":102334,"endOffset":102383,"count":0}],"isBlockCoverage":true},{"functionName":"JSUnmodifiableArray","ranges":[{"startOffset":102410,"endOffset":102471,"count":0}],"isBlockCoverage":false},{"functionName":"ArrayIterator","ranges":[{"startOffset":102492,"endOffset":102698,"count":0}],"isBlockCoverage":false},{"functionName":"JSNumber","ranges":[{"startOffset":102714,"endOffset":102741,"count":0}],"isBlockCoverage":false},{"functionName":"JSInt","ranges":[{"startOffset":102754,"endOffset":102778,"count":0}],"isBlockCoverage":true},{"functionName":"JSDouble","ranges":[{"startOffset":102794,"endOffset":102821,"count":0}],"isBlockCoverage":false},{"functionName":"JSString","ranges":[{"startOffset":102837,"endOffset":102864,"count":0}],"isBlockCoverage":true},{"functionName":"_AsyncRun__initializeScheduleImmediate","ranges":[{"startOffset":102922,"endOffset":103739,"count":1},{"startOffset":103025,"endOffset":103089,"count":0},{"startOffset":103548,"endOffset":103738,"count":0}],"isBlockCoverage":true},{"functionName":"_AsyncRun__scheduleImmediateJsOverride","ranges":[{"startOffset":103785,"endOffset":103984,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncRun__scheduleImmediateWithSetImmediate","ranges":[{"startOffset":104036,"endOffset":104236,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncRun__scheduleImmediateWithTimer","ranges":[{"startOffset":104281,"endOffset":104400,"count":0}],"isBlockCoverage":false},{"functionName":"Timer__createTimer","ranges":[{"startOffset":104426,"endOffset":104694,"count":0}],"isBlockCoverage":false},{"functionName":"Timer__createPeriodicTimer","ranges":[{"startOffset":104728,"endOffset":105021,"count":1},{"startOffset":104985,"endOffset":104988,"count":0}],"isBlockCoverage":true},{"functionName":"_TimerImpl$","ranges":[{"startOffset":105040,"endOffset":105179,"count":0}],"isBlockCoverage":false},{"functionName":"_TimerImpl$periodic","ranges":[{"startOffset":105206,"endOffset":105354,"count":1}],"isBlockCoverage":true},{"functionName":"_makeAsyncAwaitCompleter","ranges":[{"startOffset":105386,"endOffset":105529,"count":1}],"isBlockCoverage":true},{"functionName":"_asyncStartSync","ranges":[{"startOffset":105552,"endOffset":105848,"count":1}],"isBlockCoverage":true},{"functionName":"_asyncAwait","ranges":[{"startOffset":105867,"endOffset":106009,"count":1}],"isBlockCoverage":true},{"functionName":"_asyncReturn","ranges":[{"startOffset":106029,"endOffset":106143,"count":1}],"isBlockCoverage":true},{"functionName":"_asyncRethrow","ranges":[{"startOffset":106164,"endOffset":106332,"count":0}],"isBlockCoverage":false},{"functionName":"_awaitOnObject","ranges":[{"startOffset":106354,"endOffset":107170,"count":1},{"startOffset":106791,"endOffset":107164,"count":0}],"isBlockCoverage":true},{"functionName":"_wrapJsFunctionForAsync","ranges":[{"startOffset":107201,"endOffset":107687,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":107246,"endOffset":107537,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":107283,"endOffset":107528,"count":1},{"startOffset":107425,"endOffset":107518,"count":0}],"isBlockCoverage":true},{"functionName":"_Future$zoneValue","ranges":[{"startOffset":107712,"endOffset":107914,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainForeignFuture","ranges":[{"startOffset":107949,"endOffset":108400,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainCoreFuture","ranges":[{"startOffset":108432,"endOffset":109081,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__propagateToListeners","ranges":[{"startOffset":109118,"endOffset":112741,"count":1},{"startOffset":109462,"endOffset":109649,"count":0},{"startOffset":110172,"endOffset":110183,"count":0},{"startOffset":110194,"endOffset":110220,"count":0},{"startOffset":110323,"endOffset":110467,"count":0},{"startOffset":110515,"endOffset":110754,"count":0},{"startOffset":110835,"endOffset":110858,"count":0},{"startOffset":110970,"endOffset":111079,"count":0},{"startOffset":111261,"endOffset":111383,"count":0},{"startOffset":111427,"endOffset":111453,"count":0},{"startOffset":111547,"endOffset":112035,"count":0},{"startOffset":112531,"endOffset":112674,"count":0}],"isBlockCoverage":true},{"functionName":"_registerErrorHandler","ranges":[{"startOffset":112770,"endOffset":113325,"count":0}],"isBlockCoverage":false},{"functionName":"_microtaskLoop","ranges":[{"startOffset":113347,"endOffset":113621,"count":1}],"isBlockCoverage":true},{"functionName":"_startMicrotaskLoop","ranges":[{"startOffset":113648,"endOffset":113983,"count":1},{"startOffset":113877,"endOffset":113969,"count":0}],"isBlockCoverage":true},{"functionName":"_scheduleAsyncCallback","ranges":[{"startOffset":114013,"endOffset":114484,"count":1},{"startOffset":114386,"endOffset":114478,"count":0}],"isBlockCoverage":true},{"functionName":"_schedulePriorityAsyncCallback","ranges":[{"startOffset":114522,"endOffset":115197,"count":0}],"isBlockCoverage":false},{"functionName":"scheduleMicrotask","ranges":[{"startOffset":115222,"endOffset":115926,"count":0}],"isBlockCoverage":false},{"functionName":"StreamIterator_StreamIterator","ranges":[{"startOffset":115963,"endOffset":116090,"count":0}],"isBlockCoverage":false},{"functionName":"StreamController_StreamController","ranges":[{"startOffset":116131,"endOffset":116365,"count":1}],"isBlockCoverage":true},{"functionName":"_runGuarded","ranges":[{"startOffset":116384,"endOffset":116791,"count":1},{"startOffset":116615,"endOffset":116785,"count":0}],"isBlockCoverage":true},{"functionName":"_nullDataHandler","ranges":[{"startOffset":116815,"endOffset":116838,"count":0}],"isBlockCoverage":false},{"functionName":"_nullErrorHandler","ranges":[{"startOffset":116863,"endOffset":117021,"count":0}],"isBlockCoverage":false},{"functionName":"_nullDoneHandler","ranges":[{"startOffset":117045,"endOffset":117063,"count":0}],"isBlockCoverage":false},{"functionName":"Timer_Timer$periodic","ranges":[{"startOffset":117091,"endOffset":117502,"count":1},{"startOffset":117293,"endOffset":117345,"count":0}],"isBlockCoverage":true},{"functionName":"_ZoneSpecification$","ranges":[{"startOffset":117529,"endOffset":117972,"count":1}],"isBlockCoverage":true},{"functionName":"_parentDelegate","ranges":[{"startOffset":117995,"endOffset":118126,"count":1},{"startOffset":118068,"endOffset":118125,"count":0}],"isBlockCoverage":true},{"functionName":"_rootHandleUncaughtError","ranges":[{"startOffset":118158,"endOffset":118395,"count":0}],"isBlockCoverage":false},{"functionName":"_rootRun","ranges":[{"startOffset":118411,"endOffset":118914,"count":1},{"startOffset":118731,"endOffset":118749,"count":0},{"startOffset":118859,"endOffset":118860,"count":0}],"isBlockCoverage":true},{"functionName":"_rootRunUnary","ranges":[{"startOffset":118935,"endOffset":119510,"count":1},{"startOffset":119455,"endOffset":119456,"count":0}],"isBlockCoverage":true},{"functionName":"_rootRunBinary","ranges":[{"startOffset":119532,"endOffset":120183,"count":0}],"isBlockCoverage":false},{"functionName":"_rootRegisterCallback","ranges":[{"startOffset":120212,"endOffset":120314,"count":1}],"isBlockCoverage":true},{"functionName":"_rootRegisterUnaryCallback","ranges":[{"startOffset":120348,"endOffset":120466,"count":1}],"isBlockCoverage":true},{"functionName":"_rootRegisterBinaryCallback","ranges":[{"startOffset":120501,"endOffset":120627,"count":1}],"isBlockCoverage":true},{"functionName":"_rootErrorCallback","ranges":[{"startOffset":120653,"endOffset":120783,"count":0}],"isBlockCoverage":false},{"functionName":"_rootScheduleMicrotask","ranges":[{"startOffset":120813,"endOffset":121143,"count":1},{"startOffset":121071,"endOffset":121101,"count":0}],"isBlockCoverage":true},{"functionName":"_rootCreateTimer","ranges":[{"startOffset":121167,"endOffset":121430,"count":0}],"isBlockCoverage":false},{"functionName":"_rootCreatePeriodicTimer","ranges":[{"startOffset":121462,"endOffset":121766,"count":1}],"isBlockCoverage":true},{"functionName":"_rootPrint","ranges":[{"startOffset":121784,"endOffset":121874,"count":0}],"isBlockCoverage":false},{"functionName":"_printToZone","ranges":[{"startOffset":121894,"endOffset":121956,"count":0}],"isBlockCoverage":false},{"functionName":"_rootFork","ranges":[{"startOffset":121973,"endOffset":123508,"count":1},{"startOffset":122278,"endOffset":122319,"count":0},{"startOffset":123450,"endOffset":123483,"count":0}],"isBlockCoverage":true},{"functionName":"runZoned","ranges":[{"startOffset":123524,"endOffset":125443,"count":1},{"startOffset":124003,"endOffset":124288,"count":0},{"startOffset":124511,"endOffset":125049,"count":0},{"startOffset":125155,"endOffset":125442,"count":0}],"isBlockCoverage":true},{"functionName":"_runZoned","ranges":[{"startOffset":125460,"endOffset":125673,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncRun__initializeScheduleImmediate_internalCallback","ranges":[{"startOffset":125736,"endOffset":125836,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncRun__initializeScheduleImmediate_closure","ranges":[{"startOffset":125890,"endOffset":126032,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncRun__scheduleImmediateJsOverride_internalCallback","ranges":[{"startOffset":126095,"endOffset":126197,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncRun__scheduleImmediateWithSetImmediate_internalCallback","ranges":[{"startOffset":126266,"endOffset":126374,"count":0}],"isBlockCoverage":false},{"functionName":"_TimerImpl","ranges":[{"startOffset":126392,"endOffset":126443,"count":1}],"isBlockCoverage":true},{"functionName":"_TimerImpl_internalCallback","ranges":[{"startOffset":126478,"endOffset":126579,"count":0}],"isBlockCoverage":false},{"functionName":"_TimerImpl$periodic_closure","ranges":[{"startOffset":126614,"endOffset":126784,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncAwaitCompleter","ranges":[{"startOffset":126812,"endOffset":126934,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncAwaitCompleter_complete_closure","ranges":[{"startOffset":126979,"endOffset":127087,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncAwaitCompleter_completeError_closure","ranges":[{"startOffset":127137,"endOffset":127270,"count":0}],"isBlockCoverage":false},{"functionName":"_awaitOnObject_closure","ranges":[{"startOffset":127300,"endOffset":127373,"count":1}],"isBlockCoverage":true},{"functionName":"_awaitOnObject_closure0","ranges":[{"startOffset":127404,"endOffset":127478,"count":1}],"isBlockCoverage":true},{"functionName":"_wrapJsFunctionForAsync_closure","ranges":[{"startOffset":127517,"endOffset":127597,"count":1}],"isBlockCoverage":true},{"functionName":"Future","ranges":[{"startOffset":127611,"endOffset":127636,"count":0}],"isBlockCoverage":false},{"functionName":"_Completer","ranges":[{"startOffset":127654,"endOffset":127683,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncCompleter","ranges":[{"startOffset":127706,"endOffset":127791,"count":1}],"isBlockCoverage":true},{"functionName":"_SyncCompleter","ranges":[{"startOffset":127813,"endOffset":127897,"count":1}],"isBlockCoverage":true},{"functionName":"_FutureListener","ranges":[{"startOffset":127920,"endOffset":128132,"count":1}],"isBlockCoverage":true},{"functionName":"_Future","ranges":[{"startOffset":128147,"endOffset":128297,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__addListener_closure","ranges":[{"startOffset":128333,"endOffset":128435,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__prependListeners_closure","ranges":[{"startOffset":128476,"endOffset":128581,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainForeignFuture_closure","ranges":[{"startOffset":128624,"endOffset":128704,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainForeignFuture_closure0","ranges":[{"startOffset":128748,"endOffset":128829,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainForeignFuture_closure1","ranges":[{"startOffset":128873,"endOffset":129000,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__asyncComplete_closure","ranges":[{"startOffset":129038,"endOffset":129139,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__chainFuture_closure","ranges":[{"startOffset":129175,"endOffset":129274,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__asyncCompleteError_closure","ranges":[{"startOffset":129317,"endOffset":129455,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__propagateToListeners_handleWhenCompleteCallback","ranges":[{"startOffset":129519,"endOffset":129716,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__propagateToListeners_handleWhenCompleteCallback_closure","ranges":[{"startOffset":129788,"endOffset":129905,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__propagateToListeners_handleValueCallback","ranges":[{"startOffset":129962,"endOffset":130120,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__propagateToListeners_handleError","ranges":[{"startOffset":130169,"endOffset":130313,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncCallbackEntry","ranges":[{"startOffset":130340,"endOffset":130430,"count":1}],"isBlockCoverage":true},{"functionName":"Stream","ranges":[{"startOffset":130444,"endOffset":130469,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_pipe_closure","ranges":[{"startOffset":130496,"endOffset":130568,"count":1}],"isBlockCoverage":true},{"functionName":"Stream_length_closure","ranges":[{"startOffset":130597,"endOffset":130690,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_length_closure0","ranges":[{"startOffset":130720,"endOffset":130815,"count":0}],"isBlockCoverage":false},{"functionName":"StreamSubscription","ranges":[{"startOffset":130841,"endOffset":130878,"count":0}],"isBlockCoverage":false},{"functionName":"StreamTransformerBase","ranges":[{"startOffset":130907,"endOffset":130947,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamController","ranges":[{"startOffset":130972,"endOffset":131008,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamController__subscribe_closure","ranges":[{"startOffset":131052,"endOffset":131132,"count":1}],"isBlockCoverage":true},{"functionName":"_StreamController__recordCancel_complete","ranges":[{"startOffset":131180,"endOffset":131264,"count":0}],"isBlockCoverage":false},{"functionName":"_SyncStreamControllerDispatch","ranges":[{"startOffset":131301,"endOffset":131349,"count":0}],"isBlockCoverage":false},{"functionName":"_SyncStreamController","ranges":[{"startOffset":131378,"endOffset":131643,"count":1}],"isBlockCoverage":true},{"functionName":"_ControllerStream","ranges":[{"startOffset":131668,"endOffset":131760,"count":1}],"isBlockCoverage":true},{"functionName":"_ControllerSubscription","ranges":[{"startOffset":131791,"endOffset":132051,"count":1}],"isBlockCoverage":true},{"functionName":"_StreamSinkWrapper","ranges":[{"startOffset":132077,"endOffset":132173,"count":1}],"isBlockCoverage":true},{"functionName":"_AddStreamState_cancel_closure","ranges":[{"startOffset":132211,"endOffset":132285,"count":0}],"isBlockCoverage":false},{"functionName":"_BufferingStreamSubscription","ranges":[{"startOffset":132321,"endOffset":132368,"count":0}],"isBlockCoverage":false},{"functionName":"_BufferingStreamSubscription__sendError_sendError","ranges":[{"startOffset":132425,"endOffset":132577,"count":0}],"isBlockCoverage":false},{"functionName":"_BufferingStreamSubscription__sendDone_sendDone","ranges":[{"startOffset":132632,"endOffset":132723,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamImpl","ranges":[{"startOffset":132742,"endOffset":132772,"count":0}],"isBlockCoverage":false},{"functionName":"_DelayedEvent","ranges":[{"startOffset":132793,"endOffset":132825,"count":0}],"isBlockCoverage":false},{"functionName":"_DelayedData","ranges":[{"startOffset":132845,"endOffset":132950,"count":0}],"isBlockCoverage":false},{"functionName":"_DelayedError","ranges":[{"startOffset":132971,"endOffset":133084,"count":0}],"isBlockCoverage":false},{"functionName":"_DelayedDone","ranges":[{"startOffset":133104,"endOffset":133135,"count":1}],"isBlockCoverage":true},{"functionName":"_PendingEvents","ranges":[{"startOffset":133157,"endOffset":133190,"count":0}],"isBlockCoverage":false},{"functionName":"_PendingEvents_schedule_closure","ranges":[{"startOffset":133229,"endOffset":133334,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamImplEvents","ranges":[{"startOffset":133359,"endOffset":133515,"count":0}],"isBlockCoverage":false},{"functionName":"_DoneStreamSubscription","ranges":[{"startOffset":133546,"endOffset":133698,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamIterator","ranges":[{"startOffset":133721,"endOffset":133881,"count":0}],"isBlockCoverage":false},{"functionName":"_EmptyStream","ranges":[{"startOffset":133901,"endOffset":133955,"count":0}],"isBlockCoverage":false},{"functionName":"Timer","ranges":[{"startOffset":133968,"endOffset":133992,"count":0}],"isBlockCoverage":false},{"functionName":"AsyncError","ranges":[{"startOffset":134010,"endOffset":134096,"count":0}],"isBlockCoverage":false},{"functionName":"_ZoneFunction","ranges":[{"startOffset":134117,"endOffset":134229,"count":1}],"isBlockCoverage":true},{"functionName":"ZoneSpecification","ranges":[{"startOffset":134254,"endOffset":134290,"count":0}],"isBlockCoverage":false},{"functionName":"_ZoneSpecification","ranges":[{"startOffset":134316,"endOffset":134791,"count":1}],"isBlockCoverage":true},{"functionName":"ZoneDelegate","ranges":[{"startOffset":134811,"endOffset":134842,"count":0}],"isBlockCoverage":false},{"functionName":"Zone","ranges":[{"startOffset":134854,"endOffset":134877,"count":0}],"isBlockCoverage":false},{"functionName":"_ZoneDelegate","ranges":[{"startOffset":134898,"endOffset":134967,"count":0}],"isBlockCoverage":false},{"functionName":"_Zone","ranges":[{"startOffset":134980,"endOffset":135004,"count":0}],"isBlockCoverage":false},{"functionName":"_CustomZone","ranges":[{"startOffset":135023,"endOffset":135402,"count":1}],"isBlockCoverage":true},{"functionName":"_CustomZone_bindCallback_closure","ranges":[{"startOffset":135442,"endOffset":135573,"count":0}],"isBlockCoverage":false},{"functionName":"_CustomZone_bindUnaryCallback_closure","ranges":[{"startOffset":135618,"endOffset":135785,"count":1}],"isBlockCoverage":true},{"functionName":"_CustomZone_bindCallbackGuarded_closure","ranges":[{"startOffset":135832,"endOffset":135947,"count":1}],"isBlockCoverage":true},{"functionName":"_CustomZone_bindUnaryCallbackGuarded_closure","ranges":[{"startOffset":135999,"endOffset":136142,"count":1}],"isBlockCoverage":true},{"functionName":"_rootHandleUncaughtError_closure","ranges":[{"startOffset":136182,"endOffset":136291,"count":0}],"isBlockCoverage":false},{"functionName":"_RootZone","ranges":[{"startOffset":136308,"endOffset":136336,"count":1}],"isBlockCoverage":true},{"functionName":"_RootZone_bindCallback_closure","ranges":[{"startOffset":136374,"endOffset":136494,"count":0}],"isBlockCoverage":false},{"functionName":"_RootZone_bindCallbackGuarded_closure","ranges":[{"startOffset":136539,"endOffset":136643,"count":0}],"isBlockCoverage":false},{"functionName":"_RootZone_bindUnaryCallbackGuarded_closure","ranges":[{"startOffset":136693,"endOffset":136825,"count":0}],"isBlockCoverage":false},{"functionName":"runZoned_closure","ranges":[{"startOffset":136849,"endOffset":136910,"count":1}],"isBlockCoverage":true},{"functionName":"HashMap_HashMap","ranges":[{"startOffset":136933,"endOffset":136996,"count":1}],"isBlockCoverage":true},{"functionName":"_HashMap__getTableEntry","ranges":[{"startOffset":137027,"endOffset":137130,"count":0}],"isBlockCoverage":false},{"functionName":"_HashMap__setTableEntry","ranges":[{"startOffset":137161,"endOffset":137288,"count":0}],"isBlockCoverage":false},{"functionName":"_HashMap__newHashTable","ranges":[{"startOffset":137318,"endOffset":137510,"count":0}],"isBlockCoverage":false},{"functionName":"LinkedHashMap_LinkedHashMap$_literal","ranges":[{"startOffset":137554,"endOffset":137777,"count":0}],"isBlockCoverage":false},{"functionName":"LinkedHashMap_LinkedHashMap$_empty","ranges":[{"startOffset":137819,"endOffset":137889,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashMap__makeEmpty","ranges":[{"startOffset":137921,"endOffset":137989,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashSet_LinkedHashSet","ranges":[{"startOffset":138024,"endOffset":138085,"count":1}],"isBlockCoverage":true},{"functionName":"_LinkedHashSet__newHashTable","ranges":[{"startOffset":138121,"endOffset":138287,"count":0}],"isBlockCoverage":false},{"functionName":"IterableBase_iterableToShortString","ranges":[{"startOffset":138329,"endOffset":139079,"count":0}],"isBlockCoverage":false},{"functionName":"IterableBase_iterableToFullString","ranges":[{"startOffset":139120,"endOffset":139770,"count":0}],"isBlockCoverage":false},{"functionName":"_isToStringVisiting","ranges":[{"startOffset":139797,"endOffset":139972,"count":0}],"isBlockCoverage":false},{"functionName":"_iterablePartsToStrings","ranges":[{"startOffset":140003,"endOffset":142710,"count":0}],"isBlockCoverage":false},{"functionName":"MapBase_mapToString","ranges":[{"startOffset":142737,"endOffset":143352,"count":0}],"isBlockCoverage":false},{"functionName":"_HashMap","ranges":[{"startOffset":143368,"endOffset":143571,"count":1}],"isBlockCoverage":true},{"functionName":"_HashMapKeyIterable","ranges":[{"startOffset":143598,"endOffset":143685,"count":0}],"isBlockCoverage":false},{"functionName":"_HashMapKeyIterator","ranges":[{"startOffset":143712,"endOffset":143907,"count":0}],"isBlockCoverage":false},{"functionName":"_LinkedHashSet","ranges":[{"startOffset":143929,"endOffset":144201,"count":1}],"isBlockCoverage":true},{"functionName":"_LinkedHashSetCell","ranges":[{"startOffset":144227,"endOffset":144358,"count":0}],"isBlockCoverage":false},{"functionName":"_LinkedHashSetIterator","ranges":[{"startOffset":144388,"endOffset":144596,"count":0}],"isBlockCoverage":false},{"functionName":"IterableBase","ranges":[{"startOffset":144616,"endOffset":144647,"count":0}],"isBlockCoverage":false},{"functionName":"ListBase","ranges":[{"startOffset":144663,"endOffset":144690,"count":0}],"isBlockCoverage":false},{"functionName":"ListMixin","ranges":[{"startOffset":144707,"endOffset":144735,"count":0}],"isBlockCoverage":false},{"functionName":"MapBase","ranges":[{"startOffset":144750,"endOffset":144776,"count":0}],"isBlockCoverage":false},{"functionName":"MapBase_mapToString_closure","ranges":[{"startOffset":144811,"endOffset":144911,"count":0}],"isBlockCoverage":false},{"functionName":"MapMixin","ranges":[{"startOffset":144927,"endOffset":144954,"count":0}],"isBlockCoverage":false},{"functionName":"_UnmodifiableMapMixin","ranges":[{"startOffset":144983,"endOffset":145023,"count":0}],"isBlockCoverage":false},{"functionName":"MapView","ranges":[{"startOffset":145038,"endOffset":145064,"count":0}],"isBlockCoverage":false},{"functionName":"UnmodifiableMapView","ranges":[{"startOffset":145091,"endOffset":145178,"count":1}],"isBlockCoverage":true},{"functionName":"_SetBase","ranges":[{"startOffset":145194,"endOffset":145221,"count":0}],"isBlockCoverage":false},{"functionName":"_ListBase_Object_ListMixin","ranges":[{"startOffset":145255,"endOffset":145300,"count":0}],"isBlockCoverage":false},{"functionName":"_UnmodifiableMapView_MapView__UnmodifiableMapMixin","ranges":[{"startOffset":145358,"endOffset":145427,"count":0}],"isBlockCoverage":false},{"functionName":"_parseJson","ranges":[{"startOffset":145445,"endOffset":145914,"count":1},{"startOffset":145555,"endOffset":145607,"count":0},{"startOffset":145686,"endOffset":145846,"count":0}],"isBlockCoverage":true},{"functionName":"_convertJsonToDartLazy","ranges":[{"startOffset":145944,"endOffset":146324,"count":1}],"isBlockCoverage":true},{"functionName":"Utf8Decoder__convertIntercepted","ranges":[{"startOffset":146363,"endOffset":146629,"count":1},{"startOffset":146529,"endOffset":146609,"count":0}],"isBlockCoverage":true},{"functionName":"Utf8Decoder__convertInterceptedUint8List","ranges":[{"startOffset":146677,"endOffset":147268,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__useTextDecoderChecked","ranges":[{"startOffset":147310,"endOffset":147479,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__useTextDecoderUnchecked","ranges":[{"startOffset":147523,"endOffset":147743,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__unsafe","ranges":[{"startOffset":147770,"endOffset":148014,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__makeDecoder","ranges":[{"startOffset":148046,"endOffset":148262,"count":0}],"isBlockCoverage":false},{"functionName":"_scanOneByteCharacters","ranges":[{"startOffset":148292,"endOffset":148695,"count":1},{"startOffset":148570,"endOffset":148589,"count":0},{"startOffset":148635,"endOffset":148651,"count":0}],"isBlockCoverage":true},{"functionName":"Base64Codec__checkPadding","ranges":[{"startOffset":148728,"endOffset":149339,"count":0}],"isBlockCoverage":false},{"functionName":"JsonUnsupportedObjectError$","ranges":[{"startOffset":149374,"endOffset":149504,"count":0}],"isBlockCoverage":false},{"functionName":"_defaultToEncodable","ranges":[{"startOffset":149531,"endOffset":149587,"count":0}],"isBlockCoverage":false},{"functionName":"_JsonStringStringifier_stringify","ranges":[{"startOffset":149627,"endOffset":149885,"count":1},{"startOffset":149869,"endOffset":149873,"count":0}],"isBlockCoverage":true},{"functionName":"_JsonStringStringifier_printOn","ranges":[{"startOffset":149923,"endOffset":150125,"count":1}],"isBlockCoverage":true},{"functionName":"_JsonMap","ranges":[{"startOffset":150141,"endOffset":150254,"count":1}],"isBlockCoverage":true},{"functionName":"_JsonMapKeyIterable","ranges":[{"startOffset":150281,"endOffset":150355,"count":0}],"isBlockCoverage":false},{"functionName":"AsciiCodec","ranges":[{"startOffset":150373,"endOffset":150435,"count":1}],"isBlockCoverage":true},{"functionName":"_UnicodeSubsetEncoder","ranges":[{"startOffset":150464,"endOffset":150504,"count":0}],"isBlockCoverage":false},{"functionName":"AsciiEncoder","ranges":[{"startOffset":150524,"endOffset":150586,"count":1}],"isBlockCoverage":true},{"functionName":"Base64Codec","ranges":[{"startOffset":150605,"endOffset":150663,"count":1}],"isBlockCoverage":true},{"functionName":"Base64Encoder","ranges":[{"startOffset":150684,"endOffset":150744,"count":1}],"isBlockCoverage":true},{"functionName":"Codec","ranges":[{"startOffset":150757,"endOffset":150781,"count":0}],"isBlockCoverage":false},{"functionName":"_FusedCodec","ranges":[{"startOffset":150800,"endOffset":150919,"count":0}],"isBlockCoverage":false},{"functionName":"Converter","ranges":[{"startOffset":150936,"endOffset":150964,"count":0}],"isBlockCoverage":false},{"functionName":"Encoding","ranges":[{"startOffset":150980,"endOffset":151007,"count":0}],"isBlockCoverage":false},{"functionName":"JsonUnsupportedObjectError","ranges":[{"startOffset":151041,"endOffset":151150,"count":0}],"isBlockCoverage":false},{"functionName":"JsonCyclicError","ranges":[{"startOffset":151173,"endOffset":151271,"count":0}],"isBlockCoverage":false},{"functionName":"JsonCodec","ranges":[{"startOffset":151288,"endOffset":151378,"count":1}],"isBlockCoverage":true},{"functionName":"JsonEncoder","ranges":[{"startOffset":151397,"endOffset":151487,"count":1}],"isBlockCoverage":true},{"functionName":"JsonDecoder","ranges":[{"startOffset":151506,"endOffset":151564,"count":1}],"isBlockCoverage":true},{"functionName":"_JsonStringifier","ranges":[{"startOffset":151588,"endOffset":151623,"count":0}],"isBlockCoverage":false},{"functionName":"_JsonStringifier_writeMap_closure","ranges":[{"startOffset":151664,"endOffset":151776,"count":1}],"isBlockCoverage":true},{"functionName":"_JsonStringStringifier","ranges":[{"startOffset":151806,"endOffset":151942,"count":1}],"isBlockCoverage":true},{"functionName":"Utf8Codec","ranges":[{"startOffset":151959,"endOffset":152022,"count":1}],"isBlockCoverage":true},{"functionName":"Utf8Encoder","ranges":[{"startOffset":152041,"endOffset":152071,"count":1}],"isBlockCoverage":true},{"functionName":"_Utf8Encoder","ranges":[{"startOffset":152091,"endOffset":152192,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder","ranges":[{"startOffset":152211,"endOffset":152276,"count":1}],"isBlockCoverage":true},{"functionName":"_Utf8Decoder","ranges":[{"startOffset":152296,"endOffset":152498,"count":1}],"isBlockCoverage":true},{"functionName":"_Utf8Decoder_convert_addSingleBytes","ranges":[{"startOffset":152541,"endOffset":152721,"count":1}],"isBlockCoverage":true},{"functionName":"int_parse","ranges":[{"startOffset":152738,"endOffset":153106,"count":1},{"startOffset":152965,"endOffset":153105,"count":0}],"isBlockCoverage":true},{"functionName":"Error__objectToString","ranges":[{"startOffset":153135,"endOffset":153309,"count":0}],"isBlockCoverage":false},{"functionName":"List_List$filled","ranges":[{"startOffset":153333,"endOffset":153687,"count":0}],"isBlockCoverage":false},{"functionName":"List_List$from","ranges":[{"startOffset":153709,"endOffset":154115,"count":0}],"isBlockCoverage":false},{"functionName":"List_List$unmodifiable","ranges":[{"startOffset":154145,"endOffset":154366,"count":0}],"isBlockCoverage":false},{"functionName":"String_String$fromCharCodes","ranges":[{"startOffset":154401,"endOffset":155216,"count":1},{"startOffset":154876,"endOffset":154928,"count":0},{"startOffset":154950,"endOffset":155215,"count":0}],"isBlockCoverage":true},{"functionName":"String_String$fromCharCode","ranges":[{"startOffset":155250,"endOffset":155332,"count":0}],"isBlockCoverage":false},{"functionName":"String__stringFromIterable","ranges":[{"startOffset":155366,"endOffset":156339,"count":0}],"isBlockCoverage":false},{"functionName":"RegExp_RegExp","ranges":[{"startOffset":156360,"endOffset":156499,"count":0}],"isBlockCoverage":false},{"functionName":"StringBuffer__writeAll","ranges":[{"startOffset":156529,"endOffset":157013,"count":0}],"isBlockCoverage":false},{"functionName":"NoSuchMethodError$","ranges":[{"startOffset":157039,"endOffset":157217,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_base","ranges":[{"startOffset":157233,"endOffset":157431,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__uriEncode","ranges":[{"startOffset":157454,"endOffset":158643,"count":0}],"isBlockCoverage":false},{"functionName":"DateTime__fourDigits","ranges":[{"startOffset":158671,"endOffset":158964,"count":0}],"isBlockCoverage":false},{"functionName":"DateTime__threeDigits","ranges":[{"startOffset":158993,"endOffset":159121,"count":0}],"isBlockCoverage":false},{"functionName":"DateTime__twoDigits","ranges":[{"startOffset":159148,"endOffset":159231,"count":0}],"isBlockCoverage":false},{"functionName":"Duration$","ranges":[{"startOffset":159248,"endOffset":159321,"count":1}],"isBlockCoverage":true},{"functionName":"Error_safeToString","ranges":[{"startOffset":159347,"endOffset":159619,"count":0}],"isBlockCoverage":false},{"functionName":"ArgumentError$","ranges":[{"startOffset":159641,"endOffset":159728,"count":0}],"isBlockCoverage":false},{"functionName":"ArgumentError$value","ranges":[{"startOffset":159755,"endOffset":159857,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError$value","ranges":[{"startOffset":159881,"endOffset":159996,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError$range","ranges":[{"startOffset":160020,"endOffset":160181,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError_checkValueInInterval","ranges":[{"startOffset":160220,"endOffset":160409,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError_checkValidRange","ranges":[{"startOffset":160443,"endOffset":160875,"count":1},{"startOffset":160520,"endOffset":160540,"count":0},{"startOffset":160589,"endOffset":160665,"count":0},{"startOffset":160743,"endOffset":160819,"count":0}],"isBlockCoverage":true},{"functionName":"RangeError_checkNotNegative","ranges":[{"startOffset":160910,"endOffset":161106,"count":0}],"isBlockCoverage":false},{"functionName":"IndexError$","ranges":[{"startOffset":161125,"endOffset":161363,"count":0}],"isBlockCoverage":false},{"functionName":"UnsupportedError$","ranges":[{"startOffset":161388,"endOffset":161459,"count":0}],"isBlockCoverage":false},{"functionName":"UnimplementedError$","ranges":[{"startOffset":161486,"endOffset":161559,"count":0}],"isBlockCoverage":false},{"functionName":"StateError$","ranges":[{"startOffset":161578,"endOffset":161643,"count":0}],"isBlockCoverage":false},{"functionName":"ConcurrentModificationError$","ranges":[{"startOffset":161679,"endOffset":161775,"count":0}],"isBlockCoverage":false},{"functionName":"FormatException$","ranges":[{"startOffset":161799,"endOffset":161901,"count":0}],"isBlockCoverage":false},{"functionName":"List_List$generate","ranges":[{"startOffset":161927,"endOffset":162297,"count":1}],"isBlockCoverage":true},{"functionName":"Uri_parse","ranges":[{"startOffset":162314,"endOffset":168453,"count":1},{"startOffset":162832,"endOffset":162938,"count":0},{"startOffset":162980,"endOffset":163068,"count":0},{"startOffset":163649,"endOffset":163694,"count":0},{"startOffset":163774,"endOffset":163797,"count":0},{"startOffset":163894,"endOffset":163917,"count":0},{"startOffset":163983,"endOffset":164000,"count":0},{"startOffset":164205,"endOffset":164232,"count":0},{"startOffset":164283,"endOffset":164308,"count":0},{"startOffset":164355,"endOffset":164382,"count":0},{"startOffset":164432,"endOffset":164455,"count":0},{"startOffset":164497,"endOffset":164520,"count":0},{"startOffset":164568,"endOffset":164594,"count":0},{"startOffset":164644,"endOffset":164667,"count":0},{"startOffset":164709,"endOffset":164731,"count":0},{"startOffset":164797,"endOffset":164813,"count":0},{"startOffset":164867,"endOffset":167872,"count":0},{"startOffset":167927,"endOffset":168319,"count":0}],"isBlockCoverage":true},{"functionName":"Uri_decodeComponent","ranges":[{"startOffset":168480,"endOffset":168661,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_splitQueryString","ranges":[{"startOffset":168689,"endOffset":168954,"count":1}],"isBlockCoverage":true},{"functionName":"Uri__parseIPv4Address","ranges":[{"startOffset":168983,"endOffset":170538,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_parseIPv6Address","ranges":[{"startOffset":170566,"endOffset":173975,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__Uri$notSimple","ranges":[{"startOffset":174002,"endOffset":175800,"count":1},{"startOffset":174254,"endOffset":174277,"count":0},{"startOffset":174370,"endOffset":174515,"count":0},{"startOffset":174608,"endOffset":174632,"count":0},{"startOffset":174717,"endOffset":174774,"count":0},{"startOffset":174901,"endOffset":174925,"count":0},{"startOffset":175007,"endOffset":175031,"count":0},{"startOffset":175196,"endOffset":175202,"count":0},{"startOffset":175211,"endOffset":175291,"count":0},{"startOffset":175429,"endOffset":175453,"count":0},{"startOffset":175507,"endOffset":175535,"count":0},{"startOffset":175639,"endOffset":175645,"count":0},{"startOffset":175734,"endOffset":175785,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__Uri","ranges":[{"startOffset":175817,"endOffset":177057,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__defaultPort","ranges":[{"startOffset":177082,"endOffset":177220,"count":1},{"startOffset":177148,"endOffset":177219,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__fail","ranges":[{"startOffset":177238,"endOffset":177345,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__Uri$file","ranges":[{"startOffset":177367,"endOffset":177497,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__checkNonWindowsPathReservedCharacters","ranges":[{"startOffset":177548,"endOffset":177751,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__checkWindowsPathReservedCharacters","ranges":[{"startOffset":177799,"endOffset":178489,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__checkWindowsDriveLetter","ranges":[{"startOffset":178526,"endOffset":179005,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeFileUri","ranges":[{"startOffset":179030,"endOffset":179320,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeWindowsFileUrl","ranges":[{"startOffset":179352,"endOffset":181689,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makePort","ranges":[{"startOffset":181711,"endOffset":181840,"count":1},{"startOffset":181808,"endOffset":181815,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__makeHost","ranges":[{"startOffset":181862,"endOffset":182764,"count":1},{"startOffset":181952,"endOffset":181959,"count":0},{"startOffset":181993,"endOffset":182003,"count":0},{"startOffset":182067,"endOffset":182435,"count":0},{"startOffset":182479,"endOffset":182497,"count":0},{"startOffset":182603,"endOffset":182701,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__normalizeRegName","ranges":[{"startOffset":182794,"endOffset":186280,"count":1},{"startOffset":182973,"endOffset":182991,"count":0},{"startOffset":183204,"endOffset":184074,"count":0},{"startOffset":184178,"endOffset":184209,"count":0},{"startOffset":184281,"endOffset":184310,"count":0},{"startOffset":184389,"endOffset":184714,"count":0},{"startOffset":184747,"endOffset":185904,"count":0},{"startOffset":186013,"endOffset":186268,"count":0},{"startOffset":186269,"endOffset":186273,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__makeScheme","ranges":[{"startOffset":186304,"endOffset":187376,"count":1},{"startOffset":186414,"endOffset":186424,"count":0},{"startOffset":186532,"endOffset":186609,"count":0},{"startOffset":186653,"endOffset":186671,"count":0},{"startOffset":186911,"endOffset":186942,"count":0},{"startOffset":187014,"endOffset":187041,"count":0},{"startOffset":187069,"endOffset":187121,"count":0},{"startOffset":187178,"endOffset":187203,"count":0},{"startOffset":187337,"endOffset":187359,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__canonicalizeScheme","ranges":[{"startOffset":187408,"endOffset":187669,"count":1},{"startOffset":187478,"endOffset":187668,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__makeUserInfo","ranges":[{"startOffset":187695,"endOffset":187864,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makePath","ranges":[{"startOffset":187886,"endOffset":189059,"count":1},{"startOffset":188222,"endOffset":188245,"count":0},{"startOffset":188255,"endOffset":188280,"count":0},{"startOffset":188343,"endOffset":188423,"count":0},{"startOffset":188520,"endOffset":188795,"count":0},{"startOffset":188827,"endOffset":188878,"count":0},{"startOffset":188965,"endOffset":188987,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__normalizePath","ranges":[{"startOffset":189086,"endOffset":189363,"count":1},{"startOffset":189174,"endOffset":189190,"count":0},{"startOffset":189191,"endOffset":189237,"count":0},{"startOffset":189247,"endOffset":189311,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__makeQuery","ranges":[{"startOffset":189386,"endOffset":189559,"count":1},{"startOffset":189539,"endOffset":189558,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__makeFragment","ranges":[{"startOffset":189585,"endOffset":189750,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalizeEscape","ranges":[{"startOffset":189779,"endOffset":190943,"count":1},{"startOffset":189942,"endOffset":189962,"count":0},{"startOffset":190024,"endOffset":190035,"count":0},{"startOffset":190351,"endOffset":190362,"count":0},{"startOffset":190534,"endOffset":190565,"count":0},{"startOffset":190630,"endOffset":190655,"count":0},{"startOffset":190678,"endOffset":190787,"count":0},{"startOffset":190845,"endOffset":190923,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__escapeChar","ranges":[{"startOffset":190967,"endOffset":192472,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalizeOrSubstring","ranges":[{"startOffset":192506,"endOffset":192779,"count":1},{"startOffset":192768,"endOffset":192772,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__normalize","ranges":[{"startOffset":192802,"endOffset":196002,"count":1},{"startOffset":193232,"endOffset":193251,"count":0},{"startOffset":193299,"endOffset":193317,"count":0},{"startOffset":193526,"endOffset":193556,"count":0},{"startOffset":193627,"endOffset":193656,"count":0},{"startOffset":193933,"endOffset":194100,"count":0},{"startOffset":194114,"endOffset":195678,"count":0},{"startOffset":195738,"endOffset":195990,"count":0},{"startOffset":195991,"endOffset":195995,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__mayContainDotSegments","ranges":[{"startOffset":196037,"endOffset":196202,"count":1},{"startOffset":196122,"endOffset":196134,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__removeDotSegments","ranges":[{"startOffset":196233,"endOffset":197172,"count":1},{"startOffset":196374,"endOffset":197171,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__normalizeRelativePath","ranges":[{"startOffset":197207,"endOffset":198750,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__escapeScheme","ranges":[{"startOffset":198776,"endOffset":199463,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__toWindowsFilePath","ranges":[{"startOffset":199494,"endOffset":200490,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__hexCharPairToByte","ranges":[{"startOffset":200521,"endOffset":201052,"count":1},{"startOffset":200917,"endOffset":201009,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__uriDecode","ranges":[{"startOffset":201075,"endOffset":202742,"count":1},{"startOffset":201518,"endOffset":201552,"count":0},{"startOffset":201719,"endOffset":201730,"count":0},{"startOffset":201831,"endOffset":201913,"count":0},{"startOffset":202110,"endOffset":202185,"count":0},{"startOffset":202270,"endOffset":202327,"count":0},{"startOffset":202497,"endOffset":202532,"count":0}],"isBlockCoverage":true},{"functionName":"_Uri__isAlphabeticCharacter","ranges":[{"startOffset":202777,"endOffset":202890,"count":1}],"isBlockCoverage":true},{"functionName":"UriData__writeUri","ranges":[{"startOffset":202915,"endOffset":203591,"count":0}],"isBlockCoverage":false},{"functionName":"UriData__validateMimeType","ranges":[{"startOffset":203624,"endOffset":203975,"count":0}],"isBlockCoverage":false},{"functionName":"UriData__parse","ranges":[{"startOffset":203997,"endOffset":205905,"count":0}],"isBlockCoverage":false},{"functionName":"UriData__uriEncodeBytes","ranges":[{"startOffset":205936,"endOffset":207460,"count":0}],"isBlockCoverage":false},{"functionName":"_createTables","ranges":[{"startOffset":207481,"endOffset":213521,"count":1}],"isBlockCoverage":true},{"functionName":"_scan","ranges":[{"startOffset":213534,"endOffset":214326,"count":1},{"startOffset":213774,"endOffset":213792,"count":0},{"startOffset":213934,"endOffset":213964,"count":0},{"startOffset":214075,"endOffset":214085,"count":0},{"startOffset":214130,"endOffset":214158,"count":0}],"isBlockCoverage":true},{"functionName":"NoSuchMethodError_toString_closure","ranges":[{"startOffset":214368,"endOffset":214471,"count":0}],"isBlockCoverage":false},{"functionName":"bool","ranges":[{"startOffset":214483,"endOffset":214506,"count":0}],"isBlockCoverage":false},{"functionName":"DateTime","ranges":[{"startOffset":214522,"endOffset":214608,"count":0}],"isBlockCoverage":false},{"functionName":"double","ranges":[{"startOffset":214622,"endOffset":214647,"count":0}],"isBlockCoverage":false},{"functionName":"Duration","ranges":[{"startOffset":214663,"endOffset":214719,"count":1}],"isBlockCoverage":true},{"functionName":"Duration_toString_sixDigits","ranges":[{"startOffset":214754,"endOffset":214800,"count":0}],"isBlockCoverage":false},{"functionName":"Duration_toString_twoDigits","ranges":[{"startOffset":214835,"endOffset":214881,"count":0}],"isBlockCoverage":false},{"functionName":"Error","ranges":[{"startOffset":214894,"endOffset":214918,"count":0}],"isBlockCoverage":false},{"functionName":"NullThrownError","ranges":[{"startOffset":214941,"endOffset":214975,"count":0}],"isBlockCoverage":false},{"functionName":"ArgumentError","ranges":[{"startOffset":214996,"endOffset":215154,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError","ranges":[{"startOffset":215172,"endOffset":215373,"count":0}],"isBlockCoverage":false},{"functionName":"IndexError","ranges":[{"startOffset":215391,"endOffset":215571,"count":0}],"isBlockCoverage":false},{"functionName":"NoSuchMethodError","ranges":[{"startOffset":215596,"endOffset":215830,"count":0}],"isBlockCoverage":false},{"functionName":"UnsupportedError","ranges":[{"startOffset":215854,"endOffset":215916,"count":0}],"isBlockCoverage":false},{"functionName":"UnimplementedError","ranges":[{"startOffset":215942,"endOffset":216006,"count":0}],"isBlockCoverage":false},{"functionName":"StateError","ranges":[{"startOffset":216024,"endOffset":216080,"count":0}],"isBlockCoverage":false},{"functionName":"ConcurrentModificationError","ranges":[{"startOffset":216115,"endOffset":216195,"count":0}],"isBlockCoverage":false},{"functionName":"OutOfMemoryError","ranges":[{"startOffset":216219,"endOffset":216254,"count":1}],"isBlockCoverage":true},{"functionName":"StackOverflowError","ranges":[{"startOffset":216280,"endOffset":216317,"count":0}],"isBlockCoverage":false},{"functionName":"CyclicInitializationError","ranges":[{"startOffset":216350,"endOffset":216426,"count":0}],"isBlockCoverage":false},{"functionName":"_Exception","ranges":[{"startOffset":216444,"endOffset":216500,"count":0}],"isBlockCoverage":false},{"functionName":"FormatException","ranges":[{"startOffset":216523,"endOffset":216640,"count":0}],"isBlockCoverage":false},{"functionName":"Function","ranges":[{"startOffset":216656,"endOffset":216683,"count":0}],"isBlockCoverage":false},{"functionName":"int","ranges":[{"startOffset":216694,"endOffset":216716,"count":0}],"isBlockCoverage":false},{"functionName":"Iterable","ranges":[{"startOffset":216732,"endOffset":216759,"count":0}],"isBlockCoverage":false},{"functionName":"Iterator","ranges":[{"startOffset":216775,"endOffset":216802,"count":0}],"isBlockCoverage":false},{"functionName":"List","ranges":[{"startOffset":216814,"endOffset":216837,"count":0}],"isBlockCoverage":false},{"functionName":"Map","ranges":[{"startOffset":216848,"endOffset":216870,"count":0}],"isBlockCoverage":false},{"functionName":"Null","ranges":[{"startOffset":216882,"endOffset":216905,"count":0}],"isBlockCoverage":false},{"functionName":"num","ranges":[{"startOffset":216916,"endOffset":216938,"count":0}],"isBlockCoverage":false},{"functionName":"Object","ranges":[{"startOffset":216952,"endOffset":216977,"count":0}],"isBlockCoverage":true},{"functionName":"Match","ranges":[{"startOffset":216990,"endOffset":217014,"count":0}],"isBlockCoverage":false},{"functionName":"StackTrace","ranges":[{"startOffset":217032,"endOffset":217061,"count":0}],"isBlockCoverage":false},{"functionName":"_StringStackTrace","ranges":[{"startOffset":217086,"endOffset":217153,"count":0}],"isBlockCoverage":false},{"functionName":"String","ranges":[{"startOffset":217167,"endOffset":217192,"count":0}],"isBlockCoverage":false},{"functionName":"StringBuffer","ranges":[{"startOffset":217212,"endOffset":217272,"count":1}],"isBlockCoverage":true},{"functionName":"Symbol0","ranges":[{"startOffset":217287,"endOffset":217313,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_splitQueryString_closure","ranges":[{"startOffset":217349,"endOffset":217424,"count":1}],"isBlockCoverage":true},{"functionName":"Uri__parseIPv4Address_error","ranges":[{"startOffset":217459,"endOffset":217529,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_parseIPv6Address_error","ranges":[{"startOffset":217563,"endOffset":217632,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_parseIPv6Address_parseHex","ranges":[{"startOffset":217669,"endOffset":217768,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri","ranges":[{"startOffset":217780,"endOffset":218078,"count":1}],"isBlockCoverage":true},{"functionName":"_Uri__Uri$notSimple_closure","ranges":[{"startOffset":218113,"endOffset":218213,"count":1}],"isBlockCoverage":true},{"functionName":"_Uri__checkNonWindowsPathReservedCharacters_closure","ranges":[{"startOffset":218272,"endOffset":218375,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makePath_closure","ranges":[{"startOffset":218405,"endOffset":218446,"count":0}],"isBlockCoverage":false},{"functionName":"UriData","ranges":[{"startOffset":218461,"endOffset":218582,"count":0}],"isBlockCoverage":false},{"functionName":"_createTables_closure","ranges":[{"startOffset":218611,"endOffset":218651,"count":1}],"isBlockCoverage":true},{"functionName":"_createTables_build","ranges":[{"startOffset":218678,"endOffset":218742,"count":1}],"isBlockCoverage":true},{"functionName":"_createTables_setChars","ranges":[{"startOffset":218772,"endOffset":218813,"count":1}],"isBlockCoverage":true},{"functionName":"_createTables_setRange","ranges":[{"startOffset":218843,"endOffset":218884,"count":1}],"isBlockCoverage":true},{"functionName":"_SimpleUri","ranges":[{"startOffset":218902,"endOffset":219213,"count":0}],"isBlockCoverage":false},{"functionName":"_DataUri","ranges":[{"startOffset":219229,"endOffset":219531,"count":0}],"isBlockCoverage":false},{"functionName":"convertNativePromiseToDartFuture","ranges":[{"startOffset":219571,"endOffset":219951,"count":0}],"isBlockCoverage":false},{"functionName":"_StructuredClone","ranges":[{"startOffset":219975,"endOffset":220010,"count":0}],"isBlockCoverage":false},{"functionName":"_StructuredClone_walk_closure","ranges":[{"startOffset":220047,"endOffset":220148,"count":1}],"isBlockCoverage":true},{"functionName":"_AcceptStructuredClone","ranges":[{"startOffset":220178,"endOffset":220219,"count":0}],"isBlockCoverage":false},{"functionName":"_AcceptStructuredClone_walk_closure","ranges":[{"startOffset":220262,"endOffset":220369,"count":1}],"isBlockCoverage":true},{"functionName":"_StructuredCloneDart2Js","ranges":[{"startOffset":220400,"endOffset":220496,"count":1}],"isBlockCoverage":true},{"functionName":"_AcceptStructuredCloneDart2Js","ranges":[{"startOffset":220533,"endOffset":220664,"count":1}],"isBlockCoverage":true},{"functionName":"convertNativePromiseToDartFuture_closure","ranges":[{"startOffset":220712,"endOffset":220800,"count":0}],"isBlockCoverage":false},{"functionName":"convertNativePromiseToDartFuture_closure0","ranges":[{"startOffset":220849,"endOffset":220938,"count":0}],"isBlockCoverage":false},{"functionName":"SvgElement","ranges":[{"startOffset":220956,"endOffset":220985,"count":0}],"isBlockCoverage":false},{"functionName":"Uint8List","ranges":[{"startOffset":221002,"endOffset":221030,"count":0}],"isBlockCoverage":false},{"functionName":"_convertDartFunctionFast","ranges":[{"startOffset":221062,"endOffset":221474,"count":1},{"startOffset":221174,"endOffset":221190,"count":0}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":221203,"endOffset":221337,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":221239,"endOffset":221328,"count":0}],"isBlockCoverage":false},{"functionName":"_callDartFunctionFast","ranges":[{"startOffset":221503,"endOffset":221700,"count":0}],"isBlockCoverage":false},{"functionName":"allowInterop","ranges":[{"startOffset":221720,"endOffset":222089,"count":1},{"startOffset":221983,"endOffset":221992,"count":0}],"isBlockCoverage":true},{"functionName":"max","ranges":[{"startOffset":222100,"endOffset":222411,"count":0}],"isBlockCoverage":false},{"functionName":"window","ranges":[{"startOffset":222437,"endOffset":222476,"count":1}],"isBlockCoverage":true},{"functionName":"WebSocket_WebSocket","ranges":[{"startOffset":222503,"endOffset":222557,"count":1}],"isBlockCoverage":true},{"functionName":"_EventStreamSubscription$","ranges":[{"startOffset":222590,"endOffset":222884,"count":1},{"startOffset":222677,"endOffset":222683,"count":0}],"isBlockCoverage":true},{"functionName":"_convertNativeToDart_Window","ranges":[{"startOffset":222919,"endOffset":223033,"count":1},{"startOffset":222966,"endOffset":222973,"count":0}],"isBlockCoverage":true},{"functionName":"_DOMWindowCrossFrame__createSafe","ranges":[{"startOffset":223073,"endOffset":223232,"count":1},{"startOffset":223119,"endOffset":223169,"count":0}],"isBlockCoverage":true},{"functionName":"_wrapZone","ranges":[{"startOffset":223249,"endOffset":223507,"count":1},{"startOffset":223425,"endOffset":223441,"count":0}],"isBlockCoverage":true},{"functionName":"HtmlElement","ranges":[{"startOffset":223526,"endOffset":223556,"count":0}],"isBlockCoverage":false},{"functionName":"AnchorElement","ranges":[{"startOffset":223577,"endOffset":223609,"count":0}],"isBlockCoverage":false},{"functionName":"AreaElement","ranges":[{"startOffset":223628,"endOffset":223658,"count":0}],"isBlockCoverage":false},{"functionName":"Blob","ranges":[{"startOffset":223670,"endOffset":223693,"count":0}],"isBlockCoverage":false},{"functionName":"CharacterData","ranges":[{"startOffset":223714,"endOffset":223746,"count":0}],"isBlockCoverage":false},{"functionName":"DomException","ranges":[{"startOffset":223766,"endOffset":223797,"count":0}],"isBlockCoverage":false},{"functionName":"DomTokenList","ranges":[{"startOffset":223817,"endOffset":223848,"count":0}],"isBlockCoverage":false},{"functionName":"Element","ranges":[{"startOffset":223863,"endOffset":223889,"count":0}],"isBlockCoverage":false},{"functionName":"Event","ranges":[{"startOffset":223902,"endOffset":223926,"count":0}],"isBlockCoverage":false},{"functionName":"EventTarget","ranges":[{"startOffset":223945,"endOffset":223975,"count":0}],"isBlockCoverage":false},{"functionName":"File","ranges":[{"startOffset":223987,"endOffset":224010,"count":0}],"isBlockCoverage":false},{"functionName":"FormElement","ranges":[{"startOffset":224029,"endOffset":224059,"count":0}],"isBlockCoverage":false},{"functionName":"HtmlCollection","ranges":[{"startOffset":224081,"endOffset":224114,"count":0}],"isBlockCoverage":false},{"functionName":"IFrameElement","ranges":[{"startOffset":224135,"endOffset":224167,"count":0}],"isBlockCoverage":false},{"functionName":"Location","ranges":[{"startOffset":224183,"endOffset":224210,"count":0}],"isBlockCoverage":false},{"functionName":"MessageEvent","ranges":[{"startOffset":224230,"endOffset":224261,"count":0}],"isBlockCoverage":false},{"functionName":"MessagePort","ranges":[{"startOffset":224280,"endOffset":224310,"count":0}],"isBlockCoverage":false},{"functionName":"MouseEvent","ranges":[{"startOffset":224328,"endOffset":224357,"count":0}],"isBlockCoverage":false},{"functionName":"Node","ranges":[{"startOffset":224369,"endOffset":224392,"count":0}],"isBlockCoverage":false},{"functionName":"SelectElement","ranges":[{"startOffset":224413,"endOffset":224445,"count":0}],"isBlockCoverage":false},{"functionName":"UIEvent","ranges":[{"startOffset":224460,"endOffset":224486,"count":0}],"isBlockCoverage":false},{"functionName":"Window","ranges":[{"startOffset":224500,"endOffset":224525,"count":0}],"isBlockCoverage":false},{"functionName":"_EventStream","ranges":[{"startOffset":224545,"endOffset":224707,"count":0}],"isBlockCoverage":false},{"functionName":"_ElementEventStreamImpl","ranges":[{"startOffset":224738,"endOffset":224911,"count":1}],"isBlockCoverage":true},{"functionName":"_EventStreamSubscription","ranges":[{"startOffset":224943,"endOffset":225168,"count":1}],"isBlockCoverage":true},{"functionName":"_EventStreamSubscription_closure","ranges":[{"startOffset":225208,"endOffset":225285,"count":1}],"isBlockCoverage":true},{"functionName":"ImmutableListMixin","ranges":[{"startOffset":225311,"endOffset":225348,"count":0}],"isBlockCoverage":false},{"functionName":"FixedSizeListIterator","ranges":[{"startOffset":225377,"endOffset":225561,"count":0}],"isBlockCoverage":false},{"functionName":"_DOMWindowCrossFrame","ranges":[{"startOffset":225589,"endOffset":225655,"count":1}],"isBlockCoverage":true},{"functionName":"_HtmlCollection_Interceptor_ListMixin","ranges":[{"startOffset":225700,"endOffset":225756,"count":0}],"isBlockCoverage":false},{"functionName":"_HtmlCollection_Interceptor_ListMixin_ImmutableListMixin","ranges":[{"startOffset":225820,"endOffset":225895,"count":0}],"isBlockCoverage":false},{"functionName":"NullStreamSink","ranges":[{"startOffset":225924,"endOffset":226081,"count":0}],"isBlockCoverage":false},{"functionName":"NullStreamSink_addStream_closure","ranges":[{"startOffset":226117,"endOffset":226193,"count":0}],"isBlockCoverage":false},{"functionName":"Context_Context","ranges":[{"startOffset":226225,"endOffset":226413,"count":0}],"isBlockCoverage":false},{"functionName":"_parseUri","ranges":[{"startOffset":226430,"endOffset":226613,"count":0}],"isBlockCoverage":false},{"functionName":"_validateArgList","ranges":[{"startOffset":226637,"endOffset":227693,"count":0}],"isBlockCoverage":false},{"functionName":"Context","ranges":[{"startOffset":227708,"endOffset":227798,"count":0}],"isBlockCoverage":false},{"functionName":"Context_join_closure","ranges":[{"startOffset":227826,"endOffset":227865,"count":0}],"isBlockCoverage":false},{"functionName":"Context_joinAll_closure","ranges":[{"startOffset":227896,"endOffset":227938,"count":0}],"isBlockCoverage":false},{"functionName":"Context_split_closure","ranges":[{"startOffset":227967,"endOffset":228007,"count":0}],"isBlockCoverage":false},{"functionName":"_validateArgList_closure","ranges":[{"startOffset":228039,"endOffset":228082,"count":0}],"isBlockCoverage":false},{"functionName":"InternalStyle","ranges":[{"startOffset":228110,"endOffset":228142,"count":0}],"isBlockCoverage":false},{"functionName":"StreamChannelController$","ranges":[{"startOffset":228174,"endOffset":228991,"count":1}],"isBlockCoverage":true},{"functionName":"StreamChannelController","ranges":[{"startOffset":229022,"endOffset":229129,"count":1}],"isBlockCoverage":true},{"functionName":"isAlphabetic","ranges":[{"startOffset":229149,"endOffset":229311,"count":0}],"isBlockCoverage":false},{"functionName":"isDriveLetter","ranges":[{"startOffset":229332,"endOffset":229761,"count":0}],"isBlockCoverage":false},{"functionName":"ParsedPath_ParsedPath$parse","ranges":[{"startOffset":229808,"endOffset":231004,"count":0}],"isBlockCoverage":false},{"functionName":"ParsedPath","ranges":[{"startOffset":231022,"endOffset":231169,"count":0}],"isBlockCoverage":false},{"functionName":"ParsedPath_normalize_closure","ranges":[{"startOffset":231205,"endOffset":231277,"count":0}],"isBlockCoverage":false},{"functionName":"PathException$","ranges":[{"startOffset":231299,"endOffset":231367,"count":0}],"isBlockCoverage":false},{"functionName":"PathException","ranges":[{"startOffset":231388,"endOffset":231447,"count":0}],"isBlockCoverage":false},{"functionName":"Style__getPlatformStyle","ranges":[{"startOffset":231490,"endOffset":231852,"count":0}],"isBlockCoverage":false},{"functionName":"Style","ranges":[{"startOffset":231865,"endOffset":231889,"count":0}],"isBlockCoverage":false},{"functionName":"PosixStyle","ranges":[{"startOffset":231914,"endOffset":231998,"count":0}],"isBlockCoverage":false},{"functionName":"UrlStyle","ranges":[{"startOffset":232018,"endOffset":232098,"count":0}],"isBlockCoverage":false},{"functionName":"WindowsStyle","ranges":[{"startOffset":232122,"endOffset":232211,"count":0}],"isBlockCoverage":false},{"functionName":"WindowsStyle_absolutePathToUri_closure","ranges":[{"startOffset":232253,"endOffset":232310,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_Chain$parse","ranges":[{"startOffset":232344,"endOffset":233600,"count":0}],"isBlockCoverage":false},{"functionName":"Chain","ranges":[{"startOffset":233613,"endOffset":233663,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_Chain$parse_closure","ranges":[{"startOffset":233696,"endOffset":233740,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_Chain$parse_closure0","ranges":[{"startOffset":233774,"endOffset":233819,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toTrace_closure","ranges":[{"startOffset":233848,"endOffset":233888,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toString_closure0","ranges":[{"startOffset":233919,"endOffset":233961,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toString__closure0","ranges":[{"startOffset":233993,"endOffset":234036,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toString_closure","ranges":[{"startOffset":234066,"endOffset":234134,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toString__closure","ranges":[{"startOffset":234165,"endOffset":234234,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseVM","ranges":[{"startOffset":234273,"endOffset":234389,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseV8","ranges":[{"startOffset":234416,"endOffset":234532,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseFirefox","ranges":[{"startOffset":234564,"endOffset":234685,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseFriendly","ranges":[{"startOffset":234718,"endOffset":234840,"count":0}],"isBlockCoverage":false},{"functionName":"Frame__uriOrPathToUri","ranges":[{"startOffset":234869,"endOffset":235427,"count":0}],"isBlockCoverage":false},{"functionName":"Frame__catchFormatException","ranges":[{"startOffset":235462,"endOffset":235866,"count":0}],"isBlockCoverage":false},{"functionName":"Frame","ranges":[{"startOffset":235879,"endOffset":236016,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseVM_closure","ranges":[{"startOffset":236051,"endOffset":236122,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseV8_closure","ranges":[{"startOffset":236157,"endOffset":236228,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseV8_closure_parseLocation","ranges":[{"startOffset":236277,"endOffset":236362,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseFirefox_closure","ranges":[{"startOffset":236402,"endOffset":236478,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseFriendly_closure","ranges":[{"startOffset":236519,"endOffset":236596,"count":0}],"isBlockCoverage":false},{"functionName":"LazyTrace","ranges":[{"startOffset":236620,"endOffset":236712,"count":0}],"isBlockCoverage":false},{"functionName":"LazyTrace_terse_closure","ranges":[{"startOffset":236739,"endOffset":236806,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_Trace$from","ranges":[{"startOffset":236839,"endOffset":237153,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_Trace$parse","ranges":[{"startOffset":237178,"endOffset":238690,"count":0}],"isBlockCoverage":false},{"functionName":"Trace__parseVM","ranges":[{"startOffset":238712,"endOffset":239434,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseV8","ranges":[{"startOffset":239455,"endOffset":240083,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseJSCore","ranges":[{"startOffset":240108,"endOffset":240613,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFirefox","ranges":[{"startOffset":240639,"endOffset":241158,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFriendly","ranges":[{"startOffset":241185,"endOffset":241840,"count":0}],"isBlockCoverage":false},{"functionName":"Trace","ranges":[{"startOffset":241853,"endOffset":241933,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_Trace$from_closure","ranges":[{"startOffset":241965,"endOffset":242033,"count":0}],"isBlockCoverage":false},{"functionName":"Trace__parseVM_closure","ranges":[{"startOffset":242063,"endOffset":242104,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseV8_closure","ranges":[{"startOffset":242133,"endOffset":242173,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseV8_closure0","ranges":[{"startOffset":242203,"endOffset":242244,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseJSCore_closure","ranges":[{"startOffset":242277,"endOffset":242321,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseJSCore_closure0","ranges":[{"startOffset":242355,"endOffset":242400,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFirefox_closure","ranges":[{"startOffset":242434,"endOffset":242479,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFirefox_closure0","ranges":[{"startOffset":242514,"endOffset":242560,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFriendly_closure","ranges":[{"startOffset":242595,"endOffset":242641,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFriendly_closure0","ranges":[{"startOffset":242677,"endOffset":242724,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_terse_closure","ranges":[{"startOffset":242751,"endOffset":242789,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_foldFrames_closure","ranges":[{"startOffset":242821,"endOffset":242896,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_foldFrames_closure0","ranges":[{"startOffset":242929,"endOffset":242999,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_toString_closure0","ranges":[{"startOffset":243030,"endOffset":243072,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_toString_closure","ranges":[{"startOffset":243102,"endOffset":243170,"count":0}],"isBlockCoverage":false},{"functionName":"UnparsedFrame","ranges":[{"startOffset":243198,"endOffset":243437,"count":0}],"isBlockCoverage":false},{"functionName":"GuaranteeChannel$","ranges":[{"startOffset":243471,"endOffset":243729,"count":1}],"isBlockCoverage":true},{"functionName":"GuaranteeChannel","ranges":[{"startOffset":243753,"endOffset":243940,"count":1}],"isBlockCoverage":true},{"functionName":"GuaranteeChannel_closure","ranges":[{"startOffset":243972,"endOffset":244068,"count":1}],"isBlockCoverage":true},{"functionName":"GuaranteeChannel__closure","ranges":[{"startOffset":244101,"endOffset":244170,"count":1}],"isBlockCoverage":true},{"functionName":"_GuaranteeSink","ranges":[{"startOffset":244192,"endOffset":244487,"count":1}],"isBlockCoverage":true},{"functionName":"_GuaranteeSink_addStream_closure","ranges":[{"startOffset":244527,"endOffset":244603,"count":1}],"isBlockCoverage":true},{"functionName":"main","ranges":[{"startOffset":244615,"endOffset":244926,"count":1},{"startOffset":244690,"endOffset":244714,"count":0}],"isBlockCoverage":true},{"functionName":"_connectToServer","ranges":[{"startOffset":244950,"endOffset":245613,"count":1}],"isBlockCoverage":true},{"functionName":"_connectToIframe","ranges":[{"startOffset":245637,"endOffset":247021,"count":1}],"isBlockCoverage":true},{"functionName":"_TestRunner","ranges":[{"startOffset":247040,"endOffset":247070,"count":0}],"isBlockCoverage":false},{"functionName":"_JSApi","ranges":[{"startOffset":247084,"endOffset":247109,"count":0}],"isBlockCoverage":false},{"functionName":"main_closure","ranges":[{"startOffset":247129,"endOffset":247160,"count":1}],"isBlockCoverage":true},{"functionName":"main__closure","ranges":[{"startOffset":247181,"endOffset":247246,"count":1}],"isBlockCoverage":true},{"functionName":"main__closure0","ranges":[{"startOffset":247268,"endOffset":247334,"count":1}],"isBlockCoverage":true},{"functionName":"main__closure1","ranges":[{"startOffset":247356,"endOffset":247422,"count":1}],"isBlockCoverage":true},{"functionName":"main__closure2","ranges":[{"startOffset":247444,"endOffset":247510,"count":1}],"isBlockCoverage":true},{"functionName":"main__closure3","ranges":[{"startOffset":247532,"endOffset":247598,"count":1}],"isBlockCoverage":true},{"functionName":"main_closure0","ranges":[{"startOffset":247619,"endOffset":247651,"count":1}],"isBlockCoverage":true},{"functionName":"_connectToServer_closure","ranges":[{"startOffset":247683,"endOffset":247756,"count":1}],"isBlockCoverage":true},{"functionName":"_connectToServer_closure0","ranges":[{"startOffset":247789,"endOffset":247862,"count":1}],"isBlockCoverage":true},{"functionName":"_connectToIframe_closure","ranges":[{"startOffset":247894,"endOffset":248068,"count":1}],"isBlockCoverage":true},{"functionName":"_connectToIframe_closure0","ranges":[{"startOffset":248101,"endOffset":248175,"count":1}],"isBlockCoverage":true},{"functionName":"_connectToIframe_closure1","ranges":[{"startOffset":248208,"endOffset":248315,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel$","ranges":[{"startOffset":248349,"endOffset":248683,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel","ranges":[{"startOffset":248704,"endOffset":249002,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_closure","ranges":[{"startOffset":249031,"endOffset":249119,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_closure0","ranges":[{"startOffset":249149,"endOffset":249215,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_closure1","ranges":[{"startOffset":249245,"endOffset":249334,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel__closure","ranges":[{"startOffset":249364,"endOffset":249477,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_virtualChannel_closure","ranges":[{"startOffset":249521,"endOffset":249629,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_virtualChannel_closure0","ranges":[{"startOffset":249674,"endOffset":249783,"count":1}],"isBlockCoverage":true},{"functionName":"VirtualChannel","ranges":[{"startOffset":249805,"endOffset":249952,"count":1}],"isBlockCoverage":true},{"functionName":"current","ranges":[{"startOffset":249967,"endOffset":250526,"count":0}],"isBlockCoverage":false},{"functionName":"StreamChannelMixin","ranges":[{"startOffset":250559,"endOffset":250596,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":250814,"endOffset":250880,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":250900,"endOffset":250978,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":250996,"endOffset":251098,"count":0}],"isBlockCoverage":false},{"functionName":"noSuchMethod$1","ranges":[{"startOffset":251120,"endOffset":251378,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":251425,"endOffset":251482,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":251502,"endOffset":251569,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":251625,"endOffset":251686,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":251704,"endOffset":251751,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":251771,"endOffset":251813,"count":0}],"isBlockCoverage":false},{"functionName":"noSuchMethod$1","ranges":[{"startOffset":251835,"endOffset":251986,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":252061,"endOffset":252103,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":252121,"endOffset":252178,"count":0}],"isBlockCoverage":false},{"functionName":"waitUntilDone$0","ranges":[{"startOffset":252201,"endOffset":252266,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":252411,"endOffset":252677,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":252695,"endOffset":252762,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":252825,"endOffset":253058,"count":1},{"startOffset":252978,"endOffset":253024,"count":0}],"isBlockCoverage":true},{"functionName":"removeAt$1","ranges":[{"startOffset":253076,"endOffset":253376,"count":0}],"isBlockCoverage":false},{"functionName":"insert$2","ranges":[{"startOffset":253392,"endOffset":253775,"count":0}],"isBlockCoverage":false},{"functionName":"insertAll$2","ranges":[{"startOffset":253794,"endOffset":254419,"count":0}],"isBlockCoverage":false},{"functionName":"removeLast$0","ranges":[{"startOffset":254439,"endOffset":254691,"count":0}],"isBlockCoverage":false},{"functionName":"addAll$1","ranges":[{"startOffset":254707,"endOffset":255155,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":255172,"endOffset":255530,"count":0}],"isBlockCoverage":false},{"functionName":"join$1","ranges":[{"startOffset":255544,"endOffset":255804,"count":0}],"isBlockCoverage":false},{"functionName":"join$0","ranges":[{"startOffset":255818,"endOffset":255886,"count":0}],"isBlockCoverage":false},{"functionName":"fold$1$2","ranges":[{"startOffset":255902,"endOffset":256434,"count":1},{"startOffset":256336,"endOffset":256400,"count":0}],"isBlockCoverage":true},{"functionName":"elementAt$1","ranges":[{"startOffset":256453,"endOffset":256606,"count":0}],"isBlockCoverage":false},{"functionName":"sublist$2","ranges":[{"startOffset":256623,"endOffset":257154,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":257171,"endOffset":257321,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":257337,"endOffset":257511,"count":0}],"isBlockCoverage":false},{"functionName":"setRange$4","ranges":[{"startOffset":257529,"endOffset":258508,"count":0}],"isBlockCoverage":false},{"functionName":"setRange$3","ranges":[{"startOffset":258526,"endOffset":258641,"count":0}],"isBlockCoverage":false},{"functionName":"get$isNotEmpty","ranges":[{"startOffset":258663,"endOffset":258725,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":258743,"endOffset":258839,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":258859,"endOffset":258990,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":259010,"endOffset":259088,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":259106,"endOffset":259162,"count":1}],"isBlockCoverage":true},{"functionName":"set$length","ranges":[{"startOffset":259180,"endOffset":259464,"count":1},{"startOffset":259255,"endOffset":259308,"count":0},{"startOffset":259342,"endOffset":259423,"count":0}],"isBlockCoverage":true},{"functionName":"$index","ranges":[{"startOffset":259478,"endOffset":259689,"count":1},{"startOffset":259592,"endOffset":259653,"count":0}],"isBlockCoverage":true},{"functionName":"$indexSet","ranges":[{"startOffset":259706,"endOffset":260245,"count":1},{"startOffset":259897,"endOffset":259951,"count":0},{"startOffset":260028,"endOffset":260089,"count":0},{"startOffset":260147,"endOffset":260208,"count":0}],"isBlockCoverage":true},{"functionName":"get$current","ranges":[{"startOffset":260411,"endOffset":260472,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":260490,"endOffset":260928,"count":0}],"isBlockCoverage":false},{"functionName":"set$__interceptors$_current","ranges":[{"startOffset":260963,"endOffset":261101,"count":0}],"isBlockCoverage":false},{"functionName":"toRadixString$1","ranges":[{"startOffset":261175,"endOffset":262041,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":262059,"endOffset":262195,"count":1},{"startOffset":262134,"endOffset":262148,"count":0}],"isBlockCoverage":true},{"functionName":"get$hashCode","ranges":[{"startOffset":262215,"endOffset":262729,"count":0}],"isBlockCoverage":false},{"functionName":"$mod","ranges":[{"startOffset":262741,"endOffset":262992,"count":0}],"isBlockCoverage":false},{"functionName":"$tdiv","ranges":[{"startOffset":263005,"endOffset":263202,"count":0}],"isBlockCoverage":false},{"functionName":"_tdivFast$1","ranges":[{"startOffset":263221,"endOffset":263355,"count":1},{"startOffset":263313,"endOffset":263348,"count":0}],"isBlockCoverage":true},{"functionName":"_tdivSlow$1","ranges":[{"startOffset":263374,"endOffset":263848,"count":0}],"isBlockCoverage":false},{"functionName":"_shrOtherPositive$1","ranges":[{"startOffset":263875,"endOffset":264112,"count":1},{"startOffset":263995,"endOffset":264089,"count":0}],"isBlockCoverage":true},{"functionName":"_shrReceiverPositive$1","ranges":[{"startOffset":264142,"endOffset":264311,"count":0}],"isBlockCoverage":false},{"functionName":"_shrBothPositive$1","ranges":[{"startOffset":264337,"endOffset":264420,"count":1},{"startOffset":264389,"endOffset":264392,"count":0}],"isBlockCoverage":true},{"functionName":"$gt","ranges":[{"startOffset":264431,"endOffset":264592,"count":0}],"isBlockCoverage":false},{"functionName":"codeUnitAt$1","ranges":[{"startOffset":264740,"endOffset":265145,"count":1},{"startOffset":264844,"endOffset":264905,"count":0},{"startOffset":264935,"endOffset":264996,"count":0},{"startOffset":265041,"endOffset":265098,"count":0}],"isBlockCoverage":true},{"functionName":"_codeUnitAt$1","ranges":[{"startOffset":265166,"endOffset":265346,"count":1},{"startOffset":265238,"endOffset":265299,"count":0}],"isBlockCoverage":true},{"functionName":"allMatches$2","ranges":[{"startOffset":265366,"endOffset":265723,"count":0}],"isBlockCoverage":false},{"functionName":"allMatches$1","ranges":[{"startOffset":265743,"endOffset":265832,"count":0}],"isBlockCoverage":false},{"functionName":"matchAsPrefix$2","ranges":[{"startOffset":265855,"endOffset":266378,"count":0}],"isBlockCoverage":false},{"functionName":"$add","ranges":[{"startOffset":266390,"endOffset":266564,"count":0}],"isBlockCoverage":false},{"functionName":"endsWith$1","ranges":[{"startOffset":266582,"endOffset":266823,"count":0}],"isBlockCoverage":false},{"functionName":"replaceFirst$2","ranges":[{"startOffset":266845,"endOffset":267026,"count":0}],"isBlockCoverage":false},{"functionName":"replaceRange$3","ranges":[{"startOffset":267048,"endOffset":267373,"count":0}],"isBlockCoverage":false},{"functionName":"startsWith$2","ranges":[{"startOffset":267393,"endOffset":268070,"count":1},{"startOffset":267526,"endOffset":267573,"count":0},{"startOffset":267619,"endOffset":267638,"count":0},{"startOffset":267695,"endOffset":267776,"count":0},{"startOffset":267911,"endOffset":267924,"count":0},{"startOffset":267996,"endOffset":268069,"count":0}],"isBlockCoverage":true},{"functionName":"startsWith$1","ranges":[{"startOffset":268090,"endOffset":268181,"count":1}],"isBlockCoverage":true},{"functionName":"substring$2","ranges":[{"startOffset":268200,"endOffset":268888,"count":1},{"startOffset":268334,"endOffset":268386,"count":0},{"startOffset":268501,"endOffset":268525,"count":0},{"startOffset":268560,"endOffset":268620,"count":0},{"startOffset":268662,"endOffset":268722,"count":0},{"startOffset":268769,"endOffset":268827,"count":0}],"isBlockCoverage":true},{"functionName":"substring$1","ranges":[{"startOffset":268907,"endOffset":269006,"count":1}],"isBlockCoverage":true},{"functionName":"trim$0","ranges":[{"startOffset":269020,"endOffset":269700,"count":0}],"isBlockCoverage":false},{"functionName":"$mul","ranges":[{"startOffset":269712,"endOffset":270191,"count":0}],"isBlockCoverage":false},{"functionName":"padRight$1","ranges":[{"startOffset":270209,"endOffset":270458,"count":0}],"isBlockCoverage":false},{"functionName":"indexOf$2","ranges":[{"startOffset":270475,"endOffset":270731,"count":1},{"startOffset":270582,"endOffset":270663,"count":0}],"isBlockCoverage":true},{"functionName":"indexOf$1","ranges":[{"startOffset":270748,"endOffset":270836,"count":1}],"isBlockCoverage":true},{"functionName":"lastIndexOf$2","ranges":[{"startOffset":270857,"endOffset":271276,"count":0}],"isBlockCoverage":false},{"functionName":"lastIndexOf$1","ranges":[{"startOffset":271297,"endOffset":271392,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":271410,"endOffset":271584,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":271602,"endOffset":271651,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":271671,"endOffset":272077,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":272095,"endOffset":272151,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":272165,"endOffset":272372,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":272459,"endOffset":272512,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":272526,"endOffset":272627,"count":0}],"isBlockCoverage":false},{"functionName":"$asEfficientLengthIterable","ranges":[{"startOffset":272661,"endOffset":272701,"count":0}],"isBlockCoverage":false},{"functionName":"$asUnmodifiableListMixin","ranges":[{"startOffset":272733,"endOffset":272773,"count":0}],"isBlockCoverage":false},{"functionName":"$asListMixin","ranges":[{"startOffset":272793,"endOffset":272833,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":272852,"endOffset":272892,"count":0}],"isBlockCoverage":false},{"functionName":"$asList","ranges":[{"startOffset":272907,"endOffset":272947,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":273046,"endOffset":273183,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":273202,"endOffset":273263,"count":0}],"isBlockCoverage":false},{"functionName":"join$1","ranges":[{"startOffset":273277,"endOffset":274216,"count":0}],"isBlockCoverage":false},{"functionName":"join$0","ranges":[{"startOffset":274230,"endOffset":274298,"count":0}],"isBlockCoverage":false},{"functionName":"fold$1$2","ranges":[{"startOffset":274314,"endOffset":274870,"count":0}],"isBlockCoverage":false},{"functionName":"toList$1$growable","ranges":[{"startOffset":274895,"endOffset":275249,"count":0}],"isBlockCoverage":false},{"functionName":"toList$0","ranges":[{"startOffset":275265,"endOffset":275346,"count":0}],"isBlockCoverage":false},{"functionName":"get$_endIndex","ranges":[{"startOffset":275405,"endOffset":275616,"count":0}],"isBlockCoverage":false},{"functionName":"get$_startIndex","ranges":[{"startOffset":275639,"endOffset":275841,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":275859,"endOffset":276224,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":276243,"endOffset":276692,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":276746,"endOffset":276803,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":276821,"endOffset":277341,"count":0}],"isBlockCoverage":false},{"functionName":"set$__internal$_current","ranges":[{"startOffset":277372,"endOffset":277506,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":277583,"endOffset":277702,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":277720,"endOffset":277797,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":277816,"endOffset":277859,"count":0}],"isBlockCoverage":false},{"functionName":"$asEfficientLengthIterable","ranges":[{"startOffset":277975,"endOffset":278018,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":278073,"endOffset":278314,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":278333,"endOffset":278390,"count":0}],"isBlockCoverage":false},{"functionName":"set$__internal$_current","ranges":[{"startOffset":278421,"endOffset":278555,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterator","ranges":[{"startOffset":278574,"endOffset":278617,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":278676,"endOffset":278740,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":278759,"endOffset":278853,"count":0}],"isBlockCoverage":false},{"functionName":"$asEfficientLengthIterable","ranges":[{"startOffset":278887,"endOffset":278930,"count":0}],"isBlockCoverage":false},{"functionName":"$asListIterable","ranges":[{"startOffset":278953,"endOffset":278996,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":279015,"endOffset":279058,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":279114,"endOffset":279232,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":279286,"endOffset":279470,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":279489,"endOffset":279550,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":279607,"endOffset":279745,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":279764,"endOffset":279807,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":279863,"endOffset":279920,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":279938,"endOffset":280470,"count":0}],"isBlockCoverage":false},{"functionName":"set$_currentExpansion","ranges":[{"startOffset":280499,"endOffset":280668,"count":0}],"isBlockCoverage":false},{"functionName":"set$__internal$_current","ranges":[{"startOffset":280699,"endOffset":280833,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterator","ranges":[{"startOffset":280872,"endOffset":280915,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":280975,"endOffset":281097,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":281155,"endOffset":281440,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":281459,"endOffset":281520,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":281574,"endOffset":281612,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":281631,"endOffset":281663,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":281785,"endOffset":282038,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":282140,"endOffset":282204,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":282223,"endOffset":282393,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":282442,"endOffset":282661,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":282679,"endOffset":282759,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":282770,"endOffset":282934,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":283042,"endOffset":283103,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":283121,"endOffset":283182,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":283199,"endOffset":283429,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":283502,"endOffset":283560,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":283581,"endOffset":283761,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":283775,"endOffset":283884,"count":0}],"isBlockCoverage":false},{"functionName":"_fetch$1","ranges":[{"startOffset":283900,"endOffset":283974,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":283991,"endOffset":284372,"count":0}],"isBlockCoverage":false},{"functionName":"Instantiation$1","ranges":[{"startOffset":284431,"endOffset":284530,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":284548,"endOffset":284741,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":284792,"endOffset":284881,"count":0}],"isBlockCoverage":false},{"functionName":"call$4","ranges":[{"startOffset":284895,"endOffset":285000,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":285018,"endOffset":285157,"count":0}],"isBlockCoverage":false},{"functionName":"get$memberName","ranges":[{"startOffset":285220,"endOffset":285288,"count":0}],"isBlockCoverage":false},{"functionName":"get$positionalArguments","ranges":[{"startOffset":285319,"endOffset":285850,"count":0}],"isBlockCoverage":false},{"functionName":"get$namedArguments","ranges":[{"startOffset":285876,"endOffset":286722,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":286820,"endOffset":287115,"count":0}],"isBlockCoverage":false},{"functionName":"matchTypeError$1","ranges":[{"startOffset":287198,"endOffset":287850,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":287900,"endOffset":288103,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":288163,"endOffset":288563,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":288622,"endOffset":288728,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":288838,"endOffset":289012,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":289083,"endOffset":289391,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":289461,"endOffset":289555,"count":0}],"isBlockCoverage":false},{"functionName":"get$$call","ranges":[{"startOffset":289592,"endOffset":289629,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":289793,"endOffset":289982,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":290028,"endOffset":290329,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":290349,"endOffset":290718,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":290736,"endOffset":290971,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":291035,"endOffset":291081,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":291145,"endOffset":291191,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":291244,"endOffset":291314,"count":0}],"isBlockCoverage":false},{"functionName":"get$_typeName","ranges":[{"startOffset":291366,"endOffset":291542,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":291560,"endOffset":291614,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":291634,"endOffset":291830,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":291841,"endOffset":292006,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":292062,"endOffset":292120,"count":1}],"isBlockCoverage":true},{"functionName":"get$isEmpty","ranges":[{"startOffset":292139,"endOffset":292203,"count":1}],"isBlockCoverage":true},{"functionName":"get$keys","ranges":[{"startOffset":292219,"endOffset":292325,"count":0}],"isBlockCoverage":false},{"functionName":"get$values","ranges":[{"startOffset":292343,"endOffset":292585,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":292606,"endOffset":293097,"count":1},{"startOffset":292682,"endOffset":292834,"count":0},{"startOffset":292963,"endOffset":292976,"count":0},{"startOffset":293038,"endOffset":293091,"count":0}],"isBlockCoverage":true},{"functionName":"internalContainsKey$1","ranges":[{"startOffset":293126,"endOffset":293341,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":293355,"endOffset":293981,"count":1},{"startOffset":293518,"endOffset":293525,"count":0},{"startOffset":293603,"endOffset":293609,"count":0},{"startOffset":293790,"endOffset":293797,"count":0},{"startOffset":293872,"endOffset":293878,"count":0},{"startOffset":293930,"endOffset":293975,"count":0}],"isBlockCoverage":true},{"functionName":"internalGet$1","ranges":[{"startOffset":294002,"endOffset":294339,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":294356,"endOffset":295711,"count":1},{"startOffset":295102,"endOffset":295705,"count":0}],"isBlockCoverage":true},{"functionName":"putIfAbsent$2","ranges":[{"startOffset":295732,"endOffset":296105,"count":1},{"startOffset":296009,"endOffset":296104,"count":0}],"isBlockCoverage":true},{"functionName":"remove$1","ranges":[{"startOffset":296121,"endOffset":296430,"count":0}],"isBlockCoverage":false},{"functionName":"internalRemove$1","ranges":[{"startOffset":296454,"endOffset":296861,"count":0}],"isBlockCoverage":false},{"functionName":"clear$0","ranges":[{"startOffset":296876,"endOffset":297150,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":297167,"endOffset":297681,"count":1},{"startOffset":297580,"endOffset":297640,"count":0}],"isBlockCoverage":true},{"functionName":"_addHashTableEntry$3","ranges":[{"startOffset":297709,"endOffset":298113,"count":1},{"startOffset":298057,"endOffset":298107,"count":0}],"isBlockCoverage":true},{"functionName":"_removeHashTableEntry$2","ranges":[{"startOffset":298144,"endOffset":298428,"count":0}],"isBlockCoverage":false},{"functionName":"_modified$0","ranges":[{"startOffset":298447,"endOffset":298529,"count":1}],"isBlockCoverage":true},{"functionName":"_newLinkedCell$2","ranges":[{"startOffset":298553,"endOffset":299085,"count":1}],"isBlockCoverage":true},{"functionName":"_unlinkCell$1","ranges":[{"startOffset":299106,"endOffset":299471,"count":0}],"isBlockCoverage":false},{"functionName":"internalFindBucketIndex$2","ranges":[{"startOffset":299504,"endOffset":299755,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":299773,"endOffset":299834,"count":0}],"isBlockCoverage":false},{"functionName":"_getTableCell$2","ranges":[{"startOffset":299857,"endOffset":299910,"count":1}],"isBlockCoverage":true},{"functionName":"_getTableBucket$2","ranges":[{"startOffset":299935,"endOffset":299988,"count":0}],"isBlockCoverage":false},{"functionName":"_setTableEntry$3","ranges":[{"startOffset":300012,"endOffset":300073,"count":1}],"isBlockCoverage":true},{"functionName":"_deleteTableEntry$2","ranges":[{"startOffset":300100,"endOffset":300153,"count":1}],"isBlockCoverage":true},{"functionName":"_containsTableEntry$2","ranges":[{"startOffset":300182,"endOffset":300265,"count":1}],"isBlockCoverage":true},{"functionName":"_newHashTable$0","ranges":[{"startOffset":300288,"endOffset":300495,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":300587,"endOffset":300732,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":300750,"endOffset":300898,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":301001,"endOffset":301076,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":301095,"endOffset":301176,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":301196,"endOffset":301388,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":301454,"endOffset":301512,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":301530,"endOffset":302000,"count":0}],"isBlockCoverage":false},{"functionName":"set$__js_helper$_current","ranges":[{"startOffset":302032,"endOffset":302167,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":302241,"endOffset":302289,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":302363,"endOffset":302428,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":302503,"endOffset":302583,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":302658,"endOffset":302722,"count":0}],"isBlockCoverage":false},{"functionName":"get$_nativeGlobalVersion","ranges":[{"startOffset":302754,"endOffset":303029,"count":0}],"isBlockCoverage":false},{"functionName":"get$_nativeAnchoredVersion","ranges":[{"startOffset":303063,"endOffset":303350,"count":0}],"isBlockCoverage":false},{"functionName":"firstMatch$1","ranges":[{"startOffset":303370,"endOffset":303626,"count":0}],"isBlockCoverage":false},{"functionName":"allMatches$2","ranges":[{"startOffset":303646,"endOffset":303862,"count":0}],"isBlockCoverage":false},{"functionName":"allMatches$1","ranges":[{"startOffset":303882,"endOffset":303971,"count":0}],"isBlockCoverage":false},{"functionName":"_execGlobal$2","ranges":[{"startOffset":303992,"endOffset":304252,"count":0}],"isBlockCoverage":false},{"functionName":"_execAnchored$2","ranges":[{"startOffset":304275,"endOffset":304648,"count":0}],"isBlockCoverage":false},{"functionName":"matchAsPrefix$2","ranges":[{"startOffset":304671,"endOffset":304954,"count":0}],"isBlockCoverage":false},{"functionName":"get$start","ranges":[{"startOffset":305051,"endOffset":305102,"count":0}],"isBlockCoverage":false},{"functionName":"get$end","ranges":[{"startOffset":305117,"endOffset":305201,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":305215,"endOffset":305397,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":305476,"endOffset":305584,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":305603,"endOffset":305645,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":305706,"endOffset":305764,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":305782,"endOffset":306369,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterator","ranges":[{"startOffset":306408,"endOffset":306450,"count":0}],"isBlockCoverage":false},{"functionName":"get$end","ranges":[{"startOffset":306499,"endOffset":306643,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":306657,"endOffset":306806,"count":0}],"isBlockCoverage":false},{"functionName":"get$start","ranges":[{"startOffset":306840,"endOffset":306891,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":306959,"endOffset":307077,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":307096,"endOffset":307138,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":307204,"endOffset":307851,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":307870,"endOffset":307928,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterator","ranges":[{"startOffset":307967,"endOffset":308009,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":308182,"endOffset":308238,"count":0}],"isBlockCoverage":false},{"functionName":"$asJavaScriptIndexingBehavior","ranges":[{"startOffset":308313,"endOffset":308331,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":308392,"endOffset":308544,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":308561,"endOffset":308753,"count":0}],"isBlockCoverage":false},{"functionName":"$asEfficientLengthIterable","ranges":[{"startOffset":308822,"endOffset":308865,"count":0}],"isBlockCoverage":false},{"functionName":"$asFixedLengthListMixin","ranges":[{"startOffset":308896,"endOffset":308939,"count":0}],"isBlockCoverage":false},{"functionName":"$asListMixin","ranges":[{"startOffset":308959,"endOffset":309002,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":309041,"endOffset":309084,"count":0}],"isBlockCoverage":false},{"functionName":"$asList","ranges":[{"startOffset":309115,"endOffset":309158,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":309219,"endOffset":309408,"count":1}],"isBlockCoverage":true},{"functionName":"$asEfficientLengthIterable","ranges":[{"startOffset":309477,"endOffset":309517,"count":0}],"isBlockCoverage":false},{"functionName":"$asFixedLengthListMixin","ranges":[{"startOffset":309548,"endOffset":309588,"count":0}],"isBlockCoverage":false},{"functionName":"$asListMixin","ranges":[{"startOffset":309608,"endOffset":309648,"count":1}],"isBlockCoverage":true},{"functionName":"$asIterable","ranges":[{"startOffset":309687,"endOffset":309727,"count":0}],"isBlockCoverage":false},{"functionName":"$asList","ranges":[{"startOffset":309758,"endOffset":309798,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":309850,"endOffset":310002,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":310054,"endOffset":310206,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":310257,"endOffset":310409,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":310462,"endOffset":310614,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":310667,"endOffset":310819,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":310882,"endOffset":310938,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":310952,"endOffset":311104,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":311160,"endOffset":311216,"count":1}],"isBlockCoverage":true},{"functionName":"$index","ranges":[{"startOffset":311230,"endOffset":311382,"count":0}],"isBlockCoverage":false},{"functionName":"sublist$2","ranges":[{"startOffset":311399,"endOffset":311541,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":312009,"endOffset":312148,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":312250,"endOffset":312486,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":312598,"endOffset":312646,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":312812,"endOffset":312860,"count":0}],"isBlockCoverage":false},{"functionName":"_TimerImpl$2","ranges":[{"startOffset":312981,"endOffset":313267,"count":0}],"isBlockCoverage":false},{"functionName":"_TimerImpl$periodic$2","ranges":[{"startOffset":313296,"endOffset":313599,"count":1},{"startOffset":313511,"endOffset":313593,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":313680,"endOffset":313756,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":313888,"endOffset":314241,"count":0}],"isBlockCoverage":false},{"functionName":"complete$1","ranges":[{"startOffset":314370,"endOffset":314852,"count":1},{"startOffset":314559,"endOffset":314846,"count":0}],"isBlockCoverage":true},{"functionName":"completeError$2","ranges":[{"startOffset":314875,"endOffset":315072,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":315167,"endOffset":315240,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":315387,"endOffset":315467,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":315594,"endOffset":315668,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":315747,"endOffset":315907,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":316044,"endOffset":316137,"count":1}],"isBlockCoverage":true},{"functionName":"completeError$2","ranges":[{"startOffset":316289,"endOffset":316893,"count":0}],"isBlockCoverage":false},{"functionName":"completeError$1","ranges":[{"startOffset":316916,"endOffset":316987,"count":0}],"isBlockCoverage":false},{"functionName":"complete$1","ranges":[{"startOffset":317064,"endOffset":317349,"count":1},{"startOffset":317244,"endOffset":317309,"count":0}],"isBlockCoverage":true},{"functionName":"complete$0","ranges":[{"startOffset":317367,"endOffset":317441,"count":1}],"isBlockCoverage":true},{"functionName":"_completeError$2","ranges":[{"startOffset":317465,"endOffset":317560,"count":0}],"isBlockCoverage":false},{"functionName":"complete$1","ranges":[{"startOffset":317615,"endOffset":317895,"count":1},{"startOffset":317795,"endOffset":317860,"count":0}],"isBlockCoverage":true},{"functionName":"complete$0","ranges":[{"startOffset":317913,"endOffset":317987,"count":0}],"isBlockCoverage":false},{"functionName":"_completeError$2","ranges":[{"startOffset":318011,"endOffset":318101,"count":0}],"isBlockCoverage":false},{"functionName":"matchesErrorTest$1","ranges":[{"startOffset":318165,"endOffset":318401,"count":0}],"isBlockCoverage":false},{"functionName":"handleError$1","ranges":[{"startOffset":318422,"endOffset":319026,"count":0}],"isBlockCoverage":false},{"functionName":"then$1$2$onError","ranges":[{"startOffset":319080,"endOffset":319598,"count":1},{"startOffset":319465,"endOffset":319521,"count":0}],"isBlockCoverage":true},{"functionName":"then$1$1","ranges":[{"startOffset":319614,"endOffset":319686,"count":1}],"isBlockCoverage":true},{"functionName":"_thenNoZoneRegistration$1$2","ranges":[{"startOffset":319721,"endOffset":320105,"count":1}],"isBlockCoverage":true},{"functionName":"whenComplete$1","ranges":[{"startOffset":320127,"endOffset":320534,"count":0}],"isBlockCoverage":false},{"functionName":"_addListener$1","ranges":[{"startOffset":320556,"endOffset":321250,"count":1},{"startOffset":320829,"endOffset":321144,"count":0}],"isBlockCoverage":true},{"functionName":"_prependListeners$1","ranges":[{"startOffset":321277,"endOffset":322404,"count":0}],"isBlockCoverage":false},{"functionName":"_removeListeners$0","ranges":[{"startOffset":322430,"endOffset":322625,"count":1}],"isBlockCoverage":true},{"functionName":"_reverseListeners$1","ranges":[{"startOffset":322652,"endOffset":322909,"count":1}],"isBlockCoverage":true},{"functionName":"_complete$1","ranges":[{"startOffset":322928,"endOffset":323583,"count":1},{"startOffset":323168,"endOffset":323336,"count":0}],"isBlockCoverage":true},{"functionName":"_completeError$2","ranges":[{"startOffset":323607,"endOffset":323915,"count":0}],"isBlockCoverage":false},{"functionName":"_completeError$1","ranges":[{"startOffset":323939,"endOffset":324011,"count":0}],"isBlockCoverage":false},{"functionName":"_asyncComplete$1","ranges":[{"startOffset":324035,"endOffset":324387,"count":1},{"startOffset":324208,"endOffset":324269,"count":0}],"isBlockCoverage":true},{"functionName":"_chainFuture$1","ranges":[{"startOffset":324409,"endOffset":324868,"count":0}],"isBlockCoverage":false},{"functionName":"_asyncCompleteError$2","ranges":[{"startOffset":324897,"endOffset":325120,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":325203,"endOffset":325287,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":325425,"endOffset":325517,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":325657,"endOffset":325758,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":325850,"endOffset":325999,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":326013,"endOffset":326075,"count":0}],"isBlockCoverage":false},{"functionName":"$defaultValues","ranges":[{"startOffset":326120,"endOffset":326159,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":326252,"endOffset":326322,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":326457,"endOffset":326765,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":326898,"endOffset":326974,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":327114,"endOffset":327196,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":327357,"endOffset":328955,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":329075,"endOffset":329128,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":329234,"endOffset":329953,"count":1},{"startOffset":329710,"endOffset":329947,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":330050,"endOffset":330966,"count":0}],"isBlockCoverage":false},{"functionName":"pipe$1","ranges":[{"startOffset":331068,"endOffset":331333,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":331351,"endOffset":331673,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":331729,"endOffset":331793,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":331871,"endOffset":332007,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":332025,"endOffset":332139,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":332198,"endOffset":332266,"count":0}],"isBlockCoverage":false},{"functionName":"get$_pendingEvents","ranges":[{"startOffset":332504,"endOffset":332877,"count":1},{"startOffset":332650,"endOffset":332876,"count":0}],"isBlockCoverage":true},{"functionName":"_ensurePendingEvents$0","ranges":[{"startOffset":332907,"endOffset":333600,"count":0}],"isBlockCoverage":false},{"functionName":"get$_subscription","ranges":[{"startOffset":333625,"endOffset":334046,"count":1},{"startOffset":333673,"endOffset":333925,"count":0}],"isBlockCoverage":true},{"functionName":"_badEventState$0","ranges":[{"startOffset":334070,"endOffset":334263,"count":0}],"isBlockCoverage":false},{"functionName":"_ensureDoneFuture$0","ranges":[{"startOffset":334290,"endOffset":334533,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":334546,"endOffset":334760,"count":1},{"startOffset":334681,"endOffset":334728,"count":0}],"isBlockCoverage":true},{"functionName":"addError$2","ranges":[{"startOffset":334778,"endOffset":335358,"count":0}],"isBlockCoverage":false},{"functionName":"addError$1","ranges":[{"startOffset":335376,"endOffset":335442,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":335457,"endOffset":335879,"count":0}],"isBlockCoverage":false},{"functionName":"_add$1","ranges":[{"startOffset":335893,"endOffset":336207,"count":1},{"startOffset":336085,"endOffset":336201,"count":0}],"isBlockCoverage":true},{"functionName":"_async$_addError$2","ranges":[{"startOffset":336233,"endOffset":336487,"count":0}],"isBlockCoverage":false},{"functionName":"_subscribe$4","ranges":[{"startOffset":336507,"endOffset":337709,"count":1},{"startOffset":336834,"endOffset":336911,"count":0},{"startOffset":336965,"endOffset":336968,"count":0},{"startOffset":337264,"endOffset":337491,"count":0}],"isBlockCoverage":true},{"functionName":"_recordCancel$1","ranges":[{"startOffset":337732,"endOffset":338892,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":339105,"endOffset":339165,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":339261,"endOffset":339394,"count":0}],"isBlockCoverage":false},{"functionName":"_sendData$1","ranges":[{"startOffset":339533,"endOffset":339677,"count":1}],"isBlockCoverage":true},{"functionName":"_sendError$2","ranges":[{"startOffset":339697,"endOffset":339802,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":339821,"endOffset":339882,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":339984,"endOffset":340083,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":340094,"endOffset":340307,"count":0}],"isBlockCoverage":false},{"functionName":"_onCancel$0","ranges":[{"startOffset":340372,"endOffset":340443,"count":0}],"isBlockCoverage":false},{"functionName":"_onPause$0","ranges":[{"startOffset":340461,"endOffset":340868,"count":0}],"isBlockCoverage":false},{"functionName":"_onResume$0","ranges":[{"startOffset":340887,"endOffset":341296,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":341350,"endOffset":341482,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":341597,"endOffset":341672,"count":0}],"isBlockCoverage":false},{"functionName":"_BufferingStreamSubscription$4","ranges":[{"startOffset":341780,"endOffset":343046,"count":1},{"startOffset":342069,"endOffset":342106,"count":0},{"startOffset":342501,"endOffset":342838,"count":0}],"isBlockCoverage":true},{"functionName":"_setPendingEvents$1","ranges":[{"startOffset":343073,"endOffset":343490,"count":1},{"startOffset":343296,"endOffset":343484,"count":0}],"isBlockCoverage":true},{"functionName":"cancel$0","ranges":[{"startOffset":343506,"endOffset":343740,"count":0}],"isBlockCoverage":false},{"functionName":"_cancel$0","ranges":[{"startOffset":343757,"endOffset":344079,"count":0}],"isBlockCoverage":false},{"functionName":"_add$1","ranges":[{"startOffset":344093,"endOffset":344445,"count":1},{"startOffset":344310,"endOffset":344317,"count":0},{"startOffset":344368,"endOffset":344439,"count":0}],"isBlockCoverage":true},{"functionName":"_async$_addError$2","ranges":[{"startOffset":344471,"endOffset":344720,"count":0}],"isBlockCoverage":false},{"functionName":"_close$0","ranges":[{"startOffset":344736,"endOffset":344979,"count":0}],"isBlockCoverage":false},{"functionName":"_onPause$0","ranges":[{"startOffset":344997,"endOffset":345015,"count":0}],"isBlockCoverage":false},{"functionName":"_onResume$0","ranges":[{"startOffset":345034,"endOffset":345052,"count":0}],"isBlockCoverage":false},{"functionName":"_onCancel$0","ranges":[{"startOffset":345071,"endOffset":345103,"count":0}],"isBlockCoverage":false},{"functionName":"_addPending$1","ranges":[{"startOffset":345124,"endOffset":345687,"count":0}],"isBlockCoverage":false},{"functionName":"_sendData$1","ranges":[{"startOffset":345706,"endOffset":346096,"count":1}],"isBlockCoverage":true},{"functionName":"_sendError$2","ranges":[{"startOffset":346116,"endOffset":346631,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":346650,"endOffset":346982,"count":0}],"isBlockCoverage":false},{"functionName":"_guardCallback$1","ranges":[{"startOffset":347006,"endOffset":347285,"count":1}],"isBlockCoverage":true},{"functionName":"_checkState$1","ranges":[{"startOffset":347306,"endOffset":348403,"count":1},{"startOffset":347416,"endOffset":347457,"count":0},{"startOffset":347459,"endOffset":347850,"count":0},{"startOffset":347932,"endOffset":347996,"count":0},{"startOffset":348099,"endOffset":348318,"count":0},{"startOffset":348345,"endOffset":348356,"count":0},{"startOffset":348366,"endOffset":348397,"count":0}],"isBlockCoverage":true},{"functionName":"set$_async$_onData","ranges":[{"startOffset":348429,"endOffset":348607,"count":1}],"isBlockCoverage":true},{"functionName":"set$_onDone","ranges":[{"startOffset":348626,"endOffset":348722,"count":1}],"isBlockCoverage":true},{"functionName":"set$_pending","ranges":[{"startOffset":348742,"endOffset":348928,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":349070,"endOffset":349703,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":349855,"endOffset":350105,"count":0}],"isBlockCoverage":false},{"functionName":"listen$4$cancelOnError$onDone$onError","ranges":[{"startOffset":350252,"endOffset":350638,"count":1}],"isBlockCoverage":true},{"functionName":"listen$1","ranges":[{"startOffset":350654,"endOffset":350761,"count":1}],"isBlockCoverage":true},{"functionName":"listen$3$onDone$onError","ranges":[{"startOffset":350792,"endOffset":350921,"count":1}],"isBlockCoverage":true},{"functionName":"listen$2$onDone","ranges":[{"startOffset":350944,"endOffset":351061,"count":1}],"isBlockCoverage":true},{"functionName":"set$next","ranges":[{"startOffset":351113,"endOffset":351203,"count":0}],"isBlockCoverage":false},{"functionName":"get$next","ranges":[{"startOffset":351219,"endOffset":351261,"count":0}],"isBlockCoverage":false},{"functionName":"perform$1","ranges":[{"startOffset":351313,"endOffset":351448,"count":0}],"isBlockCoverage":false},{"functionName":"perform$1","ranges":[{"startOffset":351501,"endOffset":351585,"count":0}],"isBlockCoverage":false},{"functionName":"$as_DelayedEvent","ranges":[{"startOffset":351609,"endOffset":351627,"count":0}],"isBlockCoverage":false},{"functionName":"perform$1","ranges":[{"startOffset":351679,"endOffset":351735,"count":0}],"isBlockCoverage":false},{"functionName":"get$next","ranges":[{"startOffset":351751,"endOffset":351783,"count":0}],"isBlockCoverage":false},{"functionName":"set$next","ranges":[{"startOffset":351799,"endOffset":351889,"count":0}],"isBlockCoverage":false},{"functionName":"$as_DelayedEvent","ranges":[{"startOffset":351938,"endOffset":351956,"count":0}],"isBlockCoverage":false},{"functionName":"schedule$1","ranges":[{"startOffset":352011,"endOffset":352371,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":352439,"endOffset":352917,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":353038,"endOffset":353300,"count":0}],"isBlockCoverage":false},{"functionName":"_schedule$0","ranges":[{"startOffset":353365,"endOffset":353539,"count":0}],"isBlockCoverage":false},{"functionName":"cancel$0","ranges":[{"startOffset":353555,"endOffset":353615,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":353634,"endOffset":353880,"count":0}],"isBlockCoverage":false},{"functionName":"listen$4$cancelOnError$onDone$onError","ranges":[{"startOffset":354026,"endOffset":354367,"count":0}],"isBlockCoverage":false},{"functionName":"listen$1","ranges":[{"startOffset":354383,"endOffset":354490,"count":0}],"isBlockCoverage":false},{"functionName":"listen$3$onDone$onError","ranges":[{"startOffset":354521,"endOffset":354650,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":354727,"endOffset":354776,"count":0}],"isBlockCoverage":false},{"functionName":"handleUncaughtError$3","ranges":[{"startOffset":355050,"endOffset":355408,"count":0}],"isBlockCoverage":false},{"functionName":"get$_delegate","ranges":[{"startOffset":355523,"endOffset":355705,"count":0}],"isBlockCoverage":false},{"functionName":"get$errorZone","ranges":[{"startOffset":355726,"endOffset":355789,"count":1}],"isBlockCoverage":true},{"functionName":"runGuarded$1","ranges":[{"startOffset":355809,"endOffset":356114,"count":1},{"startOffset":355949,"endOffset":356108,"count":0}],"isBlockCoverage":true},{"functionName":"runUnaryGuarded$1$2","ranges":[{"startOffset":356141,"endOffset":356526,"count":1},{"startOffset":356361,"endOffset":356520,"count":0}],"isBlockCoverage":true},{"functionName":"runBinaryGuarded$2$3","ranges":[{"startOffset":356554,"endOffset":357013,"count":0}],"isBlockCoverage":false},{"functionName":"bindCallback$1$1","ranges":[{"startOffset":357037,"endOffset":357198,"count":0}],"isBlockCoverage":false},{"functionName":"bindUnaryCallback$2$1","ranges":[{"startOffset":357227,"endOffset":357422,"count":1}],"isBlockCoverage":true},{"functionName":"bindCallbackGuarded$1","ranges":[{"startOffset":357451,"endOffset":357611,"count":1}],"isBlockCoverage":true},{"functionName":"bindUnaryCallbackGuarded$1$1","ranges":[{"startOffset":357647,"endOffset":357841,"count":1}],"isBlockCoverage":true},{"functionName":"$index","ranges":[{"startOffset":357855,"endOffset":358169,"count":0}],"isBlockCoverage":false},{"functionName":"handleUncaughtError$2","ranges":[{"startOffset":358198,"endOffset":358557,"count":0}],"isBlockCoverage":false},{"functionName":"fork$2$specification$zoneValues","ranges":[{"startOffset":358596,"endOffset":358897,"count":0}],"isBlockCoverage":false},{"functionName":"run$1$1","ranges":[{"startOffset":358912,"endOffset":359343,"count":1}],"isBlockCoverage":true},{"functionName":"runUnary$2$2","ranges":[{"startOffset":359363,"endOffset":359898,"count":1}],"isBlockCoverage":true},{"functionName":"runBinary$3$3","ranges":[{"startOffset":359919,"endOffset":360544,"count":0}],"isBlockCoverage":false},{"functionName":"registerCallback$1$1","ranges":[{"startOffset":360572,"endOffset":361053,"count":1}],"isBlockCoverage":true},{"functionName":"registerUnaryCallback$2$1","ranges":[{"startOffset":361086,"endOffset":361624,"count":1}],"isBlockCoverage":true},{"functionName":"registerBinaryCallback$3$1","ranges":[{"startOffset":361658,"endOffset":362225,"count":1}],"isBlockCoverage":true},{"functionName":"errorCallback$2","ranges":[{"startOffset":362248,"endOffset":362670,"count":0}],"isBlockCoverage":false},{"functionName":"scheduleMicrotask$1","ranges":[{"startOffset":362697,"endOffset":363013,"count":1}],"isBlockCoverage":true},{"functionName":"createPeriodicTimer$2","ranges":[{"startOffset":363042,"endOffset":363397,"count":1}],"isBlockCoverage":true},{"functionName":"print$1","ranges":[{"startOffset":363412,"endOffset":363675,"count":0}],"isBlockCoverage":false},{"functionName":"set$_run","ranges":[{"startOffset":363691,"endOffset":363808,"count":1}],"isBlockCoverage":true},{"functionName":"set$_runUnary","ranges":[{"startOffset":363829,"endOffset":363961,"count":1}],"isBlockCoverage":true},{"functionName":"set$_runBinary","ranges":[{"startOffset":363983,"endOffset":364118,"count":1}],"isBlockCoverage":true},{"functionName":"set$_registerCallback","ranges":[{"startOffset":364147,"endOffset":364303,"count":1}],"isBlockCoverage":true},{"functionName":"set$_registerUnaryCallback","ranges":[{"startOffset":364337,"endOffset":364508,"count":1}],"isBlockCoverage":true},{"functionName":"set$_registerBinaryCallback","ranges":[{"startOffset":364543,"endOffset":364717,"count":1}],"isBlockCoverage":true},{"functionName":"set$_errorCallback","ranges":[{"startOffset":364743,"endOffset":364972,"count":1}],"isBlockCoverage":true},{"functionName":"set$_scheduleMicrotask","ranges":[{"startOffset":365002,"endOffset":365229,"count":1}],"isBlockCoverage":true},{"functionName":"set$_createTimer","ranges":[{"startOffset":365253,"endOffset":365479,"count":1}],"isBlockCoverage":true},{"functionName":"set$_createPeriodicTimer","ranges":[{"startOffset":365511,"endOffset":365778,"count":1}],"isBlockCoverage":true},{"functionName":"set$_print","ranges":[{"startOffset":365796,"endOffset":365977,"count":1}],"isBlockCoverage":true},{"functionName":"set$_fork","ranges":[{"startOffset":365994,"endOffset":366199,"count":1}],"isBlockCoverage":true},{"functionName":"set$_handleUncaughtError","ranges":[{"startOffset":366231,"endOffset":366468,"count":1}],"isBlockCoverage":true},{"functionName":"get$_run","ranges":[{"startOffset":366484,"endOffset":366526,"count":0}],"isBlockCoverage":false},{"functionName":"get$_runUnary","ranges":[{"startOffset":366547,"endOffset":366594,"count":0}],"isBlockCoverage":false},{"functionName":"get$_runBinary","ranges":[{"startOffset":366616,"endOffset":366664,"count":0}],"isBlockCoverage":false},{"functionName":"get$_registerCallback","ranges":[{"startOffset":366693,"endOffset":366748,"count":0}],"isBlockCoverage":false},{"functionName":"get$_registerUnaryCallback","ranges":[{"startOffset":366782,"endOffset":366842,"count":0}],"isBlockCoverage":false},{"functionName":"get$_registerBinaryCallback","ranges":[{"startOffset":366877,"endOffset":366938,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorCallback","ranges":[{"startOffset":366964,"endOffset":367016,"count":0}],"isBlockCoverage":false},{"functionName":"get$_scheduleMicrotask","ranges":[{"startOffset":367046,"endOffset":367102,"count":0}],"isBlockCoverage":false},{"functionName":"get$_createTimer","ranges":[{"startOffset":367126,"endOffset":367176,"count":0}],"isBlockCoverage":false},{"functionName":"get$_createPeriodicTimer","ranges":[{"startOffset":367208,"endOffset":367266,"count":0}],"isBlockCoverage":false},{"functionName":"get$_print","ranges":[{"startOffset":367284,"endOffset":367328,"count":0}],"isBlockCoverage":false},{"functionName":"get$_fork","ranges":[{"startOffset":367345,"endOffset":367388,"count":0}],"isBlockCoverage":false},{"functionName":"get$_handleUncaughtError","ranges":[{"startOffset":367420,"endOffset":367478,"count":0}],"isBlockCoverage":false},{"functionName":"get$parent","ranges":[{"startOffset":367496,"endOffset":367548,"count":0}],"isBlockCoverage":false},{"functionName":"get$_async$_map","ranges":[{"startOffset":367571,"endOffset":367620,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":367689,"endOffset":367765,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":367783,"endOffset":367838,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":367912,"endOffset":368062,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":368080,"endOffset":368151,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":368227,"endOffset":368300,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":368449,"endOffset":368598,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":368616,"endOffset":368683,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":368752,"endOffset":369158,"count":0}],"isBlockCoverage":false},{"functionName":"get$_run","ranges":[{"startOffset":369225,"endOffset":369292,"count":1}],"isBlockCoverage":true},{"functionName":"get$_runUnary","ranges":[{"startOffset":369313,"endOffset":369385,"count":1}],"isBlockCoverage":true},{"functionName":"get$_runBinary","ranges":[{"startOffset":369407,"endOffset":369480,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerCallback","ranges":[{"startOffset":369509,"endOffset":369589,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerUnaryCallback","ranges":[{"startOffset":369623,"endOffset":369675,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerBinaryCallback","ranges":[{"startOffset":369710,"endOffset":369762,"count":1}],"isBlockCoverage":true},{"functionName":"get$_errorCallback","ranges":[{"startOffset":369788,"endOffset":369865,"count":1}],"isBlockCoverage":true},{"functionName":"get$_scheduleMicrotask","ranges":[{"startOffset":369895,"endOffset":369976,"count":1}],"isBlockCoverage":true},{"functionName":"get$_createTimer","ranges":[{"startOffset":370000,"endOffset":370075,"count":1}],"isBlockCoverage":true},{"functionName":"get$_createPeriodicTimer","ranges":[{"startOffset":370107,"endOffset":370159,"count":1}],"isBlockCoverage":true},{"functionName":"get$_print","ranges":[{"startOffset":370177,"endOffset":370246,"count":1}],"isBlockCoverage":true},{"functionName":"get$_fork","ranges":[{"startOffset":370263,"endOffset":370331,"count":1}],"isBlockCoverage":true},{"functionName":"get$_handleUncaughtError","ranges":[{"startOffset":370363,"endOffset":370415,"count":0}],"isBlockCoverage":false},{"functionName":"get$parent","ranges":[{"startOffset":370433,"endOffset":370466,"count":1}],"isBlockCoverage":true},{"functionName":"get$_async$_map","ranges":[{"startOffset":370489,"endOffset":370549,"count":1}],"isBlockCoverage":true},{"functionName":"get$_delegate","ranges":[{"startOffset":370570,"endOffset":370764,"count":0}],"isBlockCoverage":false},{"functionName":"get$errorZone","ranges":[{"startOffset":370785,"endOffset":370822,"count":1}],"isBlockCoverage":true},{"functionName":"runGuarded$1","ranges":[{"startOffset":370842,"endOffset":371321,"count":0}],"isBlockCoverage":false},{"functionName":"runUnaryGuarded$1$2","ranges":[{"startOffset":371348,"endOffset":371910,"count":0}],"isBlockCoverage":false},{"functionName":"runBinaryGuarded$2$3","ranges":[{"startOffset":371938,"endOffset":372581,"count":0}],"isBlockCoverage":false},{"functionName":"bindCallback$1$1","ranges":[{"startOffset":372605,"endOffset":372733,"count":0}],"isBlockCoverage":false},{"functionName":"bindCallbackGuarded$1","ranges":[{"startOffset":372762,"endOffset":372889,"count":0}],"isBlockCoverage":false},{"functionName":"bindUnaryCallbackGuarded$1$1","ranges":[{"startOffset":372925,"endOffset":373077,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":373091,"endOffset":373129,"count":0}],"isBlockCoverage":false},{"functionName":"handleUncaughtError$2","ranges":[{"startOffset":373158,"endOffset":373305,"count":0}],"isBlockCoverage":false},{"functionName":"fork$2$specification$zoneValues","ranges":[{"startOffset":373344,"endOffset":373458,"count":1}],"isBlockCoverage":true},{"functionName":"run$1$1","ranges":[{"startOffset":373473,"endOffset":373668,"count":0}],"isBlockCoverage":false},{"functionName":"runUnary$2$2","ranges":[{"startOffset":373688,"endOffset":373966,"count":0}],"isBlockCoverage":false},{"functionName":"runBinary$3$3","ranges":[{"startOffset":373987,"endOffset":374346,"count":0}],"isBlockCoverage":false},{"functionName":"registerCallback$1$1","ranges":[{"startOffset":374374,"endOffset":374454,"count":0}],"isBlockCoverage":false},{"functionName":"registerUnaryCallback$2$1","ranges":[{"startOffset":374487,"endOffset":374583,"count":0}],"isBlockCoverage":false},{"functionName":"registerBinaryCallback$3$1","ranges":[{"startOffset":374617,"endOffset":374721,"count":0}],"isBlockCoverage":false},{"functionName":"errorCallback$2","ranges":[{"startOffset":374744,"endOffset":374793,"count":0}],"isBlockCoverage":false},{"functionName":"scheduleMicrotask$1","ranges":[{"startOffset":374820,"endOffset":374933,"count":0}],"isBlockCoverage":false},{"functionName":"createPeriodicTimer$2","ranges":[{"startOffset":374962,"endOffset":375105,"count":0}],"isBlockCoverage":false},{"functionName":"print$1","ranges":[{"startOffset":375120,"endOffset":375172,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":375239,"endOffset":375306,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":375324,"endOffset":375379,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":375453,"endOffset":375517,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":375664,"endOffset":375804,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":375822,"endOffset":375889,"count":0}],"isBlockCoverage":false},{"functionName":"call$5","ranges":[{"startOffset":375942,"endOffset":376743,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":376812,"endOffset":376870,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":376889,"endOffset":376953,"count":0}],"isBlockCoverage":false},{"functionName":"get$keys","ranges":[{"startOffset":376969,"endOffset":377070,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":377091,"endOffset":377529,"count":0}],"isBlockCoverage":false},{"functionName":"_containsKey$1","ranges":[{"startOffset":377551,"endOffset":377737,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":377751,"endOffset":378258,"count":0}],"isBlockCoverage":false},{"functionName":"_get$1","ranges":[{"startOffset":378272,"endOffset":378549,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":378566,"endOffset":379433,"count":0}],"isBlockCoverage":false},{"functionName":"_set$2","ranges":[{"startOffset":379447,"endOffset":380330,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":380347,"endOffset":380898,"count":0}],"isBlockCoverage":false},{"functionName":"_collection$_computeKeys$0","ranges":[{"startOffset":380932,"endOffset":382221,"count":0}],"isBlockCoverage":false},{"functionName":"_collection$_addHashTableEntry$3","ranges":[{"startOffset":382261,"endOffset":382617,"count":0}],"isBlockCoverage":false},{"functionName":"_computeHashCode$1","ranges":[{"startOffset":382643,"endOffset":382712,"count":0}],"isBlockCoverage":false},{"functionName":"_getBucket$2","ranges":[{"startOffset":382732,"endOffset":382810,"count":0}],"isBlockCoverage":false},{"functionName":"_findBucketIndex$2","ranges":[{"startOffset":382836,"endOffset":383075,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":383135,"endOffset":383198,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":383217,"endOffset":383286,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":383306,"endOffset":383438,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":383499,"endOffset":383557,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":383575,"endOffset":384056,"count":0}],"isBlockCoverage":false},{"functionName":"set$_collection$_current","ranges":[{"startOffset":384088,"endOffset":384223,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":384300,"endOffset":384484,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":384502,"endOffset":384560,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":384578,"endOffset":385195,"count":1},{"startOffset":384662,"endOffset":384687,"count":0},{"startOffset":384689,"endOffset":384885,"count":0},{"startOffset":385049,"endOffset":385189,"count":0}],"isBlockCoverage":true},{"functionName":"_contains$1","ranges":[{"startOffset":385214,"endOffset":385409,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":385422,"endOffset":386268,"count":0}],"isBlockCoverage":false},{"functionName":"_collection$_add$1","ranges":[{"startOffset":386294,"endOffset":386943,"count":0}],"isBlockCoverage":false},{"functionName":"remove$1","ranges":[{"startOffset":386959,"endOffset":387360,"count":1},{"startOffset":387018,"endOffset":387043,"count":0},{"startOffset":387053,"endOffset":387136,"count":0},{"startOffset":387304,"endOffset":387354,"count":0}],"isBlockCoverage":true},{"functionName":"_remove$1","ranges":[{"startOffset":387377,"endOffset":387746,"count":0}],"isBlockCoverage":false},{"functionName":"_collection$_addHashTableEntry$2","ranges":[{"startOffset":387786,"endOffset":388089,"count":0}],"isBlockCoverage":false},{"functionName":"_collection$_removeHashTableEntry$2","ranges":[{"startOffset":388132,"endOffset":388443,"count":1},{"startOffset":388221,"endOffset":388442,"count":0}],"isBlockCoverage":true},{"functionName":"_collection$_modified$0","ranges":[{"startOffset":388474,"endOffset":388582,"count":0}],"isBlockCoverage":false},{"functionName":"_collection$_newLinkedCell$1","ranges":[{"startOffset":388618,"endOffset":389176,"count":0}],"isBlockCoverage":false},{"functionName":"_collection$_unlinkCell$1","ranges":[{"startOffset":389209,"endOffset":389658,"count":0}],"isBlockCoverage":false},{"functionName":"_computeHashCode$1","ranges":[{"startOffset":389684,"endOffset":389761,"count":0}],"isBlockCoverage":false},{"functionName":"_getBucket$2","ranges":[{"startOffset":389781,"endOffset":389867,"count":0}],"isBlockCoverage":false},{"functionName":"_findBucketIndex$2","ranges":[{"startOffset":389893,"endOffset":390203,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":390306,"endOffset":390364,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":390382,"endOffset":390971,"count":0}],"isBlockCoverage":false},{"functionName":"set$_collection$_current","ranges":[{"startOffset":391003,"endOffset":391138,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":391329,"endOffset":391499,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":391518,"endOffset":391594,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":391613,"endOffset":391685,"count":0}],"isBlockCoverage":false},{"functionName":"get$isNotEmpty","ranges":[{"startOffset":391707,"endOffset":391775,"count":0}],"isBlockCoverage":false},{"functionName":"fillRange$3","ranges":[{"startOffset":391794,"endOffset":392116,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":392134,"endOffset":392230,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":392322,"endOffset":392591,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":392659,"endOffset":393030,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":393048,"endOffset":393131,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":393150,"endOffset":393234,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":393252,"endOffset":393313,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":393389,"endOffset":393708,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":393752,"endOffset":393815,"count":1}],"isBlockCoverage":true},{"functionName":"$indexSet","ranges":[{"startOffset":393832,"endOffset":394035,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":394052,"endOffset":394236,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":394255,"endOffset":394333,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":394351,"endOffset":394428,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":394446,"endOffset":394504,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":394608,"endOffset":394693,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":394926,"endOffset":395244,"count":1},{"startOffset":395025,"endOffset":395058,"count":0},{"startOffset":395107,"endOffset":395114,"count":0},{"startOffset":395221,"endOffset":395229,"count":0}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":395262,"endOffset":395383,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":395402,"endOffset":395463,"count":0}],"isBlockCoverage":false},{"functionName":"get$keys","ranges":[{"startOffset":395479,"endOffset":395703,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":395720,"endOffset":396180,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":396201,"endOffset":396375,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":396392,"endOffset":397032,"count":1},{"startOffset":396553,"endOffset":396587,"count":0},{"startOffset":396958,"endOffset":397018,"count":0}],"isBlockCoverage":true},{"functionName":"_computeKeys$0","ranges":[{"startOffset":397054,"endOffset":397276,"count":1}],"isBlockCoverage":true},{"functionName":"_upgrade$0","ranges":[{"startOffset":397294,"endOffset":397882,"count":0}],"isBlockCoverage":false},{"functionName":"_process$1","ranges":[{"startOffset":397900,"endOffset":398131,"count":1},{"startOffset":398012,"endOffset":398019,"count":0}],"isBlockCoverage":true},{"functionName":"$asMapMixin","ranges":[{"startOffset":398150,"endOffset":398199,"count":0}],"isBlockCoverage":false},{"functionName":"$asMap","ranges":[{"startOffset":398213,"endOffset":398262,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":398322,"endOffset":398411,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":398430,"endOffset":398755,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":398775,"endOffset":399090,"count":0}],"isBlockCoverage":false},{"functionName":"$asEfficientLengthIterable","ranges":[{"startOffset":399124,"endOffset":399167,"count":0}],"isBlockCoverage":false},{"functionName":"$asListIterable","ranges":[{"startOffset":399190,"endOffset":399233,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":399252,"endOffset":399295,"count":0}],"isBlockCoverage":false},{"functionName":"encode$1","ranges":[{"startOffset":399344,"endOffset":399419,"count":0}],"isBlockCoverage":false},{"functionName":"convert$1","ranges":[{"startOffset":399480,"endOffset":400124,"count":0}],"isBlockCoverage":false},{"functionName":"$asStreamTransformer","ranges":[{"startOffset":400152,"endOffset":400212,"count":0}],"isBlockCoverage":false},{"functionName":"$asConverter","ranges":[{"startOffset":400232,"endOffset":400292,"count":0}],"isBlockCoverage":false},{"functionName":"normalize$3","ranges":[{"startOffset":400378,"endOffset":404030,"count":0}],"isBlockCoverage":false},{"functionName":"$asCodec","ranges":[{"startOffset":404046,"endOffset":404106,"count":0}],"isBlockCoverage":false},{"functionName":"$asStreamTransformer","ranges":[{"startOffset":404170,"endOffset":404230,"count":0}],"isBlockCoverage":false},{"functionName":"$asConverter","ranges":[{"startOffset":404250,"endOffset":404310,"count":0}],"isBlockCoverage":false},{"functionName":"$asCodec","ranges":[{"startOffset":404386,"endOffset":404437,"count":0}],"isBlockCoverage":false},{"functionName":"$asCodec","ranges":[{"startOffset":404514,"endOffset":404574,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":404641,"endOffset":404894,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":404950,"endOffset":405016,"count":0}],"isBlockCoverage":false},{"functionName":"decode$2$reviver","ranges":[{"startOffset":405072,"endOffset":405191,"count":1}],"isBlockCoverage":true},{"functionName":"encode$2$toEncodable","ranges":[{"startOffset":405219,"endOffset":405389,"count":1}],"isBlockCoverage":true},{"functionName":"get$encoder","ranges":[{"startOffset":405408,"endOffset":405464,"count":1}],"isBlockCoverage":true},{"functionName":"get$decoder","ranges":[{"startOffset":405483,"endOffset":405534,"count":1}],"isBlockCoverage":true},{"functionName":"$asCodec","ranges":[{"startOffset":405550,"endOffset":405603,"count":0}],"isBlockCoverage":false},{"functionName":"$asStreamTransformer","ranges":[{"startOffset":405665,"endOffset":405718,"count":0}],"isBlockCoverage":false},{"functionName":"$asConverter","ranges":[{"startOffset":405738,"endOffset":405791,"count":0}],"isBlockCoverage":false},{"functionName":"$asStreamTransformer","ranges":[{"startOffset":405853,"endOffset":405906,"count":0}],"isBlockCoverage":false},{"functionName":"$asConverter","ranges":[{"startOffset":405926,"endOffset":405979,"count":0}],"isBlockCoverage":false},{"functionName":"writeStringContent$1","ranges":[{"startOffset":406046,"endOffset":407693,"count":1},{"startOffset":406329,"endOffset":407300,"count":0},{"startOffset":407346,"endOffset":407538,"count":0},{"startOffset":407601,"endOffset":407687,"count":0}],"isBlockCoverage":true},{"functionName":"_checkCycle$1","ranges":[{"startOffset":407714,"endOffset":408027,"count":1},{"startOffset":407871,"endOffset":407883,"count":0},{"startOffset":407911,"endOffset":407970,"count":0}],"isBlockCoverage":true},{"functionName":"writeObject$1","ranges":[{"startOffset":408048,"endOffset":408754,"count":1},{"startOffset":408163,"endOffset":408748,"count":0}],"isBlockCoverage":true},{"functionName":"writeJsonValue$1","ranges":[{"startOffset":408778,"endOffset":410030,"count":1},{"startOffset":408901,"endOffset":408914,"count":0},{"startOffset":409006,"endOffset":409072,"count":0},{"startOffset":409100,"endOffset":409167,"count":0},{"startOffset":409655,"endOffset":409678,"count":0},{"startOffset":409908,"endOffset":409931,"count":0},{"startOffset":409987,"endOffset":410016,"count":0}],"isBlockCoverage":true},{"functionName":"writeList$1","ranges":[{"startOffset":410049,"endOffset":410429,"count":1}],"isBlockCoverage":true},{"functionName":"writeMap$1","ranges":[{"startOffset":410447,"endOffset":411384,"count":1},{"startOffset":410929,"endOffset":410942,"count":0},{"startOffset":411241,"endOffset":411274,"count":0}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":411454,"endOffset":411738,"count":1},{"startOffset":411538,"endOffset":411572,"count":0}],"isBlockCoverage":true},{"functionName":"get$_partialResult","ranges":[{"startOffset":411829,"endOffset":411944,"count":0}],"isBlockCoverage":false},{"functionName":"writeNumber$1","ranges":[{"startOffset":411965,"endOffset":412063,"count":1}],"isBlockCoverage":true},{"functionName":"writeString$1","ranges":[{"startOffset":412084,"endOffset":412151,"count":1}],"isBlockCoverage":true},{"functionName":"writeStringSlice$3","ranges":[{"startOffset":412177,"endOffset":412285,"count":0}],"isBlockCoverage":false},{"functionName":"writeCharCode$1","ranges":[{"startOffset":412308,"endOffset":412387,"count":0}],"isBlockCoverage":false},{"functionName":"get$encoder","ranges":[{"startOffset":412438,"endOffset":412486,"count":0}],"isBlockCoverage":false},{"functionName":"convert$1","ranges":[{"startOffset":412537,"endOffset":413070,"count":0}],"isBlockCoverage":false},{"functionName":"$asStreamTransformer","ranges":[{"startOffset":413098,"endOffset":413158,"count":0}],"isBlockCoverage":false},{"functionName":"$asConverter","ranges":[{"startOffset":413178,"endOffset":413238,"count":0}],"isBlockCoverage":false},{"functionName":"_writeSurrogate$2","ranges":[{"startOffset":413298,"endOffset":414650,"count":0}],"isBlockCoverage":false},{"functionName":"_fillBuffer$3","ranges":[{"startOffset":414671,"endOffset":416478,"count":0}],"isBlockCoverage":false},{"functionName":"convert$1","ranges":[{"startOffset":416529,"endOffset":417119,"count":1},{"startOffset":416771,"endOffset":416785,"count":0},{"startOffset":417103,"endOffset":417107,"count":0}],"isBlockCoverage":true},{"functionName":"$asStreamTransformer","ranges":[{"startOffset":417147,"endOffset":417207,"count":0}],"isBlockCoverage":false},{"functionName":"$asConverter","ranges":[{"startOffset":417227,"endOffset":417287,"count":0}],"isBlockCoverage":false},{"functionName":"flush$2","ranges":[{"startOffset":417337,"endOffset":417609,"count":1},{"startOffset":417475,"endOffset":417603,"count":0}],"isBlockCoverage":true},{"functionName":"convert$3","ranges":[{"startOffset":417626,"endOffset":421538,"count":1},{"startOffset":418311,"endOffset":419809,"count":0},{"startOffset":420150,"endOffset":421331,"count":0},{"startOffset":421410,"endOffset":421532,"count":0}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":421610,"endOffset":421735,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":421826,"endOffset":422161,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":422248,"endOffset":422415,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":422435,"endOffset":422566,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":422584,"endOffset":423195,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":423264,"endOffset":423417,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":423437,"endOffset":423515,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":423533,"endOffset":424155,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":424219,"endOffset":424494,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":424578,"endOffset":424661,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":424763,"endOffset":424813,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorName","ranges":[{"startOffset":424871,"endOffset":424955,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorExplanation","ranges":[{"startOffset":424984,"endOffset":425019,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":425037,"endOffset":425551,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorName","ranges":[{"startOffset":425606,"endOffset":425651,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorExplanation","ranges":[{"startOffset":425680,"endOffset":426274,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorName","ranges":[{"startOffset":426329,"endOffset":426374,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorExplanation","ranges":[{"startOffset":426403,"endOffset":426799,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":426817,"endOffset":426869,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":426927,"endOffset":427772,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":427829,"endOffset":427903,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":427962,"endOffset":428088,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":428139,"endOffset":428201,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":428269,"endOffset":428498,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":428555,"endOffset":428604,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":428680,"endOffset":428730,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":428813,"endOffset":429012,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":429063,"endOffset":429125,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":429181,"endOffset":431814,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":431916,"endOffset":432069,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":432088,"endOffset":432159,"count":0}],"isBlockCoverage":false},{"functionName":"skipWhile$1","ranges":[{"startOffset":432178,"endOffset":432378,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":432395,"endOffset":432580,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":432596,"endOffset":432864,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":432883,"endOffset":433294,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":433312,"endOffset":433398,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":433568,"endOffset":433650,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":433668,"endOffset":433708,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":433808,"endOffset":433863,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":433883,"endOffset":433950,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":433968,"endOffset":434059,"count":0}],"isBlockCoverage":false},{"functionName":"noSuchMethod$1","ranges":[{"startOffset":434081,"endOffset":434328,"count":0}],"isBlockCoverage":false},{"functionName":"toString","ranges":[{"startOffset":434344,"endOffset":434398,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":434513,"endOffset":434563,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":434678,"endOffset":434733,"count":0}],"isBlockCoverage":false},{"functionName":"write$1","ranges":[{"startOffset":434748,"endOffset":434803,"count":1}],"isBlockCoverage":true},{"functionName":"writeCharCode$1","ranges":[{"startOffset":434826,"endOffset":434919,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":434937,"endOffset":435033,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":435148,"endOffset":435892,"count":1},{"startOffset":435410,"endOffset":435547,"count":0}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":435976,"endOffset":436109,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":436192,"endOffset":436325,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":436339,"endOffset":436397,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":436483,"endOffset":436948,"count":0}],"isBlockCoverage":false},{"functionName":"get$userInfo","ranges":[{"startOffset":437015,"endOffset":437062,"count":0}],"isBlockCoverage":false},{"functionName":"get$host","ranges":[{"startOffset":437078,"endOffset":437303,"count":0}],"isBlockCoverage":false},{"functionName":"get$port","ranges":[{"startOffset":437319,"endOffset":437453,"count":0}],"isBlockCoverage":false},{"functionName":"get$query","ranges":[{"startOffset":437470,"endOffset":437551,"count":0}],"isBlockCoverage":false},{"functionName":"get$fragment","ranges":[{"startOffset":437571,"endOffset":437655,"count":0}],"isBlockCoverage":false},{"functionName":"get$pathSegments","ranges":[{"startOffset":437679,"endOffset":438447,"count":0}],"isBlockCoverage":false},{"functionName":"get$queryParameters","ranges":[{"startOffset":438474,"endOffset":438764,"count":1},{"startOffset":438691,"endOffset":438695,"count":0}],"isBlockCoverage":true},{"functionName":"_mergePaths$2","ranges":[{"startOffset":438785,"endOffset":439869,"count":0}],"isBlockCoverage":false},{"functionName":"resolve$1","ranges":[{"startOffset":439886,"endOffset":439969,"count":0}],"isBlockCoverage":false},{"functionName":"resolveUri$1","ranges":[{"startOffset":439989,"endOffset":442823,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasAuthority","ranges":[{"startOffset":442847,"endOffset":442898,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasPort","ranges":[{"startOffset":442917,"endOffset":442968,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasQuery","ranges":[{"startOffset":442988,"endOffset":443040,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasFragment","ranges":[{"startOffset":443063,"endOffset":443118,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasAbsolutePath","ranges":[{"startOffset":443145,"endOffset":443210,"count":0}],"isBlockCoverage":false},{"functionName":"toFilePath$0","ranges":[{"startOffset":443230,"endOffset":444436,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":444454,"endOffset":445288,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":445299,"endOffset":446881,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":446901,"endOffset":447105,"count":0}],"isBlockCoverage":false},{"functionName":"set$_pathSegments","ranges":[{"startOffset":447130,"endOffset":447254,"count":0}],"isBlockCoverage":false},{"functionName":"set$_queryParameters","ranges":[{"startOffset":447282,"endOffset":447436,"count":1}],"isBlockCoverage":true},{"functionName":"get$scheme","ranges":[{"startOffset":447469,"endOffset":447513,"count":0}],"isBlockCoverage":false},{"functionName":"get$path","ranges":[{"startOffset":447529,"endOffset":447579,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":447643,"endOffset":447836,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":447944,"endOffset":448269,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":448348,"endOffset":448460,"count":0}],"isBlockCoverage":false},{"functionName":"get$uri","ranges":[{"startOffset":448525,"endOffset":449212,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":449230,"endOffset":449434,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":449492,"endOffset":449544,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":449620,"endOffset":449847,"count":1},{"startOffset":449723,"endOffset":449749,"count":0}],"isBlockCoverage":true},{"functionName":"call$3","ranges":[{"startOffset":449926,"endOffset":450216,"count":1},{"startOffset":450142,"endOffset":450169,"count":0}],"isBlockCoverage":true},{"functionName":"call$3","ranges":[{"startOffset":450275,"endOffset":450601,"count":1},{"startOffset":450527,"endOffset":450554,"count":0}],"isBlockCoverage":true},{"functionName":"get$hasAuthority","ranges":[{"startOffset":450658,"endOffset":450710,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasPort","ranges":[{"startOffset":450729,"endOffset":451079,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasQuery","ranges":[{"startOffset":451099,"endOffset":451337,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasFragment","ranges":[{"startOffset":451360,"endOffset":451538,"count":0}],"isBlockCoverage":false},{"functionName":"get$_isFile","ranges":[{"startOffset":451557,"endOffset":451650,"count":0}],"isBlockCoverage":false},{"functionName":"get$_isHttp","ranges":[{"startOffset":451669,"endOffset":451762,"count":0}],"isBlockCoverage":false},{"functionName":"get$_isHttps","ranges":[{"startOffset":451782,"endOffset":451876,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasAbsolutePath","ranges":[{"startOffset":451903,"endOffset":451985,"count":0}],"isBlockCoverage":false},{"functionName":"get$scheme","ranges":[{"startOffset":452003,"endOffset":452773,"count":0}],"isBlockCoverage":false},{"functionName":"get$userInfo","ranges":[{"startOffset":452793,"endOffset":453028,"count":0}],"isBlockCoverage":false},{"functionName":"get$host","ranges":[{"startOffset":453044,"endOffset":453171,"count":0}],"isBlockCoverage":false},{"functionName":"get$port","ranges":[{"startOffset":453187,"endOffset":453563,"count":0}],"isBlockCoverage":false},{"functionName":"get$path","ranges":[{"startOffset":453579,"endOffset":453674,"count":0}],"isBlockCoverage":false},{"functionName":"get$query","ranges":[{"startOffset":453691,"endOffset":453975,"count":0}],"isBlockCoverage":false},{"functionName":"get$fragment","ranges":[{"startOffset":453995,"endOffset":454227,"count":0}],"isBlockCoverage":false},{"functionName":"get$pathSegments","ranges":[{"startOffset":454251,"endOffset":455219,"count":0}],"isBlockCoverage":false},{"functionName":"get$queryParameters","ranges":[{"startOffset":455246,"endOffset":455623,"count":0}],"isBlockCoverage":false},{"functionName":"_isPort$1","ranges":[{"startOffset":455640,"endOffset":455927,"count":0}],"isBlockCoverage":false},{"functionName":"removeFragment$0","ranges":[{"startOffset":455951,"endOffset":456335,"count":0}],"isBlockCoverage":false},{"functionName":"resolve$1","ranges":[{"startOffset":456352,"endOffset":456435,"count":0}],"isBlockCoverage":false},{"functionName":"resolveUri$1","ranges":[{"startOffset":456455,"endOffset":456640,"count":0}],"isBlockCoverage":false},{"functionName":"_simpleMerge$2","ranges":[{"startOffset":456662,"endOffset":462688,"count":0}],"isBlockCoverage":false},{"functionName":"toFilePath$0","ranges":[{"startOffset":462708,"endOffset":463987,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":464007,"endOffset":464186,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":464197,"endOffset":464401,"count":0}],"isBlockCoverage":false},{"functionName":"_toNonSimple$0","ranges":[{"startOffset":464423,"endOffset":465061,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":465079,"endOffset":465122,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":465252,"endOffset":465309,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":465361,"endOffset":465418,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":465507,"endOffset":465563,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":465616,"endOffset":465673,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":465726,"endOffset":465782,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":465830,"endOffset":465889,"count":0}],"isBlockCoverage":false},{"functionName":"get$onClick","ranges":[{"startOffset":465908,"endOffset":466020,"count":0}],"isBlockCoverage":false},{"functionName":"addEventListener$3","ranges":[{"startOffset":466136,"endOffset":466350,"count":1}],"isBlockCoverage":true},{"functionName":"_addEventListener$3","ranges":[{"startOffset":466377,"endOffset":466569,"count":1}],"isBlockCoverage":true},{"functionName":"_removeEventListener$3","ranges":[{"startOffset":466599,"endOffset":466794,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":466904,"endOffset":466960,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":467015,"endOffset":467071,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":467085,"endOffset":467319,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":467336,"endOffset":467547,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":467566,"endOffset":467719,"count":0}],"isBlockCoverage":false},{"functionName":"$asEfficientLengthIterable","ranges":[{"startOffset":467788,"endOffset":467829,"count":0}],"isBlockCoverage":false},{"functionName":"$asJavaScriptIndexingBehavior","ranges":[{"startOffset":467904,"endOffset":467945,"count":0}],"isBlockCoverage":false},{"functionName":"$asListMixin","ranges":[{"startOffset":467965,"endOffset":468006,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":468045,"endOffset":468086,"count":0}],"isBlockCoverage":false},{"functionName":"$asList","ranges":[{"startOffset":468117,"endOffset":468158,"count":0}],"isBlockCoverage":false},{"functionName":"$asImmutableListMixin","ranges":[{"startOffset":468187,"endOffset":468228,"count":0}],"isBlockCoverage":false},{"functionName":"get$origin","ranges":[{"startOffset":468330,"endOffset":468485,"count":1},{"startOffset":468414,"endOffset":468484,"count":0}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":468503,"endOffset":468560,"count":0}],"isBlockCoverage":false},{"functionName":"addEventListener$3","ranges":[{"startOffset":468671,"endOffset":468926,"count":1}],"isBlockCoverage":true},{"functionName":"postMessage$1","ranges":[{"startOffset":468947,"endOffset":469079,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":469194,"endOffset":469338,"count":0}],"isBlockCoverage":false},{"functionName":"_removeChild$1","ranges":[{"startOffset":469360,"endOffset":469435,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":469505,"endOffset":469561,"count":0}],"isBlockCoverage":false},{"functionName":"get$location","ranges":[{"startOffset":469638,"endOffset":469696,"count":1}],"isBlockCoverage":true},{"functionName":"postMessage$3","ranges":[{"startOffset":469717,"endOffset":469975,"count":0}],"isBlockCoverage":false},{"functionName":"_postMessage_1$3","ranges":[{"startOffset":469999,"endOffset":470177,"count":0}],"isBlockCoverage":false},{"functionName":"listen$4$cancelOnError$onDone$onError","ranges":[{"startOffset":470279,"endOffset":470605,"count":0}],"isBlockCoverage":false},{"functionName":"listen$1","ranges":[{"startOffset":470621,"endOffset":470728,"count":0}],"isBlockCoverage":false},{"functionName":"listen$3$onDone$onError","ranges":[{"startOffset":470759,"endOffset":470888,"count":0}],"isBlockCoverage":false},{"functionName":"cancel$0","ranges":[{"startOffset":470995,"endOffset":471170,"count":0}],"isBlockCoverage":false},{"functionName":"_tryResume$0","ranges":[{"startOffset":471190,"endOffset":471364,"count":1}],"isBlockCoverage":true},{"functionName":"_unlisten$0","ranges":[{"startOffset":471383,"endOffset":471696,"count":0}],"isBlockCoverage":false},{"functionName":"set$_onData","ranges":[{"startOffset":471715,"endOffset":471819,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":471888,"endOffset":471979,"count":1}],"isBlockCoverage":true},{"functionName":"get$iterator","ranges":[{"startOffset":472060,"endOffset":472239,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":472301,"endOffset":472764,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":472783,"endOffset":472829,"count":0}],"isBlockCoverage":false},{"functionName":"set$_current","ranges":[{"startOffset":472849,"endOffset":472972,"count":0}],"isBlockCoverage":false},{"functionName":"postMessage$3","ranges":[{"startOffset":473056,"endOffset":473227,"count":1}],"isBlockCoverage":true},{"functionName":"findSlot$1","ranges":[{"startOffset":473464,"endOffset":473763,"count":1},{"startOffset":473634,"endOffset":473643,"count":0}],"isBlockCoverage":true},{"functionName":"walk$1","ranges":[{"startOffset":473777,"endOffset":475247,"count":1},{"startOffset":474098,"endOffset":474130,"count":0},{"startOffset":474165,"endOffset":474240,"count":0},{"startOffset":474273,"endOffset":474282,"count":0},{"startOffset":474315,"endOffset":474324,"count":0},{"startOffset":474419,"endOffset":474428,"count":0},{"startOffset":474556,"endOffset":474581,"count":0},{"startOffset":474667,"endOffset":474679,"count":0},{"startOffset":475007,"endOffset":475032,"count":0},{"startOffset":475094,"endOffset":475106,"count":0},{"startOffset":475155,"endOffset":475246,"count":0}],"isBlockCoverage":true},{"functionName":"copyList$2","ranges":[{"startOffset":475265,"endOffset":475616,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":475682,"endOffset":475766,"count":1}],"isBlockCoverage":true},{"functionName":"findSlot$1","ranges":[{"startOffset":475849,"endOffset":476208,"count":1},{"startOffset":476029,"endOffset":476044,"count":0},{"startOffset":476071,"endOffset":476080,"count":0}],"isBlockCoverage":true},{"functionName":"walk$1","ranges":[{"startOffset":476222,"endOffset":478314,"count":1},{"startOffset":476555,"endOffset":476884,"count":0},{"startOffset":476924,"endOffset":476999,"count":0},{"startOffset":477073,"endOffset":477118,"count":0},{"startOffset":477319,"endOffset":477344,"count":0},{"startOffset":477434,"endOffset":477446,"count":0},{"startOffset":477849,"endOffset":477874,"count":0},{"startOffset":477936,"endOffset":477948,"count":0},{"startOffset":478073,"endOffset":478076,"count":0},{"startOffset":478292,"endOffset":478313,"count":0}],"isBlockCoverage":true},{"functionName":"convertNativeToDart_AcceptStructuredClone$2$mustCopy","ranges":[{"startOffset":478374,"endOffset":478470,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":478542,"endOffset":478706,"count":1}],"isBlockCoverage":true},{"functionName":"forEachJsField$2","ranges":[{"startOffset":478846,"endOffset":479184,"count":1},{"startOffset":479052,"endOffset":479098,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":479261,"endOffset":479336,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":479433,"endOffset":479510,"count":0}],"isBlockCoverage":false},{"functionName":"get$onClick","ranges":[{"startOffset":479581,"endOffset":479693,"count":1}],"isBlockCoverage":true},{"functionName":"$asEfficientLengthIterable","ranges":[{"startOffset":479789,"endOffset":479829,"count":0}],"isBlockCoverage":false},{"functionName":"$asIterable","ranges":[{"startOffset":479868,"endOffset":479908,"count":0}],"isBlockCoverage":false},{"functionName":"$asList","ranges":[{"startOffset":479939,"endOffset":479979,"count":0}],"isBlockCoverage":false},{"functionName":"addStream$1","ranges":[{"startOffset":480035,"endOffset":480478,"count":0}],"isBlockCoverage":false},{"functionName":"_checkEventAllowed$0","ranges":[{"startOffset":480506,"endOffset":480767,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":480782,"endOffset":480870,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":480987,"endOffset":481045,"count":0}],"isBlockCoverage":false},{"functionName":"absolute$7","ranges":[{"startOffset":481161,"endOffset":481639,"count":0}],"isBlockCoverage":false},{"functionName":"absolute$1","ranges":[{"startOffset":481657,"endOffset":481775,"count":0}],"isBlockCoverage":false},{"functionName":"join$8","ranges":[{"startOffset":481789,"endOffset":482229,"count":0}],"isBlockCoverage":false},{"functionName":"join$2","ranges":[{"startOffset":482243,"endOffset":482371,"count":0}],"isBlockCoverage":false},{"functionName":"joinAll$1","ranges":[{"startOffset":482388,"endOffset":483822,"count":0}],"isBlockCoverage":false},{"functionName":"split$1","ranges":[{"startOffset":483837,"endOffset":484322,"count":0}],"isBlockCoverage":false},{"functionName":"normalize$1","ranges":[{"startOffset":484341,"endOffset":484574,"count":0}],"isBlockCoverage":false},{"functionName":"_needsNormalization$1","ranges":[{"startOffset":484603,"endOffset":486114,"count":0}],"isBlockCoverage":false},{"functionName":"relative$1","ranges":[{"startOffset":486132,"endOffset":488870,"count":0}],"isBlockCoverage":false},{"functionName":"toUri$1","ranges":[{"startOffset":488885,"endOffset":489181,"count":0}],"isBlockCoverage":false},{"functionName":"prettyUri$1","ranges":[{"startOffset":489200,"endOffset":489763,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":489820,"endOffset":489888,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":489967,"endOffset":490034,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":490111,"endOffset":490184,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":490264,"endOffset":490368,"count":0}],"isBlockCoverage":false},{"functionName":"getRoot$1","ranges":[{"startOffset":490441,"endOffset":490777,"count":0}],"isBlockCoverage":false},{"functionName":"relativePathToUri$1","ranges":[{"startOffset":490804,"endOffset":491061,"count":0}],"isBlockCoverage":false},{"functionName":"pathsEqual$2","ranges":[{"startOffset":491081,"endOffset":491140,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasTrailingSeparator","ranges":[{"startOffset":491205,"endOffset":491442,"count":0}],"isBlockCoverage":false},{"functionName":"removeTrailingSeparators$0","ranges":[{"startOffset":491476,"endOffset":491891,"count":0}],"isBlockCoverage":false},{"functionName":"normalize$0","ranges":[{"startOffset":491910,"endOffset":493391,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":493409,"endOffset":493905,"count":0}],"isBlockCoverage":false},{"functionName":"set$parts","ranges":[{"startOffset":493922,"endOffset":494022,"count":0}],"isBlockCoverage":false},{"functionName":"set$separators","ranges":[{"startOffset":494044,"endOffset":494159,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":494224,"endOffset":494290,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":494364,"endOffset":494430,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":494476,"endOffset":494529,"count":0}],"isBlockCoverage":false},{"functionName":"containsSeparator$1","ranges":[{"startOffset":494589,"endOffset":494666,"count":0}],"isBlockCoverage":false},{"functionName":"isSeparator$1","ranges":[{"startOffset":494687,"endOffset":494743,"count":0}],"isBlockCoverage":false},{"functionName":"needsSeparator$1","ranges":[{"startOffset":494767,"endOffset":494881,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$2$withDrive","ranges":[{"startOffset":494911,"endOffset":495044,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$1","ranges":[{"startOffset":495064,"endOffset":495141,"count":0}],"isBlockCoverage":false},{"functionName":"isRootRelative$1","ranges":[{"startOffset":495165,"endOffset":495207,"count":0}],"isBlockCoverage":false},{"functionName":"pathFromUri$1","ranges":[{"startOffset":495228,"endOffset":495555,"count":0}],"isBlockCoverage":false},{"functionName":"absolutePathToUri$1","ranges":[{"startOffset":495582,"endOffset":495981,"count":0}],"isBlockCoverage":false},{"functionName":"get$name","ranges":[{"startOffset":495997,"endOffset":496047,"count":0}],"isBlockCoverage":false},{"functionName":"get$separator","ranges":[{"startOffset":496068,"endOffset":496115,"count":0}],"isBlockCoverage":false},{"functionName":"containsSeparator$1","ranges":[{"startOffset":496173,"endOffset":496250,"count":0}],"isBlockCoverage":false},{"functionName":"isSeparator$1","ranges":[{"startOffset":496271,"endOffset":496327,"count":0}],"isBlockCoverage":false},{"functionName":"needsSeparator$1","ranges":[{"startOffset":496351,"endOffset":496625,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$2$withDrive","ranges":[{"startOffset":496655,"endOffset":497605,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$1","ranges":[{"startOffset":497625,"endOffset":497702,"count":0}],"isBlockCoverage":false},{"functionName":"isRootRelative$1","ranges":[{"startOffset":497726,"endOffset":497817,"count":0}],"isBlockCoverage":false},{"functionName":"pathFromUri$1","ranges":[{"startOffset":497838,"endOffset":497892,"count":0}],"isBlockCoverage":false},{"functionName":"relativePathToUri$1","ranges":[{"startOffset":497919,"endOffset":497973,"count":0}],"isBlockCoverage":false},{"functionName":"absolutePathToUri$1","ranges":[{"startOffset":498000,"endOffset":498054,"count":0}],"isBlockCoverage":false},{"functionName":"get$name","ranges":[{"startOffset":498070,"endOffset":498120,"count":0}],"isBlockCoverage":false},{"functionName":"get$separator","ranges":[{"startOffset":498141,"endOffset":498188,"count":0}],"isBlockCoverage":false},{"functionName":"containsSeparator$1","ranges":[{"startOffset":498250,"endOffset":498327,"count":0}],"isBlockCoverage":false},{"functionName":"isSeparator$1","ranges":[{"startOffset":498348,"endOffset":498423,"count":0}],"isBlockCoverage":false},{"functionName":"needsSeparator$1","ranges":[{"startOffset":498447,"endOffset":498622,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$2$withDrive","ranges":[{"startOffset":498652,"endOffset":499519,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$1","ranges":[{"startOffset":499539,"endOffset":499616,"count":0}],"isBlockCoverage":false},{"functionName":"isRootRelative$1","ranges":[{"startOffset":499640,"endOffset":499706,"count":0}],"isBlockCoverage":false},{"functionName":"pathFromUri$1","ranges":[{"startOffset":499727,"endOffset":500380,"count":0}],"isBlockCoverage":false},{"functionName":"absolutePathToUri$1","ranges":[{"startOffset":500407,"endOffset":501556,"count":0}],"isBlockCoverage":false},{"functionName":"codeUnitsEqual$2","ranges":[{"startOffset":501580,"endOffset":501969,"count":0}],"isBlockCoverage":false},{"functionName":"pathsEqual$2","ranges":[{"startOffset":501989,"endOffset":502379,"count":0}],"isBlockCoverage":false},{"functionName":"get$name","ranges":[{"startOffset":502395,"endOffset":502445,"count":0}],"isBlockCoverage":false},{"functionName":"get$separator","ranges":[{"startOffset":502466,"endOffset":502513,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":502588,"endOffset":502655,"count":0}],"isBlockCoverage":false},{"functionName":"toTrace$0","ranges":[{"startOffset":502719,"endOffset":503068,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":503086,"endOffset":503628,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":503712,"endOffset":503885,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":503968,"endOffset":504053,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":504131,"endOffset":504223,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":504303,"endOffset":504679,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":504760,"endOffset":504879,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":504958,"endOffset":505296,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":505376,"endOffset":505558,"count":0}],"isBlockCoverage":false},{"functionName":"get$isCore","ranges":[{"startOffset":505624,"endOffset":505689,"count":0}],"isBlockCoverage":false},{"functionName":"get$library","ranges":[{"startOffset":505708,"endOffset":505863,"count":0}],"isBlockCoverage":false},{"functionName":"get$$package","ranges":[{"startOffset":505883,"endOffset":506053,"count":0}],"isBlockCoverage":false},{"functionName":"get$location","ranges":[{"startOffset":506073,"endOffset":506361,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":506379,"endOffset":506469,"count":0}],"isBlockCoverage":false},{"functionName":"get$uri","ranges":[{"startOffset":506484,"endOffset":506525,"count":0}],"isBlockCoverage":false},{"functionName":"get$line","ranges":[{"startOffset":506541,"endOffset":506583,"count":0}],"isBlockCoverage":false},{"functionName":"get$column","ranges":[{"startOffset":506601,"endOffset":506645,"count":0}],"isBlockCoverage":false},{"functionName":"get$member","ranges":[{"startOffset":506663,"endOffset":506707,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":506771,"endOffset":507825,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":507908,"endOffset":508742,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":508839,"endOffset":509859,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":509948,"endOffset":511172,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":511261,"endOffset":512805,"count":0}],"isBlockCoverage":false},{"functionName":"get$_trace","ranges":[{"startOffset":512874,"endOffset":513090,"count":0}],"isBlockCoverage":false},{"functionName":"get$frames","ranges":[{"startOffset":513108,"endOffset":513171,"count":0}],"isBlockCoverage":false},{"functionName":"get$terse","ranges":[{"startOffset":513188,"endOffset":513273,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":513291,"endOffset":513357,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":513456,"endOffset":513524,"count":0}],"isBlockCoverage":false},{"functionName":"get$terse","ranges":[{"startOffset":513589,"endOffset":513680,"count":0}],"isBlockCoverage":false},{"functionName":"foldFrames$2$terse","ranges":[{"startOffset":513706,"endOffset":515185,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":515203,"endOffset":515689,"count":0}],"isBlockCoverage":false},{"functionName":"get$frames","ranges":[{"startOffset":515729,"endOffset":515773,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":515834,"endOffset":515912,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":515991,"endOffset":516074,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":516151,"endOffset":516253,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":516331,"endOffset":516414,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":516495,"endOffset":516567,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":516649,"endOffset":516732,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":516814,"endOffset":516927,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":517010,"endOffset":517098,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":517181,"endOffset":517269,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":517353,"endOffset":517442,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":517517,"endOffset":517556,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":517637,"endOffset":517967,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":518049,"endOffset":518442,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":518522,"endOffset":518641,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":518720,"endOffset":518989,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":519063,"endOffset":519108,"count":0}],"isBlockCoverage":false},{"functionName":"get$uri","ranges":[{"startOffset":519140,"endOffset":519181,"count":0}],"isBlockCoverage":false},{"functionName":"get$line","ranges":[{"startOffset":519197,"endOffset":519239,"count":0}],"isBlockCoverage":false},{"functionName":"get$column","ranges":[{"startOffset":519257,"endOffset":519301,"count":0}],"isBlockCoverage":false},{"functionName":"get$isCore","ranges":[{"startOffset":519319,"endOffset":519363,"count":0}],"isBlockCoverage":false},{"functionName":"get$library","ranges":[{"startOffset":519382,"endOffset":519427,"count":0}],"isBlockCoverage":false},{"functionName":"get$$package","ranges":[{"startOffset":519447,"endOffset":519493,"count":0}],"isBlockCoverage":false},{"functionName":"get$location","ranges":[{"startOffset":519513,"endOffset":519567,"count":0}],"isBlockCoverage":false},{"functionName":"get$member","ranges":[{"startOffset":519585,"endOffset":519629,"count":0}],"isBlockCoverage":false},{"functionName":"GuaranteeChannel$3$allowSinkErrors","ranges":[{"startOffset":519710,"endOffset":520046,"count":1}],"isBlockCoverage":true},{"functionName":"_onSinkDisconnected$0","ranges":[{"startOffset":520075,"endOffset":520266,"count":0}],"isBlockCoverage":false},{"functionName":"set$_sink","ranges":[{"startOffset":520283,"endOffset":520401,"count":1}],"isBlockCoverage":true},{"functionName":"set$_streamController","ranges":[{"startOffset":520430,"endOffset":520588,"count":1}],"isBlockCoverage":true},{"functionName":"set$_guarantee_channel$_subscription","ranges":[{"startOffset":520632,"endOffset":520801,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":520862,"endOffset":521185,"count":1},{"startOffset":520956,"endOffset":520963,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":521266,"endOffset":521392,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":521510,"endOffset":522038,"count":1},{"startOffset":521653,"endOffset":521725,"count":0},{"startOffset":521781,"endOffset":521859,"count":0},{"startOffset":521898,"endOffset":521905,"count":0}],"isBlockCoverage":true},{"functionName":"addError$2","ranges":[{"startOffset":522056,"endOffset":522478,"count":0}],"isBlockCoverage":false},{"functionName":"addError$1","ranges":[{"startOffset":522496,"endOffset":522562,"count":0}],"isBlockCoverage":false},{"functionName":"_addError$2","ranges":[{"startOffset":522581,"endOffset":522735,"count":0}],"isBlockCoverage":false},{"functionName":"_addError$1","ranges":[{"startOffset":522754,"endOffset":522821,"count":0}],"isBlockCoverage":false},{"functionName":"addStream$1","ranges":[{"startOffset":522840,"endOffset":523722,"count":1},{"startOffset":522976,"endOffset":523049,"count":0},{"startOffset":523105,"endOffset":523184,"count":0},{"startOffset":523215,"endOffset":523334,"count":0}],"isBlockCoverage":true},{"functionName":"close$0","ranges":[{"startOffset":523737,"endOffset":524196,"count":0}],"isBlockCoverage":false},{"functionName":"_onStreamDisconnected$0","ranges":[{"startOffset":524227,"endOffset":524597,"count":0}],"isBlockCoverage":false},{"functionName":"set$_addStreamSubscription","ranges":[{"startOffset":524631,"endOffset":524808,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":524925,"endOffset":525051,"count":0}],"isBlockCoverage":false},{"functionName":"_MultiChannel$1","ranges":[{"startOffset":525129,"endOffset":525778,"count":1}],"isBlockCoverage":true},{"functionName":"virtualChannel$1","ranges":[{"startOffset":525802,"endOffset":527448,"count":1},{"startOffset":526029,"endOffset":526206,"count":0},{"startOffset":526253,"endOffset":526477,"count":0},{"startOffset":526530,"endOffset":526575,"count":0},{"startOffset":526702,"endOffset":526803,"count":0}],"isBlockCoverage":true},{"functionName":"_closeChannel$2","ranges":[{"startOffset":527471,"endOffset":527872,"count":0}],"isBlockCoverage":false},{"functionName":"_closeInnerChannel$0","ranges":[{"startOffset":527900,"endOffset":528350,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":528432,"endOffset":528620,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":528638,"endOffset":528705,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":528764,"endOffset":528829,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":528956,"endOffset":529518,"count":1},{"startOffset":529164,"endOffset":529171,"count":0},{"startOffset":529457,"endOffset":529512,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":529596,"endOffset":529733,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":529751,"endOffset":529835,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":529908,"endOffset":530159,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":530177,"endOffset":530277,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":530351,"endOffset":530463,"count":0}],"isBlockCoverage":false},{"functionName":"get$local","ranges":[{"startOffset":530647,"endOffset":530691,"count":0}],"isBlockCoverage":false},{"functionName":"set$_local","ranges":[{"startOffset":530709,"endOffset":530828,"count":1}],"isBlockCoverage":true},{"functionName":"set$_foreign","ranges":[{"startOffset":530848,"endOffset":530973,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":531139,"endOffset":532002,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":532120,"endOffset":533385,"count":1},{"startOffset":532816,"endOffset":533379,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":533455,"endOffset":533696,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":533767,"endOffset":534167,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":534238,"endOffset":534587,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":534706,"endOffset":534887,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":535005,"endOffset":535323,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":535453,"endOffset":535766,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":535848,"endOffset":535966,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":536046,"endOffset":537326,"count":1},{"startOffset":536265,"endOffset":536272,"count":0},{"startOffset":536472,"endOffset":536479,"count":0},{"startOffset":536965,"endOffset":537320,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":537408,"endOffset":537676,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":537758,"endOffset":538685,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":537952,"endOffset":538612,"count":1},{"startOffset":538042,"endOffset":538098,"count":0}],"isBlockCoverage":true},{"functionName":"aliases","ranges":[{"startOffset":538714,"endOffset":539149,"count":1}],"isBlockCoverage":true},{"functionName":"installTearOffs","ranges":[{"startOffset":539157,"endOffset":544148,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":540050,"endOffset":540089,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":540135,"endOffset":540205,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":540496,"endOffset":540593,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":540702,"endOffset":540820,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":540931,"endOffset":541070,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":541195,"endOffset":541305,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":541440,"endOffset":541561,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":541698,"endOffset":541826,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":542583,"endOffset":542622,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":542757,"endOffset":542796,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":542921,"endOffset":542960,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":543161,"endOffset":543200,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":543660,"endOffset":543699,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":543800,"endOffset":543839,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":544079,"endOffset":544134,"count":0}],"isBlockCoverage":false},{"functionName":"inheritance","ranges":[{"startOffset":544156,"endOffset":556574,"count":1}],"isBlockCoverage":true},{"functionName":"constants","ranges":[{"startOffset":556582,"endOffset":566012,"count":1}],"isBlockCoverage":true},{"functionName":"getTagFallback","ranges":[{"startOffset":557622,"endOffset":557736,"count":0}],"isBlockCoverage":false},{"functionName":"C.C_JS_CONST0","ranges":[{"startOffset":557758,"endOffset":558873,"count":1},{"startOffset":558781,"endOffset":558796,"count":0}],"isBlockCoverage":true},{"functionName":"getTag","ranges":[{"startOffset":557825,"endOffset":557928,"count":0}],"isBlockCoverage":false},{"functionName":"getUnknownTag","ranges":[{"startOffset":557931,"endOffset":558148,"count":0}],"isBlockCoverage":false},{"functionName":"getUnknownTagGenericBrowser","ranges":[{"startOffset":558151,"endOffset":558326,"count":0}],"isBlockCoverage":false},{"functionName":"prototypeForTag","ranges":[{"startOffset":558329,"endOffset":558595,"count":1},{"startOffset":558399,"endOffset":558411,"count":0},{"startOffset":558545,"endOffset":558557,"count":0}],"isBlockCoverage":true},{"functionName":"discriminator","ranges":[{"startOffset":558598,"endOffset":558642,"count":0}],"isBlockCoverage":false},{"functionName":"C.C_JS_CONST6","ranges":[{"startOffset":558895,"endOffset":559359,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":558931,"endOffset":559356,"count":1},{"startOffset":558987,"endOffset":559000,"count":0},{"startOffset":559078,"endOffset":559091,"count":0},{"startOffset":559317,"endOffset":559355,"count":0}],"isBlockCoverage":true},{"functionName":"confirm","ranges":[{"startOffset":559135,"endOffset":559242,"count":1}],"isBlockCoverage":true},{"functionName":"C.C_JS_CONST1","ranges":[{"startOffset":559381,"endOffset":559530,"count":1},{"startOffset":559468,"endOffset":559529,"count":0}],"isBlockCoverage":true},{"functionName":"C.C_JS_CONST2","ranges":[{"startOffset":559552,"endOffset":560025,"count":1}],"isBlockCoverage":true},{"functionName":"getTagFixed","ranges":[{"startOffset":559648,"endOffset":559829,"count":0}],"isBlockCoverage":false},{"functionName":"prototypeForTagFixed","ranges":[{"startOffset":559832,"endOffset":559945,"count":1}],"isBlockCoverage":true},{"functionName":"C.C_JS_CONST5","ranges":[{"startOffset":560047,"endOffset":560577,"count":1},{"startOffset":560134,"endOffset":560138,"count":0},{"startOffset":560195,"endOffset":560576,"count":0}],"isBlockCoverage":true},{"functionName":"getTagFirefox","ranges":[{"startOffset":560454,"endOffset":560543,"count":0}],"isBlockCoverage":false},{"functionName":"C.C_JS_CONST4","ranges":[{"startOffset":560599,"endOffset":561481,"count":1},{"startOffset":560686,"endOffset":560690,"count":0},{"startOffset":560748,"endOffset":561480,"count":0}],"isBlockCoverage":true},{"functionName":"getTagIE","ranges":[{"startOffset":561013,"endOffset":561256,"count":0}],"isBlockCoverage":false},{"functionName":"prototypeForTagIE","ranges":[{"startOffset":561259,"endOffset":561407,"count":0}],"isBlockCoverage":false},{"functionName":"C.C_JS_CONST3","ranges":[{"startOffset":561503,"endOffset":561536,"count":1}],"isBlockCoverage":true},{"functionName":"staticFields","ranges":[{"startOffset":566020,"endOffset":566720,"count":1}],"isBlockCoverage":true},{"functionName":"lazyInitializers","ranges":[{"startOffset":566728,"endOffset":575683,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":566870,"endOffset":566948,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":567029,"endOffset":567098,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":567199,"endOffset":567387,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":567484,"endOffset":567687,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":567780,"endOffset":567891,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":567998,"endOffset":568249,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":568352,"endOffset":568465,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":568582,"endOffset":568837,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":568938,"endOffset":569053,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":569168,"endOffset":569357,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":569468,"endOffset":569585,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":569710,"endOffset":569903,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":570002,"endOffset":570077,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":570142,"endOffset":570223,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":570288,"endOffset":570350,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":570413,"endOffset":570448,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":570517,"endOffset":570578,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":570669,"endOffset":571283,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":571354,"endOffset":571512,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":571583,"endOffset":571664,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":571721,"endOffset":571771,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":571814,"endOffset":571888,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":571931,"endOffset":572008,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":572059,"endOffset":572220,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":572275,"endOffset":572548,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":572595,"endOffset":572849,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":572906,"endOffset":572966,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":573011,"endOffset":573116,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":573161,"endOffset":573279,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":573336,"endOffset":573422,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":573481,"endOffset":573591,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":573658,"endOffset":573797,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":573854,"endOffset":573959,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":574008,"endOffset":574107,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":574158,"endOffset":574221,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":574282,"endOffset":574368,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":574437,"endOffset":574524,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":574577,"endOffset":574658,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":574703,"endOffset":574773,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":574826,"endOffset":574893,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":574960,"endOffset":575064,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":575121,"endOffset":575225,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":575270,"endOffset":575364,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":575421,"endOffset":575534,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":575585,"endOffset":575677,"count":1}],"isBlockCoverage":true},{"functionName":"nativeSupport","ranges":[{"startOffset":579591,"endOffset":596530,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":579623,"endOffset":580408,"count":1},{"startOffset":580311,"endOffset":580407,"count":0}],"isBlockCoverage":true},{"functionName":"intern","ranges":[{"startOffset":579655,"endOffset":579781,"count":1}],"isBlockCoverage":true},{"functionName":"init.getIsolateTag","ranges":[{"startOffset":579810,"endOffset":579894,"count":1}],"isBlockCoverage":true},{"functionName":"Function.call$0","ranges":[{"startOffset":596565,"endOffset":596600,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$1","ranges":[{"startOffset":596632,"endOffset":596669,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2","ranges":[{"startOffset":596701,"endOffset":596744,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3","ranges":[{"startOffset":596776,"endOffset":596825,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$4","ranges":[{"startOffset":596857,"endOffset":596912,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$1$1","ranges":[{"startOffset":596946,"endOffset":596983,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3$1","ranges":[{"startOffset":597017,"endOffset":597054,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3$3","ranges":[{"startOffset":597088,"endOffset":597137,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$2","ranges":[{"startOffset":597171,"endOffset":597214,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$1","ranges":[{"startOffset":597248,"endOffset":597285,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$3","ranges":[{"startOffset":597319,"endOffset":597368,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$1$2","ranges":[{"startOffset":597402,"endOffset":597445,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$5","ranges":[{"startOffset":597477,"endOffset":597538,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3$4","ranges":[{"startOffset":597572,"endOffset":597627,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$4","ranges":[{"startOffset":597661,"endOffset":597716,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$1$4","ranges":[{"startOffset":597750,"endOffset":597805,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3$6","ranges":[{"startOffset":597839,"endOffset":597906,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$5","ranges":[{"startOffset":597940,"endOffset":598001,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":598067,"endOffset":598606,"count":1},{"startOffset":598129,"endOffset":598227,"count":0},{"startOffset":598282,"endOffset":598605,"count":0}],"isBlockCoverage":true},{"functionName":"onLoad","ranges":[{"startOffset":598329,"endOffset":598499,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":598608,"endOffset":598784,"count":1},{"startOffset":598726,"endOffset":598753,"count":0}],"isBlockCoverage":true}]},{"scriptId":"6","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":276,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":275,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_completeError$20","ranges":[{"startOffset":82,"endOffset":273,"count":0}],"isBlockCoverage":false}]},{"scriptId":"7","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":282,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":281,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_complete$11","ranges":[{"startOffset":82,"endOffset":279,"count":1}],"isBlockCoverage":true}]},{"scriptId":"8","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":276,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__completeError$22","ranges":[{"startOffset":82,"endOffset":274,"count":0}],"isBlockCoverage":false}]},{"scriptId":"9","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":276,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_add$13","ranges":[{"startOffset":82,"endOffset":274,"count":1}],"isBlockCoverage":true}]},{"scriptId":"10","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":270,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_addError$24","ranges":[{"startOffset":82,"endOffset":268,"count":1}],"isBlockCoverage":true}]},{"scriptId":"11","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":276,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_add$15","ranges":[{"startOffset":82,"endOffset":274,"count":1}],"isBlockCoverage":true}]},{"scriptId":"12","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__sendDone$06","ranges":[{"startOffset":82,"endOffset":269,"count":0}],"isBlockCoverage":false}]},{"scriptId":"13","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":270,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_addError$27","ranges":[{"startOffset":82,"endOffset":268,"count":1}],"isBlockCoverage":true}]},{"scriptId":"14","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__addError$28","ranges":[{"startOffset":82,"endOffset":269,"count":1}],"isBlockCoverage":true}]},{"scriptId":"15","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":281,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":280,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__closeInnerChannel$09","ranges":[{"startOffset":82,"endOffset":278,"count":1}],"isBlockCoverage":true}]},{"scriptId":"16","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"17","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":92,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":91,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":89,"count":1},{"startOffset":87,"endOffset":88,"count":0}],"isBlockCoverage":true}]},{"scriptId":"18","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"19","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":86,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":85,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":83,"count":0}],"isBlockCoverage":false}]},{"scriptId":"20","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"21","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":106,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":105,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":103,"count":0}],"isBlockCoverage":false}]},{"scriptId":"22","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"23","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":86,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":85,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":83,"count":0}],"isBlockCoverage":false}]},{"scriptId":"24","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"25","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":92,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":91,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":89,"count":1},{"startOffset":87,"endOffset":88,"count":0}],"isBlockCoverage":true}]},{"scriptId":"26","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"27","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":98,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":97,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":95,"count":0}],"isBlockCoverage":false}]},{"scriptId":"28","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"29","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":89,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":88,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":86,"count":0}],"isBlockCoverage":false}]},{"scriptId":"30","url":"http://localhost:33587/JvrQonmMf3ATS3rRCO76ZTlBfGvy%2Fj69/test/packages/test/dart.js","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":2011,"count":1}],"isBlockCoverage":true},{"functionName":"window.onload","ranges":[{"startOffset":384,"endOffset":2009,"count":1},{"startOffset":1295,"endOffset":1442,"count":0},{"startOffset":1491,"endOffset":1629,"count":0}],"isBlockCoverage":true},{"functionName":"sendLoadException","ranges":[{"startOffset":560,"endOffset":762,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":875,"endOffset":921,"count":0}],"isBlockCoverage":false},{"functionName":"script.onerror","ranges":[{"startOffset":1747,"endOffset":1907,"count":0}],"isBlockCoverage":false}]},{"scriptId":"31","url":"http://localhost:33587/JvrQonmMf3ATS3rRCO76ZTlBfGvy%2Fj69/test/main_test.dart.browser_test.dart.js","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":1081547,"count":1}],"isBlockCoverage":true},{"functionName":"dartProgram","ranges":[{"startOffset":1051,"endOffset":1081480,"count":1}],"isBlockCoverage":true},{"functionName":"copyProperties","ranges":[{"startOffset":1078,"endOffset":1253,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1288,"endOffset":1858,"count":1},{"startOffset":1469,"endOffset":1482,"count":0},{"startOffset":1645,"endOffset":1707,"count":0},{"startOffset":1709,"endOffset":1812,"count":0},{"startOffset":1818,"endOffset":1857,"count":0}],"isBlockCoverage":true},{"functionName":"cls","ranges":[{"startOffset":1315,"endOffset":1333,"count":1}],"isBlockCoverage":true},{"functionName":"setFunctionNamesIfNecessary","ranges":[{"startOffset":1864,"endOffset":2287,"count":1},{"startOffset":1991,"endOffset":2283,"count":0}],"isBlockCoverage":true},{"functionName":"t","ranges":[{"startOffset":1916,"endOffset":1936,"count":0}],"isBlockCoverage":false},{"functionName":"inherit","ranges":[{"startOffset":2290,"endOffset":2685,"count":1},{"startOffset":2533,"endOffset":2681,"count":0}],"isBlockCoverage":true},{"functionName":"inheritMany","ranges":[{"startOffset":2688,"endOffset":2805,"count":1}],"isBlockCoverage":true},{"functionName":"mixin","ranges":[{"startOffset":2808,"endOffset":2929,"count":1}],"isBlockCoverage":true},{"functionName":"lazy","ranges":[{"startOffset":2932,"endOffset":3681,"count":1}],"isBlockCoverage":true},{"functionName":"holder.<computed>","ranges":[{"startOffset":3094,"endOffset":3676,"count":1},{"startOffset":3429,"endOffset":3467,"count":0},{"startOffset":3539,"endOffset":3559,"count":0}],"isBlockCoverage":true},{"functionName":"holder.<computed>","ranges":[{"startOffset":3134,"endOffset":3187,"count":0}],"isBlockCoverage":false},{"functionName":"holder.<computed>","ranges":[{"startOffset":3589,"endOffset":3640,"count":1}],"isBlockCoverage":true},{"functionName":"makeConstList","ranges":[{"startOffset":3684,"endOffset":3799,"count":1}],"isBlockCoverage":true},{"functionName":"convertToFastObject","ranges":[{"startOffset":3802,"endOffset":3939,"count":1}],"isBlockCoverage":true},{"functionName":"t","ranges":[{"startOffset":3849,"endOffset":3869,"count":1}],"isBlockCoverage":true},{"functionName":"convertAllToFastObject","ranges":[{"startOffset":3942,"endOffset":4093,"count":1}],"isBlockCoverage":true},{"functionName":"tearOffGetter","ranges":[{"startOffset":4123,"endOffset":5038,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff","ranges":[{"startOffset":5041,"endOffset":5449,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":5180,"endOffset":5362,"count":1}],"isBlockCoverage":true},{"functionName":"installTearOff","ranges":[{"startOffset":5475,"endOffset":6389,"count":1}],"isBlockCoverage":true},{"functionName":"installStaticTearOff","ranges":[{"startOffset":6392,"endOffset":6715,"count":1}],"isBlockCoverage":true},{"functionName":"installInstanceTearOff","ranges":[{"startOffset":6718,"endOffset":7067,"count":1}],"isBlockCoverage":true},{"functionName":"setOrUpdateInterceptorsByTag","ranges":[{"startOffset":7070,"endOffset":7273,"count":1},{"startOffset":7234,"endOffset":7272,"count":0}],"isBlockCoverage":true},{"functionName":"setOrUpdateLeafTags","ranges":[{"startOffset":7276,"endOffset":7452,"count":1},{"startOffset":7413,"endOffset":7451,"count":0}],"isBlockCoverage":true},{"functionName":"updateTypes","ranges":[{"startOffset":7455,"endOffset":7608,"count":0}],"isBlockCoverage":false},{"functionName":"updateHolder","ranges":[{"startOffset":7611,"endOffset":7715,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":7736,"endOffset":9400,"count":1}],"isBlockCoverage":true},{"functionName":"mkInstance","ranges":[{"startOffset":7770,"endOffset":8132,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":7890,"endOffset":8123,"count":1}],"isBlockCoverage":true},{"functionName":"mkStatic","ranges":[{"startOffset":8151,"endOffset":8481,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":8256,"endOffset":8472,"count":1}],"isBlockCoverage":true},{"functionName":"initializeDeferredHunk","ranges":[{"startOffset":9406,"endOffset":9527,"count":0}],"isBlockCoverage":false},{"functionName":"getGlobalFromName","ranges":[{"startOffset":9530,"endOffset":9727,"count":0}],"isBlockCoverage":false},{"functionName":"JS_CONST","ranges":[{"startOffset":9759,"endOffset":9786,"count":0}],"isBlockCoverage":false},{"functionName":"CastIterable_CastIterable","ranges":[{"startOffset":9819,"endOffset":10153,"count":1},{"startOffset":10045,"endOffset":10152,"count":0}],"isBlockCoverage":true},{"functionName":"hexDigitValue","ranges":[{"startOffset":10174,"endOffset":10439,"count":0}],"isBlockCoverage":false},{"functionName":"SubListIterable$","ranges":[{"startOffset":10463,"endOffset":10899,"count":0}],"isBlockCoverage":false},{"functionName":"MappedIterable_MappedIterable","ranges":[{"startOffset":10936,"endOffset":11314,"count":0}],"isBlockCoverage":false},{"functionName":"IterableElementError_noElement","ranges":[{"startOffset":11352,"endOffset":11415,"count":0}],"isBlockCoverage":false},{"functionName":"IterableElementError_tooMany","ranges":[{"startOffset":11451,"endOffset":11521,"count":0}],"isBlockCoverage":false},{"functionName":"IterableElementError_tooFew","ranges":[{"startOffset":11556,"endOffset":11625,"count":0}],"isBlockCoverage":false},{"functionName":"_CastIterableBase","ranges":[{"startOffset":11650,"endOffset":11686,"count":0}],"isBlockCoverage":false},{"functionName":"CastIterator","ranges":[{"startOffset":11706,"endOffset":11789,"count":1}],"isBlockCoverage":true},{"functionName":"CastIterable","ranges":[{"startOffset":11809,"endOffset":11892,"count":0}],"isBlockCoverage":false},{"functionName":"_EfficientLengthCastIterable","ranges":[{"startOffset":11928,"endOffset":12027,"count":1}],"isBlockCoverage":true},{"functionName":"CastMap","ranges":[{"startOffset":12042,"endOffset":12120,"count":1}],"isBlockCoverage":true},{"functionName":"CastMap_forEach_closure","ranges":[{"startOffset":12151,"endOffset":12241,"count":0}],"isBlockCoverage":false},{"functionName":"CodeUnits","ranges":[{"startOffset":12258,"endOffset":12313,"count":0}],"isBlockCoverage":false},{"functionName":"EfficientLengthIterable","ranges":[{"startOffset":12344,"endOffset":12386,"count":0}],"isBlockCoverage":false},{"functionName":"ListIterable","ranges":[{"startOffset":12406,"endOffset":12437,"count":0}],"isBlockCoverage":false},{"functionName":"SubListIterable","ranges":[{"startOffset":12460,"endOffset":12640,"count":0}],"isBlockCoverage":false},{"functionName":"ListIterator","ranges":[{"startOffset":12660,"endOffset":12874,"count":1}],"isBlockCoverage":true},{"functionName":"MappedIterable","ranges":[{"startOffset":12896,"endOffset":13018,"count":1}],"isBlockCoverage":true},{"functionName":"EfficientLengthMappedIterable","ranges":[{"startOffset":13055,"endOffset":13192,"count":0}],"isBlockCoverage":false},{"functionName":"MappedIterator","ranges":[{"startOffset":13214,"endOffset":13372,"count":1}],"isBlockCoverage":true},{"functionName":"MappedListIterable","ranges":[{"startOffset":13398,"endOffset":13511,"count":1}],"isBlockCoverage":true},{"functionName":"WhereIterable","ranges":[{"startOffset":13532,"endOffset":13653,"count":1}],"isBlockCoverage":true},{"functionName":"WhereIterator","ranges":[{"startOffset":13674,"endOffset":13784,"count":1}],"isBlockCoverage":true},{"functionName":"ExpandIterable","ranges":[{"startOffset":13806,"endOffset":13928,"count":0}],"isBlockCoverage":false},{"functionName":"ExpandIterator","ranges":[{"startOffset":13950,"endOffset":14144,"count":0}],"isBlockCoverage":false},{"functionName":"SkipWhileIterable","ranges":[{"startOffset":14169,"endOffset":14294,"count":0}],"isBlockCoverage":false},{"functionName":"SkipWhileIterator","ranges":[{"startOffset":14319,"endOffset":14473,"count":0}],"isBlockCoverage":false},{"functionName":"EmptyIterator","ranges":[{"startOffset":14494,"endOffset":14549,"count":1}],"isBlockCoverage":true},{"functionName":"FixedLengthListMixin","ranges":[{"startOffset":14577,"endOffset":14616,"count":0}],"isBlockCoverage":false},{"functionName":"UnmodifiableListMixin","ranges":[{"startOffset":14645,"endOffset":14685,"count":0}],"isBlockCoverage":false},{"functionName":"UnmodifiableListBase","ranges":[{"startOffset":14713,"endOffset":14752,"count":0}],"isBlockCoverage":false},{"functionName":"ReversedListIterable","ranges":[{"startOffset":14780,"endOffset":14871,"count":1}],"isBlockCoverage":true},{"functionName":"Symbol","ranges":[{"startOffset":14885,"endOffset":14946,"count":1}],"isBlockCoverage":true},{"functionName":"ConstantMap__throwUnmodifiable","ranges":[{"startOffset":14984,"endOffset":15086,"count":0}],"isBlockCoverage":false},{"functionName":"instantiate1","ranges":[{"startOffset":15106,"endOffset":15248,"count":0}],"isBlockCoverage":false},{"functionName":"unminifyOrTag","ranges":[{"startOffset":15269,"endOffset":15468,"count":0}],"isBlockCoverage":false},{"functionName":"isJsIndexable","ranges":[{"startOffset":15489,"endOffset":15722,"count":0}],"isBlockCoverage":false},{"functionName":"S","ranges":[{"startOffset":15731,"endOffset":16230,"count":1},{"startOffset":15821,"endOffset":16229,"count":0}],"isBlockCoverage":true},{"functionName":"Primitives_objectHashCode","ranges":[{"startOffset":16263,"endOffset":16463,"count":1}],"isBlockCoverage":true},{"functionName":"Primitives_parseInt","ranges":[{"startOffset":16490,"endOffset":17741,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_objectTypeName","ranges":[{"startOffset":17774,"endOffset":17874,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives__objectTypeNameNewRti","ranges":[{"startOffset":17914,"endOffset":18695,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives__saneNativeClassName","ranges":[{"startOffset":18734,"endOffset":18825,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_dateNow","ranges":[{"startOffset":18851,"endOffset":18894,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_initTicker","ranges":[{"startOffset":18923,"endOffset":19555,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_currentUri","ranges":[{"startOffset":19584,"endOffset":19683,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives__fromCharCodeApply","ranges":[{"startOffset":19720,"endOffset":20112,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_stringFromCodePoints","ranges":[{"startOffset":20151,"endOffset":20858,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_stringFromCharCodes","ranges":[{"startOffset":20896,"endOffset":21417,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_stringFromNativeUint8List","ranges":[{"startOffset":21461,"endOffset":21888,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_stringFromCharCode","ranges":[{"startOffset":21925,"endOffset":22438,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_lazyAsJsDate","ranges":[{"startOffset":22469,"endOffset":22610,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getYear","ranges":[{"startOffset":22636,"endOffset":22752,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getMonth","ranges":[{"startOffset":22779,"endOffset":22892,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getDay","ranges":[{"startOffset":22917,"endOffset":23029,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getHours","ranges":[{"startOffset":23056,"endOffset":23169,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getMinutes","ranges":[{"startOffset":23198,"endOffset":23313,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getSeconds","ranges":[{"startOffset":23342,"endOffset":23457,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getMilliseconds","ranges":[{"startOffset":23491,"endOffset":23611,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_getProperty","ranges":[{"startOffset":23641,"endOffset":23862,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_setProperty","ranges":[{"startOffset":23892,"endOffset":24121,"count":0}],"isBlockCoverage":false},{"functionName":"iae","ranges":[{"startOffset":24132,"endOffset":24219,"count":0}],"isBlockCoverage":false},{"functionName":"ioore","ranges":[{"startOffset":24232,"endOffset":24397,"count":0}],"isBlockCoverage":false},{"functionName":"diagnoseIndexError","ranges":[{"startOffset":24423,"endOffset":24943,"count":0}],"isBlockCoverage":false},{"functionName":"diagnoseRangeError","ranges":[{"startOffset":24969,"endOffset":25354,"count":0}],"isBlockCoverage":false},{"functionName":"argumentErrorValue","ranges":[{"startOffset":25380,"endOffset":25464,"count":0}],"isBlockCoverage":false},{"functionName":"checkNum","ranges":[{"startOffset":25480,"endOffset":25619,"count":0}],"isBlockCoverage":false},{"functionName":"wrapException","ranges":[{"startOffset":25640,"endOffset":26027,"count":0}],"isBlockCoverage":false},{"functionName":"toStringWrapper","ranges":[{"startOffset":26050,"endOffset":26116,"count":0}],"isBlockCoverage":false},{"functionName":"throwExpression","ranges":[{"startOffset":26139,"endOffset":26192,"count":0}],"isBlockCoverage":false},{"functionName":"throwConcurrentModificationError","ranges":[{"startOffset":26232,"endOffset":26333,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorDecoder_extractPattern","ranges":[{"startOffset":26372,"endOffset":27376,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorDecoder_provokeCallErrorOn","ranges":[{"startOffset":27419,"endOffset":27663,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorDecoder_provokePropertyErrorOn","ranges":[{"startOffset":27710,"endOffset":27892,"count":0}],"isBlockCoverage":false},{"functionName":"NullError$","ranges":[{"startOffset":27910,"endOffset":28020,"count":0}],"isBlockCoverage":false},{"functionName":"JsNoSuchMethodError$","ranges":[{"startOffset":28048,"endOffset":28232,"count":0}],"isBlockCoverage":false},{"functionName":"unwrapException","ranges":[{"startOffset":28255,"endOffset":32748,"count":0}],"isBlockCoverage":false},{"functionName":"getTraceFromException","ranges":[{"startOffset":32777,"endOffset":33142,"count":1},{"startOffset":32881,"endOffset":32909,"count":0},{"startOffset":32947,"endOffset":32983,"count":0},{"startOffset":33055,"endOffset":33068,"count":0}],"isBlockCoverage":true},{"functionName":"objectHashCode","ranges":[{"startOffset":33164,"endOffset":33346,"count":1}],"isBlockCoverage":true},{"functionName":"fillLiteralMap","ranges":[{"startOffset":33368,"endOffset":33829,"count":1}],"isBlockCoverage":true},{"functionName":"fillLiteralSet","ranges":[{"startOffset":33851,"endOffset":34149,"count":1}],"isBlockCoverage":true},{"functionName":"invokeClosure","ranges":[{"startOffset":34170,"endOffset":34749,"count":1},{"startOffset":34441,"endOffset":34493,"count":0},{"startOffset":34502,"endOffset":34560,"count":0},{"startOffset":34569,"endOffset":34633,"count":0},{"startOffset":34641,"endOffset":34748,"count":0}],"isBlockCoverage":true},{"functionName":"convertDartClosureToJS","ranges":[{"startOffset":34779,"endOffset":35232,"count":1},{"startOffset":34862,"endOffset":34874,"count":0}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":34979,"endOffset":35131,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":35029,"endOffset":35122,"count":1}],"isBlockCoverage":true},{"functionName":"Closure_fromTearOff","ranges":[{"startOffset":35259,"endOffset":37399,"count":1},{"startOffset":36000,"endOffset":36017,"count":0},{"startOffset":37093,"endOffset":37187,"count":0}],"isBlockCoverage":true},{"functionName":"static_tear_off","ranges":[{"startOffset":35831,"endOffset":35899,"count":0}],"isBlockCoverage":false},{"functionName":"Closure__computeSignatureFunctionNewRti","ranges":[{"startOffset":37446,"endOffset":38243,"count":1},{"startOffset":37726,"endOffset":38242,"count":0}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":37580,"endOffset":37686,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":37620,"endOffset":37675,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":37997,"endOffset":38133,"count":0}],"isBlockCoverage":false},{"functionName":"Closure_cspForwardCall","ranges":[{"startOffset":38273,"endOffset":39658,"count":1},{"startOffset":38399,"endOffset":38406,"count":0},{"startOffset":38418,"endOffset":38573,"count":0},{"startOffset":38582,"endOffset":38739,"count":0},{"startOffset":38748,"endOffset":38911,"count":0},{"startOffset":38920,"endOffset":39089,"count":0},{"startOffset":39098,"endOffset":39273,"count":0},{"startOffset":39282,"endOffset":39463,"count":0}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":38443,"endOffset":38553,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":38607,"endOffset":38719,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":38773,"endOffset":38891,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":38945,"endOffset":39069,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":39123,"endOffset":39253,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":39307,"endOffset":39443,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":39498,"endOffset":39623,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":39534,"endOffset":39610,"count":0}],"isBlockCoverage":false},{"functionName":"Closure_forwardCallTo","ranges":[{"startOffset":39687,"endOffset":41342,"count":1},{"startOffset":40050,"endOffset":40076,"count":0},{"startOffset":40341,"endOffset":40358,"count":0},{"startOffset":40594,"endOffset":40672,"count":0},{"startOffset":40960,"endOffset":40977,"count":0},{"startOffset":41199,"endOffset":41277,"count":0}],"isBlockCoverage":true},{"functionName":"Closure_cspForwardInterceptedCall","ranges":[{"startOffset":41383,"endOffset":43149,"count":0}],"isBlockCoverage":false},{"functionName":"Closure_forwardInterceptedCallTo","ranges":[{"startOffset":43189,"endOffset":44760,"count":1},{"startOffset":43766,"endOffset":43792,"count":0},{"startOffset":43880,"endOffset":43956,"count":0},{"startOffset":44175,"endOffset":44192,"count":0},{"startOffset":44651,"endOffset":44668,"count":0}],"isBlockCoverage":true},{"functionName":"closureFromTearOff","ranges":[{"startOffset":44786,"endOffset":45024,"count":1}],"isBlockCoverage":true},{"functionName":"BoundClosure_evalRecipe","ranges":[{"startOffset":45055,"endOffset":45190,"count":0}],"isBlockCoverage":false},{"functionName":"BoundClosure_evalRecipeIntercepted","ranges":[{"startOffset":45232,"endOffset":45371,"count":0}],"isBlockCoverage":false},{"functionName":"BoundClosure_selfOf","ranges":[{"startOffset":45398,"endOffset":45451,"count":0}],"isBlockCoverage":false},{"functionName":"BoundClosure_receiverOf","ranges":[{"startOffset":45482,"endOffset":45539,"count":0}],"isBlockCoverage":false},{"functionName":"BoundClosure_computeFieldNamed","ranges":[{"startOffset":45577,"endOffset":45937,"count":1}],"isBlockCoverage":true},{"functionName":"boolConversionCheck","ranges":[{"startOffset":45964,"endOffset":46094,"count":1},{"startOffset":46015,"endOffset":46068,"count":0}],"isBlockCoverage":true},{"functionName":"extractFunctionTypeObjectFromInternal","ranges":[{"startOffset":46139,"endOffset":46420,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorImplementation$","ranges":[{"startOffset":46452,"endOffset":46662,"count":0}],"isBlockCoverage":false},{"functionName":"_typeDescription","ranges":[{"startOffset":46686,"endOffset":47058,"count":0}],"isBlockCoverage":false},{"functionName":"assertTest","ranges":[{"startOffset":47076,"endOffset":47290,"count":1},{"startOffset":47149,"endOffset":47289,"count":0}],"isBlockCoverage":true},{"functionName":"assertThrow","ranges":[{"startOffset":47309,"endOffset":47395,"count":0}],"isBlockCoverage":false},{"functionName":"assertHelper","ranges":[{"startOffset":47415,"endOffset":47533,"count":1},{"startOffset":47480,"endOffset":47527,"count":0}],"isBlockCoverage":true},{"functionName":"throwCyclicInit","ranges":[{"startOffset":47556,"endOffset":47658,"count":0}],"isBlockCoverage":false},{"functionName":"RuntimeError$","ranges":[{"startOffset":47679,"endOffset":47746,"count":0}],"isBlockCoverage":false},{"functionName":"getIsolateAffinityTag","ranges":[{"startOffset":47775,"endOffset":47838,"count":0}],"isBlockCoverage":false},{"functionName":"setRuntimeTypeInfo","ranges":[{"startOffset":47864,"endOffset":47973,"count":1}],"isBlockCoverage":true},{"functionName":"getRuntimeTypeInfo","ranges":[{"startOffset":47999,"endOffset":48095,"count":0}],"isBlockCoverage":false},{"functionName":"getRuntimeTypeArguments","ranges":[{"startOffset":48126,"endOffset":48282,"count":0}],"isBlockCoverage":false},{"functionName":"runtimeTypeToString","ranges":[{"startOffset":48309,"endOffset":48378,"count":0}],"isBlockCoverage":false},{"functionName":"_runtimeTypeToString","ranges":[{"startOffset":48406,"endOffset":49897,"count":0}],"isBlockCoverage":false},{"functionName":"_functionRtiToString0","ranges":[{"startOffset":49926,"endOffset":52750,"count":0}],"isBlockCoverage":false},{"functionName":"_joinArguments","ranges":[{"startOffset":52772,"endOffset":53457,"count":0}],"isBlockCoverage":false},{"functionName":"getRuntimeType","ranges":[{"startOffset":53479,"endOffset":53665,"count":0}],"isBlockCoverage":false},{"functionName":"substitute","ranges":[{"startOffset":53683,"endOffset":54227,"count":0}],"isBlockCoverage":false},{"functionName":"computeSignature","ranges":[{"startOffset":54251,"endOffset":54444,"count":0}],"isBlockCoverage":false},{"functionName":"invokeOn","ranges":[{"startOffset":54460,"endOffset":54686,"count":0}],"isBlockCoverage":false},{"functionName":"defineProperty","ranges":[{"startOffset":54708,"endOffset":54861,"count":0}],"isBlockCoverage":false},{"functionName":"lookupAndCacheInterceptor","ranges":[{"startOffset":54894,"endOffset":57451,"count":0}],"isBlockCoverage":false},{"functionName":"patchInteriorProto","ranges":[{"startOffset":57477,"endOffset":57764,"count":0}],"isBlockCoverage":false},{"functionName":"makeLeafDispatchRecord","ranges":[{"startOffset":57794,"endOffset":57929,"count":1}],"isBlockCoverage":true},{"functionName":"makeDefaultDispatchRecord","ranges":[{"startOffset":57962,"endOffset":58233,"count":1}],"isBlockCoverage":true},{"functionName":"initNativeDispatch","ranges":[{"startOffset":58259,"endOffset":58415,"count":1},{"startOffset":58325,"endOffset":58332,"count":0}],"isBlockCoverage":true},{"functionName":"initNativeDispatchContinue","ranges":[{"startOffset":58449,"endOffset":59729,"count":1}],"isBlockCoverage":true},{"functionName":"fun","ranges":[{"startOffset":58828,"endOffset":58850,"count":0}],"isBlockCoverage":false},{"functionName":"initHooks","ranges":[{"startOffset":59746,"endOffset":61000,"count":1},{"startOffset":60255,"endOffset":60668,"count":0}],"isBlockCoverage":true},{"functionName":"applyHooksTransformer","ranges":[{"startOffset":61029,"endOffset":61107,"count":1}],"isBlockCoverage":true},{"functionName":"JSSyntaxRegExp_makeNative","ranges":[{"startOffset":61140,"endOffset":61765,"count":0}],"isBlockCoverage":false},{"functionName":"_MatchImplementation$","ranges":[{"startOffset":61794,"endOffset":61977,"count":0}],"isBlockCoverage":false},{"functionName":"stringContainsUnchecked","ranges":[{"startOffset":62008,"endOffset":62496,"count":0}],"isBlockCoverage":false},{"functionName":"escapeReplacement","ranges":[{"startOffset":62521,"endOffset":62671,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceFirstRE","ranges":[{"startOffset":62699,"endOffset":62974,"count":0}],"isBlockCoverage":false},{"functionName":"quoteStringForRegExp","ranges":[{"startOffset":63002,"endOffset":63154,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceAllUnchecked","ranges":[{"startOffset":63187,"endOffset":63770,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceAllUncheckedString","ranges":[{"startOffset":63809,"endOffset":64503,"count":0}],"isBlockCoverage":false},{"functionName":"_stringIdentity","ranges":[{"startOffset":64526,"endOffset":64571,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceAllFuncUnchecked","ranges":[{"startOffset":64608,"endOffset":65417,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceFirstUnchecked","ranges":[{"startOffset":65452,"endOffset":66440,"count":0}],"isBlockCoverage":false},{"functionName":"stringReplaceRangeUnchecked","ranges":[{"startOffset":66475,"endOffset":66661,"count":0}],"isBlockCoverage":false},{"functionName":"ConstantMap","ranges":[{"startOffset":66680,"endOffset":66710,"count":0}],"isBlockCoverage":false},{"functionName":"ConstantMap_map_closure","ranges":[{"startOffset":66741,"endOffset":66867,"count":0}],"isBlockCoverage":false},{"functionName":"ConstantStringMap","ranges":[{"startOffset":66892,"endOffset":67070,"count":1}],"isBlockCoverage":true},{"functionName":"_ConstantMapKeyIterable","ranges":[{"startOffset":67101,"endOffset":67204,"count":0}],"isBlockCoverage":false},{"functionName":"Instantiation","ranges":[{"startOffset":67225,"endOffset":67257,"count":0}],"isBlockCoverage":false},{"functionName":"Instantiation1","ranges":[{"startOffset":67279,"endOffset":67372,"count":0}],"isBlockCoverage":false},{"functionName":"Primitives_initTicker_closure","ranges":[{"startOffset":67409,"endOffset":67488,"count":0}],"isBlockCoverage":false},{"functionName":"TypeErrorDecoder","ranges":[{"startOffset":67512,"endOffset":67732,"count":0}],"isBlockCoverage":false},{"functionName":"NullError","ranges":[{"startOffset":67749,"endOffset":67846,"count":0}],"isBlockCoverage":false},{"functionName":"JsNoSuchMethodError","ranges":[{"startOffset":67873,"endOffset":68011,"count":0}],"isBlockCoverage":false},{"functionName":"UnknownJsTypeError","ranges":[{"startOffset":68037,"endOffset":68114,"count":0}],"isBlockCoverage":false},{"functionName":"ExceptionAndStackTrace","ranges":[{"startOffset":68144,"endOffset":68250,"count":0}],"isBlockCoverage":true},{"functionName":"unwrapException_saveStackTrace","ranges":[{"startOffset":68288,"endOffset":68359,"count":0}],"isBlockCoverage":false},{"functionName":"_StackTrace","ranges":[{"startOffset":68378,"endOffset":68464,"count":1}],"isBlockCoverage":true},{"functionName":"Closure","ranges":[{"startOffset":68479,"endOffset":68505,"count":0}],"isBlockCoverage":true},{"functionName":"TearOffClosure","ranges":[{"startOffset":68527,"endOffset":68560,"count":0}],"isBlockCoverage":false},{"functionName":"StaticClosure","ranges":[{"startOffset":68581,"endOffset":68613,"count":1}],"isBlockCoverage":true},{"functionName":"BoundClosure","ranges":[{"startOffset":68633,"endOffset":68784,"count":1}],"isBlockCoverage":true},{"functionName":"TypeErrorImplementation","ranges":[{"startOffset":68815,"endOffset":68884,"count":0}],"isBlockCoverage":false},{"functionName":"RuntimeError","ranges":[{"startOffset":68904,"endOffset":68962,"count":0}],"isBlockCoverage":false},{"functionName":"_AssertionError","ranges":[{"startOffset":68985,"endOffset":69046,"count":0}],"isBlockCoverage":false},{"functionName":"JsLinkedHashMap","ranges":[{"startOffset":69069,"endOffset":69306,"count":1}],"isBlockCoverage":true},{"functionName":"JsLinkedHashMap_values_closure","ranges":[{"startOffset":69344,"endOffset":69418,"count":0}],"isBlockCoverage":false},{"functionName":"JsLinkedHashMap_addAll_closure","ranges":[{"startOffset":69456,"endOffset":69530,"count":0}],"isBlockCoverage":false},{"functionName":"LinkedHashMapCell","ranges":[{"startOffset":69555,"endOffset":69713,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashMapKeyIterable","ranges":[{"startOffset":69745,"endOffset":69849,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashMapKeyIterator","ranges":[{"startOffset":69881,"endOffset":70079,"count":1}],"isBlockCoverage":true},{"functionName":"initHooks_closure","ranges":[{"startOffset":70104,"endOffset":70166,"count":1}],"isBlockCoverage":true},{"functionName":"initHooks_closure0","ranges":[{"startOffset":70192,"endOffset":70262,"count":1}],"isBlockCoverage":true},{"functionName":"initHooks_closure1","ranges":[{"startOffset":70288,"endOffset":70360,"count":1}],"isBlockCoverage":true},{"functionName":"JSSyntaxRegExp","ranges":[{"startOffset":70382,"endOffset":70553,"count":0}],"isBlockCoverage":false},{"functionName":"_MatchImplementation","ranges":[{"startOffset":70581,"endOffset":70646,"count":0}],"isBlockCoverage":false},{"functionName":"_AllMatchesIterable","ranges":[{"startOffset":70673,"endOffset":70803,"count":0}],"isBlockCoverage":false},{"functionName":"_AllMatchesIterator","ranges":[{"startOffset":70830,"endOffset":71016,"count":0}],"isBlockCoverage":false},{"functionName":"StringMatch","ranges":[{"startOffset":71035,"endOffset":71119,"count":0}],"isBlockCoverage":false},{"functionName":"_StringAllMatchesIterable","ranges":[{"startOffset":71152,"endOffset":71292,"count":0}],"isBlockCoverage":false},{"functionName":"_StringAllMatchesIterator","ranges":[{"startOffset":71325,"endOffset":71513,"count":0}],"isBlockCoverage":false},{"functionName":"_ensureNativeList","ranges":[{"startOffset":71538,"endOffset":71579,"count":0}],"isBlockCoverage":false},{"functionName":"NativeInt8List__create1","ranges":[{"startOffset":71610,"endOffset":71664,"count":0}],"isBlockCoverage":false},{"functionName":"_checkValidIndex","ranges":[{"startOffset":71688,"endOffset":71845,"count":1},{"startOffset":71782,"endOffset":71839,"count":0}],"isBlockCoverage":true},{"functionName":"_checkValidRange","ranges":[{"startOffset":71869,"endOffset":72275,"count":0}],"isBlockCoverage":false},{"functionName":"NativeByteBuffer","ranges":[{"startOffset":72299,"endOffset":72334,"count":0}],"isBlockCoverage":false},{"functionName":"NativeTypedData","ranges":[{"startOffset":72357,"endOffset":72391,"count":0}],"isBlockCoverage":false},{"functionName":"NativeByteData","ranges":[{"startOffset":72413,"endOffset":72446,"count":0}],"isBlockCoverage":false},{"functionName":"NativeTypedArray","ranges":[{"startOffset":72470,"endOffset":72505,"count":0}],"isBlockCoverage":false},{"functionName":"NativeTypedArrayOfDouble","ranges":[{"startOffset":72537,"endOffset":72580,"count":0}],"isBlockCoverage":false},{"functionName":"NativeTypedArrayOfInt","ranges":[{"startOffset":72609,"endOffset":72649,"count":0}],"isBlockCoverage":false},{"functionName":"NativeFloat32List","ranges":[{"startOffset":72674,"endOffset":72710,"count":0}],"isBlockCoverage":false},{"functionName":"NativeFloat64List","ranges":[{"startOffset":72735,"endOffset":72771,"count":0}],"isBlockCoverage":false},{"functionName":"NativeInt16List","ranges":[{"startOffset":72794,"endOffset":72828,"count":0}],"isBlockCoverage":false},{"functionName":"NativeInt32List","ranges":[{"startOffset":72851,"endOffset":72885,"count":0}],"isBlockCoverage":false},{"functionName":"NativeInt8List","ranges":[{"startOffset":72907,"endOffset":72940,"count":0}],"isBlockCoverage":false},{"functionName":"NativeUint16List","ranges":[{"startOffset":72964,"endOffset":72999,"count":0}],"isBlockCoverage":false},{"functionName":"NativeUint32List","ranges":[{"startOffset":73023,"endOffset":73058,"count":0}],"isBlockCoverage":false},{"functionName":"NativeUint8ClampedList","ranges":[{"startOffset":73088,"endOffset":73129,"count":0}],"isBlockCoverage":false},{"functionName":"NativeUint8List","ranges":[{"startOffset":73152,"endOffset":73186,"count":0}],"isBlockCoverage":false},{"functionName":"_NativeTypedArrayOfDouble_NativeTypedArray_ListMixin","ranges":[{"startOffset":73246,"endOffset":73317,"count":0}],"isBlockCoverage":false},{"functionName":"_NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin","ranges":[{"startOffset":73398,"endOffset":73490,"count":0}],"isBlockCoverage":false},{"functionName":"_NativeTypedArrayOfInt_NativeTypedArray_ListMixin","ranges":[{"startOffset":73547,"endOffset":73615,"count":0}],"isBlockCoverage":false},{"functionName":"_NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin","ranges":[{"startOffset":73693,"endOffset":73782,"count":0}],"isBlockCoverage":false},{"functionName":"Rti__getFutureFromFutureOr","ranges":[{"startOffset":73816,"endOffset":74142,"count":0}],"isBlockCoverage":false},{"functionName":"Rti__isUnionOfFunctionType","ranges":[{"startOffset":74176,"endOffset":74375,"count":1}],"isBlockCoverage":true},{"functionName":"Rti__getInterfaceTypeArguments","ranges":[{"startOffset":74413,"endOffset":74497,"count":1}],"isBlockCoverage":true},{"functionName":"Rti__getBindingArguments","ranges":[{"startOffset":74529,"endOffset":74614,"count":1}],"isBlockCoverage":true},{"functionName":"Rti__getFunctionParameters","ranges":[{"startOffset":74648,"endOffset":74733,"count":1}],"isBlockCoverage":true},{"functionName":"Rti__getGenericFunctionBounds","ranges":[{"startOffset":74770,"endOffset":74855,"count":1}],"isBlockCoverage":true},{"functionName":"Rti__getCanonicalRecipe","ranges":[{"startOffset":74886,"endOffset":75056,"count":0}],"isBlockCoverage":false},{"functionName":"findType","ranges":[{"startOffset":75072,"endOffset":75154,"count":1}],"isBlockCoverage":true},{"functionName":"instantiatedGenericFunctionType","ranges":[{"startOffset":75193,"endOffset":76127,"count":0}],"isBlockCoverage":false},{"functionName":"_instantiate","ranges":[{"startOffset":76147,"endOffset":80529,"count":0}],"isBlockCoverage":false},{"functionName":"_instantiateArray","ranges":[{"startOffset":80554,"endOffset":81024,"count":0}],"isBlockCoverage":false},{"functionName":"_instantiateNamed","ranges":[{"startOffset":81049,"endOffset":81640,"count":0}],"isBlockCoverage":false},{"functionName":"_instantiateFunctionParameters","ranges":[{"startOffset":81678,"endOffset":82753,"count":0}],"isBlockCoverage":false},{"functionName":"closureFunctionType","ranges":[{"startOffset":82780,"endOffset":83037,"count":1},{"startOffset":83012,"endOffset":83036,"count":0}],"isBlockCoverage":true},{"functionName":"instanceOrFunctionType","ranges":[{"startOffset":83067,"endOffset":83352,"count":1}],"isBlockCoverage":true},{"functionName":"instanceType","ranges":[{"startOffset":83372,"endOffset":83710,"count":1},{"startOffset":83505,"endOffset":83545,"count":0}],"isBlockCoverage":true},{"functionName":"_arrayInstanceType","ranges":[{"startOffset":83736,"endOffset":83981,"count":1},{"startOffset":83939,"endOffset":83957,"count":0}],"isBlockCoverage":true},{"functionName":"_instanceType","ranges":[{"startOffset":84002,"endOffset":84127,"count":1},{"startOffset":84080,"endOffset":84120,"count":0}],"isBlockCoverage":true},{"functionName":"_instanceTypeFromConstructor","ranges":[{"startOffset":84163,"endOffset":84394,"count":1}],"isBlockCoverage":true},{"functionName":"_instanceTypeFromConstructorMiss","ranges":[{"startOffset":84434,"endOffset":84736,"count":1},{"startOffset":84532,"endOffset":84574,"count":0}],"isBlockCoverage":true},{"functionName":"getTypeFromTypesTable","ranges":[{"startOffset":84765,"endOffset":85054,"count":1}],"isBlockCoverage":true},{"functionName":"createRuntimeType","ranges":[{"startOffset":85079,"endOffset":85242,"count":1},{"startOffset":85168,"endOffset":85180,"count":0}],"isBlockCoverage":true},{"functionName":"typeLiteral","ranges":[{"startOffset":85261,"endOffset":85364,"count":1}],"isBlockCoverage":true},{"functionName":"_installSpecializedIsTest","ranges":[{"startOffset":85397,"endOffset":86499,"count":1},{"startOffset":85764,"endOffset":85806,"count":0},{"startOffset":85923,"endOffset":85939,"count":0}],"isBlockCoverage":true},{"functionName":"_generalIsTestImplementation","ranges":[{"startOffset":86535,"endOffset":86701,"count":1}],"isBlockCoverage":true},{"functionName":"_isTestViaProperty","ranges":[{"startOffset":86727,"endOffset":86913,"count":1}],"isBlockCoverage":true},{"functionName":"_generalAsCheckImplementation","ranges":[{"startOffset":86950,"endOffset":87273,"count":1},{"startOffset":87022,"endOffset":87036,"count":0},{"startOffset":87112,"endOffset":87272,"count":0}],"isBlockCoverage":true},{"functionName":"_generalTypeCheckImplementation","ranges":[{"startOffset":87312,"endOffset":87635,"count":1},{"startOffset":87474,"endOffset":87634,"count":0}],"isBlockCoverage":true},{"functionName":"checkTypeBound","ranges":[{"startOffset":87657,"endOffset":88102,"count":0}],"isBlockCoverage":false},{"functionName":"_Error_compose","ranges":[{"startOffset":88124,"endOffset":88496,"count":0}],"isBlockCoverage":false},{"functionName":"_CastError$fromMessage","ranges":[{"startOffset":88526,"endOffset":88607,"count":0}],"isBlockCoverage":false},{"functionName":"_CastError__CastError$forType","ranges":[{"startOffset":88644,"endOffset":88759,"count":0}],"isBlockCoverage":false},{"functionName":"_TypeError$fromMessage","ranges":[{"startOffset":88789,"endOffset":88870,"count":0}],"isBlockCoverage":false},{"functionName":"_TypeError__TypeError$forType","ranges":[{"startOffset":88907,"endOffset":89022,"count":0}],"isBlockCoverage":false},{"functionName":"_isTop","ranges":[{"startOffset":89036,"endOffset":89079,"count":1}],"isBlockCoverage":true},{"functionName":"_asTop","ranges":[{"startOffset":89093,"endOffset":89138,"count":1}],"isBlockCoverage":true},{"functionName":"_isBool","ranges":[{"startOffset":89153,"endOffset":89227,"count":1}],"isBlockCoverage":true},{"functionName":"_asBoolNullable","ranges":[{"startOffset":89250,"endOffset":89471,"count":1},{"startOffset":89387,"endOffset":89470,"count":0}],"isBlockCoverage":true},{"functionName":"_checkBoolNullable","ranges":[{"startOffset":89497,"endOffset":89718,"count":1},{"startOffset":89634,"endOffset":89717,"count":0}],"isBlockCoverage":true},{"functionName":"_asDoubleNullable","ranges":[{"startOffset":89743,"endOffset":89956,"count":0}],"isBlockCoverage":false},{"functionName":"_checkDoubleNullable","ranges":[{"startOffset":89984,"endOffset":90197,"count":0}],"isBlockCoverage":false},{"functionName":"_isInt","ranges":[{"startOffset":90211,"endOffset":90308,"count":1}],"isBlockCoverage":true},{"functionName":"_asIntNullable","ranges":[{"startOffset":90330,"endOffset":90573,"count":1},{"startOffset":90490,"endOffset":90572,"count":0}],"isBlockCoverage":true},{"functionName":"_checkIntNullable","ranges":[{"startOffset":90598,"endOffset":90841,"count":1},{"startOffset":90709,"endOffset":90840,"count":0}],"isBlockCoverage":true},{"functionName":"_isNum","ranges":[{"startOffset":90855,"endOffset":90919,"count":1}],"isBlockCoverage":true},{"functionName":"_asNumNullable","ranges":[{"startOffset":90941,"endOffset":91151,"count":1},{"startOffset":91019,"endOffset":91150,"count":0}],"isBlockCoverage":true},{"functionName":"_checkNumNullable","ranges":[{"startOffset":91176,"endOffset":91386,"count":0}],"isBlockCoverage":false},{"functionName":"_isString","ranges":[{"startOffset":91403,"endOffset":91467,"count":1}],"isBlockCoverage":true},{"functionName":"_asStringNullable","ranges":[{"startOffset":91492,"endOffset":91705,"count":1},{"startOffset":91619,"endOffset":91704,"count":0}],"isBlockCoverage":true},{"functionName":"_checkStringNullable","ranges":[{"startOffset":91733,"endOffset":91946,"count":1},{"startOffset":91811,"endOffset":91945,"count":0}],"isBlockCoverage":true},{"functionName":"_rtiArrayToString","ranges":[{"startOffset":91971,"endOffset":92203,"count":0}],"isBlockCoverage":false},{"functionName":"_functionRtiToString","ranges":[{"startOffset":92231,"endOffset":95348,"count":0}],"isBlockCoverage":false},{"functionName":"_rtiToString","ranges":[{"startOffset":95368,"endOffset":96985,"count":0}],"isBlockCoverage":false},{"functionName":"_unminifyOrTag","ranges":[{"startOffset":97007,"endOffset":97195,"count":0}],"isBlockCoverage":false},{"functionName":"_Universe_findRule","ranges":[{"startOffset":97221,"endOffset":97393,"count":1},{"startOffset":97343,"endOffset":97368,"count":0}],"isBlockCoverage":true},{"functionName":"_Universe_findErasedType","ranges":[{"startOffset":97425,"endOffset":98058,"count":1},{"startOffset":97640,"endOffset":98052,"count":0}],"isBlockCoverage":true},{"functionName":"_Universe_addRules","ranges":[{"startOffset":98084,"endOffset":98173,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe_addErasedTypes","ranges":[{"startOffset":98205,"endOffset":98294,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe_eval","ranges":[{"startOffset":98316,"endOffset":98586,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe_evalInEnvironment","ranges":[{"startOffset":98621,"endOffset":99004,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe_bind","ranges":[{"startOffset":99026,"endOffset":99702,"count":1},{"startOffset":99328,"endOffset":99370,"count":0},{"startOffset":99578,"endOffset":99620,"count":0}],"isBlockCoverage":true},{"functionName":"_Universe__parseRecipe","ranges":[{"startOffset":99732,"endOffset":99879,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe__finishRti","ranges":[{"startOffset":99907,"endOffset":100268,"count":1},{"startOffset":100023,"endOffset":100065,"count":0}],"isBlockCoverage":true},{"functionName":"_Universe__lookupTerminalRti","ranges":[{"startOffset":100304,"endOffset":100628,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe__lookupUnaryRti","ranges":[{"startOffset":100661,"endOffset":101026,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe__lookupGenericFunctionParameterRti","ranges":[{"startOffset":101078,"endOffset":101456,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe__canonicalRecipeJoin","ranges":[{"startOffset":101494,"endOffset":101845,"count":1},{"startOffset":101750,"endOffset":101792,"count":0}],"isBlockCoverage":true},{"functionName":"_Universe__canonicalRecipeJoinNamed","ranges":[{"startOffset":101888,"endOffset":102332,"count":0}],"isBlockCoverage":false},{"functionName":"_Universe__lookupInterfaceRti","ranges":[{"startOffset":102369,"endOffset":102971,"count":1}],"isBlockCoverage":true},{"functionName":"_Universe__lookupBindingRti","ranges":[{"startOffset":103006,"endOffset":103877,"count":1},{"startOffset":103457,"endOffset":103499,"count":0}],"isBlockCoverage":true},{"functionName":"_Universe__lookupFunctionRti","ranges":[{"startOffset":103913,"endOffset":105417,"count":1},{"startOffset":104216,"endOffset":104258,"count":0},{"startOffset":104965,"endOffset":105084,"count":0}],"isBlockCoverage":true},{"functionName":"_Universe__lookupGenericFunctionRti","ranges":[{"startOffset":105460,"endOffset":106050,"count":1},{"startOffset":105635,"endOffset":105677,"count":0},{"startOffset":105817,"endOffset":105830,"count":0}],"isBlockCoverage":true},{"functionName":"_Parser_create","ranges":[{"startOffset":106072,"endOffset":106187,"count":1}],"isBlockCoverage":true},{"functionName":"_Parser_parse","ranges":[{"startOffset":106208,"endOffset":111999,"count":1},{"startOffset":106817,"endOffset":106880,"count":0},{"startOffset":106989,"endOffset":107018,"count":0},{"startOffset":107031,"endOffset":107137,"count":0},{"startOffset":107388,"endOffset":107493,"count":0},{"startOffset":108690,"endOffset":108784,"count":0},{"startOffset":108797,"endOffset":109122,"count":0},{"startOffset":109135,"endOffset":109460,"count":0},{"startOffset":109682,"endOffset":109703,"count":0},{"startOffset":110356,"endOffset":110440,"count":0},{"startOffset":111456,"endOffset":111561,"count":0},{"startOffset":111574,"endOffset":111816,"count":0},{"startOffset":111829,"endOffset":111880,"count":0}],"isBlockCoverage":true},{"functionName":"_Parser_handleDigit","ranges":[{"startOffset":112026,"endOffset":112337,"count":1},{"startOffset":112242,"endOffset":112290,"count":0}],"isBlockCoverage":true},{"functionName":"_Parser_handleIdentifier","ranges":[{"startOffset":112369,"endOffset":113633,"count":1},{"startOffset":112644,"endOffset":112650,"count":0},{"startOffset":113401,"endOffset":113494,"count":0}],"isBlockCoverage":true},{"functionName":"_Parser_handleExtendedOperations","ranges":[{"startOffset":113673,"endOffset":114066,"count":0}],"isBlockCoverage":false},{"functionName":"_Parser_toType","ranges":[{"startOffset":114088,"endOffset":114385,"count":1}],"isBlockCoverage":true},{"functionName":"_Parser_toTypes","ranges":[{"startOffset":114408,"endOffset":114605,"count":1}],"isBlockCoverage":true},{"functionName":"_Parser_toTypesNamed","ranges":[{"startOffset":114633,"endOffset":114876,"count":0}],"isBlockCoverage":false},{"functionName":"_Parser_indexToType","ranges":[{"startOffset":114903,"endOffset":115904,"count":1},{"startOffset":115075,"endOffset":115162,"count":0},{"startOffset":115556,"endOffset":115639,"count":0},{"startOffset":115790,"endOffset":115903,"count":0}],"isBlockCoverage":true},{"functionName":"_isSubtype","ranges":[{"startOffset":115922,"endOffset":118887,"count":1},{"startOffset":116182,"endOffset":116194,"count":0},{"startOffset":116235,"endOffset":116248,"count":0},{"startOffset":116365,"endOffset":116512,"count":0},{"startOffset":116574,"endOffset":116694,"count":0},{"startOffset":116718,"endOffset":116850,"count":0},{"startOffset":116874,"endOffset":117119,"count":0},{"startOffset":117143,"endOffset":117280,"count":0},{"startOffset":117431,"endOffset":117542,"count":0},{"startOffset":117566,"endOffset":117698,"count":0},{"startOffset":117735,"endOffset":117748,"count":0},{"startOffset":117932,"endOffset":117944,"count":0},{"startOffset":117981,"endOffset":117994,"count":0},{"startOffset":118164,"endOffset":118177,"count":0},{"startOffset":118216,"endOffset":118238,"count":0},{"startOffset":118278,"endOffset":118300,"count":0},{"startOffset":118576,"endOffset":118588,"count":0},{"startOffset":118615,"endOffset":118628,"count":0},{"startOffset":118768,"endOffset":118781,"count":0},{"startOffset":118861,"endOffset":118886,"count":0}],"isBlockCoverage":true},{"functionName":"_isFunctionSubtype","ranges":[{"startOffset":118913,"endOffset":121867,"count":1},{"startOffset":119567,"endOffset":119580,"count":0},{"startOffset":120006,"endOffset":120019,"count":0},{"startOffset":120482,"endOffset":120495,"count":0},{"startOffset":120682,"endOffset":120695,"count":0},{"startOffset":120916,"endOffset":120929,"count":0},{"startOffset":120992,"endOffset":121171,"count":0},{"startOffset":121437,"endOffset":121842,"count":0}],"isBlockCoverage":true},{"functionName":"_isInterfaceSubtype","ranges":[{"startOffset":121894,"endOffset":123121,"count":1},{"startOffset":122175,"endOffset":122584,"count":0},{"startOffset":122669,"endOffset":122682,"count":0},{"startOffset":123083,"endOffset":123096,"count":0}],"isBlockCoverage":true},{"functionName":"typeEqual","ranges":[{"startOffset":123138,"endOffset":124947,"count":1},{"startOffset":123229,"endOffset":123426,"count":0},{"startOffset":123435,"endOffset":123442,"count":0},{"startOffset":123451,"endOffset":123518,"count":0},{"startOffset":123527,"endOffset":123808,"count":0},{"startOffset":123817,"endOffset":124067,"count":0},{"startOffset":124076,"endOffset":124623,"count":0},{"startOffset":124632,"endOffset":124892,"count":0},{"startOffset":124901,"endOffset":124933,"count":0}],"isBlockCoverage":true},{"functionName":"typesEqual","ranges":[{"startOffset":124965,"endOffset":125245,"count":1},{"startOffset":125093,"endOffset":125106,"count":0},{"startOffset":125207,"endOffset":125220,"count":0}],"isBlockCoverage":true},{"functionName":"namedTypesEqual","ranges":[{"startOffset":125268,"endOffset":125761,"count":0}],"isBlockCoverage":false},{"functionName":"isLegacyTopType","ranges":[{"startOffset":125784,"endOffset":125838,"count":1}],"isBlockCoverage":true},{"functionName":"isTopType","ranges":[{"startOffset":125855,"endOffset":126428,"count":1},{"startOffset":126261,"endOffset":126341,"count":0}],"isBlockCoverage":true},{"functionName":"_Utils_objectAssign","ranges":[{"startOffset":126455,"endOffset":126663,"count":1}],"isBlockCoverage":true},{"functionName":"Rti","ranges":[{"startOffset":126674,"endOffset":126970,"count":1}],"isBlockCoverage":true},{"functionName":"_FunctionParameters","ranges":[{"startOffset":126997,"endOffset":127123,"count":1}],"isBlockCoverage":true},{"functionName":"_Type","ranges":[{"startOffset":127136,"endOffset":127213,"count":1}],"isBlockCoverage":true},{"functionName":"_Error","ranges":[{"startOffset":127227,"endOffset":127252,"count":0}],"isBlockCoverage":false},{"functionName":"_CastError","ranges":[{"startOffset":127270,"endOffset":127327,"count":0}],"isBlockCoverage":false},{"functionName":"_TypeError","ranges":[{"startOffset":127345,"endOffset":127402,"count":0}],"isBlockCoverage":false},{"functionName":"extractKeys","ranges":[{"startOffset":127421,"endOffset":127537,"count":0}],"isBlockCoverage":false},{"functionName":"unmangleGlobalNameIfPreservedAnyways","ranges":[{"startOffset":127581,"endOffset":127649,"count":0}],"isBlockCoverage":false},{"functionName":"printString","ranges":[{"startOffset":127668,"endOffset":128115,"count":0}],"isBlockCoverage":false},{"functionName":"makeDispatchRecord","ranges":[{"startOffset":128153,"endOffset":128286,"count":1}],"isBlockCoverage":true},{"functionName":"getNativeInterceptor","ranges":[{"startOffset":128314,"endOffset":129994,"count":1},{"startOffset":128762,"endOffset":128776,"count":0},{"startOffset":128891,"endOffset":129041,"count":0},{"startOffset":129049,"endOffset":129138,"count":0},{"startOffset":129139,"endOffset":129190,"count":0},{"startOffset":129231,"endOffset":129993,"count":0}],"isBlockCoverage":true},{"functionName":"JSArray_JSArray$fixed","ranges":[{"startOffset":130023,"endOffset":130380,"count":0}],"isBlockCoverage":false},{"functionName":"JSArray_JSArray$markFixed","ranges":[{"startOffset":130413,"endOffset":130543,"count":0}],"isBlockCoverage":false},{"functionName":"JSArray_markFixedList","ranges":[{"startOffset":130572,"endOffset":130646,"count":1}],"isBlockCoverage":true},{"functionName":"JSString__isWhitespace","ranges":[{"startOffset":130676,"endOffset":131431,"count":0}],"isBlockCoverage":false},{"functionName":"JSString__skipLeadingWhitespace","ranges":[{"startOffset":131470,"endOffset":131788,"count":0}],"isBlockCoverage":false},{"functionName":"JSString__skipTrailingWhitespace","ranges":[{"startOffset":131828,"endOffset":132157,"count":0}],"isBlockCoverage":false},{"functionName":"getInterceptor$","ranges":[{"startOffset":132180,"endOffset":132943,"count":1},{"startOffset":132240,"endOffset":132368,"count":0},{"startOffset":132699,"endOffset":132825,"count":0}],"isBlockCoverage":true},{"functionName":"getInterceptor$ansx","ranges":[{"startOffset":132970,"endOffset":133556,"count":0}],"isBlockCoverage":false},{"functionName":"getInterceptor$asx","ranges":[{"startOffset":133582,"endOffset":134092,"count":1},{"startOffset":133715,"endOffset":133731,"count":0},{"startOffset":133848,"endOffset":133974,"count":0},{"startOffset":134039,"endOffset":134091,"count":0}],"isBlockCoverage":true},{"functionName":"getInterceptor$ax","ranges":[{"startOffset":134117,"endOffset":134551,"count":1},{"startOffset":134174,"endOffset":134190,"count":0},{"startOffset":134307,"endOffset":134433,"count":0}],"isBlockCoverage":true},{"functionName":"getInterceptor$n","ranges":[{"startOffset":134575,"endOffset":134848,"count":0}],"isBlockCoverage":false},{"functionName":"getInterceptor$s","ranges":[{"startOffset":134872,"endOffset":135145,"count":1},{"startOffset":134968,"endOffset":135144,"count":0}],"isBlockCoverage":true},{"functionName":"getInterceptor$x","ranges":[{"startOffset":135169,"endOffset":135526,"count":1},{"startOffset":135226,"endOffset":135242,"count":0},{"startOffset":135282,"endOffset":135408,"count":0},{"startOffset":135457,"endOffset":135473,"count":0}],"isBlockCoverage":true},{"functionName":"get$first$ax","ranges":[{"startOffset":135546,"endOffset":135636,"count":1}],"isBlockCoverage":true},{"functionName":"get$hashCode$","ranges":[{"startOffset":135657,"endOffset":135748,"count":1}],"isBlockCoverage":true},{"functionName":"get$isEmpty$asx","ranges":[{"startOffset":135771,"endOffset":135864,"count":1}],"isBlockCoverage":true},{"functionName":"get$iterator$ax","ranges":[{"startOffset":135887,"endOffset":135980,"count":1}],"isBlockCoverage":true},{"functionName":"get$last$ax","ranges":[{"startOffset":135999,"endOffset":136088,"count":0}],"isBlockCoverage":false},{"functionName":"get$length$asx","ranges":[{"startOffset":136110,"endOffset":136202,"count":1}],"isBlockCoverage":true},{"functionName":"get$message$x","ranges":[{"startOffset":136223,"endOffset":136314,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType$","ranges":[{"startOffset":136338,"endOffset":136432,"count":0}],"isBlockCoverage":false},{"functionName":"get$startsWith$s","ranges":[{"startOffset":136456,"endOffset":136550,"count":0}],"isBlockCoverage":false},{"functionName":"$add$ansx","ranges":[{"startOffset":136567,"endOffset":136756,"count":0}],"isBlockCoverage":false},{"functionName":"$eq$","ranges":[{"startOffset":136768,"endOffset":136998,"count":1}],"isBlockCoverage":true},{"functionName":"$index$asx","ranges":[{"startOffset":137016,"endOffset":137374,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet$ax","ranges":[{"startOffset":137394,"endOffset":137500,"count":1}],"isBlockCoverage":true},{"functionName":"_codeUnitAt$1$s","ranges":[{"startOffset":137523,"endOffset":137624,"count":1}],"isBlockCoverage":true},{"functionName":"_removeEventListener$3$x","ranges":[{"startOffset":137656,"endOffset":137782,"count":1}],"isBlockCoverage":true},{"functionName":"addEventListener$3$x","ranges":[{"startOffset":137810,"endOffset":137932,"count":1}],"isBlockCoverage":true},{"functionName":"allMatches$1$s","ranges":[{"startOffset":137954,"endOffset":138054,"count":0}],"isBlockCoverage":false},{"functionName":"allMatches$2$s","ranges":[{"startOffset":138076,"endOffset":138184,"count":0}],"isBlockCoverage":false},{"functionName":"codeUnitAt$1$s","ranges":[{"startOffset":138206,"endOffset":138306,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1$asx","ranges":[{"startOffset":138328,"endOffset":138428,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1$ax","ranges":[{"startOffset":138450,"endOffset":138550,"count":1}],"isBlockCoverage":true},{"functionName":"endsWith$1$s","ranges":[{"startOffset":138570,"endOffset":138668,"count":0}],"isBlockCoverage":false},{"functionName":"fillRange$3$ax","ranges":[{"startOffset":138690,"endOffset":138806,"count":1}],"isBlockCoverage":true},{"functionName":"map$1$1$ax","ranges":[{"startOffset":138824,"endOffset":138930,"count":0}],"isBlockCoverage":false},{"functionName":"matchAsPrefix$2$s","ranges":[{"startOffset":138955,"endOffset":139066,"count":0}],"isBlockCoverage":false},{"functionName":"padRight$1$s","ranges":[{"startOffset":139086,"endOffset":139184,"count":0}],"isBlockCoverage":false},{"functionName":"replaceRange$3$asx","ranges":[{"startOffset":139210,"endOffset":139330,"count":0}],"isBlockCoverage":false},{"functionName":"startsWith$1$s","ranges":[{"startOffset":139352,"endOffset":139452,"count":0}],"isBlockCoverage":false},{"functionName":"startsWith$2$s","ranges":[{"startOffset":139474,"endOffset":139582,"count":1}],"isBlockCoverage":true},{"functionName":"substring$1$s","ranges":[{"startOffset":139603,"endOffset":139702,"count":0}],"isBlockCoverage":false},{"functionName":"substring$2$s","ranges":[{"startOffset":139723,"endOffset":139830,"count":0}],"isBlockCoverage":false},{"functionName":"toRadixString$1$n","ranges":[{"startOffset":139855,"endOffset":139958,"count":0}],"isBlockCoverage":false},{"functionName":"toSet$0$ax","ranges":[{"startOffset":139976,"endOffset":140064,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0$","ranges":[{"startOffset":140083,"endOffset":140172,"count":0}],"isBlockCoverage":false},{"functionName":"trim$0$s","ranges":[{"startOffset":140188,"endOffset":140274,"count":0}],"isBlockCoverage":false},{"functionName":"Interceptor","ranges":[{"startOffset":140293,"endOffset":140323,"count":0}],"isBlockCoverage":false},{"functionName":"JSBool","ranges":[{"startOffset":140337,"endOffset":140362,"count":0}],"isBlockCoverage":false},{"functionName":"JSNull","ranges":[{"startOffset":140376,"endOffset":140401,"count":0}],"isBlockCoverage":false},{"functionName":"JSObject","ranges":[{"startOffset":140417,"endOffset":140444,"count":0}],"isBlockCoverage":false},{"functionName":"JavaScriptObject","ranges":[{"startOffset":140468,"endOffset":140503,"count":0}],"isBlockCoverage":false},{"functionName":"PlainJavaScriptObject","ranges":[{"startOffset":140532,"endOffset":140572,"count":0}],"isBlockCoverage":false},{"functionName":"UnknownJavaScriptObject","ranges":[{"startOffset":140603,"endOffset":140645,"count":0}],"isBlockCoverage":false},{"functionName":"JavaScriptFunction","ranges":[{"startOffset":140671,"endOffset":140708,"count":0}],"isBlockCoverage":false},{"functionName":"JSArray","ranges":[{"startOffset":140723,"endOffset":140772,"count":0}],"isBlockCoverage":true},{"functionName":"JSUnmodifiableArray","ranges":[{"startOffset":140799,"endOffset":140860,"count":0}],"isBlockCoverage":false},{"functionName":"ArrayIterator","ranges":[{"startOffset":140881,"endOffset":141052,"count":1}],"isBlockCoverage":true},{"functionName":"JSNumber","ranges":[{"startOffset":141068,"endOffset":141095,"count":0}],"isBlockCoverage":false},{"functionName":"JSInt","ranges":[{"startOffset":141108,"endOffset":141132,"count":0}],"isBlockCoverage":false},{"functionName":"JSDouble","ranges":[{"startOffset":141148,"endOffset":141175,"count":0}],"isBlockCoverage":false},{"functionName":"JSString","ranges":[{"startOffset":141191,"endOffset":141218,"count":0}],"isBlockCoverage":true},{"functionName":"_AsyncRun__initializeScheduleImmediate","ranges":[{"startOffset":141276,"endOffset":142083,"count":1},{"startOffset":141369,"endOffset":141433,"count":0},{"startOffset":141892,"endOffset":142082,"count":0}],"isBlockCoverage":true},{"functionName":"_AsyncRun__scheduleImmediateJsOverride","ranges":[{"startOffset":142129,"endOffset":142315,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncRun__scheduleImmediateWithSetImmediate","ranges":[{"startOffset":142367,"endOffset":142554,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncRun__scheduleImmediateWithTimer","ranges":[{"startOffset":142599,"endOffset":142705,"count":0}],"isBlockCoverage":false},{"functionName":"Timer__createTimer","ranges":[{"startOffset":142731,"endOffset":142922,"count":1},{"startOffset":142886,"endOffset":142889,"count":0}],"isBlockCoverage":true},{"functionName":"_TimerImpl$","ranges":[{"startOffset":142941,"endOffset":143084,"count":1}],"isBlockCoverage":true},{"functionName":"_TimerImpl$periodic","ranges":[{"startOffset":143111,"endOffset":143264,"count":0}],"isBlockCoverage":false},{"functionName":"_makeAsyncAwaitCompleter","ranges":[{"startOffset":143296,"endOffset":143454,"count":1}],"isBlockCoverage":true},{"functionName":"_asyncStartSync","ranges":[{"startOffset":143477,"endOffset":143617,"count":1}],"isBlockCoverage":true},{"functionName":"_asyncAwait","ranges":[{"startOffset":143636,"endOffset":143720,"count":1}],"isBlockCoverage":true},{"functionName":"_asyncReturn","ranges":[{"startOffset":143740,"endOffset":143811,"count":1}],"isBlockCoverage":true},{"functionName":"_asyncRethrow","ranges":[{"startOffset":143832,"endOffset":143960,"count":0}],"isBlockCoverage":false},{"functionName":"_awaitOnObject","ranges":[{"startOffset":143982,"endOffset":144686,"count":1},{"startOffset":144384,"endOffset":144441,"count":0}],"isBlockCoverage":true},{"functionName":"_wrapJsFunctionForAsync","ranges":[{"startOffset":144717,"endOffset":145220,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":144762,"endOffset":145053,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":144799,"endOffset":145044,"count":1},{"startOffset":144941,"endOffset":145034,"count":0}],"isBlockCoverage":true},{"functionName":"Future_Future","ranges":[{"startOffset":145241,"endOffset":145457,"count":1}],"isBlockCoverage":true},{"functionName":"Future_Future$microtask","ranges":[{"startOffset":145488,"endOffset":145706,"count":0}],"isBlockCoverage":false},{"functionName":"Future_Future$sync","ranges":[{"startOffset":145732,"endOffset":146777,"count":1},{"startOffset":145947,"endOffset":145961,"count":0},{"startOffset":146185,"endOffset":146771,"count":0}],"isBlockCoverage":true},{"functionName":"Future_Future$error","ranges":[{"startOffset":146804,"endOffset":147339,"count":0}],"isBlockCoverage":false},{"functionName":"Future_wait","ranges":[{"startOffset":147358,"endOffset":148702,"count":0}],"isBlockCoverage":false},{"functionName":"Future_forEach","ranges":[{"startOffset":148724,"endOffset":148925,"count":1}],"isBlockCoverage":true},{"functionName":"Future__kTrue","ranges":[{"startOffset":148946,"endOffset":148984,"count":0}],"isBlockCoverage":false},{"functionName":"Future_doWhile","ranges":[{"startOffset":149006,"endOffset":149408,"count":1}],"isBlockCoverage":true},{"functionName":"_completeWithErrorCallback","ranges":[{"startOffset":149442,"endOffset":149802,"count":0}],"isBlockCoverage":false},{"functionName":"_Future$zoneValue","ranges":[{"startOffset":149827,"endOffset":150023,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__chainForeignFuture","ranges":[{"startOffset":150058,"endOffset":150653,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainCoreFuture","ranges":[{"startOffset":150685,"endOffset":151411,"count":1},{"startOffset":150866,"endOffset":150958,"count":0},{"startOffset":150978,"endOffset":151135,"count":0}],"isBlockCoverage":true},{"functionName":"_Future__propagateToListeners","ranges":[{"startOffset":151448,"endOffset":155442,"count":1},{"startOffset":151952,"endOffset":152109,"count":0},{"startOffset":152235,"endOffset":152357,"count":0},{"startOffset":152661,"endOffset":152687,"count":0},{"startOffset":152790,"endOffset":152910,"count":0},{"startOffset":152958,"endOffset":153223,"count":0},{"startOffset":153845,"endOffset":153967,"count":0},{"startOffset":154108,"endOffset":154697,"count":0},{"startOffset":155231,"endOffset":155375,"count":0}],"isBlockCoverage":true},{"functionName":"_registerErrorHandler","ranges":[{"startOffset":155471,"endOffset":156025,"count":0}],"isBlockCoverage":false},{"functionName":"_microtaskLoop","ranges":[{"startOffset":156047,"endOffset":156321,"count":1}],"isBlockCoverage":true},{"functionName":"_startMicrotaskLoop","ranges":[{"startOffset":156348,"endOffset":156683,"count":1},{"startOffset":156577,"endOffset":156669,"count":0}],"isBlockCoverage":true},{"functionName":"_scheduleAsyncCallback","ranges":[{"startOffset":156713,"endOffset":157097,"count":1}],"isBlockCoverage":true},{"functionName":"_schedulePriorityAsyncCallback","ranges":[{"startOffset":157135,"endOffset":157721,"count":0}],"isBlockCoverage":false},{"functionName":"scheduleMicrotask","ranges":[{"startOffset":157746,"endOffset":158408,"count":1},{"startOffset":157973,"endOffset":158407,"count":0}],"isBlockCoverage":true},{"functionName":"Stream_Stream$fromFuture","ranges":[{"startOffset":158440,"endOffset":158865,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_Stream$fromIterable","ranges":[{"startOffset":158899,"endOffset":159065,"count":1}],"isBlockCoverage":true},{"functionName":"StreamIterator_StreamIterator","ranges":[{"startOffset":159102,"endOffset":159288,"count":0}],"isBlockCoverage":false},{"functionName":"StreamController_StreamController","ranges":[{"startOffset":159329,"endOffset":159628,"count":1},{"startOffset":159516,"endOffset":159621,"count":0}],"isBlockCoverage":true},{"functionName":"_runGuarded","ranges":[{"startOffset":159647,"endOffset":159995,"count":1},{"startOffset":159819,"endOffset":159989,"count":0}],"isBlockCoverage":true},{"functionName":"_AddStreamState_makeErrorHandler","ranges":[{"startOffset":160035,"endOffset":160136,"count":0}],"isBlockCoverage":false},{"functionName":"_BufferingStreamSubscription$","ranges":[{"startOffset":160173,"endOffset":160505,"count":1},{"startOffset":160287,"endOffset":160290,"count":0}],"isBlockCoverage":true},{"functionName":"_nullDataHandler","ranges":[{"startOffset":160529,"endOffset":160552,"count":0}],"isBlockCoverage":false},{"functionName":"_nullErrorHandler","ranges":[{"startOffset":160577,"endOffset":160719,"count":0}],"isBlockCoverage":false},{"functionName":"_nullDoneHandler","ranges":[{"startOffset":160743,"endOffset":160761,"count":0}],"isBlockCoverage":false},{"functionName":"_runUserCode","ranges":[{"startOffset":160781,"endOffset":161431,"count":1},{"startOffset":160958,"endOffset":161425,"count":0}],"isBlockCoverage":true},{"functionName":"_cancelAndError","ranges":[{"startOffset":161454,"endOffset":161799,"count":0}],"isBlockCoverage":false},{"functionName":"_cancelAndErrorClosure","ranges":[{"startOffset":161829,"endOffset":161940,"count":1}],"isBlockCoverage":true},{"functionName":"_cancelAndValue","ranges":[{"startOffset":161963,"endOffset":162267,"count":1}],"isBlockCoverage":true},{"functionName":"Timer_Timer","ranges":[{"startOffset":162286,"endOffset":162516,"count":1},{"startOffset":162389,"endOffset":162433,"count":0}],"isBlockCoverage":true},{"functionName":"_ZoneSpecification$","ranges":[{"startOffset":162543,"endOffset":162986,"count":1}],"isBlockCoverage":true},{"functionName":"Zone__enter","ranges":[{"startOffset":163005,"endOffset":163218,"count":1}],"isBlockCoverage":true},{"functionName":"_parentDelegate","ranges":[{"startOffset":163241,"endOffset":163377,"count":1}],"isBlockCoverage":true},{"functionName":"_rootHandleUncaughtError","ranges":[{"startOffset":163409,"endOffset":163630,"count":0}],"isBlockCoverage":false},{"functionName":"_rootRun","ranges":[{"startOffset":163646,"endOffset":164117,"count":1},{"startOffset":164009,"endOffset":164010,"count":0}],"isBlockCoverage":true},{"functionName":"_rootRunUnary","ranges":[{"startOffset":164138,"endOffset":164675,"count":1},{"startOffset":164567,"endOffset":164568,"count":0}],"isBlockCoverage":true},{"functionName":"_rootRunBinary","ranges":[{"startOffset":164697,"endOffset":165297,"count":0}],"isBlockCoverage":false},{"functionName":"_rootRegisterCallback","ranges":[{"startOffset":165326,"endOffset":165413,"count":1}],"isBlockCoverage":true},{"functionName":"_rootRegisterUnaryCallback","ranges":[{"startOffset":165447,"endOffset":165567,"count":1}],"isBlockCoverage":true},{"functionName":"_rootRegisterBinaryCallback","ranges":[{"startOffset":165602,"endOffset":165740,"count":1}],"isBlockCoverage":true},{"functionName":"_rootErrorCallback","ranges":[{"startOffset":165766,"endOffset":165885,"count":0}],"isBlockCoverage":false},{"functionName":"_rootScheduleMicrotask","ranges":[{"startOffset":165915,"endOffset":166240,"count":1},{"startOffset":166160,"endOffset":166198,"count":0}],"isBlockCoverage":true},{"functionName":"_rootCreateTimer","ranges":[{"startOffset":166264,"endOffset":166506,"count":1}],"isBlockCoverage":true},{"functionName":"_rootCreatePeriodicTimer","ranges":[{"startOffset":166538,"endOffset":166935,"count":0}],"isBlockCoverage":false},{"functionName":"_rootPrint","ranges":[{"startOffset":166953,"endOffset":167048,"count":0}],"isBlockCoverage":false},{"functionName":"_printToZone","ranges":[{"startOffset":167068,"endOffset":167130,"count":0}],"isBlockCoverage":false},{"functionName":"_rootFork","ranges":[{"startOffset":167147,"endOffset":169398,"count":1}],"isBlockCoverage":true},{"functionName":"runZoned","ranges":[{"startOffset":169414,"endOffset":171320,"count":1},{"startOffset":169842,"endOffset":170101,"count":0},{"startOffset":170196,"endOffset":170336,"count":0},{"startOffset":170963,"endOffset":171319,"count":0}],"isBlockCoverage":true},{"functionName":"_runZoned","ranges":[{"startOffset":171337,"endOffset":171497,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncRun__initializeScheduleImmediate_internalCallback","ranges":[{"startOffset":171560,"endOffset":171660,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncRun__initializeScheduleImmediate_closure","ranges":[{"startOffset":171714,"endOffset":171856,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncRun__scheduleImmediateJsOverride_internalCallback","ranges":[{"startOffset":171919,"endOffset":172021,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncRun__scheduleImmediateWithSetImmediate_internalCallback","ranges":[{"startOffset":172090,"endOffset":172198,"count":0}],"isBlockCoverage":false},{"functionName":"_TimerImpl","ranges":[{"startOffset":172216,"endOffset":172319,"count":1}],"isBlockCoverage":true},{"functionName":"_TimerImpl_internalCallback","ranges":[{"startOffset":172354,"endOffset":172455,"count":1}],"isBlockCoverage":true},{"functionName":"_TimerImpl$periodic_closure","ranges":[{"startOffset":172490,"endOffset":172660,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncAwaitCompleter","ranges":[{"startOffset":172688,"endOffset":172806,"count":1}],"isBlockCoverage":true},{"functionName":"_awaitOnObject_closure","ranges":[{"startOffset":172836,"endOffset":172909,"count":1}],"isBlockCoverage":true},{"functionName":"_awaitOnObject_closure0","ranges":[{"startOffset":172940,"endOffset":173014,"count":1}],"isBlockCoverage":true},{"functionName":"_wrapJsFunctionForAsync_closure","ranges":[{"startOffset":173053,"endOffset":173133,"count":1}],"isBlockCoverage":true},{"functionName":"_BroadcastStream","ranges":[{"startOffset":173157,"endOffset":173248,"count":1}],"isBlockCoverage":true},{"functionName":"_BroadcastSubscription","ranges":[{"startOffset":173278,"endOffset":173605,"count":1}],"isBlockCoverage":true},{"functionName":"_BroadcastStreamController","ranges":[{"startOffset":173639,"endOffset":173684,"count":0}],"isBlockCoverage":false},{"functionName":"_SyncBroadcastStreamController","ranges":[{"startOffset":173722,"endOffset":173978,"count":1}],"isBlockCoverage":true},{"functionName":"_SyncBroadcastStreamController__sendData_closure","ranges":[{"startOffset":174034,"endOffset":174152,"count":0}],"isBlockCoverage":false},{"functionName":"_SyncBroadcastStreamController__sendError_closure","ranges":[{"startOffset":174209,"endOffset":174361,"count":0}],"isBlockCoverage":false},{"functionName":"_SyncBroadcastStreamController__sendDone_closure","ranges":[{"startOffset":174417,"endOffset":174509,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncBroadcastStreamController","ranges":[{"startOffset":174548,"endOffset":174805,"count":0}],"isBlockCoverage":false},{"functionName":"Future","ranges":[{"startOffset":174819,"endOffset":174844,"count":0}],"isBlockCoverage":false},{"functionName":"Future_Future_closure","ranges":[{"startOffset":174873,"endOffset":174972,"count":1}],"isBlockCoverage":true},{"functionName":"Future_Future$microtask_closure","ranges":[{"startOffset":175011,"endOffset":175120,"count":0}],"isBlockCoverage":false},{"functionName":"Future_wait_handleError","ranges":[{"startOffset":175151,"endOffset":175316,"count":0}],"isBlockCoverage":false},{"functionName":"Future_wait_closure","ranges":[{"startOffset":175343,"endOffset":175546,"count":0}],"isBlockCoverage":false},{"functionName":"Future_forEach_closure","ranges":[{"startOffset":175576,"endOffset":175673,"count":1}],"isBlockCoverage":true},{"functionName":"Future_doWhile_closure","ranges":[{"startOffset":175703,"endOffset":175830,"count":1}],"isBlockCoverage":true},{"functionName":"TimeoutException","ranges":[{"startOffset":175854,"endOffset":175946,"count":0}],"isBlockCoverage":false},{"functionName":"Completer","ranges":[{"startOffset":175963,"endOffset":175991,"count":0}],"isBlockCoverage":false},{"functionName":"_Completer","ranges":[{"startOffset":176009,"endOffset":176038,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncCompleter","ranges":[{"startOffset":176061,"endOffset":176146,"count":1}],"isBlockCoverage":true},{"functionName":"_SyncCompleter","ranges":[{"startOffset":176168,"endOffset":176252,"count":1}],"isBlockCoverage":true},{"functionName":"_FutureListener","ranges":[{"startOffset":176275,"endOffset":176487,"count":1}],"isBlockCoverage":true},{"functionName":"_Future","ranges":[{"startOffset":176502,"endOffset":176647,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__addListener_closure","ranges":[{"startOffset":176683,"endOffset":176785,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__prependListeners_closure","ranges":[{"startOffset":176826,"endOffset":176931,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainForeignFuture_closure","ranges":[{"startOffset":176974,"endOffset":177054,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainForeignFuture_closure0","ranges":[{"startOffset":177098,"endOffset":177179,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__chainForeignFuture_closure1","ranges":[{"startOffset":177223,"endOffset":177350,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__asyncComplete_closure","ranges":[{"startOffset":177388,"endOffset":177489,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__chainFuture_closure","ranges":[{"startOffset":177525,"endOffset":177624,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__asyncCompleteError_closure","ranges":[{"startOffset":177667,"endOffset":177805,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__propagateToListeners_handleWhenCompleteCallback","ranges":[{"startOffset":177869,"endOffset":178066,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__propagateToListeners_handleWhenCompleteCallback_closure","ranges":[{"startOffset":178138,"endOffset":178255,"count":0}],"isBlockCoverage":false},{"functionName":"_Future__propagateToListeners_handleValueCallback","ranges":[{"startOffset":178312,"endOffset":178470,"count":1}],"isBlockCoverage":true},{"functionName":"_Future__propagateToListeners_handleError","ranges":[{"startOffset":178519,"endOffset":178663,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncCallbackEntry","ranges":[{"startOffset":178690,"endOffset":178780,"count":1}],"isBlockCoverage":true},{"functionName":"Stream","ranges":[{"startOffset":178794,"endOffset":178819,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_Stream$fromFuture_closure","ranges":[{"startOffset":178859,"endOffset":178963,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_Stream$fromFuture_closure0","ranges":[{"startOffset":179004,"endOffset":179086,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_Stream$fromIterable_closure","ranges":[{"startOffset":179128,"endOffset":179232,"count":1}],"isBlockCoverage":true},{"functionName":"Stream_pipe_closure","ranges":[{"startOffset":179259,"endOffset":179331,"count":1}],"isBlockCoverage":true},{"functionName":"Stream_length_closure","ranges":[{"startOffset":179360,"endOffset":179453,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_length_closure0","ranges":[{"startOffset":179483,"endOffset":179578,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_first_closure","ranges":[{"startOffset":179606,"endOffset":179726,"count":1}],"isBlockCoverage":true},{"functionName":"Stream_first_closure0","ranges":[{"startOffset":179755,"endOffset":179821,"count":1}],"isBlockCoverage":true},{"functionName":"Stream_last_closure","ranges":[{"startOffset":179848,"endOffset":179939,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_last_closure0","ranges":[{"startOffset":179967,"endOffset":180060,"count":0}],"isBlockCoverage":false},{"functionName":"Stream_firstWhere_closure","ranges":[{"startOffset":180093,"endOffset":180252,"count":1}],"isBlockCoverage":true},{"functionName":"Stream_firstWhere__closure","ranges":[{"startOffset":180286,"endOffset":180382,"count":1}],"isBlockCoverage":true},{"functionName":"Stream_firstWhere__closure0","ranges":[{"startOffset":180417,"endOffset":180544,"count":1}],"isBlockCoverage":true},{"functionName":"Stream_firstWhere_closure0","ranges":[{"startOffset":180578,"endOffset":180704,"count":1}],"isBlockCoverage":true},{"functionName":"StreamSubscription","ranges":[{"startOffset":180730,"endOffset":180767,"count":0}],"isBlockCoverage":false},{"functionName":"StreamTransformerBase","ranges":[{"startOffset":180796,"endOffset":180836,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamController","ranges":[{"startOffset":180861,"endOffset":180897,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamController__subscribe_closure","ranges":[{"startOffset":180941,"endOffset":181021,"count":1}],"isBlockCoverage":true},{"functionName":"_StreamController__recordCancel_complete","ranges":[{"startOffset":181069,"endOffset":181153,"count":1}],"isBlockCoverage":true},{"functionName":"_SyncStreamControllerDispatch","ranges":[{"startOffset":181190,"endOffset":181238,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncStreamControllerDispatch","ranges":[{"startOffset":181276,"endOffset":181325,"count":0}],"isBlockCoverage":false},{"functionName":"_AsyncStreamController","ranges":[{"startOffset":181355,"endOffset":181616,"count":0}],"isBlockCoverage":false},{"functionName":"_SyncStreamController","ranges":[{"startOffset":181645,"endOffset":181905,"count":1}],"isBlockCoverage":true},{"functionName":"_ControllerStream","ranges":[{"startOffset":181930,"endOffset":182022,"count":1}],"isBlockCoverage":true},{"functionName":"_ControllerSubscription","ranges":[{"startOffset":182053,"endOffset":182306,"count":1}],"isBlockCoverage":true},{"functionName":"_StreamSinkWrapper","ranges":[{"startOffset":182332,"endOffset":182428,"count":1}],"isBlockCoverage":true},{"functionName":"_AddStreamState","ranges":[{"startOffset":182451,"endOffset":182485,"count":0}],"isBlockCoverage":false},{"functionName":"_AddStreamState_makeErrorHandler_closure","ranges":[{"startOffset":182533,"endOffset":182622,"count":0}],"isBlockCoverage":false},{"functionName":"_AddStreamState_cancel_closure","ranges":[{"startOffset":182660,"endOffset":182734,"count":1}],"isBlockCoverage":true},{"functionName":"_StreamControllerAddStreamState","ranges":[{"startOffset":182773,"endOffset":182957,"count":1}],"isBlockCoverage":true},{"functionName":"_BufferingStreamSubscription","ranges":[{"startOffset":182993,"endOffset":183221,"count":1}],"isBlockCoverage":true},{"functionName":"_BufferingStreamSubscription__sendError_sendError","ranges":[{"startOffset":183278,"endOffset":183430,"count":0}],"isBlockCoverage":false},{"functionName":"_BufferingStreamSubscription__sendDone_sendDone","ranges":[{"startOffset":183485,"endOffset":183576,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamImpl","ranges":[{"startOffset":183595,"endOffset":183625,"count":0}],"isBlockCoverage":false},{"functionName":"_GeneratedStreamImpl","ranges":[{"startOffset":183653,"endOffset":183773,"count":1}],"isBlockCoverage":true},{"functionName":"_IterablePendingEvents","ranges":[{"startOffset":183803,"endOffset":183928,"count":1}],"isBlockCoverage":true},{"functionName":"_DelayedEvent","ranges":[{"startOffset":183949,"endOffset":183981,"count":0}],"isBlockCoverage":false},{"functionName":"_DelayedData","ranges":[{"startOffset":184001,"endOffset":184106,"count":0}],"isBlockCoverage":false},{"functionName":"_DelayedError","ranges":[{"startOffset":184127,"endOffset":184240,"count":0}],"isBlockCoverage":false},{"functionName":"_DelayedDone","ranges":[{"startOffset":184260,"endOffset":184291,"count":1}],"isBlockCoverage":true},{"functionName":"_PendingEvents","ranges":[{"startOffset":184313,"endOffset":184346,"count":0}],"isBlockCoverage":false},{"functionName":"_PendingEvents_schedule_closure","ranges":[{"startOffset":184385,"endOffset":184490,"count":1}],"isBlockCoverage":true},{"functionName":"_StreamImplEvents","ranges":[{"startOffset":184515,"endOffset":184666,"count":0}],"isBlockCoverage":false},{"functionName":"_DoneStreamSubscription","ranges":[{"startOffset":184697,"endOffset":184849,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamIterator","ranges":[{"startOffset":184872,"endOffset":184929,"count":0}],"isBlockCoverage":false},{"functionName":"_EmptyStream","ranges":[{"startOffset":184949,"endOffset":185003,"count":0}],"isBlockCoverage":false},{"functionName":"_cancelAndError_closure","ranges":[{"startOffset":185034,"endOffset":185161,"count":0}],"isBlockCoverage":false},{"functionName":"_cancelAndErrorClosure_closure","ranges":[{"startOffset":185199,"endOffset":185308,"count":1}],"isBlockCoverage":true},{"functionName":"_cancelAndValue_closure","ranges":[{"startOffset":185339,"endOffset":185434,"count":1}],"isBlockCoverage":true},{"functionName":"Timer","ranges":[{"startOffset":185447,"endOffset":185471,"count":0}],"isBlockCoverage":false},{"functionName":"AsyncError","ranges":[{"startOffset":185489,"endOffset":185575,"count":0}],"isBlockCoverage":false},{"functionName":"_ZoneFunction","ranges":[{"startOffset":185596,"endOffset":185708,"count":1}],"isBlockCoverage":true},{"functionName":"ZoneSpecification","ranges":[{"startOffset":185733,"endOffset":185769,"count":0}],"isBlockCoverage":false},{"functionName":"_ZoneSpecification","ranges":[{"startOffset":185795,"endOffset":186270,"count":1}],"isBlockCoverage":true},{"functionName":"ZoneDelegate","ranges":[{"startOffset":186290,"endOffset":186321,"count":0}],"isBlockCoverage":false},{"functionName":"Zone","ranges":[{"startOffset":186333,"endOffset":186356,"count":0}],"isBlockCoverage":false},{"functionName":"_ZoneDelegate","ranges":[{"startOffset":186377,"endOffset":186446,"count":1}],"isBlockCoverage":true},{"functionName":"_Zone","ranges":[{"startOffset":186459,"endOffset":186483,"count":0}],"isBlockCoverage":false},{"functionName":"_CustomZone","ranges":[{"startOffset":186502,"endOffset":186881,"count":1}],"isBlockCoverage":true},{"functionName":"_CustomZone_bindCallback_closure","ranges":[{"startOffset":186921,"endOffset":187052,"count":1}],"isBlockCoverage":true},{"functionName":"_CustomZone_bindUnaryCallback_closure","ranges":[{"startOffset":187097,"endOffset":187264,"count":0}],"isBlockCoverage":false},{"functionName":"_CustomZone_bindCallbackGuarded_closure","ranges":[{"startOffset":187311,"endOffset":187426,"count":1}],"isBlockCoverage":true},{"functionName":"_CustomZone_bindUnaryCallbackGuarded_closure","ranges":[{"startOffset":187478,"endOffset":187621,"count":1}],"isBlockCoverage":true},{"functionName":"_rootHandleUncaughtError_closure","ranges":[{"startOffset":187661,"endOffset":187770,"count":0}],"isBlockCoverage":false},{"functionName":"_RootZone","ranges":[{"startOffset":187787,"endOffset":187815,"count":1}],"isBlockCoverage":true},{"functionName":"_RootZone_bindCallback_closure","ranges":[{"startOffset":187853,"endOffset":187973,"count":0}],"isBlockCoverage":false},{"functionName":"_RootZone_bindCallbackGuarded_closure","ranges":[{"startOffset":188018,"endOffset":188122,"count":0}],"isBlockCoverage":false},{"functionName":"_RootZone_bindUnaryCallbackGuarded_closure","ranges":[{"startOffset":188172,"endOffset":188304,"count":0}],"isBlockCoverage":false},{"functionName":"runZoned_closure","ranges":[{"startOffset":188328,"endOffset":188389,"count":1}],"isBlockCoverage":true},{"functionName":"HashMap_HashMap","ranges":[{"startOffset":188412,"endOffset":188522,"count":1}],"isBlockCoverage":true},{"functionName":"_HashMap__getTableEntry","ranges":[{"startOffset":188553,"endOffset":188656,"count":0}],"isBlockCoverage":false},{"functionName":"_HashMap__setTableEntry","ranges":[{"startOffset":188687,"endOffset":188814,"count":1},{"startOffset":188750,"endOffset":188769,"count":0}],"isBlockCoverage":true},{"functionName":"_HashMap__newHashTable","ranges":[{"startOffset":188844,"endOffset":189036,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashMap_LinkedHashMap","ranges":[{"startOffset":189071,"endOffset":189195,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashMap_LinkedHashMap$_literal","ranges":[{"startOffset":189239,"endOffset":189480,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashMap_LinkedHashMap$_empty","ranges":[{"startOffset":189522,"endOffset":189646,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashSet_LinkedHashSet","ranges":[{"startOffset":189681,"endOffset":189769,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashSet_LinkedHashSet$_empty","ranges":[{"startOffset":189811,"endOffset":189899,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashSet_LinkedHashSet$_literal","ranges":[{"startOffset":189943,"endOffset":190104,"count":1}],"isBlockCoverage":true},{"functionName":"_LinkedHashSet__newHashTable","ranges":[{"startOffset":190140,"endOffset":190343,"count":1}],"isBlockCoverage":true},{"functionName":"_LinkedHashSetIterator$","ranges":[{"startOffset":190374,"endOffset":190595,"count":1}],"isBlockCoverage":true},{"functionName":"HashMap_HashMap$from","ranges":[{"startOffset":190623,"endOffset":190799,"count":1}],"isBlockCoverage":true},{"functionName":"IterableBase_iterableToShortString","ranges":[{"startOffset":190841,"endOffset":191704,"count":0}],"isBlockCoverage":false},{"functionName":"IterableBase_iterableToFullString","ranges":[{"startOffset":191745,"endOffset":192506,"count":0}],"isBlockCoverage":false},{"functionName":"_isToStringVisiting","ranges":[{"startOffset":192533,"endOffset":192718,"count":0}],"isBlockCoverage":false},{"functionName":"_iterablePartsToStrings","ranges":[{"startOffset":192749,"endOffset":195409,"count":0}],"isBlockCoverage":false},{"functionName":"LinkedHashMap_LinkedHashMap$from","ranges":[{"startOffset":195449,"endOffset":195649,"count":1}],"isBlockCoverage":true},{"functionName":"LinkedHashSet_LinkedHashSet$from","ranges":[{"startOffset":195689,"endOffset":195923,"count":1}],"isBlockCoverage":true},{"functionName":"MapBase_mapToString","ranges":[{"startOffset":195950,"endOffset":196637,"count":0}],"isBlockCoverage":false},{"functionName":"ListQueue$","ranges":[{"startOffset":196655,"endOffset":196883,"count":1}],"isBlockCoverage":true},{"functionName":"_ListQueueIterator$","ranges":[{"startOffset":196910,"endOffset":197072,"count":0}],"isBlockCoverage":false},{"functionName":"_HashMap","ranges":[{"startOffset":197088,"endOffset":197255,"count":1}],"isBlockCoverage":true},{"functionName":"_IdentityHashMap","ranges":[{"startOffset":197279,"endOffset":197454,"count":1}],"isBlockCoverage":true},{"functionName":"_HashMapKeyIterable","ranges":[{"startOffset":197481,"endOffset":197568,"count":0}],"isBlockCoverage":false},{"functionName":"_HashMapKeyIterator","ranges":[{"startOffset":197595,"endOffset":197778,"count":0}],"isBlockCoverage":false},{"functionName":"_LinkedHashSet","ranges":[{"startOffset":197800,"endOffset":198048,"count":1}],"isBlockCoverage":true},{"functionName":"_LinkedHashSetCell","ranges":[{"startOffset":198074,"endOffset":198205,"count":1}],"isBlockCoverage":true},{"functionName":"_LinkedHashSetIterator","ranges":[{"startOffset":198235,"endOffset":198443,"count":1}],"isBlockCoverage":true},{"functionName":"UnmodifiableListView","ranges":[{"startOffset":198471,"endOffset":198574,"count":0}],"isBlockCoverage":false},{"functionName":"HashMap_HashMap$from_closure","ranges":[{"startOffset":198610,"endOffset":198729,"count":1}],"isBlockCoverage":true},{"functionName":"IterableBase","ranges":[{"startOffset":198749,"endOffset":198780,"count":0}],"isBlockCoverage":false},{"functionName":"LinkedHashMap_LinkedHashMap$from_closure","ranges":[{"startOffset":198828,"endOffset":198959,"count":1}],"isBlockCoverage":true},{"functionName":"ListBase","ranges":[{"startOffset":198975,"endOffset":199002,"count":0}],"isBlockCoverage":false},{"functionName":"ListMixin","ranges":[{"startOffset":199019,"endOffset":199047,"count":0}],"isBlockCoverage":false},{"functionName":"MapBase","ranges":[{"startOffset":199062,"endOffset":199088,"count":0}],"isBlockCoverage":false},{"functionName":"MapBase_mapToString_closure","ranges":[{"startOffset":199123,"endOffset":199223,"count":0}],"isBlockCoverage":false},{"functionName":"MapMixin","ranges":[{"startOffset":199239,"endOffset":199266,"count":0}],"isBlockCoverage":false},{"functionName":"_UnmodifiableMapMixin","ranges":[{"startOffset":199295,"endOffset":199335,"count":0}],"isBlockCoverage":false},{"functionName":"MapView","ranges":[{"startOffset":199350,"endOffset":199376,"count":0}],"isBlockCoverage":false},{"functionName":"UnmodifiableMapView","ranges":[{"startOffset":199403,"endOffset":199490,"count":1}],"isBlockCoverage":true},{"functionName":"ListQueue","ranges":[{"startOffset":199507,"endOffset":199650,"count":1}],"isBlockCoverage":true},{"functionName":"_ListQueueIterator","ranges":[{"startOffset":199676,"endOffset":199903,"count":0}],"isBlockCoverage":false},{"functionName":"SetMixin","ranges":[{"startOffset":199919,"endOffset":199946,"count":0}],"isBlockCoverage":false},{"functionName":"SetBase","ranges":[{"startOffset":199961,"endOffset":199987,"count":0}],"isBlockCoverage":false},{"functionName":"_SetBase","ranges":[{"startOffset":200003,"endOffset":200030,"count":0}],"isBlockCoverage":false},{"functionName":"_ListBase_Object_ListMixin","ranges":[{"startOffset":200064,"endOffset":200109,"count":0}],"isBlockCoverage":false},{"functionName":"_SetBase_Object_SetMixin","ranges":[{"startOffset":200141,"endOffset":200184,"count":0}],"isBlockCoverage":false},{"functionName":"_UnmodifiableMapView_MapView__UnmodifiableMapMixin","ranges":[{"startOffset":200242,"endOffset":200311,"count":0}],"isBlockCoverage":false},{"functionName":"_parseJson","ranges":[{"startOffset":200329,"endOffset":200797,"count":0}],"isBlockCoverage":false},{"functionName":"_convertJsonToDartLazy","ranges":[{"startOffset":200827,"endOffset":201212,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__convertIntercepted","ranges":[{"startOffset":201251,"endOffset":201457,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__convertInterceptedUint8List","ranges":[{"startOffset":201505,"endOffset":202094,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__useTextDecoderChecked","ranges":[{"startOffset":202136,"endOffset":202310,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__useTextDecoderUnchecked","ranges":[{"startOffset":202354,"endOffset":202579,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__unsafe","ranges":[{"startOffset":202606,"endOffset":202845,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder__makeDecoder","ranges":[{"startOffset":202877,"endOffset":203098,"count":0}],"isBlockCoverage":false},{"functionName":"_scanOneByteCharacters","ranges":[{"startOffset":203128,"endOffset":203470,"count":0}],"isBlockCoverage":false},{"functionName":"Base64Codec__checkPadding","ranges":[{"startOffset":203503,"endOffset":204114,"count":0}],"isBlockCoverage":false},{"functionName":"_JsonMap","ranges":[{"startOffset":204130,"endOffset":204243,"count":0}],"isBlockCoverage":false},{"functionName":"_JsonMapKeyIterable","ranges":[{"startOffset":204270,"endOffset":204335,"count":0}],"isBlockCoverage":false},{"functionName":"AsciiCodec","ranges":[{"startOffset":204353,"endOffset":204382,"count":1}],"isBlockCoverage":true},{"functionName":"_UnicodeSubsetEncoder","ranges":[{"startOffset":204411,"endOffset":204451,"count":0}],"isBlockCoverage":false},{"functionName":"AsciiEncoder","ranges":[{"startOffset":204471,"endOffset":204533,"count":1}],"isBlockCoverage":true},{"functionName":"Base64Codec","ranges":[{"startOffset":204552,"endOffset":204582,"count":1}],"isBlockCoverage":true},{"functionName":"Base64Encoder","ranges":[{"startOffset":204603,"endOffset":204635,"count":1}],"isBlockCoverage":true},{"functionName":"Codec","ranges":[{"startOffset":204648,"endOffset":204672,"count":0}],"isBlockCoverage":false},{"functionName":"_FusedCodec","ranges":[{"startOffset":204691,"endOffset":204810,"count":0}],"isBlockCoverage":false},{"functionName":"Converter","ranges":[{"startOffset":204827,"endOffset":204855,"count":0}],"isBlockCoverage":false},{"functionName":"Encoding","ranges":[{"startOffset":204871,"endOffset":204898,"count":0}],"isBlockCoverage":false},{"functionName":"JsonCodec","ranges":[{"startOffset":204915,"endOffset":204943,"count":1}],"isBlockCoverage":true},{"functionName":"JsonDecoder","ranges":[{"startOffset":204962,"endOffset":205020,"count":1}],"isBlockCoverage":true},{"functionName":"Utf8Codec","ranges":[{"startOffset":205037,"endOffset":205065,"count":1}],"isBlockCoverage":true},{"functionName":"Utf8Encoder","ranges":[{"startOffset":205084,"endOffset":205114,"count":1}],"isBlockCoverage":true},{"functionName":"_Utf8Encoder","ranges":[{"startOffset":205134,"endOffset":205235,"count":0}],"isBlockCoverage":false},{"functionName":"Utf8Decoder","ranges":[{"startOffset":205254,"endOffset":205319,"count":0}],"isBlockCoverage":false},{"functionName":"_Utf8Decoder","ranges":[{"startOffset":205339,"endOffset":205550,"count":0}],"isBlockCoverage":false},{"functionName":"int_parse","ranges":[{"startOffset":205567,"endOffset":205845,"count":0}],"isBlockCoverage":false},{"functionName":"Error__objectToString","ranges":[{"startOffset":205874,"endOffset":206053,"count":0}],"isBlockCoverage":false},{"functionName":"List_List$filled","ranges":[{"startOffset":206077,"endOffset":206334,"count":0}],"isBlockCoverage":false},{"functionName":"List_List$from","ranges":[{"startOffset":206356,"endOffset":206723,"count":1}],"isBlockCoverage":true},{"functionName":"List_List$unmodifiable","ranges":[{"startOffset":206753,"endOffset":206964,"count":1}],"isBlockCoverage":true},{"functionName":"String_String$fromCharCodes","ranges":[{"startOffset":206999,"endOffset":207622,"count":0}],"isBlockCoverage":false},{"functionName":"String_String$fromCharCode","ranges":[{"startOffset":207656,"endOffset":207738,"count":0}],"isBlockCoverage":false},{"functionName":"String__stringFromIterable","ranges":[{"startOffset":207772,"endOffset":208694,"count":0}],"isBlockCoverage":false},{"functionName":"RegExp_RegExp","ranges":[{"startOffset":208715,"endOffset":208868,"count":0}],"isBlockCoverage":false},{"functionName":"StringBuffer__writeAll","ranges":[{"startOffset":208898,"endOffset":209382,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_base","ranges":[{"startOffset":209398,"endOffset":209596,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__uriEncode","ranges":[{"startOffset":209619,"endOffset":210718,"count":0}],"isBlockCoverage":false},{"functionName":"StackTrace_current","ranges":[{"startOffset":210744,"endOffset":211119,"count":1},{"startOffset":210908,"endOffset":211113,"count":0}],"isBlockCoverage":true},{"functionName":"DateTime__fourDigits","ranges":[{"startOffset":211147,"endOffset":211424,"count":0}],"isBlockCoverage":false},{"functionName":"DateTime__threeDigits","ranges":[{"startOffset":211453,"endOffset":211581,"count":0}],"isBlockCoverage":false},{"functionName":"DateTime__twoDigits","ranges":[{"startOffset":211608,"endOffset":211691,"count":0}],"isBlockCoverage":false},{"functionName":"Duration$","ranges":[{"startOffset":211708,"endOffset":211891,"count":1},{"startOffset":211794,"endOffset":211821,"count":0}],"isBlockCoverage":true},{"functionName":"Error_safeToString","ranges":[{"startOffset":211917,"endOffset":212177,"count":0}],"isBlockCoverage":false},{"functionName":"AssertionError$","ranges":[{"startOffset":212200,"endOffset":212269,"count":0}],"isBlockCoverage":false},{"functionName":"ArgumentError$","ranges":[{"startOffset":212291,"endOffset":212378,"count":0}],"isBlockCoverage":false},{"functionName":"ArgumentError$value","ranges":[{"startOffset":212405,"endOffset":212507,"count":0}],"isBlockCoverage":false},{"functionName":"ArgumentError$notNull","ranges":[{"startOffset":212536,"endOffset":212633,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError$","ranges":[{"startOffset":212652,"endOffset":212776,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError$value","ranges":[{"startOffset":212800,"endOffset":212915,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError$range","ranges":[{"startOffset":212939,"endOffset":213100,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError_checkValueInInterval","ranges":[{"startOffset":213139,"endOffset":213328,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError_checkValidRange","ranges":[{"startOffset":213362,"endOffset":213728,"count":1},{"startOffset":213442,"endOffset":213518,"count":0},{"startOffset":213596,"endOffset":213672,"count":0},{"startOffset":213700,"endOffset":213727,"count":0}],"isBlockCoverage":true},{"functionName":"RangeError_checkNotNegative","ranges":[{"startOffset":213763,"endOffset":213959,"count":0}],"isBlockCoverage":false},{"functionName":"IndexError$","ranges":[{"startOffset":213978,"endOffset":214221,"count":0}],"isBlockCoverage":false},{"functionName":"UnsupportedError$","ranges":[{"startOffset":214246,"endOffset":214317,"count":0}],"isBlockCoverage":false},{"functionName":"UnimplementedError$","ranges":[{"startOffset":214344,"endOffset":214417,"count":0}],"isBlockCoverage":false},{"functionName":"StateError$","ranges":[{"startOffset":214436,"endOffset":214501,"count":0}],"isBlockCoverage":false},{"functionName":"ConcurrentModificationError$","ranges":[{"startOffset":214537,"endOffset":214633,"count":0}],"isBlockCoverage":false},{"functionName":"FormatException$","ranges":[{"startOffset":214657,"endOffset":214759,"count":0}],"isBlockCoverage":false},{"functionName":"List_List$generate","ranges":[{"startOffset":214785,"endOffset":215096,"count":1}],"isBlockCoverage":true},{"functionName":"Map_castFrom","ranges":[{"startOffset":215116,"endOffset":215276,"count":1}],"isBlockCoverage":true},{"functionName":"print","ranges":[{"startOffset":215289,"endOffset":215458,"count":0}],"isBlockCoverage":false},{"functionName":"_combineSurrogatePair","ranges":[{"startOffset":215487,"endOffset":215575,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_parse","ranges":[{"startOffset":215592,"endOffset":222061,"count":1},{"startOffset":216121,"endOffset":216228,"count":0},{"startOffset":216270,"endOffset":216359,"count":0},{"startOffset":216950,"endOffset":216995,"count":0},{"startOffset":217075,"endOffset":217098,"count":0},{"startOffset":217195,"endOffset":217218,"count":0},{"startOffset":217284,"endOffset":217301,"count":0},{"startOffset":217506,"endOffset":217533,"count":0},{"startOffset":217584,"endOffset":217609,"count":0},{"startOffset":217656,"endOffset":217683,"count":0},{"startOffset":217733,"endOffset":217756,"count":0},{"startOffset":217798,"endOffset":217821,"count":0},{"startOffset":217869,"endOffset":217895,"count":0},{"startOffset":217945,"endOffset":217968,"count":0},{"startOffset":218399,"endOffset":218415,"count":0},{"startOffset":218500,"endOffset":218565,"count":0},{"startOffset":218652,"endOffset":218723,"count":0},{"startOffset":218766,"endOffset":218797,"count":0},{"startOffset":218798,"endOffset":218839,"count":0},{"startOffset":218936,"endOffset":218978,"count":0},{"startOffset":218999,"endOffset":219076,"count":0},{"startOffset":219213,"endOffset":219911,"count":0},{"startOffset":219947,"endOffset":220222,"count":0},{"startOffset":220275,"endOffset":221412,"count":0},{"startOffset":221479,"endOffset":221514,"count":0},{"startOffset":221584,"endOffset":221802,"count":0},{"startOffset":221927,"endOffset":222060,"count":0}],"isBlockCoverage":true},{"functionName":"Uri_decodeComponent","ranges":[{"startOffset":222088,"endOffset":222270,"count":0}],"isBlockCoverage":false},{"functionName":"Uri__parseIPv4Address","ranges":[{"startOffset":222299,"endOffset":223833,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_parseIPv6Address","ranges":[{"startOffset":223861,"endOffset":226795,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__Uri$notSimple","ranges":[{"startOffset":226822,"endOffset":228163,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__Uri","ranges":[{"startOffset":228180,"endOffset":229390,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__defaultPort","ranges":[{"startOffset":229415,"endOffset":229553,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__fail","ranges":[{"startOffset":229571,"endOffset":229678,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__Uri$file","ranges":[{"startOffset":229700,"endOffset":229830,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__checkNonWindowsPathReservedCharacters","ranges":[{"startOffset":229881,"endOffset":230033,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__checkWindowsPathReservedCharacters","ranges":[{"startOffset":230081,"endOffset":230721,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__checkWindowsDriveLetter","ranges":[{"startOffset":230758,"endOffset":231242,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeFileUri","ranges":[{"startOffset":231267,"endOffset":231594,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeWindowsFileUrl","ranges":[{"startOffset":231626,"endOffset":234062,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makePort","ranges":[{"startOffset":234084,"endOffset":234218,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeHost","ranges":[{"startOffset":234240,"endOffset":235817,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__checkZoneID","ranges":[{"startOffset":235842,"endOffset":236000,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalizeZoneID","ranges":[{"startOffset":236029,"endOffset":238805,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalizeRegName","ranges":[{"startOffset":238835,"endOffset":242233,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeScheme","ranges":[{"startOffset":242257,"endOffset":243253,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__canonicalizeScheme","ranges":[{"startOffset":243285,"endOffset":243546,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeUserInfo","ranges":[{"startOffset":243572,"endOffset":243741,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makePath","ranges":[{"startOffset":243763,"endOffset":244818,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalizePath","ranges":[{"startOffset":244845,"endOffset":245122,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeQuery","ranges":[{"startOffset":245145,"endOffset":245323,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makeFragment","ranges":[{"startOffset":245349,"endOffset":245519,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalizeEscape","ranges":[{"startOffset":245548,"endOffset":246720,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__escapeChar","ranges":[{"startOffset":246744,"endOffset":248292,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalizeOrSubstring","ranges":[{"startOffset":248326,"endOffset":248566,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalize","ranges":[{"startOffset":248589,"endOffset":251311,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__mayContainDotSegments","ranges":[{"startOffset":251346,"endOffset":251505,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__removeDotSegments","ranges":[{"startOffset":251536,"endOffset":252526,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__normalizeRelativePath","ranges":[{"startOffset":252561,"endOffset":254222,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__escapeScheme","ranges":[{"startOffset":254248,"endOffset":254933,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__toWindowsFilePath","ranges":[{"startOffset":254964,"endOffset":255945,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__hexCharPairToByte","ranges":[{"startOffset":255976,"endOffset":256491,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__uriDecode","ranges":[{"startOffset":256514,"endOffset":258126,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__isAlphabeticCharacter","ranges":[{"startOffset":258161,"endOffset":258274,"count":0}],"isBlockCoverage":false},{"functionName":"UriData__writeUri","ranges":[{"startOffset":258299,"endOffset":258967,"count":0}],"isBlockCoverage":false},{"functionName":"UriData__validateMimeType","ranges":[{"startOffset":259000,"endOffset":259351,"count":0}],"isBlockCoverage":false},{"functionName":"UriData__parse","ranges":[{"startOffset":259373,"endOffset":261418,"count":0}],"isBlockCoverage":false},{"functionName":"UriData__uriEncodeBytes","ranges":[{"startOffset":261449,"endOffset":262927,"count":0}],"isBlockCoverage":false},{"functionName":"_createTables","ranges":[{"startOffset":262948,"endOffset":267507,"count":1}],"isBlockCoverage":true},{"functionName":"_scan","ranges":[{"startOffset":267520,"endOffset":268208,"count":1},{"startOffset":267816,"endOffset":267846,"count":0},{"startOffset":267957,"endOffset":267967,"count":0},{"startOffset":268012,"endOffset":268040,"count":0}],"isBlockCoverage":true},{"functionName":"bool","ranges":[{"startOffset":268220,"endOffset":268243,"count":0}],"isBlockCoverage":false},{"functionName":"DateTime","ranges":[{"startOffset":268259,"endOffset":268339,"count":0}],"isBlockCoverage":false},{"functionName":"double","ranges":[{"startOffset":268353,"endOffset":268378,"count":0}],"isBlockCoverage":false},{"functionName":"Duration","ranges":[{"startOffset":268394,"endOffset":268450,"count":1}],"isBlockCoverage":true},{"functionName":"Duration_toString_sixDigits","ranges":[{"startOffset":268485,"endOffset":268531,"count":0}],"isBlockCoverage":false},{"functionName":"Duration_toString_twoDigits","ranges":[{"startOffset":268566,"endOffset":268612,"count":0}],"isBlockCoverage":false},{"functionName":"Error","ranges":[{"startOffset":268625,"endOffset":268649,"count":0}],"isBlockCoverage":false},{"functionName":"AssertionError","ranges":[{"startOffset":268671,"endOffset":268731,"count":0}],"isBlockCoverage":false},{"functionName":"NullThrownError","ranges":[{"startOffset":268754,"endOffset":268788,"count":0}],"isBlockCoverage":false},{"functionName":"ArgumentError","ranges":[{"startOffset":268809,"endOffset":268967,"count":0}],"isBlockCoverage":false},{"functionName":"RangeError","ranges":[{"startOffset":268985,"endOffset":269186,"count":0}],"isBlockCoverage":false},{"functionName":"IndexError","ranges":[{"startOffset":269204,"endOffset":269384,"count":0}],"isBlockCoverage":false},{"functionName":"UnsupportedError","ranges":[{"startOffset":269408,"endOffset":269470,"count":0}],"isBlockCoverage":false},{"functionName":"UnimplementedError","ranges":[{"startOffset":269496,"endOffset":269560,"count":0}],"isBlockCoverage":false},{"functionName":"StateError","ranges":[{"startOffset":269578,"endOffset":269634,"count":0}],"isBlockCoverage":false},{"functionName":"ConcurrentModificationError","ranges":[{"startOffset":269669,"endOffset":269749,"count":0}],"isBlockCoverage":false},{"functionName":"OutOfMemoryError","ranges":[{"startOffset":269773,"endOffset":269808,"count":1}],"isBlockCoverage":true},{"functionName":"StackOverflowError","ranges":[{"startOffset":269834,"endOffset":269871,"count":0}],"isBlockCoverage":false},{"functionName":"CyclicInitializationError","ranges":[{"startOffset":269904,"endOffset":269980,"count":0}],"isBlockCoverage":false},{"functionName":"_Exception","ranges":[{"startOffset":269998,"endOffset":270054,"count":0}],"isBlockCoverage":false},{"functionName":"FormatException","ranges":[{"startOffset":270077,"endOffset":270194,"count":0}],"isBlockCoverage":false},{"functionName":"Expando","ranges":[{"startOffset":270209,"endOffset":270321,"count":1}],"isBlockCoverage":true},{"functionName":"Function","ranges":[{"startOffset":270337,"endOffset":270364,"count":0}],"isBlockCoverage":false},{"functionName":"int","ranges":[{"startOffset":270375,"endOffset":270397,"count":0}],"isBlockCoverage":false},{"functionName":"Iterable","ranges":[{"startOffset":270413,"endOffset":270440,"count":0}],"isBlockCoverage":false},{"functionName":"Iterator","ranges":[{"startOffset":270456,"endOffset":270483,"count":0}],"isBlockCoverage":false},{"functionName":"List","ranges":[{"startOffset":270495,"endOffset":270518,"count":0}],"isBlockCoverage":false},{"functionName":"Map","ranges":[{"startOffset":270529,"endOffset":270551,"count":0}],"isBlockCoverage":false},{"functionName":"MapEntry","ranges":[{"startOffset":270567,"endOffset":270669,"count":1}],"isBlockCoverage":true},{"functionName":"Null","ranges":[{"startOffset":270681,"endOffset":270704,"count":0}],"isBlockCoverage":false},{"functionName":"num","ranges":[{"startOffset":270715,"endOffset":270737,"count":0}],"isBlockCoverage":false},{"functionName":"Object","ranges":[{"startOffset":270751,"endOffset":270776,"count":1}],"isBlockCoverage":true},{"functionName":"Pattern","ranges":[{"startOffset":270791,"endOffset":270817,"count":0}],"isBlockCoverage":false},{"functionName":"Match","ranges":[{"startOffset":270830,"endOffset":270854,"count":0}],"isBlockCoverage":false},{"functionName":"RegExpMatch","ranges":[{"startOffset":270873,"endOffset":270903,"count":0}],"isBlockCoverage":false},{"functionName":"Set","ranges":[{"startOffset":270914,"endOffset":270936,"count":0}],"isBlockCoverage":false},{"functionName":"StackTrace","ranges":[{"startOffset":270954,"endOffset":270983,"count":0}],"isBlockCoverage":false},{"functionName":"_StringStackTrace","ranges":[{"startOffset":271008,"endOffset":271075,"count":0}],"isBlockCoverage":false},{"functionName":"Stopwatch","ranges":[{"startOffset":271092,"endOffset":271162,"count":0}],"isBlockCoverage":false},{"functionName":"String","ranges":[{"startOffset":271176,"endOffset":271201,"count":0}],"isBlockCoverage":false},{"functionName":"Runes","ranges":[{"startOffset":271214,"endOffset":271264,"count":0}],"isBlockCoverage":false},{"functionName":"RuneIterator","ranges":[{"startOffset":271284,"endOffset":271439,"count":0}],"isBlockCoverage":false},{"functionName":"StringBuffer","ranges":[{"startOffset":271459,"endOffset":271519,"count":0}],"isBlockCoverage":false},{"functionName":"Uri","ranges":[{"startOffset":271530,"endOffset":271552,"count":0}],"isBlockCoverage":false},{"functionName":"Uri__parseIPv4Address_error","ranges":[{"startOffset":271587,"endOffset":271657,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_parseIPv6Address_error","ranges":[{"startOffset":271691,"endOffset":271760,"count":0}],"isBlockCoverage":false},{"functionName":"Uri_parseIPv6Address_parseHex","ranges":[{"startOffset":271797,"endOffset":271896,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri","ranges":[{"startOffset":271908,"endOffset":272185,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__Uri$notSimple_closure","ranges":[{"startOffset":272220,"endOffset":272320,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__checkNonWindowsPathReservedCharacters_closure","ranges":[{"startOffset":272379,"endOffset":272482,"count":0}],"isBlockCoverage":false},{"functionName":"_Uri__makePath_closure","ranges":[{"startOffset":272512,"endOffset":272553,"count":0}],"isBlockCoverage":false},{"functionName":"UriData","ranges":[{"startOffset":272568,"endOffset":272689,"count":0}],"isBlockCoverage":false},{"functionName":"_createTables_closure","ranges":[{"startOffset":272718,"endOffset":272758,"count":1}],"isBlockCoverage":true},{"functionName":"_createTables_build","ranges":[{"startOffset":272785,"endOffset":272849,"count":1}],"isBlockCoverage":true},{"functionName":"_createTables_setChars","ranges":[{"startOffset":272879,"endOffset":272920,"count":1}],"isBlockCoverage":true},{"functionName":"_createTables_setRange","ranges":[{"startOffset":272950,"endOffset":272991,"count":1}],"isBlockCoverage":true},{"functionName":"_SimpleUri","ranges":[{"startOffset":273009,"endOffset":273320,"count":1}],"isBlockCoverage":true},{"functionName":"_DataUri","ranges":[{"startOffset":273336,"endOffset":273617,"count":0}],"isBlockCoverage":false},{"functionName":"_StructuredClone","ranges":[{"startOffset":273641,"endOffset":273676,"count":0}],"isBlockCoverage":false},{"functionName":"_StructuredClone_walk_closure","ranges":[{"startOffset":273713,"endOffset":273814,"count":1}],"isBlockCoverage":true},{"functionName":"_StructuredClone_walk_closure0","ranges":[{"startOffset":273852,"endOffset":273954,"count":0}],"isBlockCoverage":false},{"functionName":"_AcceptStructuredClone","ranges":[{"startOffset":273984,"endOffset":274025,"count":0}],"isBlockCoverage":false},{"functionName":"_AcceptStructuredClone_walk_closure","ranges":[{"startOffset":274068,"endOffset":274175,"count":1}],"isBlockCoverage":true},{"functionName":"_StructuredCloneDart2Js","ranges":[{"startOffset":274206,"endOffset":274302,"count":1}],"isBlockCoverage":true},{"functionName":"_AcceptStructuredCloneDart2Js","ranges":[{"startOffset":274339,"endOffset":274470,"count":1}],"isBlockCoverage":true},{"functionName":"_convertDataTree","ranges":[{"startOffset":274494,"endOffset":274639,"count":1}],"isBlockCoverage":true},{"functionName":"promiseToFuture","ranges":[{"startOffset":274662,"endOffset":275033,"count":0}],"isBlockCoverage":false},{"functionName":"_convertDataTree__convert","ranges":[{"startOffset":275066,"endOffset":275147,"count":1}],"isBlockCoverage":true},{"functionName":"promiseToFuture_closure","ranges":[{"startOffset":275178,"endOffset":275272,"count":0}],"isBlockCoverage":false},{"functionName":"promiseToFuture_closure0","ranges":[{"startOffset":275304,"endOffset":275376,"count":0}],"isBlockCoverage":false},{"functionName":"ByteBuffer","ranges":[{"startOffset":275394,"endOffset":275423,"count":0}],"isBlockCoverage":false},{"functionName":"ByteData","ranges":[{"startOffset":275439,"endOffset":275466,"count":0}],"isBlockCoverage":false},{"functionName":"Int8List","ranges":[{"startOffset":275482,"endOffset":275509,"count":0}],"isBlockCoverage":false},{"functionName":"Uint8List","ranges":[{"startOffset":275526,"endOffset":275554,"count":0}],"isBlockCoverage":false},{"functionName":"Uint8ClampedList","ranges":[{"startOffset":275578,"endOffset":275613,"count":0}],"isBlockCoverage":false},{"functionName":"Int16List","ranges":[{"startOffset":275630,"endOffset":275658,"count":0}],"isBlockCoverage":false},{"functionName":"Uint16List","ranges":[{"startOffset":275676,"endOffset":275705,"count":0}],"isBlockCoverage":false},{"functionName":"Int32List","ranges":[{"startOffset":275722,"endOffset":275750,"count":0}],"isBlockCoverage":false},{"functionName":"Uint32List","ranges":[{"startOffset":275768,"endOffset":275797,"count":0}],"isBlockCoverage":false},{"functionName":"Float32List","ranges":[{"startOffset":275816,"endOffset":275846,"count":0}],"isBlockCoverage":false},{"functionName":"Float64List","ranges":[{"startOffset":275865,"endOffset":275895,"count":0}],"isBlockCoverage":false},{"functionName":"SqlError","ranges":[{"startOffset":275911,"endOffset":275938,"count":0}],"isBlockCoverage":false},{"functionName":"max","ranges":[{"startOffset":275949,"endOffset":276119,"count":0}],"isBlockCoverage":false},{"functionName":"pow","ranges":[{"startOffset":276130,"endOffset":276195,"count":0}],"isBlockCoverage":false},{"functionName":"_EventStreamSubscription$","ranges":[{"startOffset":276240,"endOffset":276575,"count":1},{"startOffset":276327,"endOffset":276333,"count":0}],"isBlockCoverage":true},{"functionName":"_wrapZone","ranges":[{"startOffset":276592,"endOffset":276771,"count":1},{"startOffset":276705,"endOffset":276770,"count":0}],"isBlockCoverage":true},{"functionName":"ApplicationCacheErrorEvent","ranges":[{"startOffset":276805,"endOffset":276850,"count":0}],"isBlockCoverage":false},{"functionName":"Blob","ranges":[{"startOffset":276862,"endOffset":276885,"count":0}],"isBlockCoverage":false},{"functionName":"DomError","ranges":[{"startOffset":276901,"endOffset":276928,"count":0}],"isBlockCoverage":false},{"functionName":"DomException","ranges":[{"startOffset":276948,"endOffset":276979,"count":0}],"isBlockCoverage":false},{"functionName":"ErrorEvent","ranges":[{"startOffset":276997,"endOffset":277026,"count":0}],"isBlockCoverage":false},{"functionName":"Event","ranges":[{"startOffset":277039,"endOffset":277063,"count":0}],"isBlockCoverage":false},{"functionName":"EventTarget","ranges":[{"startOffset":277082,"endOffset":277112,"count":0}],"isBlockCoverage":false},{"functionName":"File","ranges":[{"startOffset":277124,"endOffset":277147,"count":0}],"isBlockCoverage":false},{"functionName":"Location","ranges":[{"startOffset":277163,"endOffset":277190,"count":0}],"isBlockCoverage":false},{"functionName":"MediaError","ranges":[{"startOffset":277208,"endOffset":277237,"count":0}],"isBlockCoverage":false},{"functionName":"MediaKeyMessageEvent","ranges":[{"startOffset":277265,"endOffset":277304,"count":0}],"isBlockCoverage":false},{"functionName":"MessageEvent","ranges":[{"startOffset":277324,"endOffset":277355,"count":0}],"isBlockCoverage":false},{"functionName":"MessagePort","ranges":[{"startOffset":277374,"endOffset":277404,"count":0}],"isBlockCoverage":false},{"functionName":"NavigatorUserMediaError","ranges":[{"startOffset":277435,"endOffset":277477,"count":0}],"isBlockCoverage":false},{"functionName":"OverconstrainedError","ranges":[{"startOffset":277505,"endOffset":277544,"count":0}],"isBlockCoverage":false},{"functionName":"PositionError","ranges":[{"startOffset":277565,"endOffset":277597,"count":0}],"isBlockCoverage":false},{"functionName":"PresentationConnectionCloseEvent","ranges":[{"startOffset":277637,"endOffset":277688,"count":0}],"isBlockCoverage":false},{"functionName":"SpeechRecognitionError","ranges":[{"startOffset":277718,"endOffset":277759,"count":0}],"isBlockCoverage":false},{"functionName":"EventStreamProvider","ranges":[{"startOffset":277786,"endOffset":277847,"count":0}],"isBlockCoverage":false},{"functionName":"_EventStream","ranges":[{"startOffset":277867,"endOffset":278029,"count":1}],"isBlockCoverage":true},{"functionName":"_EventStreamSubscription","ranges":[{"startOffset":278061,"endOffset":278292,"count":1}],"isBlockCoverage":true},{"functionName":"_EventStreamSubscription_closure","ranges":[{"startOffset":278332,"endOffset":278409,"count":1}],"isBlockCoverage":true},{"functionName":"AsyncMemoizer","ranges":[{"startOffset":278437,"endOffset":278540,"count":0}],"isBlockCoverage":false},{"functionName":"NullStreamSink","ranges":[{"startOffset":278558,"endOffset":278715,"count":0}],"isBlockCoverage":false},{"functionName":"NullStreamSink_addStream_closure","ranges":[{"startOffset":278751,"endOffset":278827,"count":0}],"isBlockCoverage":false},{"functionName":"Validator","ranges":[{"startOffset":278840,"endOffset":278898,"count":0}],"isBlockCoverage":false},{"functionName":"SpanScanner$","ranges":[{"startOffset":278918,"endOffset":279265,"count":0}],"isBlockCoverage":false},{"functionName":"SpanScanner","ranges":[{"startOffset":279284,"endOffset":279530,"count":0}],"isBlockCoverage":false},{"functionName":"_SpanScannerState","ranges":[{"startOffset":279555,"endOffset":279663,"count":0}],"isBlockCoverage":false},{"functionName":"RemoteListener_start","ranges":[{"startOffset":279691,"endOffset":280824,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__deserializeSet","ranges":[{"startOffset":280862,"endOffset":281054,"count":1},{"startOffset":280911,"endOffset":280923,"count":0},{"startOffset":280979,"endOffset":281053,"count":0}],"isBlockCoverage":true},{"functionName":"RemoteListener__sendLoadException","ranges":[{"startOffset":281095,"endOffset":281308,"count":0}],"isBlockCoverage":false},{"functionName":"RemoteListener__sendError","ranges":[{"startOffset":281341,"endOffset":281720,"count":0}],"isBlockCoverage":false},{"functionName":"RemoteListener","ranges":[{"startOffset":281742,"endOffset":281833,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start_closure","ranges":[{"startOffset":281869,"endOffset":281974,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start_closure0","ranges":[{"startOffset":282011,"endOffset":282059,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start_closure1","ranges":[{"startOffset":282096,"endOffset":282348,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start__closure","ranges":[{"startOffset":282385,"endOffset":282637,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start___closure","ranges":[{"startOffset":282675,"endOffset":282905,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start____closure","ranges":[{"startOffset":282944,"endOffset":283053,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start____closure0","ranges":[{"startOffset":283093,"endOffset":283229,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start_____closure","ranges":[{"startOffset":283269,"endOffset":283405,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener_start___closure0","ranges":[{"startOffset":283444,"endOffset":283549,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__serializeGroup_closure","ranges":[{"startOffset":283595,"endOffset":283734,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__serializeTest_closure","ranges":[{"startOffset":283779,"endOffset":283951,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__runLiveTest_closure","ranges":[{"startOffset":283994,"endOffset":284076,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__runLiveTest_closure0","ranges":[{"startOffset":284120,"endOffset":284202,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__runLiveTest_closure1","ranges":[{"startOffset":284246,"endOffset":284358,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__runLiveTest_closure2","ranges":[{"startOffset":284402,"endOffset":284511,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__runLiveTest_closure3","ranges":[{"startOffset":284555,"endOffset":284667,"count":1}],"isBlockCoverage":true},{"functionName":"RemoteListener__runLiveTest__closure","ranges":[{"startOffset":284711,"endOffset":284793,"count":1}],"isBlockCoverage":true},{"functionName":"DelegatingSink","ranges":[{"startOffset":284822,"endOffset":284911,"count":0}],"isBlockCoverage":false},{"functionName":"None","ranges":[{"startOffset":284919,"endOffset":284942,"count":1}],"isBlockCoverage":true},{"functionName":"Scanner","ranges":[{"startOffset":284953,"endOffset":285079,"count":0}],"isBlockCoverage":false},{"functionName":"EmptyUnmodifiableSet","ranges":[{"startOffset":285103,"endOffset":285165,"count":1}],"isBlockCoverage":true},{"functionName":"Style__getPlatformStyle","ranges":[{"startOffset":285196,"endOffset":285573,"count":0}],"isBlockCoverage":false},{"functionName":"Style","ranges":[{"startOffset":285586,"endOffset":285610,"count":0}],"isBlockCoverage":false},{"functionName":"Pool$","ranges":[{"startOffset":285623,"endOffset":286231,"count":0}],"isBlockCoverage":false},{"functionName":"Pool","ranges":[{"startOffset":286243,"endOffset":286547,"count":0}],"isBlockCoverage":false},{"functionName":"Pool_close_closure","ranges":[{"startOffset":286573,"endOffset":286635,"count":0}],"isBlockCoverage":false},{"functionName":"Pool__onResourceReleaseAllowed_closure","ranges":[{"startOffset":286681,"endOffset":286794,"count":0}],"isBlockCoverage":false},{"functionName":"Pool__runOnRelease_closure","ranges":[{"startOffset":286828,"endOffset":286898,"count":0}],"isBlockCoverage":false},{"functionName":"Pool__runOnRelease_closure0","ranges":[{"startOffset":286933,"endOffset":287004,"count":0}],"isBlockCoverage":false},{"functionName":"PoolResource","ranges":[{"startOffset":287024,"endOffset":287110,"count":0}],"isBlockCoverage":false},{"functionName":"mapStackTrace","ranges":[{"startOffset":287131,"endOffset":288220,"count":0}],"isBlockCoverage":false},{"functionName":"_prettifyMember","ranges":[{"startOffset":288243,"endOffset":289263,"count":0}],"isBlockCoverage":false},{"functionName":"mapStackTrace_closure","ranges":[{"startOffset":289292,"endOffset":289456,"count":0}],"isBlockCoverage":false},{"functionName":"mapStackTrace_closure0","ranges":[{"startOffset":289486,"endOffset":289676,"count":0}],"isBlockCoverage":false},{"functionName":"mapStackTrace_closure1","ranges":[{"startOffset":289706,"endOffset":289747,"count":0}],"isBlockCoverage":false},{"functionName":"_prettifyMember_closure","ranges":[{"startOffset":289778,"endOffset":289820,"count":0}],"isBlockCoverage":false},{"functionName":"_prettifyMember_closure0","ranges":[{"startOffset":289852,"endOffset":289895,"count":0}],"isBlockCoverage":false},{"functionName":"StackZoneSpecification","ranges":[{"startOffset":289925,"endOffset":290121,"count":1}],"isBlockCoverage":true},{"functionName":"StackZoneSpecification_chainFor_closure","ranges":[{"startOffset":290168,"endOffset":290252,"count":0}],"isBlockCoverage":false},{"functionName":"StackZoneSpecification_chainFor_closure0","ranges":[{"startOffset":290300,"endOffset":290414,"count":0}],"isBlockCoverage":false},{"functionName":"StackZoneSpecification__registerCallback_closure","ranges":[{"startOffset":290470,"endOffset":290642,"count":1}],"isBlockCoverage":true},{"functionName":"StackZoneSpecification__registerUnaryCallback_closure","ranges":[{"startOffset":290703,"endOffset":290900,"count":1}],"isBlockCoverage":true},{"functionName":"StackZoneSpecification__registerUnaryCallback__closure","ranges":[{"startOffset":290962,"endOffset":291104,"count":1}],"isBlockCoverage":true},{"functionName":"StackZoneSpecification__registerBinaryCallback_closure","ranges":[{"startOffset":291166,"endOffset":291386,"count":1}],"isBlockCoverage":true},{"functionName":"StackZoneSpecification__registerBinaryCallback__closure","ranges":[{"startOffset":291449,"endOffset":291627,"count":1}],"isBlockCoverage":true},{"functionName":"StackZoneSpecification__currentTrace_closure","ranges":[{"startOffset":291679,"endOffset":291827,"count":1}],"isBlockCoverage":true},{"functionName":"_Node","ranges":[{"startOffset":291840,"endOffset":291919,"count":1}],"isBlockCoverage":true},{"functionName":"Group$","ranges":[{"startOffset":291933,"endOffset":292150,"count":1}],"isBlockCoverage":true},{"functionName":"Group","ranges":[{"startOffset":292163,"endOffset":292362,"count":1}],"isBlockCoverage":true},{"functionName":"Group_forPlatform_closure","ranges":[{"startOffset":292395,"endOffset":292467,"count":1}],"isBlockCoverage":true},{"functionName":"Group__map_closure","ranges":[{"startOffset":292493,"endOffset":292558,"count":1}],"isBlockCoverage":true},{"functionName":"Group__map_closure0","ranges":[{"startOffset":292585,"endOffset":292623,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata__parseOnPlatform","ranges":[{"startOffset":292656,"endOffset":292775,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata__parseTags","ranges":[{"startOffset":292802,"endOffset":292889,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata_Metadata","ranges":[{"startOffset":292914,"endOffset":293928,"count":1},{"startOffset":293321,"endOffset":293340,"count":0},{"startOffset":293880,"endOffset":293927,"count":0}],"isBlockCoverage":true},{"functionName":"Metadata$_","ranges":[{"startOffset":293946,"endOffset":294846,"count":1},{"startOffset":294749,"endOffset":294795,"count":0}],"isBlockCoverage":true},{"functionName":"Metadata$parse","ranges":[{"startOffset":294868,"endOffset":295398,"count":1},{"startOffset":294999,"endOffset":295008,"count":0},{"startOffset":295061,"endOffset":295067,"count":0},{"startOffset":295301,"endOffset":295347,"count":0}],"isBlockCoverage":true},{"functionName":"Metadata$deserialize","ranges":[{"startOffset":295426,"endOffset":296886,"count":1},{"startOffset":295595,"endOffset":295675,"count":0},{"startOffset":296451,"endOffset":296672,"count":0}],"isBlockCoverage":true},{"functionName":"Metadata__deserializeTimeout","ranges":[{"startOffset":296922,"endOffset":297350,"count":1},{"startOffset":297058,"endOffset":297085,"count":0},{"startOffset":297241,"endOffset":297349,"count":0}],"isBlockCoverage":true},{"functionName":"Metadata","ranges":[{"startOffset":297366,"endOffset":297685,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata_Metadata__unresolved","ranges":[{"startOffset":297722,"endOffset":298035,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata_Metadata_closure","ranges":[{"startOffset":298068,"endOffset":298138,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata$deserialize_closure","ranges":[{"startOffset":298174,"endOffset":298221,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata__validateTags_closure","ranges":[{"startOffset":298259,"endOffset":298308,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata__validateTags_closure0","ranges":[{"startOffset":298347,"endOffset":298397,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata_validatePlatformSelectors_closure","ranges":[{"startOffset":298447,"endOffset":298542,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata_merge_closure","ranges":[{"startOffset":298572,"endOffset":298613,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata_merge_closure0","ranges":[{"startOffset":298644,"endOffset":298686,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata_forPlatform_closure","ranges":[{"startOffset":298722,"endOffset":298825,"count":0}],"isBlockCoverage":false},{"functionName":"Metadata_serialize_closure","ranges":[{"startOffset":298859,"endOffset":298944,"count":1}],"isBlockCoverage":true},{"functionName":"Metadata_serialize_closure0","ranges":[{"startOffset":298979,"endOffset":299025,"count":1}],"isBlockCoverage":true},{"functionName":"IterableSet","ranges":[{"startOffset":299044,"endOffset":299138,"count":0}],"isBlockCoverage":false},{"functionName":"_IterableSet_SetMixin_UnmodifiableSetMixin","ranges":[{"startOffset":299188,"endOffset":299249,"count":0}],"isBlockCoverage":false},{"functionName":"Engine$","ranges":[{"startOffset":299264,"endOffset":300874,"count":0}],"isBlockCoverage":false},{"functionName":"Engine","ranges":[{"startOffset":300888,"endOffset":301558,"count":0}],"isBlockCoverage":false},{"functionName":"Engine_success_closure","ranges":[{"startOffset":301588,"endOffset":301629,"count":0}],"isBlockCoverage":false},{"functionName":"Engine_closure","ranges":[{"startOffset":301651,"endOffset":301709,"count":0}],"isBlockCoverage":false},{"functionName":"Engine_closure0","ranges":[{"startOffset":301732,"endOffset":301766,"count":0}],"isBlockCoverage":false},{"functionName":"Engine_run_closure","ranges":[{"startOffset":301792,"endOffset":301854,"count":0}],"isBlockCoverage":false},{"functionName":"Engine_run__closure","ranges":[{"startOffset":301881,"endOffset":301971,"count":0}],"isBlockCoverage":false},{"functionName":"Engine_run___closure","ranges":[{"startOffset":301999,"endOffset":302125,"count":0}],"isBlockCoverage":false},{"functionName":"Engine_run____closure","ranges":[{"startOffset":302154,"endOffset":302220,"count":0}],"isBlockCoverage":false},{"functionName":"Engine_run_closure0","ranges":[{"startOffset":302247,"endOffset":302338,"count":0}],"isBlockCoverage":false},{"functionName":"Engine__runLiveTest_closure","ranges":[{"startOffset":302373,"endOffset":302474,"count":0}],"isBlockCoverage":false},{"functionName":"Engine__runLiveTest_closure0","ranges":[{"startOffset":302510,"endOffset":302610,"count":0}],"isBlockCoverage":false},{"functionName":"Engine__runLiveTest_closure1","ranges":[{"startOffset":302646,"endOffset":302693,"count":0}],"isBlockCoverage":false},{"functionName":"Engine__runSkippedTest_closure","ranges":[{"startOffset":302731,"endOffset":302780,"count":0}],"isBlockCoverage":false},{"functionName":"Engine__runSkippedTest_closure0","ranges":[{"startOffset":302819,"endOffset":302924,"count":0}],"isBlockCoverage":false},{"functionName":"Engine__runSkippedTest_closure1","ranges":[{"startOffset":302963,"endOffset":303013,"count":0}],"isBlockCoverage":false},{"functionName":"binarySearch","ranges":[{"startOffset":303033,"endOffset":303712,"count":0}],"isBlockCoverage":false},{"functionName":"DelegatingStreamSubscription","ranges":[{"startOffset":303755,"endOffset":303802,"count":0}],"isBlockCoverage":false},{"functionName":"StreamCompleter","ranges":[{"startOffset":303821,"endOffset":303907,"count":1}],"isBlockCoverage":true},{"functionName":"_CompleterStream","ranges":[{"startOffset":303927,"endOffset":304055,"count":1}],"isBlockCoverage":true},{"functionName":"BooleanSelectorImpl","ranges":[{"startOffset":304078,"endOffset":304145,"count":0}],"isBlockCoverage":false},{"functionName":"mapMap","ranges":[{"startOffset":304159,"endOffset":304498,"count":1}],"isBlockCoverage":true},{"functionName":"mergeMaps","ranges":[{"startOffset":304515,"endOffset":304721,"count":1}],"isBlockCoverage":true},{"functionName":"mapMap_closure","ranges":[{"startOffset":304743,"endOffset":304846,"count":1}],"isBlockCoverage":true},{"functionName":"mapMap_closure0","ranges":[{"startOffset":304869,"endOffset":305013,"count":1}],"isBlockCoverage":true},{"functionName":"mergeMaps_closure","ranges":[{"startOffset":305038,"endOffset":305181,"count":1}],"isBlockCoverage":true},{"functionName":"UnionSetController$","ranges":[{"startOffset":305208,"endOffset":305497,"count":0}],"isBlockCoverage":false},{"functionName":"UnionSetController","ranges":[{"startOffset":305523,"endOffset":305678,"count":0}],"isBlockCoverage":false},{"functionName":"_IsTrue","ranges":[{"startOffset":305693,"endOffset":305719,"count":1}],"isBlockCoverage":true},{"functionName":"_Predicate","ranges":[{"startOffset":305737,"endOffset":305868,"count":0}],"isBlockCoverage":false},{"functionName":"FileLocation$_","ranges":[{"startOffset":305890,"endOffset":306294,"count":0}],"isBlockCoverage":false},{"functionName":"_FileSpan$","ranges":[{"startOffset":306312,"endOffset":306850,"count":0}],"isBlockCoverage":false},{"functionName":"SourceFile","ranges":[{"startOffset":306868,"endOffset":307027,"count":0}],"isBlockCoverage":false},{"functionName":"FileLocation","ranges":[{"startOffset":307047,"endOffset":307130,"count":0}],"isBlockCoverage":false},{"functionName":"_FileSpan","ranges":[{"startOffset":307147,"endOffset":307265,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpanMixin","ranges":[{"startOffset":307288,"endOffset":307322,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_Trace$current","ranges":[{"startOffset":307349,"endOffset":307488,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_Trace$from","ranges":[{"startOffset":307512,"endOffset":307838,"count":1},{"startOffset":307563,"endOffset":307639,"count":0},{"startOffset":307695,"endOffset":307837,"count":0}],"isBlockCoverage":true},{"functionName":"Trace_Trace$parse","ranges":[{"startOffset":307863,"endOffset":309377,"count":0}],"isBlockCoverage":false},{"functionName":"Trace__parseVM","ranges":[{"startOffset":309399,"endOffset":310090,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseV8","ranges":[{"startOffset":310111,"endOffset":310662,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseJSCore","ranges":[{"startOffset":310687,"endOffset":311118,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFirefox","ranges":[{"startOffset":311144,"endOffset":311604,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFriendly","ranges":[{"startOffset":311631,"endOffset":312181,"count":0}],"isBlockCoverage":false},{"functionName":"Trace","ranges":[{"startOffset":312194,"endOffset":312274,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_Trace$current_closure","ranges":[{"startOffset":312309,"endOffset":312407,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_Trace$from_closure","ranges":[{"startOffset":312439,"endOffset":312507,"count":0}],"isBlockCoverage":false},{"functionName":"Trace__parseVM_closure","ranges":[{"startOffset":312537,"endOffset":312578,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseV8_closure","ranges":[{"startOffset":312607,"endOffset":312647,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseV8_closure0","ranges":[{"startOffset":312677,"endOffset":312718,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseJSCore_closure","ranges":[{"startOffset":312751,"endOffset":312795,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseJSCore_closure0","ranges":[{"startOffset":312829,"endOffset":312874,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFirefox_closure","ranges":[{"startOffset":312908,"endOffset":312953,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFirefox_closure0","ranges":[{"startOffset":312988,"endOffset":313034,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFriendly_closure","ranges":[{"startOffset":313069,"endOffset":313115,"count":0}],"isBlockCoverage":false},{"functionName":"Trace$parseFriendly_closure0","ranges":[{"startOffset":313151,"endOffset":313198,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_foldFrames_closure","ranges":[{"startOffset":313230,"endOffset":313305,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_foldFrames_closure0","ranges":[{"startOffset":313338,"endOffset":313408,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_toString_closure0","ranges":[{"startOffset":313439,"endOffset":313481,"count":0}],"isBlockCoverage":false},{"functionName":"Trace_toString_closure","ranges":[{"startOffset":313511,"endOffset":313579,"count":0}],"isBlockCoverage":false},{"functionName":"RunnerSuite","ranges":[{"startOffset":313598,"endOffset":313764,"count":0}],"isBlockCoverage":false},{"functionName":"RunnerSuiteController","ranges":[{"startOffset":313793,"endOffset":314020,"count":0}],"isBlockCoverage":false},{"functionName":"RunnerSuiteController__close_closure","ranges":[{"startOffset":314064,"endOffset":314144,"count":0}],"isBlockCoverage":false},{"functionName":"FutureGroup","ranges":[{"startOffset":314170,"endOffset":314384,"count":0}],"isBlockCoverage":false},{"functionName":"FutureGroup_add_closure","ranges":[{"startOffset":314411,"endOffset":314505,"count":0}],"isBlockCoverage":false},{"functionName":"FutureGroup_add_closure0","ranges":[{"startOffset":314533,"endOffset":314601,"count":0}],"isBlockCoverage":false},{"functionName":"ValueResult","ranges":[{"startOffset":314616,"endOffset":314696,"count":1}],"isBlockCoverage":true},{"functionName":"PackageConfigResolver__normalizeMap","ranges":[{"startOffset":314739,"endOffset":314975,"count":1}],"isBlockCoverage":true},{"functionName":"PackageConfigResolver","ranges":[{"startOffset":315004,"endOffset":315080,"count":1}],"isBlockCoverage":true},{"functionName":"PackageConfigResolver__normalizeMap_closure","ranges":[{"startOffset":315131,"endOffset":315193,"count":1}],"isBlockCoverage":true},{"functionName":"UrlStyle","ranges":[{"startOffset":315209,"endOffset":315397,"count":0}],"isBlockCoverage":false},{"functionName":"ErrorResult","ranges":[{"startOffset":315423,"endOffset":315510,"count":0}],"isBlockCoverage":false},{"functionName":"SourceLocation$","ranges":[{"startOffset":315533,"endOffset":316255,"count":0}],"isBlockCoverage":false},{"functionName":"SourceLocation","ranges":[{"startOffset":316277,"endOffset":316429,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpan","ranges":[{"startOffset":316447,"endOffset":316476,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpanBase","ranges":[{"startOffset":316498,"endOffset":316531,"count":0}],"isBlockCoverage":false},{"functionName":"GroupEntry","ranges":[{"startOffset":316549,"endOffset":316578,"count":0}],"isBlockCoverage":false},{"functionName":"LiveTestController$","ranges":[{"startOffset":316605,"endOffset":317396,"count":1}],"isBlockCoverage":true},{"functionName":"_LiveTest","ranges":[{"startOffset":317413,"endOffset":317494,"count":1}],"isBlockCoverage":true},{"functionName":"LiveTestController","ranges":[{"startOffset":317520,"endOffset":318000,"count":1}],"isBlockCoverage":true},{"functionName":"Test","ranges":[{"startOffset":318012,"endOffset":318035,"count":0}],"isBlockCoverage":false},{"functionName":"errorsDontStopTest","ranges":[{"startOffset":318061,"endOffset":318525,"count":0}],"isBlockCoverage":false},{"functionName":"errorsDontStopTest_closure","ranges":[{"startOffset":318559,"endOffset":318659,"count":0}],"isBlockCoverage":false},{"functionName":"errorsDontStopTest_closure0","ranges":[{"startOffset":318694,"endOffset":318740,"count":0}],"isBlockCoverage":false},{"functionName":"Result","ranges":[{"startOffset":318761,"endOffset":318786,"count":0}],"isBlockCoverage":false},{"functionName":"StringDescription","ranges":[{"startOffset":318807,"endOffset":318867,"count":0}],"isBlockCoverage":false},{"functionName":"FeatureMatcher","ranges":[{"startOffset":318885,"endOffset":318918,"count":0}],"isBlockCoverage":false},{"functionName":"PosixStyle","ranges":[{"startOffset":318932,"endOffset":319073,"count":0}],"isBlockCoverage":false},{"functionName":"StringScannerException$","ranges":[{"startOffset":319104,"endOffset":319201,"count":0}],"isBlockCoverage":false},{"functionName":"StringScannerException","ranges":[{"startOffset":319231,"endOffset":319359,"count":0}],"isBlockCoverage":false},{"functionName":"PlatformSelector$parse","ranges":[{"startOffset":319389,"endOffset":319570,"count":0}],"isBlockCoverage":false},{"functionName":"PlatformSelector__wrapFormatException","ranges":[{"startOffset":319615,"endOffset":319694,"count":0}],"isBlockCoverage":false},{"functionName":"PlatformSelector","ranges":[{"startOffset":319718,"endOffset":319798,"count":1}],"isBlockCoverage":true},{"functionName":"PlatformSelector$parse_closure","ranges":[{"startOffset":319836,"endOffset":319913,"count":0}],"isBlockCoverage":false},{"functionName":"PlatformSelector_validate_closure","ranges":[{"startOffset":319954,"endOffset":320067,"count":0}],"isBlockCoverage":false},{"functionName":"PlatformSelector_validate__closure","ranges":[{"startOffset":320109,"endOffset":320196,"count":0}],"isBlockCoverage":false},{"functionName":"PlatformSelector_evaluate_closure","ranges":[{"startOffset":320237,"endOffset":320317,"count":1}],"isBlockCoverage":true},{"functionName":"SuitePlatform$","ranges":[{"startOffset":320339,"endOffset":320703,"count":1},{"startOffset":320429,"endOffset":320433,"count":0},{"startOffset":320533,"endOffset":320640,"count":0}],"isBlockCoverage":true},{"functionName":"SuitePlatform","ranges":[{"startOffset":320724,"endOffset":320837,"count":1}],"isBlockCoverage":true},{"functionName":"StackTraceMapper","ranges":[{"startOffset":320861,"endOffset":320896,"count":0}],"isBlockCoverage":false},{"functionName":"LiveSuite","ranges":[{"startOffset":320913,"endOffset":320941,"count":0}],"isBlockCoverage":false},{"functionName":"JSStackTraceMapper_deserialize","ranges":[{"startOffset":320979,"endOffset":321921,"count":1},{"startOffset":321375,"endOffset":321508,"count":0}],"isBlockCoverage":true},{"functionName":"JSStackTraceMapper__deserializePackageConfigMap","ranges":[{"startOffset":321976,"endOffset":322130,"count":1}],"isBlockCoverage":true},{"functionName":"JSStackTraceMapper","ranges":[{"startOffset":322156,"endOffset":322355,"count":1}],"isBlockCoverage":true},{"functionName":"JSStackTraceMapper__deserializePackageConfigMap_closure","ranges":[{"startOffset":322418,"endOffset":322492,"count":1}],"isBlockCoverage":true},{"functionName":"StreamGroup","ranges":[{"startOffset":322518,"endOffset":322755,"count":0}],"isBlockCoverage":false},{"functionName":"StreamGroup_add_closure","ranges":[{"startOffset":322782,"endOffset":322824,"count":0}],"isBlockCoverage":false},{"functionName":"StreamGroup_add_closure0","ranges":[{"startOffset":322852,"endOffset":322948,"count":0}],"isBlockCoverage":false},{"functionName":"StreamGroup__onListen_closure","ranges":[{"startOffset":322981,"endOffset":323054,"count":0}],"isBlockCoverage":false},{"functionName":"StreamGroup__onCancelBroadcast_closure","ranges":[{"startOffset":323096,"endOffset":323178,"count":0}],"isBlockCoverage":false},{"functionName":"StreamGroup__listenToStream_closure","ranges":[{"startOffset":323217,"endOffset":323324,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamGroupState","ranges":[{"startOffset":323345,"endOffset":323405,"count":1}],"isBlockCoverage":true},{"functionName":"Token","ranges":[{"startOffset":323414,"endOffset":323488,"count":0}],"isBlockCoverage":false},{"functionName":"IdentifierToken","ranges":[{"startOffset":323507,"endOffset":323591,"count":0}],"isBlockCoverage":false},{"functionName":"TokenType","ranges":[{"startOffset":323604,"endOffset":323656,"count":1}],"isBlockCoverage":true},{"functionName":"UnmodifiableSetView$","ranges":[{"startOffset":323684,"endOffset":323800,"count":0}],"isBlockCoverage":false},{"functionName":"UnmodifiableSetView","ranges":[{"startOffset":323827,"endOffset":323915,"count":1}],"isBlockCoverage":true},{"functionName":"UnmodifiableSetMixin","ranges":[{"startOffset":323943,"endOffset":323982,"count":0}],"isBlockCoverage":false},{"functionName":"_UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin","ranges":[{"startOffset":324045,"endOffset":324119,"count":0}],"isBlockCoverage":false},{"functionName":"WindowsStyle","ranges":[{"startOffset":324139,"endOffset":324331,"count":0}],"isBlockCoverage":false},{"functionName":"WindowsStyle_absolutePathToUri_closure","ranges":[{"startOffset":324377,"endOffset":324434,"count":0}],"isBlockCoverage":false},{"functionName":"decodeVlq","ranges":[{"startOffset":324451,"endOffset":325682,"count":0}],"isBlockCoverage":false},{"functionName":"closure","ranges":[{"startOffset":325697,"endOffset":325723,"count":0}],"isBlockCoverage":false},{"functionName":"internalBootstrapBrowserTest","ranges":[{"startOffset":325759,"endOffset":326211,"count":1}],"isBlockCoverage":true},{"functionName":"internalBootstrapBrowserTest_closure","ranges":[{"startOffset":326255,"endOffset":326310,"count":1}],"isBlockCoverage":true},{"functionName":"StreamQueue","ranges":[{"startOffset":326336,"endOffset":326620,"count":1}],"isBlockCoverage":true},{"functionName":"StreamQueue__ensureListening_closure","ranges":[{"startOffset":326660,"endOffset":326740,"count":1}],"isBlockCoverage":true},{"functionName":"StreamQueue__ensureListening_closure1","ranges":[{"startOffset":326781,"endOffset":326862,"count":1}],"isBlockCoverage":true},{"functionName":"StreamQueue__ensureListening_closure0","ranges":[{"startOffset":326903,"endOffset":326984,"count":1}],"isBlockCoverage":true},{"functionName":"_EventRequest","ranges":[{"startOffset":327001,"endOffset":327033,"count":0}],"isBlockCoverage":false},{"functionName":"_NextRequest","ranges":[{"startOffset":327049,"endOffset":327135,"count":1}],"isBlockCoverage":true},{"functionName":"_RestRequest","ranges":[{"startOffset":327151,"endOffset":327271,"count":1}],"isBlockCoverage":true},{"functionName":"Parser","ranges":[{"startOffset":327281,"endOffset":327343,"count":0}],"isBlockCoverage":false},{"functionName":"Matcher","ranges":[{"startOffset":327354,"endOffset":327380,"count":0}],"isBlockCoverage":false},{"functionName":"SourceMapSpan","ranges":[{"startOffset":327397,"endOffset":327547,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpanFormatException$","ranges":[{"startOffset":327581,"endOffset":327682,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpanException","ranges":[{"startOffset":327709,"endOffset":327747,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpanFormatException","ranges":[{"startOffset":327780,"endOffset":327911,"count":0}],"isBlockCoverage":false},{"functionName":"State","ranges":[{"startOffset":327924,"endOffset":328002,"count":1}],"isBlockCoverage":true},{"functionName":"Status","ranges":[{"startOffset":328016,"endOffset":328065,"count":1}],"isBlockCoverage":true},{"functionName":"Result0","ranges":[{"startOffset":328080,"endOffset":328130,"count":1}],"isBlockCoverage":true},{"functionName":"expect","ranges":[{"startOffset":328144,"endOffset":328244,"count":1}],"isBlockCoverage":true},{"functionName":"_expect","ranges":[{"startOffset":328259,"endOffset":329408,"count":1},{"startOffset":328467,"endOffset":328550,"count":0},{"startOffset":328759,"endOffset":328803,"count":0},{"startOffset":329097,"endOffset":329407,"count":0}],"isBlockCoverage":true},{"functionName":"fail","ranges":[{"startOffset":329420,"endOffset":329505,"count":0}],"isBlockCoverage":false},{"functionName":"formatFailure","ranges":[{"startOffset":329526,"endOffset":330135,"count":0}],"isBlockCoverage":false},{"functionName":"TestFailure","ranges":[{"startOffset":330154,"endOffset":330211,"count":0}],"isBlockCoverage":false},{"functionName":"_expect_closure0","ranges":[{"startOffset":330235,"endOffset":330270,"count":0}],"isBlockCoverage":false},{"functionName":"_expect_closure","ranges":[{"startOffset":330293,"endOffset":330327,"count":1}],"isBlockCoverage":true},{"functionName":"method1","ranges":[{"startOffset":330342,"endOffset":330388,"count":1}],"isBlockCoverage":true},{"functionName":"method2","ranges":[{"startOffset":330403,"endOffset":330449,"count":0}],"isBlockCoverage":false},{"functionName":"main0","ranges":[{"startOffset":330462,"endOffset":330529,"count":1}],"isBlockCoverage":true},{"functionName":"main_closure0","ranges":[{"startOffset":330550,"endOffset":330582,"count":1}],"isBlockCoverage":true},{"functionName":"main__closure","ranges":[{"startOffset":330603,"endOffset":330635,"count":1}],"isBlockCoverage":true},{"functionName":"StreamSinkCompleter","ranges":[{"startOffset":330669,"endOffset":330756,"count":1}],"isBlockCoverage":true},{"functionName":"_CompleterSink","ranges":[{"startOffset":330774,"endOffset":330961,"count":1}],"isBlockCoverage":true},{"functionName":"_CompleterSink__setDestinationSink_closure","ranges":[{"startOffset":331007,"endOffset":331068,"count":0}],"isBlockCoverage":false},{"functionName":"SubscriptionStream","ranges":[{"startOffset":331090,"endOffset":331200,"count":1}],"isBlockCoverage":true},{"functionName":"_CancelOnErrorSubscriptionWrapper","ranges":[{"startOffset":331237,"endOffset":331362,"count":0}],"isBlockCoverage":false},{"functionName":"_CancelOnErrorSubscriptionWrapper_onError_closure","ranges":[{"startOffset":331415,"endOffset":331541,"count":0}],"isBlockCoverage":false},{"functionName":"_CancelOnErrorSubscriptionWrapper_onError__closure","ranges":[{"startOffset":331595,"endOffset":331754,"count":0}],"isBlockCoverage":false},{"functionName":"Evaluator","ranges":[{"startOffset":331767,"endOffset":331825,"count":0}],"isBlockCoverage":false},{"functionName":"parseJsonExtended","ranges":[{"startOffset":331850,"endOffset":332085,"count":0}],"isBlockCoverage":false},{"functionName":"parseJson","ranges":[{"startOffset":332102,"endOffset":332830,"count":0}],"isBlockCoverage":false},{"functionName":"MultiSectionMapping$fromJson","ranges":[{"startOffset":332866,"endOffset":333186,"count":0}],"isBlockCoverage":false},{"functionName":"MappingBundle$fromJson","ranges":[{"startOffset":333216,"endOffset":333428,"count":0}],"isBlockCoverage":false},{"functionName":"SingleMapping$fromJson","ranges":[{"startOffset":333458,"endOffset":334453,"count":0}],"isBlockCoverage":false},{"functionName":"Mapping","ranges":[{"startOffset":334468,"endOffset":334494,"count":0}],"isBlockCoverage":false},{"functionName":"MultiSectionMapping","ranges":[{"startOffset":334521,"endOffset":334650,"count":0}],"isBlockCoverage":false},{"functionName":"MappingBundle","ranges":[{"startOffset":334671,"endOffset":334732,"count":0}],"isBlockCoverage":false},{"functionName":"SingleMapping","ranges":[{"startOffset":334753,"endOffset":335018,"count":0}],"isBlockCoverage":false},{"functionName":"SingleMapping$fromJson_closure","ranges":[{"startOffset":335056,"endOffset":335130,"count":0}],"isBlockCoverage":false},{"functionName":"SingleMapping__findLine_closure","ranges":[{"startOffset":335169,"endOffset":335243,"count":0}],"isBlockCoverage":false},{"functionName":"SingleMapping__findColumn_closure","ranges":[{"startOffset":335284,"endOffset":335362,"count":0}],"isBlockCoverage":false},{"functionName":"TargetLineEntry","ranges":[{"startOffset":335385,"endOffset":335472,"count":0}],"isBlockCoverage":false},{"functionName":"TargetEntry","ranges":[{"startOffset":335491,"endOffset":335685,"count":0}],"isBlockCoverage":false},{"functionName":"_MappingTokenizer","ranges":[{"startOffset":335710,"endOffset":335835,"count":0}],"isBlockCoverage":false},{"functionName":"_TokenKind","ranges":[{"startOffset":335853,"endOffset":335972,"count":1}],"isBlockCoverage":true},{"functionName":"LazyTrace","ranges":[{"startOffset":335989,"endOffset":336093,"count":1}],"isBlockCoverage":true},{"functionName":"LazyTrace_foldFrames_closure","ranges":[{"startOffset":336129,"endOffset":336259,"count":0}],"isBlockCoverage":false},{"functionName":"RuntimeSelection","ranges":[{"startOffset":336283,"endOffset":336318,"count":0}],"isBlockCoverage":false},{"functionName":"BooleanSelector","ranges":[{"startOffset":336348,"endOffset":336382,"count":0}],"isBlockCoverage":false},{"functionName":"All","ranges":[{"startOffset":336389,"endOffset":336411,"count":1}],"isBlockCoverage":true},{"functionName":"ParsedPath_ParsedPath$parse","ranges":[{"startOffset":336446,"endOffset":337648,"count":0}],"isBlockCoverage":false},{"functionName":"ParsedPath","ranges":[{"startOffset":337666,"endOffset":337813,"count":0}],"isBlockCoverage":false},{"functionName":"ParsedPath_normalize_closure","ranges":[{"startOffset":337849,"endOffset":337921,"count":0}],"isBlockCoverage":false},{"functionName":"PathException$","ranges":[{"startOffset":337943,"endOffset":338011,"count":0}],"isBlockCoverage":false},{"functionName":"PathException","ranges":[{"startOffset":338032,"endOffset":338091,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpanWithContext$","ranges":[{"startOffset":338121,"endOffset":338709,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpanWithContext","ranges":[{"startOffset":338738,"endOffset":338892,"count":0}],"isBlockCoverage":false},{"functionName":"LazyChain","ranges":[{"startOffset":338909,"endOffset":339001,"count":0}],"isBlockCoverage":false},{"functionName":"LazyChain_foldFrames_closure","ranges":[{"startOffset":339037,"endOffset":339167,"count":0}],"isBlockCoverage":false},{"functionName":"LazyChain_toTrace_closure","ranges":[{"startOffset":339200,"endOffset":339269,"count":0}],"isBlockCoverage":false},{"functionName":"StringScanner","ranges":[{"startOffset":339290,"endOffset":339322,"count":0}],"isBlockCoverage":false},{"functionName":"Declarer$","ranges":[{"startOffset":339339,"endOffset":340044,"count":1},{"startOffset":339457,"endOffset":339548,"count":0},{"startOffset":339600,"endOffset":339626,"count":0}],"isBlockCoverage":true},{"functionName":"Declarer","ranges":[{"startOffset":340060,"endOffset":340568,"count":1}],"isBlockCoverage":true},{"functionName":"Declarer_test_closure","ranges":[{"startOffset":340597,"endOffset":340688,"count":1}],"isBlockCoverage":true},{"functionName":"Declarer_test__closure","ranges":[{"startOffset":340718,"endOffset":340810,"count":1}],"isBlockCoverage":true},{"functionName":"Declarer_test___closure","ranges":[{"startOffset":340841,"endOffset":340934,"count":1}],"isBlockCoverage":true},{"functionName":"Declarer_group_closure","ranges":[{"startOffset":340964,"endOffset":341029,"count":1}],"isBlockCoverage":true},{"functionName":"Declarer_build_closure","ranges":[{"startOffset":341059,"endOffset":341125,"count":1}],"isBlockCoverage":true},{"functionName":"Declarer__runSetUps_closure","ranges":[{"startOffset":341160,"endOffset":341206,"count":1}],"isBlockCoverage":true},{"functionName":"Declarer__tearDownAll_closure","ranges":[{"startOffset":341243,"endOffset":341316,"count":0}],"isBlockCoverage":false},{"functionName":"Declarer__tearDownAll__closure","ranges":[{"startOffset":341354,"endOffset":341428,"count":0}],"isBlockCoverage":false},{"functionName":"Declarer__tearDownAll___closure","ranges":[{"startOffset":341467,"endOffset":341542,"count":0}],"isBlockCoverage":false},{"functionName":"PrintSink","ranges":[{"startOffset":341559,"endOffset":341626,"count":0}],"isBlockCoverage":false},{"functionName":"_expandSafe","ranges":[{"startOffset":341657,"endOffset":341839,"count":0}],"isBlockCoverage":false},{"functionName":"VariableNode","ranges":[{"startOffset":341859,"endOffset":341940,"count":0}],"isBlockCoverage":false},{"functionName":"NotNode","ranges":[{"startOffset":341955,"endOffset":342032,"count":0}],"isBlockCoverage":false},{"functionName":"OrNode","ranges":[{"startOffset":342046,"endOffset":342122,"count":0}],"isBlockCoverage":false},{"functionName":"AndNode","ranges":[{"startOffset":342137,"endOffset":342214,"count":0}],"isBlockCoverage":false},{"functionName":"ConditionalNode","ranges":[{"startOffset":342237,"endOffset":342361,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__normalizeNewlines","ranges":[{"startOffset":342399,"endOffset":343195,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__normalizeTrailingNewline","ranges":[{"startOffset":343240,"endOffset":344711,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__normalizeEndOfLine","ranges":[{"startOffset":344750,"endOffset":345414,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__lastLineLength","ranges":[{"startOffset":345449,"endOffset":345775,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter","ranges":[{"startOffset":345794,"endOffset":345999,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeFirstLine_closure","ranges":[{"startOffset":346042,"endOffset":346147,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeFirstLine_closure0","ranges":[{"startOffset":346191,"endOffset":346303,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeFirstLine_closure1","ranges":[{"startOffset":346347,"endOffset":346455,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeFirstLine_closure2","ranges":[{"startOffset":346499,"endOffset":346607,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeIntermediateLines_closure","ranges":[{"startOffset":346658,"endOffset":346771,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeLastLine_closure","ranges":[{"startOffset":346813,"endOffset":346917,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeLastLine_closure0","ranges":[{"startOffset":346960,"endOffset":347071,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeLastLine_closure1","ranges":[{"startOffset":347114,"endOffset":347221,"count":0}],"isBlockCoverage":false},{"functionName":"Highlighter__writeSidebar_closure","ranges":[{"startOffset":347262,"endOffset":347390,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_capture","ranges":[{"startOffset":347411,"endOffset":348428,"count":1},{"startOffset":347512,"endOffset":347565,"count":0},{"startOffset":347633,"endOffset":347760,"count":0}],"isBlockCoverage":true},{"functionName":"Chain_Chain$current","ranges":[{"startOffset":348455,"endOffset":348942,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_Chain$forTrace","ranges":[{"startOffset":348970,"endOffset":349524,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_Chain$parse","ranges":[{"startOffset":349549,"endOffset":350621,"count":0}],"isBlockCoverage":false},{"functionName":"Chain","ranges":[{"startOffset":350634,"endOffset":350684,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_capture_closure","ranges":[{"startOffset":350713,"endOffset":350804,"count":1}],"isBlockCoverage":true},{"functionName":"Chain_Chain$current_closure","ranges":[{"startOffset":350839,"endOffset":350937,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_Chain$forTrace_closure","ranges":[{"startOffset":350973,"endOffset":351045,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_Chain$parse_closure","ranges":[{"startOffset":351078,"endOffset":351122,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_Chain$parse_closure0","ranges":[{"startOffset":351156,"endOffset":351201,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_foldFrames_closure","ranges":[{"startOffset":351233,"endOffset":351332,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_foldFrames_closure0","ranges":[{"startOffset":351365,"endOffset":351434,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toTrace_closure","ranges":[{"startOffset":351463,"endOffset":351503,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toString_closure0","ranges":[{"startOffset":351534,"endOffset":351576,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toString__closure0","ranges":[{"startOffset":351608,"endOffset":351651,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toString_closure","ranges":[{"startOffset":351681,"endOffset":351749,"count":0}],"isBlockCoverage":false},{"functionName":"Chain_toString__closure","ranges":[{"startOffset":351780,"endOffset":351849,"count":0}],"isBlockCoverage":false},{"functionName":"Invoker_guard","ranges":[{"startOffset":351870,"endOffset":352115,"count":1}],"isBlockCoverage":true},{"functionName":"LocalTest","ranges":[{"startOffset":352132,"endOffset":352335,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker","ranges":[{"startOffset":352350,"endOffset":352742,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker_guard_closure","ranges":[{"startOffset":352771,"endOffset":352811,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker_guard__closure","ranges":[{"startOffset":352841,"endOffset":353002,"count":0}],"isBlockCoverage":false},{"functionName":"Invoker_waitForOutstandingCallbacks_closure","ranges":[{"startOffset":353053,"endOffset":353229,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker_waitForOutstandingCallbacks_closure0","ranges":[{"startOffset":353281,"endOffset":353397,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker_heartbeat_message","ranges":[{"startOffset":353430,"endOffset":353501,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker_heartbeat_closure","ranges":[{"startOffset":353534,"endOffset":353661,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker_heartbeat__closure","ranges":[{"startOffset":353695,"endOffset":353823,"count":0}],"isBlockCoverage":false},{"functionName":"Invoker__handleError_closure","ranges":[{"startOffset":353859,"endOffset":353932,"count":0}],"isBlockCoverage":false},{"functionName":"Invoker__handleError_closure0","ranges":[{"startOffset":353969,"endOffset":354042,"count":0}],"isBlockCoverage":false},{"functionName":"Invoker__onRun_closure","ranges":[{"startOffset":354072,"endOffset":354187,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker__onRun__closure","ranges":[{"startOffset":354218,"endOffset":354334,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker__onRun___closure","ranges":[{"startOffset":354366,"endOffset":354434,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker__onRun____closure","ranges":[{"startOffset":354467,"endOffset":354536,"count":1}],"isBlockCoverage":true},{"functionName":"Invoker__onRun___closure0","ranges":[{"startOffset":354569,"endOffset":354638,"count":1}],"isBlockCoverage":true},{"functionName":"_AsyncCounter","ranges":[{"startOffset":354659,"endOffset":354753,"count":1}],"isBlockCoverage":true},{"functionName":"StackTraceFormatter","ranges":[{"startOffset":354780,"endOffset":354899,"count":1}],"isBlockCoverage":true},{"functionName":"StackTraceFormatter_formatStackTrace_closure","ranges":[{"startOffset":354951,"endOffset":355039,"count":0}],"isBlockCoverage":false},{"functionName":"Suite__filterGroup","ranges":[{"startOffset":355065,"endOffset":355410,"count":1},{"startOffset":355223,"endOffset":355409,"count":0}],"isBlockCoverage":true},{"functionName":"Suite","ranges":[{"startOffset":355423,"endOffset":355528,"count":1}],"isBlockCoverage":true},{"functionName":"SuiteConfiguration__list","ranges":[{"startOffset":355560,"endOffset":355606,"count":0}],"isBlockCoverage":false},{"functionName":"SuiteConfiguration__map","ranges":[{"startOffset":355637,"endOffset":355695,"count":0}],"isBlockCoverage":false},{"functionName":"SuiteConfiguration","ranges":[{"startOffset":355721,"endOffset":355758,"count":0}],"isBlockCoverage":false},{"functionName":"RemoteException_serialize","ranges":[{"startOffset":355791,"endOffset":356552,"count":0}],"isBlockCoverage":false},{"functionName":"IntersectionSelector","ranges":[{"startOffset":356587,"endOffset":356688,"count":0}],"isBlockCoverage":false},{"functionName":"StreamChannel","ranges":[{"startOffset":356705,"endOffset":356737,"count":0}],"isBlockCoverage":false},{"functionName":"_StreamChannel","ranges":[{"startOffset":356755,"endOffset":356865,"count":1}],"isBlockCoverage":true},{"functionName":"StreamChannelMixin","ranges":[{"startOffset":356887,"endOffset":356924,"count":0}],"isBlockCoverage":false},{"functionName":"Timeout","ranges":[{"startOffset":356935,"endOffset":357022,"count":1}],"isBlockCoverage":true},{"functionName":"ExpandedReporter","ranges":[{"startOffset":357042,"endOffset":357603,"count":0}],"isBlockCoverage":false},{"functionName":"ExpandedReporter__onTestStarted_closure","ranges":[{"startOffset":357646,"endOffset":357759,"count":0}],"isBlockCoverage":false},{"functionName":"ExpandedReporter__onTestStarted_closure0","ranges":[{"startOffset":357803,"endOffset":357917,"count":0}],"isBlockCoverage":false},{"functionName":"ExpandedReporter__onTestStarted_closure1","ranges":[{"startOffset":357961,"endOffset":358075,"count":0}],"isBlockCoverage":false},{"functionName":"_declarer","ranges":[{"startOffset":358092,"endOffset":358479,"count":1},{"startOffset":358251,"endOffset":358478,"count":0}],"isBlockCoverage":true},{"functionName":"test","ranges":[{"startOffset":358491,"endOffset":358707,"count":1}],"isBlockCoverage":true},{"functionName":"group","ranges":[{"startOffset":358720,"endOffset":358937,"count":1}],"isBlockCoverage":true},{"functionName":"_declarer_closure","ranges":[{"startOffset":358962,"endOffset":358998,"count":0}],"isBlockCoverage":false},{"functionName":"_declarer__closure","ranges":[{"startOffset":359024,"endOffset":359087,"count":0}],"isBlockCoverage":false},{"functionName":"main","ranges":[{"startOffset":359099,"endOffset":359177,"count":1}],"isBlockCoverage":true},{"functionName":"main_closure","ranges":[{"startOffset":359197,"endOffset":359228,"count":1}],"isBlockCoverage":true},{"functionName":"RecursiveVisitor","ranges":[{"startOffset":359259,"endOffset":359294,"count":0}],"isBlockCoverage":false},{"functionName":"InternalStyle","ranges":[{"startOffset":359311,"endOffset":359343,"count":0}],"isBlockCoverage":false},{"functionName":"StreamChannelController$","ranges":[{"startOffset":359375,"endOffset":360324,"count":1}],"isBlockCoverage":true},{"functionName":"StreamChannelController","ranges":[{"startOffset":360355,"endOffset":360462,"count":1}],"isBlockCoverage":true},{"functionName":"Runtime_Runtime$deserialize","ranges":[{"startOffset":360497,"endOffset":361558,"count":1},{"startOffset":360735,"endOffset":361557,"count":0}],"isBlockCoverage":true},{"functionName":"Runtime","ranges":[{"startOffset":361573,"endOffset":361827,"count":1}],"isBlockCoverage":true},{"functionName":"Runtime_Runtime$deserialize_closure","ranges":[{"startOffset":361870,"endOffset":361954,"count":1}],"isBlockCoverage":true},{"functionName":"indent","ranges":[{"startOffset":361968,"endOffset":362129,"count":0}],"isBlockCoverage":false},{"functionName":"toSentence","ranges":[{"startOffset":362147,"endOffset":362529,"count":0}],"isBlockCoverage":false},{"functionName":"pluralize","ranges":[{"startOffset":362546,"endOffset":362649,"count":0}],"isBlockCoverage":false},{"functionName":"prefixLines","ranges":[{"startOffset":362668,"endOffset":363386,"count":0}],"isBlockCoverage":false},{"functionName":"closure0","ranges":[{"startOffset":363402,"endOffset":363429,"count":0}],"isBlockCoverage":false},{"functionName":"LiveSuiteController$","ranges":[{"startOffset":363457,"endOffset":364346,"count":0}],"isBlockCoverage":false},{"functionName":"_LiveSuite","ranges":[{"startOffset":364364,"endOffset":364447,"count":0}],"isBlockCoverage":false},{"functionName":"LiveSuiteController","ranges":[{"startOffset":364474,"endOffset":364920,"count":0}],"isBlockCoverage":false},{"functionName":"LiveSuiteController_closure","ranges":[{"startOffset":364955,"endOffset":365026,"count":0}],"isBlockCoverage":false},{"functionName":"LiveSuiteController_closure0","ranges":[{"startOffset":365062,"endOffset":365109,"count":0}],"isBlockCoverage":false},{"functionName":"LiveSuiteController_reportLiveTest_closure","ranges":[{"startOffset":365159,"endOffset":365309,"count":0}],"isBlockCoverage":false},{"functionName":"LiveSuiteController_close_closure","ranges":[{"startOffset":365350,"endOffset":365427,"count":0}],"isBlockCoverage":false},{"functionName":"asUri","ranges":[{"startOffset":365440,"endOffset":365612,"count":0}],"isBlockCoverage":false},{"functionName":"ensureTrailingSlash","ranges":[{"startOffset":365639,"endOffset":366120,"count":1},{"startOffset":365724,"endOffset":365758,"count":0},{"startOffset":365898,"endOffset":366119,"count":0}],"isBlockCoverage":true},{"functionName":"isAlphabetic","ranges":[{"startOffset":366140,"endOffset":366302,"count":0}],"isBlockCoverage":false},{"functionName":"isDriveLetter","ranges":[{"startOffset":366323,"endOffset":366734,"count":0}],"isBlockCoverage":false},{"functionName":"countCodeUnits","ranges":[{"startOffset":366756,"endOffset":367071,"count":0}],"isBlockCoverage":false},{"functionName":"findLineStart","ranges":[{"startOffset":367092,"endOffset":367938,"count":0}],"isBlockCoverage":false},{"functionName":"validateErrorArgs","ranges":[{"startOffset":367963,"endOffset":368466,"count":0}],"isBlockCoverage":false},{"functionName":"QueueList$","ranges":[{"startOffset":368496,"endOffset":368736,"count":1}],"isBlockCoverage":true},{"functionName":"QueueList__nextPowerOf2","ranges":[{"startOffset":368767,"endOffset":369042,"count":0}],"isBlockCoverage":false},{"functionName":"QueueList","ranges":[{"startOffset":369059,"endOffset":369215,"count":1}],"isBlockCoverage":true},{"functionName":"_QueueList_Object_ListMixin","ranges":[{"startOffset":369250,"endOffset":369296,"count":0}],"isBlockCoverage":false},{"functionName":"UnionSet","ranges":[{"startOffset":369319,"endOffset":369427,"count":0}],"isBlockCoverage":false},{"functionName":"UnionSet_length_closure","ranges":[{"startOffset":369454,"endOffset":369521,"count":0}],"isBlockCoverage":false},{"functionName":"UnionSet__iterable_closure","ranges":[{"startOffset":369551,"endOffset":369621,"count":0}],"isBlockCoverage":false},{"functionName":"_UnionSet_SetBase_UnmodifiableSetMixin","ranges":[{"startOffset":369663,"endOffset":369720,"count":0}],"isBlockCoverage":false},{"functionName":"_DelegatingIterableBase","ranges":[{"startOffset":369747,"endOffset":369789,"count":0}],"isBlockCoverage":false},{"functionName":"DelegatingIterable","ranges":[{"startOffset":369811,"endOffset":369848,"count":0}],"isBlockCoverage":false},{"functionName":"DelegatingSet","ranges":[{"startOffset":369865,"endOffset":369947,"count":0}],"isBlockCoverage":false},{"functionName":"TypeMatcher","ranges":[{"startOffset":369962,"endOffset":369992,"count":0}],"isBlockCoverage":false},{"functionName":"wrapMatcher","ranges":[{"startOffset":370011,"endOffset":370493,"count":1},{"startOffset":370116,"endOffset":370487,"count":0}],"isBlockCoverage":true},{"functionName":"escape","ranges":[{"startOffset":370507,"endOffset":370736,"count":0}],"isBlockCoverage":false},{"functionName":"_getHexLiteral","ranges":[{"startOffset":370758,"endOffset":371247,"count":0}],"isBlockCoverage":false},{"functionName":"wrapMatcher_closure","ranges":[{"startOffset":371274,"endOffset":371333,"count":0}],"isBlockCoverage":false},{"functionName":"escape_closure","ranges":[{"startOffset":371355,"endOffset":371388,"count":0}],"isBlockCoverage":false},{"functionName":"Context_Context","ranges":[{"startOffset":371411,"endOffset":371599,"count":0}],"isBlockCoverage":false},{"functionName":"_parseUri","ranges":[{"startOffset":371616,"endOffset":371786,"count":0}],"isBlockCoverage":false},{"functionName":"_validateArgList","ranges":[{"startOffset":371810,"endOffset":372805,"count":0}],"isBlockCoverage":false},{"functionName":"Context","ranges":[{"startOffset":372820,"endOffset":372910,"count":0}],"isBlockCoverage":false},{"functionName":"Context_join_closure","ranges":[{"startOffset":372938,"endOffset":372977,"count":0}],"isBlockCoverage":false},{"functionName":"Context_joinAll_closure","ranges":[{"startOffset":373008,"endOffset":373050,"count":0}],"isBlockCoverage":false},{"functionName":"Context_split_closure","ranges":[{"startOffset":373079,"endOffset":373119,"count":0}],"isBlockCoverage":false},{"functionName":"_validateArgList_closure","ranges":[{"startOffset":373151,"endOffset":373194,"count":0}],"isBlockCoverage":false},{"functionName":"_PathDirection","ranges":[{"startOffset":373216,"endOffset":373273,"count":1}],"isBlockCoverage":true},{"functionName":"_PathRelation","ranges":[{"startOffset":373294,"endOffset":373350,"count":1}],"isBlockCoverage":true},{"functionName":"_StringEqualsMatcher__writeLeading","ranges":[{"startOffset":373404,"endOffset":373714,"count":0}],"isBlockCoverage":false},{"functionName":"_StringEqualsMatcher__writeTrailing","ranges":[{"startOffset":373757,"endOffset":374094,"count":0}],"isBlockCoverage":false},{"functionName":"_StringEqualsMatcher","ranges":[{"startOffset":374122,"endOffset":374203,"count":0}],"isBlockCoverage":false},{"functionName":"_DeepMatcher","ranges":[{"startOffset":374223,"endOffset":374311,"count":0}],"isBlockCoverage":false},{"functionName":"_DeepMatcher__compareSets_closure","ranges":[{"startOffset":374352,"endOffset":374533,"count":0}],"isBlockCoverage":false},{"functionName":"PackageRootResolver","ranges":[{"startOffset":374560,"endOffset":374629,"count":0}],"isBlockCoverage":false},{"functionName":"SourceLocationMixin","ranges":[{"startOffset":374656,"endOffset":374694,"count":0}],"isBlockCoverage":false},{"functionName":"_MultiChannel$","ranges":[{"startOffset":374716,"endOffset":375095,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel","ranges":[{"startOffset":375116,"endOffset":375414,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_closure","ranges":[{"startOffset":375443,"endOffset":375531,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_closure0","ranges":[{"startOffset":375561,"endOffset":375627,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_closure1","ranges":[{"startOffset":375657,"endOffset":375746,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel__closure","ranges":[{"startOffset":375776,"endOffset":375889,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_virtualChannel_closure","ranges":[{"startOffset":375933,"endOffset":376041,"count":1}],"isBlockCoverage":true},{"functionName":"_MultiChannel_virtualChannel_closure0","ranges":[{"startOffset":376086,"endOffset":376195,"count":1}],"isBlockCoverage":true},{"functionName":"VirtualChannel","ranges":[{"startOffset":376217,"endOffset":376400,"count":1}],"isBlockCoverage":true},{"functionName":"Message","ranges":[{"startOffset":376415,"endOffset":376491,"count":0}],"isBlockCoverage":false},{"functionName":"MessageType","ranges":[{"startOffset":376510,"endOffset":376564,"count":1}],"isBlockCoverage":true},{"functionName":"current","ranges":[{"startOffset":376579,"endOffset":377522,"count":0}],"isBlockCoverage":false},{"functionName":"prettyPrint","ranges":[{"startOffset":377553,"endOffset":377748,"count":0}],"isBlockCoverage":false},{"functionName":"_typeName","ranges":[{"startOffset":377765,"endOffset":377994,"count":0}],"isBlockCoverage":false},{"functionName":"_escapeString","ranges":[{"startOffset":378015,"endOffset":378154,"count":0}],"isBlockCoverage":false},{"functionName":"prettyPrint__prettyPrint","ranges":[{"startOffset":378186,"endOffset":378292,"count":0}],"isBlockCoverage":false},{"functionName":"prettyPrint__prettyPrint_pp","ranges":[{"startOffset":378327,"endOffset":378461,"count":0}],"isBlockCoverage":false},{"functionName":"prettyPrint__prettyPrint_closure","ranges":[{"startOffset":378501,"endOffset":378578,"count":0}],"isBlockCoverage":false},{"functionName":"prettyPrint__prettyPrint_closure0","ranges":[{"startOffset":378619,"endOffset":378721,"count":0}],"isBlockCoverage":false},{"functionName":"prettyPrint__prettyPrint_closure1","ranges":[{"startOffset":378762,"endOffset":378840,"count":0}],"isBlockCoverage":false},{"functionName":"LiveTest","ranges":[{"startOffset":378856,"endOffset":378883,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseVM","ranges":[{"startOffset":378922,"endOffset":379038,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseV8","ranges":[{"startOffset":379065,"endOffset":379181,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseFirefox","ranges":[{"startOffset":379213,"endOffset":379334,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseFriendly","ranges":[{"startOffset":379367,"endOffset":379489,"count":0}],"isBlockCoverage":false},{"functionName":"Frame__uriOrPathToUri","ranges":[{"startOffset":379518,"endOffset":380076,"count":0}],"isBlockCoverage":false},{"functionName":"Frame__catchFormatException","ranges":[{"startOffset":380111,"endOffset":380455,"count":0}],"isBlockCoverage":false},{"functionName":"Frame","ranges":[{"startOffset":380468,"endOffset":380605,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseVM_closure","ranges":[{"startOffset":380640,"endOffset":380711,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseV8_closure","ranges":[{"startOffset":380746,"endOffset":380817,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseV8_closure_parseLocation","ranges":[{"startOffset":380866,"endOffset":380951,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseFirefox_closure","ranges":[{"startOffset":380991,"endOffset":381067,"count":0}],"isBlockCoverage":false},{"functionName":"Frame_Frame$parseFriendly_closure","ranges":[{"startOffset":381108,"endOffset":381185,"count":0}],"isBlockCoverage":false},{"functionName":"AsciiGlyphSet","ranges":[{"startOffset":381206,"endOffset":381238,"count":1}],"isBlockCoverage":true},{"functionName":"UnparsedFrame","ranges":[{"startOffset":381266,"endOffset":381349,"count":0}],"isBlockCoverage":false},{"functionName":"StreamChannelCompleter","ranges":[{"startOffset":381375,"endOffset":381623,"count":1}],"isBlockCoverage":true},{"functionName":"postMessageChannel","ranges":[{"startOffset":381649,"endOffset":382274,"count":1}],"isBlockCoverage":true},{"functionName":"postMessageChannel_closure","ranges":[{"startOffset":382308,"endOffset":382353,"count":1}],"isBlockCoverage":true},{"functionName":"postMessageChannel_closure0","ranges":[{"startOffset":382388,"endOffset":382464,"count":1}],"isBlockCoverage":true},{"functionName":"postMessageChannel__closure","ranges":[{"startOffset":382499,"endOffset":382575,"count":1}],"isBlockCoverage":true},{"functionName":"postMessageChannel__closure0","ranges":[{"startOffset":382611,"endOffset":382682,"count":1}],"isBlockCoverage":true},{"functionName":"postMessageChannel__closure1","ranges":[{"startOffset":382718,"endOffset":382827,"count":1}],"isBlockCoverage":true},{"functionName":"OperatingSystem_find","ranges":[{"startOffset":382855,"endOffset":383034,"count":1}],"isBlockCoverage":true},{"functionName":"OperatingSystem","ranges":[{"startOffset":383057,"endOffset":383147,"count":1}],"isBlockCoverage":true},{"functionName":"OperatingSystem_find_closure","ranges":[{"startOffset":383183,"endOffset":383260,"count":1}],"isBlockCoverage":true},{"functionName":"OperatingSystem_find_closure0","ranges":[{"startOffset":383297,"endOffset":383345,"count":1}],"isBlockCoverage":true},{"functionName":"SuiteChannelManager","ranges":[{"startOffset":383372,"endOffset":383520,"count":1}],"isBlockCoverage":true},{"functionName":"GuaranteeChannel$","ranges":[{"startOffset":383557,"endOffset":383845,"count":1}],"isBlockCoverage":true},{"functionName":"GuaranteeChannel","ranges":[{"startOffset":383869,"endOffset":384037,"count":1}],"isBlockCoverage":true},{"functionName":"GuaranteeChannel_closure","ranges":[{"startOffset":384069,"endOffset":384165,"count":1}],"isBlockCoverage":true},{"functionName":"GuaranteeChannel__closure","ranges":[{"startOffset":384198,"endOffset":384267,"count":1}],"isBlockCoverage":true},{"functionName":"_GuaranteeSink","ranges":[{"startOffset":384289,"endOffset":384584,"count":1}],"isBlockCoverage":true},{"functionName":"_GuaranteeSink__addError_closure","ranges":[{"startOffset":384624,"endOffset":384675,"count":0}],"isBlockCoverage":false},{"functionName":"_GuaranteeSink_addStream_closure","ranges":[{"startOffset":384715,"endOffset":384791,"count":1}],"isBlockCoverage":true},{"functionName":"UnicodeGlyphSet","ranges":[{"startOffset":384814,"endOffset":384848,"count":1}],"isBlockCoverage":true},{"functionName":"ClosedException$","ranges":[{"startOffset":384872,"endOffset":384928,"count":0}],"isBlockCoverage":false},{"functionName":"ClosedException","ranges":[{"startOffset":384951,"endOffset":384985,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":385218,"endOffset":385284,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":385304,"endOffset":385382,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":385400,"endOffset":385507,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":385530,"endOffset":385597,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":385644,"endOffset":385701,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":385721,"endOffset":385788,"count":1},{"startOffset":385773,"endOffset":385781,"count":0}],"isBlockCoverage":true},{"functionName":"get$runtimeType","ranges":[{"startOffset":385811,"endOffset":385867,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":385923,"endOffset":385984,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":386002,"endOffset":386049,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":386069,"endOffset":386111,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":386134,"endOffset":386190,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":386294,"endOffset":386336,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":386359,"endOffset":386419,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":386437,"endOffset":386494,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":386659,"endOffset":386925,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":386943,"endOffset":387010,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":387073,"endOffset":387290,"count":1},{"startOffset":387210,"endOffset":387256,"count":0}],"isBlockCoverage":true},{"functionName":"removeAt$1","ranges":[{"startOffset":387308,"endOffset":387608,"count":0}],"isBlockCoverage":false},{"functionName":"insert$2","ranges":[{"startOffset":387624,"endOffset":387991,"count":0}],"isBlockCoverage":false},{"functionName":"insertAll$2","ranges":[{"startOffset":388010,"endOffset":388615,"count":0}],"isBlockCoverage":false},{"functionName":"removeLast$0","ranges":[{"startOffset":388635,"endOffset":388887,"count":0}],"isBlockCoverage":false},{"functionName":"remove$1","ranges":[{"startOffset":388903,"endOffset":389218,"count":1},{"startOffset":388989,"endOffset":389038,"count":0},{"startOffset":389192,"endOffset":389217,"count":0}],"isBlockCoverage":true},{"functionName":"addAll$1","ranges":[{"startOffset":389234,"endOffset":389764,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":389781,"endOffset":390106,"count":0}],"isBlockCoverage":false},{"functionName":"map$1$1","ranges":[{"startOffset":390121,"endOffset":390359,"count":0}],"isBlockCoverage":false},{"functionName":"join$1","ranges":[{"startOffset":390373,"endOffset":390629,"count":0}],"isBlockCoverage":false},{"functionName":"join$0","ranges":[{"startOffset":390643,"endOffset":390711,"count":0}],"isBlockCoverage":false},{"functionName":"fold$1$2","ranges":[{"startOffset":390727,"endOffset":391213,"count":1},{"startOffset":391010,"endOffset":391187,"count":0}],"isBlockCoverage":true},{"functionName":"firstWhere$2$orElse","ranges":[{"startOffset":391240,"endOffset":391854,"count":1},{"startOffset":391653,"endOffset":391717,"count":0},{"startOffset":391783,"endOffset":391853,"count":0}],"isBlockCoverage":true},{"functionName":"firstWhere$1","ranges":[{"startOffset":391874,"endOffset":391969,"count":1}],"isBlockCoverage":true},{"functionName":"elementAt$1","ranges":[{"startOffset":391988,"endOffset":392141,"count":1},{"startOffset":392073,"endOffset":392105,"count":0}],"isBlockCoverage":true},{"functionName":"sublist$2","ranges":[{"startOffset":392158,"endOffset":392671,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":392688,"endOffset":392838,"count":1},{"startOffset":392767,"endOffset":392837,"count":0}],"isBlockCoverage":true},{"functionName":"get$last","ranges":[{"startOffset":392854,"endOffset":393028,"count":1},{"startOffset":392957,"endOffset":393027,"count":0}],"isBlockCoverage":true},{"functionName":"get$single","ranges":[{"startOffset":393046,"endOffset":393372,"count":0}],"isBlockCoverage":false},{"functionName":"setRange$4","ranges":[{"startOffset":393390,"endOffset":394326,"count":0}],"isBlockCoverage":false},{"functionName":"setRange$3","ranges":[{"startOffset":394344,"endOffset":394459,"count":0}],"isBlockCoverage":false},{"functionName":"fillRange$3","ranges":[{"startOffset":394478,"endOffset":394843,"count":0}],"isBlockCoverage":false},{"functionName":"replaceRange$3","ranges":[{"startOffset":394865,"endOffset":395890,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":395908,"endOffset":396081,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":396100,"endOffset":396162,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":396180,"endOffset":396276,"count":0}],"isBlockCoverage":false},{"functionName":"toSet$0","ranges":[{"startOffset":396291,"endOffset":396422,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":396442,"endOffset":396589,"count":1}],"isBlockCoverage":true},{"functionName":"get$hashCode","ranges":[{"startOffset":396609,"endOffset":396687,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":396705,"endOffset":396761,"count":1}],"isBlockCoverage":true},{"functionName":"set$length","ranges":[{"startOffset":396779,"endOffset":397195,"count":1},{"startOffset":396884,"endOffset":396937,"count":0},{"startOffset":396978,"endOffset":397046,"count":0},{"startOffset":397080,"endOffset":397154,"count":0}],"isBlockCoverage":true},{"functionName":"$index","ranges":[{"startOffset":397209,"endOffset":397523,"count":1},{"startOffset":397307,"endOffset":397368,"count":0},{"startOffset":397426,"endOffset":397487,"count":0}],"isBlockCoverage":true},{"functionName":"$indexSet","ranges":[{"startOffset":397540,"endOffset":398028,"count":1},{"startOffset":397720,"endOffset":397774,"count":0},{"startOffset":397811,"endOffset":397872,"count":0},{"startOffset":397930,"endOffset":397991,"count":0}],"isBlockCoverage":true},{"functionName":"get$current","ranges":[{"startOffset":398194,"endOffset":398240,"count":1}],"isBlockCoverage":true},{"functionName":"moveNext$0","ranges":[{"startOffset":398258,"endOffset":398662,"count":1},{"startOffset":398403,"endOffset":398465,"count":0}],"isBlockCoverage":true},{"functionName":"set$_current","ranges":[{"startOffset":398682,"endOffset":398771,"count":1}],"isBlockCoverage":true},{"functionName":"floor$0","ranges":[{"startOffset":398837,"endOffset":399285,"count":0}],"isBlockCoverage":false},{"functionName":"round$0","ranges":[{"startOffset":399300,"endOffset":399582,"count":1},{"startOffset":399425,"endOffset":399581,"count":0}],"isBlockCoverage":true},{"functionName":"toRadixString$1","ranges":[{"startOffset":399605,"endOffset":400471,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":400489,"endOffset":400625,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":400645,"endOffset":401151,"count":0}],"isBlockCoverage":false},{"functionName":"$mod","ranges":[{"startOffset":401163,"endOffset":401414,"count":0}],"isBlockCoverage":false},{"functionName":"$tdiv","ranges":[{"startOffset":401427,"endOffset":401624,"count":0}],"isBlockCoverage":false},{"functionName":"_tdivFast$1","ranges":[{"startOffset":401643,"endOffset":401777,"count":1},{"startOffset":401735,"endOffset":401770,"count":0}],"isBlockCoverage":true},{"functionName":"_tdivSlow$1","ranges":[{"startOffset":401796,"endOffset":402270,"count":0}],"isBlockCoverage":false},{"functionName":"_shlPositive$1","ranges":[{"startOffset":402292,"endOffset":402380,"count":0}],"isBlockCoverage":false},{"functionName":"_shrOtherPositive$1","ranges":[{"startOffset":402407,"endOffset":402644,"count":0}],"isBlockCoverage":false},{"functionName":"_shrReceiverPositive$1","ranges":[{"startOffset":402674,"endOffset":402843,"count":0}],"isBlockCoverage":false},{"functionName":"_shrBothPositive$1","ranges":[{"startOffset":402869,"endOffset":402952,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":402975,"endOffset":403030,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":403114,"endOffset":403169,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":403238,"endOffset":403296,"count":0}],"isBlockCoverage":false},{"functionName":"codeUnitAt$1","ranges":[{"startOffset":403347,"endOffset":403614,"count":1},{"startOffset":403404,"endOffset":403465,"count":0},{"startOffset":403510,"endOffset":403567,"count":0}],"isBlockCoverage":true},{"functionName":"_codeUnitAt$1","ranges":[{"startOffset":403635,"endOffset":403815,"count":1},{"startOffset":403707,"endOffset":403768,"count":0}],"isBlockCoverage":true},{"functionName":"allMatches$2","ranges":[{"startOffset":403835,"endOffset":404180,"count":0}],"isBlockCoverage":false},{"functionName":"allMatches$1","ranges":[{"startOffset":404200,"endOffset":404289,"count":0}],"isBlockCoverage":false},{"functionName":"matchAsPrefix$2","ranges":[{"startOffset":404312,"endOffset":404833,"count":0}],"isBlockCoverage":false},{"functionName":"$add","ranges":[{"startOffset":404845,"endOffset":405018,"count":0}],"isBlockCoverage":false},{"functionName":"endsWith$1","ranges":[{"startOffset":405036,"endOffset":405256,"count":0}],"isBlockCoverage":false},{"functionName":"splitMapJoin$2$onMatch","ranges":[{"startOffset":405286,"endOffset":405477,"count":0}],"isBlockCoverage":false},{"functionName":"replaceFirst$2","ranges":[{"startOffset":405499,"endOffset":405680,"count":0}],"isBlockCoverage":false},{"functionName":"replaceRange$3","ranges":[{"startOffset":405702,"endOffset":405903,"count":0}],"isBlockCoverage":false},{"functionName":"startsWith$2","ranges":[{"startOffset":405923,"endOffset":406447,"count":1},{"startOffset":406073,"endOffset":406154,"count":0},{"startOffset":406288,"endOffset":406301,"count":0},{"startOffset":406373,"endOffset":406446,"count":0}],"isBlockCoverage":true},{"functionName":"startsWith$1","ranges":[{"startOffset":406467,"endOffset":406558,"count":0}],"isBlockCoverage":false},{"functionName":"substring$2","ranges":[{"startOffset":406577,"endOffset":407046,"count":1},{"startOffset":406656,"endOffset":406683,"count":0},{"startOffset":406718,"endOffset":406778,"count":0},{"startOffset":406820,"endOffset":406880,"count":0},{"startOffset":406927,"endOffset":406985,"count":0}],"isBlockCoverage":true},{"functionName":"substring$1","ranges":[{"startOffset":407065,"endOffset":407164,"count":0}],"isBlockCoverage":false},{"functionName":"trim$0","ranges":[{"startOffset":407178,"endOffset":407844,"count":0}],"isBlockCoverage":false},{"functionName":"$mul","ranges":[{"startOffset":407856,"endOffset":408335,"count":0}],"isBlockCoverage":false},{"functionName":"padLeft$2","ranges":[{"startOffset":408352,"endOffset":408535,"count":0}],"isBlockCoverage":false},{"functionName":"padRight$1","ranges":[{"startOffset":408553,"endOffset":408802,"count":0}],"isBlockCoverage":false},{"functionName":"indexOf$2","ranges":[{"startOffset":408819,"endOffset":409075,"count":0}],"isBlockCoverage":false},{"functionName":"indexOf$1","ranges":[{"startOffset":409092,"endOffset":409180,"count":0}],"isBlockCoverage":false},{"functionName":"lastIndexOf$2","ranges":[{"startOffset":409201,"endOffset":409620,"count":0}],"isBlockCoverage":false},{"functionName":"lastIndexOf$1","ranges":[{"startOffset":409641,"endOffset":409736,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":409754,"endOffset":409928,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":409946,"endOffset":409995,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":410015,"endOffset":410421,"count":1}],"isBlockCoverage":true},{"functionName":"get$runtimeType","ranges":[{"startOffset":410444,"endOffset":410502,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":410520,"endOffset":410576,"count":1}],"isBlockCoverage":true},{"functionName":"$index","ranges":[{"startOffset":410590,"endOffset":410806,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":410903,"endOffset":411111,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":411129,"endOffset":411209,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":411228,"endOffset":411309,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":411326,"endOffset":411441,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":411457,"endOffset":411571,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":411589,"endOffset":411663,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":411681,"endOffset":411741,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":411794,"endOffset":411852,"count":1}],"isBlockCoverage":true},{"functionName":"get$current","ranges":[{"startOffset":411871,"endOffset":411953,"count":1}],"isBlockCoverage":true},{"functionName":"cast$2$0","ranges":[{"startOffset":412130,"endOffset":412317,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":412338,"endOffset":412405,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":412419,"endOffset":412508,"count":1}],"isBlockCoverage":true},{"functionName":"remove$1","ranges":[{"startOffset":412524,"endOffset":412615,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":412632,"endOffset":412762,"count":0}],"isBlockCoverage":false},{"functionName":"get$keys","ranges":[{"startOffset":412778,"endOffset":412919,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":412937,"endOffset":413017,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":413036,"endOffset":413117,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":413177,"endOffset":413372,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":413390,"endOffset":413458,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":413508,"endOffset":413561,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":413575,"endOffset":413681,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":413780,"endOffset":413952,"count":1}],"isBlockCoverage":true},{"functionName":"get$isEmpty","ranges":[{"startOffset":413971,"endOffset":414032,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":414049,"endOffset":414211,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":414227,"endOffset":414442,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":414460,"endOffset":414822,"count":0}],"isBlockCoverage":false},{"functionName":"join$1","ranges":[{"startOffset":414836,"endOffset":415796,"count":0}],"isBlockCoverage":false},{"functionName":"join$0","ranges":[{"startOffset":415810,"endOffset":415878,"count":0}],"isBlockCoverage":false},{"functionName":"map$1$1","ranges":[{"startOffset":415893,"endOffset":416137,"count":0}],"isBlockCoverage":false},{"functionName":"fold$1$2","ranges":[{"startOffset":416153,"endOffset":416676,"count":0}],"isBlockCoverage":false},{"functionName":"toList$1$growable","ranges":[{"startOffset":416701,"endOffset":417074,"count":1}],"isBlockCoverage":true},{"functionName":"toList$0","ranges":[{"startOffset":417090,"endOffset":417171,"count":1}],"isBlockCoverage":true},{"functionName":"toSet$0","ranges":[{"startOffset":417186,"endOffset":417453,"count":0}],"isBlockCoverage":false},{"functionName":"get$_endIndex","ranges":[{"startOffset":417512,"endOffset":417706,"count":0}],"isBlockCoverage":false},{"functionName":"get$_startIndex","ranges":[{"startOffset":417729,"endOffset":417914,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":417932,"endOffset":418288,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":418307,"endOffset":418765,"count":0}],"isBlockCoverage":false},{"functionName":"take$1","ranges":[{"startOffset":418779,"endOffset":419284,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":419338,"endOffset":419395,"count":1}],"isBlockCoverage":true},{"functionName":"moveNext$0","ranges":[{"startOffset":419413,"endOffset":419942,"count":1},{"startOffset":419627,"endOffset":419685,"count":0}],"isBlockCoverage":true},{"functionName":"set$__internal$_current","ranges":[{"startOffset":419973,"endOffset":420073,"count":1}],"isBlockCoverage":true},{"functionName":"get$iterator","ranges":[{"startOffset":420150,"endOffset":420369,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":420387,"endOffset":420464,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":420483,"endOffset":420561,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":420578,"endOffset":420669,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":420685,"endOffset":420775,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":420909,"endOffset":421176,"count":1},{"startOffset":421003,"endOffset":421107,"count":0}],"isBlockCoverage":true},{"functionName":"get$current","ranges":[{"startOffset":421195,"endOffset":421252,"count":0}],"isBlockCoverage":false},{"functionName":"set$__internal$_current","ranges":[{"startOffset":421283,"endOffset":421378,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":421437,"endOffset":421501,"count":1}],"isBlockCoverage":true},{"functionName":"elementAt$1","ranges":[{"startOffset":421520,"endOffset":421614,"count":1}],"isBlockCoverage":true},{"functionName":"get$iterator","ranges":[{"startOffset":421670,"endOffset":421816,"count":1}],"isBlockCoverage":true},{"functionName":"map$1$1","ranges":[{"startOffset":421831,"endOffset":422028,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":422082,"endOffset":422289,"count":1}],"isBlockCoverage":true},{"functionName":"get$current","ranges":[{"startOffset":422308,"endOffset":422369,"count":1}],"isBlockCoverage":true},{"functionName":"get$iterator","ranges":[{"startOffset":422426,"endOffset":422651,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":422707,"endOffset":422764,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":422782,"endOffset":423337,"count":0}],"isBlockCoverage":false},{"functionName":"set$_currentExpansion","ranges":[{"startOffset":423366,"endOffset":423491,"count":0}],"isBlockCoverage":false},{"functionName":"set$__internal$_current","ranges":[{"startOffset":423522,"endOffset":423617,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":423697,"endOffset":423851,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":423909,"endOffset":424236,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":424255,"endOffset":424316,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":424370,"endOffset":424408,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":424427,"endOffset":424464,"count":0}],"isBlockCoverage":false},{"functionName":"set$length","ranges":[{"startOffset":424545,"endOffset":424683,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":424744,"endOffset":424977,"count":0}],"isBlockCoverage":false},{"functionName":"set$length","ranges":[{"startOffset":424995,"endOffset":425127,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":425229,"endOffset":425293,"count":1}],"isBlockCoverage":true},{"functionName":"elementAt$1","ranges":[{"startOffset":425312,"endOffset":425470,"count":1}],"isBlockCoverage":true},{"functionName":"get$hashCode","ranges":[{"startOffset":425519,"endOffset":425738,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":425756,"endOffset":425836,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":425847,"endOffset":426011,"count":1},{"startOffset":425901,"endOffset":425914,"count":0}],"isBlockCoverage":true},{"functionName":"cast$2$0","ranges":[{"startOffset":426061,"endOffset":426200,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":426219,"endOffset":426280,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":426298,"endOffset":426359,"count":0}],"isBlockCoverage":false},{"functionName":"remove$1","ranges":[{"startOffset":426375,"endOffset":426448,"count":0}],"isBlockCoverage":false},{"functionName":"map$2$1","ranges":[{"startOffset":426463,"endOffset":426752,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":426827,"endOffset":427051,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":427069,"endOffset":427150,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":427208,"endOffset":427266,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":427287,"endOffset":427466,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":427480,"endOffset":427594,"count":0}],"isBlockCoverage":false},{"functionName":"_fetch$1","ranges":[{"startOffset":427610,"endOffset":427689,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":427706,"endOffset":428021,"count":1},{"startOffset":427929,"endOffset":428015,"count":0}],"isBlockCoverage":true},{"functionName":"get$keys","ranges":[{"startOffset":428037,"endOffset":428166,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":428232,"endOffset":428410,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":428428,"endOffset":428508,"count":0}],"isBlockCoverage":false},{"functionName":"Instantiation$1","ranges":[{"startOffset":428567,"endOffset":428666,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":428684,"endOffset":428871,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":428922,"endOffset":429017,"count":0}],"isBlockCoverage":false},{"functionName":"call$4","ranges":[{"startOffset":429031,"endOffset":429142,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":429160,"endOffset":429281,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":429347,"endOffset":429437,"count":0}],"isBlockCoverage":false},{"functionName":"matchTypeError$1","ranges":[{"startOffset":429520,"endOffset":430192,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":430242,"endOffset":430457,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":430546,"endOffset":430987,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":431075,"endOffset":431193,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":431303,"endOffset":431464,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":431536,"endOffset":431793,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":431863,"endOffset":432075,"count":0}],"isBlockCoverage":false},{"functionName":"get$$call","ranges":[{"startOffset":432112,"endOffset":432149,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":432313,"endOffset":432502,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":432548,"endOffset":432877,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":432897,"endOffset":433264,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":433282,"endOffset":433522,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":433586,"endOffset":433632,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":433651,"endOffset":433704,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":433757,"endOffset":433827,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":433846,"endOffset":433899,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":433955,"endOffset":434046,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":434102,"endOffset":434160,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":434179,"endOffset":434243,"count":1}],"isBlockCoverage":true},{"functionName":"get$keys","ranges":[{"startOffset":434259,"endOffset":434390,"count":1}],"isBlockCoverage":true},{"functionName":"get$values","ranges":[{"startOffset":434408,"endOffset":434602,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":434623,"endOffset":435155,"count":1},{"startOffset":435019,"endOffset":435032,"count":0},{"startOffset":435095,"endOffset":435149,"count":0}],"isBlockCoverage":true},{"functionName":"internalContainsKey$1","ranges":[{"startOffset":435184,"endOffset":435440,"count":0}],"isBlockCoverage":false},{"functionName":"addAll$1","ranges":[{"startOffset":435456,"endOffset":435602,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":435616,"endOffset":436311,"count":1},{"startOffset":435819,"endOffset":435832,"count":0},{"startOffset":435911,"endOffset":435918,"count":0},{"startOffset":436111,"endOffset":436124,"count":0},{"startOffset":436200,"endOffset":436207,"count":0},{"startOffset":436259,"endOffset":436305,"count":0}],"isBlockCoverage":true},{"functionName":"internalGet$1","ranges":[{"startOffset":436332,"endOffset":436708,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":436725,"endOffset":437424,"count":1}],"isBlockCoverage":true},{"functionName":"internalSet$2","ranges":[{"startOffset":437445,"endOffset":438198,"count":1},{"startOffset":437963,"endOffset":438192,"count":0}],"isBlockCoverage":true},{"functionName":"putIfAbsent$2","ranges":[{"startOffset":438219,"endOffset":438560,"count":1},{"startOffset":438463,"endOffset":438559,"count":0}],"isBlockCoverage":true},{"functionName":"remove$1","ranges":[{"startOffset":438576,"endOffset":438960,"count":1},{"startOffset":438743,"endOffset":438954,"count":0}],"isBlockCoverage":true},{"functionName":"internalRemove$1","ranges":[{"startOffset":438984,"endOffset":439546,"count":0}],"isBlockCoverage":false},{"functionName":"clear$0","ranges":[{"startOffset":439561,"endOffset":439847,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":439864,"endOffset":440326,"count":1},{"startOffset":440224,"endOffset":440285,"count":0}],"isBlockCoverage":true},{"functionName":"__js_helper$_addHashTableEntry$3","ranges":[{"startOffset":440366,"endOffset":440739,"count":1},{"startOffset":440683,"endOffset":440733,"count":0}],"isBlockCoverage":true},{"functionName":"__js_helper$_removeHashTableEntry$2","ranges":[{"startOffset":440782,"endOffset":441088,"count":1},{"startOffset":440854,"endOffset":440866,"count":0},{"startOffset":440946,"endOffset":440958,"count":0}],"isBlockCoverage":true},{"functionName":"_modified$0","ranges":[{"startOffset":441107,"endOffset":441189,"count":1}],"isBlockCoverage":true},{"functionName":"_newLinkedCell$2","ranges":[{"startOffset":441213,"endOffset":441682,"count":1}],"isBlockCoverage":true},{"functionName":"__js_helper$_unlinkCell$1","ranges":[{"startOffset":441715,"endOffset":442185,"count":1},{"startOffset":441930,"endOffset":441966,"count":0},{"startOffset":442077,"endOffset":442117,"count":0}],"isBlockCoverage":true},{"functionName":"internalComputeHashCode$1","ranges":[{"startOffset":442218,"endOffset":442286,"count":1}],"isBlockCoverage":true},{"functionName":"internalFindBucketIndex$2","ranges":[{"startOffset":442319,"endOffset":442570,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":442588,"endOffset":442649,"count":0}],"isBlockCoverage":false},{"functionName":"_getTableCell$2","ranges":[{"startOffset":442672,"endOffset":442725,"count":1}],"isBlockCoverage":true},{"functionName":"_getTableBucket$2","ranges":[{"startOffset":442750,"endOffset":442803,"count":1}],"isBlockCoverage":true},{"functionName":"_setTableEntry$3","ranges":[{"startOffset":442827,"endOffset":442925,"count":1}],"isBlockCoverage":true},{"functionName":"_deleteTableEntry$2","ranges":[{"startOffset":442952,"endOffset":443005,"count":1}],"isBlockCoverage":true},{"functionName":"_containsTableEntry$2","ranges":[{"startOffset":443034,"endOffset":443117,"count":1}],"isBlockCoverage":true},{"functionName":"_newHashTable$0","ranges":[{"startOffset":443140,"endOffset":443353,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":443445,"endOffset":443569,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":443587,"endOffset":443663,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":443730,"endOffset":443899,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":443917,"endOffset":443998,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":444101,"endOffset":444176,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":444195,"endOffset":444276,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":444296,"endOffset":444515,"count":1}],"isBlockCoverage":true},{"functionName":"contains$1","ranges":[{"startOffset":444533,"endOffset":444620,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":444686,"endOffset":444744,"count":1}],"isBlockCoverage":true},{"functionName":"moveNext$0","ranges":[{"startOffset":444762,"endOffset":445261,"count":1},{"startOffset":444898,"endOffset":444956,"count":0}],"isBlockCoverage":true},{"functionName":"set$__js_helper$_current","ranges":[{"startOffset":445293,"endOffset":445394,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":445468,"endOffset":445516,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":445591,"endOffset":445656,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":445732,"endOffset":445817,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":445892,"endOffset":445983,"count":0}],"isBlockCoverage":false},{"functionName":"get$_nativeGlobalVersion","ranges":[{"startOffset":446015,"endOffset":446314,"count":0}],"isBlockCoverage":false},{"functionName":"get$_nativeAnchoredVersion","ranges":[{"startOffset":446348,"endOffset":446659,"count":0}],"isBlockCoverage":false},{"functionName":"firstMatch$1","ranges":[{"startOffset":446679,"endOffset":446942,"count":0}],"isBlockCoverage":false},{"functionName":"allMatches$2","ranges":[{"startOffset":446962,"endOffset":447186,"count":0}],"isBlockCoverage":false},{"functionName":"allMatches$1","ranges":[{"startOffset":447206,"endOffset":447295,"count":0}],"isBlockCoverage":false},{"functionName":"_execGlobal$2","ranges":[{"startOffset":447316,"endOffset":447578,"count":0}],"isBlockCoverage":false},{"functionName":"_execAnchored$2","ranges":[{"startOffset":447601,"endOffset":447981,"count":0}],"isBlockCoverage":false},{"functionName":"matchAsPrefix$2","ranges":[{"startOffset":448004,"endOffset":448222,"count":0}],"isBlockCoverage":false},{"functionName":"get$start","ranges":[{"startOffset":448319,"endOffset":448369,"count":0}],"isBlockCoverage":false},{"functionName":"get$end","ranges":[{"startOffset":448384,"endOffset":448468,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":448482,"endOffset":448669,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":448771,"endOffset":448879,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":448940,"endOffset":448998,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":449016,"endOffset":450272,"count":0}],"isBlockCoverage":false},{"functionName":"get$end","ranges":[{"startOffset":450341,"endOffset":450406,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":450420,"endOffset":450574,"count":0}],"isBlockCoverage":false},{"functionName":"get$start","ranges":[{"startOffset":450608,"endOffset":450651,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":450719,"endOffset":450837,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":450854,"endOffset":451101,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":451167,"endOffset":451827,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":451846,"endOffset":451904,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":451986,"endOffset":452048,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":452215,"endOffset":452275,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":452332,"endOffset":452388,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":452487,"endOffset":452644,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":452661,"endOffset":452863,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":452995,"endOffset":453194,"count":1}],"isBlockCoverage":true},{"functionName":"get$runtimeType","ranges":[{"startOffset":453328,"endOffset":453391,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":453454,"endOffset":453517,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":453578,"endOffset":453639,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":453653,"endOffset":453810,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":453871,"endOffset":453932,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":453946,"endOffset":454103,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":454163,"endOffset":454223,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":454237,"endOffset":454394,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":454456,"endOffset":454518,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":454532,"endOffset":454689,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":454751,"endOffset":454813,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":454827,"endOffset":454984,"count":0}],"isBlockCoverage":false},{"functionName":"sublist$2","ranges":[{"startOffset":455001,"endOffset":455144,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":455234,"endOffset":455302,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":455320,"endOffset":455376,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":455390,"endOffset":455547,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":455608,"endOffset":455669,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":455687,"endOffset":455743,"count":1}],"isBlockCoverage":true},{"functionName":"$index","ranges":[{"startOffset":455757,"endOffset":455914,"count":0}],"isBlockCoverage":false},{"functionName":"sublist$2","ranges":[{"startOffset":455931,"endOffset":456073,"count":0}],"isBlockCoverage":false},{"functionName":"_eval$1","ranges":[{"startOffset":456490,"endOffset":456591,"count":1}],"isBlockCoverage":true},{"functionName":"_bind$1","ranges":[{"startOffset":456606,"endOffset":456704,"count":1}],"isBlockCoverage":true},{"functionName":"get$hashCode","ranges":[{"startOffset":456792,"endOffset":457109,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":457120,"endOffset":457259,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":457277,"endOffset":457342,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":457405,"endOffset":457452,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":457535,"endOffset":457582,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":457674,"endOffset":457802,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":457904,"endOffset":458207,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":458319,"endOffset":458367,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":458484,"endOffset":458532,"count":0}],"isBlockCoverage":false},{"functionName":"_TimerImpl$2","ranges":[{"startOffset":458604,"endOffset":458905,"count":1},{"startOffset":458807,"endOffset":458899,"count":0}],"isBlockCoverage":true},{"functionName":"_TimerImpl$periodic$2","ranges":[{"startOffset":458934,"endOffset":459252,"count":0}],"isBlockCoverage":false},{"functionName":"cancel$0","ranges":[{"startOffset":459268,"endOffset":459616,"count":1},{"startOffset":459383,"endOffset":459390,"count":0},{"startOffset":459447,"endOffset":459494,"count":0},{"startOffset":459531,"endOffset":459610,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":459697,"endOffset":459817,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":459900,"endOffset":460263,"count":0}],"isBlockCoverage":false},{"functionName":"complete$1","ranges":[{"startOffset":460343,"endOffset":460659,"count":1}],"isBlockCoverage":true},{"functionName":"completeError$2","ranges":[{"startOffset":460682,"endOffset":460845,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":460925,"endOffset":460999,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":461079,"endOffset":461223,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":461310,"endOffset":461408,"count":1}],"isBlockCoverage":true},{"functionName":"get$isBroadcast","ranges":[{"startOffset":461490,"endOffset":461527,"count":0}],"isBlockCoverage":false},{"functionName":"_onPause$0","ranges":[{"startOffset":461590,"endOffset":461608,"count":0}],"isBlockCoverage":false},{"functionName":"_onResume$0","ranges":[{"startOffset":461627,"endOffset":461645,"count":0}],"isBlockCoverage":false},{"functionName":"set$_async$_next","ranges":[{"startOffset":461669,"endOffset":461742,"count":1}],"isBlockCoverage":true},{"functionName":"set$_async$_previous","ranges":[{"startOffset":461770,"endOffset":461855,"count":1}],"isBlockCoverage":true},{"functionName":"get$_mayAddEvent","ranges":[{"startOffset":461928,"endOffset":461976,"count":1}],"isBlockCoverage":true},{"functionName":"_ensureDoneFuture$0","ranges":[{"startOffset":462003,"endOffset":462182,"count":0}],"isBlockCoverage":false},{"functionName":"_removeListener$1","ranges":[{"startOffset":462207,"endOffset":462934,"count":0}],"isBlockCoverage":false},{"functionName":"_subscribe$4","ranges":[{"startOffset":462954,"endOffset":464472,"count":1},{"startOffset":463220,"endOffset":463469,"count":0},{"startOffset":463523,"endOffset":463526,"count":0},{"startOffset":464278,"endOffset":464337,"count":0}],"isBlockCoverage":true},{"functionName":"_recordCancel$1","ranges":[{"startOffset":464495,"endOffset":465046,"count":0}],"isBlockCoverage":false},{"functionName":"_recordPause$1","ranges":[{"startOffset":465068,"endOffset":465181,"count":0}],"isBlockCoverage":false},{"functionName":"_recordResume$1","ranges":[{"startOffset":465204,"endOffset":465317,"count":0}],"isBlockCoverage":false},{"functionName":"_addEventError$0","ranges":[{"startOffset":465341,"endOffset":465610,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":465623,"endOffset":465854,"count":1},{"startOffset":465769,"endOffset":465817,"count":0}],"isBlockCoverage":true},{"functionName":"addError$2","ranges":[{"startOffset":465872,"endOffset":466438,"count":0}],"isBlockCoverage":false},{"functionName":"addError$1","ranges":[{"startOffset":466456,"endOffset":466522,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":466537,"endOffset":466942,"count":0}],"isBlockCoverage":false},{"functionName":"_async$_addError$2","ranges":[{"startOffset":466968,"endOffset":467072,"count":0}],"isBlockCoverage":false},{"functionName":"_close$0","ranges":[{"startOffset":467088,"endOffset":467356,"count":0}],"isBlockCoverage":false},{"functionName":"_forEachListener$1","ranges":[{"startOffset":467382,"endOffset":468483,"count":0}],"isBlockCoverage":false},{"functionName":"_callOnCancel$0","ranges":[{"startOffset":468506,"endOffset":468761,"count":0}],"isBlockCoverage":false},{"functionName":"set$_firstSubscription","ranges":[{"startOffset":468791,"endOffset":468946,"count":1}],"isBlockCoverage":true},{"functionName":"set$_lastSubscription","ranges":[{"startOffset":468975,"endOffset":469127,"count":1}],"isBlockCoverage":true},{"functionName":"set$_addStreamState","ranges":[{"startOffset":469154,"endOffset":469293,"count":0}],"isBlockCoverage":false},{"functionName":"get$_mayAddEvent","ranges":[{"startOffset":469547,"endOffset":469673,"count":1}],"isBlockCoverage":true},{"functionName":"_addEventError$0","ranges":[{"startOffset":469697,"endOffset":469916,"count":0}],"isBlockCoverage":false},{"functionName":"_sendData$1","ranges":[{"startOffset":469935,"endOffset":470463,"count":1},{"startOffset":470076,"endOffset":470083,"count":0},{"startOffset":470308,"endOffset":470332,"count":0},{"startOffset":470356,"endOffset":470462,"count":0}],"isBlockCoverage":true},{"functionName":"_sendError$2","ranges":[{"startOffset":470483,"endOffset":470690,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":470709,"endOffset":471070,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":471155,"endOffset":471289,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":471307,"endOffset":471403,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":471489,"endOffset":471653,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":471671,"endOffset":471767,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":471852,"endOffset":471979,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":471997,"endOffset":472093,"count":0}],"isBlockCoverage":false},{"functionName":"_sendData$1","ranges":[{"startOffset":472166,"endOffset":472489,"count":0}],"isBlockCoverage":false},{"functionName":"_sendError$2","ranges":[{"startOffset":472509,"endOffset":472759,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":472778,"endOffset":473214,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":473299,"endOffset":473599,"count":1},{"startOffset":473419,"endOffset":473593,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":473686,"endOffset":473986,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":474065,"endOffset":474620,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":474695,"endOffset":475141,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":475159,"endOffset":475217,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":475276,"endOffset":475578,"count":1},{"startOffset":475384,"endOffset":475577,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":475657,"endOffset":476933,"count":1},{"startOffset":475992,"endOffset":476655,"count":0},{"startOffset":476684,"endOffset":476827,"count":0}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":477010,"endOffset":477201,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":477241,"endOffset":477294,"count":0}],"isBlockCoverage":false},{"functionName":"completeError$2","ranges":[{"startOffset":477380,"endOffset":477925,"count":0}],"isBlockCoverage":false},{"functionName":"completeError$1","ranges":[{"startOffset":477948,"endOffset":478019,"count":0}],"isBlockCoverage":false},{"functionName":"complete$1","ranges":[{"startOffset":478096,"endOffset":478336,"count":1},{"startOffset":478231,"endOffset":478296,"count":0}],"isBlockCoverage":true},{"functionName":"complete$0","ranges":[{"startOffset":478354,"endOffset":478408,"count":1}],"isBlockCoverage":true},{"functionName":"_completeError$2","ranges":[{"startOffset":478432,"endOffset":478527,"count":0}],"isBlockCoverage":false},{"functionName":"complete$1","ranges":[{"startOffset":478582,"endOffset":478817,"count":0}],"isBlockCoverage":false},{"functionName":"complete$0","ranges":[{"startOffset":478835,"endOffset":478889,"count":0}],"isBlockCoverage":false},{"functionName":"_completeError$2","ranges":[{"startOffset":478913,"endOffset":479003,"count":0}],"isBlockCoverage":false},{"functionName":"matchesErrorTest$1","ranges":[{"startOffset":479067,"endOffset":479290,"count":0}],"isBlockCoverage":false},{"functionName":"handleError$1","ranges":[{"startOffset":479311,"endOffset":480110,"count":0}],"isBlockCoverage":false},{"functionName":"then$1$2$onError","ranges":[{"startOffset":480164,"endOffset":480845,"count":1},{"startOffset":480507,"endOffset":480563,"count":0},{"startOffset":480676,"endOffset":480679,"count":0}],"isBlockCoverage":true},{"functionName":"then$1$1","ranges":[{"startOffset":480861,"endOffset":480933,"count":1}],"isBlockCoverage":true},{"functionName":"_thenAwait$1$2","ranges":[{"startOffset":480955,"endOffset":481337,"count":1}],"isBlockCoverage":true},{"functionName":"catchError$1","ranges":[{"startOffset":481357,"endOffset":481806,"count":0}],"isBlockCoverage":false},{"functionName":"whenComplete$1","ranges":[{"startOffset":481828,"endOffset":482281,"count":1}],"isBlockCoverage":true},{"functionName":"_cloneResult$1","ranges":[{"startOffset":482303,"endOffset":482502,"count":0}],"isBlockCoverage":false},{"functionName":"_addListener$1","ranges":[{"startOffset":482524,"endOffset":483257,"count":1},{"startOffset":482868,"endOffset":483106,"count":0}],"isBlockCoverage":true},{"functionName":"_prependListeners$1","ranges":[{"startOffset":483284,"endOffset":484374,"count":1},{"startOffset":483471,"endOffset":484368,"count":0}],"isBlockCoverage":true},{"functionName":"_removeListeners$0","ranges":[{"startOffset":484400,"endOffset":484667,"count":1}],"isBlockCoverage":true},{"functionName":"_reverseListeners$1","ranges":[{"startOffset":484694,"endOffset":484951,"count":1}],"isBlockCoverage":true},{"functionName":"_complete$1","ranges":[{"startOffset":484970,"endOffset":485601,"count":1},{"startOffset":485249,"endOffset":485317,"count":0}],"isBlockCoverage":true},{"functionName":"_completeWithValue$1","ranges":[{"startOffset":485629,"endOffset":486055,"count":1}],"isBlockCoverage":true},{"functionName":"_completeError$2","ranges":[{"startOffset":486079,"endOffset":486469,"count":0}],"isBlockCoverage":false},{"functionName":"_completeError$1","ranges":[{"startOffset":486493,"endOffset":486565,"count":0}],"isBlockCoverage":false},{"functionName":"_asyncComplete$1","ranges":[{"startOffset":486589,"endOffset":487004,"count":1},{"startOffset":486779,"endOffset":486841,"count":0}],"isBlockCoverage":true},{"functionName":"_chainFuture$1","ranges":[{"startOffset":487026,"endOffset":487512,"count":0}],"isBlockCoverage":false},{"functionName":"_asyncCompleteError$2","ranges":[{"startOffset":487541,"endOffset":487857,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":487940,"endOffset":488024,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":488113,"endOffset":488205,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":488296,"endOffset":488475,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":488567,"endOffset":488768,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":488782,"endOffset":488844,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":488937,"endOffset":489007,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":489093,"endOffset":489210,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":489294,"endOffset":489370,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":489461,"endOffset":489543,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":489655,"endOffset":491612,"count":1},{"startOffset":490115,"endOffset":490871,"count":0},{"startOffset":491050,"endOffset":491298,"count":0},{"startOffset":491326,"endOffset":491606,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":491732,"endOffset":491785,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":491891,"endOffset":492537,"count":1},{"startOffset":492293,"endOffset":492531,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":492634,"endOffset":493916,"count":0}],"isBlockCoverage":false},{"functionName":"get$isBroadcast","ranges":[{"startOffset":494027,"endOffset":494065,"count":1}],"isBlockCoverage":true},{"functionName":"pipe$1","ranges":[{"startOffset":494079,"endOffset":494313,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":494331,"endOffset":494644,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":494661,"endOffset":495037,"count":1}],"isBlockCoverage":true},{"functionName":"get$last","ranges":[{"startOffset":495053,"endOffset":495429,"count":0}],"isBlockCoverage":false},{"functionName":"firstWhere$1","ranges":[{"startOffset":495449,"endOffset":495994,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":496063,"endOffset":496187,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":496205,"endOffset":496263,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":496333,"endOffset":496503,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":496593,"endOffset":496811,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":496829,"endOffset":496907,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":496963,"endOffset":497027,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":497105,"endOffset":497216,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":497234,"endOffset":497320,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":497379,"endOffset":497447,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":497523,"endOffset":497686,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":497704,"endOffset":497790,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":497848,"endOffset":498176,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":498251,"endOffset":498435,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":498453,"endOffset":498539,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":498596,"endOffset":499042,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":499123,"endOffset":499482,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":499500,"endOffset":499586,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":499649,"endOffset":499710,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":499794,"endOffset":499961,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":500044,"endOffset":500372,"count":0}],"isBlockCoverage":false},{"functionName":"get$_pendingEvents","ranges":[{"startOffset":500561,"endOffset":500951,"count":1},{"startOffset":500776,"endOffset":500950,"count":0}],"isBlockCoverage":true},{"functionName":"_ensurePendingEvents$0","ranges":[{"startOffset":500981,"endOffset":501700,"count":0}],"isBlockCoverage":false},{"functionName":"get$_async$_subscription","ranges":[{"startOffset":501732,"endOffset":502152,"count":1}],"isBlockCoverage":true},{"functionName":"_badEventState$0","ranges":[{"startOffset":502176,"endOffset":502426,"count":0}],"isBlockCoverage":false},{"functionName":"addStream$2$cancelOnError","ranges":[{"startOffset":502459,"endOffset":503511,"count":1},{"startOffset":502668,"endOffset":502716,"count":0},{"startOffset":502743,"endOffset":502874,"count":0},{"startOffset":503017,"endOffset":503060,"count":0},{"startOffset":503300,"endOffset":503316,"count":0},{"startOffset":503326,"endOffset":503339,"count":0}],"isBlockCoverage":true},{"functionName":"_ensureDoneFuture$0","ranges":[{"startOffset":503538,"endOffset":503771,"count":1},{"startOffset":503692,"endOffset":503747,"count":0}],"isBlockCoverage":true},{"functionName":"add$1","ranges":[{"startOffset":503784,"endOffset":504005,"count":1},{"startOffset":503924,"endOffset":503972,"count":0}],"isBlockCoverage":true},{"functionName":"addError$2","ranges":[{"startOffset":504023,"endOffset":504587,"count":0}],"isBlockCoverage":false},{"functionName":"addError$1","ranges":[{"startOffset":504605,"endOffset":504671,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":504686,"endOffset":504977,"count":1},{"startOffset":504785,"endOffset":504820,"count":0},{"startOffset":504848,"endOffset":504896,"count":0}],"isBlockCoverage":true},{"functionName":"_closeUnchecked$0","ranges":[{"startOffset":505002,"endOffset":505204,"count":1},{"startOffset":505082,"endOffset":505101,"count":0},{"startOffset":505141,"endOffset":505198,"count":0}],"isBlockCoverage":true},{"functionName":"_add$1","ranges":[{"startOffset":505218,"endOffset":505567,"count":1},{"startOffset":505423,"endOffset":505561,"count":0}],"isBlockCoverage":true},{"functionName":"_async$_addError$2","ranges":[{"startOffset":505593,"endOffset":505900,"count":0}],"isBlockCoverage":false},{"functionName":"_close$0","ranges":[{"startOffset":505916,"endOffset":506256,"count":0}],"isBlockCoverage":false},{"functionName":"_subscribe$4","ranges":[{"startOffset":506276,"endOffset":507433,"count":1},{"startOffset":506562,"endOffset":506639,"count":0},{"startOffset":507026,"endOffset":507213,"count":0}],"isBlockCoverage":true},{"functionName":"_recordCancel$1","ranges":[{"startOffset":507456,"endOffset":508586,"count":1},{"startOffset":507936,"endOffset":508391,"count":0}],"isBlockCoverage":true},{"functionName":"_recordPause$1","ranges":[{"startOffset":508608,"endOffset":508942,"count":1},{"startOffset":508802,"endOffset":508900,"count":0}],"isBlockCoverage":true},{"functionName":"_recordResume$1","ranges":[{"startOffset":508965,"endOffset":509301,"count":1},{"startOffset":509159,"endOffset":509258,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":509551,"endOffset":509611,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":509707,"endOffset":509840,"count":1},{"startOffset":509780,"endOffset":509798,"count":0},{"startOffset":509808,"endOffset":509834,"count":0}],"isBlockCoverage":true},{"functionName":"_sendData$1","ranges":[{"startOffset":509930,"endOffset":510047,"count":1}],"isBlockCoverage":true},{"functionName":"_sendError$2","ranges":[{"startOffset":510067,"endOffset":510179,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":510198,"endOffset":510266,"count":0}],"isBlockCoverage":false},{"functionName":"_sendData$1","ranges":[{"startOffset":510338,"endOffset":510532,"count":0}],"isBlockCoverage":false},{"functionName":"_sendError$2","ranges":[{"startOffset":510552,"endOffset":510680,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":510699,"endOffset":510788,"count":0}],"isBlockCoverage":false},{"functionName":"_createSubscription$4","ranges":[{"startOffset":510942,"endOffset":511156,"count":1}],"isBlockCoverage":true},{"functionName":"get$hashCode","ranges":[{"startOffset":511176,"endOffset":511275,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":511286,"endOffset":511499,"count":0}],"isBlockCoverage":false},{"functionName":"_onCancel$0","ranges":[{"startOffset":511564,"endOffset":511635,"count":1}],"isBlockCoverage":true},{"functionName":"_onPause$0","ranges":[{"startOffset":511653,"endOffset":511716,"count":1}],"isBlockCoverage":true},{"functionName":"_onResume$0","ranges":[{"startOffset":511735,"endOffset":511799,"count":1}],"isBlockCoverage":true},{"functionName":"add$1","ranges":[{"startOffset":511853,"endOffset":511951,"count":1}],"isBlockCoverage":true},{"functionName":"cancel$0","ranges":[{"startOffset":512090,"endOffset":512350,"count":1},{"startOffset":512181,"endOffset":512264,"count":0}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":512427,"endOffset":512562,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":512648,"endOffset":512723,"count":1}],"isBlockCoverage":true},{"functionName":"_BufferingStreamSubscription$4","ranges":[{"startOffset":512883,"endOffset":513035,"count":1}],"isBlockCoverage":true},{"functionName":"_setPendingEvents$1","ranges":[{"startOffset":513062,"endOffset":513518,"count":1}],"isBlockCoverage":true},{"functionName":"onData$1","ranges":[{"startOffset":513534,"endOffset":513897,"count":1}],"isBlockCoverage":true},{"functionName":"onError$1","ranges":[{"startOffset":513914,"endOffset":514590,"count":1},{"startOffset":514246,"endOffset":514584,"count":0}],"isBlockCoverage":true},{"functionName":"onDone$1","ranges":[{"startOffset":514606,"endOffset":514849,"count":1}],"isBlockCoverage":true},{"functionName":"pause$1","ranges":[{"startOffset":514864,"endOffset":515291,"count":1},{"startOffset":514982,"endOffset":514989,"count":0},{"startOffset":515094,"endOffset":515186,"count":0},{"startOffset":515240,"endOffset":515285,"count":0}],"isBlockCoverage":true},{"functionName":"pause$0","ranges":[{"startOffset":515306,"endOffset":515357,"count":1}],"isBlockCoverage":true},{"functionName":"resume$0","ranges":[{"startOffset":515373,"endOffset":516055,"count":1},{"startOffset":515471,"endOffset":515478,"count":0},{"startOffset":515591,"endOffset":515675,"count":0},{"startOffset":515735,"endOffset":515768,"count":0}],"isBlockCoverage":true},{"functionName":"cancel$0","ranges":[{"startOffset":516071,"endOffset":516331,"count":1}],"isBlockCoverage":true},{"functionName":"get$_mayResumeInput","ranges":[{"startOffset":516358,"endOffset":516536,"count":1},{"startOffset":516458,"endOffset":516479,"count":0},{"startOffset":516488,"endOffset":516513,"count":0}],"isBlockCoverage":true},{"functionName":"get$isPaused","ranges":[{"startOffset":516556,"endOffset":516607,"count":1}],"isBlockCoverage":true},{"functionName":"_cancel$0","ranges":[{"startOffset":516624,"endOffset":516954,"count":1}],"isBlockCoverage":true},{"functionName":"_add$1","ranges":[{"startOffset":516968,"endOffset":517413,"count":1},{"startOffset":517222,"endOffset":517229,"count":0},{"startOffset":517281,"endOffset":517407,"count":0}],"isBlockCoverage":true},{"functionName":"_async$_addError$2","ranges":[{"startOffset":517439,"endOffset":517688,"count":0}],"isBlockCoverage":false},{"functionName":"_close$0","ranges":[{"startOffset":517704,"endOffset":518023,"count":0}],"isBlockCoverage":false},{"functionName":"_onPause$0","ranges":[{"startOffset":518041,"endOffset":518106,"count":0}],"isBlockCoverage":false},{"functionName":"_onResume$0","ranges":[{"startOffset":518125,"endOffset":518190,"count":0}],"isBlockCoverage":false},{"functionName":"_onCancel$0","ranges":[{"startOffset":518209,"endOffset":518293,"count":1}],"isBlockCoverage":true},{"functionName":"_addPending$1","ranges":[{"startOffset":518314,"endOffset":518843,"count":0}],"isBlockCoverage":false},{"functionName":"_sendData$1","ranges":[{"startOffset":518862,"endOffset":519379,"count":1}],"isBlockCoverage":true},{"functionName":"_sendError$2","ranges":[{"startOffset":519399,"endOffset":520116,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":520135,"endOffset":520625,"count":0}],"isBlockCoverage":false},{"functionName":"_guardCallback$1","ranges":[{"startOffset":520649,"endOffset":520983,"count":1}],"isBlockCoverage":true},{"functionName":"_checkState$1","ranges":[{"startOffset":521004,"endOffset":522070,"count":1},{"startOffset":521160,"endOffset":521231,"count":0},{"startOffset":521271,"endOffset":521474,"count":0},{"startOffset":521848,"endOffset":521892,"count":0},{"startOffset":522010,"endOffset":522021,"count":0},{"startOffset":522031,"endOffset":522064,"count":0}],"isBlockCoverage":true},{"functionName":"set$_onData","ranges":[{"startOffset":522089,"endOffset":522219,"count":1}],"isBlockCoverage":true},{"functionName":"set$_onDone","ranges":[{"startOffset":522238,"endOffset":522321,"count":1}],"isBlockCoverage":true},{"functionName":"set$_pending","ranges":[{"startOffset":522341,"endOffset":522487,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":522629,"endOffset":523285,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":523388,"endOffset":523626,"count":0}],"isBlockCoverage":false},{"functionName":"listen$4$cancelOnError$onDone$onError","ranges":[{"startOffset":523724,"endOffset":523966,"count":1}],"isBlockCoverage":true},{"functionName":"listen$2$onDone","ranges":[{"startOffset":523989,"endOffset":524106,"count":1}],"isBlockCoverage":true},{"functionName":"listen$3$onDone$onError","ranges":[{"startOffset":524137,"endOffset":524266,"count":1}],"isBlockCoverage":true},{"functionName":"listen$1","ranges":[{"startOffset":524282,"endOffset":524389,"count":1}],"isBlockCoverage":true},{"functionName":"_createSubscription$4","ranges":[{"startOffset":524418,"endOffset":524671,"count":0}],"isBlockCoverage":false},{"functionName":"_createSubscription$4","ranges":[{"startOffset":524743,"endOffset":525243,"count":1},{"startOffset":524958,"endOffset":525035,"count":0}],"isBlockCoverage":true},{"functionName":"get$isEmpty","ranges":[{"startOffset":525307,"endOffset":525370,"count":1}],"isBlockCoverage":true},{"functionName":"handleNext$1","ranges":[{"startOffset":525390,"endOffset":526251,"count":0}],"isBlockCoverage":false},{"functionName":"set$_async$_iterator","ranges":[{"startOffset":526279,"endOffset":526387,"count":0}],"isBlockCoverage":false},{"functionName":"set$next","ranges":[{"startOffset":526439,"endOffset":526521,"count":0}],"isBlockCoverage":false},{"functionName":"get$next","ranges":[{"startOffset":526537,"endOffset":526579,"count":0}],"isBlockCoverage":false},{"functionName":"perform$1","ranges":[{"startOffset":526631,"endOffset":526743,"count":0}],"isBlockCoverage":false},{"functionName":"perform$1","ranges":[{"startOffset":526796,"endOffset":526880,"count":0}],"isBlockCoverage":false},{"functionName":"perform$1","ranges":[{"startOffset":526932,"endOffset":526988,"count":0}],"isBlockCoverage":false},{"functionName":"get$next","ranges":[{"startOffset":527004,"endOffset":527041,"count":0}],"isBlockCoverage":false},{"functionName":"set$next","ranges":[{"startOffset":527057,"endOffset":527147,"count":0}],"isBlockCoverage":false},{"functionName":"schedule$1","ranges":[{"startOffset":527227,"endOffset":527689,"count":1},{"startOffset":527390,"endOffset":527397,"count":0},{"startOffset":527491,"endOffset":527576,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":527757,"endOffset":527933,"count":1},{"startOffset":527889,"endOffset":527932,"count":0}],"isBlockCoverage":true},{"functionName":"get$isEmpty","ranges":[{"startOffset":528011,"endOffset":528074,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":528087,"endOffset":528355,"count":0}],"isBlockCoverage":false},{"functionName":"handleNext$1","ranges":[{"startOffset":528375,"endOffset":528743,"count":0}],"isBlockCoverage":false},{"functionName":"get$isPaused","ranges":[{"startOffset":528809,"endOffset":528858,"count":0}],"isBlockCoverage":false},{"functionName":"_schedule$0","ranges":[{"startOffset":528877,"endOffset":529080,"count":0}],"isBlockCoverage":false},{"functionName":"onData$1","ranges":[{"startOffset":529096,"endOffset":529175,"count":0}],"isBlockCoverage":false},{"functionName":"onError$1","ranges":[{"startOffset":529192,"endOffset":529224,"count":0}],"isBlockCoverage":false},{"functionName":"onDone$1","ranges":[{"startOffset":529240,"endOffset":529332,"count":0}],"isBlockCoverage":false},{"functionName":"pause$1","ranges":[{"startOffset":529347,"endOffset":529401,"count":0}],"isBlockCoverage":false},{"functionName":"pause$0","ranges":[{"startOffset":529416,"endOffset":529467,"count":0}],"isBlockCoverage":false},{"functionName":"resume$0","ranges":[{"startOffset":529483,"endOffset":529661,"count":0}],"isBlockCoverage":false},{"functionName":"cancel$0","ranges":[{"startOffset":529677,"endOffset":529737,"count":0}],"isBlockCoverage":false},{"functionName":"_sendDone$0","ranges":[{"startOffset":529756,"endOffset":530019,"count":0}],"isBlockCoverage":false},{"functionName":"set$_onDone","ranges":[{"startOffset":530038,"endOffset":530121,"count":0}],"isBlockCoverage":false},{"functionName":"get$isBroadcast","ranges":[{"startOffset":530245,"endOffset":530282,"count":0}],"isBlockCoverage":false},{"functionName":"listen$4$cancelOnError$onDone$onError","ranges":[{"startOffset":530327,"endOffset":530684,"count":0}],"isBlockCoverage":false},{"functionName":"listen$3$onDone$onError","ranges":[{"startOffset":530715,"endOffset":530844,"count":0}],"isBlockCoverage":false},{"functionName":"listen$1","ranges":[{"startOffset":530860,"endOffset":530967,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":531027,"endOffset":531117,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":531203,"endOffset":531339,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":531418,"endOffset":531486,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":531582,"endOffset":531631,"count":0}],"isBlockCoverage":false},{"functionName":"handleUncaughtError$3","ranges":[{"startOffset":531905,"endOffset":532247,"count":0}],"isBlockCoverage":false},{"functionName":"registerCallback$1$2","ranges":[{"startOffset":532275,"endOffset":532668,"count":1}],"isBlockCoverage":true},{"functionName":"registerUnaryCallback$2$2","ranges":[{"startOffset":532701,"endOffset":533146,"count":1}],"isBlockCoverage":true},{"functionName":"registerBinaryCallback$3$2","ranges":[{"startOffset":533180,"endOffset":533670,"count":1}],"isBlockCoverage":true},{"functionName":"errorCallback$3","ranges":[{"startOffset":533693,"endOffset":534015,"count":0}],"isBlockCoverage":false},{"functionName":"get$_delegate","ranges":[{"startOffset":534130,"endOffset":534287,"count":1}],"isBlockCoverage":true},{"functionName":"get$errorZone","ranges":[{"startOffset":534308,"endOffset":534371,"count":1}],"isBlockCoverage":true},{"functionName":"runGuarded$1","ranges":[{"startOffset":534391,"endOffset":534691,"count":1},{"startOffset":534526,"endOffset":534685,"count":0}],"isBlockCoverage":true},{"functionName":"runUnaryGuarded$1$2","ranges":[{"startOffset":534718,"endOffset":535062,"count":1},{"startOffset":534897,"endOffset":535056,"count":0}],"isBlockCoverage":true},{"functionName":"runBinaryGuarded$2$3","ranges":[{"startOffset":535090,"endOffset":535511,"count":0}],"isBlockCoverage":false},{"functionName":"bindCallback$1$1","ranges":[{"startOffset":535535,"endOffset":535681,"count":1}],"isBlockCoverage":true},{"functionName":"bindUnaryCallback$2$1","ranges":[{"startOffset":535710,"endOffset":535907,"count":0}],"isBlockCoverage":false},{"functionName":"bindCallbackGuarded$1","ranges":[{"startOffset":535936,"endOffset":536091,"count":1}],"isBlockCoverage":true},{"functionName":"bindUnaryCallbackGuarded$1$1","ranges":[{"startOffset":536127,"endOffset":536303,"count":1}],"isBlockCoverage":true},{"functionName":"$index","ranges":[{"startOffset":536317,"endOffset":536623,"count":1}],"isBlockCoverage":true},{"functionName":"handleUncaughtError$2","ranges":[{"startOffset":536652,"endOffset":537041,"count":0}],"isBlockCoverage":false},{"functionName":"fork$2$specification$zoneValues","ranges":[{"startOffset":537080,"endOffset":537413,"count":1}],"isBlockCoverage":true},{"functionName":"run$1$1","ranges":[{"startOffset":537428,"endOffset":537846,"count":1}],"isBlockCoverage":true},{"functionName":"runUnary$2$2","ranges":[{"startOffset":537866,"endOffset":538372,"count":1}],"isBlockCoverage":true},{"functionName":"runBinary$3$3","ranges":[{"startOffset":538393,"endOffset":538980,"count":0}],"isBlockCoverage":false},{"functionName":"registerCallback$1$1","ranges":[{"startOffset":539008,"endOffset":539469,"count":1}],"isBlockCoverage":true},{"functionName":"registerUnaryCallback$2$1","ranges":[{"startOffset":539502,"endOffset":540015,"count":1}],"isBlockCoverage":true},{"functionName":"registerBinaryCallback$3$1","ranges":[{"startOffset":540049,"endOffset":540607,"count":1}],"isBlockCoverage":true},{"functionName":"errorCallback$2","ranges":[{"startOffset":540630,"endOffset":541146,"count":0}],"isBlockCoverage":false},{"functionName":"scheduleMicrotask$1","ranges":[{"startOffset":541173,"endOffset":541522,"count":1}],"isBlockCoverage":true},{"functionName":"createTimer$2","ranges":[{"startOffset":541543,"endOffset":541906,"count":1}],"isBlockCoverage":true},{"functionName":"print$1","ranges":[{"startOffset":541921,"endOffset":542216,"count":0}],"isBlockCoverage":false},{"functionName":"set$_run","ranges":[{"startOffset":542232,"endOffset":542315,"count":1}],"isBlockCoverage":true},{"functionName":"set$_runUnary","ranges":[{"startOffset":542336,"endOffset":542434,"count":1}],"isBlockCoverage":true},{"functionName":"set$_runBinary","ranges":[{"startOffset":542456,"endOffset":542557,"count":1}],"isBlockCoverage":true},{"functionName":"set$_registerCallback","ranges":[{"startOffset":542586,"endOffset":542708,"count":1}],"isBlockCoverage":true},{"functionName":"set$_registerUnaryCallback","ranges":[{"startOffset":542742,"endOffset":542879,"count":1}],"isBlockCoverage":true},{"functionName":"set$_registerBinaryCallback","ranges":[{"startOffset":542914,"endOffset":543054,"count":1}],"isBlockCoverage":true},{"functionName":"set$_errorCallback","ranges":[{"startOffset":543080,"endOffset":543248,"count":1}],"isBlockCoverage":true},{"functionName":"set$_scheduleMicrotask","ranges":[{"startOffset":543278,"endOffset":543462,"count":1}],"isBlockCoverage":true},{"functionName":"set$_createTimer","ranges":[{"startOffset":543486,"endOffset":543666,"count":1}],"isBlockCoverage":true},{"functionName":"set$_createPeriodicTimer","ranges":[{"startOffset":543698,"endOffset":543908,"count":1}],"isBlockCoverage":true},{"functionName":"set$_print","ranges":[{"startOffset":543926,"endOffset":544053,"count":1}],"isBlockCoverage":true},{"functionName":"set$_fork","ranges":[{"startOffset":544070,"endOffset":544243,"count":1}],"isBlockCoverage":true},{"functionName":"set$_handleUncaughtError","ranges":[{"startOffset":544275,"endOffset":544455,"count":1}],"isBlockCoverage":true},{"functionName":"get$_run","ranges":[{"startOffset":544471,"endOffset":544513,"count":1}],"isBlockCoverage":true},{"functionName":"get$_runUnary","ranges":[{"startOffset":544534,"endOffset":544581,"count":1}],"isBlockCoverage":true},{"functionName":"get$_runBinary","ranges":[{"startOffset":544603,"endOffset":544651,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerCallback","ranges":[{"startOffset":544680,"endOffset":544735,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerUnaryCallback","ranges":[{"startOffset":544769,"endOffset":544829,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerBinaryCallback","ranges":[{"startOffset":544864,"endOffset":544925,"count":1}],"isBlockCoverage":true},{"functionName":"get$_errorCallback","ranges":[{"startOffset":544951,"endOffset":545003,"count":1}],"isBlockCoverage":true},{"functionName":"get$_scheduleMicrotask","ranges":[{"startOffset":545033,"endOffset":545089,"count":1}],"isBlockCoverage":true},{"functionName":"get$_createTimer","ranges":[{"startOffset":545113,"endOffset":545163,"count":1}],"isBlockCoverage":true},{"functionName":"get$_createPeriodicTimer","ranges":[{"startOffset":545195,"endOffset":545253,"count":1}],"isBlockCoverage":true},{"functionName":"get$_print","ranges":[{"startOffset":545271,"endOffset":545315,"count":1}],"isBlockCoverage":true},{"functionName":"get$_fork","ranges":[{"startOffset":545332,"endOffset":545375,"count":1}],"isBlockCoverage":true},{"functionName":"get$_handleUncaughtError","ranges":[{"startOffset":545407,"endOffset":545465,"count":1}],"isBlockCoverage":true},{"functionName":"get$parent","ranges":[{"startOffset":545483,"endOffset":545535,"count":1}],"isBlockCoverage":true},{"functionName":"get$_async$_map","ranges":[{"startOffset":545558,"endOffset":545607,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":545676,"endOffset":545752,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":545770,"endOffset":545824,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":545898,"endOffset":546051,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":546069,"endOffset":546156,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":546232,"endOffset":546305,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":546405,"endOffset":546531,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":546549,"endOffset":546604,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":546673,"endOffset":546999,"count":0}],"isBlockCoverage":false},{"functionName":"get$_run","ranges":[{"startOffset":547066,"endOffset":547133,"count":1}],"isBlockCoverage":true},{"functionName":"get$_runUnary","ranges":[{"startOffset":547154,"endOffset":547226,"count":1}],"isBlockCoverage":true},{"functionName":"get$_runBinary","ranges":[{"startOffset":547248,"endOffset":547321,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerCallback","ranges":[{"startOffset":547350,"endOffset":547430,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerUnaryCallback","ranges":[{"startOffset":547464,"endOffset":547516,"count":1}],"isBlockCoverage":true},{"functionName":"get$_registerBinaryCallback","ranges":[{"startOffset":547551,"endOffset":547603,"count":1}],"isBlockCoverage":true},{"functionName":"get$_errorCallback","ranges":[{"startOffset":547629,"endOffset":547706,"count":1}],"isBlockCoverage":true},{"functionName":"get$_scheduleMicrotask","ranges":[{"startOffset":547736,"endOffset":547817,"count":1}],"isBlockCoverage":true},{"functionName":"get$_createTimer","ranges":[{"startOffset":547841,"endOffset":547916,"count":1}],"isBlockCoverage":true},{"functionName":"get$_createPeriodicTimer","ranges":[{"startOffset":547948,"endOffset":548000,"count":1}],"isBlockCoverage":true},{"functionName":"get$_print","ranges":[{"startOffset":548018,"endOffset":548087,"count":1}],"isBlockCoverage":true},{"functionName":"get$_fork","ranges":[{"startOffset":548104,"endOffset":548172,"count":1}],"isBlockCoverage":true},{"functionName":"get$_handleUncaughtError","ranges":[{"startOffset":548204,"endOffset":548256,"count":1}],"isBlockCoverage":true},{"functionName":"get$parent","ranges":[{"startOffset":548274,"endOffset":548312,"count":1}],"isBlockCoverage":true},{"functionName":"get$_async$_map","ranges":[{"startOffset":548335,"endOffset":548395,"count":0}],"isBlockCoverage":false},{"functionName":"get$_delegate","ranges":[{"startOffset":548416,"endOffset":548585,"count":0}],"isBlockCoverage":false},{"functionName":"get$errorZone","ranges":[{"startOffset":548606,"endOffset":548643,"count":1}],"isBlockCoverage":true},{"functionName":"runGuarded$1","ranges":[{"startOffset":548663,"endOffset":549139,"count":0}],"isBlockCoverage":false},{"functionName":"runUnaryGuarded$1$2","ranges":[{"startOffset":549166,"endOffset":549689,"count":1},{"startOffset":549479,"endOffset":549683,"count":0}],"isBlockCoverage":true},{"functionName":"runBinaryGuarded$2$3","ranges":[{"startOffset":549717,"endOffset":550324,"count":0}],"isBlockCoverage":false},{"functionName":"bindCallback$1$1","ranges":[{"startOffset":550348,"endOffset":550461,"count":0}],"isBlockCoverage":false},{"functionName":"bindCallbackGuarded$1","ranges":[{"startOffset":550490,"endOffset":550604,"count":0}],"isBlockCoverage":false},{"functionName":"bindUnaryCallbackGuarded$1$1","ranges":[{"startOffset":550640,"endOffset":550766,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":550780,"endOffset":550823,"count":0}],"isBlockCoverage":false},{"functionName":"handleUncaughtError$2","ranges":[{"startOffset":550852,"endOffset":550983,"count":0}],"isBlockCoverage":false},{"functionName":"fork$2$specification$zoneValues","ranges":[{"startOffset":551022,"endOffset":551136,"count":1}],"isBlockCoverage":true},{"functionName":"run$1$1","ranges":[{"startOffset":551151,"endOffset":551331,"count":0}],"isBlockCoverage":false},{"functionName":"runUnary$2$2","ranges":[{"startOffset":551351,"endOffset":551608,"count":1},{"startOffset":551538,"endOffset":551607,"count":0}],"isBlockCoverage":true},{"functionName":"runBinary$3$3","ranges":[{"startOffset":551629,"endOffset":551954,"count":0}],"isBlockCoverage":false},{"functionName":"registerCallback$1$1","ranges":[{"startOffset":551982,"endOffset":552047,"count":1}],"isBlockCoverage":true},{"functionName":"registerUnaryCallback$2$1","ranges":[{"startOffset":552080,"endOffset":552178,"count":1}],"isBlockCoverage":true},{"functionName":"registerBinaryCallback$3$1","ranges":[{"startOffset":552212,"endOffset":552328,"count":1}],"isBlockCoverage":true},{"functionName":"errorCallback$2","ranges":[{"startOffset":552351,"endOffset":552448,"count":0}],"isBlockCoverage":false},{"functionName":"scheduleMicrotask$1","ranges":[{"startOffset":552475,"endOffset":552575,"count":1}],"isBlockCoverage":true},{"functionName":"createTimer$2","ranges":[{"startOffset":552596,"endOffset":552701,"count":0}],"isBlockCoverage":false},{"functionName":"print$1","ranges":[{"startOffset":552716,"endOffset":552768,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":552835,"endOffset":552902,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":552920,"endOffset":552974,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":553048,"endOffset":553112,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":553210,"endOffset":553327,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":553345,"endOffset":553400,"count":0}],"isBlockCoverage":false},{"functionName":"call$5","ranges":[{"startOffset":553453,"endOffset":554320,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":554389,"endOffset":554447,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":554466,"endOffset":554530,"count":0}],"isBlockCoverage":false},{"functionName":"get$keys","ranges":[{"startOffset":554546,"endOffset":554667,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":554688,"endOffset":555100,"count":1},{"startOffset":554860,"endOffset":554882,"count":0},{"startOffset":554924,"endOffset":554953,"count":0},{"startOffset":554955,"endOffset":555048,"count":0}],"isBlockCoverage":true},{"functionName":"_containsKey$1","ranges":[{"startOffset":555122,"endOffset":555308,"count":1}],"isBlockCoverage":true},{"functionName":"$index","ranges":[{"startOffset":555322,"endOffset":555803,"count":1},{"startOffset":555403,"endOffset":555425,"count":0},{"startOffset":555427,"endOffset":555567,"count":0},{"startOffset":555600,"endOffset":555629,"count":0},{"startOffset":555631,"endOffset":555759,"count":0}],"isBlockCoverage":true},{"functionName":"_get$1","ranges":[{"startOffset":555817,"endOffset":556095,"count":1},{"startOffset":555929,"endOffset":555941,"count":0}],"isBlockCoverage":true},{"functionName":"$indexSet","ranges":[{"startOffset":556112,"endOffset":556762,"count":1},{"startOffset":556316,"endOffset":556338,"count":0},{"startOffset":556340,"endOffset":556504,"count":0},{"startOffset":556537,"endOffset":556566,"count":0},{"startOffset":556568,"endOffset":556717,"count":0}],"isBlockCoverage":true},{"functionName":"_set$2","ranges":[{"startOffset":556776,"endOffset":557585,"count":1},{"startOffset":557442,"endOffset":557571,"count":0}],"isBlockCoverage":true},{"functionName":"remove$1","ranges":[{"startOffset":557601,"endOffset":557678,"count":0}],"isBlockCoverage":false},{"functionName":"_remove$1","ranges":[{"startOffset":557695,"endOffset":558203,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":558220,"endOffset":558693,"count":0}],"isBlockCoverage":false},{"functionName":"_computeKeys$0","ranges":[{"startOffset":558715,"endOffset":560019,"count":0}],"isBlockCoverage":false},{"functionName":"_addHashTableEntry$3","ranges":[{"startOffset":560047,"endOffset":560344,"count":0}],"isBlockCoverage":false},{"functionName":"_computeHashCode$1","ranges":[{"startOffset":560370,"endOffset":560439,"count":1}],"isBlockCoverage":true},{"functionName":"_getBucket$2","ranges":[{"startOffset":560459,"endOffset":560537,"count":1}],"isBlockCoverage":true},{"functionName":"_findBucketIndex$2","ranges":[{"startOffset":560563,"endOffset":560802,"count":1},{"startOffset":560779,"endOffset":560801,"count":0}],"isBlockCoverage":true},{"functionName":"_computeHashCode$1","ranges":[{"startOffset":560867,"endOffset":560937,"count":1}],"isBlockCoverage":true},{"functionName":"_findBucketIndex$2","ranges":[{"startOffset":560963,"endOffset":561255,"count":1},{"startOffset":561057,"endOffset":561254,"count":0}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":561315,"endOffset":561378,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":561397,"endOffset":561466,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":561486,"endOffset":561640,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":561658,"endOffset":561733,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":561794,"endOffset":561852,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":561870,"endOffset":562335,"count":0}],"isBlockCoverage":false},{"functionName":"set$_collection$_current","ranges":[{"startOffset":562367,"endOffset":562468,"count":0}],"isBlockCoverage":false},{"functionName":"_newSet$0","ranges":[{"startOffset":562542,"endOffset":562647,"count":1}],"isBlockCoverage":true},{"functionName":"get$iterator","ranges":[{"startOffset":562667,"endOffset":562927,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":562945,"endOffset":563003,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":563022,"endOffset":563086,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":563104,"endOffset":563663,"count":1},{"startOffset":563301,"endOffset":563382,"count":0},{"startOffset":563533,"endOffset":563657,"count":0}],"isBlockCoverage":true},{"functionName":"_contains$1","ranges":[{"startOffset":563682,"endOffset":563883,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":563900,"endOffset":564112,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":564128,"endOffset":564339,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":564352,"endOffset":565009,"count":1},{"startOffset":564713,"endOffset":565003,"count":0}],"isBlockCoverage":true},{"functionName":"_collection$_add$1","ranges":[{"startOffset":565035,"endOffset":565721,"count":0}],"isBlockCoverage":false},{"functionName":"remove$1","ranges":[{"startOffset":565737,"endOffset":566117,"count":1},{"startOffset":565819,"endOffset":565844,"count":0},{"startOffset":565854,"endOffset":565915,"count":0},{"startOffset":566060,"endOffset":566111,"count":0}],"isBlockCoverage":true},{"functionName":"_remove$1","ranges":[{"startOffset":566134,"endOffset":566619,"count":0}],"isBlockCoverage":false},{"functionName":"_addHashTableEntry$2","ranges":[{"startOffset":566647,"endOffset":566913,"count":1},{"startOffset":566808,"endOffset":566821,"count":0}],"isBlockCoverage":true},{"functionName":"_removeHashTableEntry$2","ranges":[{"startOffset":566944,"endOffset":567227,"count":1},{"startOffset":567033,"endOffset":567226,"count":0}],"isBlockCoverage":true},{"functionName":"_collection$_modified$0","ranges":[{"startOffset":567258,"endOffset":567366,"count":1}],"isBlockCoverage":true},{"functionName":"_collection$_newLinkedCell$1","ranges":[{"startOffset":567402,"endOffset":567925,"count":1}],"isBlockCoverage":true},{"functionName":"_unlinkCell$1","ranges":[{"startOffset":567946,"endOffset":568524,"count":0}],"isBlockCoverage":false},{"functionName":"_computeHashCode$1","ranges":[{"startOffset":568550,"endOffset":568627,"count":0}],"isBlockCoverage":false},{"functionName":"_findBucketIndex$2","ranges":[{"startOffset":568653,"endOffset":568906,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":569034,"endOffset":569092,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":569110,"endOffset":569695,"count":1},{"startOffset":569258,"endOffset":569316,"count":0},{"startOffset":569475,"endOffset":569681,"count":0}],"isBlockCoverage":true},{"functionName":"set$_collection$_current","ranges":[{"startOffset":569727,"endOffset":569828,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":569909,"endOffset":570001,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":570015,"endOffset":570118,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":570183,"endOffset":570273,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":570402,"endOffset":570492,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":570649,"endOffset":570808,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":570827,"endOffset":570903,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":570922,"endOffset":570994,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":571011,"endOffset":571186,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":571202,"endOffset":571405,"count":0}],"isBlockCoverage":false},{"functionName":"map$1$1","ranges":[{"startOffset":571420,"endOffset":571672,"count":0}],"isBlockCoverage":false},{"functionName":"toList$1$growable","ranges":[{"startOffset":571697,"endOffset":572067,"count":0}],"isBlockCoverage":false},{"functionName":"toList$0","ranges":[{"startOffset":572083,"endOffset":572164,"count":0}],"isBlockCoverage":false},{"functionName":"toSet$0","ranges":[{"startOffset":572179,"endOffset":572441,"count":0}],"isBlockCoverage":false},{"functionName":"remove$1","ranges":[{"startOffset":572457,"endOffset":572717,"count":0}],"isBlockCoverage":false},{"functionName":"_closeGap$2","ranges":[{"startOffset":572736,"endOffset":573112,"count":0}],"isBlockCoverage":false},{"functionName":"fillRange$3","ranges":[{"startOffset":573131,"endOffset":573410,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":573428,"endOffset":573524,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":573616,"endOffset":573883,"count":0}],"isBlockCoverage":false},{"functionName":"cast$2$0","ranges":[{"startOffset":573949,"endOffset":574109,"count":1}],"isBlockCoverage":true},{"functionName":"forEach$1","ranges":[{"startOffset":574126,"endOffset":574420,"count":0}],"isBlockCoverage":false},{"functionName":"map$2$1","ranges":[{"startOffset":574435,"endOffset":574940,"count":1}],"isBlockCoverage":true},{"functionName":"containsKey$1","ranges":[{"startOffset":574961,"endOffset":575031,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":575049,"endOffset":575132,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":575151,"endOffset":575235,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":575253,"endOffset":575314,"count":0}],"isBlockCoverage":false},{"functionName":"remove$1","ranges":[{"startOffset":575389,"endOffset":575497,"count":0}],"isBlockCoverage":false},{"functionName":"cast$2$0","ranges":[{"startOffset":575543,"endOffset":575614,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":575628,"endOffset":575691,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":575712,"endOffset":575776,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":575793,"endOffset":575906,"count":1}],"isBlockCoverage":true},{"functionName":"get$isEmpty","ranges":[{"startOffset":575925,"endOffset":576003,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":576021,"endOffset":576098,"count":0}],"isBlockCoverage":false},{"functionName":"get$keys","ranges":[{"startOffset":576114,"endOffset":576167,"count":0}],"isBlockCoverage":false},{"functionName":"remove$1","ranges":[{"startOffset":576183,"endOffset":576248,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":576266,"endOffset":576323,"count":0}],"isBlockCoverage":false},{"functionName":"map$2$1","ranges":[{"startOffset":576338,"endOffset":576514,"count":1}],"isBlockCoverage":true},{"functionName":"cast$2$0","ranges":[{"startOffset":576587,"endOffset":576753,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":576805,"endOffset":576990,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":577009,"endOffset":577068,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":577086,"endOffset":577176,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":577193,"endOffset":577451,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":577467,"endOffset":577803,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":577822,"endOffset":578227,"count":0}],"isBlockCoverage":false},{"functionName":"clear$0","ranges":[{"startOffset":578242,"endOffset":578565,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":578583,"endOffset":578668,"count":0}],"isBlockCoverage":false},{"functionName":"removeFirst$0","ranges":[{"startOffset":578689,"endOffset":579148,"count":1},{"startOffset":578802,"endOffset":578860,"count":0},{"startOffset":578955,"endOffset":578978,"count":0}],"isBlockCoverage":true},{"functionName":"_collection$_add$1","ranges":[{"startOffset":579174,"endOffset":580057,"count":1},{"startOffset":579524,"endOffset":580017,"count":0}],"isBlockCoverage":true},{"functionName":"set$_table","ranges":[{"startOffset":580075,"endOffset":580163,"count":1}],"isBlockCoverage":true},{"functionName":"get$current","ranges":[{"startOffset":580240,"endOffset":580298,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":580316,"endOffset":580875,"count":0}],"isBlockCoverage":false},{"functionName":"set$_collection$_current","ranges":[{"startOffset":580907,"endOffset":581008,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":581078,"endOffset":581139,"count":0}],"isBlockCoverage":false},{"functionName":"map$1$1","ranges":[{"startOffset":581154,"endOffset":581394,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":581412,"endOffset":581497,"count":0}],"isBlockCoverage":false},{"functionName":"every$1","ranges":[{"startOffset":581512,"endOffset":581772,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":581789,"endOffset":581974,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":581990,"endOffset":582256,"count":0}],"isBlockCoverage":false},{"functionName":"toSet$0","ranges":[{"startOffset":582456,"endOffset":582553,"count":1}],"isBlockCoverage":true},{"functionName":"get$isEmpty","ranges":[{"startOffset":582572,"endOffset":582636,"count":0}],"isBlockCoverage":false},{"functionName":"addAll$1","ranges":[{"startOffset":582652,"endOffset":582872,"count":1},{"startOffset":582834,"endOffset":582866,"count":0}],"isBlockCoverage":true},{"functionName":"union$1","ranges":[{"startOffset":582887,"endOffset":583059,"count":1}],"isBlockCoverage":true},{"functionName":"toList$1$growable","ranges":[{"startOffset":583084,"endOffset":583579,"count":1},{"startOffset":583450,"endOffset":583552,"count":0}],"isBlockCoverage":true},{"functionName":"toList$0","ranges":[{"startOffset":583595,"endOffset":583676,"count":1}],"isBlockCoverage":true},{"functionName":"map$1$1","ranges":[{"startOffset":583691,"endOffset":583931,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":583949,"endOffset":584034,"count":0}],"isBlockCoverage":false},{"functionName":"where$1","ranges":[{"startOffset":584049,"endOffset":584214,"count":1}],"isBlockCoverage":true},{"functionName":"fold$1$2","ranges":[{"startOffset":584230,"endOffset":584642,"count":0}],"isBlockCoverage":false},{"functionName":"every$1","ranges":[{"startOffset":584657,"endOffset":584988,"count":0}],"isBlockCoverage":false},{"functionName":"any$1","ranges":[{"startOffset":585001,"endOffset":585340,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":585357,"endOffset":585627,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":585643,"endOffset":585994,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":586272,"endOffset":586605,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":586623,"endOffset":586845,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":586864,"endOffset":586925,"count":0}],"isBlockCoverage":false},{"functionName":"get$keys","ranges":[{"startOffset":586941,"endOffset":587091,"count":0}],"isBlockCoverage":false},{"functionName":"containsKey$1","ranges":[{"startOffset":587112,"endOffset":587355,"count":0}],"isBlockCoverage":false},{"functionName":"remove$1","ranges":[{"startOffset":587371,"endOffset":587528,"count":0}],"isBlockCoverage":false},{"functionName":"forEach$1","ranges":[{"startOffset":587545,"endOffset":588211,"count":0}],"isBlockCoverage":false},{"functionName":"get$_upgradedMap","ranges":[{"startOffset":588235,"endOffset":588325,"count":0}],"isBlockCoverage":false},{"functionName":"_convert$_computeKeys$0","ranges":[{"startOffset":588356,"endOffset":588651,"count":0}],"isBlockCoverage":false},{"functionName":"_upgrade$0","ranges":[{"startOffset":588669,"endOffset":589287,"count":0}],"isBlockCoverage":false},{"functionName":"_process$1","ranges":[{"startOffset":589305,"endOffset":589541,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":589601,"endOffset":589681,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":589700,"endOffset":590025,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":590045,"endOffset":590376,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":590394,"endOffset":590464,"count":0}],"isBlockCoverage":false},{"functionName":"encode$1","ranges":[{"startOffset":590513,"endOffset":590588,"count":0}],"isBlockCoverage":false},{"functionName":"convert$1","ranges":[{"startOffset":590649,"endOffset":591298,"count":0}],"isBlockCoverage":false},{"functionName":"normalize$3","ranges":[{"startOffset":591384,"endOffset":595104,"count":0}],"isBlockCoverage":false},{"functionName":"decode$2$reviver","ranges":[{"startOffset":595311,"endOffset":595497,"count":0}],"isBlockCoverage":false},{"functionName":"get$decoder","ranges":[{"startOffset":595516,"endOffset":595567,"count":0}],"isBlockCoverage":false},{"functionName":"get$encoder","ranges":[{"startOffset":595650,"endOffset":595698,"count":0}],"isBlockCoverage":false},{"functionName":"convert$1","ranges":[{"startOffset":595749,"endOffset":596529,"count":0}],"isBlockCoverage":false},{"functionName":"_writeSurrogate$2","ranges":[{"startOffset":596589,"endOffset":598037,"count":0}],"isBlockCoverage":false},{"functionName":"_fillBuffer$3","ranges":[{"startOffset":598058,"endOffset":599908,"count":0}],"isBlockCoverage":false},{"functionName":"convert$1","ranges":[{"startOffset":599959,"endOffset":601081,"count":0}],"isBlockCoverage":false},{"functionName":"flush$2","ranges":[{"startOffset":601131,"endOffset":601378,"count":0}],"isBlockCoverage":false},{"functionName":"convert$3","ranges":[{"startOffset":601395,"endOffset":605325,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":605392,"endOffset":605547,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":605567,"endOffset":605692,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":605710,"endOffset":606328,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":606397,"endOffset":606550,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":606570,"endOffset":606648,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":606666,"endOffset":607284,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":607348,"endOffset":607623,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":607707,"endOffset":607790,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":607891,"endOffset":608058,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":608077,"endOffset":608130,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":608186,"endOffset":608236,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorName","ranges":[{"startOffset":608294,"endOffset":608378,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorExplanation","ranges":[{"startOffset":608407,"endOffset":608442,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":608460,"endOffset":608982,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":609001,"endOffset":609054,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorName","ranges":[{"startOffset":609109,"endOffset":609154,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorExplanation","ranges":[{"startOffset":609183,"endOffset":609833,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorName","ranges":[{"startOffset":609888,"endOffset":609933,"count":0}],"isBlockCoverage":false},{"functionName":"get$_errorExplanation","ranges":[{"startOffset":609962,"endOffset":610401,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":610419,"endOffset":610471,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":610528,"endOffset":610602,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":610621,"endOffset":610674,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":610733,"endOffset":610859,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":610878,"endOffset":610931,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":610982,"endOffset":611044,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":611063,"endOffset":611116,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":611184,"endOffset":611413,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":611470,"endOffset":611519,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":611595,"endOffset":611645,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":611728,"endOffset":611927,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":611978,"endOffset":612040,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":612080,"endOffset":612133,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":612189,"endOffset":614795,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":614835,"endOffset":614888,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":614932,"endOffset":615559,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":615576,"endOffset":616073,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":616091,"endOffset":616147,"count":0}],"isBlockCoverage":false},{"functionName":"map$1$1","ranges":[{"startOffset":616246,"endOffset":616443,"count":0}],"isBlockCoverage":false},{"functionName":"where$1","ranges":[{"startOffset":616458,"endOffset":616647,"count":1}],"isBlockCoverage":true},{"functionName":"contains$1","ranges":[{"startOffset":616665,"endOffset":616856,"count":0}],"isBlockCoverage":false},{"functionName":"join$1","ranges":[{"startOffset":616870,"endOffset":617364,"count":0}],"isBlockCoverage":false},{"functionName":"join$0","ranges":[{"startOffset":617378,"endOffset":617446,"count":0}],"isBlockCoverage":false},{"functionName":"toList$1$growable","ranges":[{"startOffset":617471,"endOffset":617588,"count":0}],"isBlockCoverage":false},{"functionName":"toList$0","ranges":[{"startOffset":617604,"endOffset":617685,"count":0}],"isBlockCoverage":false},{"functionName":"toSet$0","ranges":[{"startOffset":617700,"endOffset":617819,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":617837,"endOffset":618062,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":618081,"endOffset":618152,"count":0}],"isBlockCoverage":false},{"functionName":"skipWhile$1","ranges":[{"startOffset":618171,"endOffset":618368,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":618385,"endOffset":618570,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":618586,"endOffset":618852,"count":0}],"isBlockCoverage":false},{"functionName":"elementAt$1","ranges":[{"startOffset":618871,"endOffset":619282,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":619300,"endOffset":619386,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":619558,"endOffset":619650,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":619697,"endOffset":619779,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":619797,"endOffset":619837,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":619937,"endOffset":619992,"count":1}],"isBlockCoverage":true},{"functionName":"get$hashCode","ranges":[{"startOffset":620012,"endOffset":620079,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":620097,"endOffset":620193,"count":0}],"isBlockCoverage":false},{"functionName":"get$runtimeType","ranges":[{"startOffset":620216,"endOffset":620272,"count":0}],"isBlockCoverage":false},{"functionName":"toString","ranges":[{"startOffset":620288,"endOffset":620342,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":620552,"endOffset":620602,"count":0}],"isBlockCoverage":false},{"functionName":"get$elapsedMicroseconds","ranges":[{"startOffset":620687,"endOffset":621099,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":621187,"endOffset":621252,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":621268,"endOffset":621758,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":621812,"endOffset":621867,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":621885,"endOffset":622720,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":622793,"endOffset":622848,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":622866,"endOffset":622962,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":623072,"endOffset":623205,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":623288,"endOffset":623421,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":623435,"endOffset":623493,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":623579,"endOffset":624044,"count":0}],"isBlockCoverage":false},{"functionName":"get$userInfo","ranges":[{"startOffset":624111,"endOffset":624158,"count":0}],"isBlockCoverage":false},{"functionName":"get$host","ranges":[{"startOffset":624174,"endOffset":624399,"count":0}],"isBlockCoverage":false},{"functionName":"get$port","ranges":[{"startOffset":624415,"endOffset":624549,"count":0}],"isBlockCoverage":false},{"functionName":"get$query","ranges":[{"startOffset":624566,"endOffset":624647,"count":0}],"isBlockCoverage":false},{"functionName":"get$fragment","ranges":[{"startOffset":624667,"endOffset":624751,"count":0}],"isBlockCoverage":false},{"functionName":"replace$2$path$pathSegments","ranges":[{"startOffset":624786,"endOffset":625788,"count":0}],"isBlockCoverage":false},{"functionName":"replace$1$path","ranges":[{"startOffset":625810,"endOffset":625913,"count":0}],"isBlockCoverage":false},{"functionName":"replace$1$pathSegments","ranges":[{"startOffset":625943,"endOffset":626062,"count":0}],"isBlockCoverage":false},{"functionName":"get$pathSegments","ranges":[{"startOffset":626086,"endOffset":626770,"count":0}],"isBlockCoverage":false},{"functionName":"_mergePaths$2","ranges":[{"startOffset":626791,"endOffset":627849,"count":0}],"isBlockCoverage":false},{"functionName":"resolve$1","ranges":[{"startOffset":627866,"endOffset":627949,"count":0}],"isBlockCoverage":false},{"functionName":"resolveUri$1","ranges":[{"startOffset":627969,"endOffset":630843,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasAuthority","ranges":[{"startOffset":630867,"endOffset":630918,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasPort","ranges":[{"startOffset":630937,"endOffset":630988,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasQuery","ranges":[{"startOffset":631008,"endOffset":631060,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasFragment","ranges":[{"startOffset":631083,"endOffset":631138,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasAbsolutePath","ranges":[{"startOffset":631165,"endOffset":631245,"count":0}],"isBlockCoverage":false},{"functionName":"toFilePath$0","ranges":[{"startOffset":631265,"endOffset":632530,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":632548,"endOffset":633376,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":633387,"endOffset":634982,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":635002,"endOffset":635163,"count":0}],"isBlockCoverage":false},{"functionName":"set$_pathSegments","ranges":[{"startOffset":635188,"endOffset":635287,"count":0}],"isBlockCoverage":false},{"functionName":"get$scheme","ranges":[{"startOffset":635320,"endOffset":635364,"count":0}],"isBlockCoverage":false},{"functionName":"get$path","ranges":[{"startOffset":635380,"endOffset":635430,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":635494,"endOffset":635608,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":635716,"endOffset":636051,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":636130,"endOffset":636243,"count":0}],"isBlockCoverage":false},{"functionName":"get$uri","ranges":[{"startOffset":636307,"endOffset":637019,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":637037,"endOffset":637234,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":637292,"endOffset":637344,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":637420,"endOffset":637648,"count":1},{"startOffset":637523,"endOffset":637549,"count":0}],"isBlockCoverage":true},{"functionName":"call$3","ranges":[{"startOffset":637727,"endOffset":638030,"count":1},{"startOffset":637956,"endOffset":637983,"count":0}],"isBlockCoverage":true},{"functionName":"call$3","ranges":[{"startOffset":638109,"endOffset":638448,"count":1},{"startOffset":638374,"endOffset":638401,"count":0}],"isBlockCoverage":true},{"functionName":"get$hasAuthority","ranges":[{"startOffset":638525,"endOffset":638577,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasPort","ranges":[{"startOffset":638596,"endOffset":638689,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasQuery","ranges":[{"startOffset":638709,"endOffset":638780,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasFragment","ranges":[{"startOffset":638803,"endOffset":638874,"count":0}],"isBlockCoverage":false},{"functionName":"get$_isFile","ranges":[{"startOffset":638893,"endOffset":639001,"count":0}],"isBlockCoverage":false},{"functionName":"get$_isHttp","ranges":[{"startOffset":639020,"endOffset":639128,"count":0}],"isBlockCoverage":false},{"functionName":"get$_isHttps","ranges":[{"startOffset":639148,"endOffset":639257,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasAbsolutePath","ranges":[{"startOffset":639284,"endOffset":639381,"count":0}],"isBlockCoverage":false},{"functionName":"get$scheme","ranges":[{"startOffset":639399,"endOffset":640155,"count":0}],"isBlockCoverage":false},{"functionName":"get$userInfo","ranges":[{"startOffset":640175,"endOffset":640342,"count":0}],"isBlockCoverage":false},{"functionName":"get$host","ranges":[{"startOffset":640358,"endOffset":640500,"count":0}],"isBlockCoverage":false},{"functionName":"get$port","ranges":[{"startOffset":640516,"endOffset":640832,"count":0}],"isBlockCoverage":false},{"functionName":"get$path","ranges":[{"startOffset":640848,"endOffset":640958,"count":0}],"isBlockCoverage":false},{"functionName":"get$query","ranges":[{"startOffset":640975,"endOffset":641143,"count":0}],"isBlockCoverage":false},{"functionName":"get$fragment","ranges":[{"startOffset":641163,"endOffset":641320,"count":0}],"isBlockCoverage":false},{"functionName":"get$pathSegments","ranges":[{"startOffset":641344,"endOffset":642029,"count":1},{"startOffset":641575,"endOffset":641595,"count":0}],"isBlockCoverage":true},{"functionName":"_isPort$1","ranges":[{"startOffset":642046,"endOffset":642247,"count":0}],"isBlockCoverage":false},{"functionName":"removeFragment$0","ranges":[{"startOffset":642271,"endOffset":642611,"count":0}],"isBlockCoverage":false},{"functionName":"replace$2$path$pathSegments","ranges":[{"startOffset":642646,"endOffset":644260,"count":0}],"isBlockCoverage":false},{"functionName":"replace$1$path","ranges":[{"startOffset":644282,"endOffset":644385,"count":0}],"isBlockCoverage":false},{"functionName":"replace$1$pathSegments","ranges":[{"startOffset":644415,"endOffset":644534,"count":0}],"isBlockCoverage":false},{"functionName":"resolve$1","ranges":[{"startOffset":644551,"endOffset":644634,"count":0}],"isBlockCoverage":false},{"functionName":"resolveUri$1","ranges":[{"startOffset":644654,"endOffset":644839,"count":0}],"isBlockCoverage":false},{"functionName":"_simpleMerge$2","ranges":[{"startOffset":644861,"endOffset":648814,"count":0}],"isBlockCoverage":false},{"functionName":"toFilePath$0","ranges":[{"startOffset":648834,"endOffset":649861,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":649881,"endOffset":650033,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":650044,"endOffset":650236,"count":0}],"isBlockCoverage":false},{"functionName":"_toNonSimple$0","ranges":[{"startOffset":650258,"endOffset":650822,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":650840,"endOffset":650883,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":650995,"endOffset":651052,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":651137,"endOffset":651194,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":651247,"endOffset":651304,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":651323,"endOffset":651380,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":651432,"endOffset":651489,"count":0}],"isBlockCoverage":false},{"functionName":"addEventListener$3","ranges":[{"startOffset":651586,"endOffset":651788,"count":1}],"isBlockCoverage":true},{"functionName":"_addEventListener$3","ranges":[{"startOffset":651815,"endOffset":651995,"count":1}],"isBlockCoverage":true},{"functionName":"_removeEventListener$3","ranges":[{"startOffset":652025,"endOffset":652208,"count":1}],"isBlockCoverage":true},{"functionName":"get$origin","ranges":[{"startOffset":652315,"endOffset":652470,"count":1},{"startOffset":652399,"endOffset":652469,"count":0}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":652488,"endOffset":652545,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":652597,"endOffset":652654,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":652716,"endOffset":652773,"count":0}],"isBlockCoverage":false},{"functionName":"addEventListener$3","ranges":[{"startOffset":652884,"endOffset":653127,"count":1}],"isBlockCoverage":true},{"functionName":"postMessage$1","ranges":[{"startOffset":653148,"endOffset":653318,"count":1}],"isBlockCoverage":true},{"functionName":"get$message","ranges":[{"startOffset":653406,"endOffset":653463,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":653525,"endOffset":653582,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":653637,"endOffset":653694,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":653768,"endOffset":653825,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":653889,"endOffset":653946,"count":0}],"isBlockCoverage":false},{"functionName":"get$isBroadcast","ranges":[{"startOffset":654044,"endOffset":654081,"count":0}],"isBlockCoverage":false},{"functionName":"listen$4$cancelOnError$onDone$onError","ranges":[{"startOffset":654126,"endOffset":654445,"count":1}],"isBlockCoverage":true},{"functionName":"listen$3$onDone$onError","ranges":[{"startOffset":654476,"endOffset":654605,"count":0}],"isBlockCoverage":false},{"functionName":"listen$1","ranges":[{"startOffset":654621,"endOffset":654728,"count":0}],"isBlockCoverage":false},{"functionName":"cancel$0","ranges":[{"startOffset":654791,"endOffset":655010,"count":1},{"startOffset":654875,"endOffset":654887,"count":0}],"isBlockCoverage":true},{"functionName":"pause$1","ranges":[{"startOffset":655025,"endOffset":655161,"count":0}],"isBlockCoverage":false},{"functionName":"pause$0","ranges":[{"startOffset":655176,"endOffset":655227,"count":0}],"isBlockCoverage":false},{"functionName":"resume$0","ranges":[{"startOffset":655243,"endOffset":655421,"count":0}],"isBlockCoverage":false},{"functionName":"_tryResume$0","ranges":[{"startOffset":655441,"endOffset":655647,"count":1}],"isBlockCoverage":true},{"functionName":"_unlisten$0","ranges":[{"startOffset":655666,"endOffset":655969,"count":1}],"isBlockCoverage":true},{"functionName":"set$_html$_onData","ranges":[{"startOffset":655994,"endOffset":656092,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":656161,"endOffset":656236,"count":1}],"isBlockCoverage":true},{"functionName":"findSlot$1","ranges":[{"startOffset":656313,"endOffset":656603,"count":1},{"startOffset":656474,"endOffset":656483,"count":0}],"isBlockCoverage":true},{"functionName":"walk$1","ranges":[{"startOffset":656617,"endOffset":658566,"count":1},{"startOffset":656751,"endOffset":656760,"count":0},{"startOffset":656904,"endOffset":656930,"count":0},{"startOffset":656970,"endOffset":657045,"count":0},{"startOffset":657083,"endOffset":657092,"count":0},{"startOffset":657130,"endOffset":657139,"count":0},{"startOffset":657249,"endOffset":657258,"count":0},{"startOffset":657409,"endOffset":657434,"count":0},{"startOffset":657506,"endOffset":657518,"count":0},{"startOffset":657862,"endOffset":657887,"count":0},{"startOffset":657949,"endOffset":657961,"count":0},{"startOffset":658011,"endOffset":658565,"count":0}],"isBlockCoverage":true},{"functionName":"copyList$2","ranges":[{"startOffset":658584,"endOffset":658922,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":658988,"endOffset":659072,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":659158,"endOffset":659242,"count":0}],"isBlockCoverage":false},{"functionName":"findSlot$1","ranges":[{"startOffset":659324,"endOffset":659614,"count":1},{"startOffset":659485,"endOffset":659494,"count":0}],"isBlockCoverage":true},{"functionName":"walk$1","ranges":[{"startOffset":659628,"endOffset":661744,"count":1},{"startOffset":659949,"endOffset":660278,"count":0},{"startOffset":660318,"endOffset":660393,"count":0},{"startOffset":660467,"endOffset":660510,"count":0},{"startOffset":660713,"endOffset":660738,"count":0},{"startOffset":660814,"endOffset":660826,"count":0},{"startOffset":661277,"endOffset":661302,"count":0},{"startOffset":661364,"endOffset":661376,"count":0},{"startOffset":661502,"endOffset":661505,"count":0},{"startOffset":661722,"endOffset":661743,"count":0}],"isBlockCoverage":true},{"functionName":"convertNativeToDart_AcceptStructuredClone$2$mustCopy","ranges":[{"startOffset":661804,"endOffset":661900,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":661972,"endOffset":662124,"count":1}],"isBlockCoverage":true},{"functionName":"forEachObjectKey$2","ranges":[{"startOffset":662216,"endOffset":662485,"count":0}],"isBlockCoverage":false},{"functionName":"forEachJsField$2","ranges":[{"startOffset":662561,"endOffset":662902,"count":1},{"startOffset":662770,"endOffset":662816,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":662964,"endOffset":663725,"count":1},{"startOffset":663098,"endOffset":663121,"count":0},{"startOffset":663497,"endOffset":663696,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":663805,"endOffset":663896,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":663977,"endOffset":664044,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":664969,"endOffset":665026,"count":0}],"isBlockCoverage":false},{"functionName":"runOnce$1","ranges":[{"startOffset":665079,"endOffset":665381,"count":0}],"isBlockCoverage":false},{"functionName":"onData$1","ranges":[{"startOffset":665493,"endOffset":665616,"count":0}],"isBlockCoverage":false},{"functionName":"onError$1","ranges":[{"startOffset":665633,"endOffset":665732,"count":0}],"isBlockCoverage":false},{"functionName":"onDone$1","ranges":[{"startOffset":665748,"endOffset":665866,"count":0}],"isBlockCoverage":false},{"functionName":"pause$1","ranges":[{"startOffset":665881,"endOffset":665974,"count":0}],"isBlockCoverage":false},{"functionName":"pause$0","ranges":[{"startOffset":665989,"endOffset":666040,"count":0}],"isBlockCoverage":false},{"functionName":"resume$0","ranges":[{"startOffset":666056,"endOffset":666126,"count":0}],"isBlockCoverage":false},{"functionName":"cancel$0","ranges":[{"startOffset":666142,"endOffset":666219,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":666296,"endOffset":666782,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":666797,"endOffset":667077,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":667153,"endOffset":667619,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":667637,"endOffset":667703,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":667764,"endOffset":667976,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":668045,"endOffset":668148,"count":0}],"isBlockCoverage":false},{"functionName":"addStream$1","ranges":[{"startOffset":668167,"endOffset":668625,"count":0}],"isBlockCoverage":false},{"functionName":"_checkEventAllowed$0","ranges":[{"startOffset":668653,"endOffset":668914,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":668929,"endOffset":669017,"count":0}],"isBlockCoverage":false},{"functionName":"get$done","ranges":[{"startOffset":669118,"endOffset":669160,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":669229,"endOffset":669287,"count":0}],"isBlockCoverage":false},{"functionName":"complete$1","ranges":[{"startOffset":669358,"endOffset":669447,"count":0}],"isBlockCoverage":false},{"functionName":"addTo$1","ranges":[{"startOffset":669462,"endOffset":669536,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":669556,"endOffset":669672,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":669683,"endOffset":669875,"count":0}],"isBlockCoverage":false},{"functionName":"complete$1","ranges":[{"startOffset":669972,"endOffset":670080,"count":1}],"isBlockCoverage":true},{"functionName":"addTo$1","ranges":[{"startOffset":670095,"endOffset":670191,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":670211,"endOffset":670292,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":670303,"endOffset":670456,"count":0}],"isBlockCoverage":false},{"functionName":"setSourceStream$1","ranges":[{"startOffset":670537,"endOffset":670945,"count":1},{"startOffset":670703,"endOffset":670769,"count":0}],"isBlockCoverage":true},{"functionName":"listen$4$cancelOnError$onDone$onError","ranges":[{"startOffset":671029,"endOffset":671873,"count":1},{"startOffset":671585,"endOffset":671619,"count":0}],"isBlockCoverage":true},{"functionName":"listen$3$onDone$onError","ranges":[{"startOffset":671904,"endOffset":672033,"count":0}],"isBlockCoverage":false},{"functionName":"listen$1","ranges":[{"startOffset":672049,"endOffset":672156,"count":1}],"isBlockCoverage":true},{"functionName":"_linkStreamToController$0","ranges":[{"startOffset":672189,"endOffset":672550,"count":1}],"isBlockCoverage":true},{"functionName":"_createController$0","ranges":[{"startOffset":672577,"endOffset":672786,"count":1}],"isBlockCoverage":true},{"functionName":"set$_stream_completer$_controller","ranges":[{"startOffset":672827,"endOffset":672960,"count":1}],"isBlockCoverage":true},{"functionName":"set$_sourceStream","ranges":[{"startOffset":672985,"endOffset":673096,"count":1}],"isBlockCoverage":true},{"functionName":"add$1","ranges":[{"startOffset":673143,"endOffset":673811,"count":0}],"isBlockCoverage":false},{"functionName":"_onListen$0","ranges":[{"startOffset":673830,"endOffset":674010,"count":0}],"isBlockCoverage":false},{"functionName":"_onCancelBroadcast$0","ranges":[{"startOffset":674038,"endOffset":674225,"count":0}],"isBlockCoverage":false},{"functionName":"_listenToStream$1","ranges":[{"startOffset":674250,"endOffset":674687,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":674702,"endOffset":675097,"count":0}],"isBlockCoverage":false},{"functionName":"set$_stream_group$_controller","ranges":[{"startOffset":675134,"endOffset":675263,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":675339,"endOffset":675376,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":675456,"endOffset":675530,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":675548,"endOffset":675630,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":675696,"endOffset":676010,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":676028,"endOffset":676124,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":676199,"endOffset":676545,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":676563,"endOffset":676659,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":676731,"endOffset":677110,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":677188,"endOffset":677231,"count":0}],"isBlockCoverage":false},{"functionName":"get$next","ranges":[{"startOffset":677281,"endOffset":677676,"count":1},{"startOffset":677618,"endOffset":677675,"count":0}],"isBlockCoverage":true},{"functionName":"_updateRequests$0","ranges":[{"startOffset":677701,"endOffset":678244,"count":1},{"startOffset":677901,"endOffset":677955,"count":0},{"startOffset":678019,"endOffset":678042,"count":0},{"startOffset":678120,"endOffset":678151,"count":0}],"isBlockCoverage":true},{"functionName":"_extractStream$0","ranges":[{"startOffset":678268,"endOffset":678938,"count":1},{"startOffset":678406,"endOffset":678470,"count":0},{"startOffset":678575,"endOffset":678610,"count":0}],"isBlockCoverage":true},{"functionName":"_ensureListening$0","ranges":[{"startOffset":678964,"endOffset":679408,"count":1},{"startOffset":679038,"endOffset":679045,"count":0},{"startOffset":679368,"endOffset":679402,"count":0}],"isBlockCoverage":true},{"functionName":"_addResult$1","ranges":[{"startOffset":679428,"endOffset":679693,"count":1}],"isBlockCoverage":true},{"functionName":"_failClosed$0","ranges":[{"startOffset":679714,"endOffset":679784,"count":0}],"isBlockCoverage":false},{"functionName":"_addRequest$1","ranges":[{"startOffset":679805,"endOffset":680179,"count":1}],"isBlockCoverage":true},{"functionName":"set$_stream_queue$_subscription","ranges":[{"startOffset":680218,"endOffset":680355,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":680428,"endOffset":680601,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":680619,"endOffset":680685,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":680759,"endOffset":680888,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":680981,"endOffset":681129,"count":0}],"isBlockCoverage":false},{"functionName":"update$2","ranges":[{"startOffset":681233,"endOffset":681629,"count":1},{"startOffset":681475,"endOffset":681603,"count":0}],"isBlockCoverage":true},{"functionName":"update$2","ranges":[{"startOffset":681705,"endOffset":683204,"count":1},{"startOffset":681986,"endOffset":682524,"count":0},{"startOffset":682592,"endOffset":683179,"count":0}],"isBlockCoverage":true},{"functionName":"get$_canSendDirectly","ranges":[{"startOffset":683334,"endOffset":683447,"count":0}],"isBlockCoverage":false},{"functionName":"get$done","ranges":[{"startOffset":683463,"endOffset":683878,"count":0}],"isBlockCoverage":false},{"functionName":"addStream$1","ranges":[{"startOffset":683897,"endOffset":684228,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":684243,"endOffset":684519,"count":0}],"isBlockCoverage":false},{"functionName":"_ensureController$0","ranges":[{"startOffset":684546,"endOffset":684755,"count":0}],"isBlockCoverage":false},{"functionName":"_setDestinationSink$1","ranges":[{"startOffset":684784,"endOffset":685386,"count":1},{"startOffset":685061,"endOffset":685262,"count":0},{"startOffset":685349,"endOffset":685380,"count":0}],"isBlockCoverage":true},{"functionName":"set$_stream_sink_completer$_controller","ranges":[{"startOffset":685432,"endOffset":685570,"count":0}],"isBlockCoverage":false},{"functionName":"set$_destinationSink","ranges":[{"startOffset":685598,"endOffset":685722,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":685886,"endOffset":685905,"count":0}],"isBlockCoverage":false},{"functionName":"listen$4$cancelOnError$onDone$onError","ranges":[{"startOffset":686010,"endOffset":686754,"count":1},{"startOffset":686321,"endOffset":686398,"count":0},{"startOffset":686489,"endOffset":686590,"count":0}],"isBlockCoverage":true},{"functionName":"listen$3$onDone$onError","ranges":[{"startOffset":686785,"endOffset":686914,"count":0}],"isBlockCoverage":false},{"functionName":"listen$1","ranges":[{"startOffset":686930,"endOffset":687037,"count":0}],"isBlockCoverage":false},{"functionName":"set$_subscription_stream$_source","ranges":[{"startOffset":687077,"endOffset":687203,"count":1}],"isBlockCoverage":true},{"functionName":"onError$1","ranges":[{"startOffset":687276,"endOffset":687442,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":687528,"endOffset":688068,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":688174,"endOffset":688382,"count":0}],"isBlockCoverage":false},{"functionName":"evaluate$1","ranges":[{"startOffset":688481,"endOffset":688527,"count":1}],"isBlockCoverage":true},{"functionName":"intersection$1","ranges":[{"startOffset":688549,"endOffset":688592,"count":0}],"isBlockCoverage":false},{"functionName":"validate$1","ranges":[{"startOffset":688610,"endOffset":688689,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":688707,"endOffset":688748,"count":0}],"isBlockCoverage":false},{"functionName":"accept$1","ranges":[{"startOffset":688826,"endOffset":688895,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":688913,"endOffset":688956,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":688967,"endOffset":689113,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":689133,"endOffset":689193,"count":0}],"isBlockCoverage":false},{"functionName":"get$span","ranges":[{"startOffset":689225,"endOffset":689267,"count":0}],"isBlockCoverage":false},{"functionName":"accept$1","ranges":[{"startOffset":689313,"endOffset":689377,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":689395,"endOffset":689568,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":689579,"endOffset":689727,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":689747,"endOffset":689834,"count":0}],"isBlockCoverage":false},{"functionName":"get$span","ranges":[{"startOffset":689866,"endOffset":689908,"count":0}],"isBlockCoverage":false},{"functionName":"get$span","ranges":[{"startOffset":689953,"endOffset":690044,"count":0}],"isBlockCoverage":false},{"functionName":"accept$1","ranges":[{"startOffset":690060,"endOffset":690123,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":690141,"endOffset":690553,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":690564,"endOffset":690743,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":690763,"endOffset":690897,"count":0}],"isBlockCoverage":false},{"functionName":"get$span","ranges":[{"startOffset":690959,"endOffset":691050,"count":0}],"isBlockCoverage":false},{"functionName":"accept$1","ranges":[{"startOffset":691066,"endOffset":691130,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":691148,"endOffset":691558,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":691569,"endOffset":691749,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":691769,"endOffset":691903,"count":0}],"isBlockCoverage":false},{"functionName":"get$span","ranges":[{"startOffset":691973,"endOffset":692073,"count":0}],"isBlockCoverage":false},{"functionName":"accept$1","ranges":[{"startOffset":692089,"endOffset":692161,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":692179,"endOffset":692631,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":692642,"endOffset":692888,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":692908,"endOffset":693101,"count":0}],"isBlockCoverage":false},{"functionName":"visitVariable$1","ranges":[{"startOffset":693172,"endOffset":693242,"count":0}],"isBlockCoverage":false},{"functionName":"visitNot$1","ranges":[{"startOffset":693260,"endOffset":693346,"count":0}],"isBlockCoverage":false},{"functionName":"visitOr$1","ranges":[{"startOffset":693363,"endOffset":693499,"count":0}],"isBlockCoverage":false},{"functionName":"visitAnd$1","ranges":[{"startOffset":693517,"endOffset":693653,"count":0}],"isBlockCoverage":false},{"functionName":"visitConditional$1","ranges":[{"startOffset":693679,"endOffset":693831,"count":0}],"isBlockCoverage":false},{"functionName":"evaluate$1","ranges":[{"startOffset":693910,"endOffset":694228,"count":0}],"isBlockCoverage":false},{"functionName":"intersection$1","ranges":[{"startOffset":694250,"endOffset":694597,"count":0}],"isBlockCoverage":false},{"functionName":"validate$1","ranges":[{"startOffset":694615,"endOffset":694736,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":694754,"endOffset":694816,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":694827,"endOffset":694995,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":695015,"endOffset":695099,"count":0}],"isBlockCoverage":false},{"functionName":"evaluate$1","ranges":[{"startOffset":695187,"endOffset":695353,"count":0}],"isBlockCoverage":false},{"functionName":"intersection$1","ranges":[{"startOffset":695375,"endOffset":695452,"count":0}],"isBlockCoverage":false},{"functionName":"validate$1","ranges":[{"startOffset":695470,"endOffset":695639,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":695657,"endOffset":695766,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":695777,"endOffset":695993,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":696013,"endOffset":696141,"count":0}],"isBlockCoverage":false},{"functionName":"evaluate$1","ranges":[{"startOffset":696213,"endOffset":696260,"count":0}],"isBlockCoverage":false},{"functionName":"intersection$1","ranges":[{"startOffset":696282,"endOffset":696324,"count":0}],"isBlockCoverage":false},{"functionName":"validate$1","ranges":[{"startOffset":696342,"endOffset":696421,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":696439,"endOffset":696481,"count":0}],"isBlockCoverage":false},{"functionName":"parse$0","ranges":[{"startOffset":696552,"endOffset":696864,"count":0}],"isBlockCoverage":false},{"functionName":"_conditional$0","ranges":[{"startOffset":696886,"endOffset":697347,"count":0}],"isBlockCoverage":false},{"functionName":"_or$0","ranges":[{"startOffset":697360,"endOffset":697536,"count":0}],"isBlockCoverage":false},{"functionName":"_and$0","ranges":[{"startOffset":697550,"endOffset":697742,"count":0}],"isBlockCoverage":false},{"functionName":"_simpleExpression$0","ranges":[{"startOffset":697769,"endOffset":698600,"count":0}],"isBlockCoverage":false},{"functionName":"peek$0","ranges":[{"startOffset":698644,"endOffset":698770,"count":0}],"isBlockCoverage":false},{"functionName":"next$0","ranges":[{"startOffset":698784,"endOffset":699055,"count":0}],"isBlockCoverage":false},{"functionName":"scan$1","ranges":[{"startOffset":699069,"endOffset":699219,"count":0}],"isBlockCoverage":false},{"functionName":"_getNext$0","ranges":[{"startOffset":699237,"endOffset":700677,"count":0}],"isBlockCoverage":false},{"functionName":"_scanOperator$1","ranges":[{"startOffset":700700,"endOffset":701057,"count":0}],"isBlockCoverage":false},{"functionName":"_consumeWhitespace$0","ranges":[{"startOffset":701085,"endOffset":701439,"count":0}],"isBlockCoverage":false},{"functionName":"_multiLineComment$0","ranges":[{"startOffset":701466,"endOffset":701903,"count":0}],"isBlockCoverage":false},{"functionName":"get$type","ranges":[{"startOffset":701947,"endOffset":701997,"count":0}],"isBlockCoverage":false},{"functionName":"get$span","ranges":[{"startOffset":702013,"endOffset":702055,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":702111,"endOffset":702182,"count":0}],"isBlockCoverage":false},{"functionName":"get$type","ranges":[{"startOffset":702215,"endOffset":702270,"count":0}],"isBlockCoverage":false},{"functionName":"get$span","ranges":[{"startOffset":702286,"endOffset":702328,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":702378,"endOffset":702421,"count":0}],"isBlockCoverage":false},{"functionName":"visitVariable$1","ranges":[{"startOffset":702476,"endOffset":702681,"count":0}],"isBlockCoverage":false},{"functionName":"visitNot$1","ranges":[{"startOffset":702738,"endOffset":702793,"count":0}],"isBlockCoverage":false},{"functionName":"visitOr$1","ranges":[{"startOffset":702810,"endOffset":702897,"count":0}],"isBlockCoverage":false},{"functionName":"visitAnd$1","ranges":[{"startOffset":702915,"endOffset":703002,"count":0}],"isBlockCoverage":false},{"functionName":"visitConditional$1","ranges":[{"startOffset":703028,"endOffset":703160,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":703242,"endOffset":703293,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":703311,"endOffset":703346,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":703364,"endOffset":703412,"count":0}],"isBlockCoverage":false},{"functionName":"toSet$0","ranges":[{"startOffset":703427,"endOffset":703514,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":703615,"endOffset":703731,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":703749,"endOffset":703857,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":703909,"endOffset":704161,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":704179,"endOffset":704273,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":704327,"endOffset":704582,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":704600,"endOffset":704692,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":704742,"endOffset":704827,"count":0}],"isBlockCoverage":false},{"functionName":"removeFirst$0","ranges":[{"startOffset":704848,"endOffset":705338,"count":1},{"startOffset":704985,"endOffset":705036,"count":0},{"startOffset":705109,"endOffset":705132,"count":0}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":705356,"endOffset":705482,"count":1}],"isBlockCoverage":true},{"functionName":"set$length","ranges":[{"startOffset":705500,"endOffset":706426,"count":0}],"isBlockCoverage":false},{"functionName":"$index","ranges":[{"startOffset":706440,"endOffset":706924,"count":0}],"isBlockCoverage":false},{"functionName":"$indexSet","ranges":[{"startOffset":706941,"endOffset":707471,"count":0}],"isBlockCoverage":false},{"functionName":"_queue_list$_add$1","ranges":[{"startOffset":707497,"endOffset":708514,"count":1},{"startOffset":707919,"endOffset":708508,"count":0}],"isBlockCoverage":true},{"functionName":"_writeToList$1","ranges":[{"startOffset":708536,"endOffset":709305,"count":0}],"isBlockCoverage":false},{"functionName":"_preGrow$1","ranges":[{"startOffset":709323,"endOffset":709960,"count":0}],"isBlockCoverage":false},{"functionName":"set$_queue_list$_table","ranges":[{"startOffset":709990,"endOffset":710090,"count":1}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":710275,"endOffset":710401,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":710421,"endOffset":710522,"count":0}],"isBlockCoverage":false},{"functionName":"get$_union_set$_iterable","ranges":[{"startOffset":710554,"endOffset":710878,"count":0}],"isBlockCoverage":false},{"functionName":"toSet$0","ranges":[{"startOffset":710893,"endOffset":711220,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":711280,"endOffset":711601,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":711619,"endOffset":711693,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":711756,"endOffset":711836,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":711854,"endOffset":711927,"count":0}],"isBlockCoverage":false},{"functionName":"set$_union_set_controller$_set","ranges":[{"startOffset":712065,"endOffset":712173,"count":0}],"isBlockCoverage":false},{"functionName":"contains$1","ranges":[{"startOffset":712394,"endOffset":712470,"count":0}],"isBlockCoverage":false},{"functionName":"every$1","ranges":[{"startOffset":712485,"endOffset":712601,"count":0}],"isBlockCoverage":false},{"functionName":"get$first","ranges":[{"startOffset":712618,"endOffset":712695,"count":0}],"isBlockCoverage":false},{"functionName":"get$isEmpty","ranges":[{"startOffset":712714,"endOffset":712793,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":712813,"endOffset":712893,"count":0}],"isBlockCoverage":false},{"functionName":"get$last","ranges":[{"startOffset":712909,"endOffset":712985,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":713003,"endOffset":713081,"count":0}],"isBlockCoverage":false},{"functionName":"map$1$1","ranges":[{"startOffset":713096,"endOffset":713223,"count":0}],"isBlockCoverage":false},{"functionName":"toList$1$growable","ranges":[{"startOffset":713248,"endOffset":713329,"count":1}],"isBlockCoverage":true},{"functionName":"toList$0","ranges":[{"startOffset":713345,"endOffset":713426,"count":1}],"isBlockCoverage":true},{"functionName":"toSet$0","ranges":[{"startOffset":713441,"endOffset":713496,"count":0}],"isBlockCoverage":false},{"functionName":"where$1","ranges":[{"startOffset":713511,"endOffset":713627,"count":1}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":713645,"endOffset":713703,"count":0}],"isBlockCoverage":false},{"functionName":"union$1","ranges":[{"startOffset":713813,"endOffset":713967,"count":1}],"isBlockCoverage":true},{"functionName":"toSet$0","ranges":[{"startOffset":713982,"endOffset":714157,"count":0}],"isBlockCoverage":false},{"functionName":"matches$2","ranges":[{"startOffset":714254,"endOffset":714324,"count":1}],"isBlockCoverage":true},{"functionName":"describe$1","ranges":[{"startOffset":714342,"endOffset":714441,"count":0}],"isBlockCoverage":false},{"functionName":"typedMatches$2","ranges":[{"startOffset":714496,"endOffset":714602,"count":0}],"isBlockCoverage":false},{"functionName":"describe$1","ranges":[{"startOffset":714620,"endOffset":714745,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":714803,"endOffset":714863,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":714881,"endOffset":714982,"count":0}],"isBlockCoverage":false},{"functionName":"addDescriptionOf$1","ranges":[{"startOffset":715008,"endOffset":715192,"count":0}],"isBlockCoverage":false},{"functionName":"typedMatches$2","ranges":[{"startOffset":715280,"endOffset":715389,"count":0}],"isBlockCoverage":false},{"functionName":"describe$1","ranges":[{"startOffset":715407,"endOffset":715510,"count":0}],"isBlockCoverage":false},{"functionName":"describeTypedMismatch$4","ranges":[{"startOffset":715541,"endOffset":717567,"count":0}],"isBlockCoverage":false},{"functionName":"_compareIterables$5","ranges":[{"startOffset":717629,"endOffset":718839,"count":0}],"isBlockCoverage":false},{"functionName":"_compareSets$5","ranges":[{"startOffset":718861,"endOffset":720203,"count":0}],"isBlockCoverage":false},{"functionName":"_recursiveMatch$4","ranges":[{"startOffset":720228,"endOffset":723384,"count":0}],"isBlockCoverage":false},{"functionName":"_equals_matcher$_match$3","ranges":[{"startOffset":723416,"endOffset":724262,"count":0}],"isBlockCoverage":false},{"functionName":"matches$2","ranges":[{"startOffset":724279,"endOffset":724402,"count":0}],"isBlockCoverage":false},{"functionName":"describe$1","ranges":[{"startOffset":724420,"endOffset":724510,"count":0}],"isBlockCoverage":false},{"functionName":"describeMismatch$4","ranges":[{"startOffset":724536,"endOffset":725070,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":725140,"endOffset":725305,"count":0}],"isBlockCoverage":false},{"functionName":"matches$2","ranges":[{"startOffset":725378,"endOffset":725603,"count":0}],"isBlockCoverage":false},{"functionName":"describeMismatch$4","ranges":[{"startOffset":725629,"endOffset":725977,"count":0}],"isBlockCoverage":false},{"functionName":"describeTypedMismatch$4","ranges":[{"startOffset":726008,"endOffset":726176,"count":0}],"isBlockCoverage":false},{"functionName":"describeMismatch$4","ranges":[{"startOffset":726232,"endOffset":726330,"count":0}],"isBlockCoverage":false},{"functionName":"call$4","ranges":[{"startOffset":726391,"endOffset":730032,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":730116,"endOffset":730227,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":730316,"endOffset":730510,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":730599,"endOffset":730730,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":730820,"endOffset":731014,"count":0}],"isBlockCoverage":false},{"functionName":"describe$1","ranges":[{"startOffset":731085,"endOffset":731450,"count":0}],"isBlockCoverage":false},{"functionName":"matches$2","ranges":[{"startOffset":731467,"endOffset":731575,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":731631,"endOffset":731703,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":731773,"endOffset":731958,"count":0}],"isBlockCoverage":false},{"functionName":"get$packageRoot","ranges":[{"startOffset":732071,"endOffset":732108,"count":0}],"isBlockCoverage":false},{"functionName":"get$packageConfigMap","ranges":[{"startOffset":732136,"endOffset":732190,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":732270,"endOffset":732353,"count":1}],"isBlockCoverage":true},{"functionName":"get$packageConfigMap","ranges":[{"startOffset":732469,"endOffset":732506,"count":0}],"isBlockCoverage":false},{"functionName":"get$packageRoot","ranges":[{"startOffset":732529,"endOffset":732578,"count":0}],"isBlockCoverage":false},{"functionName":"absolute$7","ranges":[{"startOffset":732626,"endOffset":733114,"count":0}],"isBlockCoverage":false},{"functionName":"absolute$1","ranges":[{"startOffset":733132,"endOffset":733250,"count":0}],"isBlockCoverage":false},{"functionName":"join$8","ranges":[{"startOffset":733264,"endOffset":733650,"count":0}],"isBlockCoverage":false},{"functionName":"join$2","ranges":[{"startOffset":733664,"endOffset":733792,"count":0}],"isBlockCoverage":false},{"functionName":"joinAll$1","ranges":[{"startOffset":733809,"endOffset":735362,"count":0}],"isBlockCoverage":false},{"functionName":"split$1","ranges":[{"startOffset":735377,"endOffset":735875,"count":0}],"isBlockCoverage":false},{"functionName":"normalize$1","ranges":[{"startOffset":735894,"endOffset":736127,"count":0}],"isBlockCoverage":false},{"functionName":"_needsNormalization$1","ranges":[{"startOffset":736156,"endOffset":737652,"count":0}],"isBlockCoverage":false},{"functionName":"relative$2$from","ranges":[{"startOffset":737675,"endOffset":741067,"count":0}],"isBlockCoverage":false},{"functionName":"relative$1","ranges":[{"startOffset":741085,"endOffset":741154,"count":0}],"isBlockCoverage":false},{"functionName":"_isWithinOrEquals$2","ranges":[{"startOffset":741181,"endOffset":743129,"count":0}],"isBlockCoverage":false},{"functionName":"_isWithinOrEqualsFast$2","ranges":[{"startOffset":743160,"endOffset":747690,"count":0}],"isBlockCoverage":false},{"functionName":"_pathDirection$2","ranges":[{"startOffset":747714,"endOffset":748939,"count":0}],"isBlockCoverage":false},{"functionName":"toUri$1","ranges":[{"startOffset":748954,"endOffset":749248,"count":0}],"isBlockCoverage":false},{"functionName":"prettyUri$1","ranges":[{"startOffset":749267,"endOffset":749843,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":749900,"endOffset":749973,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":750052,"endOffset":750124,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":750201,"endOffset":750279,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":750359,"endOffset":750468,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":750542,"endOffset":750585,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":750639,"endOffset":750682,"count":0}],"isBlockCoverage":false},{"functionName":"getRoot$1","ranges":[{"startOffset":750735,"endOffset":751064,"count":0}],"isBlockCoverage":false},{"functionName":"relativePathToUri$1","ranges":[{"startOffset":751091,"endOffset":751348,"count":0}],"isBlockCoverage":false},{"functionName":"codeUnitsEqual$2","ranges":[{"startOffset":751372,"endOffset":751448,"count":0}],"isBlockCoverage":false},{"functionName":"pathsEqual$2","ranges":[{"startOffset":751468,"endOffset":751527,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasTrailingSeparator","ranges":[{"startOffset":751592,"endOffset":751829,"count":0}],"isBlockCoverage":false},{"functionName":"removeTrailingSeparators$0","ranges":[{"startOffset":751863,"endOffset":752298,"count":0}],"isBlockCoverage":false},{"functionName":"normalize$0","ranges":[{"startOffset":752317,"endOffset":753935,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":753953,"endOffset":754466,"count":0}],"isBlockCoverage":false},{"functionName":"set$parts","ranges":[{"startOffset":754483,"endOffset":754558,"count":0}],"isBlockCoverage":false},{"functionName":"set$separators","ranges":[{"startOffset":754580,"endOffset":754670,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":754735,"endOffset":754801,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":754875,"endOffset":754941,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":754981,"endOffset":755034,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":755080,"endOffset":755133,"count":0}],"isBlockCoverage":false},{"functionName":"containsSeparator$1","ranges":[{"startOffset":755193,"endOffset":755270,"count":0}],"isBlockCoverage":false},{"functionName":"isSeparator$1","ranges":[{"startOffset":755291,"endOffset":755347,"count":0}],"isBlockCoverage":false},{"functionName":"needsSeparator$1","ranges":[{"startOffset":755371,"endOffset":755500,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$2$withDrive","ranges":[{"startOffset":755530,"endOffset":755678,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$1","ranges":[{"startOffset":755698,"endOffset":755775,"count":0}],"isBlockCoverage":false},{"functionName":"isRootRelative$1","ranges":[{"startOffset":755799,"endOffset":755841,"count":0}],"isBlockCoverage":false},{"functionName":"pathFromUri$1","ranges":[{"startOffset":755862,"endOffset":756185,"count":0}],"isBlockCoverage":false},{"functionName":"absolutePathToUri$1","ranges":[{"startOffset":756212,"endOffset":756605,"count":0}],"isBlockCoverage":false},{"functionName":"get$name","ranges":[{"startOffset":756621,"endOffset":756661,"count":0}],"isBlockCoverage":false},{"functionName":"get$separator","ranges":[{"startOffset":756682,"endOffset":756718,"count":0}],"isBlockCoverage":false},{"functionName":"containsSeparator$1","ranges":[{"startOffset":756776,"endOffset":756853,"count":0}],"isBlockCoverage":false},{"functionName":"isSeparator$1","ranges":[{"startOffset":756874,"endOffset":756930,"count":0}],"isBlockCoverage":false},{"functionName":"needsSeparator$1","ranges":[{"startOffset":756954,"endOffset":757222,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$2$withDrive","ranges":[{"startOffset":757252,"endOffset":758194,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$1","ranges":[{"startOffset":758214,"endOffset":758291,"count":0}],"isBlockCoverage":false},{"functionName":"isRootRelative$1","ranges":[{"startOffset":758315,"endOffset":758421,"count":0}],"isBlockCoverage":false},{"functionName":"pathFromUri$1","ranges":[{"startOffset":758442,"endOffset":758496,"count":0}],"isBlockCoverage":false},{"functionName":"relativePathToUri$1","ranges":[{"startOffset":758523,"endOffset":758577,"count":0}],"isBlockCoverage":false},{"functionName":"absolutePathToUri$1","ranges":[{"startOffset":758604,"endOffset":758658,"count":0}],"isBlockCoverage":false},{"functionName":"get$name","ranges":[{"startOffset":758674,"endOffset":758712,"count":0}],"isBlockCoverage":false},{"functionName":"get$separator","ranges":[{"startOffset":758733,"endOffset":758769,"count":0}],"isBlockCoverage":false},{"functionName":"containsSeparator$1","ranges":[{"startOffset":758831,"endOffset":758908,"count":0}],"isBlockCoverage":false},{"functionName":"isSeparator$1","ranges":[{"startOffset":758929,"endOffset":759004,"count":0}],"isBlockCoverage":false},{"functionName":"needsSeparator$1","ranges":[{"startOffset":759028,"endOffset":759218,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$2$withDrive","ranges":[{"startOffset":759248,"endOffset":760107,"count":0}],"isBlockCoverage":false},{"functionName":"rootLength$1","ranges":[{"startOffset":760127,"endOffset":760204,"count":0}],"isBlockCoverage":false},{"functionName":"isRootRelative$1","ranges":[{"startOffset":760228,"endOffset":760294,"count":0}],"isBlockCoverage":false},{"functionName":"pathFromUri$1","ranges":[{"startOffset":760315,"endOffset":760968,"count":0}],"isBlockCoverage":false},{"functionName":"absolutePathToUri$1","ranges":[{"startOffset":760995,"endOffset":762083,"count":0}],"isBlockCoverage":false},{"functionName":"codeUnitsEqual$2","ranges":[{"startOffset":762107,"endOffset":762496,"count":0}],"isBlockCoverage":false},{"functionName":"pathsEqual$2","ranges":[{"startOffset":762516,"endOffset":762906,"count":0}],"isBlockCoverage":false},{"functionName":"get$name","ranges":[{"startOffset":762922,"endOffset":762964,"count":0}],"isBlockCoverage":false},{"functionName":"get$separator","ranges":[{"startOffset":762985,"endOffset":763022,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":763097,"endOffset":763169,"count":0}],"isBlockCoverage":false},{"functionName":"request$0","ranges":[{"startOffset":763232,"endOffset":764213,"count":0}],"isBlockCoverage":false},{"functionName":"withResource$1$1","ranges":[{"startOffset":764237,"endOffset":764370,"count":0}],"isBlockCoverage":false},{"functionName":"withResource$body$Pool","ranges":[{"startOffset":764400,"endOffset":766633,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":766648,"endOffset":766745,"count":0}],"isBlockCoverage":false},{"functionName":"_onResourceReleaseAllowed$1","ranges":[{"startOffset":766780,"endOffset":767623,"count":0}],"isBlockCoverage":false},{"functionName":"_runOnRelease$1","ranges":[{"startOffset":767646,"endOffset":768136,"count":0}],"isBlockCoverage":false},{"functionName":"_resetTimer$0","ranges":[{"startOffset":768157,"endOffset":768543,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":768598,"endOffset":769521,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":769616,"endOffset":769695,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":769777,"endOffset":769909,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":769992,"endOffset":770160,"count":0}],"isBlockCoverage":false},{"functionName":"release$0","ranges":[{"startOffset":770231,"endOffset":770780,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":770838,"endOffset":771040,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":771119,"endOffset":773479,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":773558,"endOffset":773629,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":773709,"endOffset":773806,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":773887,"endOffset":773961,"count":0}],"isBlockCoverage":false},{"functionName":"MultiSectionMapping$fromJson$3$mapUrl","ranges":[{"startOffset":774096,"endOffset":775955,"count":0}],"isBlockCoverage":false},{"functionName":"_indexFor$2","ranges":[{"startOffset":775974,"endOffset":776437,"count":0}],"isBlockCoverage":false},{"functionName":"spanFor$4$files$uri","ranges":[{"startOffset":776464,"endOffset":777052,"count":0}],"isBlockCoverage":false},{"functionName":"spanFor$3$uri","ranges":[{"startOffset":777073,"endOffset":777172,"count":0}],"isBlockCoverage":false},{"functionName":"spanFor$3$files","ranges":[{"startOffset":777195,"endOffset":777298,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":777316,"endOffset":777847,"count":0}],"isBlockCoverage":false},{"functionName":"MappingBundle$fromJson$2$mapUrl","ranges":[{"startOffset":777922,"endOffset":778250,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":778268,"endOffset":778496,"count":0}],"isBlockCoverage":false},{"functionName":"spanFor$4$files$uri","ranges":[{"startOffset":778523,"endOffset":779530,"count":0}],"isBlockCoverage":false},{"functionName":"spanFor$3$uri","ranges":[{"startOffset":779551,"endOffset":779650,"count":0}],"isBlockCoverage":false},{"functionName":"SingleMapping$fromJson$2$mapUrl","ranges":[{"startOffset":779725,"endOffset":783823,"count":0}],"isBlockCoverage":false},{"functionName":"_segmentError$2","ranges":[{"startOffset":783846,"endOffset":784041,"count":0}],"isBlockCoverage":false},{"functionName":"_findLine$1","ranges":[{"startOffset":784060,"endOffset":784406,"count":0}],"isBlockCoverage":false},{"functionName":"_findColumn$3","ranges":[{"startOffset":784427,"endOffset":785004,"count":0}],"isBlockCoverage":false},{"functionName":"spanFor$4$files$uri","ranges":[{"startOffset":785031,"endOffset":786224,"count":0}],"isBlockCoverage":false},{"functionName":"spanFor$3$uri","ranges":[{"startOffset":786245,"endOffset":786344,"count":0}],"isBlockCoverage":false},{"functionName":"spanFor$3$files","ranges":[{"startOffset":786367,"endOffset":786470,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":786488,"endOffset":786852,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":786919,"endOffset":787072,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":787159,"endOffset":787217,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":787306,"endOffset":787368,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":787443,"endOffset":787558,"count":0}],"isBlockCoverage":false},{"functionName":"get$line","ranges":[{"startOffset":787574,"endOffset":787616,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":787668,"endOffset":787921,"count":0}],"isBlockCoverage":false},{"functionName":"get$column","ranges":[{"startOffset":787939,"endOffset":787983,"count":0}],"isBlockCoverage":false},{"functionName":"moveNext$0","ranges":[{"startOffset":788041,"endOffset":788109,"count":0}],"isBlockCoverage":false},{"functionName":"get$current","ranges":[{"startOffset":788128,"endOffset":788407,"count":0}],"isBlockCoverage":false},{"functionName":"get$hasTokens","ranges":[{"startOffset":788428,"endOffset":788527,"count":0}],"isBlockCoverage":false},{"functionName":"get$nextKind","ranges":[{"startOffset":788547,"endOffset":788997,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":789015,"endOffset":789583,"count":0}],"isBlockCoverage":false},{"functionName":"get$isIdentifier","ranges":[{"startOffset":789694,"endOffset":789744,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":789788,"endOffset":790045,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":790116,"endOffset":790175,"count":0}],"isBlockCoverage":false},{"functionName":"get$lines","ranges":[{"startOffset":790192,"endOffset":790248,"count":0}],"isBlockCoverage":false},{"functionName":"SourceFile$decoded$2$url","ranges":[{"startOffset":790280,"endOffset":790792,"count":0}],"isBlockCoverage":false},{"functionName":"span$2","ranges":[{"startOffset":790806,"endOffset":790879,"count":0}],"isBlockCoverage":false},{"functionName":"getLine$1","ranges":[{"startOffset":790896,"endOffset":791616,"count":0}],"isBlockCoverage":false},{"functionName":"_isNearCachedLine$1","ranges":[{"startOffset":791643,"endOffset":792548,"count":0}],"isBlockCoverage":false},{"functionName":"_binarySearch$1","ranges":[{"startOffset":792571,"endOffset":792981,"count":0}],"isBlockCoverage":false},{"functionName":"getColumn$1","ranges":[{"startOffset":793000,"endOffset":793683,"count":0}],"isBlockCoverage":false},{"functionName":"getOffset$2","ranges":[{"startOffset":793702,"endOffset":794481,"count":0}],"isBlockCoverage":false},{"functionName":"getOffset$1","ranges":[{"startOffset":794500,"endOffset":794565,"count":0}],"isBlockCoverage":false},{"functionName":"get$sourceUrl","ranges":[{"startOffset":794621,"endOffset":794667,"count":0}],"isBlockCoverage":false},{"functionName":"get$line","ranges":[{"startOffset":794683,"endOffset":794748,"count":0}],"isBlockCoverage":false},{"functionName":"get$column","ranges":[{"startOffset":794766,"endOffset":794833,"count":0}],"isBlockCoverage":false},{"functionName":"get$offset","ranges":[{"startOffset":794851,"endOffset":794903,"count":0}],"isBlockCoverage":false},{"functionName":"get$sourceUrl","ranges":[{"startOffset":794956,"endOffset":795002,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":795020,"endOffset":795089,"count":0}],"isBlockCoverage":false},{"functionName":"get$start","ranges":[{"startOffset":795106,"endOffset":795185,"count":0}],"isBlockCoverage":false},{"functionName":"get$end","ranges":[{"startOffset":795200,"endOffset":795277,"count":0}],"isBlockCoverage":false},{"functionName":"get$text","ranges":[{"startOffset":795293,"endOffset":795463,"count":0}],"isBlockCoverage":false},{"functionName":"get$context","ranges":[{"startOffset":795482,"endOffset":796567,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":796578,"endOffset":797060,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":797080,"endOffset":797171,"count":0}],"isBlockCoverage":false},{"functionName":"expand$1","ranges":[{"startOffset":797187,"endOffset":797617,"count":0}],"isBlockCoverage":false},{"functionName":"highlight$0","ranges":[{"startOffset":797723,"endOffset":800062,"count":0}],"isBlockCoverage":false},{"functionName":"_writeFirstLine$1","ranges":[{"startOffset":800087,"endOffset":801960,"count":0}],"isBlockCoverage":false},{"functionName":"_writeIntermediateLines$1","ranges":[{"startOffset":801993,"endOffset":802716,"count":0}],"isBlockCoverage":false},{"functionName":"_writeLastLine$1","ranges":[{"startOffset":802740,"endOffset":803867,"count":0}],"isBlockCoverage":false},{"functionName":"_writeTrailingLines$1","ranges":[{"startOffset":803896,"endOffset":804584,"count":0}],"isBlockCoverage":false},{"functionName":"_writeText$1","ranges":[{"startOffset":804604,"endOffset":805084,"count":0}],"isBlockCoverage":false},{"functionName":"_writeSidebar$2$end$line","ranges":[{"startOffset":805116,"endOffset":805243,"count":0}],"isBlockCoverage":false},{"functionName":"_writeSidebar$1$end","ranges":[{"startOffset":805270,"endOffset":805346,"count":0}],"isBlockCoverage":false},{"functionName":"_writeSidebar$1$line","ranges":[{"startOffset":805374,"endOffset":805452,"count":0}],"isBlockCoverage":false},{"functionName":"_writeSidebar$0","ranges":[{"startOffset":805475,"endOffset":805549,"count":0}],"isBlockCoverage":false},{"functionName":"_countTabs$1","ranges":[{"startOffset":805569,"endOffset":805863,"count":0}],"isBlockCoverage":false},{"functionName":"_isOnlyWhitespace$1","ranges":[{"startOffset":805890,"endOffset":806214,"count":0}],"isBlockCoverage":false},{"functionName":"_colorize$2$color","ranges":[{"startOffset":806239,"endOffset":806594,"count":0}],"isBlockCoverage":false},{"functionName":"_colorize$1","ranges":[{"startOffset":806613,"endOffset":806692,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":806764,"endOffset":806982,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":807074,"endOffset":807147,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":807239,"endOffset":807514,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":807606,"endOffset":807796,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":807895,"endOffset":808102,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":808192,"endOffset":808411,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":808502,"endOffset":808715,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":808806,"endOffset":809078,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":809167,"endOffset":809588,"count":0}],"isBlockCoverage":false},{"functionName":"distance$1","ranges":[{"startOffset":809662,"endOffset":809961,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":809972,"endOffset":810183,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":810203,"endOffset":810282,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":810300,"endOffset":810590,"count":0}],"isBlockCoverage":false},{"functionName":"get$sourceUrl","ranges":[{"startOffset":810611,"endOffset":810658,"count":0}],"isBlockCoverage":false},{"functionName":"get$offset","ranges":[{"startOffset":810676,"endOffset":810728,"count":0}],"isBlockCoverage":false},{"functionName":"get$line","ranges":[{"startOffset":810744,"endOffset":810786,"count":0}],"isBlockCoverage":false},{"functionName":"get$column","ranges":[{"startOffset":810804,"endOffset":810848,"count":0}],"isBlockCoverage":false},{"functionName":"distance$1","ranges":[{"startOffset":810908,"endOffset":811205,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":811216,"endOffset":811426,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":811446,"endOffset":811524,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":811542,"endOffset":811946,"count":0}],"isBlockCoverage":false},{"functionName":"SourceSpanBase$3","ranges":[{"startOffset":812064,"endOffset":812766,"count":0}],"isBlockCoverage":false},{"functionName":"get$start","ranges":[{"startOffset":812783,"endOffset":812826,"count":0}],"isBlockCoverage":false},{"functionName":"get$end","ranges":[{"startOffset":812841,"endOffset":812882,"count":0}],"isBlockCoverage":false},{"functionName":"get$text","ranges":[{"startOffset":812898,"endOffset":812940,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":813001,"endOffset":813064,"count":0}],"isBlockCoverage":false},{"functionName":"toString$1$color","ranges":[{"startOffset":813088,"endOffset":813313,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":813331,"endOffset":813411,"count":0}],"isBlockCoverage":false},{"functionName":"get$sourceUrl","ranges":[{"startOffset":813558,"endOffset":813623,"count":0}],"isBlockCoverage":false},{"functionName":"get$length","ranges":[{"startOffset":813641,"endOffset":813799,"count":0}],"isBlockCoverage":false},{"functionName":"message$2$color","ranges":[{"startOffset":813822,"endOffset":814454,"count":0}],"isBlockCoverage":false},{"functionName":"message$1","ranges":[{"startOffset":814471,"endOffset":814568,"count":0}],"isBlockCoverage":false},{"functionName":"highlight$1$color","ranges":[{"startOffset":814593,"endOffset":815709,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":815720,"endOffset":815923,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":815943,"endOffset":816110,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":816128,"endOffset":816349,"count":0}],"isBlockCoverage":false},{"functionName":"get$context","ranges":[{"startOffset":816434,"endOffset":816480,"count":0}],"isBlockCoverage":false},{"functionName":"foldFrames$2$terse","ranges":[{"startOffset":816534,"endOffset":817349,"count":0}],"isBlockCoverage":false},{"functionName":"toTrace$0","ranges":[{"startOffset":817366,"endOffset":817684,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":817702,"endOffset":818222,"count":0}],"isBlockCoverage":false},{"functionName":"get$traces","ranges":[{"startOffset":818262,"endOffset":818306,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":818364,"endOffset":818720,"count":1},{"startOffset":818496,"endOffset":818714,"count":0}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":818738,"endOffset":818792,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":818856,"endOffset":819515,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":819600,"endOffset":819679,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":819761,"endOffset":819943,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":820026,"endOffset":820116,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":820197,"endOffset":820307,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":820389,"endOffset":820699,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":820777,"endOffset":820853,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":820933,"endOffset":821283,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":821364,"endOffset":821467,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":821546,"endOffset":821837,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":821917,"endOffset":822083,"count":0}],"isBlockCoverage":false},{"functionName":"get$isCore","ranges":[{"startOffset":822149,"endOffset":822214,"count":0}],"isBlockCoverage":false},{"functionName":"get$library","ranges":[{"startOffset":822233,"endOffset":822388,"count":0}],"isBlockCoverage":false},{"functionName":"get$$package","ranges":[{"startOffset":822408,"endOffset":822583,"count":0}],"isBlockCoverage":false},{"functionName":"get$location","ranges":[{"startOffset":822603,"endOffset":822908,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":822926,"endOffset":823016,"count":0}],"isBlockCoverage":false},{"functionName":"get$uri","ranges":[{"startOffset":823031,"endOffset":823072,"count":0}],"isBlockCoverage":false},{"functionName":"get$line","ranges":[{"startOffset":823088,"endOffset":823130,"count":0}],"isBlockCoverage":false},{"functionName":"get$column","ranges":[{"startOffset":823148,"endOffset":823192,"count":0}],"isBlockCoverage":false},{"functionName":"get$member","ranges":[{"startOffset":823210,"endOffset":823254,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":823318,"endOffset":824399,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":824483,"endOffset":825317,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":825415,"endOffset":826447,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":826536,"endOffset":827780,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":827870,"endOffset":829445,"count":0}],"isBlockCoverage":false},{"functionName":"get$_chain","ranges":[{"startOffset":829515,"endOffset":829701,"count":0}],"isBlockCoverage":false},{"functionName":"get$traces","ranges":[{"startOffset":829719,"endOffset":829782,"count":0}],"isBlockCoverage":false},{"functionName":"foldFrames$2$terse","ranges":[{"startOffset":829808,"endOffset":829965,"count":0}],"isBlockCoverage":false},{"functionName":"toTrace$0","ranges":[{"startOffset":829982,"endOffset":830069,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":830087,"endOffset":830153,"count":0}],"isBlockCoverage":false},{"functionName":"set$_lazy_chain$_inner","ranges":[{"startOffset":830183,"endOffset":830267,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":830371,"endOffset":830474,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":830556,"endOffset":830624,"count":0}],"isBlockCoverage":false},{"functionName":"get$_lazy_trace$_trace","ranges":[{"startOffset":830705,"endOffset":830903,"count":0}],"isBlockCoverage":false},{"functionName":"get$frames","ranges":[{"startOffset":830921,"endOffset":830996,"count":0}],"isBlockCoverage":false},{"functionName":"get$original","ranges":[{"startOffset":831016,"endOffset":831093,"count":0}],"isBlockCoverage":false},{"functionName":"foldFrames$2$terse","ranges":[{"startOffset":831119,"endOffset":831276,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":831294,"endOffset":831372,"count":0}],"isBlockCoverage":false},{"functionName":"set$_lazy_trace$_inner","ranges":[{"startOffset":831402,"endOffset":831486,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":831590,"endOffset":831705,"count":0}],"isBlockCoverage":false},{"functionName":"chainFor$1","ranges":[{"startOffset":831787,"endOffset":832653,"count":0}],"isBlockCoverage":false},{"functionName":"_stack_zone_specification$_registerCallback$1$4","ranges":[{"startOffset":832708,"endOffset":833201,"count":1},{"startOffset":832917,"endOffset":832966,"count":0}],"isBlockCoverage":true},{"functionName":"_stack_zone_specification$_registerCallback$4","ranges":[{"startOffset":833254,"endOffset":833402,"count":0}],"isBlockCoverage":false},{"functionName":"_stack_zone_specification$_registerUnaryCallback$2$4","ranges":[{"startOffset":833462,"endOffset":834015,"count":1},{"startOffset":833704,"endOffset":833762,"count":0}],"isBlockCoverage":true},{"functionName":"_stack_zone_specification$_registerUnaryCallback$4","ranges":[{"startOffset":834073,"endOffset":834241,"count":0}],"isBlockCoverage":false},{"functionName":"_stack_zone_specification$_registerBinaryCallback$3$4","ranges":[{"startOffset":834302,"endOffset":834911,"count":1},{"startOffset":834516,"endOffset":834648,"count":0}],"isBlockCoverage":true},{"functionName":"_stack_zone_specification$_registerBinaryCallback$4","ranges":[{"startOffset":834970,"endOffset":835154,"count":0}],"isBlockCoverage":false},{"functionName":"_stack_zone_specification$_errorCallback$5","ranges":[{"startOffset":835204,"endOffset":836108,"count":0}],"isBlockCoverage":false},{"functionName":"_stack_zone_specification$_run$1$2","ranges":[{"startOffset":836150,"endOffset":836761,"count":1},{"startOffset":836415,"endOffset":836692,"count":0}],"isBlockCoverage":true},{"functionName":"_currentTrace$1","ranges":[{"startOffset":836784,"endOffset":836966,"count":1}],"isBlockCoverage":true},{"functionName":"_trimVMChain$1","ranges":[{"startOffset":836988,"endOffset":837222,"count":0}],"isBlockCoverage":false},{"functionName":"set$_currentNode","ranges":[{"startOffset":837246,"endOffset":837336,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":837412,"endOffset":837498,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":837595,"endOffset":837689,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":837793,"endOffset":837926,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":837944,"endOffset":837998,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":838088,"endOffset":838328,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":838346,"endOffset":838433,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":838524,"endOffset":838580,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":838598,"endOffset":838652,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":838743,"endOffset":839016,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":839034,"endOffset":839141,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":839233,"endOffset":839344,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":839362,"endOffset":839416,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":839497,"endOffset":839889,"count":0}],"isBlockCoverage":false},{"functionName":"toChain$0","ranges":[{"startOffset":839953,"endOffset":840253,"count":0}],"isBlockCoverage":false},{"functionName":"foldFrames$2$terse","ranges":[{"startOffset":840307,"endOffset":841859,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":841877,"endOffset":842341,"count":0}],"isBlockCoverage":false},{"functionName":"get$frames","ranges":[{"startOffset":842381,"endOffset":842425,"count":0}],"isBlockCoverage":false},{"functionName":"get$original","ranges":[{"startOffset":842445,"endOffset":842491,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":842555,"endOffset":842867,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":842947,"endOffset":843025,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":843103,"endOffset":843191,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":843269,"endOffset":843376,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":843454,"endOffset":843542,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":843624,"endOffset":843701,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":843783,"endOffset":843871,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":843954,"endOffset":844072,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":844155,"endOffset":844248,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":844332,"endOffset":844425,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":844509,"endOffset":844603,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":844684,"endOffset":845037,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":845119,"endOffset":845519,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":845599,"endOffset":845702,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":845781,"endOffset":846034,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":846108,"endOffset":846153,"count":0}],"isBlockCoverage":false},{"functionName":"get$uri","ranges":[{"startOffset":846185,"endOffset":846226,"count":0}],"isBlockCoverage":false},{"functionName":"get$line","ranges":[{"startOffset":846242,"endOffset":846279,"count":0}],"isBlockCoverage":false},{"functionName":"get$column","ranges":[{"startOffset":846297,"endOffset":846334,"count":0}],"isBlockCoverage":false},{"functionName":"get$isCore","ranges":[{"startOffset":846352,"endOffset":846390,"count":0}],"isBlockCoverage":false},{"functionName":"get$library","ranges":[{"startOffset":846409,"endOffset":846452,"count":0}],"isBlockCoverage":false},{"functionName":"get$$package","ranges":[{"startOffset":846472,"endOffset":846509,"count":0}],"isBlockCoverage":false},{"functionName":"get$location","ranges":[{"startOffset":846529,"endOffset":846572,"count":0}],"isBlockCoverage":false},{"functionName":"get$member","ranges":[{"startOffset":846590,"endOffset":846634,"count":0}],"isBlockCoverage":false},{"functionName":"get$stream","ranges":[{"startOffset":846691,"endOffset":846863,"count":1}],"isBlockCoverage":true},{"functionName":"get$sink","ranges":[{"startOffset":846879,"endOffset":846922,"count":1}],"isBlockCoverage":true},{"functionName":"GuaranteeChannel$3$allowSinkErrors","ranges":[{"startOffset":846964,"endOffset":847401,"count":1}],"isBlockCoverage":true},{"functionName":"_onSinkDisconnected$0","ranges":[{"startOffset":847430,"endOffset":847602,"count":0}],"isBlockCoverage":false},{"functionName":"set$_sink","ranges":[{"startOffset":847619,"endOffset":847714,"count":1}],"isBlockCoverage":true},{"functionName":"set$_streamController","ranges":[{"startOffset":847743,"endOffset":847876,"count":1}],"isBlockCoverage":true},{"functionName":"set$_subscription","ranges":[{"startOffset":847901,"endOffset":848024,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":848085,"endOffset":848387,"count":1},{"startOffset":848177,"endOffset":848184,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":848468,"endOffset":848594,"count":0}],"isBlockCoverage":false},{"functionName":"get$done","ranges":[{"startOffset":848666,"endOffset":848725,"count":0}],"isBlockCoverage":false},{"functionName":"add$1","ranges":[{"startOffset":848738,"endOffset":849217,"count":1},{"startOffset":848863,"endOffset":848935,"count":0},{"startOffset":848992,"endOffset":849070,"count":0},{"startOffset":849110,"endOffset":849117,"count":0}],"isBlockCoverage":true},{"functionName":"addError$2","ranges":[{"startOffset":849235,"endOffset":849669,"count":0}],"isBlockCoverage":false},{"functionName":"addError$1","ranges":[{"startOffset":849687,"endOffset":849753,"count":0}],"isBlockCoverage":false},{"functionName":"_addError$2","ranges":[{"startOffset":849772,"endOffset":850246,"count":0}],"isBlockCoverage":false},{"functionName":"_addError$1","ranges":[{"startOffset":850265,"endOffset":850332,"count":0}],"isBlockCoverage":false},{"functionName":"addStream$1","ranges":[{"startOffset":850351,"endOffset":851289,"count":1},{"startOffset":850488,"endOffset":850561,"count":0},{"startOffset":850618,"endOffset":850697,"count":0},{"startOffset":850729,"endOffset":850857,"count":0}],"isBlockCoverage":true},{"functionName":"close$0","ranges":[{"startOffset":851304,"endOffset":851793,"count":0}],"isBlockCoverage":false},{"functionName":"_onStreamDisconnected$0","ranges":[{"startOffset":851824,"endOffset":852220,"count":0}],"isBlockCoverage":false},{"functionName":"set$_addStreamSubscription","ranges":[{"startOffset":852254,"endOffset":852404,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":852558,"endOffset":852577,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":852665,"endOffset":852791,"count":0}],"isBlockCoverage":false},{"functionName":"_MultiChannel$1","ranges":[{"startOffset":852869,"endOffset":853574,"count":1}],"isBlockCoverage":true},{"functionName":"virtualChannel$1","ranges":[{"startOffset":853598,"endOffset":855403,"count":1},{"startOffset":854008,"endOffset":854335,"count":0},{"startOffset":854389,"endOffset":854435,"count":0},{"startOffset":854564,"endOffset":854665,"count":0}],"isBlockCoverage":true},{"functionName":"virtualChannel$0","ranges":[{"startOffset":855427,"endOffset":855487,"count":1}],"isBlockCoverage":true},{"functionName":"_closeChannel$2","ranges":[{"startOffset":855510,"endOffset":855929,"count":0}],"isBlockCoverage":false},{"functionName":"_closeInnerChannel$0","ranges":[{"startOffset":855957,"endOffset":856432,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":856514,"endOffset":856645,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":856663,"endOffset":856718,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":856777,"endOffset":856842,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":856920,"endOffset":857524,"count":1},{"startOffset":857122,"endOffset":857129,"count":0},{"startOffset":857353,"endOffset":857369,"count":0},{"startOffset":857463,"endOffset":857518,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":857602,"endOffset":857750,"count":0}],"isBlockCoverage":false},{"functionName":"$signature","ranges":[{"startOffset":857768,"endOffset":857847,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":857920,"endOffset":858103,"count":1}],"isBlockCoverage":true},{"functionName":"$signature","ranges":[{"startOffset":858121,"endOffset":858184,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":858258,"endOffset":858370,"count":0}],"isBlockCoverage":false},{"functionName":"get$stream","ranges":[{"startOffset":858463,"endOffset":858515,"count":0}],"isBlockCoverage":false},{"functionName":"set$_stream_channel_completer$_channel","ranges":[{"startOffset":858606,"endOffset":858735,"count":1}],"isBlockCoverage":true},{"functionName":"get$local","ranges":[{"startOffset":858798,"endOffset":858842,"count":0}],"isBlockCoverage":false},{"functionName":"set$_local","ranges":[{"startOffset":858860,"endOffset":858957,"count":1}],"isBlockCoverage":true},{"functionName":"set$_foreign","ranges":[{"startOffset":858977,"endOffset":859080,"count":1}],"isBlockCoverage":true},{"functionName":"get$stream","ranges":[{"startOffset":859169,"endOffset":859221,"count":1}],"isBlockCoverage":true},{"functionName":"spanFrom$1","ranges":[{"startOffset":859374,"endOffset":859530,"count":0}],"isBlockCoverage":false},{"functionName":"matches$1","ranges":[{"startOffset":859547,"endOffset":859856,"count":0}],"isBlockCoverage":false},{"functionName":"error$3$length$position","ranges":[{"startOffset":859887,"endOffset":860142,"count":0}],"isBlockCoverage":false},{"functionName":"get$lastMatch","ranges":[{"startOffset":860259,"endOffset":860437,"count":0}],"isBlockCoverage":false},{"functionName":"peekChar$0","ranges":[{"startOffset":860455,"endOffset":860647,"count":0}],"isBlockCoverage":false},{"functionName":"scan$1","ranges":[{"startOffset":860661,"endOffset":860895,"count":0}],"isBlockCoverage":false},{"functionName":"expect$2$name","ranges":[{"startOffset":860916,"endOffset":861423,"count":0}],"isBlockCoverage":false},{"functionName":"expect$1","ranges":[{"startOffset":861439,"endOffset":861512,"count":0}],"isBlockCoverage":false},{"functionName":"matches$1","ranges":[{"startOffset":861529,"endOffset":861791,"count":0}],"isBlockCoverage":false},{"functionName":"glyphOrAscii$2","ranges":[{"startOffset":861849,"endOffset":861911,"count":0}],"isBlockCoverage":false},{"functionName":"get$horizontalLine","ranges":[{"startOffset":861937,"endOffset":861973,"count":0}],"isBlockCoverage":false},{"functionName":"get$verticalLine","ranges":[{"startOffset":861997,"endOffset":862033,"count":0}],"isBlockCoverage":false},{"functionName":"get$topLeftCorner","ranges":[{"startOffset":862058,"endOffset":862094,"count":0}],"isBlockCoverage":false},{"functionName":"get$bottomLeftCorner","ranges":[{"startOffset":862122,"endOffset":862158,"count":0}],"isBlockCoverage":false},{"functionName":"get$upEnd","ranges":[{"startOffset":862175,"endOffset":862211,"count":0}],"isBlockCoverage":false},{"functionName":"get$downEnd","ranges":[{"startOffset":862230,"endOffset":862266,"count":0}],"isBlockCoverage":false},{"functionName":"glyphOrAscii$2","ranges":[{"startOffset":862326,"endOffset":862382,"count":0}],"isBlockCoverage":false},{"functionName":"get$horizontalLine","ranges":[{"startOffset":862408,"endOffset":862449,"count":0}],"isBlockCoverage":false},{"functionName":"get$verticalLine","ranges":[{"startOffset":862473,"endOffset":862514,"count":0}],"isBlockCoverage":false},{"functionName":"get$topLeftCorner","ranges":[{"startOffset":862539,"endOffset":862580,"count":0}],"isBlockCoverage":false},{"functionName":"get$bottomLeftCorner","ranges":[{"startOffset":862608,"endOffset":862649,"count":0}],"isBlockCoverage":false},{"functionName":"get$upEnd","ranges":[{"startOffset":862666,"endOffset":862707,"count":0}],"isBlockCoverage":false},{"functionName":"get$downEnd","ranges":[{"startOffset":862726,"endOffset":862767,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":862840,"endOffset":864682,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":863077,"endOffset":864609,"count":1},{"startOffset":863167,"endOffset":863223,"count":0},{"startOffset":863485,"endOffset":863577,"count":0},{"startOffset":863993,"endOffset":864097,"count":0},{"startOffset":864323,"endOffset":864422,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":864764,"endOffset":865103,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":865187,"endOffset":865869,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":865953,"endOffset":866183,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":866268,"endOffset":866429,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":866513,"endOffset":866721,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":866796,"endOffset":866858,"count":0}],"isBlockCoverage":false},{"functionName":"test$9$onPlatform$retry$skip$solo$tags$testOn$timeout","ranges":[{"startOffset":866971,"endOffset":867811,"count":1},{"startOffset":867323,"endOffset":867326,"count":0},{"startOffset":867550,"endOffset":867557,"count":0},{"startOffset":867633,"endOffset":867659,"count":0}],"isBlockCoverage":true},{"functionName":"group$9$onPlatform$retry$skip$solo$tags$testOn$timeout","ranges":[{"startOffset":867873,"endOffset":869608,"count":1},{"startOffset":868325,"endOffset":868328,"count":0},{"startOffset":868584,"endOffset":868610,"count":0},{"startOffset":868684,"endOffset":868702,"count":0},{"startOffset":869525,"endOffset":869602,"count":0}],"isBlockCoverage":true},{"functionName":"build$0","ranges":[{"startOffset":869623,"endOffset":870102,"count":1}],"isBlockCoverage":true},{"functionName":"_checkNotBuilt$1","ranges":[{"startOffset":870126,"endOffset":870294,"count":1},{"startOffset":870183,"endOffset":870293,"count":0}],"isBlockCoverage":true},{"functionName":"_runSetUps$0","ranges":[{"startOffset":870314,"endOffset":871575,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":870514,"endOffset":871496,"count":1},{"startOffset":870604,"endOffset":870660,"count":0}],"isBlockCoverage":true},{"functionName":"get$_setUpAll","ranges":[{"startOffset":871596,"endOffset":871633,"count":1}],"isBlockCoverage":true},{"functionName":"get$_tearDownAll","ranges":[{"startOffset":871657,"endOffset":872027,"count":1},{"startOffset":871775,"endOffset":871849,"count":0},{"startOffset":871850,"endOffset":871873,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":872085,"endOffset":874867,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":872360,"endOffset":874794,"count":1},{"startOffset":872450,"endOffset":872506,"count":0},{"startOffset":873288,"endOffset":874287,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":874945,"endOffset":875120,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":875200,"endOffset":876169,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":875387,"endOffset":876096,"count":1},{"startOffset":875477,"endOffset":875533,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":876247,"endOffset":876413,"count":1},{"startOffset":876332,"endOffset":876412,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":876491,"endOffset":876827,"count":1},{"startOffset":876626,"endOffset":876669,"count":0},{"startOffset":876670,"endOffset":876812,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":876911,"endOffset":876963,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":877049,"endOffset":877288,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":877374,"endOffset":877550,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":877637,"endOffset":879068,"count":0}],"isBlockCoverage":false},{"functionName":"forPlatform$1","ranges":[{"startOffset":879136,"endOffset":879644,"count":1},{"startOffset":879307,"endOffset":879319,"count":0},{"startOffset":879481,"endOffset":879510,"count":0},{"startOffset":879520,"endOffset":879532,"count":0}],"isBlockCoverage":true},{"functionName":"_group$_map$1","ranges":[{"startOffset":879665,"endOffset":880149,"count":1}],"isBlockCoverage":true},{"functionName":"get$name","ranges":[{"startOffset":880187,"endOffset":880237,"count":0}],"isBlockCoverage":false},{"functionName":"get$metadata","ranges":[{"startOffset":880257,"endOffset":880303,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":880365,"endOffset":880437,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":880512,"endOffset":880602,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":880678,"endOffset":880754,"count":1}],"isBlockCoverage":true},{"functionName":"load$2$groups","ranges":[{"startOffset":880858,"endOffset":881479,"count":1}],"isBlockCoverage":true},{"functionName":"forPlatform$1","ranges":[{"startOffset":881500,"endOffset":881799,"count":1},{"startOffset":881648,"endOffset":881660,"count":0}],"isBlockCoverage":true},{"functionName":"get$name","ranges":[{"startOffset":881815,"endOffset":881865,"count":0}],"isBlockCoverage":false},{"functionName":"get$metadata","ranges":[{"startOffset":881885,"endOffset":881931,"count":0}],"isBlockCoverage":false},{"functionName":"get$_outstandingCallbacks","ranges":[{"startOffset":881994,"endOffset":882266,"count":1},{"startOffset":882147,"endOffset":882265,"count":0}],"isBlockCoverage":true},{"functionName":"addOutstandingCallback$0","ranges":[{"startOffset":882298,"endOffset":882562,"count":0}],"isBlockCoverage":false},{"functionName":"waitForOutstandingCallbacks$1","ranges":[{"startOffset":882599,"endOffset":883243,"count":1}],"isBlockCoverage":true},{"functionName":"unclosable$1$1","ranges":[{"startOffset":883265,"endOffset":883512,"count":1}],"isBlockCoverage":true},{"functionName":"heartbeat$0","ranges":[{"startOffset":883531,"endOffset":884164,"count":1},{"startOffset":883729,"endOffset":883736,"count":0},{"startOffset":883989,"endOffset":883996,"count":0}],"isBlockCoverage":true},{"functionName":"_handleError$3","ranges":[{"startOffset":884186,"endOffset":885992,"count":0}],"isBlockCoverage":false},{"functionName":"_handleError$2","ranges":[{"startOffset":886014,"endOffset":886096,"count":0}],"isBlockCoverage":false},{"functionName":"_invoker$_onRun$0","ranges":[{"startOffset":886121,"endOffset":886628,"count":1}],"isBlockCoverage":true},{"functionName":"_runTearDowns$0","ranges":[{"startOffset":886651,"endOffset":888109,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":886875,"endOffset":888027,"count":1},{"startOffset":886965,"endOffset":887021,"count":0},{"startOffset":887385,"endOffset":887694,"count":0},{"startOffset":887707,"endOffset":887841,"count":0}],"isBlockCoverage":true},{"functionName":"call$5","ranges":[{"startOffset":888167,"endOffset":888558,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":888637,"endOffset":888765,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":888865,"endOffset":889886,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":889058,"endOffset":889813,"count":1},{"startOffset":889148,"endOffset":889204,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":889986,"endOffset":890094,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":890175,"endOffset":890978,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":891060,"endOffset":891255,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":891337,"endOffset":891638,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":891722,"endOffset":891930,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":892015,"endOffset":892186,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":892264,"endOffset":892515,"count":1},{"startOffset":892445,"endOffset":892477,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":892594,"endOffset":893102,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":893182,"endOffset":895232,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":893413,"endOffset":895159,"count":1},{"startOffset":893503,"endOffset":893559,"count":0},{"startOffset":894440,"endOffset":894592,"count":0},{"startOffset":894648,"endOffset":894893,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":895313,"endOffset":896507,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":895504,"endOffset":896434,"count":1},{"startOffset":895594,"endOffset":895650,"count":0}],"isBlockCoverage":true},{"functionName":"call$4","ranges":[{"startOffset":896588,"endOffset":896759,"count":0}],"isBlockCoverage":false},{"functionName":"decrement$0","ranges":[{"startOffset":896834,"endOffset":897013,"count":1},{"startOffset":896886,"endOffset":896893,"count":0},{"startOffset":896977,"endOffset":896984,"count":0}],"isBlockCoverage":true},{"functionName":"run$0","ranges":[{"startOffset":897087,"endOffset":897565,"count":0}],"isBlockCoverage":false},{"functionName":"addError$2","ranges":[{"startOffset":897624,"endOffset":897936,"count":0}],"isBlockCoverage":false},{"functionName":"setState$1","ranges":[{"startOffset":897954,"endOffset":898264,"count":1},{"startOffset":898062,"endOffset":898069,"count":0},{"startOffset":898141,"endOffset":898148,"count":0}],"isBlockCoverage":true},{"functionName":"message$1","ranges":[{"startOffset":898281,"endOffset":898470,"count":0}],"isBlockCoverage":false},{"functionName":"_live_test_controller$_run$0","ranges":[{"startOffset":898506,"endOffset":898976,"count":1},{"startOffset":898579,"endOffset":898668,"count":0},{"startOffset":898737,"endOffset":898829,"count":0}],"isBlockCoverage":true},{"functionName":"_live_test_controller$_close$0","ranges":[{"startOffset":899014,"endOffset":899384,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":899464,"endOffset":899507,"count":0}],"isBlockCoverage":false},{"functionName":"_validateTags$0","ranges":[{"startOffset":899561,"endOffset":900156,"count":1},{"startOffset":899966,"endOffset":900155,"count":0}],"isBlockCoverage":true},{"functionName":"validatePlatformSelectors$1","ranges":[{"startOffset":900191,"endOffset":900418,"count":1}],"isBlockCoverage":true},{"functionName":"merge$1","ranges":[{"startOffset":900433,"endOffset":901393,"count":1}],"isBlockCoverage":true},{"functionName":"change$4$onPlatform$skip$skipReason$timeout","ranges":[{"startOffset":901444,"endOffset":902100,"count":0}],"isBlockCoverage":false},{"functionName":"change$1$onPlatform","ranges":[{"startOffset":902127,"endOffset":902248,"count":0}],"isBlockCoverage":false},{"functionName":"change$1$timeout","ranges":[{"startOffset":902272,"endOffset":902387,"count":0}],"isBlockCoverage":false},{"functionName":"change$2$skip$skipReason","ranges":[{"startOffset":902419,"endOffset":902546,"count":0}],"isBlockCoverage":false},{"functionName":"forPlatform$1","ranges":[{"startOffset":902567,"endOffset":902916,"count":1},{"startOffset":902687,"endOffset":902915,"count":0}],"isBlockCoverage":true},{"functionName":"serialize$0","ranges":[{"startOffset":902935,"endOffset":903762,"count":1},{"startOffset":903242,"endOffset":903261,"count":0}],"isBlockCoverage":true},{"functionName":"_serializeTimeout$1","ranges":[{"startOffset":903789,"endOffset":904104,"count":1},{"startOffset":903878,"endOffset":903892,"count":0},{"startOffset":903951,"endOffset":903965,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":904170,"endOffset":904437,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":904519,"endOffset":904859,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":904944,"endOffset":905183,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":905270,"endOffset":905391,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":905478,"endOffset":905558,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":905656,"endOffset":905903,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":905982,"endOffset":906116,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":906196,"endOffset":906330,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":906415,"endOffset":906760,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":906843,"endOffset":907050,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":907134,"endOffset":907382,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":907458,"endOffset":907501,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":907566,"endOffset":907676,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":907762,"endOffset":907799,"count":1}],"isBlockCoverage":true},{"functionName":"validate$1","ranges":[{"startOffset":907875,"endOffset":908141,"count":1},{"startOffset":908007,"endOffset":908140,"count":0}],"isBlockCoverage":true},{"functionName":"evaluate$1","ranges":[{"startOffset":908159,"endOffset":908292,"count":1}],"isBlockCoverage":true},{"functionName":"intersection$1","ranges":[{"startOffset":908314,"endOffset":908542,"count":1},{"startOffset":908448,"endOffset":908541,"count":0}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":908560,"endOffset":908639,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":908650,"endOffset":908848,"count":0}],"isBlockCoverage":false},{"functionName":"get$hashCode","ranges":[{"startOffset":908868,"endOffset":908949,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":909016,"endOffset":909144,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":909234,"endOffset":909377,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":909467,"endOffset":909603,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":909692,"endOffset":910518,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":910585,"endOffset":910628,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":910700,"endOffset":910802,"count":1}],"isBlockCoverage":true},{"functionName":"configure$3$except$mapper$only","ranges":[{"startOffset":910902,"endOffset":911192,"count":1},{"startOffset":911107,"endOffset":911132,"count":0},{"startOffset":911165,"endOffset":911186,"count":0}],"isBlockCoverage":true},{"functionName":"configure$2$except$only","ranges":[{"startOffset":911223,"endOffset":911323,"count":1}],"isBlockCoverage":true},{"functionName":"configure$1$mapper","ranges":[{"startOffset":911349,"endOffset":911443,"count":1}],"isBlockCoverage":true},{"functionName":"formatStackTrace$2$verbose","ranges":[{"startOffset":911477,"endOffset":912169,"count":0}],"isBlockCoverage":false},{"functionName":"set$_except","ranges":[{"startOffset":912188,"endOffset":912268,"count":0}],"isBlockCoverage":false},{"functionName":"set$_only","ranges":[{"startOffset":912285,"endOffset":912359,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":912440,"endOffset":912670,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":912729,"endOffset":912905,"count":1},{"startOffset":912783,"endOffset":912796,"count":0},{"startOffset":912867,"endOffset":912898,"count":0}],"isBlockCoverage":true},{"functionName":"get$hashCode","ranges":[{"startOffset":912925,"endOffset":913054,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":913072,"endOffset":913383,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":913430,"endOffset":913473,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":913521,"endOffset":913564,"count":0}],"isBlockCoverage":false},{"functionName":"toString$0","ranges":[{"startOffset":913717,"endOffset":913763,"count":0}],"isBlockCoverage":false},{"functionName":"get$message","ranges":[{"startOffset":913782,"endOffset":913835,"count":0}],"isBlockCoverage":false},{"functionName":"call$5","ranges":[{"startOffset":913888,"endOffset":914188,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":914260,"endOffset":914278,"count":1}],"isBlockCoverage":true},{"functionName":"merge$1","ranges":[{"startOffset":914342,"endOffset":915081,"count":1},{"startOffset":914467,"endOffset":914494,"count":0},{"startOffset":914552,"endOffset":914583,"count":0},{"startOffset":914632,"endOffset":914853,"count":0},{"startOffset":914955,"endOffset":914972,"count":0},{"startOffset":915015,"endOffset":915032,"count":0}],"isBlockCoverage":true},{"functionName":"apply$1","ranges":[{"startOffset":915096,"endOffset":915445,"count":1},{"startOffset":915179,"endOffset":915191,"count":0},{"startOffset":915319,"endOffset":915336,"count":0}],"isBlockCoverage":true},{"functionName":"get$hashCode","ranges":[{"startOffset":915465,"endOffset":915577,"count":0}],"isBlockCoverage":false},{"functionName":"$eq","ranges":[{"startOffset":915588,"endOffset":915784,"count":1},{"startOffset":915642,"endOffset":915655,"count":0}],"isBlockCoverage":true},{"functionName":"toString$0","ranges":[{"startOffset":915802,"endOffset":916008,"count":0}],"isBlockCoverage":false},{"functionName":"_serializeGroup$3","ranges":[{"startOffset":916070,"endOffset":917084,"count":1},{"startOffset":916473,"endOffset":916517,"count":0}],"isBlockCoverage":true},{"functionName":"_serializeTest$3","ranges":[{"startOffset":917108,"endOffset":917764,"count":1},{"startOffset":917540,"endOffset":917584,"count":0}],"isBlockCoverage":true},{"functionName":"_runLiveTest$2","ranges":[{"startOffset":917786,"endOffset":918752,"count":1}],"isBlockCoverage":true},{"functionName":"call$4","ranges":[{"startOffset":918817,"endOffset":919145,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":919231,"endOffset":919250,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":919335,"endOffset":919891,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":919976,"endOffset":920289,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":920375,"endOffset":925739,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":920701,"endOffset":925666,"count":1},{"startOffset":920791,"endOffset":920847,"count":0},{"startOffset":921070,"endOffset":921774,"count":0},{"startOffset":921820,"endOffset":922042,"count":0},{"startOffset":922087,"endOffset":922311,"count":0},{"startOffset":923050,"endOffset":923091,"count":0},{"startOffset":923567,"endOffset":923597,"count":0}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":925826,"endOffset":927365,"count":1},{"startOffset":925967,"endOffset":926041,"count":0},{"startOffset":926601,"endOffset":926671,"count":0},{"startOffset":927004,"endOffset":927069,"count":0},{"startOffset":927115,"endOffset":927359,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":927453,"endOffset":927588,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":927676,"endOffset":928035,"count":1}],"isBlockCoverage":true},{"functionName":"call$2","ranges":[{"startOffset":928122,"endOffset":928276,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":928370,"endOffset":928663,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":928757,"endOffset":929103,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":929194,"endOffset":929380,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":929472,"endOffset":929733,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":929826,"endOffset":930378,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":930471,"endOffset":930825,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":930918,"endOffset":931101,"count":1}],"isBlockCoverage":true},{"functionName":"call$1","ranges":[{"startOffset":931193,"endOffset":931352,"count":1}],"isBlockCoverage":true},{"functionName":"connectOut$1","ranges":[{"startOffset":931434,"endOffset":932439,"count":1},{"startOffset":931560,"endOffset":931587,"count":0},{"startOffset":931674,"endOffset":931767,"count":0}],"isBlockCoverage":true},{"functionName":"get$length","ranges":[{"startOffset":932491,"endOffset":932603,"count":0}],"isBlockCoverage":false},{"functionName":"get$iterator","ranges":[{"startOffset":932623,"endOffset":932784,"count":0}],"isBlockCoverage":false},{"functionName":"toSet$0","ranges":[{"startOffset":932799,"endOffset":932888,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":933051,"endOffset":933169,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":933252,"endOffset":933441,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":933506,"endOffset":933888,"count":0}],"isBlockCoverage":false},{"functionName":"get$_onUnpaused","ranges":[{"startOffset":933961,"endOffset":934099,"count":0}],"isBlockCoverage":false},{"functionName":"get$success","ranges":[{"startOffset":934118,"endOffset":935569,"count":0}],"isBlockCoverage":false},{"functionName":"get$liveTests","ranges":[{"startOffset":935590,"endOffset":936069,"count":0}],"isBlockCoverage":false},{"functionName":"Engine$3$concurrency$coverage$maxSuites","ranges":[{"startOffset":936116,"endOffset":936304,"count":0}],"isBlockCoverage":false},{"functionName":"run$0","ranges":[{"startOffset":936317,"endOffset":936943,"count":0}],"isBlockCoverage":false},{"functionName":"_runGroup$3","ranges":[{"startOffset":936962,"endOffset":937125,"count":0}],"isBlockCoverage":false},{"functionName":"_runGroup$body$Engine","ranges":[{"startOffset":937154,"endOffset":945098,"count":0}],"isBlockCoverage":false},{"functionName":"_engine$_runLiveTest$3$countSuccess","ranges":[{"startOffset":945141,"endOffset":945283,"count":0}],"isBlockCoverage":false},{"functionName":"_engine$_runLiveTest$2","ranges":[{"startOffset":945313,"endOffset":945444,"count":0}],"isBlockCoverage":false},{"functionName":"_runLiveTest$body$Engine","ranges":[{"startOffset":945476,"endOffset":948266,"count":0}],"isBlockCoverage":false},{"functionName":"_runSkippedTest$3","ranges":[{"startOffset":948291,"endOffset":948443,"count":0}],"isBlockCoverage":false},{"functionName":"_runSkippedTest$body$Engine","ranges":[{"startOffset":948478,"endOffset":950257,"count":0}],"isBlockCoverage":false},{"functionName":"_addLiveSuite$1","ranges":[{"startOffset":950280,"endOffset":951177,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":951236,"endOffset":951499,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":951570,"endOffset":951828,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":951900,"endOffset":951919,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":951993,"endOffset":952254,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":952330,"endOffset":952400,"count":0}],"isBlockCoverage":false},{"functionName":"$call$body$Engine_run__closure","ranges":[{"startOffset":952438,"endOffset":953809,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":953885,"endOffset":955623,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":955700,"endOffset":955766,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":955842,"endOffset":956062,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":956145,"endOffset":956558,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":956643,"endOffset":956740,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":956824,"endOffset":956842,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":956928,"endOffset":956946,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":957033,"endOffset":957502,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":957589,"endOffset":957607,"count":0}],"isBlockCoverage":false},{"functionName":"LiveSuiteController$1","ranges":[{"startOffset":957758,"endOffset":958027,"count":0}],"isBlockCoverage":false},{"functionName":"reportLiveTest$2$countSuccess","ranges":[{"startOffset":958064,"endOffset":958889,"count":0}],"isBlockCoverage":false},{"functionName":"close$0","ranges":[{"startOffset":958904,"endOffset":959033,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":959097,"endOffset":959152,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":959237,"endOffset":959256,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":959354,"endOffset":959967,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":960057,"endOffset":961699,"count":0}],"isBlockCoverage":false},{"functionName":"_onTestStarted$1","ranges":[{"startOffset":961781,"endOffset":963251,"count":0}],"isBlockCoverage":false},{"functionName":"_onStateChange$2","ranges":[{"startOffset":963275,"endOffset":963683,"count":0}],"isBlockCoverage":false},{"functionName":"_expanded$_onError$3","ranges":[{"startOffset":963711,"endOffset":964186,"count":0}],"isBlockCoverage":false},{"functionName":"_expanded$_onDone$1","ranges":[{"startOffset":964213,"endOffset":965237,"count":0}],"isBlockCoverage":false},{"functionName":"_progressLine$3$color$suffix","ranges":[{"startOffset":965273,"endOffset":967686,"count":0}],"isBlockCoverage":false},{"functionName":"_progressLine$2$suffix","ranges":[{"startOffset":967716,"endOffset":967820,"count":0}],"isBlockCoverage":false},{"functionName":"_progressLine$2$color","ranges":[{"startOffset":967849,"endOffset":967951,"count":0}],"isBlockCoverage":false},{"functionName":"_progressLine$1","ranges":[{"startOffset":967974,"endOffset":968068,"count":0}],"isBlockCoverage":false},{"functionName":"_description$1","ranges":[{"startOffset":968090,"endOffset":968203,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":968279,"endOffset":968386,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":968484,"endOffset":968637,"count":0}],"isBlockCoverage":false},{"functionName":"call$1","ranges":[{"startOffset":968735,"endOffset":969071,"count":0}],"isBlockCoverage":false},{"functionName":"_runner_suite$_close$0","ranges":[{"startOffset":969197,"endOffset":969305,"count":0}],"isBlockCoverage":false},{"functionName":"set$_runner_suite$_suite","ranges":[{"startOffset":969337,"endOffset":969408,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":969481,"endOffset":970301,"count":0}],"isBlockCoverage":false},{"functionName":"writeln$1","ranges":[{"startOffset":970445,"endOffset":970545,"count":0}],"isBlockCoverage":false},{"functionName":"_flush$0","ranges":[{"startOffset":970561,"endOffset":970743,"count":0}],"isBlockCoverage":false},{"functionName":"call$2","ranges":[{"startOffset":970896,"endOffset":971053,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":971128,"endOffset":974564,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":974638,"endOffset":974728,"count":0}],"isBlockCoverage":false},{"functionName":"call$0","ranges":[{"startOffset":974798,"endOffset":974868,"count":1}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":974937,"endOffset":975688,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":975109,"endOffset":975615,"count":1},{"startOffset":975199,"endOffset":975255,"count":0},{"startOffset":975440,"endOffset":975452,"count":0}],"isBlockCoverage":true},{"functionName":"call$0","ranges":[{"startOffset":975756,"endOffset":975816,"count":1}],"isBlockCoverage":true},{"functionName":"aliases","ranges":[{"startOffset":975846,"endOffset":976773,"count":1}],"isBlockCoverage":true},{"functionName":"installTearOffs","ranges":[{"startOffset":976781,"endOffset":984996,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":978155,"endOffset":978225,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":978518,"endOffset":978624,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":978734,"endOffset":978870,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":979096,"endOffset":979215,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":979350,"endOffset":979489,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":979626,"endOffset":979781,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":984923,"endOffset":984982,"count":0}],"isBlockCoverage":false},{"functionName":"inheritance","ranges":[{"startOffset":985004,"endOffset":1007745,"count":1}],"isBlockCoverage":true},{"functionName":"rtii","ranges":[{"startOffset":1029633,"endOffset":1042848,"count":1},{"startOffset":1042844,"endOffset":1042847,"count":0}],"isBlockCoverage":true},{"functionName":"constants","ranges":[{"startOffset":1042856,"endOffset":1058765,"count":1}],"isBlockCoverage":true},{"functionName":"getTagFallback","ranges":[{"startOffset":1044143,"endOffset":1044257,"count":0}],"isBlockCoverage":false},{"functionName":"C.C_JS_CONST0","ranges":[{"startOffset":1044279,"endOffset":1045394,"count":1},{"startOffset":1045302,"endOffset":1045317,"count":0}],"isBlockCoverage":true},{"functionName":"getTag","ranges":[{"startOffset":1044346,"endOffset":1044449,"count":0}],"isBlockCoverage":false},{"functionName":"getUnknownTag","ranges":[{"startOffset":1044452,"endOffset":1044669,"count":0}],"isBlockCoverage":false},{"functionName":"getUnknownTagGenericBrowser","ranges":[{"startOffset":1044672,"endOffset":1044847,"count":0}],"isBlockCoverage":false},{"functionName":"prototypeForTag","ranges":[{"startOffset":1044850,"endOffset":1045116,"count":1},{"startOffset":1044920,"endOffset":1044932,"count":0},{"startOffset":1045066,"endOffset":1045078,"count":0}],"isBlockCoverage":true},{"functionName":"discriminator","ranges":[{"startOffset":1045119,"endOffset":1045163,"count":0}],"isBlockCoverage":false},{"functionName":"C.C_JS_CONST6","ranges":[{"startOffset":1045416,"endOffset":1045880,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1045452,"endOffset":1045877,"count":1},{"startOffset":1045508,"endOffset":1045521,"count":0},{"startOffset":1045599,"endOffset":1045612,"count":0},{"startOffset":1045838,"endOffset":1045876,"count":0}],"isBlockCoverage":true},{"functionName":"confirm","ranges":[{"startOffset":1045656,"endOffset":1045763,"count":1}],"isBlockCoverage":true},{"functionName":"C.C_JS_CONST1","ranges":[{"startOffset":1045902,"endOffset":1046051,"count":1},{"startOffset":1045989,"endOffset":1046050,"count":0}],"isBlockCoverage":true},{"functionName":"C.C_JS_CONST2","ranges":[{"startOffset":1046073,"endOffset":1046546,"count":1}],"isBlockCoverage":true},{"functionName":"getTagFixed","ranges":[{"startOffset":1046169,"endOffset":1046350,"count":0}],"isBlockCoverage":false},{"functionName":"prototypeForTagFixed","ranges":[{"startOffset":1046353,"endOffset":1046466,"count":1},{"startOffset":1046417,"endOffset":1046429,"count":0}],"isBlockCoverage":true},{"functionName":"C.C_JS_CONST5","ranges":[{"startOffset":1046568,"endOffset":1047098,"count":1},{"startOffset":1046655,"endOffset":1046659,"count":0},{"startOffset":1046716,"endOffset":1047097,"count":0}],"isBlockCoverage":true},{"functionName":"getTagFirefox","ranges":[{"startOffset":1046975,"endOffset":1047064,"count":0}],"isBlockCoverage":false},{"functionName":"C.C_JS_CONST4","ranges":[{"startOffset":1047120,"endOffset":1048002,"count":1},{"startOffset":1047207,"endOffset":1047211,"count":0},{"startOffset":1047269,"endOffset":1048001,"count":0}],"isBlockCoverage":true},{"functionName":"getTagIE","ranges":[{"startOffset":1047534,"endOffset":1047777,"count":0}],"isBlockCoverage":false},{"functionName":"prototypeForTagIE","ranges":[{"startOffset":1047780,"endOffset":1047928,"count":0}],"isBlockCoverage":false},{"functionName":"C.C_JS_CONST3","ranges":[{"startOffset":1048024,"endOffset":1048057,"count":1}],"isBlockCoverage":true},{"functionName":"staticFields","ranges":[{"startOffset":1058773,"endOffset":1059835,"count":1}],"isBlockCoverage":true},{"functionName":"lazyInitializers","ranges":[{"startOffset":1059843,"endOffset":1071865,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1059985,"endOffset":1060063,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1060144,"endOffset":1060213,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1060314,"endOffset":1060502,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1060599,"endOffset":1060802,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1060895,"endOffset":1061006,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1061113,"endOffset":1061364,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1061467,"endOffset":1061580,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1061697,"endOffset":1061952,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1062053,"endOffset":1062168,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1062283,"endOffset":1062472,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1062583,"endOffset":1062700,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1062825,"endOffset":1063018,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1063117,"endOffset":1063192,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1063257,"endOffset":1063342,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1063407,"endOffset":1063495,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1063564,"endOffset":1063625,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1063716,"endOffset":1064340,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1064411,"endOffset":1064569,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1064640,"endOffset":1064721,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1064794,"endOffset":1064854,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1064911,"endOffset":1064961,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1065054,"endOffset":1065143,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1065214,"endOffset":1065295,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1065367,"endOffset":1065450,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1065513,"endOffset":1065593,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1065648,"endOffset":1065830,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1065873,"endOffset":1065947,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1065982,"endOffset":1066052,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1066095,"endOffset":1066172,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1066223,"endOffset":1066364,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1066419,"endOffset":1066666,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1066713,"endOffset":1066941,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1066998,"endOffset":1067058,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1067101,"endOffset":1067158,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1067205,"endOffset":1067275,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1067322,"endOffset":1067389,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1067434,"endOffset":1067481,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1067526,"endOffset":1067631,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1067676,"endOffset":1067794,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1067851,"endOffset":1067937,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1067996,"endOffset":1068106,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1068173,"endOffset":1068312,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1068369,"endOffset":1068474,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1068523,"endOffset":1068622,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1068673,"endOffset":1068736,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1068797,"endOffset":1068883,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1068952,"endOffset":1069039,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1069134,"endOffset":1069181,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1069234,"endOffset":1069315,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1069360,"endOffset":1069430,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1069483,"endOffset":1069550,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1069617,"endOffset":1069721,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1069778,"endOffset":1069882,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1069939,"endOffset":1070078,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1070155,"endOffset":1070594,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1070646,"endOffset":1070693,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1070745,"endOffset":1070792,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1070849,"endOffset":1070907,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1070979,"endOffset":1071062,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1071147,"endOffset":1071254,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1071331,"endOffset":1071859,"count":0}],"isBlockCoverage":false},{"functionName":"nativeSupport","ranges":[{"startOffset":1071873,"endOffset":1079153,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1071905,"endOffset":1072690,"count":1},{"startOffset":1072593,"endOffset":1072689,"count":0}],"isBlockCoverage":true},{"functionName":"intern","ranges":[{"startOffset":1071937,"endOffset":1072063,"count":1}],"isBlockCoverage":true},{"functionName":"init.getIsolateTag","ranges":[{"startOffset":1072092,"endOffset":1072176,"count":1}],"isBlockCoverage":true},{"functionName":"Function.call$0","ranges":[{"startOffset":1079188,"endOffset":1079223,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$1","ranges":[{"startOffset":1079255,"endOffset":1079292,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2","ranges":[{"startOffset":1079324,"endOffset":1079367,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3$3","ranges":[{"startOffset":1079401,"endOffset":1079450,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$2","ranges":[{"startOffset":1079484,"endOffset":1079527,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$1$1","ranges":[{"startOffset":1079561,"endOffset":1079598,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$1","ranges":[{"startOffset":1079632,"endOffset":1079669,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3","ranges":[{"startOffset":1079701,"endOffset":1079750,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$4","ranges":[{"startOffset":1079782,"endOffset":1079837,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3$1","ranges":[{"startOffset":1079871,"endOffset":1079908,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$3","ranges":[{"startOffset":1079942,"endOffset":1079991,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$1$2","ranges":[{"startOffset":1080025,"endOffset":1080068,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$5","ranges":[{"startOffset":1080100,"endOffset":1080161,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3$4","ranges":[{"startOffset":1080195,"endOffset":1080250,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$4","ranges":[{"startOffset":1080284,"endOffset":1080339,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$1$4","ranges":[{"startOffset":1080373,"endOffset":1080428,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$3$6","ranges":[{"startOffset":1080462,"endOffset":1080529,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$5","ranges":[{"startOffset":1080563,"endOffset":1080624,"count":0}],"isBlockCoverage":false},{"functionName":"Function.call$2$0","ranges":[{"startOffset":1080658,"endOffset":1080693,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1080759,"endOffset":1081298,"count":1},{"startOffset":1080821,"endOffset":1080919,"count":0},{"startOffset":1080974,"endOffset":1081297,"count":0}],"isBlockCoverage":true},{"functionName":"onLoad","ranges":[{"startOffset":1081021,"endOffset":1081191,"count":0}],"isBlockCoverage":false},{"functionName":"","ranges":[{"startOffset":1081300,"endOffset":1081476,"count":1},{"startOffset":1081418,"endOffset":1081445,"count":0}],"isBlockCoverage":true}]},{"scriptId":"32","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":284,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":283,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_startsWith$20","ranges":[{"startOffset":82,"endOffset":281,"count":0}],"isBlockCoverage":false}]},{"scriptId":"33","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":270,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onPause$01","ranges":[{"startOffset":82,"endOffset":268,"count":0}],"isBlockCoverage":false}]},{"scriptId":"34","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onResume$02","ranges":[{"startOffset":82,"endOffset":269,"count":0}],"isBlockCoverage":false}]},{"scriptId":"35","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":276,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_add$13","ranges":[{"startOffset":82,"endOffset":274,"count":0}],"isBlockCoverage":false}]},{"scriptId":"36","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":270,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_addError$24","ranges":[{"startOffset":82,"endOffset":268,"count":0}],"isBlockCoverage":false}]},{"scriptId":"37","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":270,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_complete$15","ranges":[{"startOffset":82,"endOffset":268,"count":1}],"isBlockCoverage":true}]},{"scriptId":"38","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":270,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_complete$16","ranges":[{"startOffset":82,"endOffset":268,"count":1}],"isBlockCoverage":true}]},{"scriptId":"39","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":276,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__completeError$27","ranges":[{"startOffset":82,"endOffset":274,"count":1}],"isBlockCoverage":true}]},{"scriptId":"40","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":276,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_add$18","ranges":[{"startOffset":82,"endOffset":274,"count":1}],"isBlockCoverage":true}]},{"scriptId":"41","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":270,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_addError$29","ranges":[{"startOffset":82,"endOffset":268,"count":1}],"isBlockCoverage":true}]},{"scriptId":"42","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":280,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":279,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_close$010","ranges":[{"startOffset":82,"endOffset":277,"count":1}],"isBlockCoverage":true}]},{"scriptId":"43","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":268,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":267,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__add$111","ranges":[{"startOffset":82,"endOffset":265,"count":1}],"isBlockCoverage":true}]},{"scriptId":"44","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":280,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":279,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__async$_addError$212","ranges":[{"startOffset":82,"endOffset":277,"count":1}],"isBlockCoverage":true}]},{"scriptId":"45","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":270,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":269,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__close$013","ranges":[{"startOffset":82,"endOffset":267,"count":1}],"isBlockCoverage":true}]},{"scriptId":"46","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onPause$014","ranges":[{"startOffset":82,"endOffset":269,"count":0}],"isBlockCoverage":false}]},{"scriptId":"47","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":273,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onResume$015","ranges":[{"startOffset":82,"endOffset":270,"count":1}],"isBlockCoverage":true}]},{"scriptId":"48","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":278,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_add$116","ranges":[{"startOffset":82,"endOffset":275,"count":1}],"isBlockCoverage":true}]},{"scriptId":"49","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onPause$017","ranges":[{"startOffset":82,"endOffset":269,"count":0}],"isBlockCoverage":false}]},{"scriptId":"50","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":273,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onResume$018","ranges":[{"startOffset":82,"endOffset":270,"count":0}],"isBlockCoverage":false}]},{"scriptId":"51","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":273,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__sendDone$019","ranges":[{"startOffset":82,"endOffset":270,"count":0}],"isBlockCoverage":false}]},{"scriptId":"52","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":283,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":282,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_contains$120","ranges":[{"startOffset":82,"endOffset":280,"count":0}],"isBlockCoverage":false}]},{"scriptId":"53","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":280,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":279,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_close$021","ranges":[{"startOffset":82,"endOffset":277,"count":0}],"isBlockCoverage":false}]},{"scriptId":"54","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":273,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onListen$022","ranges":[{"startOffset":82,"endOffset":270,"count":0}],"isBlockCoverage":false}]},{"scriptId":"55","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":282,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":281,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onCancelBroadcast$023","ranges":[{"startOffset":82,"endOffset":279,"count":0}],"isBlockCoverage":false}]},{"scriptId":"56","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":283,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":282,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_contains$124","ranges":[{"startOffset":82,"endOffset":280,"count":0}],"isBlockCoverage":false}]},{"scriptId":"57","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":279,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":278,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__recursiveMatch$425","ranges":[{"startOffset":82,"endOffset":276,"count":0}],"isBlockCoverage":false}]},{"scriptId":"58","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":288,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":287,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_message$2$color26","ranges":[{"startOffset":82,"endOffset":285,"count":0}],"isBlockCoverage":false}]},{"scriptId":"59","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":309,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":308,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__stack_zone_specification$_registerCallback$1$427","ranges":[{"startOffset":82,"endOffset":306,"count":1}],"isBlockCoverage":true}]},{"scriptId":"60","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":314,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":313,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__stack_zone_specification$_registerUnaryCallback$2$428","ranges":[{"startOffset":82,"endOffset":311,"count":1}],"isBlockCoverage":true}]},{"scriptId":"61","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":315,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":314,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__stack_zone_specification$_registerBinaryCallback$3$429","ranges":[{"startOffset":82,"endOffset":312,"count":1}],"isBlockCoverage":true}]},{"scriptId":"62","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":304,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":303,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__stack_zone_specification$_errorCallback$530","ranges":[{"startOffset":82,"endOffset":301,"count":1}],"isBlockCoverage":true}]},{"scriptId":"63","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":271,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_addError$231","ranges":[{"startOffset":82,"endOffset":269,"count":1}],"isBlockCoverage":true}]},{"scriptId":"64","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":273,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":272,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__addError$232","ranges":[{"startOffset":82,"endOffset":270,"count":1}],"isBlockCoverage":true}]},{"scriptId":"65","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":280,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":279,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_close$033","ranges":[{"startOffset":82,"endOffset":277,"count":0}],"isBlockCoverage":false}]},{"scriptId":"66","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":282,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":281,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__closeInnerChannel$034","ranges":[{"startOffset":82,"endOffset":279,"count":1}],"isBlockCoverage":true}]},{"scriptId":"67","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":279,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":278,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__invoker$_onRun$035","ranges":[{"startOffset":82,"endOffset":276,"count":1}],"isBlockCoverage":true}]},{"scriptId":"68","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":276,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__runTearDowns$036","ranges":[{"startOffset":82,"endOffset":274,"count":1}],"isBlockCoverage":true}]},{"scriptId":"69","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":267,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":266,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_run$037","ranges":[{"startOffset":82,"endOffset":264,"count":0}],"isBlockCoverage":false}]},{"scriptId":"70","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":282,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":281,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_message$138","ranges":[{"startOffset":82,"endOffset":279,"count":0}],"isBlockCoverage":false}]},{"scriptId":"71","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":267,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":266,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff_run$039","ranges":[{"startOffset":82,"endOffset":264,"count":0}],"isBlockCoverage":false}]},{"scriptId":"72","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":278,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":277,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__onTestStarted$140","ranges":[{"startOffset":82,"endOffset":275,"count":0}],"isBlockCoverage":false}]},{"scriptId":"73","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":281,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":280,"count":1}],"isBlockCoverage":true},{"functionName":"tearOff__expanded$_onDone$141","ranges":[{"startOffset":82,"endOffset":278,"count":0}],"isBlockCoverage":false}]},{"scriptId":"74","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"75","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":92,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":91,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":89,"count":1},{"startOffset":87,"endOffset":88,"count":0}],"isBlockCoverage":true}]},{"scriptId":"76","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"77","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":86,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":85,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":83,"count":0}],"isBlockCoverage":false}]},{"scriptId":"78","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"79","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":106,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":105,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":103,"count":0}],"isBlockCoverage":false}]},{"scriptId":"80","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"81","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":86,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":85,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":83,"count":0}],"isBlockCoverage":false}]},{"scriptId":"82","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":62,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":61,"count":1}],"isBlockCoverage":true}]},{"scriptId":"83","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":92,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":91,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":89,"count":0}],"isBlockCoverage":false}]},{"scriptId":"84","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"85","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":93,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":92,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":90,"count":1},{"startOffset":87,"endOffset":89,"count":0}],"isBlockCoverage":true}]},{"scriptId":"86","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"87","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":84,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":83,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":81,"count":0}],"isBlockCoverage":false}]},{"scriptId":"88","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"89","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":89,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":88,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":86,"count":0}],"isBlockCoverage":false}]},{"scriptId":"90","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"91","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":99,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":98,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":96,"count":1}],"isBlockCoverage":true}]},{"scriptId":"92","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"93","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":96,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":95,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":93,"count":0}],"isBlockCoverage":false}]},{"scriptId":"94","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"95","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":80,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":79,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":77,"count":1}],"isBlockCoverage":true}]},{"scriptId":"96","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"97","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":96,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":95,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":93,"count":0}],"isBlockCoverage":false}]},{"scriptId":"98","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"99","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":91,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":90,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":88,"count":1},{"startOffset":85,"endOffset":87,"count":0}],"isBlockCoverage":true}]},{"scriptId":"100","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"101","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":105,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":104,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":102,"count":1}],"isBlockCoverage":true}]},{"scriptId":"102","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"103","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":84,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":83,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":81,"count":0}],"isBlockCoverage":false}]},{"scriptId":"104","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"105","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":132,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":131,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":129,"count":0}],"isBlockCoverage":false}]},{"scriptId":"106","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"107","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":151,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":150,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":148,"count":1}],"isBlockCoverage":true}]},{"scriptId":"108","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"109","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":137,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":136,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":134,"count":1}],"isBlockCoverage":true}]},{"scriptId":"110","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"111","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":146,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":145,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":143,"count":1}],"isBlockCoverage":true}]},{"scriptId":"112","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":64,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":63,"count":1}],"isBlockCoverage":true}]},{"scriptId":"113","url":"","functions":[{"functionName":"","ranges":[{"startOffset":0,"endOffset":103,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":1,"endOffset":102,"count":1}],"isBlockCoverage":true},{"functionName":"","ranges":[{"startOffset":32,"endOffset":100,"count":1}],"isBlockCoverage":true}]}]
\ No newline at end of file
diff --git a/pkgs/coverage/test/test_files/function_coverage_app.dart b/pkgs/coverage/test/test_files/function_coverage_app.dart
new file mode 100644
index 0000000..c4868f9
--- /dev/null
+++ b/pkgs/coverage/test/test_files/function_coverage_app.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'test_library.dart';
+
+int normalFunction() {
+ return 123;
+}
+
+abstract class BaseClass {
+ int abstractMethod();
+}
+
+class SomeClass extends BaseClass {
+ SomeClass() : x = 123;
+
+ // Creates an implicit getter and setter that should be ignored.
+ int x;
+
+ int normalMethod() {
+ return 123;
+ }
+
+ static int staticMethod() {
+ return 123;
+ }
+
+ @override
+ int abstractMethod() {
+ return 123;
+ }
+}
+
+extension SomeExtension on SomeClass {
+ int extensionMethod() {
+ return 123;
+ }
+}
+
+class OtherClass {
+ int otherMethod() {
+ return 123;
+ }
+}
+
+void main() {
+ print(normalFunction());
+ print(SomeClass().normalMethod());
+ print(SomeClass.staticMethod());
+ print(SomeClass().extensionMethod());
+ print(SomeClass().abstractMethod());
+ print(OtherClass().otherMethod());
+ print(libraryFunction());
+ print(otherLibraryFunction());
+}
+
+// ignore_for_file: unreachable_from_main
diff --git a/pkgs/coverage/test/test_files/main_test.js b/pkgs/coverage/test/test_files/main_test.js
new file mode 100644
index 0000000..4c4fb3e
--- /dev/null
+++ b/pkgs/coverage/test/test_files/main_test.js
@@ -0,0 +1,26570 @@
+// Generated by dart2js (fast startup emitter, strong), the Dart to JavaScript compiler version: 2.8.0-292505767.
+// The code supports the following hooks:
+// dartPrint(message):
+// if this function is defined it is called instead of the Dart [print]
+// method.
+//
+// dartMainRunner(main, args):
+// if this function is defined, the Dart [main] method will not be invoked
+// directly. Instead, a closure that will invoke [main], and its arguments
+// [args] is passed to [dartMainRunner].
+//
+// dartDeferredLibraryLoader(uri, successCallback, errorCallback):
+// if this function is defined, it will be called when a deferred library
+// is loaded. It should load and eval the javascript of `uri`, and call
+// successCallback. If it fails to do so, it should call errorCallback with
+// an error.
+//
+// dartCallInstrumentation(id, qualifiedName):
+// if this function is defined, it will be called at each entry of a
+// method or constructor. Used only when compiling programs with
+// --experiment-call-instrumentation.
+(function dartProgram() {
+ function copyProperties(from, to) {
+ var keys = Object.keys(from);
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ to[key] = from[key];
+ }
+ }
+ var supportsDirectProtoAccess = function() {
+ var cls = function() {
+ };
+ cls.prototype = {p: {}};
+ var object = new cls();
+ if (!(object.__proto__ && object.__proto__.p === cls.prototype.p))
+ return false;
+ try {
+ if (typeof navigator != "undefined" && typeof navigator.userAgent == "string" && navigator.userAgent.indexOf("Chrome/") >= 0)
+ return true;
+ if (typeof version == "function" && version.length == 0) {
+ var v = version();
+ if (/^\d+\.\d+\.\d+\.\d+$/.test(v))
+ return true;
+ }
+ } catch (_) {
+ }
+ return false;
+ }();
+ function setFunctionNamesIfNecessary(holders) {
+ function t() {
+ }
+ ;
+ if (typeof t.name == "string")
+ return;
+ for (var i = 0; i < holders.length; i++) {
+ var holder = holders[i];
+ var keys = Object.keys(holder);
+ for (var j = 0; j < keys.length; j++) {
+ var key = keys[j];
+ var f = holder[key];
+ if (typeof f == 'function')
+ f.name = key;
+ }
+ }
+ }
+ function inherit(cls, sup) {
+ cls.prototype.constructor = cls;
+ cls.prototype["$is" + cls.name] = cls;
+ if (sup != null) {
+ if (supportsDirectProtoAccess) {
+ cls.prototype.__proto__ = sup.prototype;
+ return;
+ }
+ var clsPrototype = Object.create(sup.prototype);
+ copyProperties(cls.prototype, clsPrototype);
+ cls.prototype = clsPrototype;
+ }
+ }
+ function inheritMany(sup, classes) {
+ for (var i = 0; i < classes.length; i++)
+ inherit(classes[i], sup);
+ }
+ function mixin(cls, mixin) {
+ copyProperties(mixin.prototype, cls.prototype);
+ cls.prototype.constructor = cls;
+ }
+ function lazy(holder, name, getterName, initializer) {
+ var uninitializedSentinel = holder;
+ holder[name] = uninitializedSentinel;
+ holder[getterName] = function() {
+ holder[getterName] = function() {
+ H.throwCyclicInit(name);
+ };
+ var result;
+ var sentinelInProgress = initializer;
+ try {
+ if (holder[name] === uninitializedSentinel) {
+ result = holder[name] = sentinelInProgress;
+ result = holder[name] = initializer();
+ } else
+ result = holder[name];
+ } finally {
+ if (result === sentinelInProgress)
+ holder[name] = null;
+ holder[getterName] = function() {
+ return this[name];
+ };
+ }
+ return result;
+ };
+ }
+ function makeConstList(list) {
+ list.immutable$list = Array;
+ list.fixed$length = Array;
+ return list;
+ }
+ function convertToFastObject(properties) {
+ function t() {
+ }
+ t.prototype = properties;
+ new t();
+ return properties;
+ }
+ function convertAllToFastObject(arrayOfObjects) {
+ for (var i = 0; i < arrayOfObjects.length; ++i)
+ convertToFastObject(arrayOfObjects[i]);
+ }
+ var functionCounter = 0;
+ function tearOffGetter(funcs, applyTrampolineIndex, reflectionInfo, name, isIntercepted) {
+ return isIntercepted ? new Function("funcs", "applyTrampolineIndex", "reflectionInfo", "name", "H", "c", "return function tearOff_" + name + functionCounter++ + "(receiver) {" + "if (c === null) c = " + "H.closureFromTearOff" + "(" + "this, funcs, applyTrampolineIndex, reflectionInfo, false, true, name);" + "return new c(this, funcs[0], receiver, name);" + "}")(funcs, applyTrampolineIndex, reflectionInfo, name, H, null) : new Function("funcs", "applyTrampolineIndex", "reflectionInfo", "name", "H", "c", "return function tearOff_" + name + functionCounter++ + "() {" + "if (c === null) c = " + "H.closureFromTearOff" + "(" + "this, funcs, applyTrampolineIndex, reflectionInfo, false, false, name);" + "return new c(this, funcs[0], null, name);" + "}")(funcs, applyTrampolineIndex, reflectionInfo, name, H, null);
+ }
+ function tearOff(funcs, applyTrampolineIndex, reflectionInfo, isStatic, name, isIntercepted) {
+ var cache = null;
+ return isStatic ? function() {
+ if (cache === null)
+ cache = H.closureFromTearOff(this, funcs, applyTrampolineIndex, reflectionInfo, true, false, name).prototype;
+ return cache;
+ } : tearOffGetter(funcs, applyTrampolineIndex, reflectionInfo, name, isIntercepted);
+ }
+ var typesOffset = 0;
+ function installTearOff(container, getterName, isStatic, isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex) {
+ var funs = [];
+ for (var i = 0; i < funsOrNames.length; i++) {
+ var fun = funsOrNames[i];
+ if (typeof fun == 'string')
+ fun = container[fun];
+ fun.$callName = callNames[i];
+ funs.push(fun);
+ }
+ var fun = funs[0];
+ fun.$requiredArgCount = requiredParameterCount;
+ fun.$defaultValues = optionalParameterDefaultValues;
+ var reflectionInfo = funType;
+ if (typeof reflectionInfo == "number")
+ reflectionInfo += typesOffset;
+ var name = funsOrNames[0];
+ fun.$stubName = name;
+ var getterFunction = tearOff(funs, applyIndex || 0, reflectionInfo, isStatic, name, isIntercepted);
+ container[getterName] = getterFunction;
+ if (isStatic)
+ fun.$tearOff = getterFunction;
+ }
+ function installStaticTearOff(container, getterName, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex) {
+ return installTearOff(container, getterName, true, false, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex);
+ }
+ function installInstanceTearOff(container, getterName, isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex) {
+ return installTearOff(container, getterName, false, isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex);
+ }
+ function setOrUpdateInterceptorsByTag(newTags) {
+ var tags = init.interceptorsByTag;
+ if (!tags) {
+ init.interceptorsByTag = newTags;
+ return;
+ }
+ copyProperties(newTags, tags);
+ }
+ function setOrUpdateLeafTags(newTags) {
+ var tags = init.leafTags;
+ if (!tags) {
+ init.leafTags = newTags;
+ return;
+ }
+ copyProperties(newTags, tags);
+ }
+ function updateTypes(newTypes) {
+ var types = init.types;
+ var length = types.length;
+ types.push.apply(types, newTypes);
+ return length;
+ }
+ function updateHolder(holder, newHolder) {
+ copyProperties(newHolder, holder);
+ return holder;
+ }
+ var hunkHelpers = function() {
+ var mkInstance = function(isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, applyIndex) {
+ return function(container, getterName, name, funType) {
+ return installInstanceTearOff(container, getterName, isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, [name], funType, applyIndex);
+ };
+ },
+ mkStatic = function(requiredParameterCount, optionalParameterDefaultValues, callNames, applyIndex) {
+ return function(container, getterName, name, funType) {
+ return installStaticTearOff(container, getterName, requiredParameterCount, optionalParameterDefaultValues, callNames, [name], funType, applyIndex);
+ };
+ };
+ return {inherit: inherit, inheritMany: inheritMany, mixin: mixin, installStaticTearOff: installStaticTearOff, installInstanceTearOff: installInstanceTearOff, _instance_0u: mkInstance(0, 0, null, ["call$0"], 0), _instance_1u: mkInstance(0, 1, null, ["call$1"], 0), _instance_2u: mkInstance(0, 2, null, ["call$2"], 0), _instance_0i: mkInstance(1, 0, null, ["call$0"], 0), _instance_1i: mkInstance(1, 1, null, ["call$1"], 0), _instance_2i: mkInstance(1, 2, null, ["call$2"], 0), _static_0: mkStatic(0, null, ["call$0"], 0), _static_1: mkStatic(1, null, ["call$1"], 0), _static_2: mkStatic(2, null, ["call$2"], 0), makeConstList: makeConstList, lazy: lazy, updateHolder: updateHolder, convertToFastObject: convertToFastObject, setFunctionNamesIfNecessary: setFunctionNamesIfNecessary, updateTypes: updateTypes, setOrUpdateInterceptorsByTag: setOrUpdateInterceptorsByTag, setOrUpdateLeafTags: setOrUpdateLeafTags};
+ }();
+ function initializeDeferredHunk(hunk) {
+ typesOffset = init.types.length;
+ hunk(hunkHelpers, init, holders, $);
+ }
+ function getGlobalFromName(name) {
+ for (var i = 0; i < holders.length; i++) {
+ if (holders[i] == C)
+ continue;
+ if (holders[i][name])
+ return holders[i][name];
+ }
+ }
+ var C = {},
+ H = {JS_CONST: function JS_CONST() {
+ },
+ CastIterable_CastIterable: function(source, $S, $T) {
+ if ($S._eval$1("EfficientLengthIterable<0>")._is(source))
+ return new H._EfficientLengthCastIterable(source, $S._eval$1("@<0>")._bind$1($T)._eval$1("_EfficientLengthCastIterable<1,2>"));
+ return new H.CastIterable(source, $S._eval$1("@<0>")._bind$1($T)._eval$1("CastIterable<1,2>"));
+ },
+ hexDigitValue: function(char) {
+ var digit, letter;
+ H.assertHelper(char <= 65535);
+ digit = char ^ 48;
+ if (digit <= 9)
+ return digit;
+ letter = char | 32;
+ if (97 <= letter && letter <= 102)
+ return letter - 87;
+ return -1;
+ },
+ SubListIterable$: function(_iterable, _start, _endOrLength, $E) {
+ P.RangeError_checkNotNegative(_start, "start");
+ if (_endOrLength != null) {
+ P.RangeError_checkNotNegative(_endOrLength, "end");
+ if (_start > _endOrLength)
+ H.throwExpression(P.RangeError$range(_start, 0, _endOrLength, "start", null));
+ }
+ return new H.SubListIterable(_iterable, _start, _endOrLength, $E._eval$1("SubListIterable<0>"));
+ },
+ MappedIterable_MappedIterable: function(iterable, $function, $S, $T) {
+ if (type$.EfficientLengthIterable_dynamic._is(iterable))
+ return new H.EfficientLengthMappedIterable(iterable, $function, $S._eval$1("@<0>")._bind$1($T)._eval$1("EfficientLengthMappedIterable<1,2>"));
+ return new H.MappedIterable(iterable, $function, $S._eval$1("@<0>")._bind$1($T)._eval$1("MappedIterable<1,2>"));
+ },
+ IterableElementError_noElement: function() {
+ return new P.StateError("No element");
+ },
+ IterableElementError_tooMany: function() {
+ return new P.StateError("Too many elements");
+ },
+ IterableElementError_tooFew: function() {
+ return new P.StateError("Too few elements");
+ },
+ _CastIterableBase: function _CastIterableBase() {
+ },
+ CastIterator: function CastIterator(t0, t1) {
+ this._source = t0;
+ this.$ti = t1;
+ },
+ CastIterable: function CastIterable(t0, t1) {
+ this._source = t0;
+ this.$ti = t1;
+ },
+ _EfficientLengthCastIterable: function _EfficientLengthCastIterable(t0, t1) {
+ this._source = t0;
+ this.$ti = t1;
+ },
+ CastMap: function CastMap(t0, t1) {
+ this._source = t0;
+ this.$ti = t1;
+ },
+ CastMap_forEach_closure: function CastMap_forEach_closure(t0, t1) {
+ this.$this = t0;
+ this.f = t1;
+ },
+ CodeUnits: function CodeUnits(t0) {
+ this._string = t0;
+ },
+ EfficientLengthIterable: function EfficientLengthIterable() {
+ },
+ ListIterable: function ListIterable() {
+ },
+ SubListIterable: function SubListIterable(t0, t1, t2, t3) {
+ var _ = this;
+ _.__internal$_iterable = t0;
+ _.__internal$_start = t1;
+ _._endOrLength = t2;
+ _.$ti = t3;
+ },
+ ListIterator: function ListIterator(t0, t1, t2) {
+ var _ = this;
+ _.__internal$_iterable = t0;
+ _.__internal$_length = t1;
+ _.__internal$_index = 0;
+ _.__internal$_current = null;
+ _.$ti = t2;
+ },
+ MappedIterable: function MappedIterable(t0, t1, t2) {
+ this.__internal$_iterable = t0;
+ this._f = t1;
+ this.$ti = t2;
+ },
+ EfficientLengthMappedIterable: function EfficientLengthMappedIterable(t0, t1, t2) {
+ this.__internal$_iterable = t0;
+ this._f = t1;
+ this.$ti = t2;
+ },
+ MappedIterator: function MappedIterator(t0, t1, t2) {
+ var _ = this;
+ _.__internal$_current = null;
+ _._iterator = t0;
+ _._f = t1;
+ _.$ti = t2;
+ },
+ MappedListIterable: function MappedListIterable(t0, t1, t2) {
+ this._source = t0;
+ this._f = t1;
+ this.$ti = t2;
+ },
+ WhereIterable: function WhereIterable(t0, t1, t2) {
+ this.__internal$_iterable = t0;
+ this._f = t1;
+ this.$ti = t2;
+ },
+ WhereIterator: function WhereIterator(t0, t1, t2) {
+ this._iterator = t0;
+ this._f = t1;
+ this.$ti = t2;
+ },
+ ExpandIterable: function ExpandIterable(t0, t1, t2) {
+ this.__internal$_iterable = t0;
+ this._f = t1;
+ this.$ti = t2;
+ },
+ ExpandIterator: function ExpandIterator(t0, t1, t2, t3) {
+ var _ = this;
+ _._iterator = t0;
+ _._f = t1;
+ _._currentExpansion = t2;
+ _.__internal$_current = null;
+ _.$ti = t3;
+ },
+ SkipWhileIterable: function SkipWhileIterable(t0, t1, t2) {
+ this.__internal$_iterable = t0;
+ this._f = t1;
+ this.$ti = t2;
+ },
+ SkipWhileIterator: function SkipWhileIterator(t0, t1, t2) {
+ var _ = this;
+ _._iterator = t0;
+ _._f = t1;
+ _._hasSkipped = false;
+ _.$ti = t2;
+ },
+ EmptyIterator: function EmptyIterator(t0) {
+ this.$ti = t0;
+ },
+ FixedLengthListMixin: function FixedLengthListMixin() {
+ },
+ UnmodifiableListMixin: function UnmodifiableListMixin() {
+ },
+ UnmodifiableListBase: function UnmodifiableListBase() {
+ },
+ ReversedListIterable: function ReversedListIterable(t0, t1) {
+ this._source = t0;
+ this.$ti = t1;
+ },
+ Symbol: function Symbol(t0) {
+ this.__internal$_name = t0;
+ },
+ ConstantMap__throwUnmodifiable: function() {
+ throw H.wrapException(P.UnsupportedError$("Cannot modify unmodifiable Map"));
+ },
+ instantiate1: function(f, T1) {
+ var t1 = new H.Instantiation1(f, T1._eval$1("Instantiation1<0>"));
+ t1.Instantiation$1(f);
+ return t1;
+ },
+ unminifyOrTag: function(rawClassName) {
+ var preserved = H.unmangleGlobalNameIfPreservedAnyways(rawClassName);
+ if (typeof preserved == "string")
+ return preserved;
+ return rawClassName;
+ },
+ isJsIndexable: function(object, record) {
+ var result;
+ if (record != null) {
+ result = record.x;
+ if (result != null)
+ return result;
+ }
+ return type$.JavaScriptIndexingBehavior_dynamic._is(object);
+ },
+ S: function(value) {
+ var res;
+ if (typeof value == "string")
+ return value;
+ if (typeof value == "number") {
+ if (value !== 0)
+ return "" + value;
+ } else if (true === value)
+ return "true";
+ else if (false === value)
+ return "false";
+ else if (value == null)
+ return "null";
+ res = J.toString$0$(value);
+ if (typeof res != "string")
+ throw H.wrapException(H.argumentErrorValue(value));
+ return res;
+ },
+ Primitives_objectHashCode: function(object) {
+ var hash = object.$identityHash;
+ if (hash == null) {
+ hash = Math.random() * 0x3fffffff | 0;
+ object.$identityHash = hash;
+ }
+ return hash;
+ },
+ Primitives_parseInt: function(source, radix) {
+ var match, decimalMatch, maxCharCode, digitsPart, t1, i, _null = null;
+ if (typeof source != "string")
+ H.throwExpression(H.argumentErrorValue(source));
+ match = /^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i.exec(source);
+ if (match == null)
+ return _null;
+ if (3 >= match.length)
+ return H.ioore(match, 3);
+ decimalMatch = H._checkStringNullable(match[3]);
+ if (radix == null) {
+ if (decimalMatch != null)
+ return parseInt(source, 10);
+ if (match[2] != null)
+ return parseInt(source, 16);
+ return _null;
+ }
+ if (radix < 2 || radix > 36)
+ throw H.wrapException(P.RangeError$range(radix, 2, 36, "radix", _null));
+ if (radix === 10 && decimalMatch != null)
+ return parseInt(source, 10);
+ if (radix < 10 || decimalMatch == null) {
+ maxCharCode = radix <= 10 ? 47 + radix : 86 + radix;
+ H.assertHelper(typeof match[1] == "string");
+ digitsPart = match[1];
+ for (t1 = digitsPart.length, i = 0; i < t1; ++i)
+ if ((C.JSString_methods._codeUnitAt$1(digitsPart, i) | 32) > maxCharCode)
+ return _null;
+ }
+ return parseInt(source, radix);
+ },
+ Primitives_objectTypeName: function(object) {
+ var t1 = H.Primitives__objectTypeNameNewRti(object);
+ return t1;
+ },
+ Primitives__objectTypeNameNewRti: function(object) {
+ var dispatchName, $constructor, constructorName;
+ if (object instanceof P.Object)
+ return H._rtiToString(H.instanceType(object), null);
+ if (J.getInterceptor$(object) === C.Interceptor_methods || type$.UnknownJavaScriptObject._is(object)) {
+ dispatchName = C.C_JS_CONST(object);
+ if (H.Primitives__saneNativeClassName(dispatchName))
+ return dispatchName;
+ $constructor = object.constructor;
+ if (typeof $constructor == "function") {
+ constructorName = $constructor.name;
+ if (typeof constructorName == "string" && H.Primitives__saneNativeClassName(constructorName))
+ return constructorName;
+ }
+ }
+ return H._rtiToString(H.instanceType(object), null);
+ },
+ Primitives__saneNativeClassName: function($name) {
+ var t1 = $name !== "Object" && $name !== "";
+ return t1;
+ },
+ Primitives_dateNow: function() {
+ return Date.now();
+ },
+ Primitives_initTicker: function() {
+ var $window, performance;
+ if ($.Primitives_timerFrequency != null)
+ return;
+ $.Primitives_timerFrequency = 1000;
+ $.Primitives_timerTicks = H._js_helper_Primitives_dateNow$closure();
+ if (typeof window == "undefined")
+ return;
+ $window = window;
+ if ($window == null)
+ return;
+ performance = $window.performance;
+ if (performance == null)
+ return;
+ if (typeof performance.now != "function")
+ return;
+ $.Primitives_timerFrequency = 1000000;
+ $.Primitives_timerTicks = new H.Primitives_initTicker_closure(performance);
+ },
+ Primitives_currentUri: function() {
+ if (!!self.location)
+ return self.location.href;
+ return null;
+ },
+ Primitives__fromCharCodeApply: function(array) {
+ var result, i, i0, chunkEnd,
+ end = J.get$length$asx(array);
+ if (end <= 500)
+ return String.fromCharCode.apply(null, array);
+ for (result = "", i = 0; i < end; i = i0) {
+ i0 = i + 500;
+ chunkEnd = i0 < end ? i0 : end;
+ result += String.fromCharCode.apply(null, array.slice(i, chunkEnd));
+ }
+ return result;
+ },
+ Primitives_stringFromCodePoints: function(codePoints) {
+ var t1, i,
+ a = H.setRuntimeTypeInfo([], type$.JSArray_int);
+ for (t1 = J.get$iterator$ax(type$.Iterable_dynamic._check(codePoints)); t1.moveNext$0();) {
+ i = t1.get$current();
+ if (!H._isInt(i))
+ throw H.wrapException(H.argumentErrorValue(i));
+ if (i <= 65535)
+ C.JSArray_methods.add$1(a, i);
+ else if (i <= 1114111) {
+ C.JSArray_methods.add$1(a, 55296 + (C.JSInt_methods._shrOtherPositive$1(i - 65536, 10) & 1023));
+ C.JSArray_methods.add$1(a, 56320 + (i & 1023));
+ } else
+ throw H.wrapException(H.argumentErrorValue(i));
+ }
+ return H.Primitives__fromCharCodeApply(a);
+ },
+ Primitives_stringFromCharCodes: function(charCodes) {
+ var t1, i;
+ for (type$.Iterable_dynamic._check(charCodes), t1 = J.get$iterator$ax(charCodes); t1.moveNext$0();) {
+ i = t1.get$current();
+ if (!H._isInt(i))
+ throw H.wrapException(H.argumentErrorValue(i));
+ if (i < 0)
+ throw H.wrapException(H.argumentErrorValue(i));
+ if (i > 65535)
+ return H.Primitives_stringFromCodePoints(charCodes);
+ }
+ return H.Primitives__fromCharCodeApply(type$.List_dynamic._check(charCodes));
+ },
+ Primitives_stringFromNativeUint8List: function(charCodes, start, end) {
+ var i, result, i0, chunkEnd;
+ if (end <= 500 && start === 0 && end === charCodes.length)
+ return String.fromCharCode.apply(null, charCodes);
+ for (i = start, result = ""; i < end; i = i0) {
+ i0 = i + 500;
+ chunkEnd = i0 < end ? i0 : end;
+ result += String.fromCharCode.apply(null, charCodes.subarray(i, chunkEnd));
+ }
+ return result;
+ },
+ Primitives_stringFromCharCode: function(charCode) {
+ var bits;
+ if (typeof charCode !== "number")
+ return H.iae(charCode);
+ if (0 <= charCode) {
+ if (charCode <= 65535)
+ return String.fromCharCode(charCode);
+ if (charCode <= 1114111) {
+ bits = charCode - 65536;
+ return String.fromCharCode((55296 | C.JSInt_methods._shrOtherPositive$1(bits, 10)) >>> 0, 56320 | bits & 1023);
+ }
+ }
+ throw H.wrapException(P.RangeError$range(charCode, 0, 1114111, null, null));
+ },
+ Primitives_lazyAsJsDate: function(receiver) {
+ if (receiver.date === void 0)
+ receiver.date = new Date(receiver._value);
+ return receiver.date;
+ },
+ Primitives_getYear: function(receiver) {
+ var t1 = H.Primitives_lazyAsJsDate(receiver).getUTCFullYear() + 0;
+ return t1;
+ },
+ Primitives_getMonth: function(receiver) {
+ var t1 = H.Primitives_lazyAsJsDate(receiver).getUTCMonth() + 1;
+ return t1;
+ },
+ Primitives_getDay: function(receiver) {
+ var t1 = H.Primitives_lazyAsJsDate(receiver).getUTCDate() + 0;
+ return t1;
+ },
+ Primitives_getHours: function(receiver) {
+ var t1 = H.Primitives_lazyAsJsDate(receiver).getUTCHours() + 0;
+ return t1;
+ },
+ Primitives_getMinutes: function(receiver) {
+ var t1 = H.Primitives_lazyAsJsDate(receiver).getUTCMinutes() + 0;
+ return t1;
+ },
+ Primitives_getSeconds: function(receiver) {
+ var t1 = H.Primitives_lazyAsJsDate(receiver).getUTCSeconds() + 0;
+ return t1;
+ },
+ Primitives_getMilliseconds: function(receiver) {
+ var t1 = H.Primitives_lazyAsJsDate(receiver).getUTCMilliseconds() + 0;
+ return t1;
+ },
+ Primitives_getProperty: function(object, key) {
+ if (object == null || H._isBool(object) || typeof object == "number" || typeof object == "string")
+ throw H.wrapException(H.argumentErrorValue(object));
+ return object[key];
+ },
+ Primitives_setProperty: function(object, key, value) {
+ if (object == null || H._isBool(object) || typeof object == "number" || typeof object == "string")
+ throw H.wrapException(H.argumentErrorValue(object));
+ object[key] = value;
+ },
+ iae: function(argument) {
+ throw H.wrapException(H.argumentErrorValue(argument));
+ },
+ ioore: function(receiver, index) {
+ if (receiver == null)
+ J.get$length$asx(receiver);
+ throw H.wrapException(H.diagnoseIndexError(receiver, index));
+ },
+ diagnoseIndexError: function(indexable, index) {
+ var $length, t1, _s5_ = "index";
+ if (!H._isInt(index))
+ return new P.ArgumentError(true, index, _s5_, null);
+ $length = H._checkIntNullable(J.get$length$asx(indexable));
+ if (!(index < 0)) {
+ if (typeof $length !== "number")
+ return H.iae($length);
+ t1 = index >= $length;
+ } else
+ t1 = true;
+ if (t1)
+ return P.IndexError$(index, indexable, _s5_, null, $length);
+ return P.RangeError$value(index, _s5_);
+ },
+ diagnoseRangeError: function(start, end, $length) {
+ var _s13_ = "Invalid value";
+ if (start < 0 || start > $length)
+ return new P.RangeError(0, $length, true, start, "start", _s13_);
+ if (end != null)
+ if (end < start || end > $length)
+ return new P.RangeError(start, $length, true, end, "end", _s13_);
+ return new P.ArgumentError(true, end, "end", null);
+ },
+ argumentErrorValue: function(object) {
+ return new P.ArgumentError(true, object, null, null);
+ },
+ checkNum: function(value) {
+ if (typeof value != "number")
+ throw H.wrapException(H.argumentErrorValue(value));
+ return value;
+ },
+ wrapException: function(ex) {
+ var wrapper;
+ if (ex == null)
+ ex = new P.NullThrownError();
+ wrapper = new Error();
+ wrapper.dartException = ex;
+ if ("defineProperty" in Object) {
+ Object.defineProperty(wrapper, "message", {get: H.toStringWrapper});
+ wrapper.name = "";
+ } else
+ wrapper.toString = H.toStringWrapper;
+ return wrapper;
+ },
+ toStringWrapper: function() {
+ return J.toString$0$(this.dartException);
+ },
+ throwExpression: function(ex) {
+ throw H.wrapException(ex);
+ },
+ throwConcurrentModificationError: function(collection) {
+ throw H.wrapException(P.ConcurrentModificationError$(collection));
+ },
+ TypeErrorDecoder_extractPattern: function(message) {
+ var match, $arguments, argumentsExpr, expr, method, receiver;
+ message = H.quoteStringForRegExp(message.replace(String({}), '$receiver$'));
+ match = message.match(/\\\$[a-zA-Z]+\\\$/g);
+ if (match == null)
+ match = H.setRuntimeTypeInfo([], type$.JSArray_String);
+ $arguments = match.indexOf("\\$arguments\\$");
+ argumentsExpr = match.indexOf("\\$argumentsExpr\\$");
+ expr = match.indexOf("\\$expr\\$");
+ method = match.indexOf("\\$method\\$");
+ receiver = match.indexOf("\\$receiver\\$");
+ return new H.TypeErrorDecoder(message.replace(new RegExp('\\\\\\$arguments\\\\\\$', 'g'), '((?:x|[^x])*)').replace(new RegExp('\\\\\\$argumentsExpr\\\\\\$', 'g'), '((?:x|[^x])*)').replace(new RegExp('\\\\\\$expr\\\\\\$', 'g'), '((?:x|[^x])*)').replace(new RegExp('\\\\\\$method\\\\\\$', 'g'), '((?:x|[^x])*)').replace(new RegExp('\\\\\\$receiver\\\\\\$', 'g'), '((?:x|[^x])*)'), $arguments, argumentsExpr, expr, method, receiver);
+ },
+ TypeErrorDecoder_provokeCallErrorOn: function(expression) {
+ return function($expr$) {
+ var $argumentsExpr$ = '$arguments$';
+ try {
+ $expr$.$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+ }(expression);
+ },
+ TypeErrorDecoder_provokePropertyErrorOn: function(expression) {
+ return function($expr$) {
+ try {
+ $expr$.$method$;
+ } catch (e) {
+ return e.message;
+ }
+ }(expression);
+ },
+ NullError$: function(_message, match) {
+ return new H.NullError(_message, match == null ? null : match.method);
+ },
+ JsNoSuchMethodError$: function(_message, match) {
+ var t1 = match == null,
+ t2 = t1 ? null : match.method;
+ return new H.JsNoSuchMethodError(_message, t2, t1 ? null : match.receiver);
+ },
+ unwrapException: function(ex) {
+ var message, number, ieErrorCode, nsme, notClosure, nullCall, nullLiteralCall, undefCall, undefLiteralCall, nullProperty, undefProperty, undefLiteralProperty, match, t2, _null = null,
+ t1 = new H.unwrapException_saveStackTrace(ex);
+ if (ex == null)
+ return _null;
+ if (ex instanceof H.ExceptionAndStackTrace)
+ return t1.call$1(ex.dartException);
+ if (typeof ex !== "object")
+ return ex;
+ if ("dartException" in ex)
+ return t1.call$1(ex.dartException);
+ else if (!("message" in ex))
+ return ex;
+ message = ex.message;
+ if ("number" in ex && typeof ex.number == "number") {
+ number = ex.number;
+ ieErrorCode = number & 65535;
+ if ((C.JSInt_methods._shrOtherPositive$1(number, 16) & 8191) === 10)
+ switch (ieErrorCode) {
+ case 438:
+ return t1.call$1(H.JsNoSuchMethodError$(H.S(message) + " (Error " + ieErrorCode + ")", _null));
+ case 445:
+ case 5007:
+ return t1.call$1(H.NullError$(H.S(message) + " (Error " + ieErrorCode + ")", _null));
+ }
+ }
+ if (ex instanceof TypeError) {
+ nsme = $.$get$TypeErrorDecoder_noSuchMethodPattern();
+ notClosure = $.$get$TypeErrorDecoder_notClosurePattern();
+ nullCall = $.$get$TypeErrorDecoder_nullCallPattern();
+ nullLiteralCall = $.$get$TypeErrorDecoder_nullLiteralCallPattern();
+ undefCall = $.$get$TypeErrorDecoder_undefinedCallPattern();
+ undefLiteralCall = $.$get$TypeErrorDecoder_undefinedLiteralCallPattern();
+ nullProperty = $.$get$TypeErrorDecoder_nullPropertyPattern();
+ $.$get$TypeErrorDecoder_nullLiteralPropertyPattern();
+ undefProperty = $.$get$TypeErrorDecoder_undefinedPropertyPattern();
+ undefLiteralProperty = $.$get$TypeErrorDecoder_undefinedLiteralPropertyPattern();
+ match = nsme.matchTypeError$1(message);
+ if (match != null)
+ return t1.call$1(H.JsNoSuchMethodError$(H._checkStringNullable(message), match));
+ else {
+ match = notClosure.matchTypeError$1(message);
+ if (match != null) {
+ match.method = "call";
+ return t1.call$1(H.JsNoSuchMethodError$(H._checkStringNullable(message), match));
+ } else {
+ match = nullCall.matchTypeError$1(message);
+ if (match == null) {
+ match = nullLiteralCall.matchTypeError$1(message);
+ if (match == null) {
+ match = undefCall.matchTypeError$1(message);
+ if (match == null) {
+ match = undefLiteralCall.matchTypeError$1(message);
+ if (match == null) {
+ match = nullProperty.matchTypeError$1(message);
+ if (match == null) {
+ match = nullLiteralCall.matchTypeError$1(message);
+ if (match == null) {
+ match = undefProperty.matchTypeError$1(message);
+ if (match == null) {
+ match = undefLiteralProperty.matchTypeError$1(message);
+ t2 = match != null;
+ } else
+ t2 = true;
+ } else
+ t2 = true;
+ } else
+ t2 = true;
+ } else
+ t2 = true;
+ } else
+ t2 = true;
+ } else
+ t2 = true;
+ } else
+ t2 = true;
+ if (t2)
+ return t1.call$1(H.NullError$(H._checkStringNullable(message), match));
+ }
+ }
+ return t1.call$1(new H.UnknownJsTypeError(typeof message == "string" ? message : ""));
+ }
+ if (ex instanceof RangeError) {
+ if (typeof message == "string" && message.indexOf("call stack") !== -1)
+ return new P.StackOverflowError();
+ message = function(ex) {
+ try {
+ return String(ex);
+ } catch (e) {
+ }
+ return null;
+ }(ex);
+ return t1.call$1(new P.ArgumentError(false, _null, _null, typeof message == "string" ? message.replace(/^RangeError:\s*/, "") : message));
+ }
+ if (typeof InternalError == "function" && ex instanceof InternalError)
+ if (typeof message == "string" && message === "too much recursion")
+ return new P.StackOverflowError();
+ return ex;
+ },
+ getTraceFromException: function(exception) {
+ var trace;
+ if (exception instanceof H.ExceptionAndStackTrace)
+ return exception.stackTrace;
+ if (exception == null)
+ return new H._StackTrace(exception);
+ trace = exception.$cachedTrace;
+ if (trace != null)
+ return trace;
+ return exception.$cachedTrace = new H._StackTrace(exception);
+ },
+ objectHashCode: function(object) {
+ if (object == null || typeof object != 'object')
+ return J.get$hashCode$(object);
+ else
+ return H.Primitives_objectHashCode(object);
+ },
+ fillLiteralMap: function(keyValuePairs, result) {
+ var $length, index, index0, key,
+ t1 = Array.isArray(keyValuePairs);
+ H.assertHelper(t1);
+ $length = keyValuePairs.length;
+ for (index = 0; index < $length;) {
+ index0 = index + 1;
+ H.assertHelper(t1);
+ key = keyValuePairs[index];
+ index = index0 + 1;
+ H.assertHelper(t1);
+ result.$indexSet(0, key, keyValuePairs[index0]);
+ }
+ return result;
+ },
+ fillLiteralSet: function(values, result) {
+ var $length, index,
+ t1 = Array.isArray(values);
+ H.assertHelper(t1);
+ $length = values.length;
+ for (index = 0; index < $length; ++index) {
+ H.assertHelper(t1);
+ result.add$1(0, values[index]);
+ }
+ return result;
+ },
+ invokeClosure: function(closure, numberOfArguments, arg1, arg2, arg3, arg4) {
+ type$.Function._check(closure);
+ switch (H._checkIntNullable(numberOfArguments)) {
+ case 0:
+ return closure.call$0();
+ case 1:
+ return closure.call$1(arg1);
+ case 2:
+ return closure.call$2(arg1, arg2);
+ case 3:
+ return closure.call$3(arg1, arg2, arg3);
+ case 4:
+ return closure.call$4(arg1, arg2, arg3, arg4);
+ }
+ throw H.wrapException(new P._Exception("Unsupported number of arguments for wrapped closure"));
+ },
+ convertDartClosureToJS: function(closure, arity) {
+ var $function;
+ if (closure == null)
+ return null;
+ $function = closure.$identity;
+ if (!!$function)
+ return $function;
+ $function = function(closure, arity, invoke) {
+ return function(a1, a2, a3, a4) {
+ return invoke(closure, arity, a1, a2, a3, a4);
+ };
+ }(closure, arity, H.invokeClosure);
+ closure.$identity = $function;
+ return $function;
+ },
+ Closure_fromTearOff: function(receiver, functions, applyTrampolineIndex, reflectionInfo, isStatic, isIntercepted, propertyName) {
+ var $constructor, t1, trampoline, signatureFunction, applyTrampoline, i, stub, stubCallName, _null = null,
+ $function = functions[0],
+ callName = $function.$callName,
+ $prototype = isStatic ? Object.create(new H.StaticClosure().constructor.prototype) : Object.create(new H.BoundClosure(_null, _null, _null, _null).constructor.prototype);
+ $prototype.$initialize = $prototype.constructor;
+ if (isStatic)
+ $constructor = function static_tear_off() {
+ this.$initialize();
+ };
+ else {
+ t1 = $.Closure_functionCounter;
+ if (typeof t1 !== "number")
+ return t1.$add();
+ $.Closure_functionCounter = t1 + 1;
+ t1 = new Function("a,b,c,d" + t1, "this.$initialize(a,b,c,d" + t1 + ")");
+ $constructor = t1;
+ }
+ $prototype.constructor = $constructor;
+ $constructor.prototype = $prototype;
+ if (!isStatic) {
+ trampoline = H.Closure_forwardCallTo(receiver, $function, isIntercepted);
+ trampoline.$reflectionInfo = reflectionInfo;
+ } else {
+ $prototype.$static_name = propertyName;
+ trampoline = $function;
+ }
+ signatureFunction = H.Closure__computeSignatureFunctionNewRti(reflectionInfo, isStatic, isIntercepted);
+ $prototype.$signature = signatureFunction;
+ $prototype[callName] = trampoline;
+ for (applyTrampoline = trampoline, i = 1; i < functions.length; ++i) {
+ stub = functions[i];
+ stubCallName = stub.$callName;
+ if (stubCallName != null) {
+ stub = isStatic ? stub : H.Closure_forwardCallTo(receiver, stub, isIntercepted);
+ $prototype[stubCallName] = stub;
+ }
+ if (i === applyTrampolineIndex) {
+ stub.$reflectionInfo = reflectionInfo;
+ applyTrampoline = stub;
+ }
+ }
+ $prototype["call*"] = applyTrampoline;
+ $prototype.$requiredArgCount = $function.$requiredArgCount;
+ $prototype.$defaultValues = $function.$defaultValues;
+ return $constructor;
+ },
+ Closure__computeSignatureFunctionNewRti: function(functionType, isStatic, isIntercepted) {
+ var typeEvalMethod;
+ if (typeof functionType == "number")
+ return function(getType, t) {
+ return function() {
+ return getType(t);
+ };
+ }(H.getTypeFromTypesTable, functionType);
+ if (typeof functionType == "string") {
+ if (isStatic)
+ throw H.wrapException("Cannot compute signature for static tearoff.");
+ typeEvalMethod = isIntercepted ? H.BoundClosure_evalRecipeIntercepted : H.BoundClosure_evalRecipe;
+ return function(recipe, evalOnReceiver) {
+ return function() {
+ return evalOnReceiver(this, recipe);
+ };
+ }(functionType, typeEvalMethod);
+ }
+ throw H.wrapException("Error in functionType of tearoff");
+ },
+ Closure_cspForwardCall: function(arity, isSuperCall, stubName, $function) {
+ var getSelf = H.BoundClosure_selfOf;
+ switch (isSuperCall ? -1 : arity) {
+ case 0:
+ return function(n, S) {
+ return function() {
+ return S(this)[n]();
+ };
+ }(stubName, getSelf);
+ case 1:
+ return function(n, S) {
+ return function(a) {
+ return S(this)[n](a);
+ };
+ }(stubName, getSelf);
+ case 2:
+ return function(n, S) {
+ return function(a, b) {
+ return S(this)[n](a, b);
+ };
+ }(stubName, getSelf);
+ case 3:
+ return function(n, S) {
+ return function(a, b, c) {
+ return S(this)[n](a, b, c);
+ };
+ }(stubName, getSelf);
+ case 4:
+ return function(n, S) {
+ return function(a, b, c, d) {
+ return S(this)[n](a, b, c, d);
+ };
+ }(stubName, getSelf);
+ case 5:
+ return function(n, S) {
+ return function(a, b, c, d, e) {
+ return S(this)[n](a, b, c, d, e);
+ };
+ }(stubName, getSelf);
+ default:
+ return function(f, s) {
+ return function() {
+ return f.apply(s(this), arguments);
+ };
+ }($function, getSelf);
+ }
+ },
+ Closure_forwardCallTo: function(receiver, $function, isIntercepted) {
+ var stubName, arity, lookedUpFunction, t1, t2, selfName, $arguments;
+ if (isIntercepted)
+ return H.Closure_forwardInterceptedCallTo(receiver, $function);
+ stubName = $function.$stubName;
+ arity = $function.length;
+ lookedUpFunction = receiver[stubName];
+ t1 = $function == null ? lookedUpFunction == null : $function === lookedUpFunction;
+ t2 = !t1 || arity >= 27;
+ if (t2)
+ return H.Closure_cspForwardCall(arity, !t1, stubName, $function);
+ if (arity === 0) {
+ t1 = $.Closure_functionCounter;
+ if (typeof t1 !== "number")
+ return t1.$add();
+ $.Closure_functionCounter = t1 + 1;
+ selfName = "self" + t1;
+ t1 = "return function(){var " + selfName + " = this.";
+ t2 = $.BoundClosure_selfFieldNameCache;
+ return new Function(t1 + H.S(t2 == null ? $.BoundClosure_selfFieldNameCache = H.BoundClosure_computeFieldNamed("self") : t2) + ";return " + selfName + "." + H.S(stubName) + "();}")();
+ }
+ H.assertHelper(1 <= arity && arity < 27);
+ $arguments = "abcdefghijklmnopqrstuvwxyz".split("").splice(0, arity).join(",");
+ t1 = $.Closure_functionCounter;
+ if (typeof t1 !== "number")
+ return t1.$add();
+ $.Closure_functionCounter = t1 + 1;
+ $arguments += t1;
+ t1 = "return function(" + $arguments + "){return this.";
+ t2 = $.BoundClosure_selfFieldNameCache;
+ return new Function(t1 + H.S(t2 == null ? $.BoundClosure_selfFieldNameCache = H.BoundClosure_computeFieldNamed("self") : t2) + "." + H.S(stubName) + "(" + $arguments + ");}")();
+ },
+ Closure_cspForwardInterceptedCall: function(arity, isSuperCall, $name, $function) {
+ var getSelf = H.BoundClosure_selfOf,
+ getReceiver = H.BoundClosure_receiverOf;
+ switch (isSuperCall ? -1 : arity) {
+ case 0:
+ throw H.wrapException(H.RuntimeError$("Intercepted function with no arguments."));
+ case 1:
+ return function(n, s, r) {
+ return function() {
+ return s(this)[n](r(this));
+ };
+ }($name, getSelf, getReceiver);
+ case 2:
+ return function(n, s, r) {
+ return function(a) {
+ return s(this)[n](r(this), a);
+ };
+ }($name, getSelf, getReceiver);
+ case 3:
+ return function(n, s, r) {
+ return function(a, b) {
+ return s(this)[n](r(this), a, b);
+ };
+ }($name, getSelf, getReceiver);
+ case 4:
+ return function(n, s, r) {
+ return function(a, b, c) {
+ return s(this)[n](r(this), a, b, c);
+ };
+ }($name, getSelf, getReceiver);
+ case 5:
+ return function(n, s, r) {
+ return function(a, b, c, d) {
+ return s(this)[n](r(this), a, b, c, d);
+ };
+ }($name, getSelf, getReceiver);
+ case 6:
+ return function(n, s, r) {
+ return function(a, b, c, d, e) {
+ return s(this)[n](r(this), a, b, c, d, e);
+ };
+ }($name, getSelf, getReceiver);
+ default:
+ return function(f, s, r, a) {
+ return function() {
+ a = [r(this)];
+ Array.prototype.push.apply(a, arguments);
+ return f.apply(s(this), a);
+ };
+ }($function, getSelf, getReceiver);
+ }
+ },
+ Closure_forwardInterceptedCallTo: function(receiver, $function) {
+ var t2, stubName, arity, lookedUpFunction, t3, t4, $arguments,
+ t1 = $.BoundClosure_selfFieldNameCache;
+ if (t1 == null)
+ t1 = $.BoundClosure_selfFieldNameCache = H.BoundClosure_computeFieldNamed("self");
+ t2 = $.BoundClosure_receiverFieldNameCache;
+ if (t2 == null)
+ t2 = $.BoundClosure_receiverFieldNameCache = H.BoundClosure_computeFieldNamed("receiver");
+ stubName = $function.$stubName;
+ arity = $function.length;
+ lookedUpFunction = receiver[stubName];
+ t3 = $function == null ? lookedUpFunction == null : $function === lookedUpFunction;
+ t4 = !t3 || arity >= 28;
+ if (t4)
+ return H.Closure_cspForwardInterceptedCall(arity, !t3, stubName, $function);
+ if (arity === 1) {
+ t1 = "return function(){return this." + H.S(t1) + "." + H.S(stubName) + "(this." + H.S(t2) + ");";
+ t2 = $.Closure_functionCounter;
+ if (typeof t2 !== "number")
+ return t2.$add();
+ $.Closure_functionCounter = t2 + 1;
+ return new Function(t1 + t2 + "}")();
+ }
+ H.assertHelper(1 < arity && arity < 28);
+ $arguments = "abcdefghijklmnopqrstuvwxyz".split("").splice(0, arity - 1).join(",");
+ t1 = "return function(" + $arguments + "){return this." + H.S(t1) + "." + H.S(stubName) + "(this." + H.S(t2) + ", " + $arguments + ");";
+ t2 = $.Closure_functionCounter;
+ if (typeof t2 !== "number")
+ return t2.$add();
+ $.Closure_functionCounter = t2 + 1;
+ return new Function(t1 + t2 + "}")();
+ },
+ closureFromTearOff: function(receiver, functions, applyTrampolineIndex, reflectionInfo, isStatic, isIntercepted, $name) {
+ return H.Closure_fromTearOff(receiver, functions, applyTrampolineIndex, reflectionInfo, !!isStatic, !!isIntercepted, $name);
+ },
+ BoundClosure_evalRecipe: function(closure, recipe) {
+ return H._Universe_evalInEnvironment(init.typeUniverse, H.instanceType(closure._self), recipe);
+ },
+ BoundClosure_evalRecipeIntercepted: function(closure, recipe) {
+ return H._Universe_evalInEnvironment(init.typeUniverse, H.instanceType(closure._receiver), recipe);
+ },
+ BoundClosure_selfOf: function(closure) {
+ return closure._self;
+ },
+ BoundClosure_receiverOf: function(closure) {
+ return closure._receiver;
+ },
+ BoundClosure_computeFieldNamed: function(fieldName) {
+ var t1, i, $name,
+ template = new H.BoundClosure("self", "target", "receiver", "name"),
+ names = J.JSArray_markFixedList(Object.getOwnPropertyNames(template));
+ for (t1 = names.length, i = 0; i < t1; ++i) {
+ $name = names[i];
+ if (template[$name] === fieldName)
+ return $name;
+ }
+ },
+ boolConversionCheck: function(value) {
+ if (value == null)
+ H.assertThrow("boolean expression must not be null");
+ return value;
+ },
+ extractFunctionTypeObjectFromInternal: function(o) {
+ var signature;
+ if ("$signature" in o) {
+ signature = o.$signature;
+ if (typeof signature == "number")
+ return init.types[H._checkIntNullable(signature)];
+ else
+ return o.$signature();
+ }
+ return null;
+ },
+ TypeErrorImplementation$: function(value, type) {
+ return new H.TypeErrorImplementation("TypeError: " + P.Error_safeToString(value) + ": type '" + H.S(H._typeDescription(value)) + "' is not a subtype of type '" + type + "'");
+ },
+ _typeDescription: function(value) {
+ var functionTypeObject;
+ if (value instanceof H.Closure) {
+ functionTypeObject = H.extractFunctionTypeObjectFromInternal(J.getInterceptor$(value));
+ if (functionTypeObject != null)
+ return H.runtimeTypeToString(functionTypeObject);
+ return "Closure";
+ }
+ return H.Primitives_objectTypeName(value);
+ },
+ assertTest: function(condition) {
+ if (true === condition)
+ return false;
+ if (H._isBool(condition))
+ return !condition;
+ throw H.wrapException(H.TypeErrorImplementation$(condition, "bool"));
+ },
+ assertThrow: function(message) {
+ throw H.wrapException(new H._AssertionError(message));
+ },
+ assertHelper: function(condition) {
+ if (H.assertTest(condition))
+ throw H.wrapException(P.AssertionError$(null));
+ },
+ throwCyclicInit: function(staticName) {
+ throw H.wrapException(new P.CyclicInitializationError(staticName));
+ },
+ RuntimeError$: function(message) {
+ return new H.RuntimeError(message);
+ },
+ getIsolateAffinityTag: function($name) {
+ return init.getIsolateTag($name);
+ },
+ setRuntimeTypeInfo: function(target, rti) {
+ H.assertHelper(rti != null);
+ target.$ti = rti;
+ return target;
+ },
+ getRuntimeTypeInfo: function(target) {
+ if (target == null)
+ return null;
+ return target.$ti;
+ },
+ getRuntimeTypeArguments: function(interceptor, object, substitutionName) {
+ return H.substitute(interceptor["$as" + H.S(substitutionName)], H.getRuntimeTypeInfo(object));
+ },
+ runtimeTypeToString: function(rti) {
+ return H._runtimeTypeToString(rti, null);
+ },
+ _runtimeTypeToString: function(rti, genericContext) {
+ var t1, t2;
+ if (rti == null)
+ return "dynamic";
+ if (rti === -1)
+ return "void";
+ if (Array.isArray(rti))
+ return H.unminifyOrTag(rti[0].name) + H._joinArguments(rti, 1, genericContext);
+ if (typeof rti == "function")
+ return H.unminifyOrTag(rti.name);
+ if (rti === -2)
+ return "dynamic";
+ H.assertHelper(!(rti === -1));
+ if (typeof rti == "number") {
+ H._checkIntNullable(rti);
+ if (genericContext == null || rti < 0 || rti >= genericContext.length)
+ return "unexpected-generic-index:" + rti;
+ t1 = genericContext.length;
+ t2 = t1 - rti - 1;
+ if (t2 < 0 || t2 >= t1)
+ return H.ioore(genericContext, t2);
+ return H.S(genericContext[t2]);
+ }
+ t1 = rti != null;
+ if (t1)
+ t2 = typeof rti == "string";
+ else
+ t2 = true;
+ H.assertHelper(!t2);
+ if ('func' in rti)
+ return H._functionRtiToString0(rti, genericContext);
+ if (t1)
+ t2 = typeof rti == "string";
+ else
+ t2 = true;
+ H.assertHelper(!t2);
+ if ('futureOr' in rti) {
+ if (t1)
+ t1 = typeof rti == "string";
+ else
+ t1 = true;
+ H.assertHelper(!t1);
+ H.assertHelper('futureOr' in rti);
+ return "FutureOr<" + H._runtimeTypeToString("type" in rti ? rti.type : null, genericContext) + ">";
+ }
+ return "unknown-reified-type";
+ },
+ _functionRtiToString0: function(rti, genericContext) {
+ var boundsRti, outerContextLength, offset, i, i0, typeParameters, typeSep, t1, t2, boundRti, returnTypeText, $arguments, argumentsText, sep, _i, argument, optionalArguments, namedArguments, $name, _s2_ = ", ";
+ if ("bounds" in rti) {
+ boundsRti = rti.bounds;
+ if (genericContext == null) {
+ genericContext = H.setRuntimeTypeInfo([], type$.JSArray_String);
+ outerContextLength = null;
+ } else
+ outerContextLength = genericContext.length;
+ offset = genericContext.length;
+ for (i = boundsRti.length, i0 = i; i0 > 0; --i0)
+ C.JSArray_methods.add$1(genericContext, "T" + (offset + i0));
+ for (typeParameters = "<", typeSep = "", i0 = 0; i0 < i; ++i0, typeSep = _s2_) {
+ typeParameters += typeSep;
+ t1 = genericContext.length;
+ t2 = t1 - i0 - 1;
+ if (t2 < 0)
+ return H.ioore(genericContext, t2);
+ typeParameters = C.JSString_methods.$add(typeParameters, genericContext[t2]);
+ boundRti = boundsRti[i0];
+ if (boundRti != null && boundRti !== P.Object)
+ typeParameters += " extends " + H._runtimeTypeToString(boundRti, genericContext);
+ }
+ typeParameters += ">";
+ } else {
+ typeParameters = "";
+ outerContextLength = null;
+ }
+ returnTypeText = !!rti.v ? "void" : H._runtimeTypeToString(rti.ret, genericContext);
+ if ("args" in rti) {
+ $arguments = rti.args;
+ for (t1 = $arguments.length, argumentsText = "", sep = "", _i = 0; _i < t1; ++_i, sep = _s2_) {
+ argument = $arguments[_i];
+ argumentsText = argumentsText + sep + H._runtimeTypeToString(argument, genericContext);
+ }
+ } else {
+ argumentsText = "";
+ sep = "";
+ }
+ if ("opt" in rti) {
+ optionalArguments = rti.opt;
+ argumentsText += sep + "[";
+ for (t1 = optionalArguments.length, sep = "", _i = 0; _i < t1; ++_i, sep = _s2_) {
+ argument = optionalArguments[_i];
+ argumentsText = argumentsText + sep + H._runtimeTypeToString(argument, genericContext);
+ }
+ argumentsText += "]";
+ }
+ if ("named" in rti) {
+ namedArguments = rti.named;
+ argumentsText += sep + "{";
+ for (t1 = H.extractKeys(namedArguments), t2 = t1.length, sep = "", _i = 0; _i < t2; ++_i, sep = _s2_) {
+ $name = H._checkStringNullable(t1[_i]);
+ argumentsText = argumentsText + sep + H._runtimeTypeToString(namedArguments[$name], genericContext) + (" " + H.S($name));
+ }
+ argumentsText += "}";
+ }
+ if (outerContextLength != null)
+ genericContext.length = outerContextLength;
+ return typeParameters + "(" + argumentsText + ") => " + returnTypeText;
+ },
+ _joinArguments: function(types, startIndex, genericContext) {
+ var t1, buffer, index, separator, allDynamic, argument;
+ if (types == null)
+ return "";
+ t1 = Array.isArray(types);
+ H.assertHelper(t1);
+ buffer = new P.StringBuffer("");
+ for (index = startIndex, separator = "", allDynamic = true; H.assertHelper(t1), index < types.length; ++index, separator = ", ") {
+ buffer._contents += separator;
+ H.assertHelper(t1);
+ argument = types[index];
+ if (argument != null)
+ allDynamic = false;
+ buffer._contents += H._runtimeTypeToString(argument, genericContext);
+ }
+ return "<" + buffer.toString$0(0) + ">";
+ },
+ getRuntimeType: function(object) {
+ var rti = object instanceof H.Closure ? H.closureFunctionType(object) : null;
+ return H.createRuntimeType(rti == null ? H.instanceType(object) : rti);
+ },
+ substitute: function(substitution, $arguments) {
+ if (substitution == null)
+ return $arguments;
+ H.assertHelper(typeof substitution == "function");
+ H.assertHelper($arguments == null || Array.isArray($arguments));
+ substitution = H.invokeOn(substitution, null, $arguments);
+ if (substitution == null)
+ return null;
+ if (Array.isArray(substitution))
+ return substitution;
+ if (typeof substitution == "function")
+ return H.invokeOn(substitution, null, $arguments);
+ return $arguments;
+ },
+ computeSignature: function(signature, context, contextName) {
+ return H.invokeOn(signature, context, H.substitute(J.getInterceptor$(context)["$as" + H.S(contextName)], H.getRuntimeTypeInfo(context)));
+ },
+ invokeOn: function($function, receiver, $arguments) {
+ H.assertHelper(typeof $function == "function");
+ H.assertHelper($arguments == null || Array.isArray($arguments));
+ return $function.apply(receiver, $arguments);
+ },
+ defineProperty: function(obj, property, value) {
+ Object.defineProperty(obj, property, {value: value, enumerable: false, writable: true, configurable: true});
+ },
+ lookupAndCacheInterceptor: function(obj) {
+ var tag, record, interceptor, interceptorClass, mark, t1;
+ H.assertHelper(!(obj instanceof P.Object));
+ tag = H._checkStringNullable($.getTagFunction.call$1(obj));
+ record = $.dispatchRecordsForInstanceTags[tag];
+ if (record != null) {
+ Object.defineProperty(obj, init.dispatchPropertyName, {value: record, enumerable: false, writable: true, configurable: true});
+ return record.i;
+ }
+ interceptor = $.interceptorsForUncacheableTags[tag];
+ if (interceptor != null)
+ return interceptor;
+ interceptorClass = init.interceptorsByTag[tag];
+ if (interceptorClass == null) {
+ tag = H._checkStringNullable($.alternateTagFunction.call$2(obj, tag));
+ if (tag != null) {
+ record = $.dispatchRecordsForInstanceTags[tag];
+ if (record != null) {
+ Object.defineProperty(obj, init.dispatchPropertyName, {value: record, enumerable: false, writable: true, configurable: true});
+ return record.i;
+ }
+ interceptor = $.interceptorsForUncacheableTags[tag];
+ if (interceptor != null)
+ return interceptor;
+ interceptorClass = init.interceptorsByTag[tag];
+ }
+ }
+ if (interceptorClass == null)
+ return null;
+ interceptor = interceptorClass.prototype;
+ mark = tag[0];
+ if (mark === "!") {
+ record = H.makeLeafDispatchRecord(interceptor);
+ $.dispatchRecordsForInstanceTags[tag] = record;
+ Object.defineProperty(obj, init.dispatchPropertyName, {value: record, enumerable: false, writable: true, configurable: true});
+ return record.i;
+ }
+ if (mark === "~") {
+ $.interceptorsForUncacheableTags[tag] = interceptor;
+ return interceptor;
+ }
+ if (mark === "-") {
+ t1 = H.makeLeafDispatchRecord(interceptor);
+ Object.defineProperty(Object.getPrototypeOf(obj), init.dispatchPropertyName, {value: t1, enumerable: false, writable: true, configurable: true});
+ return t1.i;
+ }
+ if (mark === "+")
+ return H.patchInteriorProto(obj, interceptor);
+ if (mark === "*")
+ throw H.wrapException(P.UnimplementedError$(tag));
+ if (init.leafTags[tag] === true) {
+ t1 = H.makeLeafDispatchRecord(interceptor);
+ Object.defineProperty(Object.getPrototypeOf(obj), init.dispatchPropertyName, {value: t1, enumerable: false, writable: true, configurable: true});
+ return t1.i;
+ } else
+ return H.patchInteriorProto(obj, interceptor);
+ },
+ patchInteriorProto: function(obj, interceptor) {
+ var proto = Object.getPrototypeOf(obj);
+ Object.defineProperty(proto, init.dispatchPropertyName, {value: J.makeDispatchRecord(interceptor, proto, null, null), enumerable: false, writable: true, configurable: true});
+ return interceptor;
+ },
+ makeLeafDispatchRecord: function(interceptor) {
+ return J.makeDispatchRecord(interceptor, false, null, !!interceptor.$isJavaScriptIndexingBehavior);
+ },
+ makeDefaultDispatchRecord: function(tag, interceptorClass, proto) {
+ var interceptor = interceptorClass.prototype;
+ if (init.leafTags[tag] === true)
+ return H.makeLeafDispatchRecord(interceptor);
+ else
+ return J.makeDispatchRecord(interceptor, proto, null, null);
+ },
+ initNativeDispatch: function() {
+ if (true === $.initNativeDispatchFlag)
+ return;
+ $.initNativeDispatchFlag = true;
+ H.initNativeDispatchContinue();
+ },
+ initNativeDispatchContinue: function() {
+ var map, tags, fun, i, tag, proto, record, interceptorClass;
+ $.dispatchRecordsForInstanceTags = Object.create(null);
+ $.interceptorsForUncacheableTags = Object.create(null);
+ H.initHooks();
+ map = init.interceptorsByTag;
+ tags = Object.getOwnPropertyNames(map);
+ if (typeof window != "undefined") {
+ window;
+ fun = function() {
+ };
+ for (i = 0; i < tags.length; ++i) {
+ tag = tags[i];
+ proto = $.prototypeForTagFunction.call$1(tag);
+ if (proto != null) {
+ record = H.makeDefaultDispatchRecord(tag, map[tag], proto);
+ if (record != null) {
+ Object.defineProperty(proto, init.dispatchPropertyName, {value: record, enumerable: false, writable: true, configurable: true});
+ fun.prototype = proto;
+ }
+ }
+ }
+ }
+ for (i = 0; i < tags.length; ++i) {
+ tag = tags[i];
+ if (/^[A-Za-z_]/.test(tag)) {
+ interceptorClass = map[tag];
+ map["!" + tag] = interceptorClass;
+ map["~" + tag] = interceptorClass;
+ map["-" + tag] = interceptorClass;
+ map["+" + tag] = interceptorClass;
+ map["*" + tag] = interceptorClass;
+ }
+ }
+ },
+ initHooks: function() {
+ var transformers, i, transformer, getTag, getUnknownTag, prototypeForTag,
+ hooks = C.C_JS_CONST0();
+ hooks = H.applyHooksTransformer(C.C_JS_CONST1, H.applyHooksTransformer(C.C_JS_CONST2, H.applyHooksTransformer(C.C_JS_CONST3, H.applyHooksTransformer(C.C_JS_CONST3, H.applyHooksTransformer(C.C_JS_CONST4, H.applyHooksTransformer(C.C_JS_CONST5, H.applyHooksTransformer(C.C_JS_CONST6(C.C_JS_CONST), hooks)))))));
+ if (typeof dartNativeDispatchHooksTransformer != "undefined") {
+ transformers = dartNativeDispatchHooksTransformer;
+ if (typeof transformers == "function")
+ transformers = [transformers];
+ if (transformers.constructor == Array)
+ for (i = 0; i < transformers.length; ++i) {
+ transformer = transformers[i];
+ if (typeof transformer == "function")
+ hooks = transformer(hooks) || hooks;
+ }
+ }
+ getTag = hooks.getTag;
+ getUnknownTag = hooks.getUnknownTag;
+ prototypeForTag = hooks.prototypeForTag;
+ $.getTagFunction = new H.initHooks_closure(getTag);
+ $.alternateTagFunction = new H.initHooks_closure0(getUnknownTag);
+ $.prototypeForTagFunction = new H.initHooks_closure1(prototypeForTag);
+ },
+ applyHooksTransformer: function(transformer, hooks) {
+ return transformer(hooks) || hooks;
+ },
+ JSSyntaxRegExp_makeNative: function(source, multiLine, caseSensitive, unicode, dotAll, global) {
+ var m = multiLine ? "m" : "",
+ i = caseSensitive ? "" : "i",
+ u = unicode ? "u" : "",
+ s = dotAll ? "s" : "",
+ g = global ? "g" : "",
+ regexp = function(source, modifiers) {
+ try {
+ return new RegExp(source, modifiers);
+ } catch (e) {
+ return e;
+ }
+ }(source, m + i + u + s + g);
+ if (regexp instanceof RegExp)
+ return regexp;
+ throw H.wrapException(P.FormatException$("Illegal RegExp pattern (" + String(regexp) + ")", source, null));
+ },
+ _MatchImplementation$: function(pattern, _match) {
+ H.assertHelper(typeof _match.input == "string");
+ H.assertHelper(H._isInt(_match.index));
+ return new H._MatchImplementation(_match);
+ },
+ stringContainsUnchecked: function(receiver, other, startIndex) {
+ var t1, t2;
+ if (typeof other == "string")
+ return receiver.indexOf(other, startIndex) >= 0;
+ else if (other instanceof H.JSSyntaxRegExp) {
+ t1 = C.JSString_methods.substring$1(receiver, startIndex);
+ t2 = other._nativeRegExp;
+ return t2.test(t1);
+ } else {
+ t1 = J.allMatches$1$s(other, C.JSString_methods.substring$1(receiver, startIndex));
+ return !t1.get$isEmpty(t1);
+ }
+ },
+ escapeReplacement: function(replacement) {
+ if (replacement.indexOf("$", 0) >= 0)
+ return replacement.replace(/\$/g, "$$$$");
+ return replacement;
+ },
+ stringReplaceFirstRE: function(receiver, regexp, replacement, startIndex) {
+ var match = regexp._execGlobal$2(receiver, startIndex);
+ if (match == null)
+ return receiver;
+ return H.stringReplaceRangeUnchecked(receiver, match._match.index, match.get$end(), replacement);
+ },
+ quoteStringForRegExp: function(string) {
+ if (/[[\]{}()*+?.\\^$|]/.test(string))
+ return string.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&");
+ return string;
+ },
+ stringReplaceAllUnchecked: function(receiver, pattern, replacement) {
+ var nativeRegexp;
+ if (typeof pattern == "string")
+ return H.stringReplaceAllUncheckedString(receiver, pattern, replacement);
+ if (pattern instanceof H.JSSyntaxRegExp) {
+ nativeRegexp = pattern.get$_nativeGlobalVersion();
+ nativeRegexp.lastIndex = 0;
+ return receiver.replace(nativeRegexp, H.escapeReplacement(replacement));
+ }
+ if (pattern == null)
+ H.throwExpression(H.argumentErrorValue(pattern));
+ throw H.wrapException("String.replaceAll(Pattern) UNIMPLEMENTED");
+ },
+ stringReplaceAllUncheckedString: function(receiver, pattern, replacement) {
+ var $length, t1, i, index;
+ if (pattern === "") {
+ if (receiver === "")
+ return replacement;
+ $length = receiver.length;
+ for (t1 = replacement, i = 0; i < $length; ++i)
+ t1 = t1 + receiver[i] + replacement;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ }
+ index = receiver.indexOf(pattern, 0);
+ if (index < 0)
+ return receiver;
+ if (receiver.length < 500 || replacement.indexOf("$", 0) >= 0)
+ return receiver.split(pattern).join(replacement);
+ return receiver.replace(new RegExp(H.quoteStringForRegExp(pattern), 'g'), H.escapeReplacement(replacement));
+ },
+ _stringIdentity: function(string) {
+ return string;
+ },
+ stringReplaceAllFuncUnchecked: function(receiver, pattern, onMatch, onNonMatch) {
+ var t1, startIndex, t2, t3, t4, t5;
+ if (!type$.Pattern._is(pattern))
+ throw H.wrapException(P.ArgumentError$value(pattern, "pattern", "is not a Pattern"));
+ for (t1 = pattern.allMatches$1(0, receiver), t1 = new H._AllMatchesIterator(t1._re, t1.__js_helper$_string, t1._start), startIndex = 0, t2 = ""; t1.moveNext$0(); t2 = t3) {
+ t3 = t1.__js_helper$_current;
+ t4 = t3._match;
+ t5 = t4.index;
+ t3 = t2 + H.S(H._stringIdentity(C.JSString_methods.substring$2(receiver, startIndex, t5))) + H.S(onMatch.call$1(t3));
+ startIndex = t5 + t4[0].length;
+ }
+ t1 = t2 + H.S(H._stringIdentity(C.JSString_methods.substring$1(receiver, startIndex)));
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ stringReplaceFirstUnchecked: function(receiver, pattern, replacement, startIndex) {
+ var index, t1, matches, match;
+ if (typeof pattern == "string") {
+ index = receiver.indexOf(pattern, startIndex);
+ if (index < 0)
+ return receiver;
+ return H.stringReplaceRangeUnchecked(receiver, index, index + pattern.length, replacement);
+ }
+ if (pattern instanceof H.JSSyntaxRegExp)
+ return startIndex === 0 ? receiver.replace(pattern._nativeRegExp, H.escapeReplacement(replacement)) : H.stringReplaceFirstRE(receiver, pattern, replacement, startIndex);
+ if (pattern == null)
+ H.throwExpression(H.argumentErrorValue(pattern));
+ t1 = J.allMatches$2$s(pattern, receiver, startIndex);
+ matches = type$.Iterator_Match._check(t1.get$iterator(t1));
+ if (!matches.moveNext$0())
+ return receiver;
+ match = matches.get$current();
+ return C.JSString_methods.replaceRange$3(receiver, match.get$start(), match.get$end(), replacement);
+ },
+ stringReplaceRangeUnchecked: function(receiver, start, end, replacement) {
+ var prefix = receiver.substring(0, start),
+ suffix = receiver.substring(end);
+ return prefix + replacement + suffix;
+ },
+ ConstantMap: function ConstantMap() {
+ },
+ ConstantMap_map_closure: function ConstantMap_map_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.transform = t1;
+ this.result = t2;
+ },
+ ConstantStringMap: function ConstantStringMap(t0, t1, t2, t3) {
+ var _ = this;
+ _.__js_helper$_length = t0;
+ _._jsObject = t1;
+ _.__js_helper$_keys = t2;
+ _.$ti = t3;
+ },
+ _ConstantMapKeyIterable: function _ConstantMapKeyIterable(t0, t1) {
+ this.__js_helper$_map = t0;
+ this.$ti = t1;
+ },
+ Instantiation: function Instantiation() {
+ },
+ Instantiation1: function Instantiation1(t0, t1) {
+ this._genericClosure = t0;
+ this.$ti = t1;
+ },
+ Primitives_initTicker_closure: function Primitives_initTicker_closure(t0) {
+ this.performance = t0;
+ },
+ TypeErrorDecoder: function TypeErrorDecoder(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _._pattern = t0;
+ _._arguments = t1;
+ _._argumentsExpr = t2;
+ _._expr = t3;
+ _._method = t4;
+ _._receiver = t5;
+ },
+ NullError: function NullError(t0, t1) {
+ this.__js_helper$_message = t0;
+ this._method = t1;
+ },
+ JsNoSuchMethodError: function JsNoSuchMethodError(t0, t1, t2) {
+ this.__js_helper$_message = t0;
+ this._method = t1;
+ this._receiver = t2;
+ },
+ UnknownJsTypeError: function UnknownJsTypeError(t0) {
+ this.__js_helper$_message = t0;
+ },
+ ExceptionAndStackTrace: function ExceptionAndStackTrace(t0, t1) {
+ this.dartException = t0;
+ this.stackTrace = t1;
+ },
+ unwrapException_saveStackTrace: function unwrapException_saveStackTrace(t0) {
+ this.ex = t0;
+ },
+ _StackTrace: function _StackTrace(t0) {
+ this._exception = t0;
+ this._trace = null;
+ },
+ Closure: function Closure() {
+ },
+ TearOffClosure: function TearOffClosure() {
+ },
+ StaticClosure: function StaticClosure() {
+ },
+ BoundClosure: function BoundClosure(t0, t1, t2, t3) {
+ var _ = this;
+ _._self = t0;
+ _._target = t1;
+ _._receiver = t2;
+ _._name = t3;
+ },
+ TypeErrorImplementation: function TypeErrorImplementation(t0) {
+ this.message = t0;
+ },
+ RuntimeError: function RuntimeError(t0) {
+ this.message = t0;
+ },
+ _AssertionError: function _AssertionError(t0) {
+ this.message = t0;
+ },
+ JsLinkedHashMap: function JsLinkedHashMap(t0) {
+ var _ = this;
+ _.__js_helper$_length = 0;
+ _._last = _._first = _.__js_helper$_rest = _.__js_helper$_nums = _.__js_helper$_strings = null;
+ _._modifications = 0;
+ _.$ti = t0;
+ },
+ JsLinkedHashMap_values_closure: function JsLinkedHashMap_values_closure(t0) {
+ this.$this = t0;
+ },
+ JsLinkedHashMap_addAll_closure: function JsLinkedHashMap_addAll_closure(t0) {
+ this.$this = t0;
+ },
+ LinkedHashMapCell: function LinkedHashMapCell(t0, t1) {
+ var _ = this;
+ _.hashMapCellKey = t0;
+ _.hashMapCellValue = t1;
+ _._previous = _._next = null;
+ },
+ LinkedHashMapKeyIterable: function LinkedHashMapKeyIterable(t0, t1) {
+ this.__js_helper$_map = t0;
+ this.$ti = t1;
+ },
+ LinkedHashMapKeyIterator: function LinkedHashMapKeyIterator(t0, t1, t2) {
+ var _ = this;
+ _.__js_helper$_map = t0;
+ _._modifications = t1;
+ _.__js_helper$_current = _._cell = null;
+ _.$ti = t2;
+ },
+ initHooks_closure: function initHooks_closure(t0) {
+ this.getTag = t0;
+ },
+ initHooks_closure0: function initHooks_closure0(t0) {
+ this.getUnknownTag = t0;
+ },
+ initHooks_closure1: function initHooks_closure1(t0) {
+ this.prototypeForTag = t0;
+ },
+ JSSyntaxRegExp: function JSSyntaxRegExp(t0, t1) {
+ var _ = this;
+ _.pattern = t0;
+ _._nativeRegExp = t1;
+ _._nativeAnchoredRegExp = _._nativeGlobalRegExp = null;
+ },
+ _MatchImplementation: function _MatchImplementation(t0) {
+ this._match = t0;
+ },
+ _AllMatchesIterable: function _AllMatchesIterable(t0, t1, t2) {
+ this._re = t0;
+ this.__js_helper$_string = t1;
+ this._start = t2;
+ },
+ _AllMatchesIterator: function _AllMatchesIterator(t0, t1, t2) {
+ var _ = this;
+ _._regExp = t0;
+ _.__js_helper$_string = t1;
+ _._nextIndex = t2;
+ _.__js_helper$_current = null;
+ },
+ StringMatch: function StringMatch(t0, t1) {
+ this.start = t0;
+ this.pattern = t1;
+ },
+ _StringAllMatchesIterable: function _StringAllMatchesIterable(t0, t1, t2) {
+ this._input = t0;
+ this._pattern = t1;
+ this.__js_helper$_index = t2;
+ },
+ _StringAllMatchesIterator: function _StringAllMatchesIterator(t0, t1, t2) {
+ var _ = this;
+ _._input = t0;
+ _._pattern = t1;
+ _.__js_helper$_index = t2;
+ _.__js_helper$_current = null;
+ },
+ _ensureNativeList: function(list) {
+ return list;
+ },
+ NativeInt8List__create1: function(arg) {
+ return new Int8Array(arg);
+ },
+ _checkValidIndex: function(index, list, $length) {
+ if (index >>> 0 !== index || index >= $length)
+ throw H.wrapException(H.diagnoseIndexError(list, index));
+ },
+ _checkValidRange: function(start, end, $length) {
+ var t1;
+ if (!(start >>> 0 !== start))
+ if (end == null)
+ t1 = start > $length;
+ else
+ t1 = end >>> 0 !== end || start > end || end > $length;
+ else
+ t1 = true;
+ if (t1)
+ throw H.wrapException(H.diagnoseRangeError(start, end, $length));
+ if (end == null)
+ return $length;
+ return end;
+ },
+ NativeByteBuffer: function NativeByteBuffer() {
+ },
+ NativeTypedData: function NativeTypedData() {
+ },
+ NativeByteData: function NativeByteData() {
+ },
+ NativeTypedArray: function NativeTypedArray() {
+ },
+ NativeTypedArrayOfDouble: function NativeTypedArrayOfDouble() {
+ },
+ NativeTypedArrayOfInt: function NativeTypedArrayOfInt() {
+ },
+ NativeFloat32List: function NativeFloat32List() {
+ },
+ NativeFloat64List: function NativeFloat64List() {
+ },
+ NativeInt16List: function NativeInt16List() {
+ },
+ NativeInt32List: function NativeInt32List() {
+ },
+ NativeInt8List: function NativeInt8List() {
+ },
+ NativeUint16List: function NativeUint16List() {
+ },
+ NativeUint32List: function NativeUint32List() {
+ },
+ NativeUint8ClampedList: function NativeUint8ClampedList() {
+ },
+ NativeUint8List: function NativeUint8List() {
+ },
+ _NativeTypedArrayOfDouble_NativeTypedArray_ListMixin: function _NativeTypedArrayOfDouble_NativeTypedArray_ListMixin() {
+ },
+ _NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin: function _NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin() {
+ },
+ _NativeTypedArrayOfInt_NativeTypedArray_ListMixin: function _NativeTypedArrayOfInt_NativeTypedArray_ListMixin() {
+ },
+ _NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin: function _NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin() {
+ },
+ Rti__getFutureFromFutureOr: function(universe, rti) {
+ var future;
+ H.assertHelper(rti._kind === 8);
+ future = rti._precomputed1;
+ if (future == null) {
+ H.assertHelper(rti._kind === 8);
+ future = rti._precomputed1 = H._Universe__lookupInterfaceRti(universe, "Future", [rti._primary]);
+ }
+ return future;
+ },
+ Rti__isUnionOfFunctionType: function(rti) {
+ var kind = rti._kind;
+ if (kind === 6 || kind === 7 || kind === 8)
+ return H.Rti__isUnionOfFunctionType(rti._primary);
+ return kind === 11 || kind === 12;
+ },
+ Rti__getInterfaceTypeArguments: function(rti) {
+ H.assertHelper(rti._kind === 9);
+ return rti._rest;
+ },
+ Rti__getBindingArguments: function(rti) {
+ H.assertHelper(rti._kind === 10);
+ return rti._rest;
+ },
+ Rti__getFunctionParameters: function(rti) {
+ H.assertHelper(rti._kind === 11);
+ return rti._rest;
+ },
+ Rti__getGenericFunctionBounds: function(rti) {
+ H.assertHelper(rti._kind === 12);
+ return rti._rest;
+ },
+ Rti__getCanonicalRecipe: function(rti) {
+ var s = rti._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ return s;
+ },
+ findType: function(recipe) {
+ return H._Universe_eval(init.typeUniverse, recipe);
+ },
+ instantiatedGenericFunctionType: function(genericFunctionRti, instantiationRti) {
+ var bounds, typeArguments, cache, s, key, probe, rti;
+ if (genericFunctionRti == null)
+ return null;
+ bounds = H.Rti__getGenericFunctionBounds(genericFunctionRti);
+ typeArguments = H.Rti__getInterfaceTypeArguments(instantiationRti);
+ H.assertHelper(bounds.length === typeArguments.length);
+ cache = genericFunctionRti._bindCache;
+ if (cache == null)
+ cache = genericFunctionRti._bindCache = new Map();
+ s = instantiationRti._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ key = s;
+ probe = cache.get(key);
+ if (probe != null)
+ return probe;
+ H.assertHelper(genericFunctionRti._kind === 12);
+ rti = H._instantiate(init.typeUniverse, genericFunctionRti._primary, typeArguments, 0);
+ cache.set(key, rti);
+ return rti;
+ },
+ _instantiate: function(universe, rti, typeArguments, depth) {
+ var baseType, instantiatedBaseType, s, interfaceTypeArguments, instantiatedInterfaceTypeArguments, base, instantiatedBase, $arguments, instantiatedArguments, returnType, instantiatedReturnType, functionParameters, instantiatedFunctionParameters, bounds, instantiatedBounds, index,
+ _s24_ = "Missing canonical recipe",
+ t1 = rti._kind,
+ kind = t1;
+ switch (kind) {
+ case 5:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return rti;
+ case 6:
+ baseType = rti._primary;
+ instantiatedBaseType = H._instantiate(universe, baseType, typeArguments, depth);
+ if (instantiatedBaseType === baseType)
+ return rti;
+ s = instantiatedBaseType._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow(_s24_);
+ return H._Universe__lookupUnaryRti(universe, 6, instantiatedBaseType, s + "*");
+ case 7:
+ baseType = rti._primary;
+ instantiatedBaseType = H._instantiate(universe, baseType, typeArguments, depth);
+ if (instantiatedBaseType === baseType)
+ return rti;
+ s = instantiatedBaseType._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow(_s24_);
+ return H._Universe__lookupUnaryRti(universe, 7, instantiatedBaseType, s + "?");
+ case 8:
+ baseType = rti._primary;
+ instantiatedBaseType = H._instantiate(universe, baseType, typeArguments, depth);
+ if (instantiatedBaseType === baseType)
+ return rti;
+ s = instantiatedBaseType._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow(_s24_);
+ return H._Universe__lookupUnaryRti(universe, 8, instantiatedBaseType, s + "/");
+ case 9:
+ interfaceTypeArguments = H.Rti__getInterfaceTypeArguments(rti);
+ instantiatedInterfaceTypeArguments = H._instantiateArray(universe, interfaceTypeArguments, typeArguments, depth);
+ if (instantiatedInterfaceTypeArguments === interfaceTypeArguments)
+ return rti;
+ H.assertHelper(rti._kind === 9);
+ return H._Universe__lookupInterfaceRti(universe, rti._primary, instantiatedInterfaceTypeArguments);
+ case 10:
+ H.assertHelper(t1 === 10);
+ base = rti._primary;
+ instantiatedBase = H._instantiate(universe, base, typeArguments, depth);
+ $arguments = H.Rti__getBindingArguments(rti);
+ instantiatedArguments = H._instantiateArray(universe, $arguments, typeArguments, depth);
+ if (instantiatedBase === base && instantiatedArguments === $arguments)
+ return rti;
+ return H._Universe__lookupBindingRti(universe, instantiatedBase, instantiatedArguments);
+ case 11:
+ H.assertHelper(t1 === 11);
+ returnType = rti._primary;
+ instantiatedReturnType = H._instantiate(universe, returnType, typeArguments, depth);
+ functionParameters = H.Rti__getFunctionParameters(rti);
+ instantiatedFunctionParameters = H._instantiateFunctionParameters(universe, functionParameters, typeArguments, depth);
+ if (instantiatedReturnType === returnType && instantiatedFunctionParameters === functionParameters)
+ return rti;
+ return H._Universe__lookupFunctionRti(universe, instantiatedReturnType, instantiatedFunctionParameters);
+ case 12:
+ bounds = H.Rti__getGenericFunctionBounds(rti);
+ depth += bounds.length;
+ instantiatedBounds = H._instantiateArray(universe, bounds, typeArguments, depth);
+ H.assertHelper(rti._kind === 12);
+ base = rti._primary;
+ instantiatedBase = H._instantiate(universe, base, typeArguments, depth);
+ if (instantiatedBounds === bounds && instantiatedBase === base)
+ return rti;
+ return H._Universe__lookupGenericFunctionRti(universe, instantiatedBase, instantiatedBounds);
+ case 13:
+ H.assertHelper(t1 === 13);
+ index = rti._primary;
+ if (index < depth)
+ return null;
+ return typeArguments[index - depth];
+ default:
+ throw H.wrapException(P.AssertionError$("Attempted to instantiate unexpected RTI kind " + kind));
+ }
+ },
+ _instantiateArray: function(universe, rtiArray, typeArguments, depth) {
+ var changed, i, rti, instantiatedRti,
+ $length = rtiArray.length,
+ result = [];
+ for (changed = false, i = 0; i < $length; ++i) {
+ rti = rtiArray[i];
+ instantiatedRti = H._instantiate(universe, rti, typeArguments, depth);
+ if (instantiatedRti !== rti)
+ changed = true;
+ result.push(instantiatedRti);
+ }
+ return changed ? result : rtiArray;
+ },
+ _instantiateNamed: function(universe, namedArray, typeArguments, depth) {
+ var result, changed, i, t1, rti, instantiatedRti,
+ $length = namedArray.length;
+ H.assertHelper(($length & 1) === 0);
+ result = [];
+ for (changed = false, i = 0; i < $length; i += 2) {
+ t1 = namedArray[i];
+ rti = namedArray[i + 1];
+ instantiatedRti = H._instantiate(universe, rti, typeArguments, depth);
+ if (instantiatedRti !== rti)
+ changed = true;
+ result.push(t1);
+ result.push(instantiatedRti);
+ }
+ return changed ? result : namedArray;
+ },
+ _instantiateFunctionParameters: function(universe, functionParameters, typeArguments, depth) {
+ var result,
+ requiredPositional = functionParameters._requiredPositional,
+ instantiatedRequiredPositional = H._instantiateArray(universe, requiredPositional, typeArguments, depth),
+ optionalPositional = functionParameters._optionalPositional,
+ instantiatedOptionalPositional = H._instantiateArray(universe, optionalPositional, typeArguments, depth),
+ optionalNamed = functionParameters._optionalNamed,
+ instantiatedOptionalNamed = H._instantiateNamed(universe, optionalNamed, typeArguments, depth);
+ if (instantiatedRequiredPositional === requiredPositional && instantiatedOptionalPositional === optionalPositional && instantiatedOptionalNamed === optionalNamed)
+ return functionParameters;
+ result = new H._FunctionParameters();
+ result._requiredPositional = instantiatedRequiredPositional;
+ result._optionalPositional = instantiatedOptionalPositional;
+ result._optionalNamed = instantiatedOptionalNamed;
+ return result;
+ },
+ closureFunctionType: function(closure) {
+ var signature = closure.$signature;
+ if (signature != null) {
+ if (typeof signature == "number")
+ return H.getTypeFromTypesTable(signature);
+ return closure.$signature();
+ }
+ return null;
+ },
+ instanceOrFunctionType: function(object, testRti) {
+ var rti;
+ if (H.Rti__isUnionOfFunctionType(testRti))
+ if (object instanceof H.Closure) {
+ rti = H.closureFunctionType(object);
+ if (rti != null)
+ return rti;
+ }
+ return H.instanceType(object);
+ },
+ instanceType: function(object) {
+ var rti;
+ if (object instanceof P.Object) {
+ rti = object.$ti;
+ return rti != null ? rti : H._instanceTypeFromConstructor(object);
+ }
+ if (Array.isArray(object))
+ return H._arrayInstanceType(object);
+ return H._instanceTypeFromConstructor(J.getInterceptor$(object));
+ },
+ _arrayInstanceType: function(object) {
+ var rti = object.$ti,
+ defaultRti = type$.JSArray_dynamic;
+ if (rti == null)
+ return defaultRti;
+ if (rti.constructor !== defaultRti.constructor)
+ return defaultRti;
+ return rti;
+ },
+ _instanceType: function(object) {
+ var rti = object.$ti;
+ return rti != null ? rti : H._instanceTypeFromConstructor(object);
+ },
+ _instanceTypeFromConstructor: function(instance) {
+ var $constructor = instance.constructor,
+ probe = $constructor.$ccache;
+ if (probe != null)
+ return probe;
+ return H._instanceTypeFromConstructorMiss(instance, $constructor);
+ },
+ _instanceTypeFromConstructorMiss: function(instance, $constructor) {
+ var effectiveConstructor = instance instanceof H.Closure ? instance.__proto__.__proto__.constructor : $constructor,
+ rti = H._Universe_findErasedType(init.typeUniverse, effectiveConstructor.name);
+ $constructor.$ccache = rti;
+ return rti;
+ },
+ getTypeFromTypesTable: function(_index) {
+ var rti,
+ index = _index,
+ table = init.types,
+ type = table[index];
+ if (typeof type == "string") {
+ rti = H._Universe_eval(init.typeUniverse, type);
+ table[index] = rti;
+ return rti;
+ }
+ return type;
+ },
+ createRuntimeType: function(rti) {
+ var type = rti._cachedRuntimeType;
+ if (type != null)
+ return type;
+ return rti._cachedRuntimeType = new H._Type(rti);
+ },
+ typeLiteral: function(recipe) {
+ return H.createRuntimeType(H._Universe_eval(init.typeUniverse, recipe));
+ },
+ _installSpecializedIsTest: function(object) {
+ var s, key, testRti = this,
+ t1 = testRti._kind,
+ isFn = H._generalIsTestImplementation;
+ if (H.isTopType(testRti, true)) {
+ isFn = H._isTop;
+ testRti._check = testRti._as = H._asTop;
+ } else if (t1 === 9) {
+ s = testRti._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ key = s;
+ if ("int" === key)
+ isFn = H._isInt;
+ else if ("double" === key)
+ isFn = H._isNum;
+ else if ("num" === key)
+ isFn = H._isNum;
+ else if ("String" === key)
+ isFn = H._isString;
+ else if ("bool" === key)
+ isFn = H._isBool;
+ else {
+ H.assertHelper(testRti._kind === 9);
+ t1 = testRti._primary;
+ if (H.Rti__getInterfaceTypeArguments(testRti).every(H.isLegacyTopType)) {
+ testRti._specializedTestResource = "$is" + t1;
+ isFn = H._isTestViaProperty;
+ }
+ }
+ }
+ testRti._is = isFn;
+ return testRti._is(object);
+ },
+ _generalIsTestImplementation: function(object) {
+ var testRti = this;
+ return H._isSubtype(init.typeUniverse, H.instanceOrFunctionType(object, testRti), null, testRti, null, true);
+ },
+ _isTestViaProperty: function(object) {
+ var tag = this._specializedTestResource;
+ if (object instanceof P.Object)
+ return !!object[tag];
+ return !!J.getInterceptor$(object)[tag];
+ },
+ _generalAsCheckImplementation: function(object) {
+ var testRti;
+ if (object == null)
+ return object;
+ testRti = this;
+ if (testRti._is(object))
+ return object;
+ throw H.wrapException(H._CastError$fromMessage(H._Error_compose(object, H.instanceOrFunctionType(object, testRti), H._rtiToString(testRti, null))));
+ },
+ _generalTypeCheckImplementation: function(object) {
+ var testRti;
+ if (object == null)
+ return object;
+ testRti = this;
+ if (testRti._is(object))
+ return object;
+ throw H.wrapException(H._TypeError$fromMessage(H._Error_compose(object, H.instanceOrFunctionType(object, testRti), H._rtiToString(testRti, null))));
+ },
+ checkTypeBound: function(type, bound, variable, methodName) {
+ var _null = null;
+ if (H._isSubtype(init.typeUniverse, type, _null, bound, _null, true))
+ return type;
+ throw H.wrapException(H._TypeError$fromMessage("The type argument '" + H.S(H._rtiToString(type, _null)) + "' is not a subtype of the type variable bound '" + H.S(H._rtiToString(bound, _null)) + "' of type variable '" + variable + "' in '" + H.S(methodName) + "'."));
+ },
+ _Error_compose: function(object, objectRti, checkedTypeDescription) {
+ var objectDescription = P.Error_safeToString(object),
+ objectTypeDescription = H._rtiToString(objectRti == null ? H.instanceType(object) : objectRti, null);
+ return objectDescription + ": type '" + H.S(objectTypeDescription) + "' is not a subtype of type '" + H.S(checkedTypeDescription) + "'";
+ },
+ _CastError$fromMessage: function(message) {
+ return new H._CastError("CastError: " + message);
+ },
+ _CastError__CastError$forType: function(object, type) {
+ return new H._CastError("CastError: " + H._Error_compose(object, null, type));
+ },
+ _TypeError$fromMessage: function(message) {
+ return new H._TypeError("TypeError: " + message);
+ },
+ _TypeError__TypeError$forType: function(object, type) {
+ return new H._TypeError("TypeError: " + H._Error_compose(object, null, type));
+ },
+ _isTop: function(object) {
+ return true;
+ },
+ _asTop: function(object) {
+ return object;
+ },
+ _isBool: function(object) {
+ return true === object || false === object;
+ },
+ _asBoolNullable: function(object) {
+ if (true === object || false === object)
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._CastError__CastError$forType(object, "bool"));
+ },
+ _checkBoolNullable: function(object) {
+ if (true === object || false === object)
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._TypeError__TypeError$forType(object, "bool"));
+ },
+ _asDoubleNullable: function(object) {
+ if (typeof object == "number")
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._CastError__CastError$forType(object, "double"));
+ },
+ _checkDoubleNullable: function(object) {
+ if (typeof object == "number")
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._TypeError__TypeError$forType(object, "double"));
+ },
+ _isInt: function(object) {
+ return typeof object == "number" && Math.floor(object) === object;
+ },
+ _asIntNullable: function(object) {
+ if (typeof object == "number" && Math.floor(object) === object)
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._CastError__CastError$forType(object, "int"));
+ },
+ _checkIntNullable: function(object) {
+ if (typeof object == "number" && Math.floor(object) === object)
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._TypeError__TypeError$forType(object, "int"));
+ },
+ _isNum: function(object) {
+ return typeof object == "number";
+ },
+ _asNumNullable: function(object) {
+ if (typeof object == "number")
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._CastError__CastError$forType(object, "num"));
+ },
+ _checkNumNullable: function(object) {
+ if (typeof object == "number")
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._TypeError__TypeError$forType(object, "num"));
+ },
+ _isString: function(object) {
+ return typeof object == "string";
+ },
+ _asStringNullable: function(object) {
+ if (typeof object == "string")
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._CastError__CastError$forType(object, "String"));
+ },
+ _checkStringNullable: function(object) {
+ if (typeof object == "string")
+ return object;
+ if (object == null)
+ return object;
+ throw H.wrapException(H._TypeError__TypeError$forType(object, "String"));
+ },
+ _rtiArrayToString: function(array, genericContext) {
+ var s, sep, i;
+ for (s = "", sep = "", i = 0; i < array.length; ++i, sep = ", ")
+ s += C.JSString_methods.$add(sep, H._rtiToString(array[i], genericContext));
+ return s;
+ },
+ _functionRtiToString: function(functionType, genericContext, bounds) {
+ var boundsLength, outerContextLength, offset, i, typeParametersText, typeSep, t1, t2, boundRti, parameters, requiredPositional, requiredPositionalLength, optionalPositional, optionalPositionalLength, optionalNamed, optionalNamedLength, returnTypeText, argumentsText, sep, _s2_ = ", ";
+ if (bounds != null) {
+ boundsLength = bounds.length;
+ if (genericContext == null) {
+ genericContext = H.setRuntimeTypeInfo([], type$.JSArray_String);
+ outerContextLength = null;
+ } else
+ outerContextLength = genericContext.length;
+ offset = genericContext.length;
+ for (i = boundsLength; i > 0; --i)
+ C.JSArray_methods.add$1(genericContext, "T" + (offset + i));
+ for (typeParametersText = "<", typeSep = "", i = 0; i < boundsLength; ++i, typeSep = _s2_) {
+ typeParametersText += typeSep;
+ t1 = genericContext.length;
+ t2 = t1 - 1 - i;
+ if (t2 < 0)
+ return H.ioore(genericContext, t2);
+ typeParametersText = C.JSString_methods.$add(typeParametersText, genericContext[t2]);
+ boundRti = bounds[i];
+ if (!H.isTopType(boundRti, true))
+ typeParametersText += C.JSString_methods.$add(" extends ", H._rtiToString(boundRti, genericContext));
+ }
+ typeParametersText += ">";
+ } else {
+ typeParametersText = "";
+ outerContextLength = null;
+ }
+ H.assertHelper(functionType._kind === 11);
+ t1 = functionType._primary;
+ parameters = H.Rti__getFunctionParameters(functionType);
+ requiredPositional = parameters._requiredPositional;
+ requiredPositionalLength = requiredPositional.length;
+ optionalPositional = parameters._optionalPositional;
+ optionalPositionalLength = optionalPositional.length;
+ optionalNamed = parameters._optionalNamed;
+ optionalNamedLength = optionalNamed.length;
+ H.assertHelper(optionalPositionalLength === 0 || optionalNamedLength === 0);
+ returnTypeText = H._rtiToString(t1, genericContext);
+ for (argumentsText = "", sep = "", i = 0; i < requiredPositionalLength; ++i, sep = _s2_)
+ argumentsText += C.JSString_methods.$add(sep, H._rtiToString(requiredPositional[i], genericContext));
+ if (optionalPositionalLength > 0) {
+ argumentsText += sep + "[";
+ for (sep = "", i = 0; i < optionalPositionalLength; ++i, sep = _s2_)
+ argumentsText += C.JSString_methods.$add(sep, H._rtiToString(optionalPositional[i], genericContext));
+ argumentsText += "]";
+ }
+ if (optionalNamedLength > 0) {
+ argumentsText += sep + "{";
+ for (sep = "", i = 0; i < optionalNamedLength; i += 2, sep = _s2_)
+ argumentsText += C.JSString_methods.$add(sep, H._rtiToString(optionalNamed[i + 1], genericContext)) + " " + optionalNamed[i];
+ argumentsText += "}";
+ }
+ if (outerContextLength != null)
+ genericContext.length = outerContextLength;
+ return typeParametersText + "(" + argumentsText + ") => " + H.S(returnTypeText);
+ },
+ _rtiToString: function(rti, genericContext) {
+ var $name, $arguments, t2,
+ t1 = rti._kind,
+ kind = t1;
+ if (kind === 5)
+ return "erased";
+ if (kind === 2)
+ return "dynamic";
+ if (kind === 3)
+ return "void";
+ if (kind === 1)
+ return "Never";
+ if (kind === 4)
+ return "any";
+ if (kind === 6) {
+ H.assertHelper(t1 === 6);
+ return H.S(H._rtiToString(rti._primary, genericContext)) + "*";
+ }
+ if (kind === 7) {
+ H.assertHelper(t1 === 7);
+ return H.S(H._rtiToString(rti._primary, genericContext)) + "?";
+ }
+ if (kind === 8) {
+ H.assertHelper(t1 === 8);
+ return "FutureOr<" + H.S(H._rtiToString(rti._primary, genericContext)) + ">";
+ }
+ if (kind === 9) {
+ H.assertHelper(t1 === 9);
+ $name = H._unminifyOrTag(rti._primary);
+ $arguments = H.Rti__getInterfaceTypeArguments(rti);
+ return $arguments.length !== 0 ? $name + ("<" + H._rtiArrayToString($arguments, genericContext) + ">") : $name;
+ }
+ if (kind === 11)
+ return H._functionRtiToString(rti, genericContext, null);
+ if (kind === 12) {
+ H.assertHelper(t1 === 12);
+ return H._functionRtiToString(rti._primary, genericContext, H.Rti__getGenericFunctionBounds(rti));
+ }
+ if (kind === 13) {
+ H.assertHelper(t1 === 13);
+ t1 = rti._primary;
+ t2 = genericContext.length;
+ t1 = t2 - 1 - t1;
+ if (t1 < 0 || t1 >= t2)
+ return H.ioore(genericContext, t1);
+ return genericContext[t1];
+ }
+ return "?";
+ },
+ _unminifyOrTag: function(rawClassName) {
+ var preserved = H.unmangleGlobalNameIfPreservedAnyways(rawClassName);
+ if (preserved != null)
+ return preserved;
+ return rawClassName;
+ },
+ _Universe_findRule: function(universe, targetType) {
+ var rule = universe.tR[targetType];
+ for (; typeof rule == "string";)
+ rule = universe.tR[rule];
+ return rule;
+ },
+ _Universe_findErasedType: function(universe, cls) {
+ var $length, erased, $arguments, i, $interface,
+ metadata = universe.eT,
+ probe = metadata[cls];
+ if (probe == null)
+ return H._Universe_eval(universe, cls);
+ else if (typeof probe == "number") {
+ $length = probe;
+ erased = H._Universe__lookupTerminalRti(universe, 5, "#");
+ $arguments = [];
+ for (i = 0; i < $length; ++i)
+ $arguments.push(erased);
+ $interface = H._Universe__lookupInterfaceRti(universe, cls, $arguments);
+ metadata[cls] = $interface;
+ return $interface;
+ } else
+ return probe;
+ },
+ _Universe_addRules: function(universe, rules) {
+ return H._Utils_objectAssign(universe.tR, rules);
+ },
+ _Universe_addErasedTypes: function(universe, types) {
+ return H._Utils_objectAssign(universe.eT, types);
+ },
+ _Universe_eval: function(universe, recipe) {
+ var rti,
+ cache = universe.eC,
+ probe = cache.get(recipe);
+ if (probe != null)
+ return probe;
+ rti = H._Universe__parseRecipe(universe, null, recipe);
+ cache.set(recipe, rti);
+ return rti;
+ },
+ _Universe_evalInEnvironment: function(universe, environment, recipe) {
+ var probe, rti,
+ cache = environment._evalCache;
+ if (cache == null)
+ cache = environment._evalCache = new Map();
+ probe = cache.get(recipe);
+ if (probe != null)
+ return probe;
+ rti = H._Universe__parseRecipe(universe, environment, recipe);
+ cache.set(recipe, rti);
+ return rti;
+ },
+ _Universe_bind: function(universe, environment, argumentsRti) {
+ var s, argumentsRecipe, probe, rti,
+ cache = environment._bindCache;
+ if (cache == null)
+ cache = environment._bindCache = new Map();
+ s = argumentsRti._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ argumentsRecipe = s;
+ probe = cache.get(argumentsRecipe);
+ if (probe != null)
+ return probe;
+ rti = H._Universe__lookupBindingRti(universe, environment, argumentsRti._kind === 10 ? H.Rti__getBindingArguments(argumentsRti) : [argumentsRti]);
+ cache.set(argumentsRecipe, rti);
+ return rti;
+ },
+ _Universe__parseRecipe: function(universe, environment, recipe) {
+ var rti = H._Parser_parse(H._Parser_create(universe, environment, recipe));
+ return rti;
+ },
+ _Universe__finishRti: function(universe, rti) {
+ var s = rti._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ universe.eC.set(s, rti);
+ rti._as = H._generalAsCheckImplementation;
+ rti._check = H._generalTypeCheckImplementation;
+ rti._is = H._installSpecializedIsTest;
+ return rti;
+ },
+ _Universe__lookupTerminalRti: function(universe, kind, canonicalRecipe) {
+ var rti,
+ probe = universe.eC.get(canonicalRecipe);
+ if (probe != null)
+ return probe;
+ rti = new H.Rti(null, null, null);
+ rti._kind = kind;
+ rti._canonicalRecipe = canonicalRecipe;
+ return H._Universe__finishRti(universe, rti);
+ },
+ _Universe__lookupUnaryRti: function(universe, kind, baseType, canonicalRecipe) {
+ var rti,
+ probe = universe.eC.get(canonicalRecipe);
+ if (probe != null)
+ return probe;
+ rti = new H.Rti(null, null, null);
+ rti._kind = kind;
+ rti._primary = baseType;
+ rti._canonicalRecipe = canonicalRecipe;
+ return H._Universe__finishRti(universe, rti);
+ },
+ _Universe__lookupGenericFunctionParameterRti: function(universe, index) {
+ var rti,
+ canonicalRecipe = "" + index + "^",
+ probe = universe.eC.get(canonicalRecipe);
+ if (probe != null)
+ return probe;
+ rti = new H.Rti(null, null, null);
+ rti._kind = 13;
+ rti._primary = index;
+ rti._canonicalRecipe = canonicalRecipe;
+ return H._Universe__finishRti(universe, rti);
+ },
+ _Universe__canonicalRecipeJoin: function($arguments) {
+ var s, sep, i, s0,
+ $length = $arguments.length;
+ for (s = "", sep = "", i = 0; i < $length; ++i, sep = ",") {
+ s0 = $arguments[i]._canonicalRecipe;
+ if (H.assertTest(typeof s0 == "string"))
+ H.assertThrow("Missing canonical recipe");
+ s += sep + s0;
+ }
+ return s;
+ },
+ _Universe__canonicalRecipeJoinNamed: function($arguments) {
+ var s, sep, i, t1, s0,
+ $length = $arguments.length;
+ H.assertHelper(($length & 1) === 0);
+ for (s = "", sep = "", i = 0; i < $length; i += 2, sep = ",") {
+ t1 = $arguments[i];
+ s0 = $arguments[i + 1]._canonicalRecipe;
+ if (H.assertTest(typeof s0 == "string"))
+ H.assertThrow("Missing canonical recipe");
+ s += sep + t1 + ":" + s0;
+ }
+ return s;
+ },
+ _Universe__lookupInterfaceRti: function(universe, $name, $arguments) {
+ var s, probe, rti;
+ H.assertHelper(typeof $name == "string");
+ s = $name;
+ if ($arguments.length !== 0)
+ s += "<" + H._Universe__canonicalRecipeJoin($arguments) + ">";
+ probe = universe.eC.get(s);
+ if (probe != null)
+ return probe;
+ rti = new H.Rti(null, null, null);
+ rti._kind = 9;
+ rti._primary = $name;
+ rti._rest = $arguments;
+ if ($arguments.length > 0)
+ rti._precomputed1 = $arguments[0];
+ rti._canonicalRecipe = s;
+ return H._Universe__finishRti(universe, rti);
+ },
+ _Universe__lookupBindingRti: function(universe, base, $arguments) {
+ var newBase, newArguments, s, probe, rti,
+ t1 = base._kind;
+ if (t1 === 10) {
+ H.assertHelper(t1 === 10);
+ newBase = base._primary;
+ newArguments = H.Rti__getBindingArguments(base).concat($arguments);
+ } else {
+ newArguments = $arguments;
+ newBase = base;
+ }
+ s = newBase._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ s = s + ";" + ("<" + H._Universe__canonicalRecipeJoin(newArguments) + ">");
+ probe = universe.eC.get(s);
+ if (probe != null)
+ return probe;
+ rti = new H.Rti(null, null, null);
+ rti._kind = 10;
+ rti._primary = newBase;
+ rti._rest = newArguments;
+ rti._canonicalRecipe = s;
+ return H._Universe__finishRti(universe, rti);
+ },
+ _Universe__lookupFunctionRti: function(universe, returnType, parameters) {
+ var requiredPositional, requiredPositionalLength, optionalPositional, optionalPositionalLength, optionalNamed, optionalNamedLength, recipe, key, probe, rti,
+ s = returnType._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ requiredPositional = parameters._requiredPositional;
+ requiredPositionalLength = requiredPositional.length;
+ optionalPositional = parameters._optionalPositional;
+ optionalPositionalLength = optionalPositional.length;
+ optionalNamed = parameters._optionalNamed;
+ optionalNamedLength = optionalNamed.length;
+ H.assertHelper(optionalPositionalLength === 0 || optionalNamedLength === 0);
+ recipe = "(" + H._Universe__canonicalRecipeJoin(requiredPositional);
+ if (optionalPositionalLength > 0)
+ recipe += (requiredPositionalLength > 0 ? "," : "") + "[" + H._Universe__canonicalRecipeJoin(optionalPositional) + "]";
+ if (optionalNamedLength > 0)
+ recipe += (requiredPositionalLength > 0 ? "," : "") + "{" + H._Universe__canonicalRecipeJoinNamed(optionalNamed) + "}";
+ key = s + (recipe + ")");
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ rti = new H.Rti(null, null, null);
+ rti._kind = 11;
+ rti._primary = returnType;
+ rti._rest = parameters;
+ rti._canonicalRecipe = key;
+ return H._Universe__finishRti(universe, rti);
+ },
+ _Universe__lookupGenericFunctionRti: function(universe, baseFunctionType, bounds) {
+ var key, probe, rti,
+ s = baseFunctionType._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ key = s + "<" + H._Universe__canonicalRecipeJoin(bounds) + ">";
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ rti = new H.Rti(null, null, null);
+ rti._kind = 12;
+ rti._primary = baseFunctionType;
+ rti._rest = bounds;
+ rti._canonicalRecipe = key;
+ return H._Universe__finishRti(universe, rti);
+ },
+ _Parser_create: function(universe, environment, recipe) {
+ return {u: universe, e: environment, r: recipe, s: [], p: 0};
+ },
+ _Parser_parse: function(parser) {
+ var t1, i, ch, t2, t3, universe, array, head, base, u, s, parameters, optionalPositional, optionalNamed, item,
+ _s24_ = "Missing canonical recipe",
+ source = parser.r,
+ stack = parser.s;
+ for (t1 = source.length, i = 0; i < t1;) {
+ ch = source.charCodeAt(i);
+ if (ch >= 48 && ch <= 57)
+ i = H._Parser_handleDigit(i + 1, ch, source, stack);
+ else if ((((ch | 32) >>> 0) - 97 & 65535) < 26 || ch === 95 || ch === 36)
+ i = H._Parser_handleIdentifier(parser, i, source, stack, false);
+ else if (ch === 46)
+ i = H._Parser_handleIdentifier(parser, i, source, stack, true);
+ else {
+ ++i;
+ switch (ch) {
+ case 44:
+ break;
+ case 58:
+ break;
+ case 59:
+ stack.push(H._Parser_toType(parser.u, parser.e, stack.pop()));
+ break;
+ case 94:
+ t2 = parser.u;
+ t3 = stack.pop();
+ H.assertHelper(typeof t3 == "number");
+ stack.push(H._Universe__lookupGenericFunctionParameterRti(t2, t3));
+ break;
+ case 35:
+ stack.push(H._Universe__lookupTerminalRti(parser.u, 5, "#"));
+ break;
+ case 64:
+ stack.push(H._Universe__lookupTerminalRti(parser.u, 2, "@"));
+ break;
+ case 126:
+ stack.push(H._Universe__lookupTerminalRti(parser.u, 3, "~"));
+ break;
+ case 60:
+ stack.push(parser.p);
+ parser.p = stack.length;
+ break;
+ case 62:
+ universe = parser.u;
+ array = stack.splice(parser.p);
+ H._Parser_toTypes(parser.u, parser.e, array);
+ parser.p = stack.pop();
+ head = stack.pop();
+ if (typeof head == "string")
+ stack.push(H._Universe__lookupInterfaceRti(universe, head, array));
+ else {
+ base = H._Parser_toType(universe, parser.e, head);
+ switch (base._kind) {
+ case 11:
+ stack.push(H._Universe__lookupGenericFunctionRti(universe, base, array));
+ break;
+ default:
+ stack.push(H._Universe__lookupBindingRti(universe, base, array));
+ break;
+ }
+ }
+ break;
+ case 38:
+ H._Parser_handleExtendedOperations(parser, stack);
+ break;
+ case 42:
+ u = parser.u;
+ t2 = H._Parser_toType(u, parser.e, stack.pop());
+ s = t2._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow(_s24_);
+ stack.push(H._Universe__lookupUnaryRti(u, 6, t2, s + "*"));
+ break;
+ case 63:
+ u = parser.u;
+ t2 = H._Parser_toType(u, parser.e, stack.pop());
+ s = t2._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow(_s24_);
+ stack.push(H._Universe__lookupUnaryRti(u, 7, t2, s + "?"));
+ break;
+ case 47:
+ u = parser.u;
+ t2 = H._Parser_toType(u, parser.e, stack.pop());
+ s = t2._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow(_s24_);
+ stack.push(H._Universe__lookupUnaryRti(u, 8, t2, s + "/"));
+ break;
+ case 40:
+ stack.push(parser.p);
+ parser.p = stack.length;
+ break;
+ case 41:
+ universe = parser.u;
+ parameters = new H._FunctionParameters();
+ optionalPositional = universe.sEA;
+ optionalNamed = universe.sEA;
+ head = stack.pop();
+ if (typeof head == "number")
+ switch (head) {
+ case -1:
+ optionalPositional = stack.pop();
+ break;
+ case -2:
+ optionalNamed = stack.pop();
+ break;
+ default:
+ stack.push(head);
+ break;
+ }
+ else
+ stack.push(head);
+ array = stack.splice(parser.p);
+ H._Parser_toTypes(parser.u, parser.e, array);
+ parser.p = stack.pop();
+ parameters._requiredPositional = array;
+ parameters._optionalPositional = optionalPositional;
+ parameters._optionalNamed = optionalNamed;
+ stack.push(H._Universe__lookupFunctionRti(universe, H._Parser_toType(universe, parser.e, stack.pop()), parameters));
+ break;
+ case 91:
+ stack.push(parser.p);
+ parser.p = stack.length;
+ break;
+ case 93:
+ array = stack.splice(parser.p);
+ H._Parser_toTypes(parser.u, parser.e, array);
+ parser.p = stack.pop();
+ stack.push(array);
+ stack.push(-1);
+ break;
+ case 123:
+ stack.push(parser.p);
+ parser.p = stack.length;
+ break;
+ case 125:
+ array = stack.splice(parser.p);
+ H._Parser_toTypesNamed(parser.u, parser.e, array);
+ parser.p = stack.pop();
+ stack.push(array);
+ stack.push(-2);
+ break;
+ default:
+ throw "Bad character " + ch;
+ }
+ }
+ }
+ item = stack.pop();
+ return H._Parser_toType(parser.u, parser.e, item);
+ },
+ _Parser_handleDigit: function(i, digit, source, stack) {
+ var t1, ch,
+ value = digit - 48;
+ for (t1 = source.length; i < t1; ++i) {
+ ch = source.charCodeAt(i);
+ if (!(ch >= 48 && ch <= 57))
+ break;
+ value = value * 10 + (ch - 48);
+ }
+ stack.push(value);
+ return i;
+ },
+ _Parser_handleIdentifier: function(parser, start, source, stack, hasPeriod) {
+ var t1, ch, t2, string, environment, rule, recipe,
+ i = start + 1;
+ for (t1 = source.length; i < t1; ++i) {
+ ch = source.charCodeAt(i);
+ if (ch === 46) {
+ if (hasPeriod)
+ break;
+ hasPeriod = true;
+ } else {
+ if (!((((ch | 32) >>> 0) - 97 & 65535) < 26 || ch === 95 || ch === 36))
+ t2 = ch >= 48 && ch <= 57;
+ else
+ t2 = true;
+ if (!t2)
+ break;
+ }
+ }
+ string = source.substring(start, i);
+ if (hasPeriod) {
+ t1 = parser.u;
+ environment = parser.e;
+ t2 = environment._kind;
+ if (t2 === 10) {
+ H.assertHelper(t2 === 10);
+ environment = environment._primary;
+ }
+ H.assertHelper(environment._kind === 9);
+ rule = H._Universe_findRule(t1, environment._primary);
+ H.assertHelper(rule != null);
+ recipe = rule[string];
+ if (recipe == null)
+ H.throwExpression('No "' + string + '" in "' + H.Rti__getCanonicalRecipe(environment) + '"');
+ stack.push(H._Universe_evalInEnvironment(t1, environment, recipe));
+ } else
+ stack.push(string);
+ return i;
+ },
+ _Parser_handleExtendedOperations: function(parser, stack) {
+ var $top = stack.pop();
+ if (0 === $top) {
+ stack.push(H._Universe__lookupTerminalRti(parser.u, 1, "0&"));
+ return;
+ }
+ if (1 === $top) {
+ stack.push(H._Universe__lookupTerminalRti(parser.u, 4, "1&"));
+ return;
+ }
+ throw H.wrapException(P.AssertionError$("Unexpected extended operation " + H.S($top)));
+ },
+ _Parser_toType: function(universe, environment, item) {
+ if (typeof item == "string")
+ return H._Universe__lookupInterfaceRti(universe, item, universe.sEA);
+ else if (typeof item == "number")
+ return H._Parser_indexToType(universe, environment, item);
+ else
+ return item;
+ },
+ _Parser_toTypes: function(universe, environment, items) {
+ var i,
+ $length = items.length;
+ for (i = 0; i < $length; ++i)
+ items[i] = H._Parser_toType(universe, environment, items[i]);
+ },
+ _Parser_toTypesNamed: function(universe, environment, items) {
+ var i,
+ $length = items.length;
+ H.assertHelper(($length & 1) === 0);
+ for (i = 1; i < $length; i += 2)
+ items[i] = H._Parser_toType(universe, environment, items[i]);
+ },
+ _Parser_indexToType: function(universe, environment, index) {
+ var typeArguments, len,
+ t1 = environment._kind,
+ kind = t1;
+ if (kind === 10) {
+ if (index === 0) {
+ H.assertHelper(t1 === 10);
+ return environment._primary;
+ }
+ typeArguments = H.Rti__getBindingArguments(environment);
+ len = typeArguments.length;
+ if (index <= len)
+ return typeArguments[index - 1];
+ index -= len;
+ H.assertHelper(t1 === 10);
+ environment = environment._primary;
+ kind = environment._kind;
+ } else if (index === 0)
+ return environment;
+ if (kind !== 9)
+ throw H.wrapException(P.AssertionError$("Indexed base must be an interface type"));
+ typeArguments = H.Rti__getInterfaceTypeArguments(environment);
+ if (index <= typeArguments.length)
+ return typeArguments[index - 1];
+ throw H.wrapException(P.AssertionError$("Bad index " + index + " for " + environment.toString$0(0)));
+ },
+ _isSubtype: function(universe, s, sEnv, t, tEnv, isLegacy) {
+ var sKind, leftTypeVariable, t1, tKind, sBounds, tBounds;
+ if (s === t)
+ return true;
+ if (H.isTopType(t, true))
+ return true;
+ sKind = s._kind;
+ if (sKind === 4)
+ return true;
+ if (H.isTopType(s, true))
+ return false;
+ if (s === type$.Null)
+ return true;
+ leftTypeVariable = sKind === 13;
+ if (leftTypeVariable) {
+ H.assertHelper(s._kind === 13);
+ if (H._isSubtype(universe, sEnv[s._primary], sEnv, t, tEnv, true))
+ return true;
+ }
+ t1 = t._kind;
+ tKind = t1;
+ if (sKind === 6) {
+ H.assertHelper(s._kind === 6);
+ return H._isSubtype(universe, s._primary, sEnv, t, tEnv, true);
+ }
+ if (tKind === 6) {
+ H.assertHelper(t1 === 6);
+ t1 = t._primary;
+ return H._isSubtype(universe, s, sEnv, t1, tEnv, true);
+ }
+ if (sKind === 8) {
+ H.assertHelper(s._kind === 8);
+ if (!H._isSubtype(universe, s._primary, sEnv, t, tEnv, true))
+ return false;
+ return H._isSubtype(universe, H.Rti__getFutureFromFutureOr(universe, s), sEnv, t, tEnv, true);
+ }
+ if (sKind === 7) {
+ H.assertHelper(s._kind === 7);
+ t1 = H._isSubtype(universe, s._primary, sEnv, t, tEnv, true);
+ return t1;
+ }
+ if (tKind === 8) {
+ H.assertHelper(t1 === 8);
+ if (H._isSubtype(universe, s, sEnv, t._primary, tEnv, true))
+ return true;
+ return H._isSubtype(universe, s, sEnv, H.Rti__getFutureFromFutureOr(universe, t), tEnv, true);
+ }
+ if (tKind === 7) {
+ H.assertHelper(t1 === 7);
+ t1 = H._isSubtype(universe, s, sEnv, t._primary, tEnv, true);
+ return t1;
+ }
+ if (leftTypeVariable)
+ return false;
+ t1 = sKind !== 11;
+ if ((!t1 || sKind === 12) && t === type$.Function)
+ return true;
+ if (tKind === 12) {
+ if (s === type$.JavaScriptFunction)
+ return true;
+ if (sKind !== 12)
+ return false;
+ sBounds = H.Rti__getGenericFunctionBounds(s);
+ tBounds = H.Rti__getGenericFunctionBounds(t);
+ if (!H.typesEqual(sBounds, tBounds, true))
+ return false;
+ sEnv = sEnv == null ? sBounds : sBounds.concat(sEnv);
+ tEnv = tEnv == null ? tBounds : tBounds.concat(tEnv);
+ H.assertHelper(s._kind === 12);
+ t1 = s._primary;
+ H.assertHelper(t._kind === 12);
+ return H._isFunctionSubtype(universe, t1, sEnv, t._primary, tEnv, true);
+ }
+ if (tKind === 11) {
+ if (s === type$.JavaScriptFunction)
+ return true;
+ if (t1)
+ return false;
+ return H._isFunctionSubtype(universe, s, sEnv, t, tEnv, true);
+ }
+ if (sKind === 9) {
+ if (tKind !== 9)
+ return false;
+ return H._isInterfaceSubtype(universe, s, sEnv, t, tEnv, true);
+ }
+ return false;
+ },
+ _isFunctionSubtype: function(universe, s, sEnv, t, tEnv, isLegacy) {
+ var t1, sParameters, tParameters, sRequiredPositional, tRequiredPositional, sRequiredPositionalLength, tRequiredPositionalLength, requiredPositionalDelta, sOptionalPositional, tOptionalPositional, sOptionalPositionalLength, tOptionalPositionalLength, i, sOptionalNamed, tOptionalNamed, sOptionalNamedLength, tOptionalNamedLength, j, tName, sName;
+ H.assertHelper(s._kind === 11);
+ H.assertHelper(t._kind === 11);
+ H.assertHelper(s._kind === 11);
+ t1 = s._primary;
+ H.assertHelper(t._kind === 11);
+ if (!H._isSubtype(universe, t1, sEnv, t._primary, tEnv, true))
+ return false;
+ sParameters = H.Rti__getFunctionParameters(s);
+ tParameters = H.Rti__getFunctionParameters(t);
+ sRequiredPositional = sParameters._requiredPositional;
+ tRequiredPositional = tParameters._requiredPositional;
+ sRequiredPositionalLength = sRequiredPositional.length;
+ tRequiredPositionalLength = tRequiredPositional.length;
+ if (sRequiredPositionalLength > tRequiredPositionalLength)
+ return false;
+ requiredPositionalDelta = tRequiredPositionalLength - sRequiredPositionalLength;
+ sOptionalPositional = sParameters._optionalPositional;
+ tOptionalPositional = tParameters._optionalPositional;
+ sOptionalPositionalLength = sOptionalPositional.length;
+ tOptionalPositionalLength = tOptionalPositional.length;
+ if (sRequiredPositionalLength + sOptionalPositionalLength < tRequiredPositionalLength + tOptionalPositionalLength)
+ return false;
+ for (i = 0; i < sRequiredPositionalLength; ++i) {
+ t1 = sRequiredPositional[i];
+ if (!H._isSubtype(universe, tRequiredPositional[i], tEnv, t1, sEnv, true))
+ return false;
+ }
+ for (i = 0; i < requiredPositionalDelta; ++i) {
+ t1 = sOptionalPositional[i];
+ if (!H._isSubtype(universe, tRequiredPositional[sRequiredPositionalLength + i], tEnv, t1, sEnv, true))
+ return false;
+ }
+ for (i = 0; i < tOptionalPositionalLength; ++i) {
+ t1 = sOptionalPositional[requiredPositionalDelta + i];
+ if (!H._isSubtype(universe, tOptionalPositional[i], tEnv, t1, sEnv, true))
+ return false;
+ }
+ sOptionalNamed = sParameters._optionalNamed;
+ tOptionalNamed = tParameters._optionalNamed;
+ sOptionalNamedLength = sOptionalNamed.length;
+ tOptionalNamedLength = tOptionalNamed.length;
+ for (i = 0, j = 0; j < tOptionalNamedLength; j += 2) {
+ tName = tOptionalNamed[j];
+ do {
+ if (i >= sOptionalNamedLength)
+ return false;
+ sName = sOptionalNamed[i];
+ i += 2;
+ } while (sName < tName);
+ if (tName < sName)
+ return false;
+ t1 = sOptionalNamed[i - 1];
+ if (!H._isSubtype(universe, tOptionalNamed[j + 1], tEnv, t1, sEnv, true))
+ return false;
+ }
+ return true;
+ },
+ _isInterfaceSubtype: function(universe, s, sEnv, t, tEnv, isLegacy) {
+ var sName, tName, sArgs, tArgs, $length, i, t1, t2, rule, supertypeArgs;
+ H.assertHelper(s._kind === 9);
+ sName = s._primary;
+ H.assertHelper(t._kind === 9);
+ tName = t._primary;
+ if (sName === tName) {
+ sArgs = H.Rti__getInterfaceTypeArguments(s);
+ tArgs = H.Rti__getInterfaceTypeArguments(t);
+ $length = sArgs.length;
+ H.assertHelper($length === tArgs.length);
+ for (i = 0; i < $length; ++i) {
+ t1 = sArgs[i];
+ t2 = tArgs[i];
+ if (!H._isSubtype(universe, t1, sEnv, t2, tEnv, true))
+ return false;
+ }
+ return true;
+ }
+ rule = H._Universe_findRule(universe, sName);
+ if (rule == null)
+ return false;
+ supertypeArgs = rule[tName];
+ if (supertypeArgs == null)
+ return false;
+ $length = supertypeArgs.length;
+ tArgs = H.Rti__getInterfaceTypeArguments(t);
+ H.assertHelper($length === tArgs.length);
+ for (i = 0; i < $length; ++i)
+ if (!H._isSubtype(universe, H._Universe_evalInEnvironment(universe, s, supertypeArgs[i]), sEnv, tArgs[i], tEnv, true))
+ return false;
+ return true;
+ },
+ typeEqual: function(s, t, isLegacy) {
+ var t1, sKind, t2;
+ if (s === t)
+ return true;
+ if (H.isTopType(s, true))
+ return H.isTopType(t, true);
+ t1 = s._kind;
+ sKind = t1;
+ if (sKind !== t._kind)
+ return false;
+ switch (sKind) {
+ case 6:
+ case 7:
+ case 8:
+ return H.typeEqual(s._primary, t._primary, true);
+ case 9:
+ H.assertHelper(t1 === 9);
+ t1 = s._primary;
+ H.assertHelper(t._kind === 9);
+ if (t1 !== t._primary)
+ return false;
+ return H.typesEqual(H.Rti__getInterfaceTypeArguments(s), H.Rti__getInterfaceTypeArguments(t), true);
+ case 10:
+ H.assertHelper(t1 === 10);
+ t1 = s._primary;
+ H.assertHelper(t._kind === 10);
+ return H.typeEqual(t1, t._primary, true) && H.typesEqual(H.Rti__getBindingArguments(s), H.Rti__getBindingArguments(t), true);
+ case 11:
+ H.assertHelper(t1 === 11);
+ t1 = s._primary;
+ H.assertHelper(t._kind === 11);
+ if (H.typeEqual(t1, t._primary, true)) {
+ t1 = H.Rti__getFunctionParameters(s);
+ t2 = H.Rti__getFunctionParameters(t);
+ t1 = H.typesEqual(t1._requiredPositional, t2._requiredPositional, true) && H.typesEqual(t1._optionalPositional, t2._optionalPositional, true) && H.namedTypesEqual(t1._optionalNamed, t2._optionalNamed, true);
+ } else
+ t1 = false;
+ return t1;
+ case 12:
+ H.assertHelper(t1 === 12);
+ t1 = s._primary;
+ H.assertHelper(t._kind === 12);
+ return H.typeEqual(t1, t._primary, true) && H.typesEqual(H.Rti__getGenericFunctionBounds(s), H.Rti__getGenericFunctionBounds(t), true);
+ default:
+ return false;
+ }
+ },
+ typesEqual: function(sArray, tArray, isLegacy) {
+ var i,
+ sLength = sArray.length;
+ if (sLength !== tArray.length)
+ return false;
+ for (i = 0; i < sLength; ++i)
+ if (!H.typeEqual(sArray[i], tArray[i], true))
+ return false;
+ return true;
+ },
+ namedTypesEqual: function(sArray, tArray, isLegacy) {
+ var i, t1,
+ sLength = sArray.length,
+ tLength = tArray.length;
+ H.assertHelper((sLength & 1) === 0);
+ H.assertHelper((tLength & 1) === 0);
+ if (sLength !== tLength)
+ return false;
+ for (i = 0; i < sLength; i += 2) {
+ if (sArray[i] !== tArray[i])
+ return false;
+ t1 = i + 1;
+ if (!H.typeEqual(sArray[t1], tArray[t1], true))
+ return false;
+ }
+ return true;
+ },
+ isLegacyTopType: function(t) {
+ return H.isTopType(t, true);
+ },
+ isTopType: function(t, isLegacy) {
+ var t1, kind;
+ if (t === type$.Object)
+ return true;
+ t1 = t._kind;
+ kind = t1;
+ if (kind !== 2)
+ if (kind !== 3)
+ if (kind !== 4)
+ if (kind !== 5)
+ if (kind === 8) {
+ H.assertHelper(t1 === 8);
+ t1 = H.isTopType(t._primary, true);
+ } else
+ t1 = false;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ return t1;
+ },
+ _Utils_objectAssign: function(o, other) {
+ var i, key,
+ keys = Object.keys(other),
+ $length = keys.length;
+ for (i = 0; i < $length; ++i) {
+ key = keys[i];
+ o[key] = other[key];
+ }
+ },
+ Rti: function Rti(t0, t1, t2) {
+ var _ = this;
+ _._as = t0;
+ _._check = t1;
+ _._is = t2;
+ _._cachedRuntimeType = _._specializedTestResource = _._precomputed1 = null;
+ _._kind = 0;
+ _._canonicalRecipe = _._bindCache = _._evalCache = _._rest = _._primary = null;
+ },
+ _FunctionParameters: function _FunctionParameters() {
+ this._optionalNamed = this._optionalPositional = this._requiredPositional = null;
+ },
+ _Type: function _Type(t0) {
+ this._rti = t0;
+ this._hashCode = null;
+ },
+ _Error: function _Error() {
+ },
+ _CastError: function _CastError(t0) {
+ this._message = t0;
+ },
+ _TypeError: function _TypeError(t0) {
+ this._message = t0;
+ },
+ extractKeys: function(victim) {
+ return J.JSArray_JSArray$markFixed(victim ? Object.keys(victim) : [], type$.dynamic);
+ },
+ unmangleGlobalNameIfPreservedAnyways: function($name) {
+ return init.mangledGlobalNames[$name];
+ },
+ printString: function(string) {
+ if (typeof dartPrint == "function") {
+ dartPrint(string);
+ return;
+ }
+ if (typeof console == "object" && typeof console.log != "undefined") {
+ console.log(string);
+ return;
+ }
+ if (typeof window == "object")
+ return;
+ if (typeof print == "function") {
+ print(string);
+ return;
+ }
+ throw "Unable to print message: " + String(string);
+ }
+ },
+ J = {
+ makeDispatchRecord: function(interceptor, proto, extension, indexability) {
+ return {i: interceptor, p: proto, e: extension, x: indexability};
+ },
+ getNativeInterceptor: function(object) {
+ var proto, objectProto, $constructor, interceptor,
+ record = object[init.dispatchPropertyName];
+ if (record == null)
+ if ($.initNativeDispatchFlag == null) {
+ H.initNativeDispatch();
+ record = object[init.dispatchPropertyName];
+ }
+ if (record != null) {
+ proto = record.p;
+ if (false === proto)
+ return record.i;
+ if (true === proto)
+ return object;
+ objectProto = Object.getPrototypeOf(object);
+ if (proto === objectProto)
+ return record.i;
+ if (record.e === objectProto)
+ throw H.wrapException(P.UnimplementedError$("Return interceptor for " + H.S(proto(object, record))));
+ }
+ $constructor = object.constructor;
+ interceptor = $constructor == null ? null : $constructor[$.$get$JS_INTEROP_INTERCEPTOR_TAG()];
+ if (interceptor != null)
+ return interceptor;
+ interceptor = H.lookupAndCacheInterceptor(object);
+ if (interceptor != null)
+ return interceptor;
+ if (typeof object == "function")
+ return C.JavaScriptFunction_methods;
+ proto = Object.getPrototypeOf(object);
+ if (proto == null)
+ return C.PlainJavaScriptObject_methods;
+ if (proto === Object.prototype)
+ return C.PlainJavaScriptObject_methods;
+ if (typeof $constructor == "function") {
+ Object.defineProperty($constructor, $.$get$JS_INTEROP_INTERCEPTOR_TAG(), {value: C.UnknownJavaScriptObject_methods, enumerable: false, writable: true, configurable: true});
+ return C.UnknownJavaScriptObject_methods;
+ }
+ return C.UnknownJavaScriptObject_methods;
+ },
+ JSArray_JSArray$fixed: function($length, $E) {
+ if (!H._isInt($length))
+ throw H.wrapException(P.ArgumentError$value($length, "length", "is not an integer"));
+ if ($length < 0 || $length > 4294967295)
+ throw H.wrapException(P.RangeError$range($length, 0, 4294967295, "length", null));
+ return J.JSArray_JSArray$markFixed(new Array($length), $E);
+ },
+ JSArray_JSArray$markFixed: function(allocation, $E) {
+ return J.JSArray_markFixedList(H.setRuntimeTypeInfo(allocation, $E._eval$1("JSArray<0>")));
+ },
+ JSArray_markFixedList: function(list) {
+ list.fixed$length = Array;
+ return list;
+ },
+ JSString__isWhitespace: function(codeUnit) {
+ if (codeUnit < 256)
+ switch (codeUnit) {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 32:
+ case 133:
+ case 160:
+ return true;
+ default:
+ return false;
+ }
+ switch (codeUnit) {
+ case 5760:
+ case 8192:
+ case 8193:
+ case 8194:
+ case 8195:
+ case 8196:
+ case 8197:
+ case 8198:
+ case 8199:
+ case 8200:
+ case 8201:
+ case 8202:
+ case 8232:
+ case 8233:
+ case 8239:
+ case 8287:
+ case 12288:
+ case 65279:
+ return true;
+ default:
+ return false;
+ }
+ },
+ JSString__skipLeadingWhitespace: function(string, index) {
+ var t1, codeUnit;
+ for (t1 = string.length; index < t1;) {
+ codeUnit = C.JSString_methods._codeUnitAt$1(string, index);
+ if (codeUnit !== 32 && codeUnit !== 13 && !J.JSString__isWhitespace(codeUnit))
+ break;
+ ++index;
+ }
+ return index;
+ },
+ JSString__skipTrailingWhitespace: function(string, index) {
+ var index0, codeUnit;
+ for (; index > 0; index = index0) {
+ index0 = index - 1;
+ codeUnit = C.JSString_methods.codeUnitAt$1(string, index0);
+ if (codeUnit !== 32 && codeUnit !== 13 && !J.JSString__isWhitespace(codeUnit))
+ break;
+ }
+ return index;
+ },
+ getInterceptor$: function(receiver) {
+ if (typeof receiver == "number") {
+ if (Math.floor(receiver) == receiver)
+ return J.JSInt.prototype;
+ return J.JSDouble.prototype;
+ }
+ if (typeof receiver == "string")
+ return J.JSString.prototype;
+ if (receiver == null)
+ return J.JSNull.prototype;
+ if (typeof receiver == "boolean")
+ return J.JSBool.prototype;
+ if (receiver.constructor == Array)
+ return J.JSArray.prototype;
+ if (typeof receiver != "object") {
+ if (typeof receiver == "function")
+ return J.JavaScriptFunction.prototype;
+ return receiver;
+ }
+ if (receiver instanceof P.Object)
+ return receiver;
+ return J.getNativeInterceptor(receiver);
+ },
+ getInterceptor$ansx: function(receiver) {
+ if (typeof receiver == "number")
+ return J.JSNumber.prototype;
+ if (typeof receiver == "string")
+ return J.JSString.prototype;
+ if (receiver == null)
+ return receiver;
+ if (receiver.constructor == Array)
+ return J.JSArray.prototype;
+ if (typeof receiver != "object") {
+ if (typeof receiver == "function")
+ return J.JavaScriptFunction.prototype;
+ return receiver;
+ }
+ if (receiver instanceof P.Object)
+ return receiver;
+ return J.getNativeInterceptor(receiver);
+ },
+ getInterceptor$asx: function(receiver) {
+ if (typeof receiver == "string")
+ return J.JSString.prototype;
+ if (receiver == null)
+ return receiver;
+ if (receiver.constructor == Array)
+ return J.JSArray.prototype;
+ if (typeof receiver != "object") {
+ if (typeof receiver == "function")
+ return J.JavaScriptFunction.prototype;
+ return receiver;
+ }
+ if (receiver instanceof P.Object)
+ return receiver;
+ return J.getNativeInterceptor(receiver);
+ },
+ getInterceptor$ax: function(receiver) {
+ if (receiver == null)
+ return receiver;
+ if (receiver.constructor == Array)
+ return J.JSArray.prototype;
+ if (typeof receiver != "object") {
+ if (typeof receiver == "function")
+ return J.JavaScriptFunction.prototype;
+ return receiver;
+ }
+ if (receiver instanceof P.Object)
+ return receiver;
+ return J.getNativeInterceptor(receiver);
+ },
+ getInterceptor$n: function(receiver) {
+ if (typeof receiver == "number")
+ return J.JSNumber.prototype;
+ if (receiver == null)
+ return receiver;
+ if (!(receiver instanceof P.Object))
+ return J.UnknownJavaScriptObject.prototype;
+ return receiver;
+ },
+ getInterceptor$s: function(receiver) {
+ if (typeof receiver == "string")
+ return J.JSString.prototype;
+ if (receiver == null)
+ return receiver;
+ if (!(receiver instanceof P.Object))
+ return J.UnknownJavaScriptObject.prototype;
+ return receiver;
+ },
+ getInterceptor$x: function(receiver) {
+ if (receiver == null)
+ return receiver;
+ if (typeof receiver != "object") {
+ if (typeof receiver == "function")
+ return J.JavaScriptFunction.prototype;
+ return receiver;
+ }
+ if (receiver instanceof P.Object)
+ return receiver;
+ return J.getNativeInterceptor(receiver);
+ },
+ get$first$ax: function(receiver) {
+ return J.getInterceptor$ax(receiver).get$first(receiver);
+ },
+ get$hashCode$: function(receiver) {
+ return J.getInterceptor$(receiver).get$hashCode(receiver);
+ },
+ get$isEmpty$asx: function(receiver) {
+ return J.getInterceptor$asx(receiver).get$isEmpty(receiver);
+ },
+ get$iterator$ax: function(receiver) {
+ return J.getInterceptor$ax(receiver).get$iterator(receiver);
+ },
+ get$last$ax: function(receiver) {
+ return J.getInterceptor$ax(receiver).get$last(receiver);
+ },
+ get$length$asx: function(receiver) {
+ return J.getInterceptor$asx(receiver).get$length(receiver);
+ },
+ get$message$x: function(receiver) {
+ return J.getInterceptor$x(receiver).get$message(receiver);
+ },
+ get$runtimeType$: function(receiver) {
+ return J.getInterceptor$(receiver).get$runtimeType(receiver);
+ },
+ get$startsWith$s: function(receiver) {
+ return J.getInterceptor$s(receiver).get$startsWith(receiver);
+ },
+ $add$ansx: function(receiver, a0) {
+ if (typeof receiver == "number" && typeof a0 == "number")
+ return receiver + a0;
+ return J.getInterceptor$ansx(receiver).$add(receiver, a0);
+ },
+ $eq$: function(receiver, a0) {
+ if (receiver == null)
+ return a0 == null;
+ if (typeof receiver != "object")
+ return a0 != null && receiver === a0;
+ return J.getInterceptor$(receiver).$eq(receiver, a0);
+ },
+ $index$asx: function(receiver, a0) {
+ if (typeof a0 === "number")
+ if (receiver.constructor == Array || typeof receiver == "string" || H.isJsIndexable(receiver, receiver[init.dispatchPropertyName]))
+ if (a0 >>> 0 === a0 && a0 < receiver.length)
+ return receiver[a0];
+ return J.getInterceptor$asx(receiver).$index(receiver, a0);
+ },
+ $indexSet$ax: function(receiver, a0, a1) {
+ return J.getInterceptor$ax(receiver).$indexSet(receiver, a0, a1);
+ },
+ _codeUnitAt$1$s: function(receiver, a0) {
+ return J.getInterceptor$s(receiver)._codeUnitAt$1(receiver, a0);
+ },
+ _removeEventListener$3$x: function(receiver, a0, a1, a2) {
+ return J.getInterceptor$x(receiver)._removeEventListener$3(receiver, a0, a1, a2);
+ },
+ addEventListener$3$x: function(receiver, a0, a1, a2) {
+ return J.getInterceptor$x(receiver).addEventListener$3(receiver, a0, a1, a2);
+ },
+ allMatches$1$s: function(receiver, a0) {
+ return J.getInterceptor$s(receiver).allMatches$1(receiver, a0);
+ },
+ allMatches$2$s: function(receiver, a0, a1) {
+ return J.getInterceptor$s(receiver).allMatches$2(receiver, a0, a1);
+ },
+ codeUnitAt$1$s: function(receiver, a0) {
+ return J.getInterceptor$s(receiver).codeUnitAt$1(receiver, a0);
+ },
+ contains$1$asx: function(receiver, a0) {
+ return J.getInterceptor$asx(receiver).contains$1(receiver, a0);
+ },
+ elementAt$1$ax: function(receiver, a0) {
+ return J.getInterceptor$ax(receiver).elementAt$1(receiver, a0);
+ },
+ endsWith$1$s: function(receiver, a0) {
+ return J.getInterceptor$s(receiver).endsWith$1(receiver, a0);
+ },
+ fillRange$3$ax: function(receiver, a0, a1, a2) {
+ return J.getInterceptor$ax(receiver).fillRange$3(receiver, a0, a1, a2);
+ },
+ map$1$1$ax: function(receiver, a0, $T1) {
+ return J.getInterceptor$ax(receiver).map$1$1(receiver, a0, $T1);
+ },
+ matchAsPrefix$2$s: function(receiver, a0, a1) {
+ return J.getInterceptor$s(receiver).matchAsPrefix$2(receiver, a0, a1);
+ },
+ padRight$1$s: function(receiver, a0) {
+ return J.getInterceptor$s(receiver).padRight$1(receiver, a0);
+ },
+ replaceRange$3$asx: function(receiver, a0, a1, a2) {
+ return J.getInterceptor$asx(receiver).replaceRange$3(receiver, a0, a1, a2);
+ },
+ startsWith$1$s: function(receiver, a0) {
+ return J.getInterceptor$s(receiver).startsWith$1(receiver, a0);
+ },
+ startsWith$2$s: function(receiver, a0, a1) {
+ return J.getInterceptor$s(receiver).startsWith$2(receiver, a0, a1);
+ },
+ substring$1$s: function(receiver, a0) {
+ return J.getInterceptor$s(receiver).substring$1(receiver, a0);
+ },
+ substring$2$s: function(receiver, a0, a1) {
+ return J.getInterceptor$s(receiver).substring$2(receiver, a0, a1);
+ },
+ toRadixString$1$n: function(receiver, a0) {
+ return J.getInterceptor$n(receiver).toRadixString$1(receiver, a0);
+ },
+ toSet$0$ax: function(receiver) {
+ return J.getInterceptor$ax(receiver).toSet$0(receiver);
+ },
+ toString$0$: function(receiver) {
+ return J.getInterceptor$(receiver).toString$0(receiver);
+ },
+ trim$0$s: function(receiver) {
+ return J.getInterceptor$s(receiver).trim$0(receiver);
+ },
+ Interceptor: function Interceptor() {
+ },
+ JSBool: function JSBool() {
+ },
+ JSNull: function JSNull() {
+ },
+ JSObject: function JSObject() {
+ },
+ JavaScriptObject: function JavaScriptObject() {
+ },
+ PlainJavaScriptObject: function PlainJavaScriptObject() {
+ },
+ UnknownJavaScriptObject: function UnknownJavaScriptObject() {
+ },
+ JavaScriptFunction: function JavaScriptFunction() {
+ },
+ JSArray: function JSArray(t0) {
+ this.$ti = t0;
+ },
+ JSUnmodifiableArray: function JSUnmodifiableArray(t0) {
+ this.$ti = t0;
+ },
+ ArrayIterator: function ArrayIterator(t0, t1, t2) {
+ var _ = this;
+ _._iterable = t0;
+ _._length = t1;
+ _._index = 0;
+ _._current = null;
+ _.$ti = t2;
+ },
+ JSNumber: function JSNumber() {
+ },
+ JSInt: function JSInt() {
+ },
+ JSDouble: function JSDouble() {
+ },
+ JSString: function JSString() {
+ }
+ },
+ P = {
+ _AsyncRun__initializeScheduleImmediate: function() {
+ var div, span, t1 = {};
+ if (self.scheduleImmediate != null)
+ return P.async__AsyncRun__scheduleImmediateJsOverride$closure();
+ if (self.MutationObserver != null && self.document != null) {
+ div = self.document.createElement("div");
+ span = self.document.createElement("span");
+ t1.storedCallback = null;
+ new self.MutationObserver(H.convertDartClosureToJS(new P._AsyncRun__initializeScheduleImmediate_internalCallback(t1), 1)).observe(div, {childList: true});
+ return new P._AsyncRun__initializeScheduleImmediate_closure(t1, div, span);
+ } else if (self.setImmediate != null)
+ return P.async__AsyncRun__scheduleImmediateWithSetImmediate$closure();
+ return P.async__AsyncRun__scheduleImmediateWithTimer$closure();
+ },
+ _AsyncRun__scheduleImmediateJsOverride: function(callback) {
+ self.scheduleImmediate(H.convertDartClosureToJS(new P._AsyncRun__scheduleImmediateJsOverride_internalCallback(type$.void_Function._check(callback)), 0));
+ },
+ _AsyncRun__scheduleImmediateWithSetImmediate: function(callback) {
+ self.setImmediate(H.convertDartClosureToJS(new P._AsyncRun__scheduleImmediateWithSetImmediate_internalCallback(type$.void_Function._check(callback)), 0));
+ },
+ _AsyncRun__scheduleImmediateWithTimer: function(callback) {
+ P.Timer__createTimer(C.Duration_0, type$.void_Function._check(callback));
+ },
+ Timer__createTimer: function(duration, callback) {
+ var milliseconds = C.JSInt_methods._tdivFast$1(duration._duration, 1000);
+ return P._TimerImpl$(milliseconds < 0 ? 0 : milliseconds, callback);
+ },
+ _TimerImpl$: function(milliseconds, callback) {
+ var t1 = new P._TimerImpl(true);
+ t1._TimerImpl$2(milliseconds, callback);
+ return t1;
+ },
+ _TimerImpl$periodic: function(milliseconds, callback) {
+ var t1 = new P._TimerImpl(false);
+ t1._TimerImpl$periodic$2(milliseconds, callback);
+ return t1;
+ },
+ _makeAsyncAwaitCompleter: function($T) {
+ return new P._AsyncAwaitCompleter(new P._Future($.Zone__current, $T._eval$1("_Future<0>")), $T._eval$1("_AsyncAwaitCompleter<0>"));
+ },
+ _asyncStartSync: function(bodyFunction, completer) {
+ bodyFunction.call$2(0, null);
+ completer.isSync = true;
+ return completer._future;
+ },
+ _asyncAwait: function(object, bodyFunction) {
+ P._awaitOnObject(object, bodyFunction);
+ },
+ _asyncReturn: function(object, completer) {
+ completer.complete$1(object);
+ },
+ _asyncRethrow: function(object, completer) {
+ completer.completeError$2(H.unwrapException(object), H.getTraceFromException(object));
+ },
+ _awaitOnObject: function(object, bodyFunction) {
+ var t1, future,
+ thenCallback = new P._awaitOnObject_closure(bodyFunction),
+ errorCallback = new P._awaitOnObject_closure0(bodyFunction);
+ if (object instanceof P._Future)
+ object._thenAwait$1$2(thenCallback, errorCallback, type$.dynamic);
+ else {
+ t1 = type$.dynamic;
+ if (type$.Future_dynamic._is(object))
+ object.then$1$2$onError(thenCallback, errorCallback, t1);
+ else {
+ future = new P._Future($.Zone__current, type$._Future_dynamic);
+ future._state = 4;
+ future._resultOrListeners = object;
+ future._thenAwait$1$2(thenCallback, null, t1);
+ }
+ }
+ },
+ _wrapJsFunctionForAsync: function($function) {
+ var $protected = function(fn, ERROR) {
+ return function(errorCode, result) {
+ while (true)
+ try {
+ fn(errorCode, result);
+ break;
+ } catch (error) {
+ result = error;
+ errorCode = ERROR;
+ }
+ };
+ }($function, 1);
+ return $.Zone__current.registerBinaryCallback$3$1(new P._wrapJsFunctionForAsync_closure($protected), type$.Null, type$.int, type$.dynamic);
+ },
+ Future_Future: function(computation, $T) {
+ var result = new P._Future($.Zone__current, $T._eval$1("_Future<0>"));
+ P.Timer_Timer(C.Duration_0, new P.Future_Future_closure(result, computation));
+ return result;
+ },
+ Future_Future$microtask: function(computation, $T) {
+ var result = new P._Future($.Zone__current, $T._eval$1("_Future<0>"));
+ P.scheduleMicrotask(new P.Future_Future$microtask_closure(result, computation));
+ return result;
+ },
+ Future_Future$sync: function(computation, $T) {
+ var result, error, stackTrace, future, replacement, t1, t2, exception;
+ try {
+ result = computation.call$0();
+ if ($T._eval$1("Future<0>")._is(result))
+ return result;
+ else {
+ t1 = $T._check(result);
+ t2 = new P._Future($.Zone__current, $T._eval$1("_Future<0>"));
+ t2._state = 4;
+ t2._resultOrListeners = t1;
+ return t2;
+ }
+ } catch (exception) {
+ error = H.unwrapException(exception);
+ stackTrace = H.getTraceFromException(exception);
+ t1 = $.Zone__current;
+ future = new P._Future(t1, $T._eval$1("_Future<0>"));
+ replacement = t1.errorCallback$2(error, stackTrace);
+ if (replacement != null) {
+ t1 = replacement.error;
+ if (t1 == null)
+ t1 = new P.NullThrownError();
+ future._asyncCompleteError$2(t1, replacement.stackTrace);
+ } else
+ future._asyncCompleteError$2(error, stackTrace);
+ return future;
+ }
+ },
+ Future_Future$error: function(error, stackTrace, $T) {
+ var replacement,
+ t1 = $.Zone__current;
+ if (t1 !== C.C__RootZone) {
+ replacement = t1.errorCallback$2(error, stackTrace);
+ if (replacement != null) {
+ error = replacement.error;
+ if (error == null)
+ error = new P.NullThrownError();
+ stackTrace = replacement.stackTrace;
+ }
+ }
+ t1 = new P._Future($.Zone__current, $T._eval$1("_Future<0>"));
+ t1._asyncCompleteError$2(error, stackTrace);
+ return t1;
+ },
+ Future_wait: function(futures, eagerError, $T) {
+ var handleError, future, pos, e, st, t2, t3, _i, t4, exception, _box_0 = {}, cleanUp = null,
+ t1 = $T._eval$1("_Future<List<0>>"),
+ result = new P._Future($.Zone__current, t1);
+ _box_0.values = null;
+ _box_0.remaining = 0;
+ _box_0.stackTrace = _box_0.error = null;
+ handleError = new P.Future_wait_handleError(_box_0, cleanUp, true, result);
+ try {
+ for (t2 = futures.length, t3 = type$.Null, _i = 0, t4 = 0; _i < futures.length; futures.length === t2 || (0, H.throwConcurrentModificationError)(futures), ++_i) {
+ future = futures[_i];
+ pos = t4;
+ future.then$1$2$onError(new P.Future_wait_closure(_box_0, pos, result, cleanUp, true, $T), handleError, t3);
+ t4 = ++_box_0.remaining;
+ }
+ if (t4 === 0) {
+ t1 = new P._Future($.Zone__current, t1);
+ t1._asyncComplete$1(C.List_empty1);
+ return t1;
+ }
+ t1 = new Array(t4);
+ t1.fixed$length = Array;
+ _box_0.values = H.setRuntimeTypeInfo(t1, $T._eval$1("JSArray<0>"));
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ st = H.getTraceFromException(exception);
+ t1 = P.Future_Future$error(e, st, $T._eval$1("List<0>"));
+ return t1;
+ }
+ return result;
+ },
+ Future_forEach: function(elements, action, $T) {
+ return P.Future_doWhile(new P.Future_forEach_closure(new J.ArrayIterator(elements, 0, H._arrayInstanceType(elements)._eval$1("ArrayIterator<1>")), action));
+ },
+ Future__kTrue: function(_) {
+ return true;
+ },
+ Future_doWhile: function(action) {
+ var nextIteration, t1 = {},
+ t2 = $.Zone__current,
+ doneSignal = new P._Future(t2, type$._Future_dynamic);
+ t1.nextIteration = null;
+ nextIteration = t2.bindUnaryCallbackGuarded$1$1(new P.Future_doWhile_closure(t1, action, doneSignal), type$.bool);
+ t1.nextIteration = nextIteration;
+ nextIteration.call$1(true);
+ return doneSignal;
+ },
+ _completeWithErrorCallback: function(result, error, stackTrace) {
+ var replacement = $.Zone__current.errorCallback$2(error, stackTrace);
+ if (replacement != null) {
+ error = replacement.error;
+ if (error == null)
+ error = new P.NullThrownError();
+ stackTrace = replacement.stackTrace;
+ }
+ result._completeError$2(error, stackTrace);
+ },
+ _Future$zoneValue: function(value, _zone, $T) {
+ var t1 = new P._Future(_zone, $T._eval$1("_Future<0>"));
+ $T._check(value);
+ t1._state = 4;
+ t1._resultOrListeners = value;
+ return t1;
+ },
+ _Future__chainForeignFuture: function(source, target) {
+ var e, s, exception;
+ H.assertHelper(target._state < 4);
+ H.assertHelper(!(source instanceof P._Future));
+ H.assertHelper(target._state === 0);
+ target._state = 1;
+ try {
+ source.then$1$2$onError(new P._Future__chainForeignFuture_closure(target), new P._Future__chainForeignFuture_closure0(target), type$.Null);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P.scheduleMicrotask(new P._Future__chainForeignFuture_closure1(target, e, s));
+ }
+ },
+ _Future__chainCoreFuture: function(source, target) {
+ var t1, t2, t3, listeners;
+ H.assertHelper(target._state <= 1);
+ for (t1 = type$._Future_dynamic; t2 = source._state, t3 = t2 === 2, t3;) {
+ H.assertHelper(t3);
+ source = t1._check(source._resultOrListeners);
+ }
+ if (t2 >= 4) {
+ listeners = target._removeListeners$0();
+ target._cloneResult$1(source);
+ P._Future__propagateToListeners(target, listeners);
+ } else {
+ listeners = type$._FutureListener_dynamic_dynamic._check(target._resultOrListeners);
+ H.assertHelper(target._state <= 1);
+ target._state = 2;
+ target._resultOrListeners = source;
+ source._prependListeners$1(listeners);
+ }
+ },
+ _Future__propagateToListeners: function(source, listeners) {
+ var t2, t3, t4, _box_0, hasError, asyncError, listeners0, sourceResult, t5, t6, zone, previous, oldZone, current, result, _box_1 = {},
+ t1 = _box_1.source = source;
+ for (t2 = type$.AsyncError, t3 = type$._FutureListener_dynamic_dynamic, t4 = type$.Future_dynamic; true;) {
+ _box_0 = {};
+ H.assertHelper(t1._state >= 4);
+ t1 = _box_1.source;
+ hasError = t1._state === 8;
+ if (listeners == null) {
+ if (hasError) {
+ asyncError = t2._check(t1._resultOrListeners);
+ t1._zone.handleUncaughtError$2(asyncError.error, asyncError.stackTrace);
+ }
+ return;
+ }
+ for (; listeners0 = listeners._nextListener, listeners0 != null; listeners = listeners0) {
+ listeners._nextListener = null;
+ P._Future__propagateToListeners(_box_1.source, listeners);
+ }
+ t1 = _box_1.source;
+ sourceResult = t1._resultOrListeners;
+ _box_0.listenerHasError = hasError;
+ _box_0.listenerValueOrError = sourceResult;
+ t5 = !hasError;
+ if (t5) {
+ t6 = listeners.state;
+ t6 = (t6 & 1) !== 0 || (t6 & 15) === 8;
+ } else
+ t6 = true;
+ if (t6) {
+ t6 = listeners.result;
+ zone = t6._zone;
+ if (hasError) {
+ t1 = t1._zone;
+ t1 = !(t1 === zone || t1.get$errorZone() === zone.get$errorZone());
+ } else
+ t1 = false;
+ if (t1) {
+ t1 = _box_1.source;
+ H.assertHelper(t1._state === 8);
+ asyncError = t2._check(t1._resultOrListeners);
+ _box_1.source._zone.handleUncaughtError$2(asyncError.error, asyncError.stackTrace);
+ return;
+ }
+ t1 = $.Zone__current;
+ if (t1 !== zone) {
+ H.assertHelper(zone !== t1);
+ previous = $.Zone__current;
+ $.Zone__current = zone;
+ oldZone = previous;
+ } else
+ oldZone = null;
+ t1 = listeners.state;
+ if ((t1 & 15) === 8)
+ new P._Future__propagateToListeners_handleWhenCompleteCallback(_box_1, _box_0, listeners, hasError).call$0();
+ else if (t5) {
+ if ((t1 & 1) !== 0)
+ new P._Future__propagateToListeners_handleValueCallback(_box_0, listeners, sourceResult).call$0();
+ } else if ((t1 & 2) !== 0)
+ new P._Future__propagateToListeners_handleError(_box_1, _box_0, listeners).call$0();
+ if (oldZone != null)
+ $.Zone__current = oldZone;
+ t1 = _box_0.listenerValueOrError;
+ if (t4._is(t1)) {
+ if (t1._state >= 4) {
+ H.assertHelper(t6._state < 4);
+ current = t3._check(t6._resultOrListeners);
+ t6._resultOrListeners = null;
+ listeners = t6._reverseListeners$1(current);
+ H.assertHelper(t6._state < 4);
+ H.assertHelper(t1._state >= 4);
+ t6._state = t1._state;
+ t6._resultOrListeners = t1._resultOrListeners;
+ _box_1.source = t1;
+ continue;
+ } else
+ P._Future__chainCoreFuture(t1, t6);
+ return;
+ }
+ }
+ result = listeners.result;
+ H.assertHelper(result._state < 4);
+ current = t3._check(result._resultOrListeners);
+ result._resultOrListeners = null;
+ listeners = result._reverseListeners$1(current);
+ t1 = _box_0.listenerHasError;
+ t5 = _box_0.listenerValueOrError;
+ t6 = result._state >= 4;
+ if (!t1) {
+ result.$ti._precomputed1._check(t5);
+ H.assertHelper(!t6);
+ result._state = 4;
+ result._resultOrListeners = t5;
+ } else {
+ t2._check(t5);
+ H.assertHelper(!t6);
+ result._state = 8;
+ result._resultOrListeners = t5;
+ }
+ _box_1.source = result;
+ t1 = result;
+ }
+ },
+ _registerErrorHandler: function(errorHandler, zone) {
+ if (type$.dynamic_Function_Object_StackTrace._is(errorHandler))
+ return zone.registerBinaryCallback$3$1(errorHandler, type$.dynamic, type$.Object, type$.StackTrace);
+ if (type$.dynamic_Function_Object._is(errorHandler))
+ return zone.registerUnaryCallback$2$1(errorHandler, type$.dynamic, type$.Object);
+ throw H.wrapException(P.ArgumentError$value(errorHandler, "onError", "Error handler must accept one Object or one Object and a StackTrace as arguments, and return a a valid result"));
+ },
+ _microtaskLoop: function() {
+ var t1, t2;
+ for (; t1 = $._nextCallback, t1 != null;) {
+ $._lastPriorityCallback = null;
+ t2 = t1.next;
+ $._nextCallback = t2;
+ if (t2 == null)
+ $._lastCallback = null;
+ t1.callback.call$0();
+ }
+ },
+ _startMicrotaskLoop: function() {
+ $._isInCallbackLoop = true;
+ try {
+ P._microtaskLoop();
+ } finally {
+ $._lastPriorityCallback = null;
+ $._isInCallbackLoop = false;
+ if ($._nextCallback != null)
+ $.$get$_AsyncRun__scheduleImmediateClosure().call$1(P.async___startMicrotaskLoop$closure());
+ }
+ },
+ _scheduleAsyncCallback: function(callback) {
+ var newEntry = new P._AsyncCallbackEntry(callback);
+ if ($._nextCallback == null) {
+ $._nextCallback = $._lastCallback = newEntry;
+ if (!$._isInCallbackLoop)
+ $.$get$_AsyncRun__scheduleImmediateClosure().call$1(P.async___startMicrotaskLoop$closure());
+ } else
+ $._lastCallback = $._lastCallback.next = newEntry;
+ },
+ _schedulePriorityAsyncCallback: function(callback) {
+ var entry, t2,
+ t1 = $._nextCallback;
+ if (t1 == null) {
+ P._scheduleAsyncCallback(callback);
+ $._lastPriorityCallback = $._lastCallback;
+ return;
+ }
+ entry = new P._AsyncCallbackEntry(callback);
+ t2 = $._lastPriorityCallback;
+ if (t2 == null) {
+ entry.next = t1;
+ $._nextCallback = $._lastPriorityCallback = entry;
+ } else {
+ entry.next = t2.next;
+ $._lastPriorityCallback = t2.next = entry;
+ if (entry.next == null)
+ $._lastCallback = entry;
+ }
+ },
+ scheduleMicrotask: function(callback) {
+ var t1, _null = null,
+ currentZone = $.Zone__current;
+ if (C.C__RootZone === currentZone) {
+ P._rootScheduleMicrotask(_null, _null, C.C__RootZone, callback);
+ return;
+ }
+ if (C.C__RootZone === currentZone.get$_scheduleMicrotask().zone)
+ t1 = C.C__RootZone.get$errorZone() === currentZone.get$errorZone();
+ else
+ t1 = false;
+ if (t1) {
+ P._rootScheduleMicrotask(_null, _null, currentZone, currentZone.registerCallback$1$1(callback, type$.void));
+ return;
+ }
+ t1 = $.Zone__current;
+ t1.scheduleMicrotask$1(t1.bindCallbackGuarded$1(callback));
+ },
+ Stream_Stream$fromFuture: function(future, $T) {
+ var _null = null,
+ t1 = $T._eval$1("_SyncStreamController<0>"),
+ controller = new P._SyncStreamController(_null, _null, _null, _null, t1);
+ future.then$1$2$onError(new P.Stream_Stream$fromFuture_closure(controller, $T), new P.Stream_Stream$fromFuture_closure0(controller), type$.Null);
+ return new P._ControllerStream(controller, t1._eval$1("_ControllerStream<1>"));
+ },
+ Stream_Stream$fromIterable: function(elements, $T) {
+ return new P._GeneratedStreamImpl(new P.Stream_Stream$fromIterable_closure(elements, $T), $T._eval$1("_GeneratedStreamImpl<0>"));
+ },
+ StreamIterator_StreamIterator: function(stream, $T) {
+ if (stream == null)
+ H.throwExpression(P.ArgumentError$notNull("stream"));
+ return new P._StreamIterator($T._eval$1("_StreamIterator<0>"));
+ },
+ StreamController_StreamController: function(onCancel, onListen, sync, $T) {
+ var _null = null;
+ return sync ? new P._SyncStreamController(onListen, _null, _null, onCancel, $T._eval$1("_SyncStreamController<0>")) : new P._AsyncStreamController(onListen, _null, _null, onCancel, $T._eval$1("_AsyncStreamController<0>"));
+ },
+ _runGuarded: function(notificationHandler) {
+ var e, s, exception;
+ if (notificationHandler == null)
+ return;
+ try {
+ notificationHandler.call$0();
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ $.Zone__current.handleUncaughtError$2(e, s);
+ }
+ },
+ _AddStreamState_makeErrorHandler: function(controller) {
+ return new P._AddStreamState_makeErrorHandler_closure(controller);
+ },
+ _BufferingStreamSubscription$: function(onData, onError, onDone, cancelOnError, $T) {
+ var t1 = $.Zone__current,
+ t2 = cancelOnError ? 1 : 0;
+ t2 = new P._BufferingStreamSubscription(t1, t2, $T._eval$1("_BufferingStreamSubscription<0>"));
+ t2._BufferingStreamSubscription$4(onData, onError, onDone, cancelOnError, $T);
+ return t2;
+ },
+ _nullDataHandler: function(value) {
+ },
+ _nullErrorHandler: function(error, stackTrace) {
+ type$.StackTrace._check(stackTrace);
+ $.Zone__current.handleUncaughtError$2(error, stackTrace);
+ },
+ _nullDoneHandler: function() {
+ },
+ _runUserCode: function(userCode, onSuccess, onError, $T) {
+ var e, s, replacement, error, stackTrace, exception, error0;
+ try {
+ onSuccess.call$1(userCode.call$0());
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ replacement = $.Zone__current.errorCallback$2(e, s);
+ if (replacement == null)
+ onError.call$2(e, s);
+ else {
+ error0 = replacement.error;
+ error = error0 == null ? new P.NullThrownError() : error0;
+ stackTrace = replacement.stackTrace;
+ onError.call$2(error, stackTrace);
+ }
+ }
+ },
+ _cancelAndError: function(subscription, future, error, stackTrace) {
+ var cancelFuture = subscription.cancel$0();
+ if (cancelFuture != null && cancelFuture !== $.$get$Future__nullFuture())
+ cancelFuture.whenComplete$1(new P._cancelAndError_closure(future, error, stackTrace));
+ else
+ future._completeError$2(error, stackTrace);
+ },
+ _cancelAndErrorClosure: function(subscription, future) {
+ return new P._cancelAndErrorClosure_closure(subscription, future);
+ },
+ _cancelAndValue: function(subscription, future, value) {
+ var cancelFuture = subscription.cancel$0();
+ if (cancelFuture != null && cancelFuture !== $.$get$Future__nullFuture())
+ cancelFuture.whenComplete$1(new P._cancelAndValue_closure(future, value));
+ else
+ future._complete$1(value);
+ },
+ Timer_Timer: function(duration, callback) {
+ var t1 = $.Zone__current;
+ if (t1 === C.C__RootZone)
+ return t1.createTimer$2(duration, callback);
+ return t1.createTimer$2(duration, t1.bindCallbackGuarded$1(callback));
+ },
+ _ZoneSpecification$: function(createPeriodicTimer, createTimer, errorCallback, fork, handleUncaughtError, $print, registerBinaryCallback, registerCallback, registerUnaryCallback, run, runBinary, runUnary, scheduleMicrotask) {
+ return new P._ZoneSpecification(handleUncaughtError, run, runUnary, runBinary, registerCallback, registerUnaryCallback, registerBinaryCallback, errorCallback, scheduleMicrotask, createTimer, createPeriodicTimer, $print, fork);
+ },
+ Zone__enter: function(zone) {
+ var previous;
+ H.assertHelper(zone != null);
+ H.assertHelper(zone !== $.Zone__current);
+ previous = $.Zone__current;
+ $.Zone__current = zone;
+ return previous;
+ },
+ _parentDelegate: function(zone) {
+ if (zone.get$parent(zone) == null)
+ return null;
+ return zone.get$parent(zone).get$_delegate();
+ },
+ _rootHandleUncaughtError: function($self, $parent, zone, error, stackTrace) {
+ var t1 = {};
+ t1.error = error;
+ P._schedulePriorityAsyncCallback(new P._rootHandleUncaughtError_closure(t1, type$.StackTrace._check(stackTrace)));
+ },
+ _rootRun: function($self, $parent, zone, f, $R) {
+ var old,
+ t1 = type$.Zone;
+ t1._check($self);
+ type$.ZoneDelegate._check($parent);
+ t1._check(zone);
+ $R._eval$1("0()")._check(f);
+ if ($.Zone__current === zone)
+ return f.call$0();
+ old = P.Zone__enter(zone);
+ try {
+ t1 = f.call$0();
+ return t1;
+ } finally {
+ t1 = old;
+ H.assertHelper(t1 != null);
+ $.Zone__current = t1;
+ }
+ },
+ _rootRunUnary: function($self, $parent, zone, f, arg, $R, $T) {
+ var old,
+ t1 = type$.Zone;
+ t1._check($self);
+ type$.ZoneDelegate._check($parent);
+ t1._check(zone);
+ $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(f);
+ $T._check(arg);
+ if ($.Zone__current === zone)
+ return f.call$1(arg);
+ old = P.Zone__enter(zone);
+ try {
+ t1 = f.call$1(arg);
+ return t1;
+ } finally {
+ t1 = old;
+ H.assertHelper(t1 != null);
+ $.Zone__current = t1;
+ }
+ },
+ _rootRunBinary: function($self, $parent, zone, f, arg1, arg2, $R, T1, T2) {
+ var old,
+ t1 = type$.Zone;
+ t1._check($self);
+ type$.ZoneDelegate._check($parent);
+ t1._check(zone);
+ $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._check(f);
+ T1._check(arg1);
+ T2._check(arg2);
+ if ($.Zone__current === zone)
+ return f.call$2(arg1, arg2);
+ old = P.Zone__enter(zone);
+ try {
+ t1 = f.call$2(arg1, arg2);
+ return t1;
+ } finally {
+ t1 = old;
+ H.assertHelper(t1 != null);
+ $.Zone__current = t1;
+ }
+ },
+ _rootRegisterCallback: function($self, $parent, zone, f, $R) {
+ return $R._eval$1("0()")._check(f);
+ },
+ _rootRegisterUnaryCallback: function($self, $parent, zone, f, $R, $T) {
+ return $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(f);
+ },
+ _rootRegisterBinaryCallback: function($self, $parent, zone, f, $R, T1, T2) {
+ return $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._check(f);
+ },
+ _rootErrorCallback: function($self, $parent, zone, error, stackTrace) {
+ type$.StackTrace._check(stackTrace);
+ return null;
+ },
+ _rootScheduleMicrotask: function($self, $parent, zone, f) {
+ var t1;
+ type$.void_Function._check(f);
+ t1 = C.C__RootZone !== zone;
+ if (t1)
+ f = !(!t1 || C.C__RootZone.get$errorZone() === zone.get$errorZone()) ? zone.bindCallbackGuarded$1(f) : zone.bindCallback$1$1(f, type$.void);
+ P._scheduleAsyncCallback(f);
+ },
+ _rootCreateTimer: function($self, $parent, zone, duration, callback) {
+ type$.Duration._check(duration);
+ callback = zone.bindCallback$1$1(type$.void_Function._check(callback), type$.void);
+ return P.Timer__createTimer(duration, callback);
+ },
+ _rootCreatePeriodicTimer: function($self, $parent, zone, duration, callback) {
+ var milliseconds;
+ type$.Duration._check(duration);
+ callback = zone.bindUnaryCallback$2$1(type$.void_Function_Timer._check(callback), type$.dynamic, type$.Timer);
+ milliseconds = C.JSInt_methods._tdivFast$1(duration._duration, 1000);
+ return P._TimerImpl$periodic(milliseconds < 0 ? 0 : milliseconds, callback);
+ },
+ _rootPrint: function($self, $parent, zone, line) {
+ H.printString(H._checkStringNullable(line));
+ },
+ _printToZone: function(line) {
+ $.Zone__current.print$1(0, line);
+ },
+ _rootFork: function($self, $parent, zone, specification, zoneValues) {
+ var valueMap, t1, t2;
+ type$.ZoneSpecification._check(specification);
+ type$.Map_dynamic_dynamic._check(zoneValues);
+ $.printToZone = P.async___printToZone$closure();
+ if (specification == null)
+ specification = C._ZoneSpecification_ALf;
+ if (zoneValues == null)
+ valueMap = zone.get$_async$_map();
+ else {
+ t1 = type$.dynamic;
+ valueMap = P.HashMap_HashMap$from(zoneValues, t1, t1);
+ }
+ t1 = new P._CustomZone(zone, valueMap);
+ t2 = zone.get$_run();
+ t1.set$_run(t2);
+ t2 = zone.get$_runUnary();
+ t1.set$_runUnary(t2);
+ t2 = zone.get$_runBinary();
+ t1.set$_runBinary(t2);
+ t2 = specification.registerCallback;
+ t1.set$_registerCallback(t2 != null ? new P._ZoneFunction(t1, t2, type$._ZoneFunction_Function) : zone.get$_registerCallback());
+ t2 = specification.registerUnaryCallback;
+ t1.set$_registerUnaryCallback(t2 != null ? new P._ZoneFunction(t1, t2, type$._ZoneFunction_Function) : zone.get$_registerUnaryCallback());
+ t2 = specification.registerBinaryCallback;
+ t1.set$_registerBinaryCallback(t2 != null ? new P._ZoneFunction(t1, t2, type$._ZoneFunction_Function) : zone.get$_registerBinaryCallback());
+ t2 = specification.errorCallback;
+ t1.set$_errorCallback(t2 != null ? new P._ZoneFunction(t1, t2, type$._ZoneFunction_of_AsyncError_Function_Zone_ZoneDelegate_Zone_Object_StackTrace) : zone.get$_errorCallback());
+ t2 = zone.get$_scheduleMicrotask();
+ t1.set$_scheduleMicrotask(t2);
+ t2 = zone.get$_createTimer();
+ t1.set$_createTimer(t2);
+ t2 = zone.get$_createPeriodicTimer();
+ t1.set$_createPeriodicTimer(t2);
+ t2 = specification.print;
+ t1.set$_print(t2 != null ? new P._ZoneFunction(t1, t2, type$._ZoneFunction_of_void_Function_Zone_ZoneDelegate_Zone_String) : zone.get$_print());
+ t2 = zone.get$_fork();
+ t1.set$_fork(t2);
+ t2 = specification.handleUncaughtError;
+ t1.set$_handleUncaughtError(t2 != null ? new P._ZoneFunction(t1, t2, type$._ZoneFunction_of_void_Function_Zone_ZoneDelegate_Zone_Object_StackTrace) : zone.get$_handleUncaughtError());
+ return t1;
+ },
+ runZoned: function(body, onError, zoneSpecification, zoneValues, $R) {
+ var e, stackTrace, errorHandler, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, exception, _null = null, t1 = {};
+ if (onError == null)
+ return P._runZoned(body, zoneValues, zoneSpecification, $R);
+ t1.binaryOnError = t1.unaryOnError = null;
+ if (type$.void_Function_Object_StackTrace._is(onError))
+ t1.binaryOnError = onError;
+ else if (type$.void_Function_Object._is(onError))
+ t1.unaryOnError = onError;
+ else
+ throw H.wrapException(P.ArgumentError$("onError callback must take either an Object (the error), or both an Object (the error) and a StackTrace."));
+ errorHandler = new P.runZoned_closure(t1);
+ if (zoneSpecification == null)
+ zoneSpecification = P._ZoneSpecification$(_null, _null, _null, _null, errorHandler, _null, _null, _null, _null, _null, _null, _null, _null);
+ else {
+ t2 = zoneSpecification;
+ t3 = t2.run;
+ t4 = t2.runUnary;
+ t5 = t2.runBinary;
+ t6 = t2.registerCallback;
+ t7 = t2.registerUnaryCallback;
+ t8 = t2.registerBinaryCallback;
+ t9 = t2.errorCallback;
+ t10 = t2.scheduleMicrotask;
+ t11 = t2.createTimer;
+ t12 = t2.createPeriodicTimer;
+ t13 = t2.print;
+ zoneSpecification = P._ZoneSpecification$(t12, t11, t9, t2.fork, errorHandler, t13, t8, t6, t7, t3, t5, t4, t10);
+ }
+ try {
+ t2 = P._runZoned(body, zoneValues, zoneSpecification, $R);
+ return t2;
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ stackTrace = H.getTraceFromException(exception);
+ t2 = t1.binaryOnError;
+ if (t2 != null)
+ t2.call$2(e, stackTrace);
+ else {
+ H.assertHelper(t1.unaryOnError != null);
+ t1.unaryOnError.call$1(e);
+ }
+ }
+ return _null;
+ },
+ _runZoned: function(body, zoneValues, specification, $R) {
+ return $.Zone__current.fork$2$specification$zoneValues(specification, zoneValues).run$1$1(body, $R);
+ },
+ _AsyncRun__initializeScheduleImmediate_internalCallback: function _AsyncRun__initializeScheduleImmediate_internalCallback(t0) {
+ this._box_0 = t0;
+ },
+ _AsyncRun__initializeScheduleImmediate_closure: function _AsyncRun__initializeScheduleImmediate_closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.div = t1;
+ this.span = t2;
+ },
+ _AsyncRun__scheduleImmediateJsOverride_internalCallback: function _AsyncRun__scheduleImmediateJsOverride_internalCallback(t0) {
+ this.callback = t0;
+ },
+ _AsyncRun__scheduleImmediateWithSetImmediate_internalCallback: function _AsyncRun__scheduleImmediateWithSetImmediate_internalCallback(t0) {
+ this.callback = t0;
+ },
+ _TimerImpl: function _TimerImpl(t0) {
+ this._once = t0;
+ this._handle = null;
+ this._tick = 0;
+ },
+ _TimerImpl_internalCallback: function _TimerImpl_internalCallback(t0, t1) {
+ this.$this = t0;
+ this.callback = t1;
+ },
+ _TimerImpl$periodic_closure: function _TimerImpl$periodic_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _.$this = t0;
+ _.milliseconds = t1;
+ _.start = t2;
+ _.callback = t3;
+ },
+ _AsyncAwaitCompleter: function _AsyncAwaitCompleter(t0, t1) {
+ this._future = t0;
+ this.isSync = false;
+ this.$ti = t1;
+ },
+ _awaitOnObject_closure: function _awaitOnObject_closure(t0) {
+ this.bodyFunction = t0;
+ },
+ _awaitOnObject_closure0: function _awaitOnObject_closure0(t0) {
+ this.bodyFunction = t0;
+ },
+ _wrapJsFunctionForAsync_closure: function _wrapJsFunctionForAsync_closure(t0) {
+ this.$protected = t0;
+ },
+ _BroadcastStream: function _BroadcastStream(t0, t1) {
+ this._controller = t0;
+ this.$ti = t1;
+ },
+ _BroadcastSubscription: function _BroadcastSubscription(t0, t1, t2, t3) {
+ var _ = this;
+ _._eventState = 0;
+ _._async$_previous = _._async$_next = null;
+ _._controller = t0;
+ _._onDone = _._onError = _._onData = null;
+ _._zone = t1;
+ _._state = t2;
+ _._pending = _._cancelFuture = null;
+ _.$ti = t3;
+ },
+ _BroadcastStreamController: function _BroadcastStreamController() {
+ },
+ _SyncBroadcastStreamController: function _SyncBroadcastStreamController(t0, t1, t2) {
+ var _ = this;
+ _.onListen = t0;
+ _.onCancel = t1;
+ _._state = 0;
+ _._doneFuture = _._addStreamState = _._lastSubscription = _._firstSubscription = null;
+ _.$ti = t2;
+ },
+ _SyncBroadcastStreamController__sendData_closure: function _SyncBroadcastStreamController__sendData_closure(t0, t1) {
+ this.$this = t0;
+ this.data = t1;
+ },
+ _SyncBroadcastStreamController__sendError_closure: function _SyncBroadcastStreamController__sendError_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.error = t1;
+ this.stackTrace = t2;
+ },
+ _SyncBroadcastStreamController__sendDone_closure: function _SyncBroadcastStreamController__sendDone_closure(t0) {
+ this.$this = t0;
+ },
+ _AsyncBroadcastStreamController: function _AsyncBroadcastStreamController(t0, t1, t2) {
+ var _ = this;
+ _.onListen = t0;
+ _.onCancel = t1;
+ _._state = 0;
+ _._doneFuture = _._addStreamState = _._lastSubscription = _._firstSubscription = null;
+ _.$ti = t2;
+ },
+ Future: function Future() {
+ },
+ Future_Future_closure: function Future_Future_closure(t0, t1) {
+ this.result = t0;
+ this.computation = t1;
+ },
+ Future_Future$microtask_closure: function Future_Future$microtask_closure(t0, t1) {
+ this.result = t0;
+ this.computation = t1;
+ },
+ Future_wait_handleError: function Future_wait_handleError(t0, t1, t2, t3) {
+ var _ = this;
+ _._box_0 = t0;
+ _.cleanUp = t1;
+ _.eagerError = t2;
+ _.result = t3;
+ },
+ Future_wait_closure: function Future_wait_closure(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _._box_0 = t0;
+ _.pos = t1;
+ _.result = t2;
+ _.cleanUp = t3;
+ _.eagerError = t4;
+ _.T = t5;
+ },
+ Future_forEach_closure: function Future_forEach_closure(t0, t1) {
+ this.iterator = t0;
+ this.action = t1;
+ },
+ Future_doWhile_closure: function Future_doWhile_closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.action = t1;
+ this.doneSignal = t2;
+ },
+ TimeoutException: function TimeoutException(t0, t1) {
+ this.message = t0;
+ this.duration = t1;
+ },
+ Completer: function Completer() {
+ },
+ _Completer: function _Completer() {
+ },
+ _AsyncCompleter: function _AsyncCompleter(t0, t1) {
+ this.future = t0;
+ this.$ti = t1;
+ },
+ _SyncCompleter: function _SyncCompleter(t0, t1) {
+ this.future = t0;
+ this.$ti = t1;
+ },
+ _FutureListener: function _FutureListener(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._nextListener = null;
+ _.result = t0;
+ _.state = t1;
+ _.callback = t2;
+ _.errorCallback = t3;
+ _.$ti = t4;
+ },
+ _Future: function _Future(t0, t1) {
+ var _ = this;
+ _._state = 0;
+ _._zone = t0;
+ _._resultOrListeners = null;
+ _.$ti = t1;
+ },
+ _Future__addListener_closure: function _Future__addListener_closure(t0, t1) {
+ this.$this = t0;
+ this.listener = t1;
+ },
+ _Future__prependListeners_closure: function _Future__prependListeners_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ _Future__chainForeignFuture_closure: function _Future__chainForeignFuture_closure(t0) {
+ this.target = t0;
+ },
+ _Future__chainForeignFuture_closure0: function _Future__chainForeignFuture_closure0(t0) {
+ this.target = t0;
+ },
+ _Future__chainForeignFuture_closure1: function _Future__chainForeignFuture_closure1(t0, t1, t2) {
+ this.target = t0;
+ this.e = t1;
+ this.s = t2;
+ },
+ _Future__asyncComplete_closure: function _Future__asyncComplete_closure(t0, t1) {
+ this.$this = t0;
+ this.value = t1;
+ },
+ _Future__chainFuture_closure: function _Future__chainFuture_closure(t0, t1) {
+ this.$this = t0;
+ this.value = t1;
+ },
+ _Future__asyncCompleteError_closure: function _Future__asyncCompleteError_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.error = t1;
+ this.stackTrace = t2;
+ },
+ _Future__propagateToListeners_handleWhenCompleteCallback: function _Future__propagateToListeners_handleWhenCompleteCallback(t0, t1, t2, t3) {
+ var _ = this;
+ _._box_1 = t0;
+ _._box_0 = t1;
+ _.listener = t2;
+ _.hasError = t3;
+ },
+ _Future__propagateToListeners_handleWhenCompleteCallback_closure: function _Future__propagateToListeners_handleWhenCompleteCallback_closure(t0) {
+ this.originalSource = t0;
+ },
+ _Future__propagateToListeners_handleValueCallback: function _Future__propagateToListeners_handleValueCallback(t0, t1, t2) {
+ this._box_0 = t0;
+ this.listener = t1;
+ this.sourceResult = t2;
+ },
+ _Future__propagateToListeners_handleError: function _Future__propagateToListeners_handleError(t0, t1, t2) {
+ this._box_1 = t0;
+ this._box_0 = t1;
+ this.listener = t2;
+ },
+ _AsyncCallbackEntry: function _AsyncCallbackEntry(t0) {
+ this.callback = t0;
+ this.next = null;
+ },
+ Stream: function Stream() {
+ },
+ Stream_Stream$fromFuture_closure: function Stream_Stream$fromFuture_closure(t0, t1) {
+ this.controller = t0;
+ this.T = t1;
+ },
+ Stream_Stream$fromFuture_closure0: function Stream_Stream$fromFuture_closure0(t0) {
+ this.controller = t0;
+ },
+ Stream_Stream$fromIterable_closure: function Stream_Stream$fromIterable_closure(t0, t1) {
+ this.elements = t0;
+ this.T = t1;
+ },
+ Stream_pipe_closure: function Stream_pipe_closure(t0) {
+ this.streamConsumer = t0;
+ },
+ Stream_length_closure: function Stream_length_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ Stream_length_closure0: function Stream_length_closure0(t0, t1) {
+ this._box_0 = t0;
+ this.future = t1;
+ },
+ Stream_first_closure: function Stream_first_closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.$this = t1;
+ this.future = t2;
+ },
+ Stream_first_closure0: function Stream_first_closure0(t0) {
+ this.future = t0;
+ },
+ Stream_last_closure: function Stream_last_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ Stream_last_closure0: function Stream_last_closure0(t0, t1) {
+ this._box_0 = t0;
+ this.future = t1;
+ },
+ Stream_firstWhere_closure: function Stream_firstWhere_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _._box_0 = t0;
+ _.$this = t1;
+ _.test = t2;
+ _.future = t3;
+ },
+ Stream_firstWhere__closure: function Stream_firstWhere__closure(t0, t1) {
+ this.test = t0;
+ this.value = t1;
+ },
+ Stream_firstWhere__closure0: function Stream_firstWhere__closure0(t0, t1, t2) {
+ this._box_0 = t0;
+ this.future = t1;
+ this.value = t2;
+ },
+ Stream_firstWhere_closure0: function Stream_firstWhere_closure0(t0, t1, t2) {
+ this.$this = t0;
+ this.orElse = t1;
+ this.future = t2;
+ },
+ StreamSubscription: function StreamSubscription() {
+ },
+ StreamTransformerBase: function StreamTransformerBase() {
+ },
+ _StreamController: function _StreamController() {
+ },
+ _StreamController__subscribe_closure: function _StreamController__subscribe_closure(t0) {
+ this.$this = t0;
+ },
+ _StreamController__recordCancel_complete: function _StreamController__recordCancel_complete(t0) {
+ this.$this = t0;
+ },
+ _SyncStreamControllerDispatch: function _SyncStreamControllerDispatch() {
+ },
+ _AsyncStreamControllerDispatch: function _AsyncStreamControllerDispatch() {
+ },
+ _AsyncStreamController: function _AsyncStreamController(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._varData = null;
+ _._state = 0;
+ _._doneFuture = null;
+ _.onListen = t0;
+ _.onPause = t1;
+ _.onResume = t2;
+ _.onCancel = t3;
+ _.$ti = t4;
+ },
+ _SyncStreamController: function _SyncStreamController(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._varData = null;
+ _._state = 0;
+ _._doneFuture = null;
+ _.onListen = t0;
+ _.onPause = t1;
+ _.onResume = t2;
+ _.onCancel = t3;
+ _.$ti = t4;
+ },
+ _ControllerStream: function _ControllerStream(t0, t1) {
+ this._controller = t0;
+ this.$ti = t1;
+ },
+ _ControllerSubscription: function _ControllerSubscription(t0, t1, t2, t3) {
+ var _ = this;
+ _._controller = t0;
+ _._onDone = _._onError = _._onData = null;
+ _._zone = t1;
+ _._state = t2;
+ _._pending = _._cancelFuture = null;
+ _.$ti = t3;
+ },
+ _StreamSinkWrapper: function _StreamSinkWrapper(t0, t1) {
+ this._async$_target = t0;
+ this.$ti = t1;
+ },
+ _AddStreamState: function _AddStreamState() {
+ },
+ _AddStreamState_makeErrorHandler_closure: function _AddStreamState_makeErrorHandler_closure(t0) {
+ this.controller = t0;
+ },
+ _AddStreamState_cancel_closure: function _AddStreamState_cancel_closure(t0) {
+ this.$this = t0;
+ },
+ _StreamControllerAddStreamState: function _StreamControllerAddStreamState(t0, t1, t2, t3) {
+ var _ = this;
+ _.varData = t0;
+ _.addStreamFuture = t1;
+ _.addSubscription = t2;
+ _.$ti = t3;
+ },
+ _BufferingStreamSubscription: function _BufferingStreamSubscription(t0, t1, t2) {
+ var _ = this;
+ _._onDone = _._onError = _._onData = null;
+ _._zone = t0;
+ _._state = t1;
+ _._pending = _._cancelFuture = null;
+ _.$ti = t2;
+ },
+ _BufferingStreamSubscription__sendError_sendError: function _BufferingStreamSubscription__sendError_sendError(t0, t1, t2) {
+ this.$this = t0;
+ this.error = t1;
+ this.stackTrace = t2;
+ },
+ _BufferingStreamSubscription__sendDone_sendDone: function _BufferingStreamSubscription__sendDone_sendDone(t0) {
+ this.$this = t0;
+ },
+ _StreamImpl: function _StreamImpl() {
+ },
+ _GeneratedStreamImpl: function _GeneratedStreamImpl(t0, t1) {
+ this._pending = t0;
+ this._isUsed = false;
+ this.$ti = t1;
+ },
+ _IterablePendingEvents: function _IterablePendingEvents(t0, t1) {
+ this._async$_iterator = t0;
+ this._state = 0;
+ this.$ti = t1;
+ },
+ _DelayedEvent: function _DelayedEvent() {
+ },
+ _DelayedData: function _DelayedData(t0, t1) {
+ this.value = t0;
+ this.next = null;
+ this.$ti = t1;
+ },
+ _DelayedError: function _DelayedError(t0, t1) {
+ this.error = t0;
+ this.stackTrace = t1;
+ this.next = null;
+ },
+ _DelayedDone: function _DelayedDone() {
+ },
+ _PendingEvents: function _PendingEvents() {
+ },
+ _PendingEvents_schedule_closure: function _PendingEvents_schedule_closure(t0, t1) {
+ this.$this = t0;
+ this.dispatch = t1;
+ },
+ _StreamImplEvents: function _StreamImplEvents(t0) {
+ var _ = this;
+ _.lastPendingEvent = _.firstPendingEvent = null;
+ _._state = 0;
+ _.$ti = t0;
+ },
+ _DoneStreamSubscription: function _DoneStreamSubscription(t0, t1, t2) {
+ var _ = this;
+ _._zone = t0;
+ _._state = 0;
+ _._onDone = t1;
+ _.$ti = t2;
+ },
+ _StreamIterator: function _StreamIterator(t0) {
+ this.$ti = t0;
+ },
+ _EmptyStream: function _EmptyStream(t0) {
+ this.$ti = t0;
+ },
+ _cancelAndError_closure: function _cancelAndError_closure(t0, t1, t2) {
+ this.future = t0;
+ this.error = t1;
+ this.stackTrace = t2;
+ },
+ _cancelAndErrorClosure_closure: function _cancelAndErrorClosure_closure(t0, t1) {
+ this.subscription = t0;
+ this.future = t1;
+ },
+ _cancelAndValue_closure: function _cancelAndValue_closure(t0, t1) {
+ this.future = t0;
+ this.value = t1;
+ },
+ Timer: function Timer() {
+ },
+ AsyncError: function AsyncError(t0, t1) {
+ this.error = t0;
+ this.stackTrace = t1;
+ },
+ _ZoneFunction: function _ZoneFunction(t0, t1, t2) {
+ this.zone = t0;
+ this.$function = t1;
+ this.$ti = t2;
+ },
+ ZoneSpecification: function ZoneSpecification() {
+ },
+ _ZoneSpecification: function _ZoneSpecification(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) {
+ var _ = this;
+ _.handleUncaughtError = t0;
+ _.run = t1;
+ _.runUnary = t2;
+ _.runBinary = t3;
+ _.registerCallback = t4;
+ _.registerUnaryCallback = t5;
+ _.registerBinaryCallback = t6;
+ _.errorCallback = t7;
+ _.scheduleMicrotask = t8;
+ _.createTimer = t9;
+ _.createPeriodicTimer = t10;
+ _.print = t11;
+ _.fork = t12;
+ },
+ ZoneDelegate: function ZoneDelegate() {
+ },
+ Zone: function Zone() {
+ },
+ _ZoneDelegate: function _ZoneDelegate(t0) {
+ this._delegationTarget = t0;
+ },
+ _Zone: function _Zone() {
+ },
+ _CustomZone: function _CustomZone(t0, t1) {
+ var _ = this;
+ _._delegateCache = _._handleUncaughtError = _._fork = _._print = _._createPeriodicTimer = _._createTimer = _._scheduleMicrotask = _._errorCallback = _._registerBinaryCallback = _._registerUnaryCallback = _._registerCallback = _._runBinary = _._runUnary = _._run = null;
+ _.parent = t0;
+ _._async$_map = t1;
+ },
+ _CustomZone_bindCallback_closure: function _CustomZone_bindCallback_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.registered = t1;
+ this.R = t2;
+ },
+ _CustomZone_bindUnaryCallback_closure: function _CustomZone_bindUnaryCallback_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _.$this = t0;
+ _.registered = t1;
+ _.T = t2;
+ _.R = t3;
+ },
+ _CustomZone_bindCallbackGuarded_closure: function _CustomZone_bindCallbackGuarded_closure(t0, t1) {
+ this.$this = t0;
+ this.registered = t1;
+ },
+ _CustomZone_bindUnaryCallbackGuarded_closure: function _CustomZone_bindUnaryCallbackGuarded_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.registered = t1;
+ this.T = t2;
+ },
+ _rootHandleUncaughtError_closure: function _rootHandleUncaughtError_closure(t0, t1) {
+ this._box_0 = t0;
+ this.stackTrace = t1;
+ },
+ _RootZone: function _RootZone() {
+ },
+ _RootZone_bindCallback_closure: function _RootZone_bindCallback_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.f = t1;
+ this.R = t2;
+ },
+ _RootZone_bindCallbackGuarded_closure: function _RootZone_bindCallbackGuarded_closure(t0, t1) {
+ this.$this = t0;
+ this.f = t1;
+ },
+ _RootZone_bindUnaryCallbackGuarded_closure: function _RootZone_bindUnaryCallbackGuarded_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.f = t1;
+ this.T = t2;
+ },
+ runZoned_closure: function runZoned_closure(t0) {
+ this._box_0 = t0;
+ },
+ HashMap_HashMap: function($K, $V) {
+ return new P._HashMap($K._eval$1("@<0>")._bind$1($V)._eval$1("_HashMap<1,2>"));
+ },
+ _HashMap__getTableEntry: function(table, key) {
+ var entry = table[key];
+ return entry === table ? null : entry;
+ },
+ _HashMap__setTableEntry: function(table, key, value) {
+ if (value == null)
+ table[key] = table;
+ else
+ table[key] = value;
+ },
+ _HashMap__newHashTable: function() {
+ var table = Object.create(null);
+ P._HashMap__setTableEntry(table, "<non-identifier-key>", table);
+ delete table["<non-identifier-key>"];
+ return table;
+ },
+ LinkedHashMap_LinkedHashMap: function($K, $V) {
+ return new H.JsLinkedHashMap($K._eval$1("@<0>")._bind$1($V)._eval$1("JsLinkedHashMap<1,2>"));
+ },
+ LinkedHashMap_LinkedHashMap$_literal: function(keyValuePairs, $K, $V) {
+ return $K._eval$1("@<0>")._bind$1($V)._eval$1("LinkedHashMap<1,2>")._check(H.fillLiteralMap(keyValuePairs, new H.JsLinkedHashMap($K._eval$1("@<0>")._bind$1($V)._eval$1("JsLinkedHashMap<1,2>"))));
+ },
+ LinkedHashMap_LinkedHashMap$_empty: function($K, $V) {
+ return new H.JsLinkedHashMap($K._eval$1("@<0>")._bind$1($V)._eval$1("JsLinkedHashMap<1,2>"));
+ },
+ LinkedHashSet_LinkedHashSet: function($E) {
+ return new P._LinkedHashSet($E._eval$1("_LinkedHashSet<0>"));
+ },
+ LinkedHashSet_LinkedHashSet$_empty: function($E) {
+ return new P._LinkedHashSet($E._eval$1("_LinkedHashSet<0>"));
+ },
+ LinkedHashSet_LinkedHashSet$_literal: function(values, $E) {
+ return $E._eval$1("LinkedHashSet<0>")._check(H.fillLiteralSet(values, new P._LinkedHashSet($E._eval$1("_LinkedHashSet<0>"))));
+ },
+ _LinkedHashSet__newHashTable: function() {
+ var table = Object.create(null);
+ H.assertHelper(table != null);
+ table["<non-identifier-key>"] = table;
+ delete table["<non-identifier-key>"];
+ return table;
+ },
+ _LinkedHashSetIterator$: function(_set, _modifications, $E) {
+ var t1 = new P._LinkedHashSetIterator(_set, _modifications, $E._eval$1("_LinkedHashSetIterator<0>"));
+ t1._collection$_cell = _set._collection$_first;
+ return t1;
+ },
+ HashMap_HashMap$from: function(other, $K, $V) {
+ var result = P.HashMap_HashMap($K, $V);
+ other.forEach$1(0, new P.HashMap_HashMap$from_closure(result, $K, $V));
+ return result;
+ },
+ IterableBase_iterableToShortString: function(iterable, leftDelimiter, rightDelimiter) {
+ var parts, t1;
+ if (P._isToStringVisiting(iterable)) {
+ if (leftDelimiter === "(" && rightDelimiter === ")")
+ return "(...)";
+ return leftDelimiter + "..." + rightDelimiter;
+ }
+ parts = H.setRuntimeTypeInfo([], type$.JSArray_String);
+ C.JSArray_methods.add$1($._toStringVisiting, iterable);
+ try {
+ P._iterablePartsToStrings(iterable, parts);
+ } finally {
+ H.assertHelper(C.JSArray_methods.get$last($._toStringVisiting) === iterable);
+ if (0 >= $._toStringVisiting.length)
+ return H.ioore($._toStringVisiting, -1);
+ $._toStringVisiting.pop();
+ }
+ t1 = P.StringBuffer__writeAll(leftDelimiter, type$.Iterable_dynamic._check(parts), ", ") + rightDelimiter;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ IterableBase_iterableToFullString: function(iterable, leftDelimiter, rightDelimiter) {
+ var buffer, t1;
+ if (P._isToStringVisiting(iterable))
+ return leftDelimiter + "..." + rightDelimiter;
+ buffer = new P.StringBuffer(leftDelimiter);
+ C.JSArray_methods.add$1($._toStringVisiting, iterable);
+ try {
+ t1 = buffer;
+ t1._contents = P.StringBuffer__writeAll(t1._contents, iterable, ", ");
+ } finally {
+ H.assertHelper(C.JSArray_methods.get$last($._toStringVisiting) === iterable);
+ if (0 >= $._toStringVisiting.length)
+ return H.ioore($._toStringVisiting, -1);
+ $._toStringVisiting.pop();
+ }
+ buffer._contents += rightDelimiter;
+ t1 = buffer._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ _isToStringVisiting: function(o) {
+ var t1, i;
+ for (t1 = $._toStringVisiting.length, i = 0; i < t1; ++i)
+ if (o === $._toStringVisiting[i])
+ return true;
+ return false;
+ },
+ _iterablePartsToStrings: function(iterable, parts) {
+ var next, ultimateString, penultimateString, penultimate, ultimate, ultimate0, elision,
+ it = iterable.get$iterator(iterable),
+ $length = 0, count = 0;
+ while (true) {
+ if (!($length < 80 || count < 3))
+ break;
+ if (!it.moveNext$0())
+ return;
+ next = H.S(it.get$current());
+ C.JSArray_methods.add$1(parts, next);
+ $length += next.length + 2;
+ ++count;
+ }
+ if (!it.moveNext$0()) {
+ if (count <= 5)
+ return;
+ if (0 >= parts.length)
+ return H.ioore(parts, -1);
+ ultimateString = parts.pop();
+ if (0 >= parts.length)
+ return H.ioore(parts, -1);
+ penultimateString = parts.pop();
+ } else {
+ penultimate = it.get$current();
+ ++count;
+ if (!it.moveNext$0()) {
+ if (count <= 4) {
+ C.JSArray_methods.add$1(parts, H.S(penultimate));
+ return;
+ }
+ ultimateString = H.S(penultimate);
+ if (0 >= parts.length)
+ return H.ioore(parts, -1);
+ penultimateString = parts.pop();
+ $length += ultimateString.length + 2;
+ } else {
+ ultimate = it.get$current();
+ ++count;
+ H.assertHelper(count < 100);
+ for (; it.moveNext$0(); penultimate = ultimate, ultimate = ultimate0) {
+ ultimate0 = it.get$current();
+ ++count;
+ if (count > 100) {
+ while (true) {
+ if (!($length > 75 && count > 3))
+ break;
+ if (0 >= parts.length)
+ return H.ioore(parts, -1);
+ $length -= parts.pop().length + 2;
+ --count;
+ }
+ C.JSArray_methods.add$1(parts, "...");
+ return;
+ }
+ }
+ penultimateString = H.S(penultimate);
+ ultimateString = H.S(ultimate);
+ $length += ultimateString.length + penultimateString.length + 4;
+ }
+ }
+ if (count > parts.length + 2) {
+ $length += 5;
+ elision = "...";
+ } else
+ elision = null;
+ while (true) {
+ if (!($length > 80 && parts.length > 3))
+ break;
+ if (0 >= parts.length)
+ return H.ioore(parts, -1);
+ $length -= parts.pop().length + 2;
+ if (elision == null) {
+ $length += 5;
+ elision = "...";
+ }
+ }
+ if (elision != null)
+ C.JSArray_methods.add$1(parts, elision);
+ C.JSArray_methods.add$1(parts, penultimateString);
+ C.JSArray_methods.add$1(parts, ultimateString);
+ },
+ LinkedHashMap_LinkedHashMap$from: function(other, $K, $V) {
+ var result = P.LinkedHashMap_LinkedHashMap($K, $V);
+ other.forEach$1(0, new P.LinkedHashMap_LinkedHashMap$from_closure(result, $K, $V));
+ return result;
+ },
+ LinkedHashSet_LinkedHashSet$from: function(elements, $E) {
+ var t1,
+ result = P.LinkedHashSet_LinkedHashSet($E);
+ for (t1 = J.get$iterator$ax(elements); t1.moveNext$0();)
+ result.add$1(0, $E._check(t1.get$current()));
+ return result;
+ },
+ MapBase_mapToString: function(m) {
+ var result, t1 = {};
+ if (P._isToStringVisiting(m))
+ return "{...}";
+ result = new P.StringBuffer("");
+ try {
+ C.JSArray_methods.add$1($._toStringVisiting, m);
+ result._contents += "{";
+ t1.first = true;
+ m.forEach$1(0, new P.MapBase_mapToString_closure(t1, result));
+ result._contents += "}";
+ } finally {
+ H.assertHelper(C.JSArray_methods.get$last($._toStringVisiting) === m);
+ if (0 >= $._toStringVisiting.length)
+ return H.ioore($._toStringVisiting, -1);
+ $._toStringVisiting.pop();
+ }
+ t1 = result._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ ListQueue$: function($E) {
+ var t1 = new P.ListQueue($E._eval$1("ListQueue<0>")),
+ t2 = new Array(8);
+ t2.fixed$length = Array;
+ t1.set$_table(H.setRuntimeTypeInfo(t2, $E._eval$1("JSArray<0>")));
+ return t1;
+ },
+ _ListQueueIterator$: function(queue, $E) {
+ return new P._ListQueueIterator(queue, queue._tail, queue._modificationCount, queue._head, $E._eval$1("_ListQueueIterator<0>"));
+ },
+ _HashMap: function _HashMap(t0) {
+ var _ = this;
+ _._collection$_length = 0;
+ _._keys = _._collection$_rest = _._nums = _._strings = null;
+ _.$ti = t0;
+ },
+ _IdentityHashMap: function _IdentityHashMap(t0) {
+ var _ = this;
+ _._collection$_length = 0;
+ _._keys = _._collection$_rest = _._nums = _._strings = null;
+ _.$ti = t0;
+ },
+ _HashMapKeyIterable: function _HashMapKeyIterable(t0, t1) {
+ this._map = t0;
+ this.$ti = t1;
+ },
+ _HashMapKeyIterator: function _HashMapKeyIterator(t0, t1, t2) {
+ var _ = this;
+ _._map = t0;
+ _._keys = t1;
+ _._offset = 0;
+ _._collection$_current = null;
+ _.$ti = t2;
+ },
+ _LinkedHashSet: function _LinkedHashSet(t0) {
+ var _ = this;
+ _._collection$_length = 0;
+ _._collection$_last = _._collection$_first = _._collection$_rest = _._nums = _._strings = null;
+ _._collection$_modifications = 0;
+ _.$ti = t0;
+ },
+ _LinkedHashSetCell: function _LinkedHashSetCell(t0) {
+ this._element = t0;
+ this._collection$_previous = this._collection$_next = null;
+ },
+ _LinkedHashSetIterator: function _LinkedHashSetIterator(t0, t1, t2) {
+ var _ = this;
+ _._set = t0;
+ _._collection$_modifications = t1;
+ _._collection$_current = _._collection$_cell = null;
+ _.$ti = t2;
+ },
+ UnmodifiableListView: function UnmodifiableListView(t0, t1) {
+ this._collection$_source = t0;
+ this.$ti = t1;
+ },
+ HashMap_HashMap$from_closure: function HashMap_HashMap$from_closure(t0, t1, t2) {
+ this.result = t0;
+ this.K = t1;
+ this.V = t2;
+ },
+ IterableBase: function IterableBase() {
+ },
+ LinkedHashMap_LinkedHashMap$from_closure: function LinkedHashMap_LinkedHashMap$from_closure(t0, t1, t2) {
+ this.result = t0;
+ this.K = t1;
+ this.V = t2;
+ },
+ ListBase: function ListBase() {
+ },
+ ListMixin: function ListMixin() {
+ },
+ MapBase: function MapBase() {
+ },
+ MapBase_mapToString_closure: function MapBase_mapToString_closure(t0, t1) {
+ this._box_0 = t0;
+ this.result = t1;
+ },
+ MapMixin: function MapMixin() {
+ },
+ _UnmodifiableMapMixin: function _UnmodifiableMapMixin() {
+ },
+ MapView: function MapView() {
+ },
+ UnmodifiableMapView: function UnmodifiableMapView(t0, t1) {
+ this._map = t0;
+ this.$ti = t1;
+ },
+ ListQueue: function ListQueue(t0) {
+ var _ = this;
+ _._table = null;
+ _._modificationCount = _._tail = _._head = 0;
+ _.$ti = t0;
+ },
+ _ListQueueIterator: function _ListQueueIterator(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._queue = t0;
+ _._end = t1;
+ _._modificationCount = t2;
+ _._position = t3;
+ _._collection$_current = null;
+ _.$ti = t4;
+ },
+ SetMixin: function SetMixin() {
+ },
+ SetBase: function SetBase() {
+ },
+ _SetBase: function _SetBase() {
+ },
+ _ListBase_Object_ListMixin: function _ListBase_Object_ListMixin() {
+ },
+ _SetBase_Object_SetMixin: function _SetBase_Object_SetMixin() {
+ },
+ _UnmodifiableMapView_MapView__UnmodifiableMapMixin: function _UnmodifiableMapView_MapView__UnmodifiableMapMixin() {
+ },
+ _parseJson: function(source, reviver) {
+ var parsed, e, exception, t1;
+ if (typeof source != "string")
+ throw H.wrapException(H.argumentErrorValue(source));
+ parsed = null;
+ try {
+ parsed = JSON.parse(source);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ t1 = P.FormatException$(String(e), null, null);
+ throw H.wrapException(t1);
+ }
+ t1 = P._convertJsonToDartLazy(parsed);
+ return t1;
+ },
+ _convertJsonToDartLazy: function(object) {
+ var i;
+ if (object == null)
+ return null;
+ if (typeof object != "object")
+ return object;
+ if (Object.getPrototypeOf(object) !== Array.prototype)
+ return new P._JsonMap(object, Object.create(null));
+ for (i = 0; i < object.length; ++i)
+ object[i] = P._convertJsonToDartLazy(object[i]);
+ return object;
+ },
+ Utf8Decoder__convertIntercepted: function(allowMalformed, codeUnits, start, end) {
+ if (codeUnits instanceof Uint8Array)
+ return P.Utf8Decoder__convertInterceptedUint8List(false, codeUnits, start, end);
+ return null;
+ },
+ Utf8Decoder__convertInterceptedUint8List: function(allowMalformed, codeUnits, start, end) {
+ var t1, $length,
+ decoder = $.$get$Utf8Decoder__decoder();
+ if (decoder == null)
+ return null;
+ t1 = 0 === start;
+ if (t1 && true)
+ return P.Utf8Decoder__useTextDecoderChecked(decoder, codeUnits);
+ $length = codeUnits.length;
+ end = P.RangeError_checkValidRange(start, end, $length);
+ if (t1 && end === $length)
+ return P.Utf8Decoder__useTextDecoderChecked(decoder, codeUnits);
+ return P.Utf8Decoder__useTextDecoderChecked(decoder, codeUnits.subarray(start, end));
+ },
+ Utf8Decoder__useTextDecoderChecked: function(decoder, codeUnits) {
+ if (P.Utf8Decoder__unsafe(codeUnits))
+ return null;
+ return P.Utf8Decoder__useTextDecoderUnchecked(decoder, codeUnits);
+ },
+ Utf8Decoder__useTextDecoderUnchecked: function(decoder, codeUnits) {
+ var t1, exception;
+ try {
+ t1 = decoder.decode(codeUnits);
+ return t1;
+ } catch (exception) {
+ H.unwrapException(exception);
+ }
+ return null;
+ },
+ Utf8Decoder__unsafe: function(codeUnits) {
+ var i,
+ limit = codeUnits.length - 2;
+ for (i = 0; i < limit; ++i)
+ if (codeUnits[i] === 237)
+ if ((codeUnits[i + 1] & 224) === 160)
+ return true;
+ return false;
+ },
+ Utf8Decoder__makeDecoder: function() {
+ var t1, exception;
+ try {
+ t1 = new TextDecoder("utf-8", {fatal: true});
+ return t1;
+ } catch (exception) {
+ H.unwrapException(exception);
+ }
+ return null;
+ },
+ _scanOneByteCharacters: function(units, from, endIndex) {
+ var t1, i, unit;
+ for (t1 = J.getInterceptor$asx(units), i = from; i < endIndex; ++i) {
+ unit = t1.$index(units, i);
+ if (typeof unit !== "number")
+ return unit.$and();
+ if ((unit & 127) !== unit)
+ return i - from;
+ }
+ return endIndex - from;
+ },
+ Base64Codec__checkPadding: function(source, sourceIndex, sourceEnd, firstPadding, paddingCount, $length) {
+ if (C.JSInt_methods.$mod($length, 4) !== 0)
+ throw H.wrapException(P.FormatException$("Invalid base64 padding, padded length must be multiple of four, is " + $length, source, sourceEnd));
+ if (firstPadding + paddingCount !== $length)
+ throw H.wrapException(P.FormatException$("Invalid base64 padding, '=' not at the end", source, sourceIndex));
+ if (paddingCount > 2)
+ throw H.wrapException(P.FormatException$("Invalid base64 padding, more than two '=' characters", source, sourceIndex));
+ },
+ _JsonMap: function _JsonMap(t0, t1) {
+ this._original = t0;
+ this._processed = t1;
+ this._data = null;
+ },
+ _JsonMapKeyIterable: function _JsonMapKeyIterable(t0) {
+ this._parent = t0;
+ },
+ AsciiCodec: function AsciiCodec() {
+ },
+ _UnicodeSubsetEncoder: function _UnicodeSubsetEncoder() {
+ },
+ AsciiEncoder: function AsciiEncoder(t0) {
+ this._subsetMask = t0;
+ },
+ Base64Codec: function Base64Codec() {
+ },
+ Base64Encoder: function Base64Encoder() {
+ },
+ Codec: function Codec() {
+ },
+ _FusedCodec: function _FusedCodec(t0, t1, t2) {
+ this._convert$_first = t0;
+ this._second = t1;
+ this.$ti = t2;
+ },
+ Converter: function Converter() {
+ },
+ Encoding: function Encoding() {
+ },
+ JsonCodec: function JsonCodec() {
+ },
+ JsonDecoder: function JsonDecoder(t0) {
+ this._reviver = t0;
+ },
+ Utf8Codec: function Utf8Codec() {
+ },
+ Utf8Encoder: function Utf8Encoder() {
+ },
+ _Utf8Encoder: function _Utf8Encoder(t0) {
+ this._bufferIndex = this._carry = 0;
+ this._buffer = t0;
+ },
+ Utf8Decoder: function Utf8Decoder(t0) {
+ this._allowMalformed = t0;
+ },
+ _Utf8Decoder: function _Utf8Decoder(t0, t1) {
+ var _ = this;
+ _._allowMalformed = t0;
+ _._stringSink = t1;
+ _._isFirstCharacter = true;
+ _._extraUnits = _._expectedUnits = _._convert$_value = 0;
+ },
+ int_parse: function(source, onError, radix) {
+ var value = H.Primitives_parseInt(source, radix);
+ if (value != null)
+ return value;
+ if (onError != null)
+ return onError.call$1(source);
+ throw H.wrapException(P.FormatException$(source, null, null));
+ },
+ Error__objectToString: function(object) {
+ if (object instanceof H.Closure)
+ return object.toString$0(0);
+ return "Instance of '" + H.S(H.Primitives_objectTypeName(object)) + "'";
+ },
+ List_List$filled: function($length, fill, $E) {
+ var i,
+ result = J.JSArray_JSArray$fixed($length, $E);
+ if ($length !== 0 && true)
+ for (i = 0; i < result.length; ++i)
+ C.JSArray_methods.$indexSet(result, i, fill);
+ return result;
+ },
+ List_List$from: function(elements, growable, $E) {
+ var t1,
+ list = H.setRuntimeTypeInfo([], $E._eval$1("JSArray<0>"));
+ for (t1 = J.get$iterator$ax(elements); t1.moveNext$0();)
+ C.JSArray_methods.add$1(list, $E._check(t1.get$current()));
+ if (growable)
+ return list;
+ return $E._eval$1("List<0>")._check(J.JSArray_markFixedList(list));
+ },
+ List_List$unmodifiable: function(elements, $E) {
+ var result = P.List_List$from(elements, false, $E);
+ result.fixed$length = Array;
+ result.immutable$list = Array;
+ return $E._eval$1("List<0>")._check(result);
+ },
+ String_String$fromCharCodes: function(charCodes, start, end) {
+ var len;
+ if (Array.isArray(charCodes)) {
+ type$.JSArray_int._check(charCodes);
+ len = charCodes.length;
+ end = P.RangeError_checkValidRange(start, end, len);
+ return H.Primitives_stringFromCharCodes(start > 0 || end < len ? C.JSArray_methods.sublist$2(charCodes, start, end) : charCodes);
+ }
+ if (type$.NativeUint8List._is(charCodes))
+ return H.Primitives_stringFromNativeUint8List(charCodes, start, P.RangeError_checkValidRange(start, end, charCodes.length));
+ return P.String__stringFromIterable(charCodes, start, end);
+ },
+ String_String$fromCharCode: function(charCode) {
+ return H.Primitives_stringFromCharCode(charCode);
+ },
+ String__stringFromIterable: function(charCodes, start, end) {
+ var t1, it, i, list, _null = null;
+ if (start < 0)
+ throw H.wrapException(P.RangeError$range(start, 0, J.get$length$asx(charCodes), _null, _null));
+ t1 = end == null;
+ if (!t1 && end < start)
+ throw H.wrapException(P.RangeError$range(end, start, J.get$length$asx(charCodes), _null, _null));
+ it = J.get$iterator$ax(charCodes);
+ for (i = 0; i < start; ++i)
+ if (!it.moveNext$0())
+ throw H.wrapException(P.RangeError$range(start, 0, i, _null, _null));
+ list = [];
+ if (t1)
+ for (; it.moveNext$0();)
+ list.push(it.get$current());
+ else
+ for (i = start; i < end; ++i) {
+ if (!it.moveNext$0())
+ throw H.wrapException(P.RangeError$range(end, start, i, _null, _null));
+ list.push(it.get$current());
+ }
+ return H.Primitives_stringFromCharCodes(list);
+ },
+ RegExp_RegExp: function(source, multiLine) {
+ return new H.JSSyntaxRegExp(source, H.JSSyntaxRegExp_makeNative(source, multiLine, true, false, false, false));
+ },
+ StringBuffer__writeAll: function(string, objects, separator) {
+ var iterator = J.get$iterator$ax(objects);
+ if (!iterator.moveNext$0())
+ return string;
+ if (separator.length === 0) {
+ do
+ string += H.S(iterator.get$current());
+ while (iterator.moveNext$0());
+ } else {
+ string += H.S(iterator.get$current());
+ for (; iterator.moveNext$0();)
+ string = string + separator + H.S(iterator.get$current());
+ }
+ return string;
+ },
+ Uri_base: function() {
+ var uri = H.Primitives_currentUri();
+ if (uri != null)
+ return P.Uri_parse(uri);
+ throw H.wrapException(P.UnsupportedError$("'Uri.base' is not supported"));
+ },
+ _Uri__uriEncode: function(canonicalTable, text, encoding, spaceToPlus) {
+ var t1, bytes, i, t2, byte, t3,
+ _s16_ = "0123456789ABCDEF";
+ if (encoding === C.C_Utf8Codec) {
+ t1 = $.$get$_Uri__needsNoEncoding()._nativeRegExp;
+ if (typeof text != "string")
+ H.throwExpression(H.argumentErrorValue(text));
+ t1 = t1.test(text);
+ } else
+ t1 = false;
+ if (t1)
+ return text;
+ H._instanceType(encoding)._eval$1("Codec.S")._check(text);
+ bytes = encoding.get$encoder().convert$1(text);
+ for (t1 = bytes.length, i = 0, t2 = ""; i < t1; ++i) {
+ byte = bytes[i];
+ if (byte < 128) {
+ t3 = byte >>> 4;
+ if (t3 >= 8)
+ return H.ioore(canonicalTable, t3);
+ t3 = (canonicalTable[t3] & 1 << (byte & 15)) !== 0;
+ } else
+ t3 = false;
+ if (t3)
+ t2 += H.Primitives_stringFromCharCode(byte);
+ else
+ t2 = spaceToPlus && byte === 32 ? t2 + "+" : t2 + "%" + _s16_[byte >>> 4 & 15] + _s16_[byte & 15];
+ }
+ return t2.charCodeAt(0) == 0 ? t2 : t2;
+ },
+ StackTrace_current: function() {
+ var stackTrace, exception;
+ if (H.boolConversionCheck($.$get$_hasErrorStackProperty()))
+ return H.getTraceFromException(new Error());
+ try {
+ throw H.wrapException("");
+ } catch (exception) {
+ H.unwrapException(exception);
+ stackTrace = H.getTraceFromException(exception);
+ return stackTrace;
+ }
+ },
+ DateTime__fourDigits: function(n) {
+ var absN = Math.abs(n),
+ sign = n < 0 ? "-" : "";
+ if (absN >= 1000)
+ return "" + n;
+ if (absN >= 100)
+ return sign + "0" + absN;
+ if (absN >= 10)
+ return sign + "00" + absN;
+ return sign + "000" + absN;
+ },
+ DateTime__threeDigits: function(n) {
+ if (n >= 100)
+ return "" + n;
+ if (n >= 10)
+ return "0" + n;
+ return "00" + n;
+ },
+ DateTime__twoDigits: function(n) {
+ if (n >= 10)
+ return "" + n;
+ return "0" + n;
+ },
+ Duration$: function(microseconds, minutes) {
+ if (typeof microseconds !== "number")
+ return H.iae(microseconds);
+ return new P.Duration(60000000 * minutes + microseconds);
+ },
+ Error_safeToString: function(object) {
+ if (typeof object == "number" || H._isBool(object) || null == object)
+ return J.toString$0$(object);
+ if (typeof object == "string")
+ return JSON.stringify(object);
+ return P.Error__objectToString(object);
+ },
+ AssertionError$: function(message) {
+ return new P.AssertionError(message);
+ },
+ ArgumentError$: function(message) {
+ return new P.ArgumentError(false, null, null, message);
+ },
+ ArgumentError$value: function(value, $name, message) {
+ return new P.ArgumentError(true, value, $name, message);
+ },
+ ArgumentError$notNull: function($name) {
+ return new P.ArgumentError(false, null, $name, "Must not be null");
+ },
+ RangeError$: function(message) {
+ var _null = null;
+ return new P.RangeError(_null, _null, false, _null, _null, message);
+ },
+ RangeError$value: function(value, $name) {
+ return new P.RangeError(null, null, true, value, $name, "Value not in range");
+ },
+ RangeError$range: function(invalidValue, minValue, maxValue, $name, message) {
+ return new P.RangeError(minValue, maxValue, true, invalidValue, $name, "Invalid value");
+ },
+ RangeError_checkValueInInterval: function(value, minValue, maxValue, $name) {
+ if (value < minValue || value > maxValue)
+ throw H.wrapException(P.RangeError$range(value, minValue, maxValue, $name, null));
+ },
+ RangeError_checkValidRange: function(start, end, $length) {
+ if (0 > start || start > $length)
+ throw H.wrapException(P.RangeError$range(start, 0, $length, "start", null));
+ if (end != null) {
+ if (start > end || end > $length)
+ throw H.wrapException(P.RangeError$range(end, start, $length, "end", null));
+ return end;
+ }
+ return $length;
+ },
+ RangeError_checkNotNegative: function(value, $name) {
+ if (typeof value !== "number")
+ return value.$lt();
+ if (value < 0)
+ throw H.wrapException(P.RangeError$range(value, 0, null, $name, null));
+ },
+ IndexError$: function(invalidValue, indexable, $name, message, $length) {
+ var t1 = H._checkIntNullable($length == null ? J.get$length$asx(indexable) : $length);
+ return new P.IndexError(t1, true, invalidValue, $name, "Index out of range");
+ },
+ UnsupportedError$: function(message) {
+ return new P.UnsupportedError(message);
+ },
+ UnimplementedError$: function(message) {
+ return new P.UnimplementedError(message);
+ },
+ StateError$: function(message) {
+ return new P.StateError(message);
+ },
+ ConcurrentModificationError$: function(modifiedObject) {
+ return new P.ConcurrentModificationError(modifiedObject);
+ },
+ FormatException$: function(message, source, offset) {
+ return new P.FormatException(message, source, offset);
+ },
+ List_List$generate: function($length, generator, growable, $E) {
+ var i,
+ result = H.setRuntimeTypeInfo([], $E._eval$1("JSArray<0>"));
+ C.JSArray_methods.set$length(result, $length);
+ for (i = 0; i < $length; ++i)
+ C.JSArray_methods.$indexSet(result, i, generator.call$1(i));
+ return result;
+ },
+ Map_castFrom: function(source, $K, $V, K2, V2) {
+ return new H.CastMap(source, $K._eval$1("@<0>")._bind$1($V)._bind$1(K2)._bind$1(V2)._eval$1("CastMap<1,2,3,4>"));
+ },
+ print: function(object) {
+ var line = H.S(object),
+ t1 = $.printToZone;
+ if (t1 == null)
+ H.printString(line);
+ else
+ t1.call$1(line);
+ },
+ _combineSurrogatePair: function(start, end) {
+ return 65536 + ((start & 1023) << 10) + (end & 1023);
+ },
+ Uri_parse: function(uri) {
+ var delta, t1, indices, schemeEnd, hostStart, portStart, pathStart, queryStart, fragmentStart, isSimple, scheme, t2, schemeAuth, queryStart0, pathStart0, _null = null,
+ end = uri.length;
+ if (end >= 5) {
+ delta = ((J._codeUnitAt$1$s(uri, 4) ^ 58) * 3 | C.JSString_methods._codeUnitAt$1(uri, 0) ^ 100 | C.JSString_methods._codeUnitAt$1(uri, 1) ^ 97 | C.JSString_methods._codeUnitAt$1(uri, 2) ^ 116 | C.JSString_methods._codeUnitAt$1(uri, 3) ^ 97) >>> 0;
+ if (delta === 0)
+ return P.UriData__parse(end < end ? C.JSString_methods.substring$2(uri, 0, end) : uri, 5, _null).get$uri();
+ else if (delta === 32)
+ return P.UriData__parse(C.JSString_methods.substring$2(uri, 5, end), 0, _null).get$uri();
+ }
+ t1 = new Array(8);
+ t1.fixed$length = Array;
+ indices = H.setRuntimeTypeInfo(t1, type$.JSArray_int);
+ C.JSArray_methods.$indexSet(indices, 0, 0);
+ C.JSArray_methods.$indexSet(indices, 1, -1);
+ C.JSArray_methods.$indexSet(indices, 2, -1);
+ C.JSArray_methods.$indexSet(indices, 7, -1);
+ C.JSArray_methods.$indexSet(indices, 3, 0);
+ C.JSArray_methods.$indexSet(indices, 4, 0);
+ C.JSArray_methods.$indexSet(indices, 5, end);
+ C.JSArray_methods.$indexSet(indices, 6, end);
+ if (P._scan(uri, 0, end, 0, indices) >= 14)
+ C.JSArray_methods.$indexSet(indices, 7, end);
+ schemeEnd = indices[1];
+ if (typeof schemeEnd !== "number")
+ return schemeEnd.$ge();
+ if (schemeEnd >= 0)
+ if (P._scan(uri, 0, schemeEnd, 20, indices) === 20)
+ indices[7] = schemeEnd;
+ t1 = indices[2];
+ if (typeof t1 !== "number")
+ return t1.$add();
+ hostStart = t1 + 1;
+ portStart = indices[3];
+ pathStart = indices[4];
+ queryStart = indices[5];
+ fragmentStart = indices[6];
+ if (typeof fragmentStart !== "number")
+ return fragmentStart.$lt();
+ if (typeof queryStart !== "number")
+ return H.iae(queryStart);
+ if (fragmentStart < queryStart)
+ queryStart = fragmentStart;
+ if (typeof pathStart !== "number")
+ return pathStart.$lt();
+ if (pathStart < hostStart)
+ pathStart = queryStart;
+ else if (pathStart <= schemeEnd)
+ pathStart = schemeEnd + 1;
+ if (typeof portStart !== "number")
+ return portStart.$lt();
+ if (portStart < hostStart)
+ portStart = pathStart;
+ H.assertHelper(hostStart === 0 || schemeEnd <= hostStart);
+ H.assertHelper(hostStart <= portStart);
+ H.assertHelper(schemeEnd <= pathStart);
+ H.assertHelper(portStart <= pathStart);
+ H.assertHelper(pathStart <= queryStart);
+ H.assertHelper(queryStart <= fragmentStart);
+ t1 = indices[7];
+ if (typeof t1 !== "number")
+ return t1.$lt();
+ isSimple = t1 < 0;
+ if (isSimple)
+ if (hostStart > schemeEnd + 3) {
+ scheme = _null;
+ isSimple = false;
+ } else {
+ t1 = portStart > 0;
+ if (t1 && portStart + 1 === pathStart) {
+ scheme = _null;
+ isSimple = false;
+ } else {
+ if (!(queryStart < end && queryStart === pathStart + 2 && J.startsWith$2$s(uri, "..", pathStart)))
+ t2 = queryStart > pathStart + 2 && J.startsWith$2$s(uri, "/..", queryStart - 3);
+ else
+ t2 = true;
+ if (t2) {
+ scheme = _null;
+ isSimple = false;
+ } else {
+ if (schemeEnd === 4)
+ if (J.startsWith$2$s(uri, "file", 0)) {
+ if (hostStart <= 0) {
+ if (!C.JSString_methods.startsWith$2(uri, "/", pathStart)) {
+ schemeAuth = "file:///";
+ delta = 3;
+ } else {
+ schemeAuth = "file://";
+ delta = 2;
+ }
+ uri = schemeAuth + C.JSString_methods.substring$2(uri, pathStart, end);
+ schemeEnd -= 0;
+ t1 = delta - 0;
+ queryStart += t1;
+ fragmentStart += t1;
+ end = uri.length;
+ hostStart = 7;
+ portStart = 7;
+ pathStart = 7;
+ } else if (pathStart === queryStart) {
+ queryStart0 = queryStart + 1;
+ ++fragmentStart;
+ uri = C.JSString_methods.replaceRange$3(uri, pathStart, queryStart, "/");
+ ++end;
+ queryStart = queryStart0;
+ }
+ scheme = "file";
+ } else if (C.JSString_methods.startsWith$2(uri, "http", 0)) {
+ if (t1 && portStart + 3 === pathStart && C.JSString_methods.startsWith$2(uri, "80", portStart + 1)) {
+ pathStart0 = pathStart - 3;
+ queryStart -= 3;
+ fragmentStart -= 3;
+ uri = C.JSString_methods.replaceRange$3(uri, portStart, pathStart, "");
+ end -= 3;
+ pathStart = pathStart0;
+ }
+ scheme = "http";
+ } else
+ scheme = _null;
+ else if (schemeEnd === 5 && J.startsWith$2$s(uri, "https", 0)) {
+ if (t1 && portStart + 4 === pathStart && J.startsWith$2$s(uri, "443", portStart + 1)) {
+ pathStart0 = pathStart - 4;
+ queryStart -= 4;
+ fragmentStart -= 4;
+ uri = J.replaceRange$3$asx(uri, portStart, pathStart, "");
+ end -= 3;
+ pathStart = pathStart0;
+ }
+ scheme = "https";
+ } else
+ scheme = _null;
+ isSimple = true;
+ }
+ }
+ }
+ else
+ scheme = _null;
+ if (isSimple) {
+ t1 = uri.length;
+ if (end < t1) {
+ uri = J.substring$2$s(uri, 0, end);
+ schemeEnd -= 0;
+ hostStart -= 0;
+ portStart -= 0;
+ pathStart -= 0;
+ queryStart -= 0;
+ fragmentStart -= 0;
+ }
+ return new P._SimpleUri(uri, schemeEnd, hostStart, portStart, pathStart, queryStart, fragmentStart, scheme);
+ }
+ return P._Uri__Uri$notSimple(uri, 0, end, schemeEnd, hostStart, portStart, pathStart, queryStart, fragmentStart, scheme);
+ },
+ Uri_decodeComponent: function(encodedComponent) {
+ H._checkStringNullable(encodedComponent);
+ return P._Uri__uriDecode(encodedComponent, 0, encodedComponent.length, C.C_Utf8Codec, false);
+ },
+ Uri__parseIPv4Address: function(host, start, end) {
+ var t1, i, partStart, partIndex, char, part, partIndex0, _null = null,
+ _s43_ = "IPv4 address should contain exactly 4 parts",
+ _s37_ = "each part must be in the range 0..255",
+ error = new P.Uri__parseIPv4Address_error(host),
+ result = new Uint8Array(4);
+ for (t1 = result.length, i = start, partStart = i, partIndex = 0; i < end; ++i) {
+ char = C.JSString_methods.codeUnitAt$1(host, i);
+ if (char !== 46) {
+ if ((char ^ 48) > 9)
+ error.call$2("invalid character", i);
+ } else {
+ if (partIndex === 3)
+ error.call$2(_s43_, i);
+ part = P.int_parse(C.JSString_methods.substring$2(host, partStart, i), _null, _null);
+ if (typeof part !== "number")
+ return part.$gt();
+ if (part > 255)
+ error.call$2(_s37_, partStart);
+ partIndex0 = partIndex + 1;
+ if (partIndex >= t1)
+ return H.ioore(result, partIndex);
+ result[partIndex] = part;
+ partStart = i + 1;
+ partIndex = partIndex0;
+ }
+ }
+ if (partIndex !== 3)
+ error.call$2(_s43_, end);
+ part = P.int_parse(C.JSString_methods.substring$2(host, partStart, end), _null, _null);
+ if (typeof part !== "number")
+ return part.$gt();
+ if (part > 255)
+ error.call$2(_s37_, partStart);
+ if (partIndex >= t1)
+ return H.ioore(result, partIndex);
+ result[partIndex] = part;
+ return result;
+ },
+ Uri_parseIPv6Address: function(host, start, end) {
+ var parts, i, partStart, wildcardSeen, seenDot, char, atEnd, t1, last, bytes, t2, wildCardLength, index, value, j, t3,
+ error = new P.Uri_parseIPv6Address_error(host),
+ parseHex = new P.Uri_parseIPv6Address_parseHex(error, host);
+ if (host.length < 2)
+ error.call$1("address is too short");
+ parts = H.setRuntimeTypeInfo([], type$.JSArray_int);
+ for (i = start, partStart = i, wildcardSeen = false, seenDot = false; i < end; ++i) {
+ char = C.JSString_methods.codeUnitAt$1(host, i);
+ if (char === 58) {
+ if (i === start) {
+ ++i;
+ if (C.JSString_methods.codeUnitAt$1(host, i) !== 58)
+ error.call$2("invalid start colon.", i);
+ partStart = i;
+ }
+ if (i === partStart) {
+ if (wildcardSeen)
+ error.call$2("only one wildcard `::` is allowed", i);
+ C.JSArray_methods.add$1(parts, -1);
+ wildcardSeen = true;
+ } else
+ C.JSArray_methods.add$1(parts, parseHex.call$2(partStart, i));
+ partStart = i + 1;
+ } else if (char === 46)
+ seenDot = true;
+ }
+ if (parts.length === 0)
+ error.call$1("too few parts");
+ atEnd = partStart === end;
+ t1 = C.JSArray_methods.get$last(parts);
+ if (atEnd && t1 !== -1)
+ error.call$2("expected a part after last `:`", end);
+ if (!atEnd)
+ if (!seenDot)
+ C.JSArray_methods.add$1(parts, parseHex.call$2(partStart, end));
+ else {
+ last = P.Uri__parseIPv4Address(host, partStart, end);
+ C.JSArray_methods.add$1(parts, (last[0] << 8 | last[1]) >>> 0);
+ C.JSArray_methods.add$1(parts, (last[2] << 8 | last[3]) >>> 0);
+ }
+ if (wildcardSeen) {
+ if (parts.length > 7)
+ error.call$1("an address with a wildcard must have less than 7 parts");
+ } else if (parts.length !== 8)
+ error.call$1("an address without a wildcard must contain exactly 8 parts");
+ bytes = new Uint8Array(16);
+ for (t1 = parts.length, t2 = bytes.length, wildCardLength = 9 - t1, i = 0, index = 0; i < t1; ++i) {
+ value = parts[i];
+ if (value === -1)
+ for (j = 0; j < wildCardLength; ++j) {
+ if (index < 0 || index >= t2)
+ return H.ioore(bytes, index);
+ bytes[index] = 0;
+ t3 = index + 1;
+ if (t3 >= t2)
+ return H.ioore(bytes, t3);
+ bytes[t3] = 0;
+ index += 2;
+ }
+ else {
+ t3 = C.JSInt_methods._shrOtherPositive$1(value, 8);
+ if (index < 0 || index >= t2)
+ return H.ioore(bytes, index);
+ bytes[index] = t3;
+ t3 = index + 1;
+ if (t3 >= t2)
+ return H.ioore(bytes, t3);
+ bytes[t3] = value & 255;
+ index += 2;
+ }
+ }
+ return bytes;
+ },
+ _Uri__Uri$notSimple: function(uri, start, end, schemeEnd, hostStart, portStart, pathStart, queryStart, fragmentStart, scheme) {
+ var userInfoStart, userInfo, host, t1, port, path, query, _null = null;
+ if (scheme == null)
+ if (schemeEnd > start)
+ scheme = P._Uri__makeScheme(uri, start, schemeEnd);
+ else {
+ if (schemeEnd === start)
+ P._Uri__fail(uri, start, "Invalid empty scheme");
+ scheme = "";
+ }
+ if (hostStart > start) {
+ userInfoStart = schemeEnd + 3;
+ userInfo = userInfoStart < hostStart ? P._Uri__makeUserInfo(uri, userInfoStart, hostStart - 1) : "";
+ host = P._Uri__makeHost(uri, hostStart, portStart, false);
+ t1 = portStart + 1;
+ port = t1 < pathStart ? P._Uri__makePort(P.int_parse(J.substring$2$s(uri, t1, pathStart), new P._Uri__Uri$notSimple_closure(uri, portStart), _null), scheme) : _null;
+ } else {
+ port = _null;
+ host = port;
+ userInfo = "";
+ }
+ path = P._Uri__makePath(uri, pathStart, queryStart, _null, scheme, host != null);
+ query = queryStart < fragmentStart ? P._Uri__makeQuery(uri, queryStart + 1, fragmentStart, _null) : _null;
+ return new P._Uri(scheme, userInfo, host, port, path, query, fragmentStart < end ? P._Uri__makeFragment(uri, fragmentStart + 1, end) : _null);
+ },
+ _Uri__Uri: function(host, path, pathSegments, scheme) {
+ var userInfo, query, fragment, port, isFile, t1, hasAuthority, t2, _null = null;
+ scheme = P._Uri__makeScheme(scheme, 0, scheme == null ? 0 : scheme.length);
+ userInfo = P._Uri__makeUserInfo(_null, 0, 0);
+ host = P._Uri__makeHost(host, 0, host == null ? 0 : host.length, false);
+ query = P._Uri__makeQuery(_null, 0, 0, _null);
+ fragment = P._Uri__makeFragment(_null, 0, 0);
+ port = P._Uri__makePort(_null, scheme);
+ isFile = scheme === "file";
+ if (host == null)
+ t1 = userInfo.length !== 0 || port != null || isFile;
+ else
+ t1 = false;
+ if (t1)
+ host = "";
+ t1 = host == null;
+ hasAuthority = !t1;
+ path = P._Uri__makePath(path, 0, path == null ? 0 : path.length, pathSegments, scheme, hasAuthority);
+ t2 = scheme.length === 0;
+ if (t2 && t1 && !C.JSString_methods.startsWith$1(path, "/"))
+ path = P._Uri__normalizeRelativePath(path, !t2 || hasAuthority);
+ else
+ path = P._Uri__removeDotSegments(path);
+ return new P._Uri(scheme, userInfo, t1 && C.JSString_methods.startsWith$1(path, "//") ? "" : host, port, path, query, fragment);
+ },
+ _Uri__defaultPort: function(scheme) {
+ if (scheme === "http")
+ return 80;
+ if (scheme === "https")
+ return 443;
+ return 0;
+ },
+ _Uri__fail: function(uri, index, message) {
+ throw H.wrapException(P.FormatException$(message, uri, index));
+ },
+ _Uri__Uri$file: function(path, windows) {
+ return windows ? P._Uri__makeWindowsFileUrl(path, false) : P._Uri__makeFileUri(path, false);
+ },
+ _Uri__checkNonWindowsPathReservedCharacters: function(segments, argumentError) {
+ C.JSArray_methods.forEach$1(segments, new P._Uri__checkNonWindowsPathReservedCharacters_closure(false));
+ },
+ _Uri__checkWindowsPathReservedCharacters: function(segments, argumentError, firstSegment) {
+ var t1, t2;
+ for (t1 = H.SubListIterable$(segments, firstSegment, null, H._arrayInstanceType(segments)._precomputed1), t1 = new H.ListIterator(t1, t1.get$length(t1), t1.$ti._eval$1("ListIterator<ListIterable.E>")); t1.moveNext$0();) {
+ t2 = t1.__internal$_current;
+ if (J.contains$1$asx(t2, P.RegExp_RegExp('["*/:<>?\\\\|]', false)))
+ if (argumentError)
+ throw H.wrapException(P.ArgumentError$("Illegal character in path"));
+ else
+ throw H.wrapException(P.UnsupportedError$("Illegal character in path: " + t2));
+ }
+ },
+ _Uri__checkWindowsDriveLetter: function(charCode, argumentError) {
+ var t1,
+ _s21_ = "Illegal drive letter ";
+ if (!(65 <= charCode && charCode <= 90))
+ t1 = 97 <= charCode && charCode <= 122;
+ else
+ t1 = true;
+ if (t1)
+ return;
+ if (argumentError)
+ throw H.wrapException(P.ArgumentError$(_s21_ + P.String_String$fromCharCode(charCode)));
+ else
+ throw H.wrapException(P.UnsupportedError$(_s21_ + P.String_String$fromCharCode(charCode)));
+ },
+ _Uri__makeFileUri: function(path, slashTerminated) {
+ var _null = null,
+ segments = H.setRuntimeTypeInfo(path.split("/"), type$.JSArray_String);
+ if (C.JSString_methods.startsWith$1(path, "/"))
+ return P._Uri__Uri(_null, _null, segments, "file");
+ else
+ return P._Uri__Uri(_null, _null, segments, _null);
+ },
+ _Uri__makeWindowsFileUrl: function(path, slashTerminated) {
+ var t1, pathSegments, pathStart, hostPart, _s1_ = "\\", _null = null, _s4_ = "file";
+ if (C.JSString_methods.startsWith$1(path, "\\\\?\\"))
+ if (C.JSString_methods.startsWith$2(path, "UNC\\", 4))
+ path = C.JSString_methods.replaceRange$3(path, 0, 7, _s1_);
+ else {
+ path = C.JSString_methods.substring$1(path, 4);
+ if (path.length < 3 || C.JSString_methods._codeUnitAt$1(path, 1) !== 58 || C.JSString_methods._codeUnitAt$1(path, 2) !== 92)
+ throw H.wrapException(P.ArgumentError$("Windows paths with \\\\?\\ prefix must be absolute"));
+ }
+ else
+ path = H.stringReplaceAllUnchecked(path, "/", _s1_);
+ t1 = path.length;
+ if (t1 > 1 && C.JSString_methods._codeUnitAt$1(path, 1) === 58) {
+ P._Uri__checkWindowsDriveLetter(C.JSString_methods._codeUnitAt$1(path, 0), true);
+ if (t1 === 2 || C.JSString_methods._codeUnitAt$1(path, 2) !== 92)
+ throw H.wrapException(P.ArgumentError$("Windows paths with drive letter must be absolute"));
+ pathSegments = H.setRuntimeTypeInfo(path.split(_s1_), type$.JSArray_String);
+ P._Uri__checkWindowsPathReservedCharacters(pathSegments, true, 1);
+ return P._Uri__Uri(_null, _null, pathSegments, _s4_);
+ }
+ if (C.JSString_methods.startsWith$1(path, _s1_))
+ if (C.JSString_methods.startsWith$2(path, _s1_, 1)) {
+ pathStart = C.JSString_methods.indexOf$2(path, _s1_, 2);
+ t1 = pathStart < 0;
+ hostPart = t1 ? C.JSString_methods.substring$1(path, 2) : C.JSString_methods.substring$2(path, 2, pathStart);
+ pathSegments = H.setRuntimeTypeInfo((t1 ? "" : C.JSString_methods.substring$1(path, pathStart + 1)).split(_s1_), type$.JSArray_String);
+ P._Uri__checkWindowsPathReservedCharacters(pathSegments, true, 0);
+ return P._Uri__Uri(hostPart, _null, pathSegments, _s4_);
+ } else {
+ pathSegments = H.setRuntimeTypeInfo(path.split(_s1_), type$.JSArray_String);
+ P._Uri__checkWindowsPathReservedCharacters(pathSegments, true, 0);
+ return P._Uri__Uri(_null, _null, pathSegments, _s4_);
+ }
+ else {
+ pathSegments = H.setRuntimeTypeInfo(path.split(_s1_), type$.JSArray_String);
+ P._Uri__checkWindowsPathReservedCharacters(pathSegments, true, 0);
+ return P._Uri__Uri(_null, _null, pathSegments, _null);
+ }
+ },
+ _Uri__makePort: function(port, scheme) {
+ if (port != null && port === P._Uri__defaultPort(scheme))
+ return null;
+ return port;
+ },
+ _Uri__makeHost: function(host, start, end, strictIPv6) {
+ var t1, t2, index, zoneIDstart, zoneID, i;
+ if (host == null)
+ return null;
+ if (start === end)
+ return "";
+ if (C.JSString_methods.codeUnitAt$1(host, start) === 91) {
+ t1 = end - 1;
+ if (C.JSString_methods.codeUnitAt$1(host, t1) !== 93)
+ P._Uri__fail(host, start, "Missing end `]` to match `[` in host");
+ t2 = start + 1;
+ index = P._Uri__checkZoneID(host, t2, t1);
+ if (index < t1) {
+ zoneIDstart = index + 1;
+ zoneID = P._Uri__normalizeZoneID(host, C.JSString_methods.startsWith$2(host, "25", zoneIDstart) ? index + 3 : zoneIDstart, t1, "%25");
+ } else
+ zoneID = "";
+ P.Uri_parseIPv6Address(host, t2, index);
+ return C.JSString_methods.substring$2(host, start, index).toLowerCase() + zoneID + "]";
+ }
+ for (i = start; i < end; ++i)
+ if (C.JSString_methods.codeUnitAt$1(host, i) === 58) {
+ index = C.JSString_methods.indexOf$2(host, "%", start);
+ index = index >= start && index < end ? index : end;
+ if (index < end) {
+ zoneIDstart = index + 1;
+ zoneID = P._Uri__normalizeZoneID(host, C.JSString_methods.startsWith$2(host, "25", zoneIDstart) ? index + 3 : zoneIDstart, end, "%25");
+ } else
+ zoneID = "";
+ P.Uri_parseIPv6Address(host, start, index);
+ return "[" + C.JSString_methods.substring$2(host, start, index) + zoneID + "]";
+ }
+ return P._Uri__normalizeRegName(host, start, end);
+ },
+ _Uri__checkZoneID: function(host, start, end) {
+ var index = C.JSString_methods.indexOf$2(host, "%", start);
+ return index >= start && index < end ? index : end;
+ },
+ _Uri__normalizeZoneID: function(host, start, end, prefix) {
+ var index, sectionStart, isNormalized, char, replacement, t1, t2, tail, sourceLength,
+ buffer = prefix !== "" ? new P.StringBuffer(prefix) : null;
+ for (index = start, sectionStart = index, isNormalized = true; index < end;) {
+ char = C.JSString_methods.codeUnitAt$1(host, index);
+ if (char === 37) {
+ replacement = P._Uri__normalizeEscape(host, index, true);
+ t1 = replacement == null;
+ if (t1 && isNormalized) {
+ index += 3;
+ continue;
+ }
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ t2 = buffer._contents += C.JSString_methods.substring$2(host, sectionStart, index);
+ if (t1)
+ replacement = C.JSString_methods.substring$2(host, index, index + 3);
+ else if (replacement === "%")
+ P._Uri__fail(host, index, "ZoneID should not contain % anymore");
+ buffer._contents = t2 + replacement;
+ index += 3;
+ sectionStart = index;
+ isNormalized = true;
+ } else {
+ if (char < 127) {
+ t1 = char >>> 4;
+ if (t1 >= 8)
+ return H.ioore(C.List_nxB, t1);
+ t1 = (C.List_nxB[t1] & 1 << (char & 15)) !== 0;
+ } else
+ t1 = false;
+ if (t1) {
+ if (isNormalized && 65 <= char && 90 >= char) {
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ if (sectionStart < index) {
+ buffer._contents += C.JSString_methods.substring$2(host, sectionStart, index);
+ sectionStart = index;
+ }
+ isNormalized = false;
+ }
+ ++index;
+ } else {
+ if ((char & 64512) === 55296 && index + 1 < end) {
+ tail = C.JSString_methods.codeUnitAt$1(host, index + 1);
+ if ((tail & 64512) === 56320) {
+ char = 65536 | (char & 1023) << 10 | tail & 1023;
+ sourceLength = 2;
+ } else
+ sourceLength = 1;
+ } else
+ sourceLength = 1;
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ buffer._contents += C.JSString_methods.substring$2(host, sectionStart, index);
+ buffer._contents += P._Uri__escapeChar(char);
+ index += sourceLength;
+ sectionStart = index;
+ }
+ }
+ }
+ if (buffer == null)
+ return C.JSString_methods.substring$2(host, start, end);
+ if (sectionStart < end)
+ buffer._contents += C.JSString_methods.substring$2(host, sectionStart, end);
+ t1 = buffer._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ _Uri__normalizeRegName: function(host, start, end) {
+ var index, sectionStart, buffer, isNormalized, char, replacement, t1, slice, t2, sourceLength, tail;
+ for (index = start, sectionStart = index, buffer = null, isNormalized = true; index < end;) {
+ char = C.JSString_methods.codeUnitAt$1(host, index);
+ if (char === 37) {
+ replacement = P._Uri__normalizeEscape(host, index, true);
+ t1 = replacement == null;
+ if (t1 && isNormalized) {
+ index += 3;
+ continue;
+ }
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ slice = C.JSString_methods.substring$2(host, sectionStart, index);
+ t2 = buffer._contents += !isNormalized ? slice.toLowerCase() : slice;
+ if (t1) {
+ replacement = C.JSString_methods.substring$2(host, index, index + 3);
+ sourceLength = 3;
+ } else if (replacement === "%") {
+ replacement = "%25";
+ sourceLength = 1;
+ } else
+ sourceLength = 3;
+ buffer._contents = t2 + replacement;
+ index += sourceLength;
+ sectionStart = index;
+ isNormalized = true;
+ } else {
+ if (char < 127) {
+ t1 = char >>> 4;
+ if (t1 >= 8)
+ return H.ioore(C.List_qNA, t1);
+ t1 = (C.List_qNA[t1] & 1 << (char & 15)) !== 0;
+ } else
+ t1 = false;
+ if (t1) {
+ if (isNormalized && 65 <= char && 90 >= char) {
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ if (sectionStart < index) {
+ buffer._contents += C.JSString_methods.substring$2(host, sectionStart, index);
+ sectionStart = index;
+ }
+ isNormalized = false;
+ }
+ ++index;
+ } else {
+ if (char <= 93) {
+ t1 = char >>> 4;
+ if (t1 >= 8)
+ return H.ioore(C.List_2Vk, t1);
+ t1 = (C.List_2Vk[t1] & 1 << (char & 15)) !== 0;
+ } else
+ t1 = false;
+ if (t1)
+ P._Uri__fail(host, index, "Invalid character");
+ else {
+ if ((char & 64512) === 55296 && index + 1 < end) {
+ tail = C.JSString_methods.codeUnitAt$1(host, index + 1);
+ if ((tail & 64512) === 56320) {
+ char = 65536 | (char & 1023) << 10 | tail & 1023;
+ sourceLength = 2;
+ } else
+ sourceLength = 1;
+ } else
+ sourceLength = 1;
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ slice = C.JSString_methods.substring$2(host, sectionStart, index);
+ buffer._contents += !isNormalized ? slice.toLowerCase() : slice;
+ buffer._contents += P._Uri__escapeChar(char);
+ index += sourceLength;
+ sectionStart = index;
+ }
+ }
+ }
+ }
+ if (buffer == null)
+ return C.JSString_methods.substring$2(host, start, end);
+ if (sectionStart < end) {
+ slice = C.JSString_methods.substring$2(host, sectionStart, end);
+ buffer._contents += !isNormalized ? slice.toLowerCase() : slice;
+ }
+ t1 = buffer._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ _Uri__makeScheme: function(scheme, start, end) {
+ var i, containsUpperCase, codeUnit, t1;
+ if (start === end)
+ return "";
+ if (!P._Uri__isAlphabeticCharacter(J.getInterceptor$s(scheme)._codeUnitAt$1(scheme, start)))
+ P._Uri__fail(scheme, start, "Scheme not starting with alphabetic character");
+ for (i = start, containsUpperCase = false; i < end; ++i) {
+ codeUnit = C.JSString_methods._codeUnitAt$1(scheme, i);
+ if (codeUnit < 128) {
+ t1 = codeUnit >>> 4;
+ if (t1 >= 8)
+ return H.ioore(C.List_JYB, t1);
+ t1 = (C.List_JYB[t1] & 1 << (codeUnit & 15)) !== 0;
+ } else
+ t1 = false;
+ if (!t1)
+ P._Uri__fail(scheme, i, "Illegal scheme character");
+ if (65 <= codeUnit && codeUnit <= 90)
+ containsUpperCase = true;
+ }
+ scheme = C.JSString_methods.substring$2(scheme, start, end);
+ return P._Uri__canonicalizeScheme(containsUpperCase ? scheme.toLowerCase() : scheme);
+ },
+ _Uri__canonicalizeScheme: function(scheme) {
+ if (scheme === "http")
+ return "http";
+ if (scheme === "file")
+ return "file";
+ if (scheme === "https")
+ return "https";
+ if (scheme === "package")
+ return "package";
+ return scheme;
+ },
+ _Uri__makeUserInfo: function(userInfo, start, end) {
+ if (userInfo == null)
+ return "";
+ return P._Uri__normalizeOrSubstring(userInfo, start, end, C.List_gRj, false);
+ },
+ _Uri__makePath: function(path, start, end, pathSegments, scheme, hasAuthority) {
+ var result,
+ isFile = scheme === "file",
+ ensureLeadingSlash = isFile || hasAuthority,
+ t1 = path == null;
+ if (t1 && pathSegments == null)
+ return isFile ? "/" : "";
+ t1 = !t1;
+ if (t1 && pathSegments != null)
+ throw H.wrapException(P.ArgumentError$("Both path and pathSegments specified"));
+ if (t1)
+ result = P._Uri__normalizeOrSubstring(path, start, end, C.List_qg4, true);
+ else {
+ pathSegments.toString;
+ t1 = H._arrayInstanceType(pathSegments);
+ result = new H.MappedListIterable(pathSegments, t1._eval$1("String(1)")._check(new P._Uri__makePath_closure()), t1._eval$1("MappedListIterable<1,String>")).join$1(0, "/");
+ }
+ if (result.length === 0) {
+ if (isFile)
+ return "/";
+ } else if (ensureLeadingSlash && !C.JSString_methods.startsWith$1(result, "/"))
+ result = "/" + result;
+ return P._Uri__normalizePath(result, scheme, hasAuthority);
+ },
+ _Uri__normalizePath: function(path, scheme, hasAuthority) {
+ var t1 = scheme.length === 0;
+ if (t1 && !hasAuthority && !C.JSString_methods.startsWith$1(path, "/"))
+ return P._Uri__normalizeRelativePath(path, !t1 || hasAuthority);
+ return P._Uri__removeDotSegments(path);
+ },
+ _Uri__makeQuery: function(query, start, end, queryParameters) {
+ if (query != null)
+ return P._Uri__normalizeOrSubstring(query, start, end, C.List_CVk, true);
+ return null;
+ },
+ _Uri__makeFragment: function(fragment, start, end) {
+ if (fragment == null)
+ return null;
+ return P._Uri__normalizeOrSubstring(fragment, start, end, C.List_CVk, true);
+ },
+ _Uri__normalizeEscape: function(source, index, lowerCase) {
+ var t1, firstDigit, secondDigit, firstDigitValue, secondDigitValue, value;
+ H.assertHelper(C.JSString_methods.codeUnitAt$1(source, index) === 37);
+ t1 = index + 2;
+ if (t1 >= source.length)
+ return "%";
+ firstDigit = C.JSString_methods.codeUnitAt$1(source, index + 1);
+ secondDigit = C.JSString_methods.codeUnitAt$1(source, t1);
+ firstDigitValue = H.hexDigitValue(firstDigit);
+ secondDigitValue = H.hexDigitValue(secondDigit);
+ if (firstDigitValue < 0 || secondDigitValue < 0)
+ return "%";
+ value = firstDigitValue * 16 + secondDigitValue;
+ if (value < 127) {
+ t1 = C.JSInt_methods._shrOtherPositive$1(value, 4);
+ if (t1 >= 8)
+ return H.ioore(C.List_nxB, t1);
+ t1 = (C.List_nxB[t1] & 1 << (value & 15)) !== 0;
+ } else
+ t1 = false;
+ if (t1)
+ return H.Primitives_stringFromCharCode(lowerCase && 65 <= value && 90 >= value ? (value | 32) >>> 0 : value);
+ if (firstDigit >= 97 || secondDigit >= 97)
+ return C.JSString_methods.substring$2(source, index, index + 3).toUpperCase();
+ return null;
+ },
+ _Uri__escapeChar: function(char) {
+ var t1, codeUnits, flag, encodedBytes, index, byte,
+ _s16_ = "0123456789ABCDEF";
+ H.assertHelper(char <= 1114111);
+ if (char < 128) {
+ t1 = new Array(3);
+ t1.fixed$length = Array;
+ codeUnits = H.setRuntimeTypeInfo(t1, type$.JSArray_int);
+ C.JSArray_methods.$indexSet(codeUnits, 0, 37);
+ C.JSArray_methods.$indexSet(codeUnits, 1, C.JSString_methods._codeUnitAt$1(_s16_, char >>> 4));
+ C.JSArray_methods.$indexSet(codeUnits, 2, C.JSString_methods._codeUnitAt$1(_s16_, char & 15));
+ } else {
+ if (char > 2047)
+ if (char > 65535) {
+ flag = 240;
+ encodedBytes = 4;
+ } else {
+ flag = 224;
+ encodedBytes = 3;
+ }
+ else {
+ flag = 192;
+ encodedBytes = 2;
+ }
+ t1 = new Array(3 * encodedBytes);
+ t1.fixed$length = Array;
+ codeUnits = H.setRuntimeTypeInfo(t1, type$.JSArray_int);
+ for (index = 0; --encodedBytes, encodedBytes >= 0; flag = 128) {
+ byte = C.JSInt_methods._shrReceiverPositive$1(char, 6 * encodedBytes) & 63 | flag;
+ C.JSArray_methods.$indexSet(codeUnits, index, 37);
+ C.JSArray_methods.$indexSet(codeUnits, index + 1, C.JSString_methods._codeUnitAt$1(_s16_, byte >>> 4));
+ C.JSArray_methods.$indexSet(codeUnits, index + 2, C.JSString_methods._codeUnitAt$1(_s16_, byte & 15));
+ index += 3;
+ }
+ }
+ return P.String_String$fromCharCodes(codeUnits, 0, null);
+ },
+ _Uri__normalizeOrSubstring: function(component, start, end, charTable, escapeDelimiters) {
+ var t1 = P._Uri__normalize(component, start, end, charTable, escapeDelimiters);
+ return t1 == null ? C.JSString_methods.substring$2(component, start, end) : t1;
+ },
+ _Uri__normalize: function(component, start, end, charTable, escapeDelimiters) {
+ var t1, index, sectionStart, buffer, char, t2, replacement, sourceLength, tail, _null = null;
+ for (t1 = !escapeDelimiters, index = start, sectionStart = index, buffer = _null; index < end;) {
+ char = C.JSString_methods.codeUnitAt$1(component, index);
+ if (char < 127) {
+ t2 = char >>> 4;
+ if (t2 >= 8)
+ return H.ioore(charTable, t2);
+ t2 = (charTable[t2] & 1 << (char & 15)) !== 0;
+ } else
+ t2 = false;
+ if (t2)
+ ++index;
+ else {
+ if (char === 37) {
+ replacement = P._Uri__normalizeEscape(component, index, false);
+ if (replacement == null) {
+ index += 3;
+ continue;
+ }
+ if ("%" === replacement) {
+ replacement = "%25";
+ sourceLength = 1;
+ } else
+ sourceLength = 3;
+ } else {
+ if (t1)
+ if (char <= 93) {
+ t2 = char >>> 4;
+ if (t2 >= 8)
+ return H.ioore(C.List_2Vk, t2);
+ t2 = (C.List_2Vk[t2] & 1 << (char & 15)) !== 0;
+ } else
+ t2 = false;
+ else
+ t2 = false;
+ if (t2) {
+ P._Uri__fail(component, index, "Invalid character");
+ sourceLength = _null;
+ replacement = sourceLength;
+ } else {
+ if ((char & 64512) === 55296) {
+ t2 = index + 1;
+ if (t2 < end) {
+ tail = C.JSString_methods.codeUnitAt$1(component, t2);
+ if ((tail & 64512) === 56320) {
+ char = 65536 | (char & 1023) << 10 | tail & 1023;
+ sourceLength = 2;
+ } else
+ sourceLength = 1;
+ } else
+ sourceLength = 1;
+ } else
+ sourceLength = 1;
+ replacement = P._Uri__escapeChar(char);
+ }
+ }
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ buffer._contents += C.JSString_methods.substring$2(component, sectionStart, index);
+ buffer._contents += H.S(replacement);
+ if (typeof sourceLength !== "number")
+ return H.iae(sourceLength);
+ index += sourceLength;
+ sectionStart = index;
+ }
+ }
+ if (buffer == null)
+ return _null;
+ if (sectionStart < end)
+ buffer._contents += C.JSString_methods.substring$2(component, sectionStart, end);
+ t1 = buffer._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ _Uri__mayContainDotSegments: function(path) {
+ if (C.JSString_methods.startsWith$1(path, "."))
+ return true;
+ return C.JSString_methods.indexOf$1(path, "/.") !== -1;
+ },
+ _Uri__removeDotSegments: function(path) {
+ var output, t1, t2, appendSlash, _i, segment, t3;
+ if (!P._Uri__mayContainDotSegments(path))
+ return path;
+ H.assertHelper(path.length !== 0);
+ output = H.setRuntimeTypeInfo([], type$.JSArray_String);
+ for (t1 = path.split("/"), t2 = t1.length, appendSlash = false, _i = 0; _i < t2; ++_i) {
+ segment = t1[_i];
+ if (J.$eq$(segment, "..")) {
+ t3 = output.length;
+ if (t3 !== 0) {
+ if (0 >= t3)
+ return H.ioore(output, -1);
+ output.pop();
+ if (output.length === 0)
+ C.JSArray_methods.add$1(output, "");
+ }
+ appendSlash = true;
+ } else if ("." === segment)
+ appendSlash = true;
+ else {
+ C.JSArray_methods.add$1(output, segment);
+ appendSlash = false;
+ }
+ }
+ if (appendSlash)
+ C.JSArray_methods.add$1(output, "");
+ return C.JSArray_methods.join$1(output, "/");
+ },
+ _Uri__normalizeRelativePath: function(path, allowScheme) {
+ var output, t1, t2, appendSlash, _i, segment;
+ H.assertHelper(!C.JSString_methods.startsWith$1(path, "/"));
+ if (!P._Uri__mayContainDotSegments(path))
+ return !allowScheme ? P._Uri__escapeScheme(path) : path;
+ H.assertHelper(path.length !== 0);
+ output = H.setRuntimeTypeInfo([], type$.JSArray_String);
+ for (t1 = path.split("/"), t2 = t1.length, appendSlash = false, _i = 0; _i < t2; ++_i) {
+ segment = t1[_i];
+ if (".." === segment)
+ if (output.length !== 0 && C.JSArray_methods.get$last(output) !== "..") {
+ if (0 >= output.length)
+ return H.ioore(output, -1);
+ output.pop();
+ appendSlash = true;
+ } else {
+ C.JSArray_methods.add$1(output, "..");
+ appendSlash = false;
+ }
+ else if ("." === segment)
+ appendSlash = true;
+ else {
+ C.JSArray_methods.add$1(output, segment);
+ appendSlash = false;
+ }
+ }
+ t1 = output.length;
+ if (t1 !== 0)
+ if (t1 === 1) {
+ if (0 >= t1)
+ return H.ioore(output, 0);
+ t1 = output[0].length === 0;
+ } else
+ t1 = false;
+ else
+ t1 = true;
+ if (t1)
+ return "./";
+ if (appendSlash || C.JSArray_methods.get$last(output) === "..")
+ C.JSArray_methods.add$1(output, "");
+ if (!allowScheme) {
+ if (0 >= output.length)
+ return H.ioore(output, 0);
+ C.JSArray_methods.$indexSet(output, 0, P._Uri__escapeScheme(output[0]));
+ }
+ return C.JSArray_methods.join$1(output, "/");
+ },
+ _Uri__escapeScheme: function(path) {
+ var i, char, t2,
+ t1 = path.length;
+ if (t1 >= 2 && P._Uri__isAlphabeticCharacter(J._codeUnitAt$1$s(path, 0)))
+ for (i = 1; i < t1; ++i) {
+ char = C.JSString_methods._codeUnitAt$1(path, i);
+ if (char === 58)
+ return C.JSString_methods.substring$2(path, 0, i) + "%3A" + C.JSString_methods.substring$1(path, i + 1);
+ if (char <= 127) {
+ t2 = char >>> 4;
+ if (t2 >= 8)
+ return H.ioore(C.List_JYB, t2);
+ t2 = (C.List_JYB[t2] & 1 << (char & 15)) === 0;
+ } else
+ t2 = true;
+ if (t2)
+ break;
+ }
+ return path;
+ },
+ _Uri__toWindowsFilePath: function(uri) {
+ var hasDriveLetter, t2, host,
+ segments = uri.get$pathSegments(),
+ t1 = segments.length;
+ if (t1 > 0 && J.get$length$asx(segments[0]) === 2 && J.codeUnitAt$1$s(segments[0], 1) === 58) {
+ if (0 >= t1)
+ return H.ioore(segments, 0);
+ P._Uri__checkWindowsDriveLetter(J.codeUnitAt$1$s(segments[0], 0), false);
+ P._Uri__checkWindowsPathReservedCharacters(segments, false, 1);
+ hasDriveLetter = true;
+ } else {
+ P._Uri__checkWindowsPathReservedCharacters(segments, false, 0);
+ hasDriveLetter = false;
+ }
+ t2 = uri.get$hasAbsolutePath() && !hasDriveLetter ? "\\" : "";
+ if (uri.get$hasAuthority()) {
+ host = uri.get$host(uri);
+ if (host.length !== 0)
+ t2 = t2 + "\\" + host + "\\";
+ }
+ t2 = P.StringBuffer__writeAll(t2, segments, "\\");
+ t1 = hasDriveLetter && t1 === 1 ? t2 + "\\" : t2;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ _Uri__hexCharPairToByte: function(s, pos) {
+ var byte, i, charCode;
+ for (byte = 0, i = 0; i < 2; ++i) {
+ charCode = C.JSString_methods._codeUnitAt$1(s, pos + i);
+ if (48 <= charCode && charCode <= 57)
+ byte = byte * 16 + charCode - 48;
+ else {
+ charCode |= 32;
+ if (97 <= charCode && charCode <= 102)
+ byte = byte * 16 + charCode - 87;
+ else
+ throw H.wrapException(P.ArgumentError$("Invalid URL encoding"));
+ }
+ }
+ return byte;
+ },
+ _Uri__uriDecode: function(text, start, end, encoding, plusToSpace) {
+ var t1, simple, t2, i, codeUnit, t3, bytes;
+ H.assertHelper(start <= end);
+ t1 = text.length;
+ H.assertHelper(end <= t1);
+ t2 = J.getInterceptor$s(text);
+ i = start;
+ while (true) {
+ if (!(i < end)) {
+ simple = true;
+ break;
+ }
+ codeUnit = t2._codeUnitAt$1(text, i);
+ if (codeUnit <= 127)
+ if (codeUnit !== 37)
+ t3 = false;
+ else
+ t3 = true;
+ else
+ t3 = true;
+ if (t3) {
+ simple = false;
+ break;
+ }
+ ++i;
+ }
+ if (simple) {
+ if (C.C_Utf8Codec !== encoding)
+ t1 = false;
+ else
+ t1 = true;
+ if (t1)
+ return t2.substring$2(text, start, end);
+ else
+ bytes = new H.CodeUnits(t2.substring$2(text, start, end));
+ } else {
+ bytes = H.setRuntimeTypeInfo([], type$.JSArray_int);
+ for (i = start; i < end; ++i) {
+ codeUnit = t2._codeUnitAt$1(text, i);
+ if (codeUnit > 127)
+ throw H.wrapException(P.ArgumentError$("Illegal percent encoding in URI"));
+ if (codeUnit === 37) {
+ if (i + 3 > t1)
+ throw H.wrapException(P.ArgumentError$("Truncated URI"));
+ C.JSArray_methods.add$1(bytes, P._Uri__hexCharPairToByte(text, i + 1));
+ i += 2;
+ } else
+ C.JSArray_methods.add$1(bytes, codeUnit);
+ }
+ }
+ type$.List_int._check(bytes);
+ return new P.Utf8Decoder(false).convert$1(bytes);
+ },
+ _Uri__isAlphabeticCharacter: function(codeUnit) {
+ var lowerCase = codeUnit | 32;
+ return 97 <= lowerCase && lowerCase <= 122;
+ },
+ UriData__writeUri: function(mimeType, charsetName, parameters, buffer, indices) {
+ var slashIndex, t1;
+ if (true)
+ buffer._contents = buffer._contents;
+ else {
+ slashIndex = P.UriData__validateMimeType("");
+ if (slashIndex < 0)
+ throw H.wrapException(P.ArgumentError$value("", "mimeType", "Invalid MIME type"));
+ t1 = buffer._contents += H.S(P._Uri__uriEncode(C.List_qFt, C.JSString_methods.substring$2("", 0, slashIndex), C.C_Utf8Codec, false));
+ buffer._contents = t1 + "/";
+ buffer._contents += H.S(P._Uri__uriEncode(C.List_qFt, C.JSString_methods.substring$1("", slashIndex + 1), C.C_Utf8Codec, false));
+ }
+ },
+ UriData__validateMimeType: function(mimeType) {
+ var t1, slashIndex, i;
+ for (t1 = mimeType.length, slashIndex = -1, i = 0; i < t1; ++i) {
+ if (C.JSString_methods._codeUnitAt$1(mimeType, i) !== 47)
+ continue;
+ if (slashIndex < 0) {
+ slashIndex = i;
+ continue;
+ }
+ return -1;
+ }
+ return slashIndex;
+ },
+ UriData__parse: function(text, start, sourceUri) {
+ var indices, t1, i, slashIndex, char, equalsIndex, lastSeparator, t2, data,
+ _s17_ = "Invalid MIME type";
+ H.assertHelper(start === 0 || start === 5);
+ H.assertHelper(start === 5 === C.JSString_methods.startsWith$1(text, "data:"));
+ indices = H.setRuntimeTypeInfo([start - 1], type$.JSArray_int);
+ for (t1 = text.length, i = start, slashIndex = -1, char = null; i < t1; ++i) {
+ char = C.JSString_methods._codeUnitAt$1(text, i);
+ if (char === 44 || char === 59)
+ break;
+ if (char === 47) {
+ if (slashIndex < 0) {
+ slashIndex = i;
+ continue;
+ }
+ throw H.wrapException(P.FormatException$(_s17_, text, i));
+ }
+ }
+ if (slashIndex < 0 && i > start)
+ throw H.wrapException(P.FormatException$(_s17_, text, i));
+ for (; char !== 44;) {
+ C.JSArray_methods.add$1(indices, i);
+ ++i;
+ for (equalsIndex = -1; i < t1; ++i) {
+ char = C.JSString_methods._codeUnitAt$1(text, i);
+ if (char === 61) {
+ if (equalsIndex < 0)
+ equalsIndex = i;
+ } else if (char === 59 || char === 44)
+ break;
+ }
+ if (equalsIndex >= 0)
+ C.JSArray_methods.add$1(indices, equalsIndex);
+ else {
+ lastSeparator = C.JSArray_methods.get$last(indices);
+ if (char !== 44 || i !== lastSeparator + 7 || !C.JSString_methods.startsWith$2(text, "base64", lastSeparator + 1))
+ throw H.wrapException(P.FormatException$("Expecting '='", text, i));
+ break;
+ }
+ }
+ C.JSArray_methods.add$1(indices, i);
+ t2 = i + 1;
+ if ((indices.length & 1) === 1)
+ text = C.C_Base64Codec.normalize$3(text, t2, t1);
+ else {
+ data = P._Uri__normalize(text, t2, t1, C.List_CVk, true);
+ if (data != null)
+ text = C.JSString_methods.replaceRange$3(text, t2, t1, data);
+ }
+ return new P.UriData(text, indices, sourceUri);
+ },
+ UriData__uriEncodeBytes: function(canonicalTable, bytes, buffer) {
+ var t1, byteOr, i, byte, t2, t3,
+ _s16_ = "0123456789ABCDEF";
+ for (t1 = J.getInterceptor$asx(bytes), byteOr = 0, i = 0; i < t1.get$length(bytes); ++i) {
+ byte = t1.$index(bytes, i);
+ if (typeof byte !== "number")
+ return H.iae(byte);
+ byteOr |= byte;
+ if (byte < 128) {
+ t2 = C.JSInt_methods._shrOtherPositive$1(byte, 4);
+ if (t2 >= 8)
+ return H.ioore(canonicalTable, t2);
+ t2 = (canonicalTable[t2] & 1 << (byte & 15)) !== 0;
+ } else
+ t2 = false;
+ t3 = buffer._contents;
+ if (t2)
+ buffer._contents = t3 + H.Primitives_stringFromCharCode(byte);
+ else {
+ t2 = t3 + H.Primitives_stringFromCharCode(37);
+ buffer._contents = t2;
+ t2 += H.Primitives_stringFromCharCode(C.JSString_methods._codeUnitAt$1(_s16_, C.JSInt_methods._shrOtherPositive$1(byte, 4)));
+ buffer._contents = t2;
+ buffer._contents = t2 + H.Primitives_stringFromCharCode(C.JSString_methods._codeUnitAt$1(_s16_, byte & 15));
+ }
+ }
+ if ((byteOr & 4294967040) >>> 0 !== 0)
+ for (i = 0; i < t1.get$length(bytes); ++i) {
+ byte = t1.$index(bytes, i);
+ if (typeof byte !== "number")
+ return byte.$lt();
+ if (byte < 0 || byte > 255)
+ throw H.wrapException(P.ArgumentError$value(byte, "non-byte value", null));
+ }
+ },
+ _createTables: function() {
+ var _s77_ = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~!$&'()*+,;=",
+ _s1_ = ".", _s1_0 = ":", _s1_1 = "/", _s1_2 = "?", _s1_3 = "#",
+ t1 = type$.Uint8List,
+ tables = P.List_List$generate(22, new P._createTables_closure(), true, t1),
+ t2 = new P._createTables_build(tables),
+ t3 = new P._createTables_setChars(),
+ t4 = new P._createTables_setRange(),
+ t5 = t1._check(t2.call$2(0, 225));
+ t3.call$3(t5, _s77_, 1);
+ t3.call$3(t5, _s1_, 14);
+ t3.call$3(t5, _s1_0, 34);
+ t3.call$3(t5, _s1_1, 3);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(14, 225));
+ t3.call$3(t5, _s77_, 1);
+ t3.call$3(t5, _s1_, 15);
+ t3.call$3(t5, _s1_0, 34);
+ t3.call$3(t5, _s1_1, 234);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(15, 225));
+ t3.call$3(t5, _s77_, 1);
+ t3.call$3(t5, "%", 225);
+ t3.call$3(t5, _s1_0, 34);
+ t3.call$3(t5, _s1_1, 9);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(1, 225));
+ t3.call$3(t5, _s77_, 1);
+ t3.call$3(t5, _s1_0, 34);
+ t3.call$3(t5, _s1_1, 10);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(2, 235));
+ t3.call$3(t5, _s77_, 139);
+ t3.call$3(t5, _s1_1, 131);
+ t3.call$3(t5, _s1_, 146);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(3, 235));
+ t3.call$3(t5, _s77_, 11);
+ t3.call$3(t5, _s1_1, 68);
+ t3.call$3(t5, _s1_, 18);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(4, 229));
+ t3.call$3(t5, _s77_, 5);
+ t4.call$3(t5, "AZ", 229);
+ t3.call$3(t5, _s1_0, 102);
+ t3.call$3(t5, "@", 68);
+ t3.call$3(t5, "[", 232);
+ t3.call$3(t5, _s1_1, 138);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(5, 229));
+ t3.call$3(t5, _s77_, 5);
+ t4.call$3(t5, "AZ", 229);
+ t3.call$3(t5, _s1_0, 102);
+ t3.call$3(t5, "@", 68);
+ t3.call$3(t5, _s1_1, 138);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(6, 231));
+ t4.call$3(t5, "19", 7);
+ t3.call$3(t5, "@", 68);
+ t3.call$3(t5, _s1_1, 138);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(7, 231));
+ t4.call$3(t5, "09", 7);
+ t3.call$3(t5, "@", 68);
+ t3.call$3(t5, _s1_1, 138);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t3.call$3(t1._check(t2.call$2(8, 8)), "]", 5);
+ t5 = t1._check(t2.call$2(9, 235));
+ t3.call$3(t5, _s77_, 11);
+ t3.call$3(t5, _s1_, 16);
+ t3.call$3(t5, _s1_1, 234);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(16, 235));
+ t3.call$3(t5, _s77_, 11);
+ t3.call$3(t5, _s1_, 17);
+ t3.call$3(t5, _s1_1, 234);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(17, 235));
+ t3.call$3(t5, _s77_, 11);
+ t3.call$3(t5, _s1_1, 9);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(10, 235));
+ t3.call$3(t5, _s77_, 11);
+ t3.call$3(t5, _s1_, 18);
+ t3.call$3(t5, _s1_1, 234);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(18, 235));
+ t3.call$3(t5, _s77_, 11);
+ t3.call$3(t5, _s1_, 19);
+ t3.call$3(t5, _s1_1, 234);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(19, 235));
+ t3.call$3(t5, _s77_, 11);
+ t3.call$3(t5, _s1_1, 234);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(11, 235));
+ t3.call$3(t5, _s77_, 11);
+ t3.call$3(t5, _s1_1, 10);
+ t3.call$3(t5, _s1_2, 172);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(12, 236));
+ t3.call$3(t5, _s77_, 12);
+ t3.call$3(t5, _s1_2, 12);
+ t3.call$3(t5, _s1_3, 205);
+ t5 = t1._check(t2.call$2(13, 237));
+ t3.call$3(t5, _s77_, 13);
+ t3.call$3(t5, _s1_2, 13);
+ t4.call$3(t1._check(t2.call$2(20, 245)), "az", 21);
+ t2 = t1._check(t2.call$2(21, 245));
+ t4.call$3(t2, "az", 21);
+ t4.call$3(t2, "09", 21);
+ t3.call$3(t2, "+-.", 21);
+ return tables;
+ },
+ _scan: function(uri, start, end, state, indices) {
+ var t1, i, table, char, transition,
+ tables = $.$get$_scannerTables();
+ H.assertHelper(end <= uri.length);
+ for (t1 = J.getInterceptor$s(uri), i = start; i < end; ++i) {
+ if (state < 0 || state >= tables.length)
+ return H.ioore(tables, state);
+ table = tables[state];
+ char = t1._codeUnitAt$1(uri, i) ^ 96;
+ if (char > 95)
+ char = 31;
+ if (char >= table.length)
+ return H.ioore(table, char);
+ transition = table[char];
+ state = transition & 31;
+ C.JSArray_methods.$indexSet(indices, transition >>> 5, i);
+ }
+ return state;
+ },
+ bool: function bool() {
+ },
+ DateTime: function DateTime(t0, t1) {
+ this._value = t0;
+ this.isUtc = t1;
+ },
+ double: function double() {
+ },
+ Duration: function Duration(t0) {
+ this._duration = t0;
+ },
+ Duration_toString_sixDigits: function Duration_toString_sixDigits() {
+ },
+ Duration_toString_twoDigits: function Duration_toString_twoDigits() {
+ },
+ Error: function Error() {
+ },
+ AssertionError: function AssertionError(t0) {
+ this.message = t0;
+ },
+ NullThrownError: function NullThrownError() {
+ },
+ ArgumentError: function ArgumentError(t0, t1, t2, t3) {
+ var _ = this;
+ _._hasValue = t0;
+ _.invalidValue = t1;
+ _.name = t2;
+ _.message = t3;
+ },
+ RangeError: function RangeError(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _.start = t0;
+ _.end = t1;
+ _._hasValue = t2;
+ _.invalidValue = t3;
+ _.name = t4;
+ _.message = t5;
+ },
+ IndexError: function IndexError(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _.length = t0;
+ _._hasValue = t1;
+ _.invalidValue = t2;
+ _.name = t3;
+ _.message = t4;
+ },
+ UnsupportedError: function UnsupportedError(t0) {
+ this.message = t0;
+ },
+ UnimplementedError: function UnimplementedError(t0) {
+ this.message = t0;
+ },
+ StateError: function StateError(t0) {
+ this.message = t0;
+ },
+ ConcurrentModificationError: function ConcurrentModificationError(t0) {
+ this.modifiedObject = t0;
+ },
+ OutOfMemoryError: function OutOfMemoryError() {
+ },
+ StackOverflowError: function StackOverflowError() {
+ },
+ CyclicInitializationError: function CyclicInitializationError(t0) {
+ this.variableName = t0;
+ },
+ _Exception: function _Exception(t0) {
+ this.message = t0;
+ },
+ FormatException: function FormatException(t0, t1, t2) {
+ this.message = t0;
+ this.source = t1;
+ this.offset = t2;
+ },
+ Expando: function Expando(t0, t1, t2) {
+ this._jsWeakMapOrKey = t0;
+ this.name = t1;
+ this.$ti = t2;
+ },
+ Function: function Function() {
+ },
+ int: function int() {
+ },
+ Iterable: function Iterable() {
+ },
+ Iterator: function Iterator() {
+ },
+ List: function List() {
+ },
+ Map: function Map() {
+ },
+ MapEntry: function MapEntry(t0, t1, t2) {
+ this.key = t0;
+ this.value = t1;
+ this.$ti = t2;
+ },
+ Null: function Null() {
+ },
+ num: function num() {
+ },
+ Object: function Object() {
+ },
+ Pattern: function Pattern() {
+ },
+ Match: function Match() {
+ },
+ RegExpMatch: function RegExpMatch() {
+ },
+ Set: function Set() {
+ },
+ StackTrace: function StackTrace() {
+ },
+ _StringStackTrace: function _StringStackTrace(t0) {
+ this._stackTrace = t0;
+ },
+ Stopwatch: function Stopwatch() {
+ this._stop = this._core$_start = 0;
+ },
+ String: function String() {
+ },
+ Runes: function Runes(t0) {
+ this.string = t0;
+ },
+ RuneIterator: function RuneIterator(t0) {
+ var _ = this;
+ _.string = t0;
+ _._nextPosition = _._core$_position = 0;
+ _._currentCodePoint = null;
+ },
+ StringBuffer: function StringBuffer(t0) {
+ this._contents = t0;
+ },
+ Uri: function Uri() {
+ },
+ Uri__parseIPv4Address_error: function Uri__parseIPv4Address_error(t0) {
+ this.host = t0;
+ },
+ Uri_parseIPv6Address_error: function Uri_parseIPv6Address_error(t0) {
+ this.host = t0;
+ },
+ Uri_parseIPv6Address_parseHex: function Uri_parseIPv6Address_parseHex(t0, t1) {
+ this.error = t0;
+ this.host = t1;
+ },
+ _Uri: function _Uri(t0, t1, t2, t3, t4, t5, t6) {
+ var _ = this;
+ _.scheme = t0;
+ _._userInfo = t1;
+ _._host = t2;
+ _._port = t3;
+ _.path = t4;
+ _._query = t5;
+ _._fragment = t6;
+ _._hashCodeCache = _._text = _._pathSegments = null;
+ },
+ _Uri__Uri$notSimple_closure: function _Uri__Uri$notSimple_closure(t0, t1) {
+ this.uri = t0;
+ this.portStart = t1;
+ },
+ _Uri__checkNonWindowsPathReservedCharacters_closure: function _Uri__checkNonWindowsPathReservedCharacters_closure(t0) {
+ this.argumentError = t0;
+ },
+ _Uri__makePath_closure: function _Uri__makePath_closure() {
+ },
+ UriData: function UriData(t0, t1, t2) {
+ this._text = t0;
+ this._separatorIndices = t1;
+ this._uriCache = t2;
+ },
+ _createTables_closure: function _createTables_closure() {
+ },
+ _createTables_build: function _createTables_build(t0) {
+ this.tables = t0;
+ },
+ _createTables_setChars: function _createTables_setChars() {
+ },
+ _createTables_setRange: function _createTables_setRange() {
+ },
+ _SimpleUri: function _SimpleUri(t0, t1, t2, t3, t4, t5, t6, t7) {
+ var _ = this;
+ _._uri = t0;
+ _._schemeEnd = t1;
+ _._hostStart = t2;
+ _._portStart = t3;
+ _._pathStart = t4;
+ _._queryStart = t5;
+ _._fragmentStart = t6;
+ _._schemeCache = t7;
+ _._hashCodeCache = null;
+ },
+ _DataUri: function _DataUri(t0, t1, t2, t3, t4, t5, t6) {
+ var _ = this;
+ _.scheme = t0;
+ _._userInfo = t1;
+ _._host = t2;
+ _._port = t3;
+ _.path = t4;
+ _._query = t5;
+ _._fragment = t6;
+ _._hashCodeCache = _._text = _._pathSegments = null;
+ },
+ _StructuredClone: function _StructuredClone() {
+ },
+ _StructuredClone_walk_closure: function _StructuredClone_walk_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ _StructuredClone_walk_closure0: function _StructuredClone_walk_closure0(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ _AcceptStructuredClone: function _AcceptStructuredClone() {
+ },
+ _AcceptStructuredClone_walk_closure: function _AcceptStructuredClone_walk_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ _StructuredCloneDart2Js: function _StructuredCloneDart2Js(t0, t1) {
+ this.values = t0;
+ this.copies = t1;
+ },
+ _AcceptStructuredCloneDart2Js: function _AcceptStructuredCloneDart2Js(t0, t1) {
+ this.values = t0;
+ this.copies = t1;
+ this.mustCopy = false;
+ },
+ _convertDataTree: function(data) {
+ return new P._convertDataTree__convert(new P._IdentityHashMap(type$._IdentityHashMap_dynamic_dynamic)).call$1(data);
+ },
+ promiseToFuture: function(jsPromise, $T) {
+ var t1 = new P._Future($.Zone__current, $T._eval$1("_Future<0>")),
+ completer = new P._AsyncCompleter(t1, $T._eval$1("_AsyncCompleter<0>"));
+ jsPromise.then(H.convertDartClosureToJS(new P.promiseToFuture_closure(completer, $T), 1), H.convertDartClosureToJS(new P.promiseToFuture_closure0(completer), 1));
+ return t1;
+ },
+ _convertDataTree__convert: function _convertDataTree__convert(t0) {
+ this._convertedObjects = t0;
+ },
+ promiseToFuture_closure: function promiseToFuture_closure(t0, t1) {
+ this.completer = t0;
+ this.T = t1;
+ },
+ promiseToFuture_closure0: function promiseToFuture_closure0(t0) {
+ this.completer = t0;
+ },
+ ByteBuffer: function ByteBuffer() {
+ },
+ ByteData: function ByteData() {
+ },
+ Int8List: function Int8List() {
+ },
+ Uint8List: function Uint8List() {
+ },
+ Uint8ClampedList: function Uint8ClampedList() {
+ },
+ Int16List: function Int16List() {
+ },
+ Uint16List: function Uint16List() {
+ },
+ Int32List: function Int32List() {
+ },
+ Uint32List: function Uint32List() {
+ },
+ Float32List: function Float32List() {
+ },
+ Float64List: function Float64List() {
+ },
+ SqlError: function SqlError() {
+ },
+ max: function(a, b, $T) {
+ H.checkTypeBound($T, type$.num, "T", "max");
+ $T._check(a);
+ $T._check(b);
+ return Math.max(H.checkNum(a), H.checkNum(b));
+ },
+ pow: function(x, exponent) {
+ return Math.pow(x, exponent);
+ }
+ },
+ W = {
+ _EventStreamSubscription$: function(_target, _eventType, onData, _useCapture, $T) {
+ var t1 = onData == null ? null : W._wrapZone(new W._EventStreamSubscription_closure(onData), type$.Event);
+ t1 = new W._EventStreamSubscription(_target, _eventType, t1, false, $T._eval$1("_EventStreamSubscription<0>"));
+ t1._tryResume$0();
+ return t1;
+ },
+ _wrapZone: function(callback, $T) {
+ var t1 = $.Zone__current;
+ if (t1 === C.C__RootZone)
+ return callback;
+ return t1.bindUnaryCallbackGuarded$1$1(callback, $T);
+ },
+ ApplicationCacheErrorEvent: function ApplicationCacheErrorEvent() {
+ },
+ Blob: function Blob() {
+ },
+ DomError: function DomError() {
+ },
+ DomException: function DomException() {
+ },
+ ErrorEvent: function ErrorEvent() {
+ },
+ Event: function Event() {
+ },
+ EventTarget: function EventTarget() {
+ },
+ File: function File() {
+ },
+ Location: function Location() {
+ },
+ MediaError: function MediaError() {
+ },
+ MediaKeyMessageEvent: function MediaKeyMessageEvent() {
+ },
+ MessageEvent: function MessageEvent() {
+ },
+ MessagePort: function MessagePort() {
+ },
+ NavigatorUserMediaError: function NavigatorUserMediaError() {
+ },
+ OverconstrainedError: function OverconstrainedError() {
+ },
+ PositionError: function PositionError() {
+ },
+ PresentationConnectionCloseEvent: function PresentationConnectionCloseEvent() {
+ },
+ SpeechRecognitionError: function SpeechRecognitionError() {
+ },
+ EventStreamProvider: function EventStreamProvider(t0) {
+ this.$ti = t0;
+ },
+ _EventStream: function _EventStream(t0, t1, t2, t3) {
+ var _ = this;
+ _._html$_target = t0;
+ _._eventType = t1;
+ _._useCapture = t2;
+ _.$ti = t3;
+ },
+ _EventStreamSubscription: function _EventStreamSubscription(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._pauseCount = 0;
+ _._html$_target = t0;
+ _._eventType = t1;
+ _._html$_onData = t2;
+ _._useCapture = t3;
+ _.$ti = t4;
+ },
+ _EventStreamSubscription_closure: function _EventStreamSubscription_closure(t0) {
+ this.onData = t0;
+ }
+ },
+ S = {AsyncMemoizer: function AsyncMemoizer(t0, t1) {
+ this._async_memoizer$_completer = t0;
+ this.$ti = t1;
+ }, NullStreamSink: function NullStreamSink(t0, t1) {
+ var _ = this;
+ _.done = t0;
+ _._addingStream = _._null_stream_sink$_closed = false;
+ _.$ti = t1;
+ }, NullStreamSink_addStream_closure: function NullStreamSink_addStream_closure(t0) {
+ this.$this = t0;
+ }, Validator: function Validator(t0) {
+ this._isDefined = t0;
+ },
+ SpanScanner$: function(string) {
+ var t1, t2;
+ string.toString;
+ t1 = new H.CodeUnits(string);
+ t2 = H.setRuntimeTypeInfo([0], type$.JSArray_int);
+ t2 = new Y.SourceFile(null, t2, new Uint32Array(H._ensureNativeList(t1.toList$0(t1))));
+ t2.SourceFile$decoded$2$url(t1, null);
+ return new S.SpanScanner(t2, null, string);
+ },
+ SpanScanner: function SpanScanner(t0, t1, t2) {
+ var _ = this;
+ _._sourceFile = t0;
+ _._lastSpan = null;
+ _.sourceUrl = t1;
+ _.string = t2;
+ _._string_scanner$_position = 0;
+ _._lastMatchPosition = _._lastMatch = null;
+ },
+ _SpanScannerState: function _SpanScannerState(t0, t1) {
+ this._span_scanner$_scanner = t0;
+ this.position = t1;
+ },
+ RemoteListener_start: function(getMain, beforeLoad, hidePrints) {
+ var printZone, spec, t3, _null = null, t1 = {},
+ controller = B.StreamChannelController$(false, true, type$.Object),
+ t2 = type$.dynamic,
+ channel = D._MultiChannel$(controller._local, t2);
+ t1.verboseChain = true;
+ printZone = $.Zone__current;
+ spec = P._ZoneSpecification$(_null, _null, _null, _null, _null, new S.RemoteListener_start_closure(printZone, channel), _null, _null, _null, _null, _null, _null, _null);
+ P.Stream_Stream$fromIterable([], t2).listen$1(new S.RemoteListener_start_closure0()).cancel$0();
+ t3 = type$.String;
+ P.runZoned(type$.Null_Function._check(new S.RemoteListener_start_closure1(t1, getMain, channel, controller, beforeLoad, printZone, spec)), _null, _null, P.LinkedHashMap_LinkedHashMap$_literal([$.$get$_currentKey(), new N.SuiteChannelManager(P.LinkedHashMap_LinkedHashMap$_empty(t3, type$.StreamChannel_dynamic), P.LinkedHashMap_LinkedHashMap$_empty(t3, type$.StreamChannelCompleter_dynamic), P.LinkedHashSet_LinkedHashSet$_empty(t3))], t2, t2), type$.Null);
+ return controller._foreign;
+ },
+ RemoteListener__deserializeSet: function(list) {
+ if (list == null)
+ return null;
+ if (J.get$isEmpty$asx(list))
+ return null;
+ return P.LinkedHashSet_LinkedHashSet$from(list, type$.String);
+ },
+ RemoteListener__sendLoadException: function(channel, message) {
+ var t1 = type$.String;
+ channel._mainController._foreign._sink.add$1(0, P.LinkedHashMap_LinkedHashMap$_literal(["type", "loadException", "message", message], t1, t1));
+ },
+ RemoteListener__sendError: function(channel, error, stackTrace, verboseChain) {
+ channel._mainController._foreign._sink.add$1(0, P.LinkedHashMap_LinkedHashMap$_literal(["type", "error", "error", U.RemoteException_serialize(error, type$.StackTraceFormatter._as($.Zone__current.$index(0, $.$get$_currentKey0())).formatStackTrace$2$verbose(stackTrace, verboseChain))], type$.String, type$.Object));
+ },
+ RemoteListener: function RemoteListener(t0, t1) {
+ this._suite = t0;
+ this._printZone = t1;
+ },
+ RemoteListener_start_closure: function RemoteListener_start_closure(t0, t1) {
+ this.printZone = t0;
+ this.channel = t1;
+ },
+ RemoteListener_start_closure0: function RemoteListener_start_closure0() {
+ },
+ RemoteListener_start_closure1: function RemoteListener_start_closure1(t0, t1, t2, t3, t4, t5, t6) {
+ var _ = this;
+ _._box_0 = t0;
+ _.getMain = t1;
+ _.channel = t2;
+ _.controller = t3;
+ _.beforeLoad = t4;
+ _.printZone = t5;
+ _.spec = t6;
+ },
+ RemoteListener_start__closure: function RemoteListener_start__closure(t0, t1, t2, t3, t4, t5, t6) {
+ var _ = this;
+ _._box_0 = t0;
+ _.getMain = t1;
+ _.channel = t2;
+ _.controller = t3;
+ _.beforeLoad = t4;
+ _.printZone = t5;
+ _.spec = t6;
+ },
+ RemoteListener_start___closure: function RemoteListener_start___closure(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _._box_0 = t0;
+ _.getMain = t1;
+ _.channel = t2;
+ _.controller = t3;
+ _.beforeLoad = t4;
+ _.printZone = t5;
+ },
+ RemoteListener_start____closure: function RemoteListener_start____closure(t0, t1) {
+ this.controller = t0;
+ this.channel = t1;
+ },
+ RemoteListener_start____closure0: function RemoteListener_start____closure0(t0, t1, t2) {
+ this.suite = t0;
+ this.printZone = t1;
+ this.channel = t2;
+ },
+ RemoteListener_start_____closure: function RemoteListener_start_____closure(t0, t1, t2) {
+ this.suite = t0;
+ this.printZone = t1;
+ this.channel = t2;
+ },
+ RemoteListener_start___closure0: function RemoteListener_start___closure0(t0, t1) {
+ this._box_0 = t0;
+ this.channel = t1;
+ },
+ RemoteListener__serializeGroup_closure: function RemoteListener__serializeGroup_closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.$this = t1;
+ this.channel = t2;
+ },
+ RemoteListener__serializeTest_closure: function RemoteListener__serializeTest_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _.$this = t0;
+ _.test = t1;
+ _.groups = t2;
+ _.channel = t3;
+ },
+ RemoteListener__runLiveTest_closure: function RemoteListener__runLiveTest_closure(t0) {
+ this.liveTest = t0;
+ },
+ RemoteListener__runLiveTest_closure0: function RemoteListener__runLiveTest_closure0(t0) {
+ this.channel = t0;
+ },
+ RemoteListener__runLiveTest_closure1: function RemoteListener__runLiveTest_closure1(t0, t1) {
+ this.channel = t0;
+ this.liveTest = t1;
+ },
+ RemoteListener__runLiveTest_closure2: function RemoteListener__runLiveTest_closure2(t0, t1) {
+ this.$this = t0;
+ this.channel = t1;
+ },
+ RemoteListener__runLiveTest_closure3: function RemoteListener__runLiveTest_closure3(t0, t1) {
+ this.liveTest = t0;
+ this.channel = t1;
+ },
+ RemoteListener__runLiveTest__closure: function RemoteListener__runLiveTest__closure(t0) {
+ this.channel = t0;
+ }
+ },
+ O = {DelegatingSink: function DelegatingSink(t0, t1) {
+ this._sink$_sink = t0;
+ this.$ti = t1;
+ }, None: function None() {
+ }, Scanner: function Scanner(t0) {
+ this._scanner = t0;
+ this._scanner$_next = null;
+ this._endOfFileEmitted = false;
+ }, EmptyUnmodifiableSet: function EmptyUnmodifiableSet(t0) {
+ this.$ti = t0;
+ },
+ Style__getPlatformStyle: function() {
+ if (P.Uri_base().get$scheme() !== "file")
+ return $.$get$Style_url();
+ var t1 = P.Uri_base();
+ if (!C.JSString_methods.endsWith$1(t1.get$path(t1), "/"))
+ return $.$get$Style_url();
+ if (P._Uri__Uri(null, "a/b", null, null).toFilePath$0() === "a\\b")
+ return $.$get$Style_windows();
+ return $.$get$Style_posix();
+ },
+ Style: function Style() {
+ },
+ Pool$: function(_maxAllocatedResources) {
+ var t4,
+ t1 = type$.Completer_PoolResource,
+ t2 = P.ListQueue$(t1),
+ t3 = P.ListQueue$(type$.void_Function);
+ t1 = P.ListQueue$(t1);
+ t4 = $.Zone__current;
+ if (_maxAllocatedResources <= 0)
+ H.throwExpression(P.ArgumentError$value(_maxAllocatedResources, "maxAllocatedResources", "Must be greater than zero."));
+ return new O.Pool(t2, t3, t1, _maxAllocatedResources, new S.AsyncMemoizer(new P._AsyncCompleter(new P._Future(t4, type$._Future_dynamic), type$._AsyncCompleter_dynamic), type$.AsyncMemoizer_dynamic));
+ },
+ Pool: function Pool(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._requestedResources = t0;
+ _._onReleaseCallbacks = t1;
+ _._onReleaseCompleters = t2;
+ _._maxAllocatedResources = t3;
+ _._allocatedResources = 0;
+ _._closeGroup = _._timer = null;
+ _._pool$_closeMemo = t4;
+ },
+ Pool_close_closure: function Pool_close_closure(t0) {
+ this.$this = t0;
+ },
+ Pool__onResourceReleaseAllowed_closure: function Pool__onResourceReleaseAllowed_closure(t0, t1) {
+ this.zone = t0;
+ this.registered = t1;
+ },
+ Pool__runOnRelease_closure: function Pool__runOnRelease_closure(t0) {
+ this.$this = t0;
+ },
+ Pool__runOnRelease_closure0: function Pool__runOnRelease_closure0(t0) {
+ this.$this = t0;
+ },
+ PoolResource: function PoolResource(t0) {
+ this._pool = t0;
+ this._released = false;
+ },
+ mapStackTrace: function(sourceMap, stackTrace, minified, packageResolver, sdkRoot) {
+ var t2, t3, sdkLib, t4, t1 = {};
+ t1.packageResolver = packageResolver;
+ if (type$.Chain._is(stackTrace)) {
+ t2 = stackTrace.get$traces();
+ t3 = H._arrayInstanceType(t2);
+ return new U.Chain(P.List_List$unmodifiable(new H.MappedListIterable(t2, t3._eval$1("Trace(1)")._check(new O.mapStackTrace_closure(t1, sourceMap, false, sdkRoot)), t3._eval$1("MappedListIterable<1,Trace>")), type$.Trace));
+ }
+ t2 = sdkRoot == null;
+ !t2;
+ sdkLib = t2 ? null : sdkRoot.toString$0(0) + "/lib";
+ t2 = Y.Trace_Trace$from(stackTrace).get$frames();
+ t3 = H._arrayInstanceType(t2);
+ t4 = t3._eval$1("MappedListIterable<1,Frame>");
+ return new Y.Trace(P.List_List$unmodifiable(new H.MappedListIterable(t2, t3._eval$1("Frame(1)")._check(new O.mapStackTrace_closure0(t1, sourceMap, sdkRoot, sdkLib, false)), t4).super$Iterable$where(0, t4._eval$1("bool(ListIterable.E)")._check(new O.mapStackTrace_closure1())), type$.Frame), new P._StringStackTrace(null));
+ },
+ _prettifyMember: function(member) {
+ var t2, t3,
+ t1 = P.RegExp_RegExp("/?<$", false);
+ member.toString;
+ t1 = H.stringReplaceAllUnchecked(member, t1, "");
+ t2 = P.RegExp_RegExp("\\$\\d+(\\$[a-zA-Z_0-9]+)*$", false);
+ t3 = type$.String_Function_Match;
+ t2 = C.JSString_methods.splitMapJoin$2$onMatch(H.stringReplaceAllUnchecked(t1, t2, ""), P.RegExp_RegExp("(_+)closure\\d*\\.call$", false), t3._check(new O._prettifyMember_closure()));
+ t1 = P.RegExp_RegExp("\\.call$", false);
+ t1 = H.stringReplaceAllUnchecked(t2, t1, "");
+ t2 = P.RegExp_RegExp("^dart\\.", false);
+ t1 = H.stringReplaceAllUnchecked(t1, t2, "");
+ t2 = P.RegExp_RegExp("[a-zA-Z_0-9]+\\$", false);
+ t1 = H.stringReplaceAllUnchecked(t1, t2, "");
+ t2 = P.RegExp_RegExp("^[a-zA-Z_0-9]+.(static|dart).", false);
+ return C.JSString_methods.splitMapJoin$2$onMatch(H.stringReplaceAllUnchecked(t1, t2, ""), P.RegExp_RegExp("([a-zA-Z0-9]+)_", false), t3._check(new O._prettifyMember_closure0()));
+ },
+ mapStackTrace_closure: function mapStackTrace_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _._box_0 = t0;
+ _.sourceMap = t1;
+ _.minified = t2;
+ _.sdkRoot = t3;
+ },
+ mapStackTrace_closure0: function mapStackTrace_closure0(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._box_0 = t0;
+ _.sourceMap = t1;
+ _.sdkRoot = t2;
+ _.sdkLib = t3;
+ _.minified = t4;
+ },
+ mapStackTrace_closure1: function mapStackTrace_closure1() {
+ },
+ _prettifyMember_closure: function _prettifyMember_closure() {
+ },
+ _prettifyMember_closure0: function _prettifyMember_closure0() {
+ },
+ StackZoneSpecification: function StackZoneSpecification(t0, t1, t2) {
+ var _ = this;
+ _._chains = t0;
+ _._stack_zone_specification$_onError = t1;
+ _._currentNode = null;
+ _._errorZone = t2;
+ },
+ StackZoneSpecification_chainFor_closure: function StackZoneSpecification_chainFor_closure(t0) {
+ this._box_0 = t0;
+ },
+ StackZoneSpecification_chainFor_closure0: function StackZoneSpecification_chainFor_closure0(t0, t1) {
+ this.$this = t0;
+ this.original = t1;
+ },
+ StackZoneSpecification__registerCallback_closure: function StackZoneSpecification__registerCallback_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _.$this = t0;
+ _.f = t1;
+ _.node = t2;
+ _.R = t3;
+ },
+ StackZoneSpecification__registerUnaryCallback_closure: function StackZoneSpecification__registerUnaryCallback_closure(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _.$this = t0;
+ _.f = t1;
+ _.node = t2;
+ _.T = t3;
+ _.R = t4;
+ },
+ StackZoneSpecification__registerUnaryCallback__closure: function StackZoneSpecification__registerUnaryCallback__closure(t0, t1, t2) {
+ this.f = t0;
+ this.arg = t1;
+ this.R = t2;
+ },
+ StackZoneSpecification__registerBinaryCallback_closure: function StackZoneSpecification__registerBinaryCallback_closure(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _.$this = t0;
+ _.f = t1;
+ _.node = t2;
+ _.T1 = t3;
+ _.T2 = t4;
+ _.R = t5;
+ },
+ StackZoneSpecification__registerBinaryCallback__closure: function StackZoneSpecification__registerBinaryCallback__closure(t0, t1, t2, t3) {
+ var _ = this;
+ _.f = t0;
+ _.arg1 = t1;
+ _.arg2 = t2;
+ _.R = t3;
+ },
+ StackZoneSpecification__currentTrace_closure: function StackZoneSpecification__currentTrace_closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.$this = t1;
+ this.stackTrace = t2;
+ },
+ _Node: function _Node(t0, t1) {
+ this.trace = t0;
+ this.previous = t1;
+ },
+ Group$: function($name, entries, metadata, setUpAll, tearDownAll, trace) {
+ var t1 = P.List_List$unmodifiable(entries, type$.GroupEntry);
+ return new O.Group($name, metadata, trace, t1, setUpAll, tearDownAll);
+ },
+ Group: function Group(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _.name = t0;
+ _.metadata = t1;
+ _.trace = t2;
+ _.entries = t3;
+ _.setUpAll = t4;
+ _.tearDownAll = t5;
+ },
+ Group_forPlatform_closure: function Group_forPlatform_closure(t0) {
+ this.platform = t0;
+ },
+ Group__map_closure: function Group__map_closure(t0) {
+ this.callback = t0;
+ },
+ Group__map_closure0: function Group__map_closure0() {
+ },
+ Metadata__parseOnPlatform: function(onPlatform) {
+ return P.LinkedHashMap_LinkedHashMap$_empty(type$.PlatformSelector, type$.Metadata);
+ },
+ Metadata__parseTags: function(tags) {
+ return P.LinkedHashSet_LinkedHashSet$_empty(type$.String);
+ },
+ Metadata_Metadata: function(chainStackTraces, forTag, onPlatform, retry, skip, skipReason, tags, testOn, timeout, verboseTrace) {
+ var t2, t3, empty, t4, merged, _null = null, t1 = {};
+ t1.tags = tags;
+ t1.forTag = forTag;
+ t2 = new O.Metadata_Metadata__unresolved(t1, testOn, timeout, skip, verboseTrace, chainStackTraces, retry, skipReason, onPlatform);
+ if (forTag == null || tags == null)
+ return t2.call$0();
+ t1.tags = P.LinkedHashSet_LinkedHashSet$from(tags, type$.String);
+ t3 = type$.Metadata;
+ t1.forTag = P.LinkedHashMap_LinkedHashMap$from(t1.forTag, type$.BooleanSelector, t3);
+ empty = O.Metadata$_(_null, _null, _null, _null, _null, _null, _null, _null, _null, _null);
+ t4 = t1.forTag.get$keys();
+ merged = C.JSArray_methods.fold$1$2(P.List_List$from(t4, true, H._instanceType(t4)._eval$1("Iterable.E")), empty, new O.Metadata_Metadata_closure(t1), t3);
+ if (merged === empty)
+ return t2.call$0();
+ return merged.merge$1(t2.call$0());
+ },
+ Metadata$_: function(chainStackTraces, forTag, onPlatform, retry, skip, skipReason, tags, testOn, timeout, verboseTrace) {
+ var t1 = testOn == null ? C.PlatformSelector_All : testOn,
+ t2 = timeout == null ? C.Timeout_null_1 : timeout,
+ t3 = tags == null ? P.LinkedHashSet_LinkedHashSet$_empty(type$.String) : tags.toSet$0(0),
+ t4 = onPlatform == null ? C.Map_empty : new P.UnmodifiableMapView(onPlatform, type$.UnmodifiableMapView_PlatformSelector_Metadata),
+ t5 = forTag == null ? C.Map_empty0 : new P.UnmodifiableMapView(forTag, type$.UnmodifiableMapView_BooleanSelector_Metadata);
+ t5 = new O.Metadata(t1, t2, skip, skipReason, verboseTrace, chainStackTraces, new L.UnmodifiableSetView(t3, type$.UnmodifiableSetView_String), retry, t4, t5);
+ if (retry != null)
+ P.RangeError_checkNotNegative(retry, "retry");
+ t5._validateTags$0();
+ return t5;
+ },
+ Metadata$parse: function(onPlatform, retry, skip, tags, testOn, timeout) {
+ var _null = null,
+ t1 = timeout == null ? C.Timeout_null_1 : timeout,
+ t2 = skip == null,
+ t3 = t2 ? _null : skip,
+ t4 = O.Metadata__parseOnPlatform(onPlatform);
+ t4 = new O.Metadata(C.PlatformSelector_All, t1, t3, _null, _null, _null, O.Metadata__parseTags(tags), retry, t4, C.Map_empty0);
+ !t2;
+ if (retry != null)
+ P.RangeError_checkNotNegative(retry, "retry");
+ t4._validateTags$0();
+ return t4;
+ },
+ Metadata$deserialize: function(serialized) {
+ var pair, t13,
+ t1 = J.getInterceptor$asx(serialized),
+ t2 = t1.$index(serialized, "testOn") == null ? C.PlatformSelector_All : E.PlatformSelector$parse(H._asStringNullable(t1.$index(serialized, "testOn"))),
+ t3 = O.Metadata__deserializeTimeout(t1.$index(serialized, "timeout")),
+ t4 = H._asBoolNullable(t1.$index(serialized, "skip")),
+ t5 = H._asStringNullable(t1.$index(serialized, "skipReason")),
+ t6 = H._asBoolNullable(t1.$index(serialized, "verboseTrace")),
+ t7 = H._asBoolNullable(t1.$index(serialized, "chainStackTraces")),
+ t8 = H._asIntNullable(t1.$index(serialized, "retry")),
+ t9 = type$.Iterable_dynamic,
+ t10 = P.LinkedHashSet_LinkedHashSet$from(t9._as(t1.$index(serialized, "tags")), type$.String),
+ t11 = type$.Metadata,
+ t12 = P.LinkedHashMap_LinkedHashMap$_empty(type$.PlatformSelector, t11);
+ for (t9 = J.get$iterator$ax(t9._check(t1.$index(serialized, "onPlatform"))); t9.moveNext$0();) {
+ pair = t9.get$current();
+ t13 = J.getInterceptor$ax(pair);
+ t12.$indexSet(0, E.PlatformSelector$parse(H._asStringNullable(t13.get$first(pair))), O.Metadata$deserialize(t13.get$last(pair)));
+ }
+ return new O.Metadata(t2, t3, t4, t5, t6, t7, t10, t8, t12, type$.Map_dynamic_dynamic._as(t1.$index(serialized, "forTag")).map$2$1(0, new O.Metadata$deserialize_closure(), type$.BooleanSelector, t11));
+ },
+ Metadata__deserializeTimeout: function(serialized) {
+ var scaleFactor,
+ t1 = J.getInterceptor$(serialized);
+ if (t1.$eq(serialized, "none"))
+ return C.Timeout_null_null;
+ scaleFactor = t1.$index(serialized, "scaleFactor");
+ if (scaleFactor != null)
+ return new R.Timeout(null, H._asNumNullable(scaleFactor));
+ return new R.Timeout(P.Duration$(H._asIntNullable(t1.$index(serialized, "duration")), 0), null);
+ },
+ Metadata: function Metadata(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) {
+ var _ = this;
+ _.testOn = t0;
+ _.timeout = t1;
+ _._skip = t2;
+ _.skipReason = t3;
+ _._verboseTrace = t4;
+ _._chainStackTraces = t5;
+ _.tags = t6;
+ _._retry = t7;
+ _.onPlatform = t8;
+ _.forTag = t9;
+ },
+ Metadata_Metadata__unresolved: function Metadata_Metadata__unresolved(t0, t1, t2, t3, t4, t5, t6, t7, t8) {
+ var _ = this;
+ _._box_0 = t0;
+ _.testOn = t1;
+ _.timeout = t2;
+ _.skip = t3;
+ _.verboseTrace = t4;
+ _.chainStackTraces = t5;
+ _.retry = t6;
+ _.skipReason = t7;
+ _.onPlatform = t8;
+ },
+ Metadata_Metadata_closure: function Metadata_Metadata_closure(t0) {
+ this._box_0 = t0;
+ },
+ Metadata$deserialize_closure: function Metadata$deserialize_closure() {
+ },
+ Metadata__validateTags_closure: function Metadata__validateTags_closure() {
+ },
+ Metadata__validateTags_closure0: function Metadata__validateTags_closure0() {
+ },
+ Metadata_validatePlatformSelectors_closure: function Metadata_validatePlatformSelectors_closure(t0) {
+ this.validVariables = t0;
+ },
+ Metadata_merge_closure: function Metadata_merge_closure() {
+ },
+ Metadata_merge_closure0: function Metadata_merge_closure0() {
+ },
+ Metadata_forPlatform_closure: function Metadata_forPlatform_closure(t0, t1) {
+ this._box_0 = t0;
+ this.platform = t1;
+ },
+ Metadata_serialize_closure: function Metadata_serialize_closure(t0) {
+ this.serializedOnPlatform = t0;
+ },
+ Metadata_serialize_closure0: function Metadata_serialize_closure0() {
+ },
+ IterableSet: function IterableSet(t0, t1) {
+ this._iterable_set$_base = t0;
+ this.$ti = t1;
+ },
+ _IterableSet_SetMixin_UnmodifiableSetMixin: function _IterableSet_SetMixin_UnmodifiableSetMixin() {
+ },
+ Engine$: function() {
+ var t6, t7, t8, t9, t10, t11, _null = null,
+ t1 = $.Zone__current,
+ t2 = H.setRuntimeTypeInfo([], type$.JSArray_dynamic),
+ t3 = type$.RunnerSuite,
+ t4 = P.StreamController_StreamController(_null, _null, false, t3),
+ t5 = new L.StreamGroup(C._StreamGroupState_dormant, new H.JsLinkedHashMap(type$.JsLinkedHashMap_of_Stream_LiveTest_and_StreamSubscription_LiveTest), type$.StreamGroup_LiveTest);
+ t5.set$_stream_group$_controller(new P._SyncBroadcastStreamController(t5.get$_onListen(), t5.get$_onCancelBroadcast(), type$._SyncBroadcastStreamController_LiveTest));
+ t6 = type$.LiveTest;
+ t7 = Y.UnionSetController$(true, t6);
+ t8 = Y.UnionSetController$(true, t6);
+ t9 = Y.UnionSetController$(true, t6);
+ t10 = Q.QueueList$(t6);
+ t11 = O.Pool$(1);
+ t1 = new O.Engine(t11, O.Pool$(2), new F.FutureGroup(new P._AsyncCompleter(new P._Future(t1, type$._Future_List_dynamic), type$._AsyncCompleter_List_dynamic), t2, type$.FutureGroup_dynamic), P.LinkedHashSet_LinkedHashSet$_empty(type$.StreamSubscription_dynamic), t4, P.LinkedHashSet_LinkedHashSet$_empty(t3), new P._AsyncBroadcastStreamController(_null, _null, type$._AsyncBroadcastStreamController_RunnerSuite), P.LinkedHashSet_LinkedHashSet$_empty(type$.LiveSuite), new P._AsyncBroadcastStreamController(_null, _null, type$._AsyncBroadcastStreamController_LiveSuite), t5, t7, t8, t9, t10, P.LinkedHashSet_LinkedHashSet$_empty(t6), P.LinkedHashSet_LinkedHashSet$_empty(t6));
+ t1.Engine$3$concurrency$coverage$maxSuites(_null, _null, _null);
+ return t1;
+ },
+ Engine: function Engine(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) {
+ var _ = this;
+ _._engine$_closed = _._engine$_runCalled = false;
+ _._closedBeforeDone = null;
+ _._runPool = t0;
+ _._loadPool = t1;
+ _._group = t2;
+ _._engine$_subscriptions = t3;
+ _._suiteController = t4;
+ _._addedSuites = t5;
+ _._onSuiteAddedController = t6;
+ _._liveSuites = t7;
+ _._onSuiteStartedController = t8;
+ _._onTestStartedGroup = t9;
+ _._passedGroup = t10;
+ _._skippedGroup = t11;
+ _._failedGroup = t12;
+ _._active = t13;
+ _._restarted = t14;
+ _._activeLoadTests = t15;
+ },
+ Engine_success_closure: function Engine_success_closure() {
+ },
+ Engine_closure: function Engine_closure(t0) {
+ this.$this = t0;
+ },
+ Engine_closure0: function Engine_closure0() {
+ },
+ Engine_run_closure: function Engine_run_closure(t0) {
+ this.$this = t0;
+ },
+ Engine_run__closure: function Engine_run__closure(t0, t1) {
+ this.$this = t0;
+ this.suite = t1;
+ },
+ Engine_run___closure: function Engine_run___closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.$this = t1;
+ this.loadResource = t2;
+ },
+ Engine_run____closure: function Engine_run____closure(t0) {
+ this._box_0 = t0;
+ },
+ Engine_run_closure0: function Engine_run_closure0(t0, t1) {
+ this._box_1 = t0;
+ this.$this = t1;
+ },
+ Engine__runLiveTest_closure: function Engine__runLiveTest_closure(t0, t1) {
+ this.$this = t0;
+ this.liveTest = t1;
+ },
+ Engine__runLiveTest_closure0: function Engine__runLiveTest_closure0(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ Engine__runLiveTest_closure1: function Engine__runLiveTest_closure1() {
+ },
+ Engine__runSkippedTest_closure: function Engine__runSkippedTest_closure() {
+ },
+ Engine__runSkippedTest_closure0: function Engine__runSkippedTest_closure0(t0, t1) {
+ this._box_0 = t0;
+ this.skipped = t1;
+ },
+ Engine__runSkippedTest_closure1: function Engine__runSkippedTest_closure1() {
+ },
+ binarySearch: function(list, matches) {
+ var max, min, half;
+ if (list.length === 0)
+ return -1;
+ if (H.boolConversionCheck(matches.call$1(C.JSArray_methods.get$first(list))))
+ return 0;
+ if (!H.boolConversionCheck(matches.call$1(C.JSArray_methods.get$last(list))))
+ return list.length;
+ max = list.length - 1;
+ for (min = 0; min < max;) {
+ half = min + C.JSInt_methods._tdivFast$1(max - min, 2);
+ if (half < 0 || half >= list.length)
+ return H.ioore(list, half);
+ if (H.boolConversionCheck(matches.call$1(list[half])))
+ max = half;
+ else
+ min = half + 1;
+ }
+ return max;
+ }
+ },
+ Y = {DelegatingStreamSubscription: function DelegatingStreamSubscription() {
+ }, StreamCompleter: function StreamCompleter(t0, t1) {
+ this._stream = t0;
+ this.$ti = t1;
+ }, _CompleterStream: function _CompleterStream(t0) {
+ this._sourceStream = this._stream_completer$_controller = null;
+ this.$ti = t0;
+ }, BooleanSelectorImpl: function BooleanSelectorImpl(t0) {
+ this._selector = t0;
+ },
+ mapMap: function(map, value, K1, V1, K2, V2) {
+ var key, result, t1 = {};
+ t1.key = key;
+ t1.value = value;
+ t1.key = null;
+ t1.key = new Y.mapMap_closure(K2, K1, V1);
+ result = P.LinkedHashMap_LinkedHashMap$_empty(K2, V2);
+ map.forEach$1(0, new Y.mapMap_closure0(t1, result, K1, V1));
+ return result;
+ },
+ mergeMaps: function(map1, map2, value, $K, $V) {
+ var result = P.LinkedHashMap_LinkedHashMap$from(map1, $K, $V);
+ map2.forEach$1(0, new Y.mergeMaps_closure(result, value, $K, $V));
+ return result;
+ },
+ mapMap_closure: function mapMap_closure(t0, t1, t2) {
+ this.K2 = t0;
+ this.K1 = t1;
+ this.V1 = t2;
+ },
+ mapMap_closure0: function mapMap_closure0(t0, t1, t2, t3) {
+ var _ = this;
+ _._box_0 = t0;
+ _.result = t1;
+ _.K1 = t2;
+ _.V1 = t3;
+ },
+ mergeMaps_closure: function mergeMaps_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _.result = t0;
+ _.value = t1;
+ _.K = t2;
+ _.V = t3;
+ },
+ UnionSetController$: function(disjoint, $E) {
+ var t1 = P.LinkedHashSet_LinkedHashSet($E._eval$1("Set<0>")),
+ t2 = new Y.UnionSetController(t1, $E._eval$1("UnionSetController<0>"));
+ t2.set$_union_set_controller$_set(new M.UnionSet(t1, true, $E._eval$1("UnionSet<0>")));
+ return t2;
+ },
+ UnionSetController: function UnionSetController(t0, t1) {
+ this._union_set_controller$_set = null;
+ this._union_set_controller$_sets = t0;
+ this.$ti = t1;
+ },
+ _IsTrue: function _IsTrue() {
+ },
+ _Predicate: function _Predicate(t0, t1, t2) {
+ this._matcher = t0;
+ this._core_matchers$_description = t1;
+ this.$ti = t2;
+ },
+ FileLocation$_: function(file, offset) {
+ if (offset < 0)
+ H.throwExpression(P.RangeError$("Offset may not be negative, was " + offset + "."));
+ else if (offset > file._decodedChars.length)
+ H.throwExpression(P.RangeError$("Offset " + offset + " must not be greater than the number of characters in the file, " + file.get$length(file) + "."));
+ return new Y.FileLocation(file, offset);
+ },
+ _FileSpan$: function(file, _start, _end) {
+ if (_end < _start)
+ H.throwExpression(P.ArgumentError$("End " + _end + " must come after start " + _start + "."));
+ else if (_end > file._decodedChars.length)
+ H.throwExpression(P.RangeError$("End " + _end + " must not be greater than the number of characters in the file, " + file.get$length(file) + "."));
+ else if (_start < 0)
+ H.throwExpression(P.RangeError$("Start may not be negative, was " + _start + "."));
+ return new Y._FileSpan(file, _start, _end);
+ },
+ SourceFile: function SourceFile(t0, t1, t2) {
+ var _ = this;
+ _.url = t0;
+ _._lineStarts = t1;
+ _._decodedChars = t2;
+ _._cachedLine = null;
+ },
+ FileLocation: function FileLocation(t0, t1) {
+ this.file = t0;
+ this.offset = t1;
+ },
+ _FileSpan: function _FileSpan(t0, t1, t2) {
+ this.file = t0;
+ this._file$_start = t1;
+ this._file$_end = t2;
+ },
+ SourceSpanMixin: function SourceSpanMixin() {
+ },
+ Trace_Trace$current: function(level) {
+ return new T.LazyTrace(new Y.Trace_Trace$current_closure(Y.Trace_Trace$from(P.StackTrace_current()), level));
+ },
+ Trace_Trace$from: function(trace) {
+ if (trace == null)
+ throw H.wrapException(P.ArgumentError$("Cannot create a Trace from null."));
+ if (type$.Trace._is(trace))
+ return trace;
+ if (type$.Chain._is(trace))
+ return trace.toTrace$0();
+ return new T.LazyTrace(new Y.Trace_Trace$from_closure(trace));
+ },
+ Trace_Trace$parse: function(trace) {
+ var error, t1, exception;
+ try {
+ if (trace.length === 0) {
+ t1 = P.List_List$unmodifiable(H.setRuntimeTypeInfo([], type$.JSArray_Frame), type$.Frame);
+ return new Y.Trace(t1, new P._StringStackTrace(null));
+ }
+ if (C.JSString_methods.contains$1(trace, $.$get$_v8Trace())) {
+ t1 = Y.Trace$parseV8(trace);
+ return t1;
+ }
+ if (C.JSString_methods.contains$1(trace, "\tat ")) {
+ t1 = Y.Trace$parseJSCore(trace);
+ return t1;
+ }
+ if (C.JSString_methods.contains$1(trace, $.$get$_firefoxSafariTrace())) {
+ t1 = Y.Trace$parseFirefox(trace);
+ return t1;
+ }
+ if (C.JSString_methods.contains$1(trace, "===== asynchronous gap ===========================\n")) {
+ t1 = U.Chain_Chain$parse(trace).toTrace$0();
+ return t1;
+ }
+ if (C.JSString_methods.contains$1(trace, $.$get$_friendlyTrace())) {
+ t1 = Y.Trace$parseFriendly(trace);
+ return t1;
+ }
+ t1 = P.List_List$unmodifiable(Y.Trace__parseVM(trace), type$.Frame);
+ return new Y.Trace(t1, new P._StringStackTrace(trace));
+ } catch (exception) {
+ t1 = H.unwrapException(exception);
+ if (type$.FormatException._is(t1)) {
+ error = t1;
+ throw H.wrapException(P.FormatException$(H.S(J.get$message$x(error)) + "\nStack trace:\n" + H.S(trace), null, null));
+ } else
+ throw exception;
+ }
+ },
+ Trace__parseVM: function(trace) {
+ var t2, $frames,
+ t1 = J.trim$0$s(trace),
+ lines = H.setRuntimeTypeInfo(H.stringReplaceAllUnchecked(t1, "<asynchronous suspension>\n", "").split("\n"), type$.JSArray_String);
+ t1 = H.SubListIterable$(lines, 0, lines.length - 1, type$.String);
+ t2 = t1.$ti;
+ $frames = new H.MappedListIterable(t1, t2._eval$1("Frame(ListIterable.E)")._check(new Y.Trace__parseVM_closure()), t2._eval$1("MappedListIterable<ListIterable.E,Frame>")).toList$0(0);
+ if (!J.endsWith$1$s(C.JSArray_methods.get$last(lines), ".da"))
+ C.JSArray_methods.add$1($frames, A.Frame_Frame$parseVM(C.JSArray_methods.get$last(lines)));
+ return $frames;
+ },
+ Trace$parseV8: function(trace) {
+ var t2, t3,
+ t1 = H.SubListIterable$(H.setRuntimeTypeInfo(trace.split("\n"), type$.JSArray_String), 1, null, type$.String);
+ t1 = t1.super$Iterable$skipWhile(0, t1.$ti._eval$1("bool(ListIterable.E)")._check(new Y.Trace$parseV8_closure()));
+ t2 = type$.Frame;
+ t3 = t1.$ti;
+ return new Y.Trace(P.List_List$unmodifiable(H.MappedIterable_MappedIterable(t1, t3._eval$1("Frame(Iterable.E)")._check(new Y.Trace$parseV8_closure0()), t3._eval$1("Iterable.E"), t2), t2), new P._StringStackTrace(trace));
+ },
+ Trace$parseJSCore: function(trace) {
+ return new Y.Trace(P.List_List$unmodifiable(new H.MappedIterable(new H.WhereIterable(H.setRuntimeTypeInfo(trace.split("\n"), type$.JSArray_String), type$.bool_Function_String._check(new Y.Trace$parseJSCore_closure()), type$.WhereIterable_String), type$.Frame_Function_String._check(new Y.Trace$parseJSCore_closure0()), type$.MappedIterable_String_Frame), type$.Frame), new P._StringStackTrace(trace));
+ },
+ Trace$parseFirefox: function(trace) {
+ return new Y.Trace(P.List_List$unmodifiable(new H.MappedIterable(new H.WhereIterable(H.setRuntimeTypeInfo(C.JSString_methods.trim$0(trace).split("\n"), type$.JSArray_String), type$.bool_Function_String._check(new Y.Trace$parseFirefox_closure()), type$.WhereIterable_String), type$.Frame_Function_String._check(new Y.Trace$parseFirefox_closure0()), type$.MappedIterable_String_Frame), type$.Frame), new P._StringStackTrace(trace));
+ },
+ Trace$parseFriendly: function(trace) {
+ var t1 = trace.length === 0 ? H.setRuntimeTypeInfo([], type$.JSArray_Frame) : new H.MappedIterable(new H.WhereIterable(H.setRuntimeTypeInfo(C.JSString_methods.trim$0(trace).split("\n"), type$.JSArray_String), type$.bool_Function_String._check(new Y.Trace$parseFriendly_closure()), type$.WhereIterable_String), type$.Frame_Function_String._check(new Y.Trace$parseFriendly_closure0()), type$.MappedIterable_String_Frame);
+ return new Y.Trace(P.List_List$unmodifiable(t1, type$.Frame), new P._StringStackTrace(trace));
+ },
+ Trace: function Trace(t0, t1) {
+ this.frames = t0;
+ this.original = t1;
+ },
+ Trace_Trace$current_closure: function Trace_Trace$current_closure(t0, t1) {
+ this.trace = t0;
+ this.level = t1;
+ },
+ Trace_Trace$from_closure: function Trace_Trace$from_closure(t0) {
+ this.trace = t0;
+ },
+ Trace__parseVM_closure: function Trace__parseVM_closure() {
+ },
+ Trace$parseV8_closure: function Trace$parseV8_closure() {
+ },
+ Trace$parseV8_closure0: function Trace$parseV8_closure0() {
+ },
+ Trace$parseJSCore_closure: function Trace$parseJSCore_closure() {
+ },
+ Trace$parseJSCore_closure0: function Trace$parseJSCore_closure0() {
+ },
+ Trace$parseFirefox_closure: function Trace$parseFirefox_closure() {
+ },
+ Trace$parseFirefox_closure0: function Trace$parseFirefox_closure0() {
+ },
+ Trace$parseFriendly_closure: function Trace$parseFriendly_closure() {
+ },
+ Trace$parseFriendly_closure0: function Trace$parseFriendly_closure0() {
+ },
+ Trace_foldFrames_closure: function Trace_foldFrames_closure(t0) {
+ this.oldPredicate = t0;
+ },
+ Trace_foldFrames_closure0: function Trace_foldFrames_closure0(t0) {
+ this._box_0 = t0;
+ },
+ Trace_toString_closure0: function Trace_toString_closure0() {
+ },
+ Trace_toString_closure: function Trace_toString_closure(t0) {
+ this.longest = t0;
+ },
+ RunnerSuite: function RunnerSuite(t0, t1, t2, t3) {
+ var _ = this;
+ _._runner_suite$_controller = t0;
+ _.platform = t1;
+ _.path = t2;
+ _.group = t3;
+ },
+ RunnerSuiteController: function RunnerSuiteController(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._config = t0;
+ _._runner_suite$_onClose = t1;
+ _._onDebuggingController = t2;
+ _._channelNames = t3;
+ _._closeMemo = t4;
+ },
+ RunnerSuiteController__close_closure: function RunnerSuiteController__close_closure(t0) {
+ this.$this = t0;
+ }
+ },
+ F = {FutureGroup: function FutureGroup(t0, t1, t2) {
+ var _ = this;
+ _._future_group$_pending = 0;
+ _._future_group$_closed = false;
+ _._future_group$_completer = t0;
+ _._values = t1;
+ _.$ti = t2;
+ }, FutureGroup_add_closure: function FutureGroup_add_closure(t0, t1) {
+ this.$this = t0;
+ this.index = t1;
+ }, FutureGroup_add_closure0: function FutureGroup_add_closure0(t0) {
+ this.$this = t0;
+ }, ValueResult: function ValueResult(t0, t1) {
+ this.value = t0;
+ this.$ti = t1;
+ },
+ PackageConfigResolver__normalizeMap: function(map) {
+ var t1 = type$.String,
+ t2 = type$.Uri;
+ return new P.UnmodifiableMapView(Y.mapMap(map, new F.PackageConfigResolver__normalizeMap_closure(), t1, t2, t1, t2), type$.UnmodifiableMapView_String_Uri);
+ },
+ PackageConfigResolver: function PackageConfigResolver(t0) {
+ this.packageConfigMap = t0;
+ },
+ PackageConfigResolver__normalizeMap_closure: function PackageConfigResolver__normalizeMap_closure() {
+ },
+ UrlStyle: function UrlStyle(t0, t1, t2, t3) {
+ var _ = this;
+ _.separatorPattern = t0;
+ _.needsSeparatorPattern = t1;
+ _.rootPattern = t2;
+ _.relativeRootPattern = t3;
+ }
+ },
+ V = {ErrorResult: function ErrorResult(t0, t1) {
+ this.error = t0;
+ this.stackTrace = t1;
+ },
+ SourceLocation$: function(offset, column, line, sourceUrl) {
+ var t2, t3, t4, t5,
+ t1 = typeof sourceUrl == "string" ? P.Uri_parse(sourceUrl) : sourceUrl;
+ type$.Uri._check(t1);
+ t2 = line == null;
+ t3 = t2 ? 0 : line;
+ t4 = column == null;
+ t5 = t4 ? offset : column;
+ if (offset < 0)
+ H.throwExpression(P.RangeError$("Offset may not be negative, was " + offset + "."));
+ else if (!t2 && line < 0)
+ H.throwExpression(P.RangeError$("Line may not be negative, was " + H.S(line) + "."));
+ else if (!t4 && column < 0)
+ H.throwExpression(P.RangeError$("Column may not be negative, was " + H.S(column) + "."));
+ return new V.SourceLocation(t1, offset, t3, t5);
+ },
+ SourceLocation: function SourceLocation(t0, t1, t2, t3) {
+ var _ = this;
+ _.sourceUrl = t0;
+ _.offset = t1;
+ _.line = t2;
+ _.column = t3;
+ },
+ SourceSpan: function SourceSpan() {
+ },
+ SourceSpanBase: function SourceSpanBase() {
+ },
+ GroupEntry: function GroupEntry() {
+ },
+ LiveTestController$: function(suite, _test, onRun, onClose, groups) {
+ var _null = null,
+ t1 = H.setRuntimeTypeInfo([], type$.JSArray_AsyncError),
+ t2 = $.Zone__current,
+ t3 = P.List_List$unmodifiable(groups, type$.Group);
+ t1 = new V.LiveTestController(suite, t3, _test, onRun, onClose, t1, C.State_Status_pending_Result_success, new P._SyncBroadcastStreamController(_null, _null, type$._SyncBroadcastStreamController_State), new P._SyncBroadcastStreamController(_null, _null, type$._SyncBroadcastStreamController_AsyncError), new P._SyncBroadcastStreamController(_null, _null, type$._SyncBroadcastStreamController_Message), new P._AsyncCompleter(new P._Future(t2, type$._Future_void), type$._AsyncCompleter_void));
+ t1._liveTest = new V._LiveTest(t1);
+ return t1;
+ },
+ _LiveTest: function _LiveTest(t0) {
+ this._live_test_controller$_controller = t0;
+ },
+ LiveTestController: function LiveTestController(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) {
+ var _ = this;
+ _._liveTest = null;
+ _._live_test_controller$_suite = t0;
+ _._groups = t1;
+ _._test = t2;
+ _._onRun = t3;
+ _._onClose = t4;
+ _._errors = t5;
+ _._live_test_controller$_state = t6;
+ _._onStateChangeController = t7;
+ _._onErrorController = t8;
+ _._onMessageController = t9;
+ _.completer = t10;
+ _._runCalled = false;
+ },
+ Test: function Test() {
+ },
+ errorsDontStopTest: function(body) {
+ var t1 = $.Zone__current,
+ t2 = new P._Future(t1, type$._Future_dynamic),
+ t3 = type$.Invoker;
+ t3._as(t1.$index(0, C.Symbol_cQL)).addOutstandingCallback$0();
+ t3._as($.Zone__current.$index(0, C.Symbol_cQL)).waitForOutstandingCallbacks$1(new V.errorsDontStopTest_closure(body, new P._AsyncCompleter(t2, type$._AsyncCompleter_dynamic))).then$1$1(new V.errorsDontStopTest_closure0(), type$.void);
+ return t2;
+ },
+ errorsDontStopTest_closure: function errorsDontStopTest_closure(t0, t1) {
+ this.body = t0;
+ this.completer = t1;
+ },
+ errorsDontStopTest_closure0: function errorsDontStopTest_closure0() {
+ }
+ },
+ E = {Result: function Result() {
+ }, StringDescription: function StringDescription(t0) {
+ this._out = t0;
+ }, FeatureMatcher: function FeatureMatcher() {
+ }, PosixStyle: function PosixStyle(t0, t1, t2) {
+ this.separatorPattern = t0;
+ this.needsSeparatorPattern = t1;
+ this.rootPattern = t2;
+ },
+ StringScannerException$: function(message, span, source) {
+ return new E.StringScannerException(message, span);
+ },
+ StringScannerException: function StringScannerException(t0, t1) {
+ this._span_exception$_message = t0;
+ this._span_exception$_span = t1;
+ },
+ PlatformSelector$parse: function(selector) {
+ return new E.PlatformSelector(E.PlatformSelector__wrapFormatException(new E.PlatformSelector$parse_closure(selector), null, type$.BooleanSelector));
+ },
+ PlatformSelector__wrapFormatException: function(body, span, $T) {
+ var t1 = body.call$0();
+ return t1;
+ },
+ PlatformSelector: function PlatformSelector(t0) {
+ this._platform_selector$_inner = t0;
+ },
+ PlatformSelector$parse_closure: function PlatformSelector$parse_closure(t0) {
+ this.selector = t0;
+ },
+ PlatformSelector_validate_closure: function PlatformSelector_validate_closure(t0, t1) {
+ this.$this = t0;
+ this.validVariables = t1;
+ },
+ PlatformSelector_validate__closure: function PlatformSelector_validate__closure(t0) {
+ this.validVariables = t0;
+ },
+ PlatformSelector_evaluate_closure: function PlatformSelector_evaluate_closure(t0) {
+ this.platform = t0;
+ },
+ SuitePlatform$: function(runtime, inGoogle, os) {
+ var t1 = os == null ? C.OperatingSystem_none_none : os;
+ if (H.boolConversionCheck(runtime.isBrowser) && t1 !== C.OperatingSystem_none_none)
+ H.throwExpression(P.ArgumentError$('No OS should be passed for runtime "' + runtime.toString$0(0) + '".'));
+ return new E.SuitePlatform(runtime, t1, inGoogle);
+ },
+ SuitePlatform: function SuitePlatform(t0, t1, t2) {
+ this.runtime = t0;
+ this.os = t1;
+ this.inGoogle = t2;
+ },
+ StackTraceMapper: function StackTraceMapper() {
+ },
+ LiveSuite: function LiveSuite() {
+ },
+ JSStackTraceMapper_deserialize: function(serialized) {
+ var t1, t2, t3,
+ _s11_ = "packageRoot",
+ packageRoot = H._asStringNullable(serialized.$index(0, _s11_));
+ if (packageRoot == null)
+ packageRoot = "";
+ t1 = H._asStringNullable(serialized.$index(0, "mapContents"));
+ t2 = P.Uri_parse(H._asStringNullable(serialized.$index(0, "sdkRoot")));
+ if (packageRoot.length !== 0)
+ t3 = new D.PackageRootResolver(B.ensureTrailingSlash(B.asUri(P.Uri_parse(H._asStringNullable(serialized.$index(0, _s11_))), _s11_)));
+ else {
+ t3 = type$.String;
+ t3 = F.PackageConfigResolver__normalizeMap(E.JSStackTraceMapper__deserializePackageConfigMap(type$.Map_dynamic_dynamic._as(serialized.$index(0, "packageConfigMap")).cast$2$0(0, t3, t3)));
+ t3 = new F.PackageConfigResolver(t3);
+ }
+ return new E.JSStackTraceMapper(t3, t2, t1, P.Uri_parse(H._asStringNullable(serialized.$index(0, "mapUrl"))));
+ },
+ JSStackTraceMapper__deserializePackageConfigMap: function(serialized) {
+ return serialized.map$2$1(0, new E.JSStackTraceMapper__deserializePackageConfigMap_closure(), type$.String, type$.Uri);
+ },
+ JSStackTraceMapper: function JSStackTraceMapper(t0, t1, t2, t3) {
+ var _ = this;
+ _._mapping = null;
+ _._packageResolver = t0;
+ _._sdkRoot = t1;
+ _._mapContents = t2;
+ _._mapUrl = t3;
+ },
+ JSStackTraceMapper__deserializePackageConfigMap_closure: function JSStackTraceMapper__deserializePackageConfigMap_closure() {
+ }
+ },
+ L = {StreamGroup: function StreamGroup(t0, t1, t2) {
+ var _ = this;
+ _._stream_group$_controller = null;
+ _._stream_group$_closed = false;
+ _._stream_group$_state = t0;
+ _._stream_group$_subscriptions = t1;
+ _.$ti = t2;
+ }, StreamGroup_add_closure: function StreamGroup_add_closure() {
+ }, StreamGroup_add_closure0: function StreamGroup_add_closure0(t0, t1) {
+ this.$this = t0;
+ this.stream = t1;
+ }, StreamGroup__onListen_closure: function StreamGroup__onListen_closure(t0) {
+ this.$this = t0;
+ }, StreamGroup__onCancelBroadcast_closure: function StreamGroup__onCancelBroadcast_closure(t0) {
+ this.$this = t0;
+ }, StreamGroup__listenToStream_closure: function StreamGroup__listenToStream_closure(t0, t1) {
+ this.$this = t0;
+ this.stream = t1;
+ }, _StreamGroupState: function _StreamGroupState(t0) {
+ this.name = t0;
+ }, Token: function Token(t0, t1) {
+ this.type = t0;
+ this.span = t1;
+ }, IdentifierToken: function IdentifierToken(t0, t1) {
+ this.span = t0;
+ this.name = t1;
+ }, TokenType: function TokenType(t0) {
+ this.name = t0;
+ },
+ UnmodifiableSetView$: function(setBase, $E) {
+ return new L.UnmodifiableSetView(setBase, $E._eval$1("UnmodifiableSetView<0>"));
+ },
+ UnmodifiableSetView: function UnmodifiableSetView(t0, t1) {
+ this._base = t0;
+ this.$ti = t1;
+ },
+ UnmodifiableSetMixin: function UnmodifiableSetMixin() {
+ },
+ _UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin: function _UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin() {
+ },
+ WindowsStyle: function WindowsStyle(t0, t1, t2, t3) {
+ var _ = this;
+ _.separatorPattern = t0;
+ _.needsSeparatorPattern = t1;
+ _.rootPattern = t2;
+ _.relativeRootPattern = t3;
+ },
+ WindowsStyle_absolutePathToUri_closure: function WindowsStyle_absolutePathToUri_closure() {
+ },
+ decodeVlq: function(chars) {
+ var t1, t2, result, $stop, shift, t3, char, digit, result0, _null = null;
+ for (t1 = chars._parser$_length, t2 = chars._internal, result = 0, $stop = false, shift = 0; !$stop;) {
+ t3 = ++chars.index;
+ if (t3 >= t1)
+ throw H.wrapException(P.StateError$("incomplete VLQ value"));
+ if (t3 >= 0 && true) {
+ if (t3 < 0 || t3 >= t2.length)
+ return H.ioore(t2, t3);
+ char = t2[t3];
+ } else
+ char = _null;
+ t3 = $.$get$_digits();
+ if (!t3.containsKey$1(char))
+ throw H.wrapException(P.FormatException$("invalid character in VLQ encoding: " + H.S(char), _null, _null));
+ digit = t3.$index(0, char);
+ if (typeof digit !== "number")
+ return digit.$and();
+ $stop = (digit & 32) === 0;
+ result += C.JSInt_methods._shlPositive$1(digit & 31, shift);
+ shift += 5;
+ }
+ result0 = result >>> 1;
+ result = (result & 1) === 1 ? -result0 : result0;
+ if (result < $.$get$MIN_INT32() || result > $.$get$MAX_INT32())
+ throw H.wrapException(P.FormatException$("expected an encoded 32 bit int, but we got: " + result, _null, _null));
+ return result;
+ },
+ closure: function closure() {
+ },
+ internalBootstrapBrowserTest: function(getMain) {
+ var t2,
+ channel = S.RemoteListener_start(getMain, new L.internalBootstrapBrowserTest_closure(), false),
+ t1 = N.postMessageChannel();
+ t1.$ti._eval$1("StreamChannel<1>")._check(channel);
+ t1.get$stream(t1).pipe$1(channel._sink);
+ t2 = channel._streamController;
+ t2.toString;
+ new P._ControllerStream(t2, H._instanceType(t2)._eval$1("_ControllerStream<1>")).pipe$1(t1.get$sink());
+ },
+ internalBootstrapBrowserTest_closure: function internalBootstrapBrowserTest_closure() {
+ }
+ },
+ G = {StreamQueue: function StreamQueue(t0, t1, t2, t3) {
+ var _ = this;
+ _._stream_queue$_source = t0;
+ _._stream_queue$_subscription = null;
+ _._isClosed = _._isDone = false;
+ _._eventsReceived = 0;
+ _._eventQueue = t1;
+ _._requestQueue = t2;
+ _.$ti = t3;
+ }, StreamQueue__ensureListening_closure: function StreamQueue__ensureListening_closure(t0) {
+ this.$this = t0;
+ }, StreamQueue__ensureListening_closure1: function StreamQueue__ensureListening_closure1(t0) {
+ this.$this = t0;
+ }, StreamQueue__ensureListening_closure0: function StreamQueue__ensureListening_closure0(t0) {
+ this.$this = t0;
+ }, _EventRequest: function _EventRequest() {
+ }, _NextRequest: function _NextRequest(t0, t1) {
+ this._completer = t0;
+ this.$ti = t1;
+ }, _RestRequest: function _RestRequest(t0, t1, t2) {
+ this._completer = t0;
+ this._streamQueue = t1;
+ this.$ti = t2;
+ }, Parser: function Parser(t0) {
+ this._parser0$_scanner = t0;
+ }, Matcher: function Matcher() {
+ }, SourceMapSpan: function SourceMapSpan(t0, t1, t2, t3) {
+ var _ = this;
+ _.isIdentifier = t0;
+ _.start = t1;
+ _.end = t2;
+ _.text = t3;
+ },
+ SourceSpanFormatException$: function(message, span, _source) {
+ return new G.SourceSpanFormatException(message, span);
+ },
+ SourceSpanException: function SourceSpanException() {
+ },
+ SourceSpanFormatException: function SourceSpanFormatException(t0, t1) {
+ this._span_exception$_message = t0;
+ this._span_exception$_span = t1;
+ },
+ State: function State(t0, t1) {
+ this.status = t0;
+ this.result = t1;
+ },
+ Status: function Status(t0) {
+ this.name = t0;
+ },
+ Result0: function Result0(t0) {
+ this.name = t0;
+ },
+ expect: function(actual, matcher, reason) {
+ G._expect(true, matcher, null, reason, null, false);
+ },
+ _expect: function(actual, matcher, formatter, reason, skip, verbose) {
+ var matchState, e, trace, exception,
+ t1 = type$.Invoker;
+ if (t1._as($.Zone__current.$index(0, C.Symbol_cQL)) == null)
+ throw H.wrapException(P.StateError$("expect() may only be called within a test."));
+ t1 = t1._as($.Zone__current.$index(0, C.Symbol_cQL));
+ if (H.boolConversionCheck(H._asBoolNullable($.Zone__current.$index(0, t1._closableKey))) && t1._onCloseCompleter.future._state !== 0)
+ throw H.wrapException(K.ClosedException$());
+ matcher = M.wrapMatcher(matcher);
+ t1 = type$.dynamic;
+ matchState = P.LinkedHashMap_LinkedHashMap$_empty(t1, t1);
+ try {
+ if (matcher.matches$2(0, true, matchState)) {
+ t1 = P.Future_Future$sync(new G._expect_closure(), t1);
+ return t1;
+ }
+ t1 = reason;
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ trace = H.getTraceFromException(exception);
+ t1 = reason == null ? H.S(e) + " at " + H.S(trace) : reason;
+ }
+ G.fail(new G._expect_closure0().call$5(true, matcher, t1, matchState, false));
+ },
+ fail: function(message) {
+ return H.throwExpression(new G.TestFailure(message));
+ },
+ formatFailure: function(expected, actual, which, reason) {
+ var t2,
+ t1 = new E.StringDescription(new P.StringBuffer("")).addDescriptionOf$1(expected)._out._contents;
+ t1 = B.indent(t1.charCodeAt(0) == 0 ? t1 : t1, "Expected: ") + "\n";
+ t2 = new E.StringDescription(new P.StringBuffer("")).addDescriptionOf$1(true)._out._contents;
+ t2 = t1 + (B.indent(t2.charCodeAt(0) == 0 ? t2 : t2, " Actual: ") + "\n");
+ t1 = which.length !== 0 ? t2 + (B.indent(which, " Which: ") + "\n") : t2;
+ if (reason != null)
+ t1 += reason + "\n";
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ TestFailure: function TestFailure(t0) {
+ this.message = t0;
+ },
+ _expect_closure0: function _expect_closure0() {
+ },
+ _expect_closure: function _expect_closure() {
+ },
+ method1: function() {
+ return $.x = $.x + 1;
+ },
+ method2: function() {
+ return $.x = $.x + 1;
+ },
+ main0: function() {
+ R.group("a group", new G.main_closure0());
+ },
+ main_closure0: function main_closure0() {
+ },
+ main__closure: function main__closure() {
+ }
+ },
+ T = {StreamSinkCompleter: function StreamSinkCompleter(t0, t1) {
+ this.sink = t0;
+ this.$ti = t1;
+ }, _CompleterSink: function _CompleterSink(t0) {
+ var _ = this;
+ _._destinationSink = _._stream_sink_completer$_doneCompleter = _._stream_sink_completer$_controller = null;
+ _.$ti = t0;
+ }, _CompleterSink__setDestinationSink_closure: function _CompleterSink__setDestinationSink_closure() {
+ }, SubscriptionStream: function SubscriptionStream(t0, t1) {
+ this._subscription_stream$_source = t0;
+ this.$ti = t1;
+ }, _CancelOnErrorSubscriptionWrapper: function _CancelOnErrorSubscriptionWrapper(t0, t1) {
+ this._stream_subscription$_source = t0;
+ this.$ti = t1;
+ }, _CancelOnErrorSubscriptionWrapper_onError_closure: function _CancelOnErrorSubscriptionWrapper_onError_closure(t0, t1) {
+ this.$this = t0;
+ this.handleError = t1;
+ }, _CancelOnErrorSubscriptionWrapper_onError__closure: function _CancelOnErrorSubscriptionWrapper_onError__closure(t0, t1, t2) {
+ this.handleError = t0;
+ this.error = t1;
+ this.stackTrace = t2;
+ }, Evaluator: function Evaluator(t0) {
+ this._semantics = t0;
+ },
+ parseJsonExtended: function(json, mapUrl, otherMaps) {
+ if (type$.List_dynamic._is(json))
+ return T.MappingBundle$fromJson(json, H._checkStringNullable(mapUrl));
+ return T.parseJson(type$.Map_dynamic_dynamic._as(json), null, null);
+ },
+ parseJson: function(map, mapUrl, otherMaps) {
+ var _s8_ = "sections";
+ if (!J.$eq$(map.$index(0, "version"), 3))
+ throw H.wrapException(P.ArgumentError$("unexpected source map version: " + H.S(map.$index(0, "version")) + ". Only version 3 is supported."));
+ if (map.containsKey$1(_s8_)) {
+ if (map.containsKey$1("mappings") || map.containsKey$1("sources") || map.containsKey$1("names"))
+ throw H.wrapException(P.FormatException$('map containing "sections" cannot contain "mappings", "sources", or "names".', null, null));
+ return T.MultiSectionMapping$fromJson(type$.List_dynamic._check(map.$index(0, _s8_)), otherMaps, mapUrl);
+ }
+ return T.SingleMapping$fromJson(map, mapUrl);
+ },
+ MultiSectionMapping$fromJson: function(sections, otherMaps, mapUrl) {
+ var t1 = type$.JSArray_int;
+ t1 = new T.MultiSectionMapping(H.setRuntimeTypeInfo([], t1), H.setRuntimeTypeInfo([], t1), H.setRuntimeTypeInfo([], type$.JSArray_Mapping));
+ t1.MultiSectionMapping$fromJson$3$mapUrl(sections, otherMaps, mapUrl);
+ return t1;
+ },
+ MappingBundle$fromJson: function(json, mapUrl) {
+ var t1 = new T.MappingBundle(P.LinkedHashMap_LinkedHashMap$_empty(type$.String, type$.SingleMapping));
+ t1.MappingBundle$fromJson$2$mapUrl(json, mapUrl);
+ return t1;
+ },
+ SingleMapping$fromJson: function(map, mapUrl) {
+ var t5, t6, t7, t8,
+ t1 = H._checkStringNullable(map.$index(0, "file")),
+ t2 = type$.Iterable_dynamic,
+ t3 = type$.String,
+ t4 = P.List_List$from(t2._check(map.$index(0, "sources")), true, t3);
+ t2 = P.List_List$from(t2._check(map.$index(0, "names")), true, t3);
+ t5 = H._checkIntNullable(J.get$length$asx(map.$index(0, "sources")));
+ if (typeof t5 !== "number")
+ return H.iae(t5);
+ t5 = new Array(t5);
+ t5.fixed$length = Array;
+ t5 = H.setRuntimeTypeInfo(t5, type$.JSArray_SourceFile);
+ t6 = H._checkStringNullable(map.$index(0, "sourceRoot"));
+ t7 = H.setRuntimeTypeInfo([], type$.JSArray_TargetLineEntry);
+ t8 = typeof mapUrl == "string" ? P.Uri_parse(mapUrl) : mapUrl;
+ t3 = new T.SingleMapping(t4, t2, t5, t7, t1, t6, type$.Uri._check(t8), P.LinkedHashMap_LinkedHashMap$_empty(t3, type$.dynamic));
+ t3.SingleMapping$fromJson$2$mapUrl(map, mapUrl);
+ return t3;
+ },
+ Mapping: function Mapping() {
+ },
+ MultiSectionMapping: function MultiSectionMapping(t0, t1, t2) {
+ this._lineStart = t0;
+ this._columnStart = t1;
+ this._maps = t2;
+ },
+ MappingBundle: function MappingBundle(t0) {
+ this._mappings = t0;
+ },
+ SingleMapping: function SingleMapping(t0, t1, t2, t3, t4, t5, t6, t7) {
+ var _ = this;
+ _.urls = t0;
+ _.names = t1;
+ _.files = t2;
+ _.lines = t3;
+ _.targetUrl = t4;
+ _.sourceRoot = t5;
+ _._parser$_mapUrl = t6;
+ _.extensions = t7;
+ },
+ SingleMapping$fromJson_closure: function SingleMapping$fromJson_closure(t0) {
+ this.$this = t0;
+ },
+ SingleMapping__findLine_closure: function SingleMapping__findLine_closure(t0) {
+ this.line = t0;
+ },
+ SingleMapping__findColumn_closure: function SingleMapping__findColumn_closure(t0) {
+ this.column = t0;
+ },
+ TargetLineEntry: function TargetLineEntry(t0, t1) {
+ this.line = t0;
+ this.entries = t1;
+ },
+ TargetEntry: function TargetEntry(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _.column = t0;
+ _.sourceUrlId = t1;
+ _.sourceLine = t2;
+ _.sourceColumn = t3;
+ _.sourceNameId = t4;
+ },
+ _MappingTokenizer: function _MappingTokenizer(t0, t1) {
+ this._internal = t0;
+ this._parser$_length = t1;
+ this.index = -1;
+ },
+ _TokenKind: function _TokenKind(t0, t1, t2) {
+ this.isNewLine = t0;
+ this.isNewSegment = t1;
+ this.isEof = t2;
+ },
+ LazyTrace: function LazyTrace(t0) {
+ this._lazy_trace$_thunk = t0;
+ this._lazy_trace$_inner = null;
+ },
+ LazyTrace_foldFrames_closure: function LazyTrace_foldFrames_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.predicate = t1;
+ this.terse = t2;
+ },
+ RuntimeSelection: function RuntimeSelection() {
+ }
+ },
+ X = {BooleanSelector: function BooleanSelector() {
+ }, All: function All() {
+ },
+ ParsedPath_ParsedPath$parse: function(path, style) {
+ var t1, parts, separators, start, i,
+ root = style.getRoot$1(path);
+ style.isRootRelative$1(path);
+ if (root != null)
+ path = J.substring$1$s(path, root.length);
+ t1 = type$.JSArray_String;
+ parts = H.setRuntimeTypeInfo([], t1);
+ separators = H.setRuntimeTypeInfo([], t1);
+ t1 = path.length;
+ if (t1 !== 0 && style.isSeparator$1(C.JSString_methods._codeUnitAt$1(path, 0))) {
+ if (0 >= t1)
+ return H.ioore(path, 0);
+ C.JSArray_methods.add$1(separators, path[0]);
+ start = 1;
+ } else {
+ C.JSArray_methods.add$1(separators, "");
+ start = 0;
+ }
+ for (i = start; i < t1; ++i)
+ if (style.isSeparator$1(C.JSString_methods._codeUnitAt$1(path, i))) {
+ C.JSArray_methods.add$1(parts, C.JSString_methods.substring$2(path, start, i));
+ C.JSArray_methods.add$1(separators, path[i]);
+ start = i + 1;
+ }
+ if (start < t1) {
+ C.JSArray_methods.add$1(parts, C.JSString_methods.substring$1(path, start));
+ C.JSArray_methods.add$1(separators, "");
+ }
+ return new X.ParsedPath(style, root, parts, separators);
+ },
+ ParsedPath: function ParsedPath(t0, t1, t2, t3) {
+ var _ = this;
+ _.style = t0;
+ _.root = t1;
+ _.parts = t2;
+ _.separators = t3;
+ },
+ ParsedPath_normalize_closure: function ParsedPath_normalize_closure(t0) {
+ this.$this = t0;
+ },
+ PathException$: function(message) {
+ return new X.PathException(message);
+ },
+ PathException: function PathException(t0) {
+ this.message = t0;
+ },
+ SourceSpanWithContext$: function(start, end, text, _context) {
+ var t1 = new X.SourceSpanWithContext(_context, start, end, text);
+ t1.SourceSpanBase$3(start, end, text);
+ if (!C.JSString_methods.contains$1(_context, text))
+ H.throwExpression(P.ArgumentError$('The context line "' + _context + '" must contain "' + text + '".'));
+ if (B.findLineStart(_context, text, start.get$column()) == null)
+ H.throwExpression(P.ArgumentError$('The span text "' + text + '" must start at column ' + (start.get$column() + 1) + ' in a line within "' + _context + '".'));
+ return t1;
+ },
+ SourceSpanWithContext: function SourceSpanWithContext(t0, t1, t2, t3) {
+ var _ = this;
+ _._context = t0;
+ _.start = t1;
+ _.end = t2;
+ _.text = t3;
+ },
+ LazyChain: function LazyChain(t0) {
+ this._thunk = t0;
+ this._lazy_chain$_inner = null;
+ },
+ LazyChain_foldFrames_closure: function LazyChain_foldFrames_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.predicate = t1;
+ this.terse = t2;
+ },
+ LazyChain_toTrace_closure: function LazyChain_toTrace_closure(t0) {
+ this.$this = t0;
+ },
+ StringScanner: function StringScanner() {
+ },
+ Declarer$: function(collectTraces, metadata, noRetry, platformVariables) {
+ var _null = null,
+ t1 = metadata == null ? O.Metadata_Metadata(_null, _null, _null, _null, _null, _null, _null, _null, _null, _null) : metadata,
+ t2 = platformVariables == null ? C.C_EmptyUnmodifiableSet : platformVariables,
+ t3 = type$.JSArray_of_dynamic_Function,
+ t4 = type$.JSArray_GroupEntry;
+ return new X.Declarer(_null, _null, t1, t2, _null, collectTraces, noRetry, H.setRuntimeTypeInfo([], t3), H.setRuntimeTypeInfo([], t3), H.setRuntimeTypeInfo([], t3), new R.Timeout(P.Duration$(0, 12), _null), H.setRuntimeTypeInfo([], t3), H.setRuntimeTypeInfo([], t4), H.setRuntimeTypeInfo([], t4));
+ },
+ Declarer: function Declarer(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) {
+ var _ = this;
+ _._declarer$_parent = t0;
+ _._declarer$_name = t1;
+ _._metadata = t2;
+ _._platformVariables = t3;
+ _._declarer$_trace = t4;
+ _._collectTraces = t5;
+ _._noRetry = t6;
+ _._setUps = t7;
+ _._tearDowns = t8;
+ _._setUpAlls = t9;
+ _._timeout = t10;
+ _._tearDownAlls = t11;
+ _._entries = t12;
+ _._built = false;
+ _._soloEntries = t13;
+ },
+ Declarer_test_closure: function Declarer_test_closure(t0, t1) {
+ this.$this = t0;
+ this.body = t1;
+ },
+ Declarer_test__closure: function Declarer_test__closure(t0, t1) {
+ this.$this = t0;
+ this.body = t1;
+ },
+ Declarer_test___closure: function Declarer_test___closure(t0, t1) {
+ this.$this = t0;
+ this.body = t1;
+ },
+ Declarer_group_closure: function Declarer_group_closure(t0) {
+ this.body = t0;
+ },
+ Declarer_build_closure: function Declarer_build_closure(t0) {
+ this.$this = t0;
+ },
+ Declarer__runSetUps_closure: function Declarer__runSetUps_closure() {
+ },
+ Declarer__tearDownAll_closure: function Declarer__tearDownAll_closure(t0) {
+ this.$this = t0;
+ },
+ Declarer__tearDownAll__closure: function Declarer__tearDownAll__closure(t0) {
+ this.$this = t0;
+ },
+ Declarer__tearDownAll___closure: function Declarer__tearDownAll___closure(t0) {
+ this.$this = t0;
+ },
+ PrintSink: function PrintSink(t0) {
+ this._print_sink$_buffer = t0;
+ }
+ },
+ U = {
+ _expandSafe: function(start, end) {
+ if (start == null || end == null)
+ return null;
+ if (start.file !== end.file)
+ return null;
+ return start.expand$1(0, end);
+ },
+ VariableNode: function VariableNode(t0, t1) {
+ this.span = t0;
+ this.name = t1;
+ },
+ NotNode: function NotNode(t0, t1) {
+ this.span = t0;
+ this.child = t1;
+ },
+ OrNode: function OrNode(t0, t1) {
+ this.left = t0;
+ this.right = t1;
+ },
+ AndNode: function AndNode(t0, t1) {
+ this.left = t0;
+ this.right = t1;
+ },
+ ConditionalNode: function ConditionalNode(t0, t1, t2) {
+ this.condition = t0;
+ this.whenTrue = t1;
+ this.whenFalse = t2;
+ },
+ Highlighter__normalizeNewlines: function(span) {
+ var t1, endOffset, i, t2, t3, t4,
+ text = span.get$text();
+ if (!C.JSString_methods.contains$1(text, "\r\n"))
+ return span;
+ t1 = span.get$end();
+ endOffset = t1.get$offset(t1);
+ for (t1 = text.length - 1, i = 0; i < t1; ++i)
+ if (C.JSString_methods._codeUnitAt$1(text, i) === 13 && C.JSString_methods._codeUnitAt$1(text, i + 1) === 10)
+ --endOffset;
+ t1 = span.get$start();
+ t2 = span.get$sourceUrl();
+ t3 = span.get$end().get$line();
+ t2 = V.SourceLocation$(endOffset, span.get$end().get$column(), t3, t2);
+ t3 = H.stringReplaceAllUnchecked(text, "\r\n", "\n");
+ t4 = span.get$context();
+ return X.SourceSpanWithContext$(t1, t2, t3, H.stringReplaceAllUnchecked(t4, "\r\n", "\n"));
+ },
+ Highlighter__normalizeTrailingNewline: function(span) {
+ var context, text, start, end, t1, t2, t3;
+ if (!C.JSString_methods.endsWith$1(span.get$context(), "\n"))
+ return span;
+ if (C.JSString_methods.endsWith$1(span.get$text(), "\n\n"))
+ return span;
+ context = C.JSString_methods.substring$2(span.get$context(), 0, span.get$context().length - 1);
+ text = span.get$text();
+ start = span.get$start();
+ end = span.get$end();
+ if (C.JSString_methods.endsWith$1(span.get$text(), "\n")) {
+ t1 = B.findLineStart(span.get$context(), span.get$text(), span.get$start().get$column());
+ t2 = span.get$start().get$column();
+ if (typeof t1 !== "number")
+ return t1.$add();
+ t2 = t1 + t2 + span.get$length(span) === span.get$context().length;
+ t1 = t2;
+ } else
+ t1 = false;
+ if (t1) {
+ text = C.JSString_methods.substring$2(span.get$text(), 0, span.get$text().length - 1);
+ t1 = span.get$end();
+ t1 = t1.get$offset(t1);
+ t2 = span.get$sourceUrl();
+ t3 = span.get$end().get$line();
+ if (typeof t3 !== "number")
+ return t3.$sub();
+ end = V.SourceLocation$(t1 - 1, U.Highlighter__lastLineLength(text), t3 - 1, t2);
+ t1 = span.get$start();
+ t1 = t1.get$offset(t1);
+ t2 = span.get$end();
+ start = t1 === t2.get$offset(t2) ? end : span.get$start();
+ }
+ return X.SourceSpanWithContext$(start, end, text, context);
+ },
+ Highlighter__normalizeEndOfLine: function(span) {
+ var text, t1, t2, t3, t4;
+ if (span.get$end().get$column() !== 0)
+ return span;
+ if (span.get$end().get$line() == span.get$start().get$line())
+ return span;
+ text = C.JSString_methods.substring$2(span.get$text(), 0, span.get$text().length - 1);
+ t1 = span.get$start();
+ t2 = span.get$end();
+ t2 = t2.get$offset(t2);
+ t3 = span.get$sourceUrl();
+ t4 = span.get$end().get$line();
+ if (typeof t4 !== "number")
+ return t4.$sub();
+ return X.SourceSpanWithContext$(t1, V.SourceLocation$(t2 - 1, U.Highlighter__lastLineLength(text), t4 - 1, t3), text, span.get$context());
+ },
+ Highlighter__lastLineLength: function(text) {
+ var t1 = text.length;
+ if (t1 === 0)
+ return 0;
+ if (C.JSString_methods.codeUnitAt$1(text, t1 - 1) === 10)
+ return t1 === 1 ? 0 : t1 - C.JSString_methods.lastIndexOf$2(text, "\n", t1 - 2) - 1;
+ else
+ return t1 - C.JSString_methods.lastIndexOf$1(text, "\n") - 1;
+ },
+ Highlighter: function Highlighter(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._span = t0;
+ _._color = t1;
+ _._multiline = t2;
+ _._paddingBeforeSidebar = t3;
+ _._highlighter$_buffer = t4;
+ },
+ Highlighter__writeFirstLine_closure: function Highlighter__writeFirstLine_closure(t0, t1) {
+ this.$this = t0;
+ this.line = t1;
+ },
+ Highlighter__writeFirstLine_closure0: function Highlighter__writeFirstLine_closure0(t0, t1) {
+ this.$this = t0;
+ this.textInside = t1;
+ },
+ Highlighter__writeFirstLine_closure1: function Highlighter__writeFirstLine_closure1(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ Highlighter__writeFirstLine_closure2: function Highlighter__writeFirstLine_closure2(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ Highlighter__writeIntermediateLines_closure: function Highlighter__writeIntermediateLines_closure(t0, t1) {
+ this.$this = t0;
+ this.line = t1;
+ },
+ Highlighter__writeLastLine_closure: function Highlighter__writeLastLine_closure(t0, t1) {
+ this.$this = t0;
+ this.line = t1;
+ },
+ Highlighter__writeLastLine_closure0: function Highlighter__writeLastLine_closure0(t0, t1) {
+ this.$this = t0;
+ this.textInside = t1;
+ },
+ Highlighter__writeLastLine_closure1: function Highlighter__writeLastLine_closure1(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ Highlighter__writeSidebar_closure: function Highlighter__writeSidebar_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.line = t1;
+ this.end = t2;
+ },
+ Chain_capture: function(callback, errorZone, when, $T) {
+ var t1, spec, _null = null;
+ if (!when)
+ return P.runZoned(callback, _null, _null, _null, $T);
+ if (typeof WeakMap == "function")
+ t1 = new WeakMap();
+ else {
+ t1 = $.Expando__keyCount;
+ $.Expando__keyCount = t1 + 1;
+ t1 = "expando$key$" + t1;
+ }
+ spec = new O.StackZoneSpecification(new P.Expando(t1, "stack chains", type$.Expando__Node), _null, false);
+ t1 = type$.dynamic;
+ return P.runZoned(new U.Chain_capture_closure(callback, $T), _null, P._ZoneSpecification$(_null, _null, spec.get$_stack_zone_specification$_errorCallback(), _null, _null, _null, spec.get$_stack_zone_specification$_registerBinaryCallback(), spec.get$_stack_zone_specification$_registerCallback(), spec.get$_stack_zone_specification$_registerUnaryCallback(), _null, _null, _null, _null), P.LinkedHashMap_LinkedHashMap$_literal([$.$get$_specKey(), spec, $.$get$StackZoneSpecification_disableKey(), false], t1, t1), $T);
+ },
+ Chain_Chain$current: function() {
+ var t1 = $.Zone__current,
+ t2 = $.$get$_specKey(),
+ t3 = type$.StackZoneSpecification;
+ if (t3._check(t1.$index(0, t2)) != null) {
+ t1 = t3._check($.Zone__current.$index(0, t2));
+ t2 = t1._currentTrace$1(3);
+ t1 = t1._currentNode;
+ return new O._Node(Y.Trace_Trace$from(t2), t1).toChain$0();
+ }
+ return new X.LazyChain(new U.Chain_Chain$current_closure(U.Chain_Chain$forTrace(P.StackTrace_current()), 0));
+ },
+ Chain_Chain$forTrace: function(trace) {
+ var t1, t2, t3;
+ if (type$.Chain._is(trace))
+ return trace;
+ t1 = $.Zone__current;
+ t2 = $.$get$_specKey();
+ t3 = type$.StackZoneSpecification;
+ if (t3._check(t1.$index(0, t2)) != null)
+ return t3._check($.Zone__current.$index(0, t2)).chainFor$1(trace);
+ t1 = type$.Trace;
+ if (t1._is(trace))
+ return new U.Chain(P.List_List$unmodifiable(H.setRuntimeTypeInfo([trace], type$.JSArray_Trace), t1));
+ return new X.LazyChain(new U.Chain_Chain$forTrace_closure(trace));
+ },
+ Chain_Chain$parse: function(chain) {
+ var _s26_ = "<asynchronous suspension>\n",
+ _s51_ = "===== asynchronous gap ===========================\n";
+ if (chain.length === 0)
+ return new U.Chain(P.List_List$unmodifiable(H.setRuntimeTypeInfo([], type$.JSArray_Trace), type$.Trace));
+ if (C.JSString_methods.contains$1(chain, _s26_))
+ return new U.Chain(P.List_List$unmodifiable(new H.MappedListIterable(H.setRuntimeTypeInfo(chain.split(_s26_), type$.JSArray_String), type$.Trace_Function_String._check(new U.Chain_Chain$parse_closure()), type$.MappedListIterable_String_Trace), type$.Trace));
+ if (!C.JSString_methods.contains$1(chain, _s51_))
+ return new U.Chain(P.List_List$unmodifiable(H.setRuntimeTypeInfo([Y.Trace_Trace$parse(chain)], type$.JSArray_Trace), type$.Trace));
+ return new U.Chain(P.List_List$unmodifiable(new H.MappedListIterable(H.setRuntimeTypeInfo(chain.split(_s51_), type$.JSArray_String), type$.Trace_Function_String._check(new U.Chain_Chain$parse_closure0()), type$.MappedListIterable_String_Trace), type$.Trace));
+ },
+ Chain: function Chain(t0) {
+ this.traces = t0;
+ },
+ Chain_capture_closure: function Chain_capture_closure(t0, t1) {
+ this.callback = t0;
+ this.T = t1;
+ },
+ Chain_Chain$current_closure: function Chain_Chain$current_closure(t0, t1) {
+ this.chain = t0;
+ this.level = t1;
+ },
+ Chain_Chain$forTrace_closure: function Chain_Chain$forTrace_closure(t0) {
+ this.trace = t0;
+ },
+ Chain_Chain$parse_closure: function Chain_Chain$parse_closure() {
+ },
+ Chain_Chain$parse_closure0: function Chain_Chain$parse_closure0() {
+ },
+ Chain_foldFrames_closure: function Chain_foldFrames_closure(t0, t1) {
+ this.predicate = t0;
+ this.terse = t1;
+ },
+ Chain_foldFrames_closure0: function Chain_foldFrames_closure0(t0) {
+ this.terse = t0;
+ },
+ Chain_toTrace_closure: function Chain_toTrace_closure() {
+ },
+ Chain_toString_closure0: function Chain_toString_closure0() {
+ },
+ Chain_toString__closure0: function Chain_toString__closure0() {
+ },
+ Chain_toString_closure: function Chain_toString_closure(t0) {
+ this.longest = t0;
+ },
+ Chain_toString__closure: function Chain_toString__closure(t0) {
+ this.longest = t0;
+ },
+ Invoker_guard: function(callback, $T) {
+ var _null = null;
+ return P.runZoned(callback, _null, P._ZoneSpecification$(_null, _null, _null, _null, new U.Invoker_guard_closure(), _null, _null, _null, _null, _null, _null, _null, _null), _null, $T);
+ },
+ LocalTest: function LocalTest(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _.name = t0;
+ _.metadata = t1;
+ _.trace = t2;
+ _.isScaffoldAll = t3;
+ _._body = t4;
+ _._guarded = t5;
+ },
+ Invoker: function Invoker(t0, t1, t2, t3, t4, t5, t6) {
+ var _ = this;
+ _._invoker$_controller = null;
+ _._guarded = t0;
+ _._closableKey = t1;
+ _._onCloseCompleter = t2;
+ _._outstandingCallbackZones = t3;
+ _._counterKey = t4;
+ _._runCount = 0;
+ _._timeoutTimer = _._invokerZone = null;
+ _._invoker$_tearDowns = t5;
+ _._printsOnFailure = t6;
+ },
+ Invoker_guard_closure: function Invoker_guard_closure() {
+ },
+ Invoker_guard__closure: function Invoker_guard__closure(t0, t1, t2, t3) {
+ var _ = this;
+ _.invoker = t0;
+ _.zone = t1;
+ _.error = t2;
+ _.stackTrace = t3;
+ },
+ Invoker_waitForOutstandingCallbacks_closure: function Invoker_waitForOutstandingCallbacks_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _._box_0 = t0;
+ _.$this = t1;
+ _.fn = t2;
+ _.counter = t3;
+ },
+ Invoker_waitForOutstandingCallbacks_closure0: function Invoker_waitForOutstandingCallbacks_closure0(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ Invoker_heartbeat_message: function Invoker_heartbeat_message(t0) {
+ this.timeout = t0;
+ },
+ Invoker_heartbeat_closure: function Invoker_heartbeat_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.message = t1;
+ this.timeout = t2;
+ },
+ Invoker_heartbeat__closure: function Invoker_heartbeat__closure(t0, t1, t2) {
+ this.$this = t0;
+ this.message = t1;
+ this.timeout = t2;
+ },
+ Invoker__handleError_closure: function Invoker__handleError_closure(t0) {
+ this._box_0 = t0;
+ },
+ Invoker__handleError_closure0: function Invoker__handleError_closure0(t0) {
+ this.$this = t0;
+ },
+ Invoker__onRun_closure: function Invoker__onRun_closure(t0, t1) {
+ this.$this = t0;
+ this.outstandingCallbacksForBody = t1;
+ },
+ Invoker__onRun__closure: function Invoker__onRun__closure(t0, t1) {
+ this.$this = t0;
+ this.outstandingCallbacksForBody = t1;
+ },
+ Invoker__onRun___closure: function Invoker__onRun___closure(t0) {
+ this.$this = t0;
+ },
+ Invoker__onRun____closure: function Invoker__onRun____closure(t0) {
+ this.$this = t0;
+ },
+ Invoker__onRun___closure0: function Invoker__onRun___closure0(t0) {
+ this.$this = t0;
+ },
+ _AsyncCounter: function _AsyncCounter(t0) {
+ this._count = 1;
+ this._invoker$_completer = t0;
+ },
+ StackTraceFormatter: function StackTraceFormatter(t0, t1) {
+ this._mapper = null;
+ this._except = t0;
+ this._only = t1;
+ },
+ StackTraceFormatter_formatStackTrace_closure: function StackTraceFormatter_formatStackTrace_closure(t0) {
+ this.$this = t0;
+ },
+ Suite__filterGroup: function(group, platform) {
+ var t1, _null = null,
+ filtered = group.forPlatform$1(platform);
+ if (filtered != null)
+ return filtered;
+ t1 = P.List_List$unmodifiable(H.setRuntimeTypeInfo([], type$.JSArray_GroupEntry), type$.GroupEntry);
+ return new O.Group(_null, group.metadata, _null, t1, _null, _null);
+ },
+ Suite: function Suite(t0, t1, t2) {
+ this.platform = t0;
+ this.path = t1;
+ this.group = t2;
+ },
+ SuiteConfiguration__list: function(input, $T) {
+ return null;
+ },
+ SuiteConfiguration__map: function(input, $K, $V) {
+ return C.Map_empty1;
+ },
+ SuiteConfiguration: function SuiteConfiguration() {
+ },
+ RemoteException_serialize: function(error, stackTrace) {
+ var exception, supertype, t1, message = null;
+ if (typeof error == "string")
+ message = error;
+ else
+ try {
+ message = J.toString$0$(J.get$message$x(error));
+ } catch (exception) {
+ if (!type$.NoSuchMethodError._is(H.unwrapException(exception)))
+ throw exception;
+ }
+ supertype = error instanceof G.TestFailure ? "TestFailure" : null;
+ t1 = J.getInterceptor$(error);
+ return P.LinkedHashMap_LinkedHashMap$_literal(["message", message, "type", t1.get$runtimeType(error).toString$0(0), "supertype", supertype, "toString", t1.toString$0(error), "stackChain", J.toString$0$(U.Chain_Chain$forTrace(stackTrace))], type$.String, type$.dynamic);
+ }
+ },
+ R = {IntersectionSelector: function IntersectionSelector(t0, t1) {
+ this._selector1 = t0;
+ this._selector2 = t1;
+ }, StreamChannel: function StreamChannel() {
+ }, _StreamChannel: function _StreamChannel(t0, t1, t2) {
+ this.stream = t0;
+ this.sink = t1;
+ this.$ti = t2;
+ }, StreamChannelMixin: function StreamChannelMixin() {
+ }, Timeout: function Timeout(t0, t1) {
+ this.duration = t0;
+ this.scaleFactor = t1;
+ }, ExpandedReporter: function ExpandedReporter(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) {
+ var _ = this;
+ _._expanded$_color = t0;
+ _._green = t1;
+ _._red = t2;
+ _._yellow = t3;
+ _._gray = t4;
+ _._bold = t5;
+ _._noColor = t6;
+ _._engine = t7;
+ _._printPath = t8;
+ _._printPlatform = t9;
+ _._stopwatch = t10;
+ _._lastProgressSuffix = _._lastProgressMessage = _._lastProgressFailed = _._lastProgressSkipped = _._lastProgressPassed = null;
+ _._subscriptions = t11;
+ _._expanded$_sink = t12;
+ }, ExpandedReporter__onTestStarted_closure: function ExpandedReporter__onTestStarted_closure(t0, t1) {
+ this.$this = t0;
+ this.liveTest = t1;
+ }, ExpandedReporter__onTestStarted_closure0: function ExpandedReporter__onTestStarted_closure0(t0, t1) {
+ this.$this = t0;
+ this.liveTest = t1;
+ }, ExpandedReporter__onTestStarted_closure1: function ExpandedReporter__onTestStarted_closure1(t0, t1) {
+ this.$this = t0;
+ this.liveTest = t1;
+ },
+ _declarer: function() {
+ var t1,
+ declarer = type$.Declarer._as($.Zone__current.$index(0, C.Symbol_Drw));
+ if (declarer != null)
+ return declarer;
+ t1 = $._globalDeclarer;
+ if (t1 != null)
+ return t1;
+ $._globalDeclarer = X.Declarer$(false, null, false, null);
+ P.scheduleMicrotask(new R._declarer_closure());
+ return $._globalDeclarer;
+ },
+ test: function(description, body) {
+ var _null = null;
+ R._declarer().test$9$onPlatform$retry$skip$solo$tags$testOn$timeout(description, body, _null, _null, _null, false, _null, _null, _null);
+ return;
+ },
+ group: function(description, body) {
+ var _null = null;
+ R._declarer().group$9$onPlatform$retry$skip$solo$tags$testOn$timeout(description, body, _null, _null, _null, false, _null, _null, _null);
+ return;
+ },
+ _declarer_closure: function _declarer_closure() {
+ },
+ _declarer__closure: function _declarer__closure(t0) {
+ this.engine = t0;
+ },
+ main: function() {
+ L.internalBootstrapBrowserTest(new R.main_closure());
+ },
+ main_closure: function main_closure() {
+ }
+ },
+ B = {RecursiveVisitor: function RecursiveVisitor() {
+ }, InternalStyle: function InternalStyle() {
+ },
+ StreamChannelController$: function(allowForeignErrors, sync, $T) {
+ var _null = null,
+ t1 = new B.StreamChannelController($T._eval$1("StreamChannelController<0>")),
+ localToForeignController = P.StreamController_StreamController(_null, _null, true, $T),
+ foreignToLocalController = P.StreamController_StreamController(_null, _null, true, $T),
+ t2 = H._instanceType(foreignToLocalController),
+ t3 = H._instanceType(localToForeignController);
+ t1.set$_local(K.GuaranteeChannel$(new P._ControllerStream(foreignToLocalController, t2._eval$1("_ControllerStream<1>")), new P._StreamSinkWrapper(localToForeignController, t3._eval$1("_StreamSinkWrapper<1>")), true, $T));
+ t1.set$_foreign(K.GuaranteeChannel$(new P._ControllerStream(localToForeignController, t3._eval$1("_ControllerStream<1>")), new P._StreamSinkWrapper(foreignToLocalController, t2._eval$1("_StreamSinkWrapper<1>")), allowForeignErrors, $T));
+ return t1;
+ },
+ StreamChannelController: function StreamChannelController(t0) {
+ this._foreign = this._local = null;
+ this.$ti = t0;
+ },
+ Runtime_Runtime$deserialize: function(serialized) {
+ var $parent, t1, t2, t3,
+ _s10_ = "identifier";
+ if (typeof serialized == "string")
+ return C.JSArray_methods.firstWhere$1(C.List_m7e, new B.Runtime_Runtime$deserialize_closure(serialized));
+ type$.Map_dynamic_dynamic._as(serialized);
+ $parent = serialized.$index(0, "parent");
+ if ($parent != null) {
+ t1 = H._asStringNullable(serialized.$index(0, "name"));
+ t2 = H._asStringNullable(serialized.$index(0, _s10_));
+ t3 = B.Runtime_Runtime$deserialize($parent);
+ return new B.Runtime(t1, t2, t3, t3.isDartVM, t3.isBrowser, t3.isJS, t3.isBlink, t3.isHeadless);
+ }
+ return new B.Runtime(H._asStringNullable(serialized.$index(0, "name")), H._asStringNullable(serialized.$index(0, _s10_)), null, H._asBoolNullable(serialized.$index(0, "isDartVM")), H._asBoolNullable(serialized.$index(0, "isBrowser")), H._asBoolNullable(serialized.$index(0, "isJS")), H._asBoolNullable(serialized.$index(0, "isBlink")), H._asBoolNullable(serialized.$index(0, "isHeadless")));
+ },
+ Runtime: function Runtime(t0, t1, t2, t3, t4, t5, t6, t7) {
+ var _ = this;
+ _.name = t0;
+ _.identifier = t1;
+ _.parent = t2;
+ _.isDartVM = t3;
+ _.isBrowser = t4;
+ _.isJS = t5;
+ _.isBlink = t6;
+ _.isHeadless = t7;
+ },
+ Runtime_Runtime$deserialize_closure: function Runtime_Runtime$deserialize_closure(t0) {
+ this.serialized = t0;
+ },
+ indent: function(string, first) {
+ var size = first == null ? 2 : first.length;
+ return B.prefixLines(string, C.JSString_methods.$mul(" ", size), first);
+ },
+ toSentence: function(iter) {
+ var result,
+ t1 = iter.length;
+ if (t1 === 1)
+ return J.toString$0$(C.JSArray_methods.get$first(iter));
+ result = H.SubListIterable$(iter, 0, t1 - 1, H._arrayInstanceType(iter)._precomputed1).join$1(0, ", ");
+ if (iter.length > 2)
+ result += ",";
+ return result + " and " + H.S(C.JSArray_methods.get$last(iter));
+ },
+ pluralize: function($name, number) {
+ if (number === 1)
+ return $name;
+ return $name + "s";
+ },
+ prefixLines: function(text, prefix, first) {
+ var single, lines, t1, t2;
+ if (first == null)
+ first = prefix;
+ single = first;
+ lines = H.setRuntimeTypeInfo(text.split("\n"), type$.JSArray_String);
+ if (lines.length === 1)
+ return single + text;
+ t1 = first + H.S(C.JSArray_methods.get$first(lines)) + "\n";
+ for (t2 = H.SubListIterable$(lines, 1, null, type$.String).take$1(0, lines.length - 2), t2 = new H.ListIterator(t2, t2.get$length(t2), t2.$ti._eval$1("ListIterator<ListIterable.E>")); t2.moveNext$0();)
+ t1 += prefix + H.S(t2.__internal$_current) + "\n";
+ t1 += prefix + H.S(C.JSArray_methods.get$last(lines));
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ closure0: function closure0() {
+ },
+ LiveSuiteController$: function(_suite) {
+ var t1 = $.Zone__current,
+ t2 = H.setRuntimeTypeInfo([], type$.JSArray_dynamic),
+ t3 = $.Zone__current,
+ t4 = type$._Future_dynamic,
+ t5 = type$._AsyncCompleter_dynamic,
+ t6 = type$.LiveTest;
+ t5 = new B.LiveSuiteController(_suite, new F.FutureGroup(new P._AsyncCompleter(new P._Future(t1, type$._Future_List_dynamic), type$._AsyncCompleter_List_dynamic), t2, type$.FutureGroup_dynamic), new P._AsyncCompleter(new P._Future(t3, t4), t5), new P._SyncBroadcastStreamController(null, null, type$._SyncBroadcastStreamController_LiveTest), P.LinkedHashSet_LinkedHashSet$_empty(t6), P.LinkedHashSet_LinkedHashSet$_empty(t6), P.LinkedHashSet_LinkedHashSet$_empty(t6), new S.AsyncMemoizer(new P._AsyncCompleter(new P._Future(t3, t4), t5), type$.AsyncMemoizer_dynamic));
+ t5.LiveSuiteController$1(_suite);
+ return t5;
+ },
+ _LiveSuite: function _LiveSuite(t0) {
+ this._live_suite_controller$_controller = t0;
+ },
+ LiveSuiteController: function LiveSuiteController(t0, t1, t2, t3, t4, t5, t6, t7) {
+ var _ = this;
+ _._liveSuite = null;
+ _._live_suite_controller$_suite = t0;
+ _._onCompleteGroup = t1;
+ _._live_suite_controller$_onCloseCompleter = t2;
+ _._onTestStartedController = t3;
+ _._passed = t4;
+ _._skipped = t5;
+ _._failed = t6;
+ _._live_suite_controller$_active = null;
+ _._live_suite_controller$_closeMemo = t7;
+ },
+ LiveSuiteController_closure: function LiveSuiteController_closure(t0) {
+ this.$this = t0;
+ },
+ LiveSuiteController_closure0: function LiveSuiteController_closure0() {
+ },
+ LiveSuiteController_reportLiveTest_closure: function LiveSuiteController_reportLiveTest_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.liveTest = t1;
+ this.countSuccess = t2;
+ },
+ LiveSuiteController_close_closure: function LiveSuiteController_close_closure(t0) {
+ this.$this = t0;
+ },
+ asUri: function(uri, $name) {
+ if (type$.Uri._is(uri))
+ return uri;
+ throw H.wrapException(P.ArgumentError$value(uri, $name, "Must be a String or a Uri."));
+ },
+ ensureTrailingSlash: function(uri) {
+ var t1;
+ if (uri.get$pathSegments().length === 0)
+ return uri.replace$1$path(0, "/");
+ t1 = C.JSArray_methods.get$last(uri.get$pathSegments());
+ t1.toString;
+ if (J.get$length$asx(t1) === 0)
+ return uri;
+ t1 = uri.get$pathSegments();
+ t1 = H.setRuntimeTypeInfo(t1.slice(0), H._arrayInstanceType(t1)._eval$1("JSArray<1>"));
+ C.JSArray_methods.add$1(t1, "");
+ return uri.replace$1$pathSegments(0, t1);
+ },
+ isAlphabetic: function(char) {
+ var t1;
+ if (!(char >= 65 && char <= 90))
+ t1 = char >= 97 && char <= 122;
+ else
+ t1 = true;
+ return t1;
+ },
+ isDriveLetter: function(path, index) {
+ var t1 = path.length,
+ t2 = index + 2;
+ if (t1 < t2)
+ return false;
+ if (!B.isAlphabetic(C.JSString_methods.codeUnitAt$1(path, index)))
+ return false;
+ if (C.JSString_methods.codeUnitAt$1(path, index + 1) !== 58)
+ return false;
+ if (t1 === t2)
+ return true;
+ return C.JSString_methods.codeUnitAt$1(path, t2) === 47;
+ },
+ countCodeUnits: function(string, codeUnit) {
+ var t1, count;
+ for (t1 = new H.CodeUnits(string), t1 = new H.ListIterator(t1, t1.get$length(t1), type$.CodeUnits._eval$1("ListIterator<ListMixin.E>")), count = 0; t1.moveNext$0();)
+ if (t1.__internal$_current === codeUnit)
+ ++count;
+ return count;
+ },
+ findLineStart: function(context, text, column) {
+ var beginningOfLine, index, lineStart;
+ if (text.length === 0)
+ for (beginningOfLine = 0; true;) {
+ index = C.JSString_methods.indexOf$2(context, "\n", beginningOfLine);
+ if (index === -1)
+ return context.length - beginningOfLine >= column ? beginningOfLine : null;
+ if (index - beginningOfLine >= column)
+ return beginningOfLine;
+ beginningOfLine = index + 1;
+ }
+ index = C.JSString_methods.indexOf$1(context, text);
+ for (; index !== -1;) {
+ lineStart = index === 0 ? 0 : C.JSString_methods.lastIndexOf$2(context, "\n", index - 1) + 1;
+ if (column === index - lineStart)
+ return lineStart;
+ index = C.JSString_methods.indexOf$2(context, text, index + 1);
+ }
+ return null;
+ },
+ validateErrorArgs: function(string, match, position, $length) {
+ var t1;
+ if (position < 0)
+ throw H.wrapException(P.RangeError$("position must be greater than or equal to 0."));
+ else if (position > string.length)
+ throw H.wrapException(P.RangeError$("position must be less than or equal to the string length."));
+ t1 = position + $length > string.length;
+ if (t1)
+ throw H.wrapException(P.RangeError$("position plus length must not go beyond the end of the string."));
+ }
+ },
+ Q = {
+ QueueList$: function($E) {
+ var t1 = new Q.QueueList($E._eval$1("QueueList<0>")),
+ t2 = new Array(8);
+ t2.fixed$length = Array;
+ t1.set$_queue_list$_table(H.setRuntimeTypeInfo(t2, $E._eval$1("JSArray<0>")));
+ return t1;
+ },
+ QueueList__nextPowerOf2: function(number) {
+ var nextNumber;
+ H.assertHelper(number > 0);
+ number = (number << 1 >>> 0) - 1;
+ for (; true; number = nextNumber) {
+ nextNumber = (number & number - 1) >>> 0;
+ if (nextNumber === 0)
+ return number;
+ }
+ },
+ QueueList: function QueueList(t0) {
+ var _ = this;
+ _._queue_list$_table = null;
+ _._queue_list$_tail = _._queue_list$_head = 0;
+ _.$ti = t0;
+ },
+ _QueueList_Object_ListMixin: function _QueueList_Object_ListMixin() {
+ }
+ },
+ M = {UnionSet: function UnionSet(t0, t1, t2) {
+ this._sets = t0;
+ this._disjoint = t1;
+ this.$ti = t2;
+ }, UnionSet_length_closure: function UnionSet_length_closure(t0) {
+ this.$this = t0;
+ }, UnionSet__iterable_closure: function UnionSet__iterable_closure(t0) {
+ this.$this = t0;
+ }, _UnionSet_SetBase_UnmodifiableSetMixin: function _UnionSet_SetBase_UnmodifiableSetMixin() {
+ }, _DelegatingIterableBase: function _DelegatingIterableBase() {
+ }, DelegatingIterable: function DelegatingIterable() {
+ }, DelegatingSet: function DelegatingSet(t0, t1) {
+ this._base = t0;
+ this.$ti = t1;
+ }, TypeMatcher: function TypeMatcher() {
+ },
+ wrapMatcher: function(x) {
+ var _s18_ = "satisfies function";
+ if (x instanceof G.Matcher)
+ return x;
+ else if (type$.bool_Function_Object._is(x))
+ return new Y._Predicate(x, _s18_, type$._Predicate_Object);
+ else if (type$.bool_Function_Null._is(x))
+ return new Y._Predicate(new M.wrapMatcher_closure(x), _s18_, type$._Predicate_dynamic);
+ else
+ return typeof x == "string" ? new D._StringEqualsMatcher(x) : new D._DeepMatcher(x, 100);
+ },
+ escape: function(str) {
+ str.toString;
+ return C.JSString_methods.splitMapJoin$2$onMatch(H.stringReplaceAllUnchecked(str, "\\", "\\\\"), $.$get$_escapeRegExp(), type$.String_Function_Match._check(new M.escape_closure()));
+ },
+ _getHexLiteral: function(input) {
+ var t1, it, result;
+ H._checkStringNullable(input);
+ input.toString;
+ t1 = new P.Runes(input);
+ it = t1.get$iterator(t1);
+ if (!it.moveNext$0())
+ H.throwExpression(H.IterableElementError_noElement());
+ result = it.get$current();
+ if (it.moveNext$0())
+ H.throwExpression(H.IterableElementError_tooMany());
+ return "\\x" + C.JSString_methods.padLeft$2(J.toRadixString$1$n(result, 16).toUpperCase(), 2, "0");
+ },
+ wrapMatcher_closure: function wrapMatcher_closure(t0) {
+ this.x = t0;
+ },
+ escape_closure: function escape_closure() {
+ },
+ Context_Context: function(style) {
+ var current = style == null ? D.current() : ".";
+ if (style == null)
+ style = $.$get$Style_platform();
+ return new M.Context(style, current);
+ },
+ _parseUri: function(uri) {
+ if (type$.Uri._is(uri))
+ return uri;
+ throw H.wrapException(P.ArgumentError$value(uri, "uri", "Value must be a String or a Uri"));
+ },
+ _validateArgList: function(method, args) {
+ var numArgs, i, numArgs0, message, t1, t2, t3;
+ for (numArgs = args.length, i = 1; i < numArgs; ++i) {
+ if (args[i] == null || args[i - 1] != null)
+ continue;
+ for (; numArgs >= 1; numArgs = numArgs0) {
+ numArgs0 = numArgs - 1;
+ if (args[numArgs0] != null)
+ break;
+ }
+ message = new P.StringBuffer("");
+ t1 = method + "(";
+ message._contents = t1;
+ t2 = H.SubListIterable$(args, 0, numArgs, H._arrayInstanceType(args)._precomputed1);
+ t3 = t2.$ti;
+ t3 = t1 + new H.MappedListIterable(t2, t3._eval$1("String(ListIterable.E)")._check(new M._validateArgList_closure()), t3._eval$1("MappedListIterable<ListIterable.E,String>")).join$1(0, ", ");
+ message._contents = t3;
+ message._contents = t3 + ("): part " + (i - 1) + " was null, but part " + i + " was not.");
+ throw H.wrapException(P.ArgumentError$(message.toString$0(0)));
+ }
+ },
+ Context: function Context(t0, t1) {
+ this.style = t0;
+ this._context$_current = t1;
+ },
+ Context_join_closure: function Context_join_closure() {
+ },
+ Context_joinAll_closure: function Context_joinAll_closure() {
+ },
+ Context_split_closure: function Context_split_closure() {
+ },
+ _validateArgList_closure: function _validateArgList_closure() {
+ },
+ _PathDirection: function _PathDirection(t0) {
+ this.name = t0;
+ },
+ _PathRelation: function _PathRelation(t0) {
+ this.name = t0;
+ }
+ },
+ D = {
+ _StringEqualsMatcher__writeLeading: function(buff, s, start) {
+ var t1 = buff._contents;
+ if (start > 10) {
+ t1 += "... ";
+ buff._contents = t1;
+ buff._contents = t1 + C.JSString_methods.substring$2(s, start - 10, start);
+ } else
+ buff._contents = t1 + C.JSString_methods.substring$2(s, 0, start);
+ },
+ _StringEqualsMatcher__writeTrailing: function(buff, s, start) {
+ var t1 = start + 10,
+ t2 = buff._contents;
+ if (t1 > s.length)
+ buff._contents = t2 + C.JSString_methods.substring$1(s, start);
+ else {
+ t1 = t2 + C.JSString_methods.substring$2(s, start, t1);
+ buff._contents = t1;
+ buff._contents = t1 + " ...";
+ }
+ },
+ _StringEqualsMatcher: function _StringEqualsMatcher(t0) {
+ this._equals_matcher$_value = t0;
+ },
+ _DeepMatcher: function _DeepMatcher(t0, t1) {
+ this._expected = t0;
+ this._limit = t1;
+ },
+ _DeepMatcher__compareSets_closure: function _DeepMatcher__compareSets_closure(t0, t1, t2, t3) {
+ var _ = this;
+ _.matcher = t0;
+ _.expectedElement = t1;
+ _.location = t2;
+ _.depth = t3;
+ },
+ PackageRootResolver: function PackageRootResolver(t0) {
+ this.packageRoot = t0;
+ },
+ SourceLocationMixin: function SourceLocationMixin() {
+ },
+ _MultiChannel$: function(_inner, $T) {
+ var t1 = type$.int;
+ t1 = new D._MultiChannel(_inner, B.StreamChannelController$(true, true, $T), P.LinkedHashMap_LinkedHashMap$_empty(t1, $T._eval$1("StreamChannelController<0>")), P.LinkedHashSet_LinkedHashSet(t1), P.LinkedHashSet_LinkedHashSet(t1), $T._eval$1("_MultiChannel<0>"));
+ t1._MultiChannel$1(_inner, $T);
+ return t1;
+ },
+ _MultiChannel: function _MultiChannel(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _._multi_channel$_inner = t0;
+ _._innerStreamSubscription = null;
+ _._mainController = t1;
+ _._controllers = t2;
+ _._pendingIds = t3;
+ _._closedIds = t4;
+ _._nextId = 1;
+ _.$ti = t5;
+ },
+ _MultiChannel_closure: function _MultiChannel_closure(t0, t1) {
+ this.$this = t0;
+ this.T = t1;
+ },
+ _MultiChannel_closure0: function _MultiChannel_closure0(t0) {
+ this.$this = t0;
+ },
+ _MultiChannel_closure1: function _MultiChannel_closure1(t0, t1) {
+ this.$this = t0;
+ this.T = t1;
+ },
+ _MultiChannel__closure: function _MultiChannel__closure(t0, t1, t2) {
+ this.$this = t0;
+ this.id = t1;
+ this.T = t2;
+ },
+ _MultiChannel_virtualChannel_closure: function _MultiChannel_virtualChannel_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ _MultiChannel_virtualChannel_closure0: function _MultiChannel_virtualChannel_closure0(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ VirtualChannel: function VirtualChannel(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._multi_channel$_parent = t0;
+ _.id = t1;
+ _.stream = t2;
+ _.sink = t3;
+ _.$ti = t4;
+ },
+ Message: function Message(t0, t1) {
+ this.type = t0;
+ this.text = t1;
+ },
+ MessageType: function MessageType(t0) {
+ this.name = t0;
+ },
+ current: function() {
+ var exception, t1, path, lastIndex, uri = null;
+ try {
+ uri = P.Uri_base();
+ } catch (exception) {
+ if (type$.Exception._is(H.unwrapException(exception))) {
+ t1 = $._current;
+ if (t1 != null)
+ return t1;
+ throw exception;
+ } else
+ throw exception;
+ }
+ if (J.$eq$(uri, $._currentUriBase))
+ return $._current;
+ $._currentUriBase = uri;
+ if ($.$get$Style_platform() == $.$get$Style_url())
+ return $._current = uri.resolve$1(".").toString$0(0);
+ else {
+ path = uri.toFilePath$0();
+ t1 = path.length;
+ lastIndex = t1 - 1;
+ if (lastIndex < 0)
+ return H.ioore(path, lastIndex);
+ t1 = path[lastIndex];
+ H.assertHelper(t1 === "/" || t1 === "\\");
+ return $._current = lastIndex === 0 ? path : C.JSString_methods.substring$2(path, 0, lastIndex);
+ }
+ }
+ },
+ Z = {
+ prettyPrint: function(object, maxItems, maxLineLength) {
+ return new Z.prettyPrint__prettyPrint(maxItems, maxLineLength).call$4(object, 0, P.LinkedHashSet_LinkedHashSet$_empty(type$.Object), true);
+ },
+ _typeName: function(x) {
+ if (type$.Type._is(x))
+ return "Type";
+ if (type$.Uri._is(x))
+ return "Uri";
+ if (type$.Set_dynamic._is(x))
+ return "Set";
+ return J.get$runtimeType$(x).toString$0(0);
+ },
+ _escapeString: function(source) {
+ var t1 = M.escape(H._checkStringNullable(source));
+ return H.stringReplaceAllUnchecked(t1, "'", "\\'");
+ },
+ prettyPrint__prettyPrint: function prettyPrint__prettyPrint(t0, t1) {
+ this.maxItems = t0;
+ this.maxLineLength = t1;
+ },
+ prettyPrint__prettyPrint_pp: function prettyPrint__prettyPrint_pp(t0, t1, t2) {
+ this._box_0 = t0;
+ this._prettyPrint = t1;
+ this.indent = t2;
+ },
+ prettyPrint__prettyPrint_closure: function prettyPrint__prettyPrint_closure(t0) {
+ this.indent = t0;
+ },
+ prettyPrint__prettyPrint_closure0: function prettyPrint__prettyPrint_closure0(t0, t1) {
+ this.pp = t0;
+ this.object = t1;
+ },
+ prettyPrint__prettyPrint_closure1: function prettyPrint__prettyPrint_closure1(t0) {
+ this.indent = t0;
+ },
+ LiveTest: function LiveTest() {
+ }
+ },
+ A = {
+ Frame_Frame$parseVM: function(frame) {
+ return A.Frame__catchFormatException(frame, new A.Frame_Frame$parseVM_closure(frame));
+ },
+ Frame_Frame$parseV8: function(frame) {
+ return A.Frame__catchFormatException(frame, new A.Frame_Frame$parseV8_closure(frame));
+ },
+ Frame_Frame$parseFirefox: function(frame) {
+ return A.Frame__catchFormatException(frame, new A.Frame_Frame$parseFirefox_closure(frame));
+ },
+ Frame_Frame$parseFriendly: function(frame) {
+ return A.Frame__catchFormatException(frame, new A.Frame_Frame$parseFriendly_closure(frame));
+ },
+ Frame__uriOrPathToUri: function(uriOrPath) {
+ if (J.getInterceptor$asx(uriOrPath).contains$1(uriOrPath, $.$get$Frame__uriRegExp()))
+ return P.Uri_parse(uriOrPath);
+ else if (C.JSString_methods.contains$1(uriOrPath, $.$get$Frame__windowsRegExp()))
+ return P._Uri__Uri$file(uriOrPath, true);
+ else if (C.JSString_methods.startsWith$1(uriOrPath, "/"))
+ return P._Uri__Uri$file(uriOrPath, false);
+ if (C.JSString_methods.contains$1(uriOrPath, "\\"))
+ return $.$get$windows().toUri$1(uriOrPath);
+ return P.Uri_parse(uriOrPath);
+ },
+ Frame__catchFormatException: function(text, body) {
+ var t1, exception;
+ try {
+ t1 = body.call$0();
+ return t1;
+ } catch (exception) {
+ if (type$.FormatException._is(H.unwrapException(exception)))
+ return new N.UnparsedFrame(P._Uri__Uri(null, "unparsed", null, null), text);
+ else
+ throw exception;
+ }
+ },
+ Frame: function Frame(t0, t1, t2, t3) {
+ var _ = this;
+ _.uri = t0;
+ _.line = t1;
+ _.column = t2;
+ _.member = t3;
+ },
+ Frame_Frame$parseVM_closure: function Frame_Frame$parseVM_closure(t0) {
+ this.frame = t0;
+ },
+ Frame_Frame$parseV8_closure: function Frame_Frame$parseV8_closure(t0) {
+ this.frame = t0;
+ },
+ Frame_Frame$parseV8_closure_parseLocation: function Frame_Frame$parseV8_closure_parseLocation(t0) {
+ this.frame = t0;
+ },
+ Frame_Frame$parseFirefox_closure: function Frame_Frame$parseFirefox_closure(t0) {
+ this.frame = t0;
+ },
+ Frame_Frame$parseFriendly_closure: function Frame_Frame$parseFriendly_closure(t0) {
+ this.frame = t0;
+ },
+ AsciiGlyphSet: function AsciiGlyphSet() {
+ }
+ },
+ N = {UnparsedFrame: function UnparsedFrame(t0, t1) {
+ this.uri = t0;
+ this.member = t1;
+ }, StreamChannelCompleter: function StreamChannelCompleter(t0, t1, t2) {
+ var _ = this;
+ _._streamCompleter = t0;
+ _._sinkCompleter = t1;
+ _._stream_channel_completer$_channel = null;
+ _._stream_channel_completer$_set = false;
+ _.$ti = t2;
+ },
+ postMessageChannel: function() {
+ var t1, t2,
+ controller = B.StreamChannelController$(true, true, type$.dynamic);
+ new W._EventStream(window, "message", false, type$._EventStream_MessageEvent).firstWhere$1(0, new N.postMessageChannel_closure()).then$1$1(new N.postMessageChannel_closure0(controller), type$.Null);
+ t1 = P.LinkedHashMap_LinkedHashMap$_literal(["href", window.location.href, "ready", true], type$.String, type$.Object);
+ t1 = P._convertDataTree(t1);
+ t2 = window.location;
+ self.window.parent.postMessage(t1, (t2 && C.Location_methods).get$origin(t2));
+ return controller._foreign;
+ },
+ postMessageChannel_closure: function postMessageChannel_closure() {
+ },
+ postMessageChannel_closure0: function postMessageChannel_closure0(t0) {
+ this.controller = t0;
+ },
+ postMessageChannel__closure: function postMessageChannel__closure(t0) {
+ this.controller = t0;
+ },
+ postMessageChannel__closure0: function postMessageChannel__closure0(t0) {
+ this.port = t0;
+ },
+ postMessageChannel__closure1: function postMessageChannel__closure1(t0, t1) {
+ this.port = t0;
+ this.portSubscription = t1;
+ },
+ OperatingSystem_find: function(identifier) {
+ return C.JSArray_methods.firstWhere$2$orElse(C.List_opx, new N.OperatingSystem_find_closure(identifier), new N.OperatingSystem_find_closure0());
+ },
+ OperatingSystem: function OperatingSystem(t0, t1) {
+ this.name = t0;
+ this.identifier = t1;
+ },
+ OperatingSystem_find_closure: function OperatingSystem_find_closure(t0) {
+ this.identifier = t0;
+ },
+ OperatingSystem_find_closure0: function OperatingSystem_find_closure0() {
+ },
+ SuiteChannelManager: function SuiteChannelManager(t0, t1, t2) {
+ this._incomingConnections = t0;
+ this._outgoingConnections = t1;
+ this._names = t2;
+ }
+ },
+ K = {
+ GuaranteeChannel$: function(innerStream, innerSink, allowSinkErrors, $T) {
+ var t2, t1 = {};
+ t1.innerStream = innerStream;
+ t2 = new K.GuaranteeChannel($T._eval$1("GuaranteeChannel<0>"));
+ t2.GuaranteeChannel$3$allowSinkErrors(innerSink, allowSinkErrors, t1, $T);
+ return t2;
+ },
+ GuaranteeChannel: function GuaranteeChannel(t0) {
+ var _ = this;
+ _._subscription = _._streamController = _._sink = null;
+ _._disconnected = false;
+ _.$ti = t0;
+ },
+ GuaranteeChannel_closure: function GuaranteeChannel_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ GuaranteeChannel__closure: function GuaranteeChannel__closure(t0) {
+ this.$this = t0;
+ },
+ _GuaranteeSink: function _GuaranteeSink(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._inner = t0;
+ _._channel = t1;
+ _._doneCompleter = t2;
+ _._closed = _._disconnected = false;
+ _._addStreamCompleter = _._addStreamSubscription = null;
+ _._allowErrors = t3;
+ _.$ti = t4;
+ },
+ _GuaranteeSink__addError_closure: function _GuaranteeSink__addError_closure() {
+ },
+ _GuaranteeSink_addStream_closure: function _GuaranteeSink_addStream_closure(t0) {
+ this.$this = t0;
+ },
+ UnicodeGlyphSet: function UnicodeGlyphSet() {
+ },
+ ClosedException$: function() {
+ return new K.ClosedException();
+ },
+ ClosedException: function ClosedException() {
+ }
+ };
+ var holders = [C, H, J, P, W, S, O, Y, F, V, E, L, G, T, X, U, R, B, Q, M, D, Z, A, N, K];
+ hunkHelpers.setFunctionNamesIfNecessary(holders);
+ var $ = {};
+ H.JS_CONST.prototype = {};
+ J.Interceptor.prototype = {
+ $eq: function(receiver, other) {
+ return receiver === other;
+ },
+ get$hashCode: function(receiver) {
+ return H.Primitives_objectHashCode(receiver);
+ },
+ toString$0: function(receiver) {
+ return "Instance of '" + H.S(H.Primitives_objectTypeName(receiver)) + "'";
+ },
+ get$runtimeType: function(receiver) {
+ return H.getRuntimeType(receiver);
+ }
+ };
+ J.JSBool.prototype = {
+ toString$0: function(receiver) {
+ return String(receiver);
+ },
+ get$hashCode: function(receiver) {
+ return receiver ? 519018 : 218159;
+ },
+ get$runtimeType: function(receiver) {
+ return C.Type_bool_lhE;
+ },
+ $isbool: 1
+ };
+ J.JSNull.prototype = {
+ $eq: function(receiver, other) {
+ return null == other;
+ },
+ toString$0: function(receiver) {
+ return "null";
+ },
+ get$hashCode: function(receiver) {
+ return 0;
+ },
+ get$runtimeType: function(receiver) {
+ return C.Type_Null_Yyn;
+ },
+ $isNull: 1
+ };
+ J.JSObject.prototype = {};
+ J.JavaScriptObject.prototype = {
+ get$hashCode: function(receiver) {
+ return 0;
+ },
+ get$runtimeType: function(receiver) {
+ return C.Type_JSObject_8k0;
+ },
+ toString$0: function(receiver) {
+ return String(receiver);
+ },
+ $isJSObject: 1
+ };
+ J.PlainJavaScriptObject.prototype = {};
+ J.UnknownJavaScriptObject.prototype = {};
+ J.JavaScriptFunction.prototype = {
+ toString$0: function(receiver) {
+ var dartClosure = receiver[$.$get$DART_CLOSURE_PROPERTY_NAME()];
+ if (dartClosure == null)
+ return this.super$JavaScriptObject$toString(receiver);
+ return "JavaScript function for " + H.S(J.toString$0$(dartClosure));
+ },
+ $signature: function() {
+ return {func: 1, opt: [,,,,,,,,,,,,,,,,]};
+ },
+ $isFunction: 1
+ };
+ J.JSArray.prototype = {
+ add$1: function(receiver, value) {
+ H._arrayInstanceType(receiver)._precomputed1._check(value);
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("add"));
+ receiver.push(value);
+ },
+ removeAt$1: function(receiver, index) {
+ var t1;
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("removeAt"));
+ t1 = receiver.length;
+ if (index >= t1)
+ throw H.wrapException(P.RangeError$value(index, null));
+ return receiver.splice(index, 1)[0];
+ },
+ insert$2: function(receiver, index, value) {
+ var t1;
+ H._arrayInstanceType(receiver)._precomputed1._check(value);
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("insert"));
+ t1 = receiver.length;
+ if (index > t1)
+ throw H.wrapException(P.RangeError$value(index, null));
+ receiver.splice(index, 0, value);
+ },
+ insertAll$2: function(receiver, index, iterable) {
+ var t1, insertionLength, end;
+ H._arrayInstanceType(receiver)._eval$1("Iterable<1>")._check(iterable);
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("insertAll"));
+ t1 = receiver.length;
+ P.RangeError_checkValueInInterval(index, 0, t1, "index");
+ insertionLength = iterable.length;
+ this.set$length(receiver, t1 + insertionLength);
+ end = index + insertionLength;
+ this.setRange$4(receiver, end, receiver.length, receiver, index);
+ this.setRange$3(receiver, index, end, iterable);
+ },
+ removeLast$0: function(receiver) {
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("removeLast"));
+ if (receiver.length === 0)
+ throw H.wrapException(H.diagnoseIndexError(receiver, -1));
+ return receiver.pop();
+ },
+ remove$1: function(receiver, element) {
+ var i;
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("remove"));
+ for (i = 0; i < receiver.length; ++i)
+ if (J.$eq$(receiver[i], element)) {
+ receiver.splice(i, 1);
+ return true;
+ }
+ return false;
+ },
+ addAll$1: function(receiver, collection) {
+ var i, t1, e, i0;
+ H._arrayInstanceType(receiver)._eval$1("Iterable<1>")._check(collection);
+ i = receiver.length;
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("addAll"));
+ for (t1 = J.get$iterator$ax(collection); t1.moveNext$0(); i = i0) {
+ e = t1.get$current();
+ i0 = i + 1;
+ H.assertHelper(i === receiver.length || H.throwExpression(P.ConcurrentModificationError$(receiver)));
+ receiver.push(e);
+ }
+ },
+ forEach$1: function(receiver, f) {
+ var end, i;
+ H._arrayInstanceType(receiver)._eval$1("~(1)")._check(f);
+ end = receiver.length;
+ for (i = 0; i < end; ++i) {
+ f.call$1(receiver[i]);
+ if (receiver.length !== end)
+ throw H.wrapException(P.ConcurrentModificationError$(receiver));
+ }
+ },
+ map$1$1: function(receiver, f, $T) {
+ var t1 = H._arrayInstanceType(receiver);
+ return new H.MappedListIterable(receiver, t1._bind$1($T)._eval$1("1(2)")._check(f), t1._eval$1("@<1>")._bind$1($T)._eval$1("MappedListIterable<1,2>"));
+ },
+ join$1: function(receiver, separator) {
+ var i,
+ list = new Array(receiver.length);
+ list.fixed$length = Array;
+ for (i = 0; i < receiver.length; ++i)
+ this.$indexSet(list, i, H.S(receiver[i]));
+ return list.join(separator);
+ },
+ join$0: function($receiver) {
+ return this.join$1($receiver, "");
+ },
+ fold$1$2: function(receiver, initialValue, combine, $T) {
+ var $length, value, i;
+ $T._check(initialValue);
+ H._arrayInstanceType(receiver)._bind$1($T)._eval$1("1(1,2)")._check(combine);
+ $length = receiver.length;
+ for (value = initialValue, i = 0; i < $length; ++i) {
+ value = combine.call$2(value, receiver[i]);
+ if (receiver.length !== $length)
+ throw H.wrapException(P.ConcurrentModificationError$(receiver));
+ }
+ return value;
+ },
+ firstWhere$2$orElse: function(receiver, test, orElse) {
+ var end, i, element,
+ t1 = H._arrayInstanceType(receiver);
+ t1._eval$1("bool(1)")._check(test);
+ t1._eval$1("1()")._check(orElse);
+ end = receiver.length;
+ for (i = 0; i < end; ++i) {
+ element = receiver[i];
+ if (H.boolConversionCheck(test.call$1(element)))
+ return element;
+ if (receiver.length !== end)
+ throw H.wrapException(P.ConcurrentModificationError$(receiver));
+ }
+ if (orElse != null)
+ return orElse.call$0();
+ throw H.wrapException(H.IterableElementError_noElement());
+ },
+ firstWhere$1: function($receiver, test) {
+ return this.firstWhere$2$orElse($receiver, test, null);
+ },
+ elementAt$1: function(receiver, index) {
+ if (index < 0 || index >= receiver.length)
+ return H.ioore(receiver, index);
+ return receiver[index];
+ },
+ sublist$2: function(receiver, start, end) {
+ if (start < 0 || start > receiver.length)
+ throw H.wrapException(P.RangeError$range(start, 0, receiver.length, "start", null));
+ if (end < start || end > receiver.length)
+ throw H.wrapException(P.RangeError$range(end, start, receiver.length, "end", null));
+ if (start === end)
+ return H.setRuntimeTypeInfo([], H._arrayInstanceType(receiver));
+ return H.setRuntimeTypeInfo(receiver.slice(start, end), H._arrayInstanceType(receiver));
+ },
+ get$first: function(receiver) {
+ if (receiver.length > 0)
+ return receiver[0];
+ throw H.wrapException(H.IterableElementError_noElement());
+ },
+ get$last: function(receiver) {
+ var t1 = receiver.length;
+ if (t1 > 0)
+ return receiver[t1 - 1];
+ throw H.wrapException(H.IterableElementError_noElement());
+ },
+ get$single: function(receiver) {
+ var t1 = receiver.length;
+ if (t1 === 1) {
+ if (0 >= t1)
+ return H.ioore(receiver, 0);
+ return receiver[0];
+ }
+ if (t1 === 0)
+ throw H.wrapException(H.IterableElementError_noElement());
+ throw H.wrapException(H.IterableElementError_tooMany());
+ },
+ setRange$4: function(receiver, start, end, iterable, skipCount) {
+ var $length, i,
+ t1 = H._arrayInstanceType(receiver);
+ t1._eval$1("Iterable<1>")._check(iterable);
+ if (!!receiver.immutable$list)
+ H.throwExpression(P.UnsupportedError$("setRange"));
+ P.RangeError_checkValidRange(start, end, receiver.length);
+ $length = end - start;
+ if ($length === 0)
+ return;
+ P.RangeError_checkNotNegative(skipCount, "skipCount");
+ t1._eval$1("List<1>")._check(iterable);
+ t1 = J.getInterceptor$asx(iterable);
+ if (skipCount + $length > t1.get$length(iterable))
+ throw H.wrapException(H.IterableElementError_tooFew());
+ if (skipCount < start)
+ for (i = $length - 1; i >= 0; --i)
+ receiver[start + i] = t1.$index(iterable, skipCount + i);
+ else
+ for (i = 0; i < $length; ++i)
+ receiver[start + i] = t1.$index(iterable, skipCount + i);
+ },
+ setRange$3: function($receiver, start, end, iterable) {
+ return this.setRange$4($receiver, start, end, iterable, 0);
+ },
+ fillRange$3: function(receiver, start, end, fillValue) {
+ var i;
+ H._arrayInstanceType(receiver)._precomputed1._check(fillValue);
+ if (!!receiver.immutable$list)
+ H.throwExpression(P.UnsupportedError$("fill range"));
+ P.RangeError_checkValidRange(start, end, receiver.length);
+ for (i = start; i < end; ++i)
+ receiver[i] = fillValue;
+ },
+ replaceRange$3: function(receiver, start, end, replacement) {
+ var t1, removeLength, insertEnd, delta, newLength, _this = this;
+ H._arrayInstanceType(receiver)._eval$1("Iterable<1>")._check(replacement);
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("replaceRange"));
+ t1 = receiver.length;
+ P.RangeError_checkValidRange(start, end, t1);
+ removeLength = end - start;
+ insertEnd = start + 1;
+ if (removeLength >= 1) {
+ delta = removeLength - 1;
+ newLength = t1 - delta;
+ _this.setRange$3(receiver, start, insertEnd, replacement);
+ if (delta !== 0) {
+ _this.setRange$4(receiver, insertEnd, newLength, receiver, end);
+ _this.set$length(receiver, newLength);
+ }
+ } else {
+ newLength = t1 + (1 - removeLength);
+ _this.set$length(receiver, newLength);
+ _this.setRange$4(receiver, insertEnd, newLength, receiver, end);
+ _this.setRange$3(receiver, start, insertEnd, replacement);
+ }
+ },
+ contains$1: function(receiver, other) {
+ var i;
+ for (i = 0; i < receiver.length; ++i)
+ if (J.$eq$(receiver[i], other))
+ return true;
+ return false;
+ },
+ get$isEmpty: function(receiver) {
+ return receiver.length === 0;
+ },
+ toString$0: function(receiver) {
+ return P.IterableBase_iterableToFullString(receiver, "[", "]");
+ },
+ toSet$0: function(receiver) {
+ return P.LinkedHashSet_LinkedHashSet$from(receiver, H._arrayInstanceType(receiver)._precomputed1);
+ },
+ get$iterator: function(receiver) {
+ return new J.ArrayIterator(receiver, receiver.length, H._arrayInstanceType(receiver)._eval$1("ArrayIterator<1>"));
+ },
+ get$hashCode: function(receiver) {
+ return H.Primitives_objectHashCode(receiver);
+ },
+ get$length: function(receiver) {
+ return receiver.length;
+ },
+ set$length: function(receiver, newLength) {
+ var _s9_ = "newLength";
+ if (!!receiver.fixed$length)
+ H.throwExpression(P.UnsupportedError$("set length"));
+ if (!H._isInt(newLength))
+ throw H.wrapException(P.ArgumentError$value(newLength, _s9_, null));
+ if (newLength < 0)
+ throw H.wrapException(P.RangeError$range(newLength, 0, null, _s9_, null));
+ receiver.length = newLength;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ if (!H._isInt(index))
+ throw H.wrapException(H.diagnoseIndexError(receiver, index));
+ if (index >= receiver.length || index < 0)
+ throw H.wrapException(H.diagnoseIndexError(receiver, index));
+ return receiver[index];
+ },
+ $indexSet: function(receiver, index, value) {
+ H._checkIntNullable(index);
+ H._arrayInstanceType(receiver)._precomputed1._check(value);
+ if (!!receiver.immutable$list)
+ H.throwExpression(P.UnsupportedError$("indexed set"));
+ if (!H._isInt(index))
+ throw H.wrapException(H.diagnoseIndexError(receiver, index));
+ if (index >= receiver.length || index < 0)
+ throw H.wrapException(H.diagnoseIndexError(receiver, index));
+ receiver[index] = value;
+ },
+ $isEfficientLengthIterable: 1,
+ $isIterable: 1,
+ $isList: 1
+ };
+ J.JSUnmodifiableArray.prototype = {};
+ J.ArrayIterator.prototype = {
+ get$current: function() {
+ return this._current;
+ },
+ moveNext$0: function() {
+ var t2, _this = this,
+ t1 = _this._iterable,
+ $length = t1.length;
+ if (_this._length !== $length)
+ throw H.wrapException(H.throwConcurrentModificationError(t1));
+ t2 = _this._index;
+ if (t2 >= $length) {
+ _this.set$_current(null);
+ return false;
+ }
+ _this.set$_current(t1[t2]);
+ ++_this._index;
+ return true;
+ },
+ set$_current: function(_current) {
+ this._current = this.$ti._precomputed1._check(_current);
+ },
+ $isIterator: 1
+ };
+ J.JSNumber.prototype = {
+ floor$0: function(receiver) {
+ var truncated, d;
+ if (receiver >= 0) {
+ if (receiver <= 2147483647)
+ return receiver | 0;
+ } else if (receiver >= -2147483648) {
+ truncated = receiver | 0;
+ return receiver === truncated ? truncated : truncated - 1;
+ }
+ d = Math.floor(receiver);
+ if (isFinite(d))
+ return d;
+ throw H.wrapException(P.UnsupportedError$("" + receiver + ".floor()"));
+ },
+ round$0: function(receiver) {
+ if (receiver > 0) {
+ if (receiver !== 1 / 0)
+ return Math.round(receiver);
+ } else if (receiver > -1 / 0)
+ return 0 - Math.round(0 - receiver);
+ throw H.wrapException(P.UnsupportedError$("" + receiver + ".round()"));
+ },
+ toRadixString$1: function(receiver, radix) {
+ var result, match, t1, exponent;
+ if (radix < 2 || radix > 36)
+ throw H.wrapException(P.RangeError$range(radix, 2, 36, "radix", null));
+ result = receiver.toString(radix);
+ if (C.JSString_methods.codeUnitAt$1(result, result.length - 1) !== 41)
+ return result;
+ match = /^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(result);
+ if (match == null)
+ H.throwExpression(P.UnsupportedError$("Unexpected toString result: " + result));
+ t1 = match.length;
+ if (1 >= t1)
+ return H.ioore(match, 1);
+ result = match[1];
+ if (3 >= t1)
+ return H.ioore(match, 3);
+ exponent = +match[3];
+ t1 = match[2];
+ if (t1 != null) {
+ result += t1;
+ exponent -= t1.length;
+ }
+ return result + C.JSString_methods.$mul("0", exponent);
+ },
+ toString$0: function(receiver) {
+ if (receiver === 0 && 1 / receiver < 0)
+ return "-0.0";
+ else
+ return "" + receiver;
+ },
+ get$hashCode: function(receiver) {
+ var absolute, floorLog2, factor, scaled,
+ intValue = receiver | 0;
+ if (receiver === intValue)
+ return 536870911 & intValue;
+ absolute = Math.abs(receiver);
+ floorLog2 = Math.log(absolute) / 0.6931471805599453 | 0;
+ factor = Math.pow(2, floorLog2);
+ scaled = absolute < 1 ? absolute / factor : factor / absolute;
+ return 536870911 & ((scaled * 9007199254740992 | 0) + (scaled * 3542243181176521 | 0)) * 599197 + floorLog2 * 1259;
+ },
+ $mod: function(receiver, other) {
+ var result = receiver % other;
+ if (result === 0)
+ return 0;
+ if (result > 0)
+ return result;
+ if (other < 0)
+ return result - other;
+ else
+ return result + other;
+ },
+ $tdiv: function(receiver, other) {
+ if ((receiver | 0) === receiver)
+ if (other >= 1 || other < -1)
+ return receiver / other | 0;
+ return this._tdivSlow$1(receiver, other);
+ },
+ _tdivFast$1: function(receiver, other) {
+ return (receiver | 0) === receiver ? receiver / other | 0 : this._tdivSlow$1(receiver, other);
+ },
+ _tdivSlow$1: function(receiver, other) {
+ var quotient = receiver / other;
+ if (quotient >= -2147483648 && quotient <= 2147483647)
+ return quotient | 0;
+ if (quotient > 0) {
+ if (quotient !== 1 / 0)
+ return Math.floor(quotient);
+ } else if (quotient > -1 / 0)
+ return Math.ceil(quotient);
+ throw H.wrapException(P.UnsupportedError$("Result of truncating division is " + H.S(quotient) + ": " + H.S(receiver) + " ~/ " + other));
+ },
+ _shlPositive$1: function(receiver, other) {
+ return other > 31 ? 0 : receiver << other >>> 0;
+ },
+ _shrOtherPositive$1: function(receiver, other) {
+ var t1;
+ if (receiver > 0)
+ t1 = this._shrBothPositive$1(receiver, other);
+ else {
+ t1 = other > 31 ? 31 : other;
+ t1 = receiver >> t1 >>> 0;
+ }
+ return t1;
+ },
+ _shrReceiverPositive$1: function(receiver, other) {
+ if (other < 0)
+ throw H.wrapException(H.argumentErrorValue(other));
+ return this._shrBothPositive$1(receiver, other);
+ },
+ _shrBothPositive$1: function(receiver, other) {
+ return other > 31 ? 0 : receiver >>> other;
+ },
+ get$runtimeType: function(receiver) {
+ return C.Type_num_cv7;
+ },
+ $isdouble: 1,
+ $isnum: 1
+ };
+ J.JSInt.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_int_tHn;
+ },
+ $isint: 1
+ };
+ J.JSDouble.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_double_K1J;
+ }
+ };
+ J.JSString.prototype = {
+ codeUnitAt$1: function(receiver, index) {
+ if (index < 0)
+ throw H.wrapException(H.diagnoseIndexError(receiver, index));
+ if (index >= receiver.length)
+ H.throwExpression(H.diagnoseIndexError(receiver, index));
+ return receiver.charCodeAt(index);
+ },
+ _codeUnitAt$1: function(receiver, index) {
+ if (index >= receiver.length)
+ throw H.wrapException(H.diagnoseIndexError(receiver, index));
+ return receiver.charCodeAt(index);
+ },
+ allMatches$2: function(receiver, string, start) {
+ var t1;
+ if (typeof string != "string")
+ H.throwExpression(H.argumentErrorValue(string));
+ t1 = string.length;
+ if (start > t1)
+ throw H.wrapException(P.RangeError$range(start, 0, t1, null, null));
+ return new H._StringAllMatchesIterable(string, receiver, start);
+ },
+ allMatches$1: function($receiver, string) {
+ return this.allMatches$2($receiver, string, 0);
+ },
+ matchAsPrefix$2: function(receiver, string, start) {
+ var t1, t2, i, _null = null;
+ if (start < 0 || start > string.length)
+ throw H.wrapException(P.RangeError$range(start, 0, string.length, _null, _null));
+ t1 = receiver.length;
+ if (start + t1 > string.length)
+ return _null;
+ for (t2 = J.getInterceptor$s(string), i = 0; i < t1; ++i)
+ if (t2.codeUnitAt$1(string, start + i) !== this._codeUnitAt$1(receiver, i))
+ return _null;
+ return new H.StringMatch(start, receiver);
+ },
+ $add: function(receiver, other) {
+ if (typeof other != "string")
+ throw H.wrapException(P.ArgumentError$value(other, null, null));
+ return receiver + other;
+ },
+ endsWith$1: function(receiver, other) {
+ var otherLength = other.length,
+ t1 = receiver.length;
+ if (otherLength > t1)
+ return false;
+ return other === this.substring$1(receiver, t1 - otherLength);
+ },
+ splitMapJoin$2$onMatch: function(receiver, from, onMatch) {
+ return H.stringReplaceAllFuncUnchecked(receiver, from, type$.String_Function_Match._check(onMatch), type$.String_Function_String._check(null));
+ },
+ replaceFirst$2: function(receiver, from, to) {
+ P.RangeError_checkValueInInterval(0, 0, receiver.length, "startIndex");
+ return H.stringReplaceFirstUnchecked(receiver, from, to, 0);
+ },
+ replaceRange$3: function(receiver, start, end, replacement) {
+ end = P.RangeError_checkValidRange(start, end, receiver.length);
+ return H.stringReplaceRangeUnchecked(receiver, start, end, replacement);
+ },
+ startsWith$2: function(receiver, pattern, index) {
+ var endIndex;
+ type$.Pattern._check(pattern);
+ if (index < 0 || index > receiver.length)
+ throw H.wrapException(P.RangeError$range(index, 0, receiver.length, null, null));
+ if (typeof pattern == "string") {
+ endIndex = index + pattern.length;
+ if (endIndex > receiver.length)
+ return false;
+ return pattern === receiver.substring(index, endIndex);
+ }
+ return J.matchAsPrefix$2$s(pattern, receiver, index) != null;
+ },
+ startsWith$1: function($receiver, pattern) {
+ return this.startsWith$2($receiver, pattern, 0);
+ },
+ substring$2: function(receiver, startIndex, endIndex) {
+ if (endIndex == null)
+ endIndex = receiver.length;
+ if (startIndex < 0)
+ throw H.wrapException(P.RangeError$value(startIndex, null));
+ if (startIndex > endIndex)
+ throw H.wrapException(P.RangeError$value(startIndex, null));
+ if (endIndex > receiver.length)
+ throw H.wrapException(P.RangeError$value(endIndex, null));
+ return receiver.substring(startIndex, endIndex);
+ },
+ substring$1: function($receiver, startIndex) {
+ return this.substring$2($receiver, startIndex, null);
+ },
+ trim$0: function(receiver) {
+ var startIndex, t1, endIndex0,
+ result = receiver.trim(),
+ endIndex = result.length;
+ if (endIndex === 0)
+ return result;
+ if (this._codeUnitAt$1(result, 0) === 133) {
+ startIndex = J.JSString__skipLeadingWhitespace(result, 1);
+ if (startIndex === endIndex)
+ return "";
+ } else
+ startIndex = 0;
+ t1 = endIndex - 1;
+ endIndex0 = this.codeUnitAt$1(result, t1) === 133 ? J.JSString__skipTrailingWhitespace(result, t1) : endIndex;
+ if (startIndex === 0 && endIndex0 === endIndex)
+ return result;
+ return result.substring(startIndex, endIndex0);
+ },
+ $mul: function(receiver, times) {
+ var s, result;
+ if (0 >= times)
+ return "";
+ if (times === 1 || receiver.length === 0)
+ return receiver;
+ if (times !== times >>> 0)
+ throw H.wrapException(C.C_OutOfMemoryError);
+ for (s = receiver, result = ""; true;) {
+ if ((times & 1) === 1)
+ result = s + result;
+ times = times >>> 1;
+ if (times === 0)
+ break;
+ s += s;
+ }
+ return result;
+ },
+ padLeft$2: function(receiver, width, padding) {
+ var delta = width - receiver.length;
+ if (delta <= 0)
+ return receiver;
+ return this.$mul(padding, delta) + receiver;
+ },
+ padRight$1: function(receiver, width) {
+ var delta;
+ if (typeof width !== "number")
+ return width.$sub();
+ delta = width - receiver.length;
+ if (delta <= 0)
+ return receiver;
+ return receiver + this.$mul(" ", delta);
+ },
+ indexOf$2: function(receiver, pattern, start) {
+ var t1;
+ if (start < 0 || start > receiver.length)
+ throw H.wrapException(P.RangeError$range(start, 0, receiver.length, null, null));
+ t1 = receiver.indexOf(pattern, start);
+ return t1;
+ },
+ indexOf$1: function($receiver, pattern) {
+ return this.indexOf$2($receiver, pattern, 0);
+ },
+ lastIndexOf$2: function(receiver, pattern, start) {
+ var t1, t2;
+ if (start == null)
+ start = receiver.length;
+ else if (start < 0 || start > receiver.length)
+ throw H.wrapException(P.RangeError$range(start, 0, receiver.length, null, null));
+ t1 = pattern.length;
+ t2 = receiver.length;
+ if (start + t1 > t2)
+ start = t2 - t1;
+ return receiver.lastIndexOf(pattern, start);
+ },
+ lastIndexOf$1: function($receiver, pattern) {
+ return this.lastIndexOf$2($receiver, pattern, null);
+ },
+ contains$1: function(receiver, other) {
+ if (other == null)
+ H.throwExpression(H.argumentErrorValue(other));
+ return H.stringContainsUnchecked(receiver, other, 0);
+ },
+ toString$0: function(receiver) {
+ return receiver;
+ },
+ get$hashCode: function(receiver) {
+ var t1, hash, i;
+ for (t1 = receiver.length, hash = 0, i = 0; i < t1; ++i) {
+ hash = 536870911 & hash + receiver.charCodeAt(i);
+ hash = 536870911 & hash + ((524287 & hash) << 10);
+ hash ^= hash >> 6;
+ }
+ hash = 536870911 & hash + ((67108863 & hash) << 3);
+ hash ^= hash >> 11;
+ return 536870911 & hash + ((16383 & hash) << 15);
+ },
+ get$runtimeType: function(receiver) {
+ return C.Type_String_k8F;
+ },
+ get$length: function(receiver) {
+ return receiver.length;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ if (index >= receiver.length || index < 0)
+ throw H.wrapException(H.diagnoseIndexError(receiver, index));
+ return receiver[index];
+ },
+ $isPattern: 1,
+ $isString: 1
+ };
+ H._CastIterableBase.prototype = {
+ get$iterator: function(_) {
+ var t1 = this._source,
+ t2 = H._instanceType(this);
+ return new H.CastIterator(t1.get$iterator(t1), t2._eval$1("@<1>")._bind$1(t2._rest[1])._eval$1("CastIterator<1,2>"));
+ },
+ get$length: function(_) {
+ var t1 = this._source;
+ return t1.get$length(t1);
+ },
+ get$isEmpty: function(_) {
+ var t1 = this._source;
+ return t1.get$isEmpty(t1);
+ },
+ get$first: function(_) {
+ var t1 = this._source;
+ return H._instanceType(this)._rest[1]._as(t1.get$first(t1));
+ },
+ get$last: function(_) {
+ var t1 = this._source;
+ return H._instanceType(this)._rest[1]._as(t1.get$last(t1));
+ },
+ contains$1: function(_, other) {
+ return this._source.contains$1(0, other);
+ },
+ toString$0: function(_) {
+ return this._source.toString$0(0);
+ }
+ };
+ H.CastIterator.prototype = {
+ moveNext$0: function() {
+ return this._source.moveNext$0();
+ },
+ get$current: function() {
+ return this.$ti._rest[1]._as(this._source.get$current());
+ },
+ $isIterator: 1
+ };
+ H.CastIterable.prototype = {};
+ H._EfficientLengthCastIterable.prototype = {$isEfficientLengthIterable: 1};
+ H.CastMap.prototype = {
+ cast$2$0: function(_, RK, RV) {
+ var t1 = this.$ti;
+ return new H.CastMap(this._source, t1._eval$1("@<1>")._bind$1(t1._rest[1])._bind$1(RK)._bind$1(RV)._eval$1("CastMap<1,2,3,4>"));
+ },
+ containsKey$1: function(key) {
+ return this._source.containsKey$1(key);
+ },
+ $index: function(_, key) {
+ return this.$ti._rest[3]._as(this._source.$index(0, key));
+ },
+ remove$1: function(_, key) {
+ return this.$ti._rest[3]._as(this._source.remove$1(0, key));
+ },
+ forEach$1: function(_, f) {
+ this._source.forEach$1(0, new H.CastMap_forEach_closure(this, this.$ti._eval$1("~(3,4)")._check(f)));
+ },
+ get$keys: function() {
+ var t1 = this.$ti;
+ return H.CastIterable_CastIterable(this._source.get$keys(), t1._precomputed1, t1._rest[2]);
+ },
+ get$length: function(_) {
+ var t1 = this._source;
+ return t1.get$length(t1);
+ },
+ get$isEmpty: function(_) {
+ var t1 = this._source;
+ return t1.get$isEmpty(t1);
+ }
+ };
+ H.CastMap_forEach_closure.prototype = {
+ call$2: function(key, value) {
+ var t1 = this.$this.$ti;
+ t1._precomputed1._check(key);
+ t1._rest[1]._check(value);
+ this.f.call$2(t1._rest[2]._as(key), t1._rest[3]._as(value));
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Null(1,2)");
+ }
+ };
+ H.CodeUnits.prototype = {
+ get$length: function(_) {
+ return this._string.length;
+ },
+ $index: function(_, i) {
+ return C.JSString_methods.codeUnitAt$1(this._string, H._checkIntNullable(i));
+ }
+ };
+ H.EfficientLengthIterable.prototype = {};
+ H.ListIterable.prototype = {
+ get$iterator: function(_) {
+ var _this = this;
+ return new H.ListIterator(_this, _this.get$length(_this), H._instanceType(_this)._eval$1("ListIterator<ListIterable.E>"));
+ },
+ get$isEmpty: function(_) {
+ return this.get$length(this) === 0;
+ },
+ get$first: function(_) {
+ if (this.get$length(this) === 0)
+ throw H.wrapException(H.IterableElementError_noElement());
+ return this.elementAt$1(0, 0);
+ },
+ get$last: function(_) {
+ var _this = this;
+ if (_this.get$length(_this) === 0)
+ throw H.wrapException(H.IterableElementError_noElement());
+ return _this.elementAt$1(0, _this.get$length(_this) - 1);
+ },
+ contains$1: function(_, element) {
+ var i, _this = this,
+ $length = _this.get$length(_this);
+ for (i = 0; i < $length; ++i) {
+ if (J.$eq$(_this.elementAt$1(0, i), element))
+ return true;
+ if ($length !== _this.get$length(_this))
+ throw H.wrapException(P.ConcurrentModificationError$(_this));
+ }
+ return false;
+ },
+ join$1: function(_, separator) {
+ var first, t1, i, _this = this,
+ $length = _this.get$length(_this);
+ if (separator.length !== 0) {
+ if ($length === 0)
+ return "";
+ first = H.S(_this.elementAt$1(0, 0));
+ if ($length !== _this.get$length(_this))
+ throw H.wrapException(P.ConcurrentModificationError$(_this));
+ for (t1 = first, i = 1; i < $length; ++i) {
+ t1 = t1 + separator + H.S(_this.elementAt$1(0, i));
+ if ($length !== _this.get$length(_this))
+ throw H.wrapException(P.ConcurrentModificationError$(_this));
+ }
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ } else {
+ for (i = 0, t1 = ""; i < $length; ++i) {
+ t1 += H.S(_this.elementAt$1(0, i));
+ if ($length !== _this.get$length(_this))
+ throw H.wrapException(P.ConcurrentModificationError$(_this));
+ }
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ }
+ },
+ join$0: function($receiver) {
+ return this.join$1($receiver, "");
+ },
+ map$1$1: function(_, f, $T) {
+ var t1 = H._instanceType(this);
+ return new H.MappedListIterable(this, t1._bind$1($T)._eval$1("1(ListIterable.E)")._check(f), t1._eval$1("@<ListIterable.E>")._bind$1($T)._eval$1("MappedListIterable<1,2>"));
+ },
+ fold$1$2: function(_, initialValue, combine, $T) {
+ var $length, value, i, _this = this;
+ $T._check(initialValue);
+ H._instanceType(_this)._bind$1($T)._eval$1("1(1,ListIterable.E)")._check(combine);
+ $length = _this.get$length(_this);
+ for (value = initialValue, i = 0; i < $length; ++i) {
+ value = combine.call$2(value, _this.elementAt$1(0, i));
+ if ($length !== _this.get$length(_this))
+ throw H.wrapException(P.ConcurrentModificationError$(_this));
+ }
+ return value;
+ },
+ toList$1$growable: function(_, growable) {
+ var i, _this = this,
+ result = H.setRuntimeTypeInfo([], H._instanceType(_this)._eval$1("JSArray<ListIterable.E>"));
+ C.JSArray_methods.set$length(result, _this.get$length(_this));
+ for (i = 0; i < _this.get$length(_this); ++i)
+ C.JSArray_methods.$indexSet(result, i, _this.elementAt$1(0, i));
+ return result;
+ },
+ toList$0: function($receiver) {
+ return this.toList$1$growable($receiver, true);
+ },
+ toSet$0: function(_) {
+ var i, _this = this,
+ result = P.LinkedHashSet_LinkedHashSet(H._instanceType(_this)._eval$1("ListIterable.E"));
+ for (i = 0; i < _this.get$length(_this); ++i)
+ result.add$1(0, _this.elementAt$1(0, i));
+ return result;
+ }
+ };
+ H.SubListIterable.prototype = {
+ get$_endIndex: function() {
+ var $length = J.get$length$asx(this.__internal$_iterable),
+ t1 = this._endOrLength;
+ if (t1 == null || t1 > $length)
+ return $length;
+ return t1;
+ },
+ get$_startIndex: function() {
+ var $length = J.get$length$asx(this.__internal$_iterable),
+ t1 = this.__internal$_start;
+ if (t1 > $length)
+ return $length;
+ return t1;
+ },
+ get$length: function(_) {
+ var t2,
+ $length = J.get$length$asx(this.__internal$_iterable),
+ t1 = this.__internal$_start;
+ if (t1 >= $length)
+ return 0;
+ t2 = this._endOrLength;
+ if (t2 == null || t2 >= $length)
+ return $length - t1;
+ if (typeof t2 !== "number")
+ return t2.$sub();
+ return t2 - t1;
+ },
+ elementAt$1: function(_, index) {
+ var t1, _this = this,
+ realIndex = _this.get$_startIndex() + index;
+ if (index >= 0) {
+ t1 = _this.get$_endIndex();
+ if (typeof t1 !== "number")
+ return H.iae(t1);
+ t1 = realIndex >= t1;
+ } else
+ t1 = true;
+ if (t1)
+ throw H.wrapException(P.IndexError$(index, _this, "index", null, null));
+ return J.elementAt$1$ax(_this.__internal$_iterable, realIndex);
+ },
+ take$1: function(_, count) {
+ var t1, t2, newEnd, _this = this;
+ P.RangeError_checkNotNegative(count, "count");
+ t1 = _this._endOrLength;
+ t2 = _this.__internal$_start;
+ newEnd = t2 + count;
+ if (t1 == null)
+ return H.SubListIterable$(_this.__internal$_iterable, t2, newEnd, _this.$ti._precomputed1);
+ else {
+ if (t1 < newEnd)
+ return _this;
+ return H.SubListIterable$(_this.__internal$_iterable, t2, newEnd, _this.$ti._precomputed1);
+ }
+ }
+ };
+ H.ListIterator.prototype = {
+ get$current: function() {
+ return this.__internal$_current;
+ },
+ moveNext$0: function() {
+ var t3, _this = this,
+ t1 = _this.__internal$_iterable,
+ t2 = J.getInterceptor$asx(t1),
+ $length = t2.get$length(t1);
+ if (_this.__internal$_length !== $length)
+ throw H.wrapException(P.ConcurrentModificationError$(t1));
+ t3 = _this.__internal$_index;
+ if (t3 >= $length) {
+ _this.set$__internal$_current(null);
+ return false;
+ }
+ _this.set$__internal$_current(t2.elementAt$1(t1, t3));
+ ++_this.__internal$_index;
+ return true;
+ },
+ set$__internal$_current: function(_current) {
+ this.__internal$_current = this.$ti._precomputed1._check(_current);
+ },
+ $isIterator: 1
+ };
+ H.MappedIterable.prototype = {
+ get$iterator: function(_) {
+ var t1 = H._instanceType(this);
+ return new H.MappedIterator(J.get$iterator$ax(this.__internal$_iterable), this._f, t1._eval$1("@<1>")._bind$1(t1._rest[1])._eval$1("MappedIterator<1,2>"));
+ },
+ get$length: function(_) {
+ return J.get$length$asx(this.__internal$_iterable);
+ },
+ get$isEmpty: function(_) {
+ return J.get$isEmpty$asx(this.__internal$_iterable);
+ },
+ get$first: function(_) {
+ return this._f.call$1(J.get$first$ax(this.__internal$_iterable));
+ },
+ get$last: function(_) {
+ return this._f.call$1(J.get$last$ax(this.__internal$_iterable));
+ }
+ };
+ H.EfficientLengthMappedIterable.prototype = {$isEfficientLengthIterable: 1};
+ H.MappedIterator.prototype = {
+ moveNext$0: function() {
+ var _this = this,
+ t1 = _this._iterator;
+ if (t1.moveNext$0()) {
+ _this.set$__internal$_current(_this._f.call$1(t1.get$current()));
+ return true;
+ }
+ _this.set$__internal$_current(null);
+ return false;
+ },
+ get$current: function() {
+ return this.__internal$_current;
+ },
+ set$__internal$_current: function(_current) {
+ this.__internal$_current = this.$ti._rest[1]._check(_current);
+ }
+ };
+ H.MappedListIterable.prototype = {
+ get$length: function(_) {
+ return J.get$length$asx(this._source);
+ },
+ elementAt$1: function(_, index) {
+ return this._f.call$1(J.elementAt$1$ax(this._source, index));
+ }
+ };
+ H.WhereIterable.prototype = {
+ get$iterator: function(_) {
+ return new H.WhereIterator(J.get$iterator$ax(this.__internal$_iterable), this._f, this.$ti._eval$1("WhereIterator<1>"));
+ },
+ map$1$1: function(_, f, $T) {
+ var t1 = this.$ti;
+ return new H.MappedIterable(this, t1._bind$1($T)._eval$1("1(2)")._check(f), t1._eval$1("@<1>")._bind$1($T)._eval$1("MappedIterable<1,2>"));
+ }
+ };
+ H.WhereIterator.prototype = {
+ moveNext$0: function() {
+ var t1, t2;
+ for (t1 = this._iterator, t2 = this._f; t1.moveNext$0();)
+ if (H.boolConversionCheck(t2.call$1(t1.get$current())))
+ return true;
+ return false;
+ },
+ get$current: function() {
+ return this._iterator.get$current();
+ }
+ };
+ H.ExpandIterable.prototype = {
+ get$iterator: function(_) {
+ var t1 = this.$ti;
+ return new H.ExpandIterator(J.get$iterator$ax(this.__internal$_iterable), this._f, C.C_EmptyIterator, t1._eval$1("@<1>")._bind$1(t1._rest[1])._eval$1("ExpandIterator<1,2>"));
+ }
+ };
+ H.ExpandIterator.prototype = {
+ get$current: function() {
+ return this.__internal$_current;
+ },
+ moveNext$0: function() {
+ var t1, t2, _this = this;
+ if (_this._currentExpansion == null)
+ return false;
+ for (t1 = _this._iterator, t2 = _this._f; !_this._currentExpansion.moveNext$0();) {
+ _this.set$__internal$_current(null);
+ if (t1.moveNext$0()) {
+ _this.set$_currentExpansion(null);
+ _this.set$_currentExpansion(J.get$iterator$ax(t2.call$1(t1.get$current())));
+ } else
+ return false;
+ }
+ _this.set$__internal$_current(_this._currentExpansion.get$current());
+ return true;
+ },
+ set$_currentExpansion: function(_currentExpansion) {
+ this._currentExpansion = this.$ti._eval$1("Iterator<2>")._check(_currentExpansion);
+ },
+ set$__internal$_current: function(_current) {
+ this.__internal$_current = this.$ti._rest[1]._check(_current);
+ },
+ $isIterator: 1
+ };
+ H.SkipWhileIterable.prototype = {
+ get$iterator: function(_) {
+ return new H.SkipWhileIterator(J.get$iterator$ax(this.__internal$_iterable), this._f, this.$ti._eval$1("SkipWhileIterator<1>"));
+ }
+ };
+ H.SkipWhileIterator.prototype = {
+ moveNext$0: function() {
+ var t1, t2, _this = this;
+ if (!_this._hasSkipped) {
+ _this._hasSkipped = true;
+ for (t1 = _this._iterator, t2 = _this._f; t1.moveNext$0();)
+ if (!H.boolConversionCheck(t2.call$1(t1.get$current())))
+ return true;
+ }
+ return _this._iterator.moveNext$0();
+ },
+ get$current: function() {
+ return this._iterator.get$current();
+ }
+ };
+ H.EmptyIterator.prototype = {
+ moveNext$0: function() {
+ return false;
+ },
+ get$current: function() {
+ return null;
+ },
+ $isIterator: 1
+ };
+ H.FixedLengthListMixin.prototype = {
+ set$length: function(receiver, newLength) {
+ throw H.wrapException(P.UnsupportedError$("Cannot change the length of a fixed-length list"));
+ }
+ };
+ H.UnmodifiableListMixin.prototype = {
+ $indexSet: function(_, index, value) {
+ H._checkIntNullable(index);
+ H._instanceType(this)._eval$1("UnmodifiableListMixin.E")._check(value);
+ throw H.wrapException(P.UnsupportedError$("Cannot modify an unmodifiable list"));
+ },
+ set$length: function(_, newLength) {
+ throw H.wrapException(P.UnsupportedError$("Cannot change the length of an unmodifiable list"));
+ }
+ };
+ H.UnmodifiableListBase.prototype = {};
+ H.ReversedListIterable.prototype = {
+ get$length: function(_) {
+ return J.get$length$asx(this._source);
+ },
+ elementAt$1: function(_, index) {
+ var t1 = this._source,
+ t2 = J.getInterceptor$asx(t1);
+ return t2.elementAt$1(t1, t2.get$length(t1) - 1 - index);
+ }
+ };
+ H.Symbol.prototype = {
+ get$hashCode: function(_) {
+ var hash = this._hashCode;
+ if (hash != null)
+ return hash;
+ hash = 536870911 & 664597 * J.get$hashCode$(this.__internal$_name);
+ this._hashCode = hash;
+ return hash;
+ },
+ toString$0: function(_) {
+ return 'Symbol("' + H.S(this.__internal$_name) + '")';
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof H.Symbol && this.__internal$_name == other.__internal$_name;
+ }
+ };
+ H.ConstantMap.prototype = {
+ cast$2$0: function(_, RK, RV) {
+ var t1 = H._instanceType(this);
+ return P.Map_castFrom(this, t1._precomputed1, t1._rest[1], RK, RV);
+ },
+ get$isEmpty: function(_) {
+ return this.get$length(this) === 0;
+ },
+ toString$0: function(_) {
+ return P.MapBase_mapToString(this);
+ },
+ remove$1: function(_, key) {
+ return H.ConstantMap__throwUnmodifiable();
+ },
+ map$2$1: function(_, transform, K2, V2) {
+ var result = P.LinkedHashMap_LinkedHashMap$_empty(K2, V2);
+ this.forEach$1(0, new H.ConstantMap_map_closure(this, H._instanceType(this)._bind$1(K2)._bind$1(V2)._eval$1("MapEntry<1,2>(3,4)")._check(transform), result));
+ return result;
+ },
+ $isMap: 1
+ };
+ H.ConstantMap_map_closure.prototype = {
+ call$2: function(key, value) {
+ var t1 = H._instanceType(this.$this),
+ entry = this.transform.call$2(t1._precomputed1._check(key), t1._rest[1]._check(value));
+ this.result.$indexSet(0, entry.key, entry.value);
+ },
+ $signature: function() {
+ return H._instanceType(this.$this)._eval$1("Null(1,2)");
+ }
+ };
+ H.ConstantStringMap.prototype = {
+ get$length: function(_) {
+ return this.__js_helper$_length;
+ },
+ containsKey$1: function(key) {
+ if (typeof key != "string")
+ return false;
+ if ("__proto__" === key)
+ return false;
+ return this._jsObject.hasOwnProperty(key);
+ },
+ $index: function(_, key) {
+ if (!this.containsKey$1(key))
+ return null;
+ return this._fetch$1(key);
+ },
+ _fetch$1: function(key) {
+ return this._jsObject[H._checkStringNullable(key)];
+ },
+ forEach$1: function(_, f) {
+ var keys, t2, i, key,
+ t1 = H._instanceType(this);
+ t1._eval$1("~(1,2)")._check(f);
+ keys = this.__js_helper$_keys;
+ for (t2 = keys.length, t1 = t1._rest[1], i = 0; i < t2; ++i) {
+ key = keys[i];
+ f.call$2(key, t1._check(this._fetch$1(key)));
+ }
+ },
+ get$keys: function() {
+ return new H._ConstantMapKeyIterable(this, H._instanceType(this)._eval$1("_ConstantMapKeyIterable<1>"));
+ }
+ };
+ H._ConstantMapKeyIterable.prototype = {
+ get$iterator: function(_) {
+ var t1 = this.__js_helper$_map.__js_helper$_keys;
+ return new J.ArrayIterator(t1, t1.length, H._arrayInstanceType(t1)._eval$1("ArrayIterator<1>"));
+ },
+ get$length: function(_) {
+ return this.__js_helper$_map.__js_helper$_keys.length;
+ }
+ };
+ H.Instantiation.prototype = {
+ Instantiation$1: function(_genericClosure) {
+ if (false)
+ H.instantiatedGenericFunctionType(0, 0);
+ },
+ toString$0: function(_) {
+ var types = "<" + C.JSArray_methods.join$1([H.createRuntimeType(this.$ti._precomputed1)], ", ") + ">";
+ return H.S(this._genericClosure) + " with " + types;
+ }
+ };
+ H.Instantiation1.prototype = {
+ call$2: function(a0, a1) {
+ return this._genericClosure.call$1$2(a0, a1, this.$ti._rest[0]);
+ },
+ call$4: function(a0, a1, a2, a3) {
+ return this._genericClosure.call$1$4(a0, a1, a2, a3, this.$ti._rest[0]);
+ },
+ $signature: function() {
+ return H.instantiatedGenericFunctionType(H.closureFunctionType(this._genericClosure), this.$ti);
+ }
+ };
+ H.Primitives_initTicker_closure.prototype = {
+ call$0: function() {
+ return C.JSNumber_methods.floor$0(1000 * this.performance.now());
+ },
+ $signature: 36
+ };
+ H.TypeErrorDecoder.prototype = {
+ matchTypeError$1: function(message) {
+ var result, t1, _this = this,
+ match = new RegExp(_this._pattern).exec(message);
+ if (match == null)
+ return null;
+ result = Object.create(null);
+ t1 = _this._arguments;
+ if (t1 !== -1)
+ result.arguments = match[t1 + 1];
+ t1 = _this._argumentsExpr;
+ if (t1 !== -1)
+ result.argumentsExpr = match[t1 + 1];
+ t1 = _this._expr;
+ if (t1 !== -1)
+ result.expr = match[t1 + 1];
+ t1 = _this._method;
+ if (t1 !== -1)
+ result.method = match[t1 + 1];
+ t1 = _this._receiver;
+ if (t1 !== -1)
+ result.receiver = match[t1 + 1];
+ return result;
+ }
+ };
+ H.NullError.prototype = {
+ toString$0: function(_) {
+ var t1 = this._method;
+ if (t1 == null)
+ return "NoSuchMethodError: " + H.S(this.__js_helper$_message);
+ return "NoSuchMethodError: method not found: '" + t1 + "' on null";
+ },
+ $isNoSuchMethodError: 1
+ };
+ H.JsNoSuchMethodError.prototype = {
+ toString$0: function(_) {
+ var t2, _this = this,
+ _s38_ = "NoSuchMethodError: method not found: '",
+ t1 = _this._method;
+ if (t1 == null)
+ return "NoSuchMethodError: " + H.S(_this.__js_helper$_message);
+ t2 = _this._receiver;
+ if (t2 == null)
+ return _s38_ + t1 + "' (" + H.S(_this.__js_helper$_message) + ")";
+ return _s38_ + t1 + "' on '" + t2 + "' (" + H.S(_this.__js_helper$_message) + ")";
+ },
+ $isNoSuchMethodError: 1
+ };
+ H.UnknownJsTypeError.prototype = {
+ toString$0: function(_) {
+ var t1 = this.__js_helper$_message;
+ return t1.length === 0 ? "Error" : "Error: " + t1;
+ }
+ };
+ H.ExceptionAndStackTrace.prototype = {};
+ H.unwrapException_saveStackTrace.prototype = {
+ call$1: function(error) {
+ if (type$.Error._is(error))
+ if (error.$thrownJsError == null)
+ error.$thrownJsError = this.ex;
+ return error;
+ },
+ $signature: 18
+ };
+ H._StackTrace.prototype = {
+ toString$0: function(_) {
+ var trace,
+ t1 = this._trace;
+ if (t1 != null)
+ return t1;
+ t1 = this._exception;
+ trace = t1 !== null && typeof t1 === "object" ? t1.stack : null;
+ return this._trace = trace == null ? "" : trace;
+ },
+ $isStackTrace: 1
+ };
+ H.Closure.prototype = {
+ toString$0: function(_) {
+ var $constructor = this.constructor,
+ $name = $constructor == null ? null : $constructor.name;
+ return "Closure '" + H.unminifyOrTag($name == null ? "unknown" : $name) + "'";
+ },
+ $isFunction: 1,
+ get$$call: function() {
+ return this;
+ },
+ "call*": "call$1",
+ $requiredArgCount: 1,
+ $defaultValues: null
+ };
+ H.TearOffClosure.prototype = {};
+ H.StaticClosure.prototype = {
+ toString$0: function(_) {
+ var $name = this.$static_name;
+ if ($name == null)
+ return "Closure of unknown static method";
+ return "Closure '" + H.unminifyOrTag($name) + "'";
+ }
+ };
+ H.BoundClosure.prototype = {
+ $eq: function(_, other) {
+ var _this = this;
+ if (other == null)
+ return false;
+ if (_this === other)
+ return true;
+ if (!(other instanceof H.BoundClosure))
+ return false;
+ return _this._self === other._self && _this._target === other._target && _this._receiver === other._receiver;
+ },
+ get$hashCode: function(_) {
+ var receiverHashCode,
+ t1 = this._receiver;
+ if (t1 == null)
+ receiverHashCode = H.Primitives_objectHashCode(this._self);
+ else
+ receiverHashCode = typeof t1 !== "object" ? J.get$hashCode$(t1) : H.Primitives_objectHashCode(t1);
+ return (receiverHashCode ^ H.Primitives_objectHashCode(this._target)) >>> 0;
+ },
+ toString$0: function(_) {
+ var receiver = this._receiver;
+ if (receiver == null)
+ receiver = this._self;
+ return "Closure '" + H.S(this._name) + "' of " + ("Instance of '" + H.S(H.Primitives_objectTypeName(receiver)) + "'");
+ }
+ };
+ H.TypeErrorImplementation.prototype = {
+ toString$0: function(_) {
+ return this.message;
+ },
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ H.RuntimeError.prototype = {
+ toString$0: function(_) {
+ return "RuntimeError: " + H.S(this.message);
+ },
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ H._AssertionError.prototype = {
+ toString$0: function(_) {
+ return "Assertion failed: " + P.Error_safeToString(this.message);
+ }
+ };
+ H.JsLinkedHashMap.prototype = {
+ get$length: function(_) {
+ return this.__js_helper$_length;
+ },
+ get$isEmpty: function(_) {
+ return this.__js_helper$_length === 0;
+ },
+ get$keys: function() {
+ return new H.LinkedHashMapKeyIterable(this, H._instanceType(this)._eval$1("LinkedHashMapKeyIterable<1>"));
+ },
+ get$values: function() {
+ var t1 = H._instanceType(this);
+ return H.MappedIterable_MappedIterable(this.get$keys(), new H.JsLinkedHashMap_values_closure(this), t1._precomputed1, t1._rest[1]);
+ },
+ containsKey$1: function(key) {
+ var strings, nums, _this = this;
+ if (typeof key == "string") {
+ strings = _this.__js_helper$_strings;
+ if (strings == null)
+ return false;
+ return _this._containsTableEntry$2(strings, key);
+ } else if (typeof key == "number" && (key & 0x3ffffff) === key) {
+ nums = _this.__js_helper$_nums;
+ if (nums == null)
+ return false;
+ return _this._containsTableEntry$2(nums, key);
+ } else
+ return _this.internalContainsKey$1(key);
+ },
+ internalContainsKey$1: function(key) {
+ var _this = this,
+ rest = _this.__js_helper$_rest;
+ if (rest == null)
+ return false;
+ return _this.internalFindBucketIndex$2(_this._getTableBucket$2(rest, _this.internalComputeHashCode$1(key)), key) >= 0;
+ },
+ addAll$1: function(_, other) {
+ H._instanceType(this)._eval$1("Map<1,2>")._check(other).forEach$1(0, new H.JsLinkedHashMap_addAll_closure(this));
+ },
+ $index: function(_, key) {
+ var strings, cell, t1, nums, _this = this, _null = null;
+ if (typeof key == "string") {
+ strings = _this.__js_helper$_strings;
+ if (strings == null)
+ return _null;
+ cell = _this._getTableCell$2(strings, key);
+ t1 = cell == null ? _null : cell.hashMapCellValue;
+ return t1;
+ } else if (typeof key == "number" && (key & 0x3ffffff) === key) {
+ nums = _this.__js_helper$_nums;
+ if (nums == null)
+ return _null;
+ cell = _this._getTableCell$2(nums, key);
+ t1 = cell == null ? _null : cell.hashMapCellValue;
+ return t1;
+ } else
+ return _this.internalGet$1(key);
+ },
+ internalGet$1: function(key) {
+ var bucket, index, _this = this,
+ rest = _this.__js_helper$_rest;
+ if (rest == null)
+ return null;
+ bucket = _this._getTableBucket$2(rest, _this.internalComputeHashCode$1(key));
+ index = _this.internalFindBucketIndex$2(bucket, key);
+ if (index < 0)
+ return null;
+ return bucket[index].hashMapCellValue;
+ },
+ $indexSet: function(_, key, value) {
+ var strings, nums, _this = this,
+ t1 = H._instanceType(_this);
+ t1._precomputed1._check(key);
+ t1._rest[1]._check(value);
+ if (typeof key == "string") {
+ strings = _this.__js_helper$_strings;
+ _this.__js_helper$_addHashTableEntry$3(strings == null ? _this.__js_helper$_strings = _this._newHashTable$0() : strings, key, value);
+ } else if (typeof key == "number" && (key & 0x3ffffff) === key) {
+ nums = _this.__js_helper$_nums;
+ _this.__js_helper$_addHashTableEntry$3(nums == null ? _this.__js_helper$_nums = _this._newHashTable$0() : nums, key, value);
+ } else
+ _this.internalSet$2(key, value);
+ },
+ internalSet$2: function(key, value) {
+ var rest, hash, bucket, index, _this = this,
+ t1 = H._instanceType(_this);
+ t1._precomputed1._check(key);
+ t1._rest[1]._check(value);
+ rest = _this.__js_helper$_rest;
+ if (rest == null)
+ rest = _this.__js_helper$_rest = _this._newHashTable$0();
+ hash = _this.internalComputeHashCode$1(key);
+ bucket = _this._getTableBucket$2(rest, hash);
+ if (bucket == null)
+ _this._setTableEntry$3(rest, hash, [_this._newLinkedCell$2(key, value)]);
+ else {
+ index = _this.internalFindBucketIndex$2(bucket, key);
+ if (index >= 0)
+ bucket[index].hashMapCellValue = value;
+ else
+ bucket.push(_this._newLinkedCell$2(key, value));
+ }
+ },
+ putIfAbsent$2: function(key, ifAbsent) {
+ var value, _this = this,
+ t1 = H._instanceType(_this);
+ t1._precomputed1._check(key);
+ t1._eval$1("2()")._check(ifAbsent);
+ if (_this.containsKey$1(key))
+ return _this.$index(0, key);
+ value = ifAbsent.call$0();
+ _this.$indexSet(0, key, value);
+ return value;
+ },
+ remove$1: function(_, key) {
+ var _this = this;
+ if (typeof key == "string")
+ return _this.__js_helper$_removeHashTableEntry$2(_this.__js_helper$_strings, key);
+ else if (typeof key == "number" && (key & 0x3ffffff) === key)
+ return _this.__js_helper$_removeHashTableEntry$2(_this.__js_helper$_nums, key);
+ else
+ return _this.internalRemove$1(key);
+ },
+ internalRemove$1: function(key) {
+ var hash, bucket, index, cell, _this = this,
+ rest = _this.__js_helper$_rest;
+ if (rest == null)
+ return null;
+ hash = _this.internalComputeHashCode$1(key);
+ bucket = _this._getTableBucket$2(rest, hash);
+ index = _this.internalFindBucketIndex$2(bucket, key);
+ if (index < 0)
+ return null;
+ cell = bucket.splice(index, 1)[0];
+ _this.__js_helper$_unlinkCell$1(cell);
+ if (bucket.length === 0)
+ _this._deleteTableEntry$2(rest, hash);
+ return cell.hashMapCellValue;
+ },
+ clear$0: function(_) {
+ var _this = this;
+ if (_this.__js_helper$_length > 0) {
+ _this.__js_helper$_strings = _this.__js_helper$_nums = _this.__js_helper$_rest = _this._first = _this._last = null;
+ _this.__js_helper$_length = 0;
+ _this._modified$0();
+ }
+ },
+ forEach$1: function(_, action) {
+ var cell, modifications, _this = this;
+ H._instanceType(_this)._eval$1("~(1,2)")._check(action);
+ cell = _this._first;
+ modifications = _this._modifications;
+ for (; cell != null;) {
+ action.call$2(cell.hashMapCellKey, cell.hashMapCellValue);
+ if (modifications !== _this._modifications)
+ throw H.wrapException(P.ConcurrentModificationError$(_this));
+ cell = cell._next;
+ }
+ },
+ __js_helper$_addHashTableEntry$3: function(table, key, value) {
+ var cell, _this = this,
+ t1 = H._instanceType(_this);
+ t1._precomputed1._check(key);
+ t1._rest[1]._check(value);
+ cell = _this._getTableCell$2(table, key);
+ if (cell == null)
+ _this._setTableEntry$3(table, key, _this._newLinkedCell$2(key, value));
+ else
+ cell.hashMapCellValue = value;
+ },
+ __js_helper$_removeHashTableEntry$2: function(table, key) {
+ var cell;
+ if (table == null)
+ return null;
+ cell = this._getTableCell$2(table, key);
+ if (cell == null)
+ return null;
+ this.__js_helper$_unlinkCell$1(cell);
+ this._deleteTableEntry$2(table, key);
+ return cell.hashMapCellValue;
+ },
+ _modified$0: function() {
+ this._modifications = this._modifications + 1 & 67108863;
+ },
+ _newLinkedCell$2: function(key, value) {
+ var last, _this = this,
+ t1 = H._instanceType(_this),
+ cell = new H.LinkedHashMapCell(t1._precomputed1._check(key), t1._rest[1]._check(value));
+ if (_this._first == null)
+ _this._first = _this._last = cell;
+ else {
+ last = _this._last;
+ cell._previous = last;
+ _this._last = last._next = cell;
+ }
+ ++_this.__js_helper$_length;
+ _this._modified$0();
+ return cell;
+ },
+ __js_helper$_unlinkCell$1: function(cell) {
+ var _this = this,
+ previous = cell._previous,
+ next = cell._next;
+ if (previous == null) {
+ H.assertHelper(cell == _this._first);
+ _this._first = next;
+ } else
+ previous._next = next;
+ if (next == null) {
+ H.assertHelper(cell == _this._last);
+ _this._last = previous;
+ } else
+ next._previous = previous;
+ --_this.__js_helper$_length;
+ _this._modified$0();
+ },
+ internalComputeHashCode$1: function(key) {
+ return J.get$hashCode$(key) & 0x3ffffff;
+ },
+ internalFindBucketIndex$2: function(bucket, key) {
+ var $length, i;
+ if (bucket == null)
+ return -1;
+ $length = bucket.length;
+ for (i = 0; i < $length; ++i)
+ if (J.$eq$(bucket[i].hashMapCellKey, key))
+ return i;
+ return -1;
+ },
+ toString$0: function(_) {
+ return P.MapBase_mapToString(this);
+ },
+ _getTableCell$2: function(table, key) {
+ return table[key];
+ },
+ _getTableBucket$2: function(table, key) {
+ return table[key];
+ },
+ _setTableEntry$3: function(table, key, value) {
+ H.assertHelper(value != null);
+ table[key] = value;
+ },
+ _deleteTableEntry$2: function(table, key) {
+ delete table[key];
+ },
+ _containsTableEntry$2: function(table, key) {
+ return this._getTableCell$2(table, key) != null;
+ },
+ _newHashTable$0: function() {
+ var _s20_ = "<non-identifier-key>",
+ table = Object.create(null);
+ this._setTableEntry$3(table, _s20_, table);
+ this._deleteTableEntry$2(table, _s20_);
+ return table;
+ },
+ $isLinkedHashMap: 1
+ };
+ H.JsLinkedHashMap_values_closure.prototype = {
+ call$1: function(each) {
+ var t1 = this.$this;
+ return t1.$index(0, H._instanceType(t1)._precomputed1._check(each));
+ },
+ $signature: function() {
+ return H._instanceType(this.$this)._eval$1("2(1)");
+ }
+ };
+ H.JsLinkedHashMap_addAll_closure.prototype = {
+ call$2: function(key, value) {
+ var t1 = this.$this,
+ t2 = H._instanceType(t1);
+ t1.$indexSet(0, t2._precomputed1._check(key), t2._rest[1]._check(value));
+ },
+ $signature: function() {
+ return H._instanceType(this.$this)._eval$1("Null(1,2)");
+ }
+ };
+ H.LinkedHashMapCell.prototype = {};
+ H.LinkedHashMapKeyIterable.prototype = {
+ get$length: function(_) {
+ return this.__js_helper$_map.__js_helper$_length;
+ },
+ get$isEmpty: function(_) {
+ return this.__js_helper$_map.__js_helper$_length === 0;
+ },
+ get$iterator: function(_) {
+ var t1 = this.__js_helper$_map,
+ t2 = new H.LinkedHashMapKeyIterator(t1, t1._modifications, this.$ti._eval$1("LinkedHashMapKeyIterator<1>"));
+ t2._cell = t1._first;
+ return t2;
+ },
+ contains$1: function(_, element) {
+ return this.__js_helper$_map.containsKey$1(element);
+ }
+ };
+ H.LinkedHashMapKeyIterator.prototype = {
+ get$current: function() {
+ return this.__js_helper$_current;
+ },
+ moveNext$0: function() {
+ var _this = this,
+ t1 = _this.__js_helper$_map;
+ if (_this._modifications !== t1._modifications)
+ throw H.wrapException(P.ConcurrentModificationError$(t1));
+ else {
+ t1 = _this._cell;
+ if (t1 == null) {
+ _this.set$__js_helper$_current(null);
+ return false;
+ } else {
+ _this.set$__js_helper$_current(t1.hashMapCellKey);
+ _this._cell = _this._cell._next;
+ return true;
+ }
+ }
+ },
+ set$__js_helper$_current: function(_current) {
+ this.__js_helper$_current = this.$ti._precomputed1._check(_current);
+ },
+ $isIterator: 1
+ };
+ H.initHooks_closure.prototype = {
+ call$1: function(o) {
+ return this.getTag(o);
+ },
+ $signature: 18
+ };
+ H.initHooks_closure0.prototype = {
+ call$2: function(o, tag) {
+ return this.getUnknownTag(o, tag);
+ },
+ $signature: 104
+ };
+ H.initHooks_closure1.prototype = {
+ call$1: function(tag) {
+ return this.prototypeForTag(H._checkStringNullable(tag));
+ },
+ $signature: 94
+ };
+ H.JSSyntaxRegExp.prototype = {
+ toString$0: function(_) {
+ return "RegExp/" + this.pattern + "/" + this._nativeRegExp.flags;
+ },
+ get$_nativeGlobalVersion: function() {
+ var _this = this,
+ t1 = _this._nativeGlobalRegExp;
+ if (t1 != null)
+ return t1;
+ t1 = _this._nativeRegExp;
+ return _this._nativeGlobalRegExp = H.JSSyntaxRegExp_makeNative(_this.pattern, t1.multiline, !t1.ignoreCase, t1.unicode, t1.dotAll, true);
+ },
+ get$_nativeAnchoredVersion: function() {
+ var _this = this,
+ t1 = _this._nativeAnchoredRegExp;
+ if (t1 != null)
+ return t1;
+ t1 = _this._nativeRegExp;
+ return _this._nativeAnchoredRegExp = H.JSSyntaxRegExp_makeNative(_this.pattern + "|()", t1.multiline, !t1.ignoreCase, t1.unicode, t1.dotAll, true);
+ },
+ firstMatch$1: function(string) {
+ var m;
+ if (typeof string != "string")
+ H.throwExpression(H.argumentErrorValue(string));
+ m = this._nativeRegExp.exec(string);
+ if (m == null)
+ return null;
+ return H._MatchImplementation$(this, m);
+ },
+ allMatches$2: function(_, string, start) {
+ var t1 = string.length;
+ if (start > t1)
+ throw H.wrapException(P.RangeError$range(start, 0, t1, null, null));
+ return new H._AllMatchesIterable(this, string, start);
+ },
+ allMatches$1: function($receiver, string) {
+ return this.allMatches$2($receiver, string, 0);
+ },
+ _execGlobal$2: function(string, start) {
+ var match,
+ regexp = this.get$_nativeGlobalVersion();
+ regexp.lastIndex = start;
+ match = regexp.exec(string);
+ if (match == null)
+ return null;
+ return H._MatchImplementation$(this, match);
+ },
+ _execAnchored$2: function(string, start) {
+ var match,
+ regexp = this.get$_nativeAnchoredVersion();
+ regexp.lastIndex = start;
+ match = regexp.exec(string);
+ if (match == null)
+ return null;
+ if (0 >= match.length)
+ return H.ioore(match, -1);
+ if (match.pop() != null)
+ return null;
+ return H._MatchImplementation$(this, match);
+ },
+ matchAsPrefix$2: function(_, string, start) {
+ if (start < 0 || start > string.length)
+ throw H.wrapException(P.RangeError$range(start, 0, string.length, null, null));
+ return this._execAnchored$2(string, start);
+ },
+ $isPattern: 1,
+ $isRegExp: 1
+ };
+ H._MatchImplementation.prototype = {
+ get$start: function() {
+ return this._match.index;
+ },
+ get$end: function() {
+ var t1 = this._match;
+ return t1.index + t1[0].length;
+ },
+ $index: function(_, index) {
+ var t1;
+ H._checkIntNullable(index);
+ t1 = this._match;
+ if (index >= t1.length)
+ return H.ioore(t1, index);
+ return t1[index];
+ },
+ $isMatch: 1,
+ $isRegExpMatch: 1
+ };
+ H._AllMatchesIterable.prototype = {
+ get$iterator: function(_) {
+ return new H._AllMatchesIterator(this._re, this.__js_helper$_string, this._start);
+ }
+ };
+ H._AllMatchesIterator.prototype = {
+ get$current: function() {
+ return this.__js_helper$_current;
+ },
+ moveNext$0: function() {
+ var t2, t3, match, nextIndex, _this = this,
+ t1 = _this.__js_helper$_string;
+ if (t1 == null)
+ return false;
+ t2 = _this._nextIndex;
+ if (t2 <= t1.length) {
+ t3 = _this._regExp;
+ match = t3._execGlobal$2(t1, t2);
+ if (match != null) {
+ _this.__js_helper$_current = match;
+ nextIndex = match.get$end();
+ if (match._match.index === nextIndex) {
+ if (t3._nativeRegExp.unicode) {
+ t1 = _this._nextIndex;
+ t2 = t1 + 1;
+ t3 = _this.__js_helper$_string;
+ if (t2 < t3.length) {
+ t1 = J.getInterceptor$s(t3).codeUnitAt$1(t3, t1);
+ if (t1 >= 55296 && t1 <= 56319) {
+ t1 = C.JSString_methods.codeUnitAt$1(t3, t2);
+ t1 = t1 >= 56320 && t1 <= 57343;
+ } else
+ t1 = false;
+ } else
+ t1 = false;
+ } else
+ t1 = false;
+ nextIndex = (t1 ? nextIndex + 1 : nextIndex) + 1;
+ }
+ _this._nextIndex = nextIndex;
+ return true;
+ }
+ }
+ _this.__js_helper$_string = _this.__js_helper$_current = null;
+ return false;
+ },
+ $isIterator: 1
+ };
+ H.StringMatch.prototype = {
+ get$end: function() {
+ return this.start + this.pattern.length;
+ },
+ $index: function(_, g) {
+ H._checkIntNullable(g);
+ if (g !== 0)
+ H.throwExpression(P.RangeError$value(g, null));
+ return this.pattern;
+ },
+ $isMatch: 1,
+ get$start: function() {
+ return this.start;
+ }
+ };
+ H._StringAllMatchesIterable.prototype = {
+ get$iterator: function(_) {
+ return new H._StringAllMatchesIterator(this._input, this._pattern, this.__js_helper$_index);
+ },
+ get$first: function(_) {
+ var t1 = this._pattern,
+ index = this._input.indexOf(t1, this.__js_helper$_index);
+ if (index >= 0)
+ return new H.StringMatch(index, t1);
+ throw H.wrapException(H.IterableElementError_noElement());
+ }
+ };
+ H._StringAllMatchesIterator.prototype = {
+ moveNext$0: function() {
+ var index, end, _this = this,
+ t1 = _this.__js_helper$_index,
+ t2 = _this._pattern,
+ t3 = t2.length,
+ t4 = _this._input,
+ t5 = t4.length;
+ if (t1 + t3 > t5) {
+ _this.__js_helper$_current = null;
+ return false;
+ }
+ index = t4.indexOf(t2, t1);
+ if (index < 0) {
+ _this.__js_helper$_index = t5 + 1;
+ _this.__js_helper$_current = null;
+ return false;
+ }
+ end = index + t3;
+ _this.__js_helper$_current = new H.StringMatch(index, t2);
+ _this.__js_helper$_index = end === _this.__js_helper$_index ? end + 1 : end;
+ return true;
+ },
+ get$current: function() {
+ return this.__js_helper$_current;
+ },
+ $isIterator: 1
+ };
+ H.NativeByteBuffer.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_ByteBuffer_RkP;
+ },
+ $isNativeByteBuffer: 1,
+ $isByteBuffer: 1
+ };
+ H.NativeTypedData.prototype = {$isNativeTypedData: 1};
+ H.NativeByteData.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_ByteData_zNC;
+ }
+ };
+ H.NativeTypedArray.prototype = {
+ get$length: function(receiver) {
+ return receiver.length;
+ },
+ $isJavaScriptIndexingBehavior: 1
+ };
+ H.NativeTypedArrayOfDouble.prototype = {
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ H._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $indexSet: function(receiver, index, value) {
+ H._checkIntNullable(index);
+ H._checkDoubleNullable(value);
+ H._checkValidIndex(index, receiver, receiver.length);
+ receiver[index] = value;
+ },
+ $isEfficientLengthIterable: 1,
+ $isIterable: 1,
+ $isList: 1
+ };
+ H.NativeTypedArrayOfInt.prototype = {
+ $indexSet: function(receiver, index, value) {
+ H._checkIntNullable(index);
+ H._checkIntNullable(value);
+ H._checkValidIndex(index, receiver, receiver.length);
+ receiver[index] = value;
+ },
+ $isEfficientLengthIterable: 1,
+ $isIterable: 1,
+ $isList: 1
+ };
+ H.NativeFloat32List.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Float32List_LB7;
+ }
+ };
+ H.NativeFloat64List.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Float64List_LB7;
+ }
+ };
+ H.NativeInt16List.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Int16List_uXf;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ H._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ }
+ };
+ H.NativeInt32List.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Int32List_O50;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ H._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ }
+ };
+ H.NativeInt8List.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Int8List_ekJ;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ H._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ }
+ };
+ H.NativeUint16List.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Uint16List_2bx;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ H._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ }
+ };
+ H.NativeUint32List.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Uint32List_2bx;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ H._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ sublist$2: function(receiver, start, end) {
+ return new Uint32Array(receiver.subarray(start, H._checkValidRange(start, end, receiver.length)));
+ },
+ $isUint32List: 1
+ };
+ H.NativeUint8ClampedList.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Uint8ClampedList_Jik;
+ },
+ get$length: function(receiver) {
+ return receiver.length;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ H._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ }
+ };
+ H.NativeUint8List.prototype = {
+ get$runtimeType: function(receiver) {
+ return C.Type_Uint8List_WLA;
+ },
+ get$length: function(receiver) {
+ return receiver.length;
+ },
+ $index: function(receiver, index) {
+ H._checkIntNullable(index);
+ H._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ sublist$2: function(receiver, start, end) {
+ return new Uint8Array(receiver.subarray(start, H._checkValidRange(start, end, receiver.length)));
+ },
+ $isNativeUint8List: 1,
+ $isUint8List: 1
+ };
+ H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin.prototype = {};
+ H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin.prototype = {};
+ H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin.prototype = {};
+ H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin.prototype = {};
+ H.Rti.prototype = {
+ _eval$1: function(recipe) {
+ return H._Universe_evalInEnvironment(init.typeUniverse, this, recipe);
+ },
+ _bind$1: function(typeOrTuple) {
+ return H._Universe_bind(init.typeUniverse, this, typeOrTuple);
+ }
+ };
+ H._FunctionParameters.prototype = {};
+ H._Type.prototype = {
+ get$hashCode: function(_) {
+ var s,
+ t1 = this._hashCode;
+ if (t1 == null) {
+ s = this._rti._canonicalRecipe;
+ if (H.assertTest(typeof s == "string"))
+ H.assertThrow("Missing canonical recipe");
+ t1 = this._hashCode = C.JSString_methods.get$hashCode(s);
+ }
+ return t1;
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof H._Type && this._rti == other._rti;
+ },
+ toString$0: function(_) {
+ return H._rtiToString(this._rti, null);
+ },
+ $isType: 1
+ };
+ H._Error.prototype = {
+ toString$0: function(_) {
+ return this._message;
+ }
+ };
+ H._CastError.prototype = {};
+ H._TypeError.prototype = {
+ get$message: function(_) {
+ return this._message;
+ }
+ };
+ P._AsyncRun__initializeScheduleImmediate_internalCallback.prototype = {
+ call$1: function(_) {
+ var t1 = this._box_0,
+ f = t1.storedCallback;
+ t1.storedCallback = null;
+ f.call$0();
+ },
+ $signature: 3
+ };
+ P._AsyncRun__initializeScheduleImmediate_closure.prototype = {
+ call$1: function(callback) {
+ var t1, t2;
+ type$.void_Function._check(callback);
+ t1 = this._box_0;
+ H.assertHelper(t1.storedCallback == null);
+ t1.storedCallback = callback;
+ t1 = this.div;
+ t2 = this.span;
+ t1.firstChild ? t1.removeChild(t2) : t1.appendChild(t2);
+ },
+ $signature: 91
+ };
+ P._AsyncRun__scheduleImmediateJsOverride_internalCallback.prototype = {
+ call$0: function() {
+ this.callback.call$0();
+ },
+ $signature: 0
+ };
+ P._AsyncRun__scheduleImmediateWithSetImmediate_internalCallback.prototype = {
+ call$0: function() {
+ this.callback.call$0();
+ },
+ $signature: 0
+ };
+ P._TimerImpl.prototype = {
+ _TimerImpl$2: function(milliseconds, callback) {
+ if (self.setTimeout != null)
+ this._handle = self.setTimeout(H.convertDartClosureToJS(new P._TimerImpl_internalCallback(this, callback), 0), milliseconds);
+ else
+ throw H.wrapException(P.UnsupportedError$("`setTimeout()` not found."));
+ },
+ _TimerImpl$periodic$2: function(milliseconds, callback) {
+ if (self.setTimeout != null)
+ this._handle = self.setInterval(H.convertDartClosureToJS(new P._TimerImpl$periodic_closure(this, milliseconds, Date.now(), callback), 0), milliseconds);
+ else
+ throw H.wrapException(P.UnsupportedError$("Periodic timer."));
+ },
+ cancel$0: function() {
+ if (self.setTimeout != null) {
+ var t1 = this._handle;
+ if (t1 == null)
+ return;
+ if (this._once)
+ self.clearTimeout(t1);
+ else
+ self.clearInterval(t1);
+ this._handle = null;
+ } else
+ throw H.wrapException(P.UnsupportedError$("Canceling a timer."));
+ },
+ $isTimer: 1
+ };
+ P._TimerImpl_internalCallback.prototype = {
+ call$0: function() {
+ var t1 = this.$this;
+ t1._handle = null;
+ t1._tick = 1;
+ this.callback.call$0();
+ },
+ $signature: 1
+ };
+ P._TimerImpl$periodic_closure.prototype = {
+ call$0: function() {
+ var duration, _this = this,
+ t1 = _this.$this,
+ tick = t1._tick + 1,
+ t2 = _this.milliseconds;
+ if (t2 > 0) {
+ duration = Date.now() - _this.start;
+ if (duration > (tick + 1) * t2)
+ tick = C.JSInt_methods.$tdiv(duration, t2);
+ }
+ t1._tick = tick;
+ _this.callback.call$1(t1);
+ },
+ $signature: 0
+ };
+ P._AsyncAwaitCompleter.prototype = {
+ complete$1: function(value) {
+ var t2, t3,
+ t1 = this.$ti;
+ t1._eval$1("1/")._check(value);
+ t2 = !this.isSync || t1._eval$1("Future<1>")._is(value);
+ t3 = this._future;
+ if (t2)
+ t3._asyncComplete$1(value);
+ else
+ t3._completeWithValue$1(t1._precomputed1._check(value));
+ },
+ completeError$2: function(e, st) {
+ var t1 = this._future;
+ if (this.isSync)
+ t1._completeError$2(e, st);
+ else
+ t1._asyncCompleteError$2(e, st);
+ },
+ $isCompleter: 1
+ };
+ P._awaitOnObject_closure.prototype = {
+ call$1: function(result) {
+ return this.bodyFunction.call$2(0, result);
+ },
+ $signature: 15
+ };
+ P._awaitOnObject_closure0.prototype = {
+ call$2: function(error, stackTrace) {
+ this.bodyFunction.call$2(1, new H.ExceptionAndStackTrace(error, type$.StackTrace._check(stackTrace)));
+ },
+ $signature: 5
+ };
+ P._wrapJsFunctionForAsync_closure.prototype = {
+ call$2: function(errorCode, result) {
+ this.$protected(H._checkIntNullable(errorCode), result);
+ },
+ $signature: 89
+ };
+ P._BroadcastStream.prototype = {
+ get$isBroadcast: function() {
+ return true;
+ }
+ };
+ P._BroadcastSubscription.prototype = {
+ _onPause$0: function() {
+ },
+ _onResume$0: function() {
+ },
+ set$_async$_next: function(_next) {
+ this._async$_next = this.$ti._check(_next);
+ },
+ set$_async$_previous: function(_previous) {
+ this._async$_previous = this.$ti._check(_previous);
+ }
+ };
+ P._BroadcastStreamController.prototype = {
+ get$_mayAddEvent: function() {
+ return this._state < 4;
+ },
+ _ensureDoneFuture$0: function() {
+ var t1 = this._doneFuture;
+ if (t1 != null)
+ return t1;
+ return this._doneFuture = new P._Future($.Zone__current, type$._Future_dynamic);
+ },
+ _removeListener$1: function(subscription) {
+ var previous, next, _this = this;
+ H._instanceType(_this)._eval$1("_BroadcastSubscription<1>")._check(subscription);
+ H.assertHelper(subscription._controller === _this);
+ H.assertHelper(subscription._async$_next !== subscription);
+ previous = subscription._async$_previous;
+ next = subscription._async$_next;
+ if (previous == null)
+ _this.set$_firstSubscription(next);
+ else
+ previous.set$_async$_next(next);
+ if (next == null)
+ _this.set$_lastSubscription(previous);
+ else
+ next.set$_async$_previous(previous);
+ subscription.set$_async$_previous(subscription);
+ subscription.set$_async$_next(subscription);
+ },
+ _subscribe$4: function(onData, onError, onDone, cancelOnError) {
+ var t2, t3, t4, subscription, oldLast, _this = this,
+ t1 = H._instanceType(_this);
+ t1._eval$1("~(1)")._check(onData);
+ type$.void_Function._check(onDone);
+ if ((_this._state & 4) !== 0) {
+ if (onDone == null)
+ onDone = P.async___nullDoneHandler$closure();
+ t1 = new P._DoneStreamSubscription($.Zone__current, onDone, t1._eval$1("_DoneStreamSubscription<1>"));
+ t1._schedule$0();
+ return t1;
+ }
+ t2 = $.Zone__current;
+ t3 = cancelOnError ? 1 : 0;
+ t4 = t1._eval$1("_BroadcastSubscription<1>");
+ subscription = new P._BroadcastSubscription(_this, t2, t3, t4);
+ subscription._BufferingStreamSubscription$4(onData, onError, onDone, cancelOnError, t1._precomputed1);
+ subscription.set$_async$_previous(subscription);
+ subscription.set$_async$_next(subscription);
+ t4._check(subscription);
+ H.assertHelper(subscription._async$_next === subscription);
+ subscription._eventState = _this._state & 1;
+ oldLast = _this._lastSubscription;
+ _this.set$_lastSubscription(subscription);
+ subscription.set$_async$_next(null);
+ subscription.set$_async$_previous(oldLast);
+ if (oldLast == null)
+ _this.set$_firstSubscription(subscription);
+ else
+ oldLast.set$_async$_next(subscription);
+ if (_this._firstSubscription == _this._lastSubscription)
+ P._runGuarded(_this.onListen);
+ return subscription;
+ },
+ _recordCancel$1: function(sub) {
+ var _this = this,
+ t1 = H._instanceType(_this);
+ sub = t1._eval$1("_BroadcastSubscription<1>")._check(t1._eval$1("StreamSubscription<1>")._check(sub));
+ if (sub._async$_next === sub)
+ return null;
+ t1 = (sub._eventState & 2) !== 0;
+ if (t1) {
+ H.assertHelper(t1);
+ sub._eventState |= 4;
+ } else {
+ _this._removeListener$1(sub);
+ if ((_this._state & 2) === 0 && _this._firstSubscription == null)
+ _this._callOnCancel$0();
+ }
+ return null;
+ },
+ _recordPause$1: function(subscription) {
+ H._instanceType(this)._eval$1("StreamSubscription<1>")._check(subscription);
+ },
+ _recordResume$1: function(subscription) {
+ H._instanceType(this)._eval$1("StreamSubscription<1>")._check(subscription);
+ },
+ _addEventError$0: function() {
+ var t1 = this._state;
+ if ((t1 & 4) !== 0)
+ return new P.StateError("Cannot add new events after calling close");
+ H.assertHelper((t1 & 8) !== 0);
+ return new P.StateError("Cannot add new events while doing an addStream");
+ },
+ add$1: function(_, data) {
+ var _this = this;
+ H._instanceType(_this)._precomputed1._check(data);
+ if (!_this.get$_mayAddEvent())
+ throw H.wrapException(_this._addEventError$0());
+ _this._sendData$1(data);
+ },
+ addError$2: function(error, stackTrace) {
+ var replacement;
+ type$.StackTrace._check(stackTrace);
+ if (error == null)
+ error = new P.NullThrownError();
+ if (!this.get$_mayAddEvent())
+ throw H.wrapException(this._addEventError$0());
+ replacement = $.Zone__current.errorCallback$2(error, stackTrace);
+ if (replacement != null) {
+ error = replacement.error;
+ if (error == null)
+ error = new P.NullThrownError();
+ stackTrace = replacement.stackTrace;
+ }
+ this._sendError$2(error, stackTrace);
+ },
+ addError$1: function(error) {
+ return this.addError$2(error, null);
+ },
+ close$0: function(_) {
+ var doneFuture, _this = this;
+ if ((_this._state & 4) !== 0) {
+ H.assertHelper(_this._doneFuture != null);
+ return _this._doneFuture;
+ }
+ if (!_this.get$_mayAddEvent())
+ throw H.wrapException(_this._addEventError$0());
+ _this._state |= 4;
+ doneFuture = _this._ensureDoneFuture$0();
+ _this._sendDone$0();
+ return doneFuture;
+ },
+ _async$_addError$2: function(error, stackTrace) {
+ this._sendError$2(error, type$.StackTrace._check(stackTrace));
+ },
+ _close$0: function() {
+ var addState, _this = this;
+ H.assertHelper((_this._state & 8) !== 0);
+ addState = _this._addStreamState;
+ _this.set$_addStreamState(null);
+ _this._state &= 4294967287;
+ addState.addStreamFuture._asyncComplete$1(null);
+ },
+ _forEachListener$1: function(action) {
+ var t1, subscription, id, next, _this = this;
+ H._instanceType(_this)._eval$1("~(_BufferingStreamSubscription<1>)")._check(action);
+ t1 = _this._state;
+ if ((t1 & 2) !== 0)
+ throw H.wrapException(P.StateError$("Cannot fire new event. Controller is already firing an event"));
+ subscription = _this._firstSubscription;
+ if (subscription == null)
+ return;
+ id = t1 & 1;
+ _this._state = t1 ^ 3;
+ for (; subscription != null;) {
+ t1 = subscription._eventState;
+ if ((t1 & 1) === id) {
+ subscription._eventState = t1 | 2;
+ action.call$1(subscription);
+ t1 = subscription._eventState ^= 1;
+ next = subscription._async$_next;
+ if ((t1 & 4) !== 0)
+ _this._removeListener$1(subscription);
+ subscription._eventState &= 4294967293;
+ subscription = next;
+ } else
+ subscription = subscription._async$_next;
+ }
+ _this._state &= 4294967293;
+ if (_this._firstSubscription == null)
+ _this._callOnCancel$0();
+ },
+ _callOnCancel$0: function() {
+ var _this = this;
+ H.assertHelper(_this._firstSubscription == null);
+ if ((_this._state & 4) !== 0 && _this._doneFuture._state === 0)
+ _this._doneFuture._asyncComplete$1(null);
+ P._runGuarded(_this.onCancel);
+ },
+ set$_firstSubscription: function(_firstSubscription) {
+ this._firstSubscription = H._instanceType(this)._eval$1("_BroadcastSubscription<1>")._check(_firstSubscription);
+ },
+ set$_lastSubscription: function(_lastSubscription) {
+ this._lastSubscription = H._instanceType(this)._eval$1("_BroadcastSubscription<1>")._check(_lastSubscription);
+ },
+ set$_addStreamState: function(_addStreamState) {
+ this._addStreamState = H._instanceType(this)._eval$1("_AddStreamState<1>")._check(_addStreamState);
+ },
+ $isEventSink: 1,
+ $isStreamConsumer: 1,
+ $isStreamSink: 1,
+ $isStreamController: 1,
+ $is_StreamControllerLifecycle: 1,
+ $is_EventDispatch: 1,
+ $isSink: 1
+ };
+ P._SyncBroadcastStreamController.prototype = {
+ get$_mayAddEvent: function() {
+ return P._BroadcastStreamController.prototype.get$_mayAddEvent.call(this) && (this._state & 2) === 0;
+ },
+ _addEventError$0: function() {
+ if ((this._state & 2) !== 0)
+ return new P.StateError("Cannot fire new event. Controller is already firing an event");
+ return this.super$_BroadcastStreamController$_addEventError();
+ },
+ _sendData$1: function(data) {
+ var t1, _this = this;
+ _this.$ti._precomputed1._check(data);
+ if (_this._firstSubscription == null)
+ return;
+ t1 = _this._firstSubscription;
+ if (t1 == _this._lastSubscription) {
+ _this._state |= 2;
+ t1._add$1(data);
+ _this._state &= 4294967293;
+ if (_this._firstSubscription == null)
+ _this._callOnCancel$0();
+ return;
+ }
+ _this._forEachListener$1(new P._SyncBroadcastStreamController__sendData_closure(_this, data));
+ },
+ _sendError$2: function(error, stackTrace) {
+ if (this._firstSubscription == null)
+ return;
+ this._forEachListener$1(new P._SyncBroadcastStreamController__sendError_closure(this, error, stackTrace));
+ },
+ _sendDone$0: function() {
+ var _this = this;
+ if (_this._firstSubscription != null)
+ _this._forEachListener$1(new P._SyncBroadcastStreamController__sendDone_closure(_this));
+ else {
+ H.assertHelper(_this._doneFuture != null);
+ H.assertHelper(_this._doneFuture._state === 0);
+ _this._doneFuture._asyncComplete$1(null);
+ }
+ }
+ };
+ P._SyncBroadcastStreamController__sendData_closure.prototype = {
+ call$1: function(subscription) {
+ this.$this.$ti._eval$1("_BufferingStreamSubscription<1>")._check(subscription)._add$1(this.data);
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Null(_BufferingStreamSubscription<1>)");
+ }
+ };
+ P._SyncBroadcastStreamController__sendError_closure.prototype = {
+ call$1: function(subscription) {
+ this.$this.$ti._eval$1("_BufferingStreamSubscription<1>")._check(subscription)._async$_addError$2(this.error, this.stackTrace);
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Null(_BufferingStreamSubscription<1>)");
+ }
+ };
+ P._SyncBroadcastStreamController__sendDone_closure.prototype = {
+ call$1: function(subscription) {
+ this.$this.$ti._eval$1("_BufferingStreamSubscription<1>")._check(subscription)._close$0();
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Null(_BufferingStreamSubscription<1>)");
+ }
+ };
+ P._AsyncBroadcastStreamController.prototype = {
+ _sendData$1: function(data) {
+ var subscription,
+ t1 = this.$ti;
+ t1._precomputed1._check(data);
+ for (subscription = this._firstSubscription, t1 = t1._eval$1("_DelayedData<1>"); subscription != null; subscription = subscription._async$_next)
+ subscription._addPending$1(new P._DelayedData(data, t1));
+ },
+ _sendError$2: function(error, stackTrace) {
+ var subscription;
+ for (subscription = this._firstSubscription; subscription != null; subscription = subscription._async$_next)
+ subscription._addPending$1(new P._DelayedError(error, stackTrace));
+ },
+ _sendDone$0: function() {
+ var _this = this,
+ subscription = _this._firstSubscription;
+ if (subscription != null)
+ for (; subscription != null; subscription = subscription._async$_next)
+ subscription._addPending$1(C.C__DelayedDone);
+ else {
+ H.assertHelper(_this._doneFuture != null);
+ H.assertHelper(_this._doneFuture._state === 0);
+ _this._doneFuture._asyncComplete$1(null);
+ }
+ }
+ };
+ P.Future.prototype = {};
+ P.Future_Future_closure.prototype = {
+ call$0: function() {
+ var e, s, exception;
+ try {
+ this.result._complete$1(this.computation.call$0());
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P._completeWithErrorCallback(this.result, e, s);
+ }
+ },
+ $signature: 0
+ };
+ P.Future_Future$microtask_closure.prototype = {
+ call$0: function() {
+ var e, s, exception;
+ try {
+ this.result._complete$1(this.computation.call$0());
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P._completeWithErrorCallback(this.result, e, s);
+ }
+ },
+ $signature: 0
+ };
+ P.Future_wait_handleError.prototype = {
+ call$2: function(theError, theStackTrace) {
+ var t1, t2, _this = this;
+ type$.StackTrace._check(theStackTrace);
+ t1 = _this._box_0;
+ t2 = --t1.remaining;
+ if (t1.values != null) {
+ t1.values = null;
+ if (t1.remaining === 0 || _this.eagerError)
+ _this.result._completeError$2(theError, theStackTrace);
+ else {
+ t1.error = theError;
+ t1.stackTrace = theStackTrace;
+ }
+ } else if (t2 === 0 && !_this.eagerError)
+ _this.result._completeError$2(t1.error, t1.stackTrace);
+ },
+ $signature: 5
+ };
+ P.Future_wait_closure.prototype = {
+ call$1: function(value) {
+ var t1, t2, _this = this;
+ _this.T._check(value);
+ t1 = _this._box_0;
+ --t1.remaining;
+ t2 = t1.values;
+ if (t2 != null) {
+ C.JSArray_methods.$indexSet(t2, _this.pos, value);
+ if (t1.remaining === 0)
+ _this.result._completeWithValue$1(t1.values);
+ } else if (t1.remaining === 0 && !_this.eagerError)
+ _this.result._completeError$2(t1.error, t1.stackTrace);
+ },
+ $signature: function() {
+ return this.T._eval$1("Null(0)");
+ }
+ };
+ P.Future_forEach_closure.prototype = {
+ call$0: function() {
+ var result,
+ t1 = this.iterator;
+ if (!t1.moveNext$0())
+ return false;
+ result = this.action.call$1(t1._current);
+ if (type$.Future_dynamic._is(result))
+ return result.then$1$1(P.async_Future__kTrue$closure(), type$.bool);
+ return true;
+ },
+ $signature: 81
+ };
+ P.Future_doWhile_closure.prototype = {
+ call$1: function(keepGoing) {
+ var result, error, stackTrace, t1, t2, exception, error0, stackTrace0, replacement, _this = this;
+ H._checkBoolNullable(keepGoing);
+ for (t1 = type$.Future_bool, t2 = _this.action; H.boolConversionCheck(keepGoing);) {
+ result = null;
+ try {
+ result = t2.call$0();
+ } catch (exception) {
+ error = H.unwrapException(exception);
+ stackTrace = H.getTraceFromException(exception);
+ error0 = error;
+ stackTrace0 = stackTrace;
+ replacement = $.Zone__current.errorCallback$2(error0, stackTrace0);
+ if (replacement != null) {
+ error = replacement.error;
+ if (error == null)
+ error = new P.NullThrownError();
+ stackTrace = replacement.stackTrace;
+ } else {
+ stackTrace = stackTrace0;
+ error = error0;
+ }
+ _this.doneSignal._asyncCompleteError$2(error, stackTrace);
+ return;
+ }
+ if (t1._is(result)) {
+ result.then$1$2$onError(_this._box_0.nextIteration, _this.doneSignal.get$_completeError(), type$.void);
+ return;
+ }
+ keepGoing = H._checkBoolNullable(result);
+ }
+ _this.doneSignal._complete$1(null);
+ },
+ $signature: 43
+ };
+ P.TimeoutException.prototype = {
+ toString$0: function(_) {
+ var t1 = this.duration,
+ result = (t1 != null ? "TimeoutException after " + t1.toString$0(0) : "TimeoutException") + ": " + this.message;
+ return result;
+ },
+ $isException: 1,
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ P.Completer.prototype = {};
+ P._Completer.prototype = {
+ completeError$2: function(error, stackTrace) {
+ var replacement;
+ if (error == null)
+ error = new P.NullThrownError();
+ if (this.future._state !== 0)
+ throw H.wrapException(P.StateError$("Future already completed"));
+ replacement = $.Zone__current.errorCallback$2(error, stackTrace);
+ if (replacement != null) {
+ error = replacement.error;
+ if (error == null)
+ error = new P.NullThrownError();
+ stackTrace = replacement.stackTrace;
+ }
+ this._completeError$2(error, stackTrace);
+ },
+ completeError$1: function(error) {
+ return this.completeError$2(error, null);
+ },
+ $isCompleter: 1
+ };
+ P._AsyncCompleter.prototype = {
+ complete$1: function(value) {
+ var t1;
+ this.$ti._eval$1("1/")._check(value);
+ t1 = this.future;
+ if (t1._state !== 0)
+ throw H.wrapException(P.StateError$("Future already completed"));
+ t1._asyncComplete$1(value);
+ },
+ complete$0: function() {
+ return this.complete$1(null);
+ },
+ _completeError$2: function(error, stackTrace) {
+ this.future._asyncCompleteError$2(error, stackTrace);
+ }
+ };
+ P._SyncCompleter.prototype = {
+ complete$1: function(value) {
+ var t1;
+ this.$ti._eval$1("1/")._check(value);
+ t1 = this.future;
+ if (t1._state !== 0)
+ throw H.wrapException(P.StateError$("Future already completed"));
+ t1._complete$1(value);
+ },
+ complete$0: function() {
+ return this.complete$1(null);
+ },
+ _completeError$2: function(error, stackTrace) {
+ this.future._completeError$2(error, stackTrace);
+ }
+ };
+ P._FutureListener.prototype = {
+ matchesErrorTest$1: function(asyncError) {
+ if ((this.state & 15) !== 6)
+ return true;
+ return this.result._zone.runUnary$2$2(type$.bool_Function_Object._check(this.callback), asyncError.error, type$.bool, type$.Object);
+ },
+ handleError$1: function(asyncError) {
+ var errorCallback, t2, t3, t4, _this = this,
+ t1 = (_this.state & 2) !== 0;
+ if (t1) {
+ H.assertHelper(t1);
+ t1 = _this.errorCallback != null;
+ } else
+ t1 = false;
+ H.assertHelper(t1);
+ errorCallback = _this.errorCallback;
+ t1 = type$.dynamic;
+ t2 = type$.Object;
+ t3 = _this.$ti._eval$1("2/");
+ t4 = _this.result._zone;
+ if (type$.dynamic_Function_Object_StackTrace._is(errorCallback))
+ return t3._check(t4.runBinary$3$3(errorCallback, asyncError.error, asyncError.stackTrace, t1, t2, type$.StackTrace));
+ else {
+ H.assertHelper(type$.dynamic_Function_Object._is(errorCallback));
+ return t3._check(t4.runUnary$2$2(errorCallback, asyncError.error, t1, t2));
+ }
+ }
+ };
+ P._Future.prototype = {
+ then$1$2$onError: function(f, onError, $R) {
+ var currentZone, result, t2,
+ t1 = this.$ti;
+ t1._bind$1($R)._eval$1("1/(2)")._check(f);
+ currentZone = $.Zone__current;
+ if (currentZone !== C.C__RootZone) {
+ f = currentZone.registerUnaryCallback$2$1(f, $R._eval$1("0/"), t1._precomputed1);
+ if (onError != null)
+ onError = P._registerErrorHandler(onError, currentZone);
+ }
+ result = new P._Future($.Zone__current, $R._eval$1("_Future<0>"));
+ t2 = onError == null ? 1 : 3;
+ this._addListener$1(new P._FutureListener(result, t2, f, onError, t1._eval$1("@<1>")._bind$1($R)._eval$1("_FutureListener<1,2>")));
+ return result;
+ },
+ then$1$1: function(f, $R) {
+ return this.then$1$2$onError(f, null, $R);
+ },
+ _thenAwait$1$2: function(f, onError, $E) {
+ var result,
+ t1 = this.$ti;
+ t1._bind$1($E)._eval$1("1/(2)")._check(f);
+ result = new P._Future($.Zone__current, $E._eval$1("_Future<0>"));
+ this._addListener$1(new P._FutureListener(result, (onError == null ? 1 : 3) | 16, f, onError, t1._eval$1("@<1>")._bind$1($E)._eval$1("_FutureListener<1,2>")));
+ return result;
+ },
+ catchError$1: function(onError) {
+ var t1, t2, result;
+ type$.bool_Function_dynamic._check(null);
+ t1 = this.$ti;
+ t2 = $.Zone__current;
+ result = new P._Future(t2, t1);
+ if (t2 !== C.C__RootZone)
+ onError = P._registerErrorHandler(onError, t2);
+ this._addListener$1(new P._FutureListener(result, 2, null, onError, t1._eval$1("@<1>")._bind$1(t1._precomputed1)._eval$1("_FutureListener<1,2>")));
+ return result;
+ },
+ whenComplete$1: function(action) {
+ var t1, t2, result;
+ type$.dynamic_Function._check(action);
+ t1 = this.$ti;
+ t2 = $.Zone__current;
+ result = new P._Future(t2, t1);
+ if (t2 !== C.C__RootZone)
+ action = t2.registerCallback$1$1(action, type$.dynamic);
+ this._addListener$1(new P._FutureListener(result, 8, action, null, t1._eval$1("@<1>")._bind$1(t1._precomputed1)._eval$1("_FutureListener<1,2>")));
+ return result;
+ },
+ _cloneResult$1: function(source) {
+ H.assertHelper(this._state < 4);
+ H.assertHelper(source._state >= 4);
+ this._state = source._state;
+ this._resultOrListeners = source._resultOrListeners;
+ },
+ _addListener$1: function(listener) {
+ var t1, source, _this = this;
+ H.assertHelper(listener._nextListener == null);
+ t1 = _this._state;
+ if (t1 <= 1) {
+ listener._nextListener = type$._FutureListener_dynamic_dynamic._check(_this._resultOrListeners);
+ _this._resultOrListeners = listener;
+ } else {
+ if (t1 === 2) {
+ source = type$._Future_dynamic._check(_this._resultOrListeners);
+ if (source._state < 4) {
+ source._addListener$1(listener);
+ return;
+ }
+ _this._cloneResult$1(source);
+ }
+ H.assertHelper(_this._state >= 4);
+ _this._zone.scheduleMicrotask$1(new P._Future__addListener_closure(_this, listener));
+ }
+ },
+ _prependListeners$1: function(listeners) {
+ var t1, existingListeners, cursor, cursor0, source, _this = this, _box_0 = {};
+ _box_0.listeners = listeners;
+ if (listeners == null)
+ return;
+ t1 = _this._state;
+ if (t1 <= 1) {
+ existingListeners = type$._FutureListener_dynamic_dynamic._check(_this._resultOrListeners);
+ cursor = _this._resultOrListeners = listeners;
+ if (existingListeners != null) {
+ for (; cursor0 = cursor._nextListener, cursor0 != null; cursor = cursor0)
+ ;
+ cursor._nextListener = existingListeners;
+ }
+ } else {
+ if (t1 === 2) {
+ source = type$._Future_dynamic._check(_this._resultOrListeners);
+ if (source._state < 4) {
+ source._prependListeners$1(listeners);
+ return;
+ }
+ _this._cloneResult$1(source);
+ }
+ H.assertHelper(_this._state >= 4);
+ _box_0.listeners = _this._reverseListeners$1(listeners);
+ _this._zone.scheduleMicrotask$1(new P._Future__prependListeners_closure(_box_0, _this));
+ }
+ },
+ _removeListeners$0: function() {
+ var current, _this = this;
+ H.assertHelper(_this._state < 4);
+ current = type$._FutureListener_dynamic_dynamic._check(_this._resultOrListeners);
+ _this._resultOrListeners = null;
+ return _this._reverseListeners$1(current);
+ },
+ _reverseListeners$1: function(listeners) {
+ var current, prev, next;
+ for (current = listeners, prev = null; current != null; prev = current, current = next) {
+ next = current._nextListener;
+ current._nextListener = prev;
+ }
+ return prev;
+ },
+ _complete$1: function(value) {
+ var listeners, _this = this,
+ t1 = _this.$ti;
+ t1._eval$1("1/")._check(value);
+ H.assertHelper(_this._state < 4);
+ if (t1._eval$1("Future<1>")._is(value))
+ if (t1._is(value))
+ P._Future__chainCoreFuture(value, _this);
+ else
+ P._Future__chainForeignFuture(value, _this);
+ else {
+ listeners = _this._removeListeners$0();
+ t1._precomputed1._check(value);
+ H.assertHelper(_this._state < 4);
+ _this._state = 4;
+ _this._resultOrListeners = value;
+ P._Future__propagateToListeners(_this, listeners);
+ }
+ },
+ _completeWithValue$1: function(value) {
+ var listeners, _this = this,
+ t1 = _this.$ti;
+ t1._precomputed1._check(value);
+ H.assertHelper(_this._state < 4);
+ H.assertHelper(!t1._eval$1("Future<1>")._is(value));
+ listeners = _this._removeListeners$0();
+ H.assertHelper(_this._state < 4);
+ _this._state = 4;
+ _this._resultOrListeners = value;
+ P._Future__propagateToListeners(_this, listeners);
+ },
+ _completeError$2: function(error, stackTrace) {
+ var listeners, _this = this;
+ type$.StackTrace._check(stackTrace);
+ H.assertHelper(_this._state < 4);
+ listeners = _this._removeListeners$0();
+ H.assertHelper(_this._state < 4);
+ _this._state = 8;
+ _this._resultOrListeners = new P.AsyncError(error, stackTrace);
+ P._Future__propagateToListeners(_this, listeners);
+ },
+ _completeError$1: function(error) {
+ return this._completeError$2(error, null);
+ },
+ _asyncComplete$1: function(value) {
+ var _this = this,
+ t1 = _this.$ti;
+ t1._eval$1("1/")._check(value);
+ H.assertHelper(_this._state < 4);
+ if (t1._eval$1("Future<1>")._is(value)) {
+ _this._chainFuture$1(value);
+ return;
+ }
+ H.assertHelper(_this._state === 0);
+ _this._state = 1;
+ _this._zone.scheduleMicrotask$1(new P._Future__asyncComplete_closure(_this, value));
+ },
+ _chainFuture$1: function(value) {
+ var _this = this,
+ t1 = _this.$ti;
+ t1._eval$1("Future<1>")._check(value);
+ if (t1._is(value)) {
+ if (value._state === 8) {
+ H.assertHelper(_this._state === 0);
+ _this._state = 1;
+ _this._zone.scheduleMicrotask$1(new P._Future__chainFuture_closure(_this, value));
+ } else
+ P._Future__chainCoreFuture(value, _this);
+ return;
+ }
+ P._Future__chainForeignFuture(value, _this);
+ },
+ _asyncCompleteError$2: function(error, stackTrace) {
+ var _this = this;
+ type$.StackTrace._check(stackTrace);
+ H.assertHelper(_this._state < 4);
+ H.assertHelper(_this._state === 0);
+ _this._state = 1;
+ _this._zone.scheduleMicrotask$1(new P._Future__asyncCompleteError_closure(_this, error, stackTrace));
+ },
+ $isFuture: 1
+ };
+ P._Future__addListener_closure.prototype = {
+ call$0: function() {
+ P._Future__propagateToListeners(this.$this, this.listener);
+ },
+ $signature: 0
+ };
+ P._Future__prependListeners_closure.prototype = {
+ call$0: function() {
+ P._Future__propagateToListeners(this.$this, this._box_0.listeners);
+ },
+ $signature: 0
+ };
+ P._Future__chainForeignFuture_closure.prototype = {
+ call$1: function(value) {
+ var t1 = this.target;
+ H.assertHelper(t1._state === 1);
+ H.assertHelper(t1._state === 1);
+ t1._state = 0;
+ t1._complete$1(value);
+ },
+ $signature: 3
+ };
+ P._Future__chainForeignFuture_closure0.prototype = {
+ call$2: function(error, stackTrace) {
+ var t1;
+ type$.StackTrace._check(stackTrace);
+ t1 = this.target;
+ H.assertHelper(t1._state === 1);
+ t1._completeError$2(error, stackTrace);
+ },
+ call$1: function(error) {
+ return this.call$2(error, null);
+ },
+ $signature: 80
+ };
+ P._Future__chainForeignFuture_closure1.prototype = {
+ call$0: function() {
+ this.target._completeError$2(this.e, this.s);
+ },
+ $signature: 0
+ };
+ P._Future__asyncComplete_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this;
+ t1._completeWithValue$1(t1.$ti._precomputed1._check(this.value));
+ },
+ $signature: 0
+ };
+ P._Future__chainFuture_closure.prototype = {
+ call$0: function() {
+ P._Future__chainCoreFuture(this.value, this.$this);
+ },
+ $signature: 0
+ };
+ P._Future__asyncCompleteError_closure.prototype = {
+ call$0: function() {
+ this.$this._completeError$2(this.error, this.stackTrace);
+ },
+ $signature: 0
+ };
+ P._Future__propagateToListeners_handleWhenCompleteCallback.prototype = {
+ call$0: function() {
+ var completeResult, e, s, t3, exception, originalSource, _this = this,
+ t1 = _this.listener,
+ t2 = t1.state;
+ H.assertHelper((t2 & 1) === 0);
+ t3 = (t2 & 2) === 0;
+ H.assertHelper(t3);
+ completeResult = null;
+ try {
+ H.assertHelper(t3);
+ H.assertHelper((t2 & 15) === 8);
+ completeResult = t1.result._zone.run$1$1(type$.dynamic_Function._check(t1.callback), type$.dynamic);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ if (_this.hasError) {
+ t1 = _this._box_1.source;
+ H.assertHelper(t1._state === 8);
+ t1 = type$.AsyncError._check(t1._resultOrListeners).error;
+ t2 = e;
+ t2 = t1 == null ? t2 == null : t1 === t2;
+ t1 = t2;
+ } else
+ t1 = false;
+ t2 = _this._box_0;
+ if (t1) {
+ t1 = _this._box_1.source;
+ H.assertHelper(t1._state === 8);
+ t2.listenerValueOrError = type$.AsyncError._check(t1._resultOrListeners);
+ } else
+ t2.listenerValueOrError = new P.AsyncError(e, s);
+ t2.listenerHasError = true;
+ return;
+ }
+ if (type$.Future_dynamic._is(completeResult)) {
+ if (completeResult instanceof P._Future && completeResult._state >= 4) {
+ if (completeResult._state === 8) {
+ t1 = completeResult;
+ H.assertHelper(t1._state === 8);
+ t2 = _this._box_0;
+ t2.listenerValueOrError = type$.AsyncError._check(t1._resultOrListeners);
+ t2.listenerHasError = true;
+ }
+ return;
+ }
+ originalSource = _this._box_1.source;
+ t1 = _this._box_0;
+ t1.listenerValueOrError = completeResult.then$1$1(new P._Future__propagateToListeners_handleWhenCompleteCallback_closure(originalSource), type$.dynamic);
+ t1.listenerHasError = false;
+ }
+ },
+ $signature: 1
+ };
+ P._Future__propagateToListeners_handleWhenCompleteCallback_closure.prototype = {
+ call$1: function(_) {
+ return this.originalSource;
+ },
+ $signature: 75
+ };
+ P._Future__propagateToListeners_handleValueCallback.prototype = {
+ call$0: function() {
+ var e, s, t1, t2, t3, t4, exception, _this = this;
+ try {
+ t1 = _this.listener;
+ t2 = t1.$ti;
+ t3 = t2._precomputed1;
+ t4 = t3._check(_this.sourceResult);
+ H.assertHelper((t1.state & 1) !== 0);
+ _this._box_0.listenerValueOrError = t1.result._zone.runUnary$2$2(t2._eval$1("2/(1)")._check(t1.callback), t4, t2._eval$1("2/"), t3);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ t1 = _this._box_0;
+ t1.listenerValueOrError = new P.AsyncError(e, s);
+ t1.listenerHasError = true;
+ }
+ },
+ $signature: 1
+ };
+ P._Future__propagateToListeners_handleError.prototype = {
+ call$0: function() {
+ var asyncError, e, s, t1, t2, exception, t3, t4, t5, _this = this;
+ try {
+ t1 = _this._box_1.source;
+ H.assertHelper(t1._state === 8);
+ asyncError = type$.AsyncError._check(t1._resultOrListeners);
+ t1 = _this.listener;
+ if (H.boolConversionCheck(t1.matchesErrorTest$1(asyncError))) {
+ H.assertHelper((t1.state & 2) !== 0);
+ t2 = t1.errorCallback != null;
+ } else
+ t2 = false;
+ if (t2) {
+ t2 = _this._box_0;
+ t2.listenerValueOrError = t1.handleError$1(asyncError);
+ t2.listenerHasError = false;
+ }
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ t1 = _this._box_1;
+ t2 = t1.source;
+ H.assertHelper(t2._state === 8);
+ t3 = type$.AsyncError;
+ t2 = t3._check(t2._resultOrListeners).error;
+ t4 = e;
+ t5 = _this._box_0;
+ if (t2 == null ? t4 == null : t2 === t4) {
+ t1 = t1.source;
+ H.assertHelper(t1._state === 8);
+ t5.listenerValueOrError = t3._check(t1._resultOrListeners);
+ } else
+ t5.listenerValueOrError = new P.AsyncError(e, s);
+ t5.listenerHasError = true;
+ }
+ },
+ $signature: 1
+ };
+ P._AsyncCallbackEntry.prototype = {};
+ P.Stream.prototype = {
+ get$isBroadcast: function() {
+ return false;
+ },
+ pipe$1: function(streamConsumer) {
+ H._instanceType(this)._eval$1("StreamConsumer<Stream.T>")._check(streamConsumer);
+ return streamConsumer.addStream$1(this).then$1$1(new P.Stream_pipe_closure(streamConsumer), type$.dynamic);
+ },
+ get$length: function(_) {
+ var t1 = {},
+ future = new P._Future($.Zone__current, type$._Future_int);
+ t1.count = 0;
+ this.listen$4$cancelOnError$onDone$onError(new P.Stream_length_closure(t1, this), true, new P.Stream_length_closure0(t1, future), future.get$_completeError());
+ return future;
+ },
+ get$first: function(_) {
+ var t1 = {},
+ future = new P._Future($.Zone__current, H._instanceType(this)._eval$1("_Future<Stream.T>"));
+ t1.subscription = null;
+ t1.subscription = this.listen$4$cancelOnError$onDone$onError(new P.Stream_first_closure(t1, this, future), true, new P.Stream_first_closure0(future), future.get$_completeError());
+ return future;
+ },
+ get$last: function(_) {
+ var t1 = {},
+ future = new P._Future($.Zone__current, H._instanceType(this)._eval$1("_Future<Stream.T>"));
+ t1.result = null;
+ t1.foundResult = false;
+ this.listen$4$cancelOnError$onDone$onError(new P.Stream_last_closure(t1, this), true, new P.Stream_last_closure0(t1, future), future.get$_completeError());
+ return future;
+ },
+ firstWhere$1: function(_, test) {
+ var future, _this = this, t1 = {},
+ t2 = H._instanceType(_this);
+ t2._eval$1("bool(Stream.T)")._check(test);
+ t2._eval$1("Stream.T()")._check(null);
+ future = new P._Future($.Zone__current, t2._eval$1("_Future<Stream.T>"));
+ t1.subscription = null;
+ t1.subscription = _this.listen$4$cancelOnError$onDone$onError(new P.Stream_firstWhere_closure(t1, _this, test, future), true, new P.Stream_firstWhere_closure0(_this, null, future), future.get$_completeError());
+ return future;
+ }
+ };
+ P.Stream_Stream$fromFuture_closure.prototype = {
+ call$1: function(value) {
+ var t1 = this.controller;
+ t1._add$1(this.T._check(value));
+ t1._closeUnchecked$0();
+ },
+ $signature: function() {
+ return this.T._eval$1("Null(0)");
+ }
+ };
+ P.Stream_Stream$fromFuture_closure0.prototype = {
+ call$2: function(error, stackTrace) {
+ var t1 = this.controller;
+ t1._async$_addError$2(error, type$.StackTrace._check(stackTrace));
+ t1._closeUnchecked$0();
+ },
+ $signature: 6
+ };
+ P.Stream_Stream$fromIterable_closure.prototype = {
+ call$0: function() {
+ var t1 = this.elements;
+ return new P._IterablePendingEvents(new J.ArrayIterator(t1, 0, H._arrayInstanceType(t1)._eval$1("ArrayIterator<1>")), this.T._eval$1("_IterablePendingEvents<0>"));
+ },
+ $signature: function() {
+ return this.T._eval$1("_IterablePendingEvents<0>()");
+ }
+ };
+ P.Stream_pipe_closure.prototype = {
+ call$1: function(_) {
+ return this.streamConsumer.close$0(0);
+ },
+ $signature: 73
+ };
+ P.Stream_length_closure.prototype = {
+ call$1: function(_) {
+ H._instanceType(this.$this)._eval$1("Stream.T")._check(_);
+ ++this._box_0.count;
+ },
+ $signature: function() {
+ return H._instanceType(this.$this)._eval$1("Null(Stream.T)");
+ }
+ };
+ P.Stream_length_closure0.prototype = {
+ call$0: function() {
+ this.future._complete$1(this._box_0.count);
+ },
+ $signature: 0
+ };
+ P.Stream_first_closure.prototype = {
+ call$1: function(value) {
+ H._instanceType(this.$this)._eval$1("Stream.T")._check(value);
+ P._cancelAndValue(this._box_0.subscription, this.future, value);
+ },
+ $signature: function() {
+ return H._instanceType(this.$this)._eval$1("Null(Stream.T)");
+ }
+ };
+ P.Stream_first_closure0.prototype = {
+ call$0: function() {
+ var e, s, t1, exception;
+ try {
+ t1 = H.IterableElementError_noElement();
+ throw H.wrapException(t1);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P._completeWithErrorCallback(this.future, e, s);
+ }
+ },
+ $signature: 0
+ };
+ P.Stream_last_closure.prototype = {
+ call$1: function(value) {
+ var t1;
+ H._instanceType(this.$this)._eval$1("Stream.T")._check(value);
+ t1 = this._box_0;
+ t1.foundResult = true;
+ t1.result = value;
+ },
+ $signature: function() {
+ return H._instanceType(this.$this)._eval$1("Null(Stream.T)");
+ }
+ };
+ P.Stream_last_closure0.prototype = {
+ call$0: function() {
+ var e, s, exception,
+ t1 = this._box_0;
+ if (t1.foundResult) {
+ this.future._complete$1(t1.result);
+ return;
+ }
+ try {
+ t1 = H.IterableElementError_noElement();
+ throw H.wrapException(t1);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P._completeWithErrorCallback(this.future, e, s);
+ }
+ },
+ $signature: 0
+ };
+ P.Stream_firstWhere_closure.prototype = {
+ call$1: function(value) {
+ var t1, t2, _this = this;
+ H._instanceType(_this.$this)._eval$1("Stream.T")._check(value);
+ t1 = _this._box_0;
+ t2 = _this.future;
+ P._runUserCode(new P.Stream_firstWhere__closure(_this.test, value), new P.Stream_firstWhere__closure0(t1, t2, value), P._cancelAndErrorClosure(t1.subscription, t2), type$.bool);
+ },
+ $signature: function() {
+ return H._instanceType(this.$this)._eval$1("Null(Stream.T)");
+ }
+ };
+ P.Stream_firstWhere__closure.prototype = {
+ call$0: function() {
+ return this.test.call$1(this.value);
+ },
+ $signature: 49
+ };
+ P.Stream_firstWhere__closure0.prototype = {
+ call$1: function(isMatch) {
+ if (H.boolConversionCheck(H._checkBoolNullable(isMatch)))
+ P._cancelAndValue(this._box_0.subscription, this.future, this.value);
+ },
+ $signature: 43
+ };
+ P.Stream_firstWhere_closure0.prototype = {
+ call$0: function() {
+ var e, s, t1, exception;
+ try {
+ t1 = H.IterableElementError_noElement();
+ throw H.wrapException(t1);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P._completeWithErrorCallback(this.future, e, s);
+ }
+ },
+ $signature: 0
+ };
+ P.StreamSubscription.prototype = {};
+ P.StreamTransformerBase.prototype = {$isStreamTransformer: 1};
+ P._StreamController.prototype = {
+ get$_pendingEvents: function() {
+ var t1, _this = this;
+ H.assertHelper((_this._state & 3) === 0);
+ if ((_this._state & 8) === 0)
+ return H._instanceType(_this)._eval$1("_PendingEvents<1>")._check(_this._varData);
+ t1 = H._instanceType(_this);
+ return t1._eval$1("_PendingEvents<1>")._check(t1._eval$1("_StreamControllerAddStreamState<1>")._check(_this._varData).varData);
+ },
+ _ensurePendingEvents$0: function() {
+ var t1, state, t2, _this = this;
+ H.assertHelper((_this._state & 3) === 0);
+ if ((_this._state & 8) === 0) {
+ t1 = _this._varData;
+ if (t1 == null)
+ t1 = _this._varData = new P._StreamImplEvents(H._instanceType(_this)._eval$1("_StreamImplEvents<1>"));
+ return H._instanceType(_this)._eval$1("_StreamImplEvents<1>")._check(t1);
+ }
+ t1 = H._instanceType(_this);
+ state = t1._eval$1("_StreamControllerAddStreamState<1>")._check(_this._varData);
+ t2 = state.varData;
+ if (t2 == null)
+ t2 = state.varData = new P._StreamImplEvents(t1._eval$1("_StreamImplEvents<1>"));
+ return t1._eval$1("_StreamImplEvents<1>")._check(t2);
+ },
+ get$_async$_subscription: function() {
+ var t1, _this = this;
+ H.assertHelper((_this._state & 1) !== 0);
+ if ((_this._state & 8) !== 0) {
+ t1 = H._instanceType(_this);
+ return t1._eval$1("_ControllerSubscription<1>")._check(t1._eval$1("_StreamControllerAddStreamState<1>")._check(_this._varData).varData);
+ }
+ return H._instanceType(_this)._eval$1("_ControllerSubscription<1>")._check(_this._varData);
+ },
+ _badEventState$0: function() {
+ var t1 = this._state;
+ if ((t1 & 4) !== 0)
+ return new P.StateError("Cannot add event after closing");
+ H.assertHelper((t1 & 8) !== 0);
+ return new P.StateError("Cannot add event while adding a stream");
+ },
+ addStream$2$cancelOnError: function(source, cancelOnError) {
+ var t2, t3, t4, t5, _this = this,
+ t1 = H._instanceType(_this);
+ t1._eval$1("Stream<1>")._check(source);
+ t2 = _this._state;
+ if (t2 >= 4)
+ throw H.wrapException(_this._badEventState$0());
+ if ((t2 & 2) !== 0) {
+ t1 = new P._Future($.Zone__current, type$._Future_dynamic);
+ t1._asyncComplete$1(null);
+ return t1;
+ }
+ t2 = _this._varData;
+ t3 = cancelOnError === true;
+ t4 = new P._Future($.Zone__current, type$._Future_dynamic);
+ t5 = t3 ? P._AddStreamState_makeErrorHandler(_this) : _this.get$_async$_addError();
+ t5 = source.listen$4$cancelOnError$onDone$onError(_this.get$_add(), t3, _this.get$_close(), t5);
+ t3 = _this._state;
+ if ((t3 & 1) !== 0 ? (_this.get$_async$_subscription()._state & 4) !== 0 : (t3 & 2) === 0)
+ t5.pause$0();
+ _this._varData = new P._StreamControllerAddStreamState(t2, t4, t5, t1._eval$1("_StreamControllerAddStreamState<1>"));
+ _this._state |= 8;
+ return t4;
+ },
+ _ensureDoneFuture$0: function() {
+ var t1 = this._doneFuture;
+ if (t1 == null)
+ t1 = this._doneFuture = (this._state & 2) !== 0 ? $.$get$Future__nullFuture() : new P._Future($.Zone__current, type$._Future_dynamic);
+ return t1;
+ },
+ add$1: function(_, value) {
+ var _this = this;
+ H._instanceType(_this)._precomputed1._check(value);
+ if (_this._state >= 4)
+ throw H.wrapException(_this._badEventState$0());
+ _this._add$1(value);
+ },
+ addError$2: function(error, stackTrace) {
+ var replacement;
+ type$.StackTrace._check(stackTrace);
+ if (this._state >= 4)
+ throw H.wrapException(this._badEventState$0());
+ if (error == null)
+ error = new P.NullThrownError();
+ replacement = $.Zone__current.errorCallback$2(error, stackTrace);
+ if (replacement != null) {
+ error = replacement.error;
+ if (error == null)
+ error = new P.NullThrownError();
+ stackTrace = replacement.stackTrace;
+ }
+ this._async$_addError$2(error, stackTrace);
+ },
+ addError$1: function(error) {
+ return this.addError$2(error, null);
+ },
+ close$0: function(_) {
+ var _this = this,
+ t1 = _this._state;
+ if ((t1 & 4) !== 0)
+ return _this._ensureDoneFuture$0();
+ if (t1 >= 4)
+ throw H.wrapException(_this._badEventState$0());
+ _this._closeUnchecked$0();
+ return _this._ensureDoneFuture$0();
+ },
+ _closeUnchecked$0: function() {
+ var t1 = this._state |= 4;
+ if ((t1 & 1) !== 0)
+ this._sendDone$0();
+ else if ((t1 & 3) === 0)
+ this._ensurePendingEvents$0().add$1(0, C.C__DelayedDone);
+ },
+ _add$1: function(value) {
+ var t2, _this = this,
+ t1 = H._instanceType(_this);
+ t1._precomputed1._check(value);
+ t2 = _this._state;
+ if ((t2 & 1) !== 0)
+ _this._sendData$1(value);
+ else if ((t2 & 3) === 0)
+ _this._ensurePendingEvents$0().add$1(0, new P._DelayedData(value, t1._eval$1("_DelayedData<1>")));
+ },
+ _async$_addError$2: function(error, stackTrace) {
+ var t1;
+ type$.StackTrace._check(stackTrace);
+ t1 = this._state;
+ if ((t1 & 1) !== 0)
+ this._sendError$2(error, stackTrace);
+ else if ((t1 & 3) === 0)
+ this._ensurePendingEvents$0().add$1(0, new P._DelayedError(error, stackTrace));
+ },
+ _close$0: function() {
+ var addState, _this = this;
+ H.assertHelper((_this._state & 8) !== 0);
+ addState = H._instanceType(_this)._eval$1("_StreamControllerAddStreamState<1>")._check(_this._varData);
+ _this._varData = addState.varData;
+ _this._state &= 4294967287;
+ addState.addStreamFuture._asyncComplete$1(null);
+ },
+ _subscribe$4: function(onData, onError, onDone, cancelOnError) {
+ var t2, t3, subscription, pendingEvents, addState, _this = this,
+ t1 = H._instanceType(_this);
+ t1._eval$1("~(1)")._check(onData);
+ type$.void_Function._check(onDone);
+ if ((_this._state & 3) !== 0)
+ throw H.wrapException(P.StateError$("Stream has already been listened to."));
+ t2 = $.Zone__current;
+ t3 = cancelOnError ? 1 : 0;
+ subscription = new P._ControllerSubscription(_this, t2, t3, t1._eval$1("_ControllerSubscription<1>"));
+ subscription._BufferingStreamSubscription$4(onData, onError, onDone, cancelOnError, t1._precomputed1);
+ pendingEvents = _this.get$_pendingEvents();
+ t3 = _this._state |= 1;
+ if ((t3 & 8) !== 0) {
+ addState = t1._eval$1("_StreamControllerAddStreamState<1>")._check(_this._varData);
+ addState.varData = subscription;
+ addState.addSubscription.resume$0();
+ } else
+ _this._varData = subscription;
+ subscription._setPendingEvents$1(pendingEvents);
+ subscription._guardCallback$1(new P._StreamController__subscribe_closure(_this));
+ return subscription;
+ },
+ _recordCancel$1: function(subscription) {
+ var result, e, s, exception, result0, _this = this,
+ t1 = H._instanceType(_this);
+ t1._eval$1("StreamSubscription<1>")._check(subscription);
+ result = null;
+ if ((_this._state & 8) !== 0)
+ result = t1._eval$1("_StreamControllerAddStreamState<1>")._check(_this._varData).cancel$0();
+ _this._varData = null;
+ _this._state = _this._state & 4294967286 | 2;
+ t1 = _this.onCancel;
+ if (t1 != null)
+ if (result == null)
+ try {
+ result = type$.Future_dynamic._check(t1.call$0());
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ result0 = new P._Future($.Zone__current, type$._Future_dynamic);
+ result0._asyncCompleteError$2(e, s);
+ result = result0;
+ }
+ else
+ result = result.whenComplete$1(t1);
+ t1 = new P._StreamController__recordCancel_complete(_this);
+ if (result != null)
+ result = result.whenComplete$1(t1);
+ else
+ t1.call$0();
+ return result;
+ },
+ _recordPause$1: function(subscription) {
+ var _this = this,
+ t1 = H._instanceType(_this);
+ t1._eval$1("StreamSubscription<1>")._check(subscription);
+ if ((_this._state & 8) !== 0)
+ t1._eval$1("_StreamControllerAddStreamState<1>")._check(_this._varData).addSubscription.pause$0();
+ P._runGuarded(_this.onPause);
+ },
+ _recordResume$1: function(subscription) {
+ var _this = this,
+ t1 = H._instanceType(_this);
+ t1._eval$1("StreamSubscription<1>")._check(subscription);
+ if ((_this._state & 8) !== 0)
+ t1._eval$1("_StreamControllerAddStreamState<1>")._check(_this._varData).addSubscription.resume$0();
+ P._runGuarded(_this.onResume);
+ },
+ $isEventSink: 1,
+ $isStreamConsumer: 1,
+ $isStreamSink: 1,
+ $isStreamController: 1,
+ $is_StreamControllerLifecycle: 1,
+ $is_EventDispatch: 1,
+ $isSink: 1
+ };
+ P._StreamController__subscribe_closure.prototype = {
+ call$0: function() {
+ P._runGuarded(this.$this.onListen);
+ },
+ $signature: 0
+ };
+ P._StreamController__recordCancel_complete.prototype = {
+ call$0: function() {
+ var t1 = this.$this._doneFuture;
+ if (t1 != null && t1._state === 0)
+ t1._asyncComplete$1(null);
+ },
+ $signature: 1
+ };
+ P._SyncStreamControllerDispatch.prototype = {
+ _sendData$1: function(data) {
+ this.$ti._precomputed1._check(data);
+ this.get$_async$_subscription()._add$1(data);
+ },
+ _sendError$2: function(error, stackTrace) {
+ this.get$_async$_subscription()._async$_addError$2(error, stackTrace);
+ },
+ _sendDone$0: function() {
+ this.get$_async$_subscription()._close$0();
+ }
+ };
+ P._AsyncStreamControllerDispatch.prototype = {
+ _sendData$1: function(data) {
+ var t1 = this.$ti;
+ t1._precomputed1._check(data);
+ this.get$_async$_subscription()._addPending$1(new P._DelayedData(data, t1._eval$1("_DelayedData<1>")));
+ },
+ _sendError$2: function(error, stackTrace) {
+ this.get$_async$_subscription()._addPending$1(new P._DelayedError(error, stackTrace));
+ },
+ _sendDone$0: function() {
+ this.get$_async$_subscription()._addPending$1(C.C__DelayedDone);
+ }
+ };
+ P._AsyncStreamController.prototype = {};
+ P._SyncStreamController.prototype = {};
+ P._ControllerStream.prototype = {
+ _createSubscription$4: function(onData, onError, onDone, cancelOnError) {
+ return this._controller._subscribe$4(H._instanceType(this)._eval$1("~(1)")._check(onData), onError, type$.void_Function._check(onDone), cancelOnError);
+ },
+ get$hashCode: function(_) {
+ return (H.Primitives_objectHashCode(this._controller) ^ 892482866) >>> 0;
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ if (this === other)
+ return true;
+ return other instanceof P._ControllerStream && other._controller === this._controller;
+ }
+ };
+ P._ControllerSubscription.prototype = {
+ _onCancel$0: function() {
+ return this._controller._recordCancel$1(this);
+ },
+ _onPause$0: function() {
+ this._controller._recordPause$1(this);
+ },
+ _onResume$0: function() {
+ this._controller._recordResume$1(this);
+ }
+ };
+ P._StreamSinkWrapper.prototype = {
+ add$1: function(_, data) {
+ this._async$_target.add$1(0, this.$ti._precomputed1._check(data));
+ },
+ $isEventSink: 1,
+ $isStreamConsumer: 1,
+ $isStreamSink: 1,
+ $isSink: 1
+ };
+ P._AddStreamState.prototype = {
+ cancel$0: function() {
+ var cancel = this.addSubscription.cancel$0();
+ if (cancel == null) {
+ this.addStreamFuture._asyncComplete$1(null);
+ return null;
+ }
+ return cancel.whenComplete$1(new P._AddStreamState_cancel_closure(this));
+ }
+ };
+ P._AddStreamState_makeErrorHandler_closure.prototype = {
+ call$2: function(e, s) {
+ var t1 = this.controller;
+ t1._async$_addError$2(e, type$.StackTrace._check(s));
+ t1._close$0();
+ },
+ $signature: 5
+ };
+ P._AddStreamState_cancel_closure.prototype = {
+ call$0: function() {
+ this.$this.addStreamFuture._asyncComplete$1(null);
+ },
+ $signature: 0
+ };
+ P._StreamControllerAddStreamState.prototype = {};
+ P._BufferingStreamSubscription.prototype = {
+ _BufferingStreamSubscription$4: function(onData, onError, onDone, cancelOnError, $T) {
+ this.onData$1(onData);
+ this.onError$1(0, onError);
+ this.onDone$1(onDone);
+ },
+ _setPendingEvents$1: function(pendingEvents) {
+ var _this = this;
+ H._instanceType(_this)._eval$1("_PendingEvents<_BufferingStreamSubscription.T>")._check(pendingEvents);
+ H.assertHelper(_this._pending == null);
+ if (pendingEvents == null)
+ return;
+ _this.set$_pending(pendingEvents);
+ if (!pendingEvents.get$isEmpty(pendingEvents)) {
+ _this._state = (_this._state | 64) >>> 0;
+ _this._pending.schedule$1(_this);
+ }
+ },
+ onData$1: function(handleData) {
+ var t1 = H._instanceType(this);
+ t1._eval$1("~(_BufferingStreamSubscription.T)")._check(handleData);
+ if (handleData == null)
+ handleData = P.async___nullDataHandler$closure();
+ this.set$_onData(this._zone.registerUnaryCallback$2$1(handleData, type$.dynamic, t1._eval$1("_BufferingStreamSubscription.T")));
+ },
+ onError$1: function(_, handleError) {
+ var _this = this;
+ if (handleError == null)
+ handleError = P.async___nullErrorHandler$closure();
+ if (type$.void_Function_Object_StackTrace._is(handleError))
+ _this._onError = _this._zone.registerBinaryCallback$3$1(handleError, type$.dynamic, type$.Object, type$.StackTrace);
+ else if (type$.void_Function_Object._is(handleError))
+ _this._onError = _this._zone.registerUnaryCallback$2$1(handleError, type$.dynamic, type$.Object);
+ else
+ throw H.wrapException(P.ArgumentError$("handleError callback must take either an Object (the error), or both an Object (the error) and a StackTrace."));
+ },
+ onDone$1: function(handleDone) {
+ type$.void_Function._check(handleDone);
+ if (handleDone == null)
+ handleDone = P.async___nullDoneHandler$closure();
+ this.set$_onDone(this._zone.registerCallback$1$1(handleDone, type$.void));
+ },
+ pause$1: function(resumeSignal) {
+ var t2, t3, _this = this,
+ t1 = _this._state;
+ if ((t1 & 8) !== 0)
+ return;
+ t2 = (t1 + 128 | 4) >>> 0;
+ _this._state = t2;
+ if (t1 < 128 && _this._pending != null) {
+ t3 = _this._pending;
+ if (t3._state === 1)
+ t3._state = 3;
+ }
+ if ((t1 & 4) === 0 && (t2 & 32) === 0)
+ _this._guardCallback$1(_this.get$_onPause());
+ },
+ pause$0: function() {
+ return this.pause$1(null);
+ },
+ resume$0: function() {
+ var _this = this,
+ t1 = _this._state;
+ if ((t1 & 8) !== 0)
+ return;
+ if (t1 >= 128) {
+ t1 = _this._state -= 128;
+ if (t1 < 128) {
+ if ((t1 & 64) !== 0) {
+ t1 = _this._pending;
+ t1 = !t1.get$isEmpty(t1);
+ } else
+ t1 = false;
+ if (t1)
+ _this._pending.schedule$1(_this);
+ else {
+ H.assertHelper(_this.get$_mayResumeInput());
+ t1 = (_this._state & 4294967291) >>> 0;
+ _this._state = t1;
+ if ((t1 & 32) === 0)
+ _this._guardCallback$1(_this.get$_onResume());
+ }
+ }
+ }
+ },
+ cancel$0: function() {
+ var _this = this,
+ t1 = (_this._state & 4294967279) >>> 0;
+ _this._state = t1;
+ if ((t1 & 8) === 0)
+ _this._cancel$0();
+ t1 = _this._cancelFuture;
+ return t1 == null ? $.$get$Future__nullFuture() : t1;
+ },
+ get$_mayResumeInput: function() {
+ if (this._state < 128) {
+ var t1 = this._pending;
+ t1 = t1 == null || t1.get$isEmpty(t1);
+ } else
+ t1 = false;
+ return t1;
+ },
+ get$isPaused: function() {
+ return this._state >= 128;
+ },
+ _cancel$0: function() {
+ var t2, _this = this,
+ t1 = _this._state = (_this._state | 8) >>> 0;
+ if ((t1 & 64) !== 0) {
+ t2 = _this._pending;
+ if (t2._state === 1)
+ t2._state = 3;
+ }
+ if ((t1 & 32) === 0)
+ _this.set$_pending(null);
+ _this._cancelFuture = _this._onCancel$0();
+ },
+ _add$1: function(data) {
+ var t2, _this = this,
+ t1 = H._instanceType(_this);
+ t1._eval$1("_BufferingStreamSubscription.T")._check(data);
+ H.assertHelper((_this._state & 2) === 0);
+ t2 = _this._state;
+ if ((t2 & 8) !== 0)
+ return;
+ if (t2 < 32)
+ _this._sendData$1(data);
+ else
+ _this._addPending$1(new P._DelayedData(data, t1._eval$1("_DelayedData<_BufferingStreamSubscription.T>")));
+ },
+ _async$_addError$2: function(error, stackTrace) {
+ var t1 = this._state;
+ if ((t1 & 8) !== 0)
+ return;
+ if (t1 < 32)
+ this._sendError$2(error, stackTrace);
+ else
+ this._addPending$1(new P._DelayedError(error, stackTrace));
+ },
+ _close$0: function() {
+ var t1, _this = this;
+ H.assertHelper((_this._state & 2) === 0);
+ t1 = _this._state;
+ if ((t1 & 8) !== 0)
+ return;
+ t1 = (t1 | 2) >>> 0;
+ _this._state = t1;
+ if (t1 < 32)
+ _this._sendDone$0();
+ else
+ _this._addPending$1(C.C__DelayedDone);
+ },
+ _onPause$0: function() {
+ H.assertHelper((this._state & 4) !== 0);
+ },
+ _onResume$0: function() {
+ H.assertHelper((this._state & 4) === 0);
+ },
+ _onCancel$0: function() {
+ H.assertHelper((this._state & 8) !== 0);
+ return null;
+ },
+ _addPending$1: function($event) {
+ var _this = this,
+ t1 = H._instanceType(_this)._eval$1("_StreamImplEvents<_BufferingStreamSubscription.T>"),
+ pending = t1._check(_this._pending);
+ if (pending == null) {
+ pending = new P._StreamImplEvents(t1);
+ _this.set$_pending(pending);
+ }
+ pending.add$1(0, $event);
+ t1 = _this._state;
+ if ((t1 & 64) === 0) {
+ t1 = (t1 | 64) >>> 0;
+ _this._state = t1;
+ if (t1 < 128)
+ _this._pending.schedule$1(_this);
+ }
+ },
+ _sendData$1: function(data) {
+ var t2, _this = this,
+ t1 = H._instanceType(_this)._eval$1("_BufferingStreamSubscription.T");
+ t1._check(data);
+ H.assertHelper((_this._state & 8) === 0);
+ H.assertHelper(_this._state < 128);
+ H.assertHelper((_this._state & 32) === 0);
+ t2 = _this._state;
+ _this._state = (t2 | 32) >>> 0;
+ _this._zone.runUnaryGuarded$1$2(_this._onData, data, t1);
+ _this._state = (_this._state & 4294967263) >>> 0;
+ _this._checkState$1((t2 & 4) !== 0);
+ },
+ _sendError$2: function(error, stackTrace) {
+ var t1, t2, _this = this;
+ type$.StackTrace._check(stackTrace);
+ H.assertHelper((_this._state & 8) === 0);
+ H.assertHelper(_this._state < 128);
+ H.assertHelper((_this._state & 32) === 0);
+ t1 = _this._state;
+ t2 = new P._BufferingStreamSubscription__sendError_sendError(_this, error, stackTrace);
+ if ((t1 & 1) !== 0) {
+ _this._state = (t1 | 16) >>> 0;
+ _this._cancel$0();
+ t1 = _this._cancelFuture;
+ if (t1 != null && t1 !== $.$get$Future__nullFuture())
+ t1.whenComplete$1(t2);
+ else
+ t2.call$0();
+ } else {
+ t2.call$0();
+ _this._checkState$1((t1 & 4) !== 0);
+ }
+ },
+ _sendDone$0: function() {
+ var t1, t2, _this = this;
+ H.assertHelper((_this._state & 8) === 0);
+ H.assertHelper(_this._state < 128);
+ H.assertHelper((_this._state & 32) === 0);
+ t1 = new P._BufferingStreamSubscription__sendDone_sendDone(_this);
+ _this._cancel$0();
+ _this._state = (_this._state | 16) >>> 0;
+ t2 = _this._cancelFuture;
+ if (t2 != null && t2 !== $.$get$Future__nullFuture())
+ t2.whenComplete$1(t1);
+ else
+ t1.call$0();
+ },
+ _guardCallback$1: function(callback) {
+ var t1, _this = this;
+ type$.void_Function._check(callback);
+ H.assertHelper((_this._state & 32) === 0);
+ t1 = _this._state;
+ _this._state = (t1 | 32) >>> 0;
+ callback.call$0();
+ _this._state = (_this._state & 4294967263) >>> 0;
+ _this._checkState$1((t1 & 4) !== 0);
+ },
+ _checkState$1: function(wasInputPaused) {
+ var t1, isInputPaused, _this = this;
+ H.assertHelper((_this._state & 32) === 0);
+ if ((_this._state & 64) !== 0) {
+ t1 = _this._pending;
+ t1 = t1.get$isEmpty(t1);
+ } else
+ t1 = false;
+ if (t1) {
+ t1 = (_this._state & 4294967231) >>> 0;
+ _this._state = t1;
+ if ((t1 & 4) !== 0 && _this.get$_mayResumeInput())
+ _this._state = (_this._state & 4294967291) >>> 0;
+ }
+ for (; true; wasInputPaused = isInputPaused) {
+ t1 = _this._state;
+ if ((t1 & 8) !== 0) {
+ _this.set$_pending(null);
+ return;
+ }
+ isInputPaused = (t1 & 4) !== 0;
+ if (wasInputPaused === isInputPaused)
+ break;
+ _this._state = (t1 ^ 32) >>> 0;
+ if (isInputPaused)
+ _this._onPause$0();
+ else
+ _this._onResume$0();
+ _this._state = (_this._state & 4294967263) >>> 0;
+ }
+ t1 = _this._state;
+ if ((t1 & 64) !== 0 && t1 < 128)
+ _this._pending.schedule$1(_this);
+ },
+ set$_onData: function(_onData) {
+ this._onData = H._instanceType(this)._eval$1("~(_BufferingStreamSubscription.T)")._check(_onData);
+ },
+ set$_onDone: function(_onDone) {
+ this._onDone = type$.void_Function._check(_onDone);
+ },
+ set$_pending: function(_pending) {
+ this._pending = H._instanceType(this)._eval$1("_PendingEvents<_BufferingStreamSubscription.T>")._check(_pending);
+ },
+ $isStreamSubscription: 1,
+ $is_EventDispatch: 1
+ };
+ P._BufferingStreamSubscription__sendError_sendError.prototype = {
+ call$0: function() {
+ var onError, t3, t4, t5,
+ t1 = this.$this,
+ t2 = t1._state;
+ if ((t2 & 8) !== 0 && (t2 & 16) === 0)
+ return;
+ t1._state = (t2 | 32) >>> 0;
+ onError = t1._onError;
+ t2 = this.error;
+ t3 = type$.Object;
+ t4 = t1._zone;
+ if (type$.void_Function_Object_StackTrace._is(onError))
+ t4.runBinaryGuarded$2$3(onError, t2, this.stackTrace, t3, type$.StackTrace);
+ else {
+ t5 = type$.void_Function_Object;
+ H.assertHelper(t5._is(onError));
+ t4.runUnaryGuarded$1$2(t5._check(t1._onError), t2, t3);
+ }
+ t1._state = (t1._state & 4294967263) >>> 0;
+ },
+ $signature: 1
+ };
+ P._BufferingStreamSubscription__sendDone_sendDone.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ t2 = t1._state;
+ if ((t2 & 16) === 0)
+ return;
+ t1._state = (t2 | 42) >>> 0;
+ t1._zone.runGuarded$1(t1._onDone);
+ t1._state = (t1._state & 4294967263) >>> 0;
+ },
+ $signature: 1
+ };
+ P._StreamImpl.prototype = {
+ listen$4$cancelOnError$onDone$onError: function(onData, cancelOnError, onDone, onError) {
+ return this._createSubscription$4(H._instanceType(this)._eval$1("~(1)")._check(onData), onError, type$.void_Function._check(onDone), true === H._checkBoolNullable(cancelOnError));
+ },
+ listen$2$onDone: function(onData, onDone) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, onDone, null);
+ },
+ listen$3$onDone$onError: function(onData, onDone, onError) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, onDone, onError);
+ },
+ listen$1: function(onData) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, null, null);
+ },
+ _createSubscription$4: function(onData, onError, onDone, cancelOnError) {
+ var t1 = H._instanceType(this);
+ return P._BufferingStreamSubscription$(t1._eval$1("~(1)")._check(onData), onError, type$.void_Function._check(onDone), cancelOnError, t1._precomputed1);
+ }
+ };
+ P._GeneratedStreamImpl.prototype = {
+ _createSubscription$4: function(onData, onError, onDone, cancelOnError) {
+ var _this = this,
+ t1 = _this.$ti;
+ t1._eval$1("~(1)")._check(onData);
+ type$.void_Function._check(onDone);
+ if (_this._isUsed)
+ throw H.wrapException(P.StateError$("Stream has already been listened to."));
+ _this._isUsed = true;
+ t1 = P._BufferingStreamSubscription$(onData, onError, onDone, cancelOnError, t1._precomputed1);
+ t1._setPendingEvents$1(_this._pending.call$0());
+ return t1;
+ }
+ };
+ P._IterablePendingEvents.prototype = {
+ get$isEmpty: function(_) {
+ return this._async$_iterator == null;
+ },
+ handleNext$1: function(dispatch) {
+ var hasMore, e, s, t1, exception, _this = this;
+ _this.$ti._eval$1("_EventDispatch<1>")._check(dispatch);
+ t1 = _this._async$_iterator;
+ if (t1 == null)
+ throw H.wrapException(P.StateError$("No events pending."));
+ hasMore = null;
+ try {
+ hasMore = t1.moveNext$0();
+ if (H.boolConversionCheck(hasMore))
+ dispatch._sendData$1(_this._async$_iterator.get$current());
+ else {
+ _this.set$_async$_iterator(null);
+ dispatch._sendDone$0();
+ }
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ if (hasMore == null) {
+ _this.set$_async$_iterator(C.C_EmptyIterator);
+ dispatch._sendError$2(e, s);
+ } else
+ dispatch._sendError$2(e, s);
+ }
+ },
+ set$_async$_iterator: function(_iterator) {
+ this._async$_iterator = this.$ti._eval$1("Iterator<1>")._check(_iterator);
+ }
+ };
+ P._DelayedEvent.prototype = {
+ set$next: function(next) {
+ this.next = type$._DelayedEvent_dynamic._check(next);
+ },
+ get$next: function() {
+ return this.next;
+ }
+ };
+ P._DelayedData.prototype = {
+ perform$1: function(dispatch) {
+ this.$ti._eval$1("_EventDispatch<1>")._check(dispatch)._sendData$1(this.value);
+ }
+ };
+ P._DelayedError.prototype = {
+ perform$1: function(dispatch) {
+ dispatch._sendError$2(this.error, this.stackTrace);
+ }
+ };
+ P._DelayedDone.prototype = {
+ perform$1: function(dispatch) {
+ dispatch._sendDone$0();
+ },
+ get$next: function() {
+ return null;
+ },
+ set$next: function(_) {
+ throw H.wrapException(P.StateError$("No events after a done."));
+ },
+ $is_DelayedEvent: 1
+ };
+ P._PendingEvents.prototype = {
+ schedule$1: function(dispatch) {
+ var t1, _this = this;
+ H._instanceType(_this)._eval$1("_EventDispatch<1>")._check(dispatch);
+ if (_this._state === 1)
+ return;
+ H.assertHelper(!_this.get$isEmpty(_this));
+ t1 = _this._state;
+ if (t1 >= 1) {
+ H.assertHelper(t1 === 3);
+ _this._state = 1;
+ return;
+ }
+ P.scheduleMicrotask(new P._PendingEvents_schedule_closure(_this, dispatch));
+ _this._state = 1;
+ }
+ };
+ P._PendingEvents_schedule_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ oldState = t1._state;
+ t1._state = 0;
+ if (oldState === 3)
+ return;
+ t1.handleNext$1(this.dispatch);
+ },
+ $signature: 0
+ };
+ P._StreamImplEvents.prototype = {
+ get$isEmpty: function(_) {
+ return this.lastPendingEvent == null;
+ },
+ add$1: function(_, $event) {
+ var _this = this,
+ t1 = _this.lastPendingEvent;
+ if (t1 == null)
+ _this.firstPendingEvent = _this.lastPendingEvent = $event;
+ else {
+ t1.set$next($event);
+ _this.lastPendingEvent = $event;
+ }
+ },
+ handleNext$1: function(dispatch) {
+ var $event, t1, _this = this;
+ _this.$ti._eval$1("_EventDispatch<1>")._check(dispatch);
+ H.assertHelper(_this._state !== 1);
+ $event = _this.firstPendingEvent;
+ t1 = $event.get$next();
+ _this.firstPendingEvent = t1;
+ if (t1 == null)
+ _this.lastPendingEvent = null;
+ $event.perform$1(dispatch);
+ }
+ };
+ P._DoneStreamSubscription.prototype = {
+ get$isPaused: function() {
+ return this._state >= 4;
+ },
+ _schedule$0: function() {
+ var _this = this;
+ if ((_this._state & 2) !== 0)
+ return;
+ _this._zone.scheduleMicrotask$1(_this.get$_sendDone());
+ _this._state = (_this._state | 2) >>> 0;
+ },
+ onData$1: function(handleData) {
+ this.$ti._eval$1("~(1)")._check(handleData);
+ },
+ onError$1: function(_, handleError) {
+ },
+ onDone$1: function(handleDone) {
+ this.set$_onDone(type$.void_Function._check(handleDone));
+ },
+ pause$1: function(resumeSignal) {
+ this._state += 4;
+ },
+ pause$0: function() {
+ return this.pause$1(null);
+ },
+ resume$0: function() {
+ var t1 = this._state;
+ if (t1 >= 4) {
+ t1 = this._state = t1 - 4;
+ if (t1 < 4 && (t1 & 1) === 0)
+ this._schedule$0();
+ }
+ },
+ cancel$0: function() {
+ return $.$get$Future__nullFuture();
+ },
+ _sendDone$0: function() {
+ var _this = this,
+ t1 = _this._state = (_this._state & 4294967293) >>> 0;
+ if (t1 >= 4)
+ return;
+ _this._state = (t1 | 1) >>> 0;
+ t1 = _this._onDone;
+ if (t1 != null)
+ _this._zone.runGuarded$1(t1);
+ },
+ set$_onDone: function(_onDone) {
+ this._onDone = type$.void_Function._check(_onDone);
+ },
+ $isStreamSubscription: 1
+ };
+ P._StreamIterator.prototype = {};
+ P._EmptyStream.prototype = {
+ get$isBroadcast: function() {
+ return true;
+ },
+ listen$4$cancelOnError$onDone$onError: function(onData, cancelOnError, onDone, onError) {
+ var t1 = this.$ti;
+ t1._eval$1("~(1)")._check(onData);
+ type$.void_Function._check(onDone);
+ H._checkBoolNullable(cancelOnError);
+ t1 = new P._DoneStreamSubscription($.Zone__current, onDone, t1._eval$1("_DoneStreamSubscription<1>"));
+ t1._schedule$0();
+ return t1;
+ },
+ listen$3$onDone$onError: function(onData, onDone, onError) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, onDone, onError);
+ },
+ listen$1: function(onData) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, null, null);
+ }
+ };
+ P._cancelAndError_closure.prototype = {
+ call$0: function() {
+ return this.future._completeError$2(this.error, this.stackTrace);
+ },
+ $signature: 1
+ };
+ P._cancelAndErrorClosure_closure.prototype = {
+ call$2: function(error, stackTrace) {
+ P._cancelAndError(this.subscription, this.future, error, type$.StackTrace._check(stackTrace));
+ },
+ $signature: 5
+ };
+ P._cancelAndValue_closure.prototype = {
+ call$0: function() {
+ return this.future._complete$1(this.value);
+ },
+ $signature: 1
+ };
+ P.Timer.prototype = {};
+ P.AsyncError.prototype = {
+ toString$0: function(_) {
+ return H.S(this.error);
+ },
+ $isError: 1
+ };
+ P._ZoneFunction.prototype = {};
+ P.ZoneSpecification.prototype = {};
+ P._ZoneSpecification.prototype = {$isZoneSpecification: 1};
+ P.ZoneDelegate.prototype = {};
+ P.Zone.prototype = {};
+ P._ZoneDelegate.prototype = {
+ handleUncaughtError$3: function(zone, error, stackTrace) {
+ var implementation, implZone;
+ type$.StackTrace._check(stackTrace);
+ implementation = this._delegationTarget.get$_handleUncaughtError();
+ implZone = implementation.zone;
+ return implementation.$function.call$5(implZone, P._parentDelegate(implZone), zone, error, stackTrace);
+ },
+ registerCallback$1$2: function(zone, f, $R) {
+ var implementation, implZone;
+ $R._eval$1("0()")._check(f);
+ implementation = this._delegationTarget.get$_registerCallback();
+ implZone = implementation.zone;
+ return type$.A_Function_Function_A_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function._check(implementation.$function).call$1$4(implZone, P._parentDelegate(implZone), zone, f, $R);
+ },
+ registerUnaryCallback$2$2: function(zone, f, $R, $T) {
+ var implementation, implZone;
+ $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(f);
+ implementation = this._delegationTarget.get$_registerUnaryCallback();
+ implZone = implementation.zone;
+ return type$.A_Function_B_Function_A_and_B_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function_B._check(implementation.$function).call$2$4(implZone, P._parentDelegate(implZone), zone, f, $R, $T);
+ },
+ registerBinaryCallback$3$2: function(zone, f, $R, T1, T2) {
+ var implementation, implZone;
+ $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._check(f);
+ implementation = this._delegationTarget.get$_registerBinaryCallback();
+ implZone = implementation.zone;
+ return type$.A_Function_2_B_and_C_Function_A_and_B_and_C_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function_2_B_and_C._check(implementation.$function).call$3$4(implZone, P._parentDelegate(implZone), zone, f, $R, T1, T2);
+ },
+ errorCallback$3: function(zone, error, stackTrace) {
+ var implementation = this._delegationTarget.get$_errorCallback(),
+ implZone = implementation.zone;
+ if (implZone === C.C__RootZone)
+ return null;
+ return implementation.$function.call$5(implZone, P._parentDelegate(implZone), zone, error, stackTrace);
+ },
+ $isZoneDelegate: 1
+ };
+ P._Zone.prototype = {$isZone: 1};
+ P._CustomZone.prototype = {
+ get$_delegate: function() {
+ var t1 = this._delegateCache;
+ if (t1 != null)
+ return t1;
+ return this._delegateCache = new P._ZoneDelegate(this);
+ },
+ get$errorZone: function() {
+ return this._handleUncaughtError.zone;
+ },
+ runGuarded$1: function(f) {
+ var e, s, exception;
+ type$.void_Function._check(f);
+ try {
+ this.run$1$1(f, type$.void);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ this.handleUncaughtError$2(e, s);
+ }
+ },
+ runUnaryGuarded$1$2: function(f, arg, $T) {
+ var e, s, exception;
+ $T._eval$1("~(0)")._check(f);
+ $T._check(arg);
+ try {
+ this.runUnary$2$2(f, arg, type$.void, $T);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ this.handleUncaughtError$2(e, s);
+ }
+ },
+ runBinaryGuarded$2$3: function(f, arg1, arg2, T1, T2) {
+ var e, s, exception;
+ T1._eval$1("@<0>")._bind$1(T2)._eval$1("~(1,2)")._check(f);
+ T1._check(arg1);
+ T2._check(arg2);
+ try {
+ this.runBinary$3$3(f, arg1, arg2, type$.void, T1, T2);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ this.handleUncaughtError$2(e, s);
+ }
+ },
+ bindCallback$1$1: function(f, $R) {
+ return new P._CustomZone_bindCallback_closure(this, this.registerCallback$1$1($R._eval$1("0()")._check(f), $R), $R);
+ },
+ bindUnaryCallback$2$1: function(f, $R, $T) {
+ return new P._CustomZone_bindUnaryCallback_closure(this, this.registerUnaryCallback$2$1($R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(f), $R, $T), $T, $R);
+ },
+ bindCallbackGuarded$1: function(f) {
+ return new P._CustomZone_bindCallbackGuarded_closure(this, this.registerCallback$1$1(type$.void_Function._check(f), type$.void));
+ },
+ bindUnaryCallbackGuarded$1$1: function(f, $T) {
+ return new P._CustomZone_bindUnaryCallbackGuarded_closure(this, this.registerUnaryCallback$2$1($T._eval$1("~(0)")._check(f), type$.void, $T), $T);
+ },
+ $index: function(_, key) {
+ var value,
+ t1 = this._async$_map,
+ result = t1.$index(0, key);
+ if (result != null || t1.containsKey$1(key))
+ return result;
+ value = this.parent.$index(0, key);
+ if (value != null)
+ t1.$indexSet(0, key, value);
+ return value;
+ },
+ handleUncaughtError$2: function(error, stackTrace) {
+ var implementation, t1, parentDelegate;
+ type$.StackTrace._check(stackTrace);
+ implementation = this._handleUncaughtError;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return implementation.$function.call$5(t1, parentDelegate, this, error, stackTrace);
+ },
+ fork$2$specification$zoneValues: function(specification, zoneValues) {
+ var t1, parentDelegate,
+ implementation = this._fork;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return implementation.$function.call$5(t1, parentDelegate, this, specification, zoneValues);
+ },
+ run$1$1: function(f, $R) {
+ var implementation, t1, parentDelegate;
+ $R._eval$1("0()")._check(f);
+ implementation = this._run;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return type$.A_Function_A_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function._check(implementation.$function).call$1$4(t1, parentDelegate, this, f, $R);
+ },
+ runUnary$2$2: function(f, arg, $R, $T) {
+ var implementation, t1, parentDelegate;
+ $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(f);
+ $T._check(arg);
+ implementation = this._runUnary;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return type$.A_Function_A_and_B_5_Zone_and_ZoneDelegate_and_Zone_and_A_Function_B_and_B._check(implementation.$function).call$2$5(t1, parentDelegate, this, f, arg, $R, $T);
+ },
+ runBinary$3$3: function(f, arg1, arg2, $R, T1, T2) {
+ var implementation, t1, parentDelegate;
+ $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._check(f);
+ T1._check(arg1);
+ T2._check(arg2);
+ implementation = this._runBinary;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return type$.A_Function_A_and_B_and_C_6_Zone_and_ZoneDelegate_and_Zone_and_A_Function_2_B_and_C_and_B_and_C._check(implementation.$function).call$3$6(t1, parentDelegate, this, f, arg1, arg2, $R, T1, T2);
+ },
+ registerCallback$1$1: function(callback, $R) {
+ var implementation, t1, parentDelegate;
+ $R._eval$1("0()")._check(callback);
+ implementation = this._registerCallback;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return type$.A_Function_Function_A_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function._check(implementation.$function).call$1$4(t1, parentDelegate, this, callback, $R);
+ },
+ registerUnaryCallback$2$1: function(callback, $R, $T) {
+ var implementation, t1, parentDelegate;
+ $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(callback);
+ implementation = this._registerUnaryCallback;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return type$.A_Function_B_Function_A_and_B_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function_B._check(implementation.$function).call$2$4(t1, parentDelegate, this, callback, $R, $T);
+ },
+ registerBinaryCallback$3$1: function(callback, $R, T1, T2) {
+ var implementation, t1, parentDelegate;
+ $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._check(callback);
+ implementation = this._registerBinaryCallback;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return type$.A_Function_2_B_and_C_Function_A_and_B_and_C_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function_2_B_and_C._check(implementation.$function).call$3$4(t1, parentDelegate, this, callback, $R, T1, T2);
+ },
+ errorCallback$2: function(error, stackTrace) {
+ var implementation, implementationZone, parentDelegate;
+ type$.StackTrace._check(stackTrace);
+ implementation = this._errorCallback;
+ H.assertHelper(implementation != null);
+ implementationZone = implementation.zone;
+ if (implementationZone === C.C__RootZone)
+ return null;
+ parentDelegate = P._parentDelegate(implementationZone);
+ return implementation.$function.call$5(implementationZone, parentDelegate, this, error, stackTrace);
+ },
+ scheduleMicrotask$1: function(f) {
+ var implementation, t1, parentDelegate;
+ type$.void_Function._check(f);
+ implementation = this._scheduleMicrotask;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return implementation.$function.call$4(t1, parentDelegate, this, f);
+ },
+ createTimer$2: function(duration, f) {
+ var implementation, t1, parentDelegate;
+ type$.void_Function._check(f);
+ implementation = this._createTimer;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return implementation.$function.call$5(t1, parentDelegate, this, duration, f);
+ },
+ print$1: function(_, line) {
+ var t1, parentDelegate,
+ implementation = this._print;
+ H.assertHelper(implementation != null);
+ t1 = implementation.zone;
+ parentDelegate = P._parentDelegate(t1);
+ return implementation.$function.call$4(t1, parentDelegate, this, line);
+ },
+ set$_run: function(_run) {
+ this._run = type$._ZoneFunction_Function._check(_run);
+ },
+ set$_runUnary: function(_runUnary) {
+ this._runUnary = type$._ZoneFunction_Function._check(_runUnary);
+ },
+ set$_runBinary: function(_runBinary) {
+ this._runBinary = type$._ZoneFunction_Function._check(_runBinary);
+ },
+ set$_registerCallback: function(_registerCallback) {
+ this._registerCallback = type$._ZoneFunction_Function._check(_registerCallback);
+ },
+ set$_registerUnaryCallback: function(_registerUnaryCallback) {
+ this._registerUnaryCallback = type$._ZoneFunction_Function._check(_registerUnaryCallback);
+ },
+ set$_registerBinaryCallback: function(_registerBinaryCallback) {
+ this._registerBinaryCallback = type$._ZoneFunction_Function._check(_registerBinaryCallback);
+ },
+ set$_errorCallback: function(_errorCallback) {
+ this._errorCallback = type$._ZoneFunction_of_AsyncError_Function_Zone_ZoneDelegate_Zone_Object_StackTrace._check(_errorCallback);
+ },
+ set$_scheduleMicrotask: function(_scheduleMicrotask) {
+ this._scheduleMicrotask = type$._ZoneFunction_of_void_Function_4_Zone_and_ZoneDelegate_and_Zone_and_void_Function._check(_scheduleMicrotask);
+ },
+ set$_createTimer: function(_createTimer) {
+ this._createTimer = type$._ZoneFunction_of_Timer_Function_5_Zone_and_ZoneDelegate_and_Zone_and_Duration_and_void_Function._check(_createTimer);
+ },
+ set$_createPeriodicTimer: function(_createPeriodicTimer) {
+ this._createPeriodicTimer = type$._ZoneFunction_of_Timer_Function_5_Zone_and_ZoneDelegate_and_Zone_and_Duration_and_void_Function_Timer._check(_createPeriodicTimer);
+ },
+ set$_print: function(_print) {
+ this._print = type$._ZoneFunction_of_void_Function_Zone_ZoneDelegate_Zone_String._check(_print);
+ },
+ set$_fork: function(_fork) {
+ this._fork = type$._ZoneFunction_of_Zone_Function_5_Zone_and_ZoneDelegate_and_Zone_and_ZoneSpecification_and_Map_dynamic_dynamic._check(_fork);
+ },
+ set$_handleUncaughtError: function(_handleUncaughtError) {
+ this._handleUncaughtError = type$._ZoneFunction_of_void_Function_Zone_ZoneDelegate_Zone_Object_StackTrace._check(_handleUncaughtError);
+ },
+ get$_run: function() {
+ return this._run;
+ },
+ get$_runUnary: function() {
+ return this._runUnary;
+ },
+ get$_runBinary: function() {
+ return this._runBinary;
+ },
+ get$_registerCallback: function() {
+ return this._registerCallback;
+ },
+ get$_registerUnaryCallback: function() {
+ return this._registerUnaryCallback;
+ },
+ get$_registerBinaryCallback: function() {
+ return this._registerBinaryCallback;
+ },
+ get$_errorCallback: function() {
+ return this._errorCallback;
+ },
+ get$_scheduleMicrotask: function() {
+ return this._scheduleMicrotask;
+ },
+ get$_createTimer: function() {
+ return this._createTimer;
+ },
+ get$_createPeriodicTimer: function() {
+ return this._createPeriodicTimer;
+ },
+ get$_print: function() {
+ return this._print;
+ },
+ get$_fork: function() {
+ return this._fork;
+ },
+ get$_handleUncaughtError: function() {
+ return this._handleUncaughtError;
+ },
+ get$parent: function(receiver) {
+ return this.parent;
+ },
+ get$_async$_map: function() {
+ return this._async$_map;
+ }
+ };
+ P._CustomZone_bindCallback_closure.prototype = {
+ call$0: function() {
+ return this.$this.run$1$1(this.registered, this.R);
+ },
+ $signature: function() {
+ return this.R._eval$1("0()");
+ }
+ };
+ P._CustomZone_bindUnaryCallback_closure.prototype = {
+ call$1: function(arg) {
+ var _this = this,
+ t1 = _this.T;
+ return _this.$this.runUnary$2$2(_this.registered, t1._check(arg), _this.R, t1);
+ },
+ $signature: function() {
+ return this.R._eval$1("@<0>")._bind$1(this.T)._eval$1("1(2)");
+ }
+ };
+ P._CustomZone_bindCallbackGuarded_closure.prototype = {
+ call$0: function() {
+ return this.$this.runGuarded$1(this.registered);
+ },
+ $signature: 1
+ };
+ P._CustomZone_bindUnaryCallbackGuarded_closure.prototype = {
+ call$1: function(arg) {
+ var t1 = this.T;
+ return this.$this.runUnaryGuarded$1$2(this.registered, t1._check(arg), t1);
+ },
+ $signature: function() {
+ return this.T._eval$1("~(0)");
+ }
+ };
+ P._rootHandleUncaughtError_closure.prototype = {
+ call$0: function() {
+ var error,
+ t1 = this._box_0,
+ t2 = t1.error;
+ t1 = t2 == null ? t1.error = new P.NullThrownError() : t2;
+ t2 = this.stackTrace;
+ if (t2 == null)
+ throw H.wrapException(t1);
+ error = H.wrapException(t1);
+ error.stack = t2.toString$0(0);
+ throw error;
+ },
+ $signature: 0
+ };
+ P._RootZone.prototype = {
+ get$_run: function() {
+ return C._ZoneFunction__RootZone__rootRun;
+ },
+ get$_runUnary: function() {
+ return C._ZoneFunction__RootZone__rootRunUnary;
+ },
+ get$_runBinary: function() {
+ return C._ZoneFunction__RootZone__rootRunBinary;
+ },
+ get$_registerCallback: function() {
+ return C._ZoneFunction__RootZone__rootRegisterCallback;
+ },
+ get$_registerUnaryCallback: function() {
+ return C._ZoneFunction_Eeh;
+ },
+ get$_registerBinaryCallback: function() {
+ return C._ZoneFunction_7G2;
+ },
+ get$_errorCallback: function() {
+ return C._ZoneFunction__RootZone__rootErrorCallback;
+ },
+ get$_scheduleMicrotask: function() {
+ return C._ZoneFunction__RootZone__rootScheduleMicrotask;
+ },
+ get$_createTimer: function() {
+ return C._ZoneFunction__RootZone__rootCreateTimer;
+ },
+ get$_createPeriodicTimer: function() {
+ return C._ZoneFunction_3bB;
+ },
+ get$_print: function() {
+ return C._ZoneFunction__RootZone__rootPrint;
+ },
+ get$_fork: function() {
+ return C._ZoneFunction__RootZone__rootFork;
+ },
+ get$_handleUncaughtError: function() {
+ return C._ZoneFunction_NMc;
+ },
+ get$parent: function(_) {
+ return null;
+ },
+ get$_async$_map: function() {
+ return $.$get$_RootZone__rootMap();
+ },
+ get$_delegate: function() {
+ var t1 = $._RootZone__rootDelegate;
+ if (t1 != null)
+ return t1;
+ return $._RootZone__rootDelegate = new P._ZoneDelegate(this);
+ },
+ get$errorZone: function() {
+ return this;
+ },
+ runGuarded$1: function(f) {
+ var e, s, exception, _null = null;
+ type$.void_Function._check(f);
+ try {
+ if (C.C__RootZone === $.Zone__current) {
+ f.call$0();
+ return;
+ }
+ P._rootRun(_null, _null, this, f, type$.void);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P._rootHandleUncaughtError(_null, _null, this, e, type$.StackTrace._check(s));
+ }
+ },
+ runUnaryGuarded$1$2: function(f, arg, $T) {
+ var e, s, exception, _null = null;
+ $T._eval$1("~(0)")._check(f);
+ $T._check(arg);
+ try {
+ if (C.C__RootZone === $.Zone__current) {
+ f.call$1(arg);
+ return;
+ }
+ P._rootRunUnary(_null, _null, this, f, arg, type$.void, $T);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P._rootHandleUncaughtError(_null, _null, this, e, type$.StackTrace._check(s));
+ }
+ },
+ runBinaryGuarded$2$3: function(f, arg1, arg2, T1, T2) {
+ var e, s, exception, _null = null;
+ T1._eval$1("@<0>")._bind$1(T2)._eval$1("~(1,2)")._check(f);
+ T1._check(arg1);
+ T2._check(arg2);
+ try {
+ if (C.C__RootZone === $.Zone__current) {
+ f.call$2(arg1, arg2);
+ return;
+ }
+ P._rootRunBinary(_null, _null, this, f, arg1, arg2, type$.void, T1, T2);
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ P._rootHandleUncaughtError(_null, _null, this, e, type$.StackTrace._check(s));
+ }
+ },
+ bindCallback$1$1: function(f, $R) {
+ return new P._RootZone_bindCallback_closure(this, $R._eval$1("0()")._check(f), $R);
+ },
+ bindCallbackGuarded$1: function(f) {
+ return new P._RootZone_bindCallbackGuarded_closure(this, type$.void_Function._check(f));
+ },
+ bindUnaryCallbackGuarded$1$1: function(f, $T) {
+ return new P._RootZone_bindUnaryCallbackGuarded_closure(this, $T._eval$1("~(0)")._check(f), $T);
+ },
+ $index: function(_, key) {
+ return null;
+ },
+ handleUncaughtError$2: function(error, stackTrace) {
+ P._rootHandleUncaughtError(null, null, this, error, type$.StackTrace._check(stackTrace));
+ },
+ fork$2$specification$zoneValues: function(specification, zoneValues) {
+ return P._rootFork(null, null, this, specification, zoneValues);
+ },
+ run$1$1: function(f, $R) {
+ $R._eval$1("0()")._check(f);
+ if ($.Zone__current === C.C__RootZone)
+ return f.call$0();
+ return P._rootRun(null, null, this, f, $R);
+ },
+ runUnary$2$2: function(f, arg, $R, $T) {
+ $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(f);
+ $T._check(arg);
+ if ($.Zone__current === C.C__RootZone)
+ return f.call$1(arg);
+ return P._rootRunUnary(null, null, this, f, arg, $R, $T);
+ },
+ runBinary$3$3: function(f, arg1, arg2, $R, T1, T2) {
+ $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._check(f);
+ T1._check(arg1);
+ T2._check(arg2);
+ if ($.Zone__current === C.C__RootZone)
+ return f.call$2(arg1, arg2);
+ return P._rootRunBinary(null, null, this, f, arg1, arg2, $R, T1, T2);
+ },
+ registerCallback$1$1: function(f, $R) {
+ return $R._eval$1("0()")._check(f);
+ },
+ registerUnaryCallback$2$1: function(f, $R, $T) {
+ return $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(f);
+ },
+ registerBinaryCallback$3$1: function(f, $R, T1, T2) {
+ return $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._check(f);
+ },
+ errorCallback$2: function(error, stackTrace) {
+ type$.StackTrace._check(stackTrace);
+ return null;
+ },
+ scheduleMicrotask$1: function(f) {
+ P._rootScheduleMicrotask(null, null, this, type$.void_Function._check(f));
+ },
+ createTimer$2: function(duration, f) {
+ return P.Timer__createTimer(duration, type$.void_Function._check(f));
+ },
+ print$1: function(_, line) {
+ H.printString(line);
+ }
+ };
+ P._RootZone_bindCallback_closure.prototype = {
+ call$0: function() {
+ return this.$this.run$1$1(this.f, this.R);
+ },
+ $signature: function() {
+ return this.R._eval$1("0()");
+ }
+ };
+ P._RootZone_bindCallbackGuarded_closure.prototype = {
+ call$0: function() {
+ return this.$this.runGuarded$1(this.f);
+ },
+ $signature: 1
+ };
+ P._RootZone_bindUnaryCallbackGuarded_closure.prototype = {
+ call$1: function(arg) {
+ var t1 = this.T;
+ return this.$this.runUnaryGuarded$1$2(this.f, t1._check(arg), t1);
+ },
+ $signature: function() {
+ return this.T._eval$1("~(0)");
+ }
+ };
+ P.runZoned_closure.prototype = {
+ call$5: function($self, $parent, zone, error, stackTrace) {
+ var e, s, t2, t3, t4, exception,
+ t1 = type$.StackTrace;
+ t1._check(stackTrace);
+ try {
+ t2 = this._box_0;
+ t3 = type$.void;
+ t4 = type$.Object;
+ if (t2.binaryOnError != null)
+ $self.get$parent($self).runBinary$3$3(t2.binaryOnError, error, stackTrace, t3, t4, t1);
+ else {
+ H.assertHelper(t2.unaryOnError != null);
+ $self.get$parent($self).runUnary$2$2(t2.unaryOnError, error, t3, t4);
+ }
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ s = H.getTraceFromException(exception);
+ t1 = e;
+ if (t1 == null ? error == null : t1 === error)
+ $parent.handleUncaughtError$3(zone, error, stackTrace);
+ else
+ $parent.handleUncaughtError$3(zone, e, s);
+ }
+ },
+ $signature: 28
+ };
+ P._HashMap.prototype = {
+ get$length: function(_) {
+ return this._collection$_length;
+ },
+ get$isEmpty: function(_) {
+ return this._collection$_length === 0;
+ },
+ get$keys: function() {
+ return new P._HashMapKeyIterable(this, H._instanceType(this)._eval$1("_HashMapKeyIterable<1>"));
+ },
+ containsKey$1: function(key) {
+ var strings, nums;
+ if (typeof key == "string" && key !== "__proto__") {
+ strings = this._strings;
+ return strings == null ? false : strings[key] != null;
+ } else if (typeof key == "number" && (key & 1073741823) === key) {
+ nums = this._nums;
+ return nums == null ? false : nums[key] != null;
+ } else
+ return this._containsKey$1(key);
+ },
+ _containsKey$1: function(key) {
+ var rest = this._collection$_rest;
+ if (rest == null)
+ return false;
+ return this._findBucketIndex$2(this._getBucket$2(rest, key), key) >= 0;
+ },
+ $index: function(_, key) {
+ var strings, t1, nums;
+ if (typeof key == "string" && key !== "__proto__") {
+ strings = this._strings;
+ t1 = strings == null ? null : P._HashMap__getTableEntry(strings, key);
+ return t1;
+ } else if (typeof key == "number" && (key & 1073741823) === key) {
+ nums = this._nums;
+ t1 = nums == null ? null : P._HashMap__getTableEntry(nums, key);
+ return t1;
+ } else
+ return this._get$1(key);
+ },
+ _get$1: function(key) {
+ var bucket, index,
+ rest = this._collection$_rest;
+ if (rest == null)
+ return null;
+ bucket = this._getBucket$2(rest, key);
+ index = this._findBucketIndex$2(bucket, key);
+ return index < 0 ? null : bucket[index + 1];
+ },
+ $indexSet: function(_, key, value) {
+ var strings, nums, _this = this,
+ t1 = H._instanceType(_this);
+ t1._precomputed1._check(key);
+ t1._rest[1]._check(value);
+ if (typeof key == "string" && key !== "__proto__") {
+ strings = _this._strings;
+ _this._addHashTableEntry$3(strings == null ? _this._strings = P._HashMap__newHashTable() : strings, key, value);
+ } else if (typeof key == "number" && (key & 1073741823) === key) {
+ nums = _this._nums;
+ _this._addHashTableEntry$3(nums == null ? _this._nums = P._HashMap__newHashTable() : nums, key, value);
+ } else
+ _this._set$2(key, value);
+ },
+ _set$2: function(key, value) {
+ var rest, hash, bucket, index, _this = this,
+ t1 = H._instanceType(_this);
+ t1._precomputed1._check(key);
+ t1._rest[1]._check(value);
+ rest = _this._collection$_rest;
+ if (rest == null)
+ rest = _this._collection$_rest = P._HashMap__newHashTable();
+ hash = _this._computeHashCode$1(key);
+ bucket = rest[hash];
+ if (bucket == null) {
+ P._HashMap__setTableEntry(rest, hash, [key, value]);
+ ++_this._collection$_length;
+ _this._keys = null;
+ } else {
+ index = _this._findBucketIndex$2(bucket, key);
+ if (index >= 0)
+ bucket[index + 1] = value;
+ else {
+ bucket.push(key, value);
+ ++_this._collection$_length;
+ _this._keys = null;
+ }
+ }
+ },
+ remove$1: function(_, key) {
+ var t1 = this._remove$1(key);
+ return t1;
+ },
+ _remove$1: function(key) {
+ var hash, bucket, index, result, _this = this,
+ rest = _this._collection$_rest;
+ if (rest == null)
+ return null;
+ hash = _this._computeHashCode$1(key);
+ bucket = rest[hash];
+ index = _this._findBucketIndex$2(bucket, key);
+ if (index < 0)
+ return null;
+ --_this._collection$_length;
+ _this._keys = null;
+ result = bucket.splice(index, 2)[1];
+ if (0 === bucket.length)
+ delete rest[hash];
+ return result;
+ },
+ forEach$1: function(_, action) {
+ var keys, $length, i, key, _this = this,
+ t1 = H._instanceType(_this);
+ t1._eval$1("~(1,2)")._check(action);
+ keys = _this._computeKeys$0();
+ for ($length = keys.length, t1 = t1._precomputed1, i = 0; i < $length; ++i) {
+ key = keys[i];
+ action.call$2(t1._check(key), _this.$index(0, key));
+ if (keys !== _this._keys)
+ throw H.wrapException(P.ConcurrentModificationError$(_this));
+ }
+ },
+ _computeKeys$0: function() {
+ var result, strings, names, entries, index, i, nums, rest, bucket, $length, i0, _this = this,
+ t1 = _this._keys;
+ if (t1 != null)
+ return t1;
+ result = new Array(_this._collection$_length);
+ result.fixed$length = Array;
+ strings = _this._strings;
+ if (strings != null) {
+ names = Object.getOwnPropertyNames(strings);
+ entries = names.length;
+ for (index = 0, i = 0; i < entries; ++i) {
+ result[index] = names[i];
+ ++index;
+ }
+ } else
+ index = 0;
+ nums = _this._nums;
+ if (nums != null) {
+ names = Object.getOwnPropertyNames(nums);
+ entries = names.length;
+ for (i = 0; i < entries; ++i) {
+ result[index] = +names[i];
+ ++index;
+ }
+ }
+ rest = _this._collection$_rest;
+ if (rest != null) {
+ names = Object.getOwnPropertyNames(rest);
+ entries = names.length;
+ for (i = 0; i < entries; ++i) {
+ bucket = rest[names[i]];
+ $length = bucket.length;
+ for (i0 = 0; i0 < $length; i0 += 2) {
+ result[index] = bucket[i0];
+ ++index;
+ }
+ }
+ }
+ H.assertHelper(index === _this._collection$_length);
+ return _this._keys = result;
+ },
+ _addHashTableEntry$3: function(table, key, value) {
+ var t1 = H._instanceType(this);
+ t1._precomputed1._check(key);
+ t1._rest[1]._check(value);
+ if (table[key] == null) {
+ ++this._collection$_length;
+ this._keys = null;
+ }
+ P._HashMap__setTableEntry(table, key, value);
+ },
+ _computeHashCode$1: function(key) {
+ return J.get$hashCode$(key) & 1073741823;
+ },
+ _getBucket$2: function(table, key) {
+ return table[this._computeHashCode$1(key)];
+ },
+ _findBucketIndex$2: function(bucket, key) {
+ var $length, i;
+ if (bucket == null)
+ return -1;
+ $length = bucket.length;
+ for (i = 0; i < $length; i += 2)
+ if (J.$eq$(bucket[i], key))
+ return i;
+ return -1;
+ }
+ };
+ P._IdentityHashMap.prototype = {
+ _computeHashCode$1: function(key) {
+ return H.objectHashCode(key) & 1073741823;
+ },
+ _findBucketIndex$2: function(bucket, key) {
+ var $length, i, t1;
+ if (bucket == null)
+ return -1;
+ $length = bucket.length;
+ for (i = 0; i < $length; i += 2) {
+ t1 = bucket[i];
+ if (t1 == null ? key == null : t1 === key)
+ return i;
+ }
+ return -1;
+ }
+ };
+ P._HashMapKeyIterable.prototype = {
+ get$length: function(_) {
+ return this._map._collection$_length;
+ },
+ get$isEmpty: function(_) {
+ return this._map._collection$_length === 0;
+ },
+ get$iterator: function(_) {
+ var t1 = this._map;
+ return new P._HashMapKeyIterator(t1, t1._computeKeys$0(), this.$ti._eval$1("_HashMapKeyIterator<1>"));
+ },
+ contains$1: function(_, element) {
+ return this._map.containsKey$1(element);
+ }
+ };
+ P._HashMapKeyIterator.prototype = {
+ get$current: function() {
+ return this._collection$_current;
+ },
+ moveNext$0: function() {
+ var _this = this,
+ keys = _this._keys,
+ offset = _this._offset,
+ t1 = _this._map;
+ if (keys !== t1._keys)
+ throw H.wrapException(P.ConcurrentModificationError$(t1));
+ else if (offset >= keys.length) {
+ _this.set$_collection$_current(null);
+ return false;
+ } else {
+ _this.set$_collection$_current(keys[offset]);
+ _this._offset = offset + 1;
+ return true;
+ }
+ },
+ set$_collection$_current: function(_current) {
+ this._collection$_current = this.$ti._precomputed1._check(_current);
+ },
+ $isIterator: 1
+ };
+ P._LinkedHashSet.prototype = {
+ _newSet$0: function() {
+ return new P._LinkedHashSet(H._instanceType(this)._eval$1("_LinkedHashSet<1>"));
+ },
+ get$iterator: function(_) {
+ var _this = this,
+ t1 = new P._LinkedHashSetIterator(_this, _this._collection$_modifications, H._instanceType(_this)._eval$1("_LinkedHashSetIterator<1>"));
+ t1._collection$_cell = _this._collection$_first;
+ return t1;
+ },
+ get$length: function(_) {
+ return this._collection$_length;
+ },
+ get$isEmpty: function(_) {
+ return this._collection$_length === 0;
+ },
+ contains$1: function(_, object) {
+ var strings, nums;
+ if (typeof object == "string" && object !== "__proto__") {
+ strings = this._strings;
+ if (strings == null)
+ return false;
+ return type$._LinkedHashSetCell._check(strings[object]) != null;
+ } else if (typeof object == "number" && (object & 1073741823) === object) {
+ nums = this._nums;
+ if (nums == null)
+ return false;
+ return type$._LinkedHashSetCell._check(nums[object]) != null;
+ } else
+ return this._contains$1(object);
+ },
+ _contains$1: function(object) {
+ var rest = this._collection$_rest;
+ if (rest == null)
+ return false;
+ return this._findBucketIndex$2(rest[this._computeHashCode$1(object)], object) >= 0;
+ },
+ get$first: function(_) {
+ var t1 = this._collection$_first;
+ if (t1 == null)
+ throw H.wrapException(P.StateError$("No elements"));
+ return H._instanceType(this)._precomputed1._check(t1._element);
+ },
+ get$last: function(_) {
+ var t1 = this._collection$_last;
+ if (t1 == null)
+ throw H.wrapException(P.StateError$("No elements"));
+ return H._instanceType(this)._precomputed1._check(t1._element);
+ },
+ add$1: function(_, element) {
+ var strings, nums, _this = this;
+ H._instanceType(_this)._precomputed1._check(element);
+ if (typeof element == "string" && element !== "__proto__") {
+ strings = _this._strings;
+ return _this._addHashTableEntry$2(strings == null ? _this._strings = P._LinkedHashSet__newHashTable() : strings, element);
+ } else if (typeof element == "number" && (element & 1073741823) === element) {
+ nums = _this._nums;
+ return _this._addHashTableEntry$2(nums == null ? _this._nums = P._LinkedHashSet__newHashTable() : nums, element);
+ } else
+ return _this._collection$_add$1(element);
+ },
+ _collection$_add$1: function(element) {
+ var rest, hash, bucket, t1, _this = this;
+ H._instanceType(_this)._precomputed1._check(element);
+ rest = _this._collection$_rest;
+ if (rest == null)
+ rest = _this._collection$_rest = P._LinkedHashSet__newHashTable();
+ hash = _this._computeHashCode$1(element);
+ bucket = rest[hash];
+ if (bucket == null) {
+ t1 = [_this._collection$_newLinkedCell$1(element)];
+ H.assertHelper(t1 != null);
+ rest[hash] = t1;
+ } else {
+ if (_this._findBucketIndex$2(bucket, element) >= 0)
+ return false;
+ bucket.push(_this._collection$_newLinkedCell$1(element));
+ }
+ return true;
+ },
+ remove$1: function(_, object) {
+ var _this = this;
+ if (typeof object == "string" && object !== "__proto__")
+ return _this._removeHashTableEntry$2(_this._strings, object);
+ else if (typeof object == "number" && (object & 1073741823) === object)
+ return _this._removeHashTableEntry$2(_this._nums, object);
+ else
+ return _this._remove$1(object);
+ },
+ _remove$1: function(object) {
+ var hash, bucket, index, cell, _this = this,
+ rest = _this._collection$_rest;
+ if (rest == null)
+ return false;
+ hash = _this._computeHashCode$1(object);
+ bucket = rest[hash];
+ index = _this._findBucketIndex$2(bucket, object);
+ if (index < 0)
+ return false;
+ cell = bucket.splice(index, 1)[0];
+ if (0 === bucket.length)
+ delete rest[hash];
+ _this._unlinkCell$1(cell);
+ return true;
+ },
+ _addHashTableEntry$2: function(table, element) {
+ H._instanceType(this)._precomputed1._check(element);
+ if (type$._LinkedHashSetCell._check(table[element]) != null)
+ return false;
+ table[element] = this._collection$_newLinkedCell$1(element);
+ return true;
+ },
+ _removeHashTableEntry$2: function(table, element) {
+ var cell;
+ if (table == null)
+ return false;
+ cell = type$._LinkedHashSetCell._check(table[element]);
+ if (cell == null)
+ return false;
+ this._unlinkCell$1(cell);
+ delete table[element];
+ return true;
+ },
+ _collection$_modified$0: function() {
+ this._collection$_modifications = 1073741823 & this._collection$_modifications + 1;
+ },
+ _collection$_newLinkedCell$1: function(element) {
+ var last, _this = this,
+ cell = new P._LinkedHashSetCell(H._instanceType(_this)._precomputed1._check(element));
+ if (_this._collection$_first == null)
+ _this._collection$_first = _this._collection$_last = cell;
+ else {
+ last = _this._collection$_last;
+ cell._collection$_previous = last;
+ _this._collection$_last = last._collection$_next = cell;
+ }
+ ++_this._collection$_length;
+ _this._collection$_modified$0();
+ return cell;
+ },
+ _unlinkCell$1: function(cell) {
+ var _this = this,
+ previous = cell._collection$_previous,
+ next = cell._collection$_next;
+ if (previous == null) {
+ H.assertHelper(cell == _this._collection$_first);
+ _this._collection$_first = next;
+ } else
+ previous._collection$_next = next;
+ if (next == null) {
+ H.assertHelper(cell == _this._collection$_last);
+ _this._collection$_last = previous;
+ } else
+ next._collection$_previous = previous;
+ --_this._collection$_length;
+ _this._collection$_modified$0();
+ },
+ _computeHashCode$1: function(element) {
+ return J.get$hashCode$(element) & 1073741823;
+ },
+ _findBucketIndex$2: function(bucket, element) {
+ var $length, i;
+ if (bucket == null)
+ return -1;
+ $length = bucket.length;
+ for (i = 0; i < $length; ++i)
+ if (J.$eq$(bucket[i]._element, element))
+ return i;
+ return -1;
+ },
+ $isLinkedHashSet: 1
+ };
+ P._LinkedHashSetCell.prototype = {};
+ P._LinkedHashSetIterator.prototype = {
+ get$current: function() {
+ return this._collection$_current;
+ },
+ moveNext$0: function() {
+ var _this = this,
+ t1 = _this._set;
+ if (_this._collection$_modifications !== t1._collection$_modifications)
+ throw H.wrapException(P.ConcurrentModificationError$(t1));
+ else {
+ t1 = _this._collection$_cell;
+ if (t1 == null) {
+ _this.set$_collection$_current(null);
+ return false;
+ } else {
+ _this.set$_collection$_current(_this.$ti._precomputed1._check(t1._element));
+ _this._collection$_cell = _this._collection$_cell._collection$_next;
+ return true;
+ }
+ }
+ },
+ set$_collection$_current: function(_current) {
+ this._collection$_current = this.$ti._precomputed1._check(_current);
+ },
+ $isIterator: 1
+ };
+ P.UnmodifiableListView.prototype = {
+ get$length: function(_) {
+ var t1 = this._collection$_source;
+ return t1.get$length(t1);
+ },
+ $index: function(_, index) {
+ return this._collection$_source.$index(0, H._checkIntNullable(index));
+ }
+ };
+ P.HashMap_HashMap$from_closure.prototype = {
+ call$2: function(k, v) {
+ this.result.$indexSet(0, this.K._check(k), this.V._check(v));
+ },
+ $signature: 6
+ };
+ P.IterableBase.prototype = {};
+ P.LinkedHashMap_LinkedHashMap$from_closure.prototype = {
+ call$2: function(k, v) {
+ this.result.$indexSet(0, this.K._check(k), this.V._check(v));
+ },
+ $signature: 6
+ };
+ P.ListBase.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.ListMixin.prototype = {
+ get$iterator: function(receiver) {
+ return new H.ListIterator(receiver, this.get$length(receiver), H.instanceType(receiver)._eval$1("ListIterator<ListMixin.E>"));
+ },
+ elementAt$1: function(receiver, index) {
+ return this.$index(receiver, index);
+ },
+ get$isEmpty: function(receiver) {
+ return this.get$length(receiver) === 0;
+ },
+ get$first: function(receiver) {
+ if (this.get$length(receiver) === 0)
+ throw H.wrapException(H.IterableElementError_noElement());
+ return this.$index(receiver, 0);
+ },
+ get$last: function(receiver) {
+ if (this.get$length(receiver) === 0)
+ throw H.wrapException(H.IterableElementError_noElement());
+ return this.$index(receiver, this.get$length(receiver) - 1);
+ },
+ map$1$1: function(receiver, f, $T) {
+ var t1 = H.instanceType(receiver);
+ return new H.MappedListIterable(receiver, t1._bind$1($T)._eval$1("1(ListMixin.E)")._check(f), t1._eval$1("@<ListMixin.E>")._bind$1($T)._eval$1("MappedListIterable<1,2>"));
+ },
+ toList$1$growable: function(receiver, growable) {
+ var i,
+ result = H.setRuntimeTypeInfo([], H.instanceType(receiver)._eval$1("JSArray<ListMixin.E>"));
+ C.JSArray_methods.set$length(result, this.get$length(receiver));
+ for (i = 0; i < this.get$length(receiver); ++i)
+ C.JSArray_methods.$indexSet(result, i, this.$index(receiver, i));
+ return result;
+ },
+ toList$0: function($receiver) {
+ return this.toList$1$growable($receiver, true);
+ },
+ toSet$0: function(receiver) {
+ var i,
+ result = P.LinkedHashSet_LinkedHashSet(H.instanceType(receiver)._eval$1("ListMixin.E"));
+ for (i = 0; i < this.get$length(receiver); ++i)
+ result.add$1(0, this.$index(receiver, i));
+ return result;
+ },
+ remove$1: function(receiver, element) {
+ var i;
+ for (i = 0; i < this.get$length(receiver); ++i)
+ if (J.$eq$(this.$index(receiver, i), element)) {
+ this._closeGap$2(receiver, i, i + 1);
+ return true;
+ }
+ return false;
+ },
+ _closeGap$2: function(receiver, start, end) {
+ var size, i, _this = this,
+ $length = _this.get$length(receiver);
+ H.assertHelper(start < end);
+ H.assertHelper(end <= $length);
+ size = end - start;
+ for (i = end; i < $length; ++i)
+ _this.$indexSet(receiver, i - size, _this.$index(receiver, i));
+ _this.set$length(receiver, $length - size);
+ },
+ fillRange$3: function(receiver, start, end, fill) {
+ var i;
+ H.instanceType(receiver)._eval$1("ListMixin.E")._check(fill);
+ P.RangeError_checkValidRange(start, end, this.get$length(receiver));
+ for (i = start; i < end; ++i)
+ this.$indexSet(receiver, i, fill);
+ },
+ toString$0: function(receiver) {
+ return P.IterableBase_iterableToFullString(receiver, "[", "]");
+ }
+ };
+ P.MapBase.prototype = {};
+ P.MapBase_mapToString_closure.prototype = {
+ call$2: function(k, v) {
+ var t2,
+ t1 = this._box_0;
+ if (!t1.first)
+ this.result._contents += ", ";
+ t1.first = false;
+ t1 = this.result;
+ t2 = t1._contents += H.S(k);
+ t1._contents = t2 + ": ";
+ t1._contents += H.S(v);
+ },
+ $signature: 6
+ };
+ P.MapMixin.prototype = {
+ cast$2$0: function(_, RK, RV) {
+ var t1 = H._instanceType(this);
+ return P.Map_castFrom(this, t1._eval$1("MapMixin.K"), t1._eval$1("MapMixin.V"), RK, RV);
+ },
+ forEach$1: function(_, action) {
+ var t1, key;
+ H._instanceType(this)._eval$1("~(MapMixin.K,MapMixin.V)")._check(action);
+ for (t1 = this.get$keys(), t1 = t1.get$iterator(t1); t1.moveNext$0();) {
+ key = t1.get$current();
+ action.call$2(key, this.$index(0, key));
+ }
+ },
+ map$2$1: function(_, transform, K2, V2) {
+ var result, t1, key, entry;
+ H._instanceType(this)._bind$1(K2)._bind$1(V2)._eval$1("MapEntry<1,2>(MapMixin.K,MapMixin.V)")._check(transform);
+ result = P.LinkedHashMap_LinkedHashMap$_empty(K2, V2);
+ for (t1 = this.get$keys(), t1 = t1.get$iterator(t1); t1.moveNext$0();) {
+ key = t1.get$current();
+ entry = transform.call$2(key, this.$index(0, key));
+ result.$indexSet(0, entry.key, entry.value);
+ }
+ return result;
+ },
+ containsKey$1: function(key) {
+ return this.get$keys().contains$1(0, key);
+ },
+ get$length: function(_) {
+ var t1 = this.get$keys();
+ return t1.get$length(t1);
+ },
+ get$isEmpty: function(_) {
+ var t1 = this.get$keys();
+ return t1.get$isEmpty(t1);
+ },
+ toString$0: function(_) {
+ return P.MapBase_mapToString(this);
+ },
+ $isMap: 1
+ };
+ P._UnmodifiableMapMixin.prototype = {
+ remove$1: function(_, key) {
+ throw H.wrapException(P.UnsupportedError$("Cannot modify unmodifiable map"));
+ }
+ };
+ P.MapView.prototype = {
+ cast$2$0: function(_, RK, RV) {
+ return this._map.cast$2$0(0, RK, RV);
+ },
+ $index: function(_, key) {
+ return this._map.$index(0, key);
+ },
+ containsKey$1: function(key) {
+ return this._map.containsKey$1(key);
+ },
+ forEach$1: function(_, action) {
+ this._map.forEach$1(0, H._instanceType(this)._eval$1("~(1,2)")._check(action));
+ },
+ get$isEmpty: function(_) {
+ var t1 = this._map;
+ return t1.get$isEmpty(t1);
+ },
+ get$length: function(_) {
+ var t1 = this._map;
+ return t1.get$length(t1);
+ },
+ get$keys: function() {
+ return this._map.get$keys();
+ },
+ remove$1: function(_, key) {
+ return this._map.remove$1(0, key);
+ },
+ toString$0: function(_) {
+ return this._map.toString$0(0);
+ },
+ map$2$1: function(_, transform, K2, V2) {
+ return this._map.map$2$1(0, H._instanceType(this)._bind$1(K2)._bind$1(V2)._eval$1("MapEntry<1,2>(3,4)")._check(transform), K2, V2);
+ },
+ $isMap: 1
+ };
+ P.UnmodifiableMapView.prototype = {
+ cast$2$0: function(_, RK, RV) {
+ return new P.UnmodifiableMapView(this._map.cast$2$0(0, RK, RV), RK._eval$1("@<0>")._bind$1(RV)._eval$1("UnmodifiableMapView<1,2>"));
+ }
+ };
+ P.ListQueue.prototype = {
+ get$iterator: function(_) {
+ var _this = this;
+ return new P._ListQueueIterator(_this, _this._tail, _this._modificationCount, _this._head, _this.$ti._eval$1("_ListQueueIterator<1>"));
+ },
+ get$isEmpty: function(_) {
+ return this._head === this._tail;
+ },
+ get$length: function(_) {
+ return (this._tail - this._head & this._table.length - 1) >>> 0;
+ },
+ get$first: function(_) {
+ var t2,
+ t1 = this._head;
+ if (t1 === this._tail)
+ throw H.wrapException(H.IterableElementError_noElement());
+ t2 = this._table;
+ if (t1 >= t2.length)
+ return H.ioore(t2, t1);
+ return t2[t1];
+ },
+ get$last: function(_) {
+ var t3,
+ t1 = this._head,
+ t2 = this._tail;
+ if (t1 === t2)
+ throw H.wrapException(H.IterableElementError_noElement());
+ t1 = this._table;
+ t3 = t1.length;
+ t2 = (t2 - 1 & t3 - 1) >>> 0;
+ if (t2 < 0 || t2 >= t3)
+ return H.ioore(t1, t2);
+ return t1[t2];
+ },
+ elementAt$1: function(_, index) {
+ var t1, t2, t3, _this = this,
+ $length = _this.get$length(_this);
+ if (0 > index || index >= $length)
+ H.throwExpression(P.IndexError$(index, _this, "index", null, $length));
+ t1 = _this._table;
+ t2 = t1.length;
+ t3 = (_this._head + index & t2 - 1) >>> 0;
+ if (t3 < 0 || t3 >= t2)
+ return H.ioore(t1, t3);
+ return t1[t3];
+ },
+ clear$0: function(_) {
+ var _this = this,
+ i = _this._head;
+ if (i !== _this._tail) {
+ for (; i !== _this._tail; i = (i + 1 & _this._table.length - 1) >>> 0)
+ C.JSArray_methods.$indexSet(_this._table, i, null);
+ _this._head = _this._tail = 0;
+ ++_this._modificationCount;
+ }
+ },
+ toString$0: function(_) {
+ return P.IterableBase_iterableToFullString(this, "{", "}");
+ },
+ removeFirst$0: function() {
+ var t2, result, _this = this,
+ t1 = _this._head;
+ if (t1 === _this._tail)
+ throw H.wrapException(H.IterableElementError_noElement());
+ ++_this._modificationCount;
+ t2 = _this._table;
+ if (t1 >= t2.length)
+ return H.ioore(t2, t1);
+ result = t2[t1];
+ C.JSArray_methods.$indexSet(t2, t1, null);
+ _this._head = (_this._head + 1 & _this._table.length - 1) >>> 0;
+ return result;
+ },
+ _collection$_add$1: function(element) {
+ var t2, t3, newTable, split, _this = this,
+ t1 = _this.$ti;
+ t1._precomputed1._check(element);
+ C.JSArray_methods.$indexSet(_this._table, _this._tail, element);
+ t2 = _this._tail;
+ t3 = _this._table.length;
+ t2 = (t2 + 1 & t3 - 1) >>> 0;
+ _this._tail = t2;
+ if (_this._head === t2) {
+ t2 = new Array(t3 * 2);
+ t2.fixed$length = Array;
+ newTable = H.setRuntimeTypeInfo(t2, t1._eval$1("JSArray<1>"));
+ t1 = _this._table;
+ t2 = _this._head;
+ split = t1.length - t2;
+ C.JSArray_methods.setRange$4(newTable, 0, split, t1, t2);
+ C.JSArray_methods.setRange$4(newTable, split, split + _this._head, _this._table, 0);
+ _this._head = 0;
+ _this._tail = _this._table.length;
+ _this.set$_table(newTable);
+ }
+ ++_this._modificationCount;
+ },
+ set$_table: function(_table) {
+ this._table = this.$ti._eval$1("List<1>")._check(_table);
+ },
+ $isQueue: 1
+ };
+ P._ListQueueIterator.prototype = {
+ get$current: function() {
+ return this._collection$_current;
+ },
+ moveNext$0: function() {
+ var t2, t3, _this = this,
+ t1 = _this._queue;
+ if (_this._modificationCount !== t1._modificationCount)
+ H.throwExpression(P.ConcurrentModificationError$(t1));
+ t2 = _this._position;
+ if (t2 === _this._end) {
+ _this.set$_collection$_current(null);
+ return false;
+ }
+ t3 = t1._table;
+ if (t2 >= t3.length)
+ return H.ioore(t3, t2);
+ _this.set$_collection$_current(t3[t2]);
+ _this._position = (_this._position + 1 & t1._table.length - 1) >>> 0;
+ return true;
+ },
+ set$_collection$_current: function(_current) {
+ this._collection$_current = this.$ti._precomputed1._check(_current);
+ },
+ $isIterator: 1
+ };
+ P.SetMixin.prototype = {
+ get$isEmpty: function(_) {
+ return this.get$length(this) === 0;
+ },
+ map$1$1: function(_, f, $T) {
+ var t1 = H._instanceType(this);
+ return new H.EfficientLengthMappedIterable(this, t1._bind$1($T)._eval$1("1(2)")._check(f), t1._eval$1("@<1>")._bind$1($T)._eval$1("EfficientLengthMappedIterable<1,2>"));
+ },
+ toString$0: function(_) {
+ return P.IterableBase_iterableToFullString(this, "{", "}");
+ },
+ every$1: function(_, f) {
+ var t1;
+ H._instanceType(this)._eval$1("bool(1)")._check(f);
+ for (t1 = this.get$iterator(this); t1.moveNext$0();)
+ if (!H.boolConversionCheck(f.call$1(t1.get$current())))
+ return false;
+ return true;
+ },
+ get$first: function(_) {
+ var it = this.get$iterator(this);
+ if (!it.moveNext$0())
+ throw H.wrapException(H.IterableElementError_noElement());
+ return it.get$current();
+ },
+ get$last: function(_) {
+ var result,
+ it = this.get$iterator(this);
+ if (!it.moveNext$0())
+ throw H.wrapException(H.IterableElementError_noElement());
+ do
+ result = it.get$current();
+ while (it.moveNext$0());
+ return result;
+ },
+ $isEfficientLengthIterable: 1,
+ $isIterable: 1,
+ $isSet: 1
+ };
+ P.SetBase.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isSet: 1};
+ P._SetBase.prototype = {
+ toSet$0: function(_) {
+ var t1 = this._newSet$0();
+ t1.addAll$1(0, this);
+ return t1;
+ },
+ get$isEmpty: function(_) {
+ return this._collection$_length === 0;
+ },
+ addAll$1: function(_, elements) {
+ var t1;
+ H._instanceType(this)._eval$1("Iterable<1>")._check(elements);
+ for (t1 = elements.get$iterator(elements); t1.moveNext$0();)
+ this.add$1(0, t1.get$current());
+ },
+ union$1: function(other) {
+ var t1;
+ H._instanceType(this)._eval$1("Set<1>")._check(other);
+ t1 = this.toSet$0(0);
+ t1.addAll$1(0, other);
+ return t1;
+ },
+ toList$1$growable: function(_, growable) {
+ var i, i0, _this = this,
+ t1 = H._instanceType(_this),
+ result = H.setRuntimeTypeInfo([], t1._eval$1("JSArray<1>"));
+ C.JSArray_methods.set$length(result, _this._collection$_length);
+ for (t1 = P._LinkedHashSetIterator$(_this, _this._collection$_modifications, t1._precomputed1), i = 0; t1.moveNext$0(); i = i0) {
+ i0 = i + 1;
+ C.JSArray_methods.$indexSet(result, i, t1._collection$_current);
+ }
+ return result;
+ },
+ toList$0: function($receiver) {
+ return this.toList$1$growable($receiver, true);
+ },
+ map$1$1: function(_, f, $T) {
+ var t1 = H._instanceType(this);
+ return new H.EfficientLengthMappedIterable(this, t1._bind$1($T)._eval$1("1(2)")._check(f), t1._eval$1("@<1>")._bind$1($T)._eval$1("EfficientLengthMappedIterable<1,2>"));
+ },
+ toString$0: function(_) {
+ return P.IterableBase_iterableToFullString(this, "{", "}");
+ },
+ where$1: function(_, f) {
+ var t1 = H._instanceType(this);
+ return new H.WhereIterable(this, t1._eval$1("bool(1)")._check(f), t1._eval$1("WhereIterable<1>"));
+ },
+ fold$1$2: function(_, initialValue, combine, $T) {
+ var t1, value;
+ $T._check(initialValue);
+ t1 = H._instanceType(this);
+ t1._bind$1($T)._eval$1("1(1,2)")._check(combine);
+ for (t1 = P._LinkedHashSetIterator$(this, this._collection$_modifications, t1._precomputed1), value = initialValue; t1.moveNext$0();)
+ value = combine.call$2(value, t1._collection$_current);
+ return value;
+ },
+ every$1: function(_, f) {
+ var t1 = H._instanceType(this);
+ t1._eval$1("bool(1)")._check(f);
+ for (t1 = P._LinkedHashSetIterator$(this, this._collection$_modifications, t1._precomputed1); t1.moveNext$0();)
+ if (!H.boolConversionCheck(f.call$1(t1._collection$_current)))
+ return false;
+ return true;
+ },
+ any$1: function(_, test) {
+ var t1 = H._instanceType(this);
+ t1._eval$1("bool(1)")._check(test);
+ for (t1 = P._LinkedHashSetIterator$(this, this._collection$_modifications, t1._precomputed1); t1.moveNext$0();)
+ if (H.boolConversionCheck(test.call$1(t1._collection$_current)))
+ return true;
+ return false;
+ },
+ get$first: function(_) {
+ var it = P._LinkedHashSetIterator$(this, this._collection$_modifications, H._instanceType(this)._precomputed1);
+ if (!it.moveNext$0())
+ throw H.wrapException(H.IterableElementError_noElement());
+ return it._collection$_current;
+ },
+ get$last: function(_) {
+ var result,
+ it = P._LinkedHashSetIterator$(this, this._collection$_modifications, H._instanceType(this)._precomputed1);
+ if (!it.moveNext$0())
+ throw H.wrapException(H.IterableElementError_noElement());
+ do
+ result = it._collection$_current;
+ while (it.moveNext$0());
+ return result;
+ },
+ $isEfficientLengthIterable: 1,
+ $isIterable: 1,
+ $isSet: 1
+ };
+ P._ListBase_Object_ListMixin.prototype = {};
+ P._SetBase_Object_SetMixin.prototype = {};
+ P._UnmodifiableMapView_MapView__UnmodifiableMapMixin.prototype = {};
+ P._JsonMap.prototype = {
+ $index: function(_, key) {
+ var result,
+ t1 = this._processed;
+ if (t1 == null)
+ return this.get$_upgradedMap().$index(0, key);
+ else if (typeof key != "string")
+ return null;
+ else {
+ result = t1[key];
+ return typeof result == "undefined" ? this._process$1(key) : result;
+ }
+ },
+ get$length: function(_) {
+ var t1;
+ if (this._processed == null) {
+ t1 = this.get$_upgradedMap();
+ t1 = t1.get$length(t1);
+ } else
+ t1 = this._convert$_computeKeys$0().length;
+ return t1;
+ },
+ get$isEmpty: function(_) {
+ return this.get$length(this) === 0;
+ },
+ get$keys: function() {
+ if (this._processed == null)
+ return this.get$_upgradedMap().get$keys();
+ return new P._JsonMapKeyIterable(this);
+ },
+ containsKey$1: function(key) {
+ if (this._processed == null)
+ return this.get$_upgradedMap().containsKey$1(key);
+ if (typeof key != "string")
+ return false;
+ return Object.prototype.hasOwnProperty.call(this._original, key);
+ },
+ remove$1: function(_, key) {
+ if (this._processed != null && !this.containsKey$1(key))
+ return null;
+ return this._upgrade$0().remove$1(0, key);
+ },
+ forEach$1: function(_, f) {
+ var keys, i, key, value, _this = this;
+ type$.void_Function_String_dynamic._check(f);
+ if (_this._processed == null)
+ return _this.get$_upgradedMap().forEach$1(0, f);
+ keys = _this._convert$_computeKeys$0();
+ for (i = 0; i < keys.length; ++i) {
+ key = keys[i];
+ value = _this._processed[key];
+ if (typeof value == "undefined") {
+ value = P._convertJsonToDartLazy(_this._original[key]);
+ _this._processed[key] = value;
+ }
+ f.call$2(key, value);
+ if (keys !== _this._data)
+ throw H.wrapException(P.ConcurrentModificationError$(_this));
+ }
+ },
+ get$_upgradedMap: function() {
+ H.assertHelper(this._processed == null);
+ return this._data;
+ },
+ _convert$_computeKeys$0: function() {
+ var keys, _this = this;
+ H.assertHelper(_this._processed != null);
+ keys = type$.List_dynamic._check(_this._data);
+ if (keys == null)
+ keys = _this._data = H.setRuntimeTypeInfo(Object.keys(_this._original), type$.JSArray_String);
+ return keys;
+ },
+ _upgrade$0: function() {
+ var result, keys, i, t1, key, _this = this;
+ if (_this._processed == null)
+ return _this.get$_upgradedMap();
+ result = P.LinkedHashMap_LinkedHashMap$_empty(type$.String, type$.dynamic);
+ keys = _this._convert$_computeKeys$0();
+ for (i = 0; t1 = keys.length, i < t1; ++i) {
+ key = keys[i];
+ result.$indexSet(0, key, _this.$index(0, key));
+ }
+ if (t1 === 0)
+ C.JSArray_methods.add$1(keys, null);
+ else
+ C.JSArray_methods.set$length(keys, 0);
+ _this._original = _this._processed = null;
+ return _this._data = result;
+ },
+ _process$1: function(key) {
+ var result;
+ if (!Object.prototype.hasOwnProperty.call(this._original, key))
+ return null;
+ result = P._convertJsonToDartLazy(this._original[key]);
+ return this._processed[key] = result;
+ }
+ };
+ P._JsonMapKeyIterable.prototype = {
+ get$length: function(_) {
+ var t1 = this._parent;
+ return t1.get$length(t1);
+ },
+ elementAt$1: function(_, index) {
+ var t1 = this._parent;
+ if (t1._processed == null)
+ t1 = t1.get$keys().elementAt$1(0, index);
+ else {
+ t1 = t1._convert$_computeKeys$0();
+ if (index < 0 || index >= t1.length)
+ return H.ioore(t1, index);
+ t1 = t1[index];
+ }
+ return t1;
+ },
+ get$iterator: function(_) {
+ var t1 = this._parent;
+ if (t1._processed == null) {
+ t1 = t1.get$keys();
+ t1 = t1.get$iterator(t1);
+ } else {
+ t1 = t1._convert$_computeKeys$0();
+ t1 = new J.ArrayIterator(t1, t1.length, H._arrayInstanceType(t1)._eval$1("ArrayIterator<1>"));
+ }
+ return t1;
+ },
+ contains$1: function(_, key) {
+ return this._parent.containsKey$1(key);
+ }
+ };
+ P.AsciiCodec.prototype = {
+ encode$1: function(source) {
+ return C.AsciiEncoder_127.convert$1(source);
+ }
+ };
+ P._UnicodeSubsetEncoder.prototype = {
+ convert$1: function(string) {
+ var $length, result, t1, t2, t3, i, codeUnit;
+ H._checkStringNullable(string);
+ $length = P.RangeError_checkValidRange(0, null, string.length) - 0;
+ result = new Uint8Array($length);
+ for (t1 = result.length, t2 = ~this._subsetMask, t3 = J.getInterceptor$s(string), i = 0; i < $length; ++i) {
+ codeUnit = t3._codeUnitAt$1(string, i);
+ if ((codeUnit & t2) !== 0)
+ throw H.wrapException(P.ArgumentError$value(string, "string", "Contains invalid characters."));
+ if (i >= t1)
+ return H.ioore(result, i);
+ result[i] = codeUnit;
+ }
+ return result;
+ }
+ };
+ P.AsciiEncoder.prototype = {};
+ P.Base64Codec.prototype = {
+ normalize$3: function(source, start, end) {
+ var inverseAlphabet, i, sliceStart, buffer, firstPadding, firstPaddingSourceIndex, paddingCount, i0, char, i1, digit1, digit2, char0, value, t2, endLength, $length,
+ _s31_ = "Invalid base64 encoding length ",
+ t1 = source.length;
+ end = P.RangeError_checkValidRange(start, end, t1);
+ inverseAlphabet = $.$get$_Base64Decoder__inverseAlphabet();
+ for (i = start, sliceStart = i, buffer = null, firstPadding = -1, firstPaddingSourceIndex = -1, paddingCount = 0; i < end; i = i0) {
+ i0 = i + 1;
+ char = C.JSString_methods._codeUnitAt$1(source, i);
+ if (char === 37) {
+ i1 = i0 + 2;
+ if (i1 <= end) {
+ H.assertHelper(i1 <= t1);
+ digit1 = H.hexDigitValue(C.JSString_methods._codeUnitAt$1(source, i0));
+ digit2 = H.hexDigitValue(C.JSString_methods._codeUnitAt$1(source, i0 + 1));
+ char0 = digit1 * 16 + digit2 - (digit2 & 256);
+ if (char0 === 37)
+ char0 = -1;
+ i0 = i1;
+ } else
+ char0 = -1;
+ } else
+ char0 = char;
+ if (0 <= char0 && char0 <= 127) {
+ if (char0 < 0 || char0 >= inverseAlphabet.length)
+ return H.ioore(inverseAlphabet, char0);
+ value = inverseAlphabet[char0];
+ if (value >= 0) {
+ char0 = C.JSString_methods.codeUnitAt$1("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", value);
+ if (char0 === char)
+ continue;
+ char = char0;
+ } else {
+ if (value === -1) {
+ if (firstPadding < 0) {
+ t2 = buffer == null ? null : buffer._contents.length;
+ if (t2 == null)
+ t2 = 0;
+ firstPadding = t2 + (i - sliceStart);
+ firstPaddingSourceIndex = i;
+ }
+ ++paddingCount;
+ if (char === 61)
+ continue;
+ }
+ char = char0;
+ }
+ if (value !== -2) {
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ t2 = buffer._contents += C.JSString_methods.substring$2(source, sliceStart, i);
+ buffer._contents = t2 + H.Primitives_stringFromCharCode(char);
+ sliceStart = i0;
+ continue;
+ }
+ }
+ throw H.wrapException(P.FormatException$("Invalid base64 data", source, i));
+ }
+ if (buffer != null) {
+ t1 = buffer._contents += C.JSString_methods.substring$2(source, sliceStart, end);
+ t2 = t1.length;
+ if (firstPadding >= 0)
+ P.Base64Codec__checkPadding(source, firstPaddingSourceIndex, end, firstPadding, paddingCount, t2);
+ else {
+ endLength = C.JSInt_methods.$mod(t2 - 1, 4) + 1;
+ if (endLength === 1)
+ throw H.wrapException(P.FormatException$(_s31_, source, end));
+ for (; endLength < 4;) {
+ t1 += "=";
+ buffer._contents = t1;
+ ++endLength;
+ }
+ }
+ t1 = buffer._contents;
+ return C.JSString_methods.replaceRange$3(source, start, end, t1.charCodeAt(0) == 0 ? t1 : t1);
+ }
+ $length = end - start;
+ if (firstPadding >= 0)
+ P.Base64Codec__checkPadding(source, firstPaddingSourceIndex, end, firstPadding, paddingCount, $length);
+ else {
+ endLength = C.JSInt_methods.$mod($length, 4);
+ if (endLength === 1)
+ throw H.wrapException(P.FormatException$(_s31_, source, end));
+ if (endLength > 1)
+ source = C.JSString_methods.replaceRange$3(source, end, end, endLength === 2 ? "==" : "=");
+ }
+ return source;
+ }
+ };
+ P.Base64Encoder.prototype = {};
+ P.Codec.prototype = {};
+ P._FusedCodec.prototype = {};
+ P.Converter.prototype = {};
+ P.Encoding.prototype = {};
+ P.JsonCodec.prototype = {
+ decode$2$reviver: function(source, reviver) {
+ var t1;
+ type$.dynamic_Function_Object_Object._check(reviver);
+ t1 = P._parseJson(source, this.get$decoder()._reviver);
+ return t1;
+ },
+ get$decoder: function() {
+ return C.JsonDecoder_null;
+ }
+ };
+ P.JsonDecoder.prototype = {};
+ P.Utf8Codec.prototype = {
+ get$encoder: function() {
+ return C.C_Utf8Encoder;
+ }
+ };
+ P.Utf8Encoder.prototype = {
+ convert$1: function(string) {
+ var end, $length, t1, encoder, endPosition, t2, lastCodeUnit;
+ H._checkStringNullable(string);
+ end = P.RangeError_checkValidRange(0, null, string.length);
+ $length = end - 0;
+ if ($length === 0)
+ return new Uint8Array(0);
+ t1 = new Uint8Array($length * 3);
+ encoder = new P._Utf8Encoder(t1);
+ endPosition = encoder._fillBuffer$3(string, 0, end);
+ t2 = end - 1;
+ H.assertHelper(endPosition >= t2);
+ if (endPosition !== end) {
+ lastCodeUnit = J.codeUnitAt$1$s(string, t2);
+ H.assertHelper((lastCodeUnit & 64512) === 55296);
+ H.assertHelper(!encoder._writeSurrogate$2(lastCodeUnit, 0));
+ }
+ return C.NativeUint8List_methods.sublist$2(t1, 0, encoder._bufferIndex);
+ }
+ };
+ P._Utf8Encoder.prototype = {
+ _writeSurrogate$2: function(leadingSurrogate, nextCodeUnit) {
+ var rune, t3, t4, _this = this,
+ t1 = _this._buffer,
+ t2 = t1.length;
+ if ((nextCodeUnit & 64512) === 56320) {
+ rune = 65536 + ((leadingSurrogate & 1023) << 10) | nextCodeUnit & 1023;
+ H.assertHelper(rune > 65535);
+ H.assertHelper(rune <= 1114111);
+ t3 = _this._bufferIndex;
+ t4 = _this._bufferIndex = t3 + 1;
+ if (t3 >= t2)
+ return H.ioore(t1, t3);
+ t1[t3] = 240 | rune >>> 18;
+ t3 = _this._bufferIndex = t4 + 1;
+ if (t4 >= t2)
+ return H.ioore(t1, t4);
+ t1[t4] = 128 | rune >>> 12 & 63;
+ t4 = _this._bufferIndex = t3 + 1;
+ if (t3 >= t2)
+ return H.ioore(t1, t3);
+ t1[t3] = 128 | rune >>> 6 & 63;
+ _this._bufferIndex = t4 + 1;
+ if (t4 >= t2)
+ return H.ioore(t1, t4);
+ t1[t4] = 128 | rune & 63;
+ return true;
+ } else {
+ t3 = _this._bufferIndex;
+ t4 = _this._bufferIndex = t3 + 1;
+ if (t3 >= t2)
+ return H.ioore(t1, t3);
+ t1[t3] = 224 | leadingSurrogate >>> 12;
+ t3 = _this._bufferIndex = t4 + 1;
+ if (t4 >= t2)
+ return H.ioore(t1, t4);
+ t1[t4] = 128 | leadingSurrogate >>> 6 & 63;
+ _this._bufferIndex = t3 + 1;
+ if (t3 >= t2)
+ return H.ioore(t1, t3);
+ t1[t3] = 128 | leadingSurrogate & 63;
+ return false;
+ }
+ },
+ _fillBuffer$3: function(str, start, end) {
+ var t1, t2, t3, stringIndex, codeUnit, t4, stringIndex0, t5, _this = this;
+ if (start !== end && (J.codeUnitAt$1$s(str, end - 1) & 64512) === 55296)
+ --end;
+ for (t1 = _this._buffer, t2 = t1.length, t3 = J.getInterceptor$s(str), stringIndex = start; stringIndex < end; ++stringIndex) {
+ codeUnit = t3._codeUnitAt$1(str, stringIndex);
+ if (codeUnit <= 127) {
+ t4 = _this._bufferIndex;
+ if (t4 >= t2)
+ break;
+ _this._bufferIndex = t4 + 1;
+ t1[t4] = codeUnit;
+ } else if ((codeUnit & 64512) === 55296) {
+ if (_this._bufferIndex + 3 >= t2)
+ break;
+ stringIndex0 = stringIndex + 1;
+ if (_this._writeSurrogate$2(codeUnit, C.JSString_methods._codeUnitAt$1(str, stringIndex0)))
+ stringIndex = stringIndex0;
+ } else if (codeUnit <= 2047) {
+ t4 = _this._bufferIndex;
+ t5 = t4 + 1;
+ if (t5 >= t2)
+ break;
+ _this._bufferIndex = t5;
+ if (t4 >= t2)
+ return H.ioore(t1, t4);
+ t1[t4] = 192 | codeUnit >>> 6;
+ _this._bufferIndex = t5 + 1;
+ t1[t5] = 128 | codeUnit & 63;
+ } else {
+ H.assertHelper(codeUnit <= 65535);
+ t4 = _this._bufferIndex;
+ if (t4 + 2 >= t2)
+ break;
+ t5 = _this._bufferIndex = t4 + 1;
+ if (t4 >= t2)
+ return H.ioore(t1, t4);
+ t1[t4] = 224 | codeUnit >>> 12;
+ t4 = _this._bufferIndex = t5 + 1;
+ if (t5 >= t2)
+ return H.ioore(t1, t5);
+ t1[t5] = 128 | codeUnit >>> 6 & 63;
+ _this._bufferIndex = t4 + 1;
+ if (t4 >= t2)
+ return H.ioore(t1, t4);
+ t1[t4] = 128 | codeUnit & 63;
+ }
+ }
+ return stringIndex;
+ }
+ };
+ P.Utf8Decoder.prototype = {
+ convert$1: function(codeUnits) {
+ var result, end, oneBytes, firstPart, buffer, start, isFirstCharacter, decoder, t1;
+ type$.List_int._check(codeUnits);
+ result = P.Utf8Decoder__convertIntercepted(false, codeUnits, 0, null);
+ if (result != null)
+ return result;
+ end = P.RangeError_checkValidRange(0, null, J.get$length$asx(codeUnits));
+ oneBytes = P._scanOneByteCharacters(codeUnits, 0, end);
+ if (oneBytes > 0) {
+ firstPart = P.String_String$fromCharCodes(codeUnits, 0, oneBytes);
+ if (oneBytes === end)
+ return firstPart;
+ buffer = new P.StringBuffer(firstPart);
+ start = oneBytes;
+ isFirstCharacter = false;
+ } else {
+ start = 0;
+ buffer = null;
+ isFirstCharacter = true;
+ }
+ if (buffer == null)
+ buffer = new P.StringBuffer("");
+ decoder = new P._Utf8Decoder(false, buffer);
+ decoder._isFirstCharacter = isFirstCharacter;
+ decoder.convert$3(codeUnits, start, end);
+ decoder.flush$2(codeUnits, end);
+ t1 = buffer._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ }
+ };
+ P._Utf8Decoder.prototype = {
+ flush$2: function(source, offset) {
+ var t1;
+ type$.List_int._check(source);
+ if (this._expectedUnits > 0) {
+ t1 = P.FormatException$("Unfinished UTF-8 octet sequence", source, offset);
+ throw H.wrapException(t1);
+ }
+ },
+ convert$3: function(codeUnits, startIndex, endIndex) {
+ var value, expectedUnits, extraUnits, t1, t2, i, unit, t3, oneBytes, i0, i1, t4, _this = this,
+ _s21_ = "Bad UTF-8 encoding 0x";
+ type$.List_int._check(codeUnits);
+ value = _this._convert$_value;
+ expectedUnits = _this._expectedUnits;
+ extraUnits = _this._extraUnits;
+ _this._extraUnits = _this._expectedUnits = _this._convert$_value = 0;
+ $label0$0:
+ for (t1 = J.getInterceptor$asx(codeUnits), t2 = _this._stringSink, i = startIndex; true; i = i1) {
+ $label1$1:
+ if (expectedUnits > 0) {
+ do {
+ if (i === endIndex)
+ break $label0$0;
+ unit = t1.$index(codeUnits, i);
+ if (typeof unit !== "number")
+ return unit.$and();
+ if ((unit & 192) !== 128) {
+ t3 = P.FormatException$(_s21_ + C.JSInt_methods.toRadixString$1(unit, 16), codeUnits, i);
+ throw H.wrapException(t3);
+ } else {
+ value = (value << 6 | unit & 63) >>> 0;
+ --expectedUnits;
+ ++i;
+ }
+ } while (expectedUnits > 0);
+ t3 = extraUnits - 1;
+ if (t3 < 0 || t3 >= 4)
+ return H.ioore(C.List_127_2047_65535_1114111, t3);
+ if (value <= C.List_127_2047_65535_1114111[t3]) {
+ t3 = P.FormatException$("Overlong encoding of 0x" + C.JSInt_methods.toRadixString$1(value, 16), codeUnits, i - extraUnits - 1);
+ throw H.wrapException(t3);
+ }
+ if (value > 1114111) {
+ t3 = P.FormatException$("Character outside valid Unicode range: 0x" + C.JSInt_methods.toRadixString$1(value, 16), codeUnits, i - extraUnits - 1);
+ throw H.wrapException(t3);
+ }
+ if (!_this._isFirstCharacter || value !== 65279)
+ t2._contents += H.Primitives_stringFromCharCode(value);
+ _this._isFirstCharacter = false;
+ }
+ for (t3 = i < endIndex; t3;) {
+ oneBytes = P._scanOneByteCharacters(codeUnits, i, endIndex);
+ if (oneBytes > 0) {
+ _this._isFirstCharacter = false;
+ i0 = i + oneBytes;
+ H.assertHelper(i0 <= endIndex);
+ t2._contents += P.String_String$fromCharCodes(codeUnits, i, i0);
+ if (i0 === endIndex)
+ break;
+ } else
+ i0 = i;
+ i1 = i0 + 1;
+ unit = t1.$index(codeUnits, i0);
+ if (typeof unit !== "number")
+ return unit.$lt();
+ if (unit < 0) {
+ t4 = P.FormatException$("Negative UTF-8 code unit: -0x" + C.JSInt_methods.toRadixString$1(-unit, 16), codeUnits, i1 - 1);
+ throw H.wrapException(t4);
+ } else {
+ H.assertHelper(unit > 127);
+ if ((unit & 224) === 192) {
+ value = unit & 31;
+ expectedUnits = 1;
+ extraUnits = 1;
+ continue $label0$0;
+ }
+ if ((unit & 240) === 224) {
+ value = unit & 15;
+ expectedUnits = 2;
+ extraUnits = 2;
+ continue $label0$0;
+ }
+ if ((unit & 248) === 240 && unit < 245) {
+ value = unit & 7;
+ expectedUnits = 3;
+ extraUnits = 3;
+ continue $label0$0;
+ }
+ t4 = P.FormatException$(_s21_ + C.JSInt_methods.toRadixString$1(unit, 16), codeUnits, i1 - 1);
+ throw H.wrapException(t4);
+ }
+ }
+ break $label0$0;
+ }
+ if (expectedUnits > 0) {
+ _this._convert$_value = value;
+ _this._expectedUnits = expectedUnits;
+ _this._extraUnits = extraUnits;
+ }
+ }
+ };
+ P.bool.prototype = {};
+ P.DateTime.prototype = {
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof P.DateTime && this._value === other._value && true;
+ },
+ get$hashCode: function(_) {
+ var t1 = this._value;
+ return (t1 ^ C.JSInt_methods._shrOtherPositive$1(t1, 30)) & 1073741823;
+ },
+ toString$0: function(_) {
+ var _this = this,
+ y = P.DateTime__fourDigits(H.Primitives_getYear(_this)),
+ m = P.DateTime__twoDigits(H.Primitives_getMonth(_this)),
+ d = P.DateTime__twoDigits(H.Primitives_getDay(_this)),
+ h = P.DateTime__twoDigits(H.Primitives_getHours(_this)),
+ min = P.DateTime__twoDigits(H.Primitives_getMinutes(_this)),
+ sec = P.DateTime__twoDigits(H.Primitives_getSeconds(_this)),
+ ms = P.DateTime__threeDigits(H.Primitives_getMilliseconds(_this)),
+ t1 = y + "-" + m + "-" + d + " " + h + ":" + min + ":" + sec + "." + ms + "Z";
+ return t1;
+ }
+ };
+ P.double.prototype = {};
+ P.Duration.prototype = {
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof P.Duration && this._duration === other._duration;
+ },
+ get$hashCode: function(_) {
+ return C.JSInt_methods.get$hashCode(this._duration);
+ },
+ toString$0: function(_) {
+ var twoDigitMinutes, twoDigitSeconds, sixDigitUs,
+ t1 = new P.Duration_toString_twoDigits(),
+ t2 = this._duration;
+ if (t2 < 0)
+ return "-" + new P.Duration(0 - t2).toString$0(0);
+ twoDigitMinutes = t1.call$1(C.JSInt_methods._tdivFast$1(t2, 60000000) % 60);
+ twoDigitSeconds = t1.call$1(C.JSInt_methods._tdivFast$1(t2, 1000000) % 60);
+ sixDigitUs = new P.Duration_toString_sixDigits().call$1(t2 % 1000000);
+ return "" + C.JSInt_methods._tdivFast$1(t2, 3600000000) + ":" + H.S(twoDigitMinutes) + ":" + H.S(twoDigitSeconds) + "." + H.S(sixDigitUs);
+ }
+ };
+ P.Duration_toString_sixDigits.prototype = {
+ call$1: function(n) {
+ if (n >= 100000)
+ return "" + n;
+ if (n >= 10000)
+ return "0" + n;
+ if (n >= 1000)
+ return "00" + n;
+ if (n >= 100)
+ return "000" + n;
+ if (n >= 10)
+ return "0000" + n;
+ return "00000" + n;
+ },
+ $signature: 25
+ };
+ P.Duration_toString_twoDigits.prototype = {
+ call$1: function(n) {
+ if (n >= 10)
+ return "" + n;
+ return "0" + n;
+ },
+ $signature: 25
+ };
+ P.Error.prototype = {};
+ P.AssertionError.prototype = {
+ toString$0: function(_) {
+ var t1 = this.message;
+ if (t1 != null)
+ return "Assertion failed: " + P.Error_safeToString(t1);
+ return "Assertion failed";
+ },
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ P.NullThrownError.prototype = {
+ toString$0: function(_) {
+ return "Throw of null.";
+ }
+ };
+ P.ArgumentError.prototype = {
+ get$_errorName: function() {
+ return "Invalid argument" + (!this._hasValue ? "(s)" : "");
+ },
+ get$_errorExplanation: function() {
+ return "";
+ },
+ toString$0: function(_) {
+ var message, prefix, explanation, errorValue, _this = this,
+ t1 = _this.name,
+ nameString = t1 != null ? " (" + t1 + ")" : "";
+ t1 = _this.message;
+ message = t1 == null ? "" : ": " + H.S(t1);
+ prefix = _this.get$_errorName() + nameString + message;
+ if (!_this._hasValue)
+ return prefix;
+ explanation = _this.get$_errorExplanation();
+ errorValue = P.Error_safeToString(_this.invalidValue);
+ return prefix + explanation + ": " + errorValue;
+ },
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ P.RangeError.prototype = {
+ get$_errorName: function() {
+ return "RangeError";
+ },
+ get$_errorExplanation: function() {
+ var t1, explanation, t2, _this = this;
+ H.assertHelper(_this._hasValue);
+ t1 = _this.start;
+ if (t1 == null) {
+ t1 = _this.end;
+ explanation = t1 != null ? ": Not less than or equal to " + H.S(t1) : "";
+ } else {
+ t2 = _this.end;
+ if (t2 == null)
+ explanation = ": Not greater than or equal to " + H.S(t1);
+ else if (t2 > t1)
+ explanation = ": Not in range " + H.S(t1) + ".." + H.S(t2) + ", inclusive";
+ else
+ explanation = t2 < t1 ? ": Valid value range is empty" : ": Only valid value is " + H.S(t1);
+ }
+ return explanation;
+ }
+ };
+ P.IndexError.prototype = {
+ get$_errorName: function() {
+ return "RangeError";
+ },
+ get$_errorExplanation: function() {
+ var invalidValue, t1;
+ H.assertHelper(this._hasValue);
+ invalidValue = H._checkIntNullable(this.invalidValue);
+ if (typeof invalidValue !== "number")
+ return invalidValue.$lt();
+ if (invalidValue < 0)
+ return ": index must not be negative";
+ t1 = this.length;
+ if (t1 === 0)
+ return ": no indices are valid";
+ return ": index should be less than " + H.S(t1);
+ },
+ get$length: function(receiver) {
+ return this.length;
+ }
+ };
+ P.UnsupportedError.prototype = {
+ toString$0: function(_) {
+ return "Unsupported operation: " + this.message;
+ },
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ P.UnimplementedError.prototype = {
+ toString$0: function(_) {
+ var t1 = this.message;
+ return t1 != null ? "UnimplementedError: " + t1 : "UnimplementedError";
+ },
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ P.StateError.prototype = {
+ toString$0: function(_) {
+ return "Bad state: " + this.message;
+ },
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ P.ConcurrentModificationError.prototype = {
+ toString$0: function(_) {
+ var t1 = this.modifiedObject;
+ if (t1 == null)
+ return "Concurrent modification during iteration.";
+ return "Concurrent modification during iteration: " + P.Error_safeToString(t1) + ".";
+ }
+ };
+ P.OutOfMemoryError.prototype = {
+ toString$0: function(_) {
+ return "Out of Memory";
+ },
+ $isError: 1
+ };
+ P.StackOverflowError.prototype = {
+ toString$0: function(_) {
+ return "Stack Overflow";
+ },
+ $isError: 1
+ };
+ P.CyclicInitializationError.prototype = {
+ toString$0: function(_) {
+ var t1 = this.variableName;
+ return t1 == null ? "Reading static variable during its initialization" : "Reading static variable '" + t1 + "' during its initialization";
+ }
+ };
+ P._Exception.prototype = {
+ toString$0: function(_) {
+ return "Exception: " + this.message;
+ },
+ $isException: 1,
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ P.FormatException.prototype = {
+ toString$0: function(_) {
+ var source, lineNum, lineStart, previousCharWasCR, i, char, lineEnd, end, start, prefix, postfix, slice,
+ t1 = this.message,
+ report = t1 != null && "" !== t1 ? "FormatException: " + H.S(t1) : "FormatException",
+ offset = this.offset,
+ objectSource = this.source;
+ if (typeof objectSource == "string") {
+ if (offset != null)
+ t1 = offset < 0 || offset > objectSource.length;
+ else
+ t1 = false;
+ if (t1)
+ offset = null;
+ if (offset == null) {
+ source = objectSource.length > 78 ? C.JSString_methods.substring$2(objectSource, 0, 75) + "..." : objectSource;
+ return report + "\n" + source;
+ }
+ for (lineNum = 1, lineStart = 0, previousCharWasCR = false, i = 0; i < offset; ++i) {
+ char = C.JSString_methods._codeUnitAt$1(objectSource, i);
+ if (char === 10) {
+ if (lineStart !== i || !previousCharWasCR)
+ ++lineNum;
+ lineStart = i + 1;
+ previousCharWasCR = false;
+ } else if (char === 13) {
+ ++lineNum;
+ lineStart = i + 1;
+ previousCharWasCR = true;
+ }
+ }
+ report = lineNum > 1 ? report + (" (at line " + lineNum + ", character " + (offset - lineStart + 1) + ")\n") : report + (" (at character " + (offset + 1) + ")\n");
+ lineEnd = objectSource.length;
+ for (i = offset; i < lineEnd; ++i) {
+ char = C.JSString_methods.codeUnitAt$1(objectSource, i);
+ if (char === 10 || char === 13) {
+ lineEnd = i;
+ break;
+ }
+ }
+ if (lineEnd - lineStart > 78)
+ if (offset - lineStart < 75) {
+ end = lineStart + 75;
+ start = lineStart;
+ prefix = "";
+ postfix = "...";
+ } else {
+ if (lineEnd - offset < 75) {
+ start = lineEnd - 75;
+ end = lineEnd;
+ postfix = "";
+ } else {
+ start = offset - 36;
+ end = offset + 36;
+ postfix = "...";
+ }
+ prefix = "...";
+ }
+ else {
+ end = lineEnd;
+ start = lineStart;
+ prefix = "";
+ postfix = "";
+ }
+ slice = C.JSString_methods.substring$2(objectSource, start, end);
+ return report + prefix + slice + postfix + "\n" + C.JSString_methods.$mul(" ", offset - start + prefix.length) + "^\n";
+ } else
+ return offset != null ? report + (" (at offset " + H.S(offset) + ")") : report;
+ },
+ $isException: 1,
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ P.Expando.prototype = {
+ $index: function(_, object) {
+ var t2, values,
+ t1 = this._jsWeakMapOrKey;
+ if (typeof t1 != "string") {
+ if (object != null)
+ t2 = typeof object == "number" || typeof object == "string";
+ else
+ t2 = true;
+ if (t2)
+ H.throwExpression(P.ArgumentError$value(object, "Expandos are not allowed on strings, numbers, booleans or null", null));
+ return t1.get(object);
+ }
+ values = H.Primitives_getProperty(object, "expando$values");
+ t1 = values == null ? null : H.Primitives_getProperty(values, t1);
+ return this.$ti._precomputed1._check(t1);
+ },
+ $indexSet: function(_, object, value) {
+ var t1, values,
+ _s14_ = "expando$values";
+ this.$ti._precomputed1._check(value);
+ t1 = this._jsWeakMapOrKey;
+ if (typeof t1 != "string")
+ t1.set(object, value);
+ else {
+ values = H.Primitives_getProperty(object, _s14_);
+ if (values == null) {
+ values = new P.Object();
+ H.Primitives_setProperty(object, _s14_, values);
+ }
+ H.Primitives_setProperty(values, t1, value);
+ }
+ },
+ toString$0: function(_) {
+ return "Expando:" + this.name;
+ }
+ };
+ P.Function.prototype = {};
+ P.int.prototype = {};
+ P.Iterable.prototype = {
+ map$1$1: function(_, f, $T) {
+ var t1 = H._instanceType(this);
+ return H.MappedIterable_MappedIterable(this, t1._bind$1($T)._eval$1("1(Iterable.E)")._check(f), t1._eval$1("Iterable.E"), $T);
+ },
+ where$1: function(_, test) {
+ var t1 = H._instanceType(this);
+ return new H.WhereIterable(this, t1._eval$1("bool(Iterable.E)")._check(test), t1._eval$1("WhereIterable<Iterable.E>"));
+ },
+ contains$1: function(_, element) {
+ var t1;
+ for (t1 = this.get$iterator(this); t1.moveNext$0();)
+ if (J.$eq$(t1.get$current(), element))
+ return true;
+ return false;
+ },
+ join$1: function(_, separator) {
+ var t1,
+ iterator = this.get$iterator(this);
+ if (!iterator.moveNext$0())
+ return "";
+ if (separator === "") {
+ t1 = "";
+ do
+ t1 += H.S(iterator.get$current());
+ while (iterator.moveNext$0());
+ } else {
+ t1 = H.S(iterator.get$current());
+ for (; iterator.moveNext$0();)
+ t1 = t1 + separator + H.S(iterator.get$current());
+ }
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ join$0: function($receiver) {
+ return this.join$1($receiver, "");
+ },
+ toList$1$growable: function(_, growable) {
+ return P.List_List$from(this, true, H._instanceType(this)._eval$1("Iterable.E"));
+ },
+ toList$0: function($receiver) {
+ return this.toList$1$growable($receiver, true);
+ },
+ toSet$0: function(_) {
+ return P.LinkedHashSet_LinkedHashSet$from(this, H._instanceType(this)._eval$1("Iterable.E"));
+ },
+ get$length: function(_) {
+ var it, count;
+ H.assertHelper(!type$.EfficientLengthIterable_dynamic._is(this));
+ it = this.get$iterator(this);
+ for (count = 0; it.moveNext$0();)
+ ++count;
+ return count;
+ },
+ get$isEmpty: function(_) {
+ return !this.get$iterator(this).moveNext$0();
+ },
+ skipWhile$1: function(_, test) {
+ var t1 = H._instanceType(this);
+ return new H.SkipWhileIterable(this, t1._eval$1("bool(Iterable.E)")._check(test), t1._eval$1("SkipWhileIterable<Iterable.E>"));
+ },
+ get$first: function(_) {
+ var it = this.get$iterator(this);
+ if (!it.moveNext$0())
+ throw H.wrapException(H.IterableElementError_noElement());
+ return it.get$current();
+ },
+ get$last: function(_) {
+ var result,
+ it = this.get$iterator(this);
+ if (!it.moveNext$0())
+ throw H.wrapException(H.IterableElementError_noElement());
+ do
+ result = it.get$current();
+ while (it.moveNext$0());
+ return result;
+ },
+ elementAt$1: function(_, index) {
+ var t1, elementIndex, element;
+ P.RangeError_checkNotNegative(index, "index");
+ for (t1 = this.get$iterator(this), elementIndex = 0; t1.moveNext$0();) {
+ element = t1.get$current();
+ if (index === elementIndex)
+ return element;
+ ++elementIndex;
+ }
+ throw H.wrapException(P.IndexError$(index, this, "index", null, elementIndex));
+ },
+ toString$0: function(_) {
+ return P.IterableBase_iterableToShortString(this, "(", ")");
+ }
+ };
+ P.Iterator.prototype = {};
+ P.List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1};
+ P.Map.prototype = {};
+ P.MapEntry.prototype = {
+ toString$0: function(_) {
+ return "MapEntry(" + H.S(this.key) + ": " + H.S(this.value) + ")";
+ }
+ };
+ P.Null.prototype = {
+ get$hashCode: function(_) {
+ return P.Object.prototype.get$hashCode.call(this, this);
+ },
+ toString$0: function(_) {
+ return "null";
+ }
+ };
+ P.num.prototype = {};
+ P.Object.prototype = {constructor: P.Object, $isObject: 1,
+ $eq: function(_, other) {
+ return this === other;
+ },
+ get$hashCode: function(_) {
+ return H.Primitives_objectHashCode(this);
+ },
+ toString$0: function(_) {
+ return "Instance of '" + H.S(H.Primitives_objectTypeName(this)) + "'";
+ },
+ get$runtimeType: function(_) {
+ return H.getRuntimeType(this);
+ },
+ toString: function() {
+ return this.toString$0(this);
+ }
+ };
+ P.Pattern.prototype = {};
+ P.Match.prototype = {};
+ P.RegExpMatch.prototype = {$isMatch: 1};
+ P.Set.prototype = {};
+ P.StackTrace.prototype = {};
+ P._StringStackTrace.prototype = {
+ toString$0: function(_) {
+ return this._stackTrace;
+ },
+ $isStackTrace: 1
+ };
+ P.Stopwatch.prototype = {
+ get$elapsedMicroseconds: function() {
+ var t2, ticks,
+ t1 = this._stop;
+ if (t1 == null)
+ t1 = H._checkIntNullable($.Primitives_timerTicks.call$0());
+ t2 = this._core$_start;
+ if (typeof t1 !== "number")
+ return t1.$sub();
+ ticks = t1 - t2;
+ t1 = $.Stopwatch__frequency;
+ if (t1 === 1000000)
+ return ticks;
+ H.assertHelper(t1 === 1000);
+ return ticks * 1000;
+ }
+ };
+ P.String.prototype = {$isPattern: 1};
+ P.Runes.prototype = {
+ get$iterator: function(_) {
+ return new P.RuneIterator(this.string);
+ },
+ get$last: function(_) {
+ var code, previousCode,
+ t1 = this.string,
+ t2 = t1.length;
+ if (t2 === 0)
+ throw H.wrapException(P.StateError$("No elements."));
+ code = C.JSString_methods.codeUnitAt$1(t1, t2 - 1);
+ if ((code & 64512) === 56320 && t2 > 1) {
+ previousCode = C.JSString_methods.codeUnitAt$1(t1, t2 - 2);
+ if ((previousCode & 64512) === 55296)
+ return P._combineSurrogatePair(previousCode, code);
+ }
+ return code;
+ }
+ };
+ P.RuneIterator.prototype = {
+ get$current: function() {
+ return this._currentCodePoint;
+ },
+ moveNext$0: function() {
+ var codeUnit, nextPosition, nextCodeUnit, _this = this,
+ t1 = _this._core$_position = _this._nextPosition,
+ t2 = _this.string,
+ t3 = t2.length;
+ if (t1 === t3) {
+ _this._currentCodePoint = null;
+ return false;
+ }
+ codeUnit = C.JSString_methods._codeUnitAt$1(t2, t1);
+ nextPosition = t1 + 1;
+ if ((codeUnit & 64512) === 55296 && nextPosition < t3) {
+ nextCodeUnit = C.JSString_methods._codeUnitAt$1(t2, nextPosition);
+ if ((nextCodeUnit & 64512) === 56320) {
+ _this._nextPosition = nextPosition + 1;
+ _this._currentCodePoint = P._combineSurrogatePair(codeUnit, nextCodeUnit);
+ return true;
+ }
+ }
+ _this._nextPosition = nextPosition;
+ _this._currentCodePoint = codeUnit;
+ return true;
+ },
+ $isIterator: 1
+ };
+ P.StringBuffer.prototype = {
+ get$length: function(_) {
+ return this._contents.length;
+ },
+ toString$0: function(_) {
+ var t1 = this._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ $isStringSink: 1
+ };
+ P.Uri.prototype = {};
+ P.Uri__parseIPv4Address_error.prototype = {
+ call$2: function(msg, position) {
+ throw H.wrapException(P.FormatException$("Illegal IPv4 address, " + msg, this.host, position));
+ },
+ $signature: 68
+ };
+ P.Uri_parseIPv6Address_error.prototype = {
+ call$2: function(msg, position) {
+ throw H.wrapException(P.FormatException$("Illegal IPv6 address, " + msg, this.host, position));
+ },
+ call$1: function(msg) {
+ return this.call$2(msg, null);
+ },
+ $signature: 67
+ };
+ P.Uri_parseIPv6Address_parseHex.prototype = {
+ call$2: function(start, end) {
+ var value;
+ if (end - start > 4)
+ this.error.call$2("an IPv6 part can only contain a maximum of 4 hex digits", start);
+ value = P.int_parse(C.JSString_methods.substring$2(this.host, start, end), null, 16);
+ if (typeof value !== "number")
+ return value.$lt();
+ if (value < 0 || value > 65535)
+ this.error.call$2("each part must be in the range of `0x0..0xFFFF`", start);
+ return value;
+ },
+ $signature: 65
+ };
+ P._Uri.prototype = {
+ get$userInfo: function() {
+ return this._userInfo;
+ },
+ get$host: function(_) {
+ var t1 = this._host;
+ if (t1 == null)
+ return "";
+ if (C.JSString_methods.startsWith$1(t1, "["))
+ return C.JSString_methods.substring$2(t1, 1, t1.length - 1);
+ return t1;
+ },
+ get$port: function(_) {
+ var t1 = this._port;
+ if (t1 == null)
+ return P._Uri__defaultPort(this.scheme);
+ return t1;
+ },
+ get$query: function() {
+ var t1 = this._query;
+ return t1 == null ? "" : t1;
+ },
+ get$fragment: function() {
+ var t1 = this._fragment;
+ return t1 == null ? "" : t1;
+ },
+ replace$2$path$pathSegments: function(_, path, pathSegments) {
+ var scheme, isFile, userInfo, port, host, hasAuthority, t1, _this = this;
+ type$.Iterable_String._check(pathSegments);
+ type$.Map_String_dynamic._check(null);
+ scheme = _this.scheme;
+ isFile = scheme === "file";
+ userInfo = _this._userInfo;
+ port = _this._port;
+ host = _this._host;
+ if (!(host != null))
+ host = userInfo.length !== 0 || port != null || isFile ? "" : null;
+ hasAuthority = host != null;
+ t1 = path == null;
+ if (!t1 || pathSegments != null)
+ path = P._Uri__makePath(path, 0, t1 ? 0 : path.length, pathSegments, scheme, hasAuthority);
+ else {
+ path = _this.path;
+ if (!isFile)
+ t1 = hasAuthority && path.length !== 0;
+ else
+ t1 = true;
+ if (t1 && !C.JSString_methods.startsWith$1(path, "/"))
+ path = "/" + path;
+ }
+ return new P._Uri(scheme, userInfo, host, port, path, _this._query, _this._fragment);
+ },
+ replace$1$path: function($receiver, path) {
+ return this.replace$2$path$pathSegments($receiver, path, null);
+ },
+ replace$1$pathSegments: function($receiver, pathSegments) {
+ return this.replace$2$path$pathSegments($receiver, null, pathSegments);
+ },
+ get$pathSegments: function() {
+ var pathToSplit,
+ result = this._pathSegments;
+ if (result != null)
+ return result;
+ pathToSplit = this.path;
+ if (pathToSplit.length !== 0 && C.JSString_methods._codeUnitAt$1(pathToSplit, 0) === 47)
+ pathToSplit = C.JSString_methods.substring$1(pathToSplit, 1);
+ result = pathToSplit === "" ? C.List_empty : P.List_List$unmodifiable(new H.MappedListIterable(H.setRuntimeTypeInfo(pathToSplit.split("/"), type$.JSArray_String), type$.dynamic_Function_String._check(P.core_Uri_decodeComponent$closure()), type$.MappedListIterable_String_dynamic), type$.String);
+ this.set$_pathSegments(result);
+ return result;
+ },
+ _mergePaths$2: function(base, reference) {
+ var backCount, refStart, baseEnd, newEnd, delta, t1;
+ for (backCount = 0, refStart = 0; C.JSString_methods.startsWith$2(reference, "../", refStart);) {
+ refStart += 3;
+ ++backCount;
+ }
+ baseEnd = C.JSString_methods.lastIndexOf$1(base, "/");
+ while (true) {
+ if (!(baseEnd > 0 && backCount > 0))
+ break;
+ newEnd = C.JSString_methods.lastIndexOf$2(base, "/", baseEnd - 1);
+ if (newEnd < 0)
+ break;
+ delta = baseEnd - newEnd;
+ t1 = delta !== 2;
+ if (!t1 || delta === 3)
+ if (C.JSString_methods.codeUnitAt$1(base, newEnd + 1) === 46)
+ t1 = !t1 || C.JSString_methods.codeUnitAt$1(base, newEnd + 2) === 46;
+ else
+ t1 = false;
+ else
+ t1 = false;
+ if (t1)
+ break;
+ --backCount;
+ baseEnd = newEnd;
+ }
+ return C.JSString_methods.replaceRange$3(base, baseEnd + 1, null, C.JSString_methods.substring$1(reference, refStart - 3 * backCount));
+ },
+ resolve$1: function(reference) {
+ return this.resolveUri$1(P.Uri_parse(reference));
+ },
+ resolveUri$1: function(reference) {
+ var targetScheme, targetUserInfo, targetHost, targetPort, targetPath, targetQuery, t1, mergedPath, t2, _this = this, _null = null;
+ if (reference.get$scheme().length !== 0) {
+ targetScheme = reference.get$scheme();
+ if (reference.get$hasAuthority()) {
+ targetUserInfo = reference.get$userInfo();
+ targetHost = reference.get$host(reference);
+ targetPort = reference.get$hasPort() ? reference.get$port(reference) : _null;
+ } else {
+ targetPort = _null;
+ targetHost = targetPort;
+ targetUserInfo = "";
+ }
+ targetPath = P._Uri__removeDotSegments(reference.get$path(reference));
+ targetQuery = reference.get$hasQuery() ? reference.get$query() : _null;
+ } else {
+ targetScheme = _this.scheme;
+ if (reference.get$hasAuthority()) {
+ targetUserInfo = reference.get$userInfo();
+ targetHost = reference.get$host(reference);
+ targetPort = P._Uri__makePort(reference.get$hasPort() ? reference.get$port(reference) : _null, targetScheme);
+ targetPath = P._Uri__removeDotSegments(reference.get$path(reference));
+ targetQuery = reference.get$hasQuery() ? reference.get$query() : _null;
+ } else {
+ targetUserInfo = _this._userInfo;
+ targetHost = _this._host;
+ targetPort = _this._port;
+ if (reference.get$path(reference) === "") {
+ targetPath = _this.path;
+ targetQuery = reference.get$hasQuery() ? reference.get$query() : _this._query;
+ } else {
+ if (reference.get$hasAbsolutePath())
+ targetPath = P._Uri__removeDotSegments(reference.get$path(reference));
+ else {
+ t1 = _this.path;
+ if (t1.length === 0)
+ if (targetHost == null)
+ targetPath = targetScheme.length === 0 ? reference.get$path(reference) : P._Uri__removeDotSegments(reference.get$path(reference));
+ else
+ targetPath = P._Uri__removeDotSegments("/" + reference.get$path(reference));
+ else {
+ mergedPath = _this._mergePaths$2(t1, reference.get$path(reference));
+ t2 = targetScheme.length === 0;
+ if (!t2 || targetHost != null || C.JSString_methods.startsWith$1(t1, "/"))
+ targetPath = P._Uri__removeDotSegments(mergedPath);
+ else
+ targetPath = P._Uri__normalizeRelativePath(mergedPath, !t2 || targetHost != null);
+ }
+ }
+ targetQuery = reference.get$hasQuery() ? reference.get$query() : _null;
+ }
+ }
+ }
+ return new P._Uri(targetScheme, targetUserInfo, targetHost, targetPort, targetPath, targetQuery, reference.get$hasFragment() ? reference.get$fragment() : _null);
+ },
+ get$hasAuthority: function() {
+ return this._host != null;
+ },
+ get$hasPort: function() {
+ return this._port != null;
+ },
+ get$hasQuery: function() {
+ return this._query != null;
+ },
+ get$hasFragment: function() {
+ return this._fragment != null;
+ },
+ get$hasAbsolutePath: function() {
+ return C.JSString_methods.startsWith$1(this.path, "/");
+ },
+ toFilePath$0: function() {
+ var windows, pathSegments, _this = this,
+ t1 = _this.scheme;
+ if (t1 !== "" && t1 !== "file")
+ throw H.wrapException(P.UnsupportedError$("Cannot extract a file path from a " + H.S(t1) + " URI"));
+ t1 = _this._query;
+ if ((t1 == null ? "" : t1) !== "")
+ throw H.wrapException(P.UnsupportedError$("Cannot extract a file path from a URI with a query component"));
+ t1 = _this._fragment;
+ if ((t1 == null ? "" : t1) !== "")
+ throw H.wrapException(P.UnsupportedError$("Cannot extract a file path from a URI with a fragment component"));
+ windows = $.$get$_Uri__isWindowsCached();
+ if (H.boolConversionCheck(windows))
+ t1 = P._Uri__toWindowsFilePath(_this);
+ else {
+ if (_this._host != null && _this.get$host(_this) !== "")
+ H.throwExpression(P.UnsupportedError$("Cannot extract a non-Windows file path from a file URI with an authority"));
+ pathSegments = _this.get$pathSegments();
+ P._Uri__checkNonWindowsPathReservedCharacters(pathSegments, false);
+ t1 = P.StringBuffer__writeAll(C.JSString_methods.startsWith$1(_this.path, "/") ? "/" : "", pathSegments, "/");
+ t1 = t1.charCodeAt(0) == 0 ? t1 : t1;
+ }
+ return t1;
+ },
+ toString$0: function(_) {
+ var t2, t3, t4, _this = this,
+ t1 = _this._text;
+ if (t1 == null) {
+ t1 = _this.scheme;
+ t2 = t1.length !== 0 ? t1 + ":" : "";
+ t3 = _this._host;
+ t4 = t3 == null;
+ if (!t4 || t1 === "file") {
+ t1 = t2 + "//";
+ t2 = _this._userInfo;
+ if (t2.length !== 0)
+ t1 = t1 + t2 + "@";
+ if (!t4)
+ t1 += t3;
+ t2 = _this._port;
+ if (t2 != null)
+ t1 = t1 + ":" + H.S(t2);
+ } else
+ t1 = t2;
+ t1 += _this.path;
+ t2 = _this._query;
+ if (t2 != null)
+ t1 = t1 + "?" + t2;
+ t2 = _this._fragment;
+ if (t2 != null)
+ t1 = t1 + "#" + t2;
+ t1 = _this._text = t1.charCodeAt(0) == 0 ? t1 : t1;
+ }
+ return t1;
+ },
+ $eq: function(_, other) {
+ var t1, t2, _this = this;
+ if (other == null)
+ return false;
+ if (_this === other)
+ return true;
+ if (type$.Uri._is(other))
+ if (_this.scheme == other.get$scheme())
+ if (_this._host != null === other.get$hasAuthority())
+ if (_this._userInfo == other.get$userInfo())
+ if (_this.get$host(_this) == other.get$host(other))
+ if (_this.get$port(_this) == other.get$port(other))
+ if (_this.path === other.get$path(other)) {
+ t1 = _this._query;
+ t2 = t1 == null;
+ if (!t2 === other.get$hasQuery()) {
+ if (t2)
+ t1 = "";
+ if (t1 === other.get$query()) {
+ t1 = _this._fragment;
+ t2 = t1 == null;
+ if (!t2 === other.get$hasFragment()) {
+ if (t2)
+ t1 = "";
+ t1 = t1 === other.get$fragment();
+ } else
+ t1 = false;
+ } else
+ t1 = false;
+ } else
+ t1 = false;
+ } else
+ t1 = false;
+ else
+ t1 = false;
+ else
+ t1 = false;
+ else
+ t1 = false;
+ else
+ t1 = false;
+ else
+ t1 = false;
+ else
+ t1 = false;
+ return t1;
+ },
+ get$hashCode: function(_) {
+ var t1 = this._hashCodeCache;
+ return t1 == null ? this._hashCodeCache = C.JSString_methods.get$hashCode(this.toString$0(0)) : t1;
+ },
+ set$_pathSegments: function(_pathSegments) {
+ this._pathSegments = type$.List_String._check(_pathSegments);
+ },
+ $isUri: 1,
+ get$scheme: function() {
+ return this.scheme;
+ },
+ get$path: function(receiver) {
+ return this.path;
+ }
+ };
+ P._Uri__Uri$notSimple_closure.prototype = {
+ call$1: function(_) {
+ throw H.wrapException(P.FormatException$("Invalid port", this.uri, this.portStart + 1));
+ },
+ $signature: 30
+ };
+ P._Uri__checkNonWindowsPathReservedCharacters_closure.prototype = {
+ call$1: function(segment) {
+ var _s23_ = "Illegal path character ";
+ H._checkStringNullable(segment);
+ if (J.contains$1$asx(segment, "/"))
+ if (this.argumentError)
+ throw H.wrapException(P.ArgumentError$(_s23_ + segment));
+ else
+ throw H.wrapException(P.UnsupportedError$(_s23_ + segment));
+ },
+ $signature: 30
+ };
+ P._Uri__makePath_closure.prototype = {
+ call$1: function(s) {
+ return P._Uri__uriEncode(C.List_qg40, H._checkStringNullable(s), C.C_Utf8Codec, false);
+ },
+ $signature: 7
+ };
+ P.UriData.prototype = {
+ get$uri: function() {
+ var t2, queryIndex, end, query, _this = this, _null = null,
+ t1 = _this._uriCache;
+ if (t1 != null)
+ return t1;
+ t1 = _this._separatorIndices;
+ if (0 >= t1.length)
+ return H.ioore(t1, 0);
+ t2 = _this._text;
+ t1 = t1[0] + 1;
+ queryIndex = C.JSString_methods.indexOf$2(t2, "?", t1);
+ end = t2.length;
+ if (queryIndex >= 0) {
+ query = P._Uri__normalizeOrSubstring(t2, queryIndex + 1, end, C.List_CVk, false);
+ end = queryIndex;
+ } else
+ query = _null;
+ return _this._uriCache = new P._DataUri("data", _null, _null, _null, P._Uri__normalizeOrSubstring(t2, t1, end, C.List_qg4, false), query, _null);
+ },
+ toString$0: function(_) {
+ var t2,
+ t1 = this._separatorIndices;
+ if (0 >= t1.length)
+ return H.ioore(t1, 0);
+ t2 = this._text;
+ return t1[0] === -1 ? "data:" + t2 : t2;
+ }
+ };
+ P._createTables_closure.prototype = {
+ call$1: function(_) {
+ return new Uint8Array(96);
+ },
+ $signature: 64
+ };
+ P._createTables_build.prototype = {
+ call$2: function(state, defaultTransition) {
+ var t1 = this.tables;
+ if (state >= t1.length)
+ return H.ioore(t1, state);
+ t1 = t1[state];
+ J.fillRange$3$ax(t1, 0, 96, defaultTransition);
+ return t1;
+ },
+ $signature: 62
+ };
+ P._createTables_setChars.prototype = {
+ call$3: function(target, chars, transition) {
+ var t1, t2, i, t3;
+ for (t1 = chars.length, t2 = target.length, i = 0; i < t1; ++i) {
+ t3 = C.JSString_methods._codeUnitAt$1(chars, i) ^ 96;
+ if (t3 >= t2)
+ return H.ioore(target, t3);
+ target[t3] = transition;
+ }
+ },
+ $signature: 41
+ };
+ P._createTables_setRange.prototype = {
+ call$3: function(target, range, transition) {
+ var i, n, t1, t2;
+ for (i = C.JSString_methods._codeUnitAt$1(range, 0), n = C.JSString_methods._codeUnitAt$1(range, 1), t1 = target.length; i <= n; ++i) {
+ t2 = (i ^ 96) >>> 0;
+ if (t2 >= t1)
+ return H.ioore(target, t2);
+ target[t2] = transition;
+ }
+ },
+ $signature: 41
+ };
+ P._SimpleUri.prototype = {
+ get$hasAuthority: function() {
+ return this._hostStart > 0;
+ },
+ get$hasPort: function() {
+ return this._hostStart > 0 && this._portStart + 1 < this._pathStart;
+ },
+ get$hasQuery: function() {
+ return this._queryStart < this._fragmentStart;
+ },
+ get$hasFragment: function() {
+ return this._fragmentStart < this._uri.length;
+ },
+ get$_isFile: function() {
+ return this._schemeEnd === 4 && C.JSString_methods.startsWith$1(this._uri, "file");
+ },
+ get$_isHttp: function() {
+ return this._schemeEnd === 4 && C.JSString_methods.startsWith$1(this._uri, "http");
+ },
+ get$_isHttps: function() {
+ return this._schemeEnd === 5 && C.JSString_methods.startsWith$1(this._uri, "https");
+ },
+ get$hasAbsolutePath: function() {
+ return C.JSString_methods.startsWith$2(this._uri, "/", this._pathStart);
+ },
+ get$scheme: function() {
+ var t2, _this = this,
+ _s7_ = "package",
+ t1 = _this._schemeEnd;
+ if (t1 <= 0)
+ return "";
+ t2 = _this._schemeCache;
+ if (t2 != null)
+ return t2;
+ if (_this.get$_isHttp())
+ t1 = _this._schemeCache = "http";
+ else if (_this.get$_isHttps()) {
+ _this._schemeCache = "https";
+ t1 = "https";
+ } else if (_this.get$_isFile()) {
+ _this._schemeCache = "file";
+ t1 = "file";
+ } else if (t1 === 7 && C.JSString_methods.startsWith$1(_this._uri, _s7_)) {
+ _this._schemeCache = _s7_;
+ t1 = _s7_;
+ } else {
+ t1 = C.JSString_methods.substring$2(_this._uri, 0, t1);
+ _this._schemeCache = t1;
+ }
+ return t1;
+ },
+ get$userInfo: function() {
+ var t1 = this._hostStart,
+ t2 = this._schemeEnd + 3;
+ return t1 > t2 ? C.JSString_methods.substring$2(this._uri, t2, t1 - 1) : "";
+ },
+ get$host: function(_) {
+ var t1 = this._hostStart;
+ return t1 > 0 ? C.JSString_methods.substring$2(this._uri, t1, this._portStart) : "";
+ },
+ get$port: function(_) {
+ var _this = this;
+ if (_this.get$hasPort())
+ return P.int_parse(C.JSString_methods.substring$2(_this._uri, _this._portStart + 1, _this._pathStart), null, null);
+ if (_this.get$_isHttp())
+ return 80;
+ if (_this.get$_isHttps())
+ return 443;
+ return 0;
+ },
+ get$path: function(_) {
+ return C.JSString_methods.substring$2(this._uri, this._pathStart, this._queryStart);
+ },
+ get$query: function() {
+ var t1 = this._queryStart,
+ t2 = this._fragmentStart;
+ return t1 < t2 ? C.JSString_methods.substring$2(this._uri, t1 + 1, t2) : "";
+ },
+ get$fragment: function() {
+ var t1 = this._fragmentStart,
+ t2 = this._uri;
+ return t1 < t2.length ? C.JSString_methods.substring$1(t2, t1 + 1) : "";
+ },
+ get$pathSegments: function() {
+ var parts, i,
+ start = this._pathStart,
+ end = this._queryStart,
+ t1 = this._uri;
+ if (C.JSString_methods.startsWith$2(t1, "/", start))
+ ++start;
+ if (start === end)
+ return C.List_empty;
+ parts = H.setRuntimeTypeInfo([], type$.JSArray_String);
+ for (i = start; i < end; ++i)
+ if (C.JSString_methods.codeUnitAt$1(t1, i) === 47) {
+ C.JSArray_methods.add$1(parts, C.JSString_methods.substring$2(t1, start, i));
+ start = i + 1;
+ }
+ C.JSArray_methods.add$1(parts, C.JSString_methods.substring$2(t1, start, end));
+ return P.List_List$unmodifiable(parts, type$.String);
+ },
+ _isPort$1: function(port) {
+ var portDigitStart = this._portStart + 1;
+ return portDigitStart + port.length === this._pathStart && C.JSString_methods.startsWith$2(this._uri, port, portDigitStart);
+ },
+ removeFragment$0: function() {
+ var _this = this,
+ t1 = _this._fragmentStart,
+ t2 = _this._uri;
+ if (t1 >= t2.length)
+ return _this;
+ return new P._SimpleUri(C.JSString_methods.substring$2(t2, 0, t1), _this._schemeEnd, _this._hostStart, _this._portStart, _this._pathStart, _this._queryStart, t1, _this._schemeCache);
+ },
+ replace$2$path$pathSegments: function(_, path, pathSegments) {
+ var scheme, isFile, t1, userInfo, port, host, hasAuthority, t2, query, fragment, _this = this, _null = null;
+ type$.Iterable_String._check(pathSegments);
+ type$.Map_String_dynamic._check(null);
+ scheme = _this.get$scheme();
+ isFile = scheme === "file";
+ t1 = _this._hostStart;
+ userInfo = t1 > 0 ? C.JSString_methods.substring$2(_this._uri, _this._schemeEnd + 3, t1) : "";
+ port = _this.get$hasPort() ? _this.get$port(_this) : _null;
+ t1 = _this._hostStart;
+ if (t1 > 0)
+ host = C.JSString_methods.substring$2(_this._uri, t1, _this._portStart);
+ else
+ host = userInfo.length !== 0 || port != null || isFile ? "" : _null;
+ hasAuthority = host != null;
+ t1 = path == null;
+ if (!t1 || pathSegments != null)
+ path = P._Uri__makePath(path, 0, t1 ? 0 : path.length, pathSegments, scheme, hasAuthority);
+ else {
+ path = C.JSString_methods.substring$2(_this._uri, _this._pathStart, _this._queryStart);
+ if (!isFile)
+ t1 = hasAuthority && path.length !== 0;
+ else
+ t1 = true;
+ if (t1 && !C.JSString_methods.startsWith$1(path, "/"))
+ path = "/" + path;
+ }
+ t1 = _this._queryStart;
+ t2 = _this._fragmentStart;
+ query = t1 < t2 ? C.JSString_methods.substring$2(_this._uri, t1 + 1, t2) : _null;
+ t1 = _this._fragmentStart;
+ t2 = _this._uri;
+ fragment = t1 < t2.length ? C.JSString_methods.substring$1(t2, t1 + 1) : _null;
+ return new P._Uri(scheme, userInfo, host, port, path, query, fragment);
+ },
+ replace$1$path: function($receiver, path) {
+ return this.replace$2$path$pathSegments($receiver, path, null);
+ },
+ replace$1$pathSegments: function($receiver, pathSegments) {
+ return this.replace$2$path$pathSegments($receiver, null, pathSegments);
+ },
+ resolve$1: function(reference) {
+ return this.resolveUri$1(P.Uri_parse(reference));
+ },
+ resolveUri$1: function(reference) {
+ if (reference instanceof P._SimpleUri)
+ return this._simpleMerge$2(this, reference);
+ return this._toNonSimple$0().resolveUri$1(reference);
+ },
+ _simpleMerge$2: function(base, ref) {
+ var t2, t3, isSimple, delta, refStart, baseStart, baseEnd, baseUri, baseStart0, backCount, refStart0, insert,
+ t1 = ref._schemeEnd;
+ if (t1 > 0)
+ return ref;
+ t2 = ref._hostStart;
+ if (t2 > 0) {
+ t3 = base._schemeEnd;
+ if (t3 <= 0)
+ return ref;
+ if (base.get$_isFile())
+ isSimple = ref._pathStart !== ref._queryStart;
+ else if (base.get$_isHttp())
+ isSimple = !ref._isPort$1("80");
+ else
+ isSimple = !base.get$_isHttps() || !ref._isPort$1("443");
+ if (isSimple) {
+ delta = t3 + 1;
+ return new P._SimpleUri(C.JSString_methods.substring$2(base._uri, 0, delta) + C.JSString_methods.substring$1(ref._uri, t1 + 1), t3, t2 + delta, ref._portStart + delta, ref._pathStart + delta, ref._queryStart + delta, ref._fragmentStart + delta, base._schemeCache);
+ } else
+ return this._toNonSimple$0().resolveUri$1(ref);
+ }
+ refStart = ref._pathStart;
+ t1 = ref._queryStart;
+ if (refStart === t1) {
+ t2 = ref._fragmentStart;
+ if (t1 < t2) {
+ t3 = base._queryStart;
+ delta = t3 - t1;
+ return new P._SimpleUri(C.JSString_methods.substring$2(base._uri, 0, t3) + C.JSString_methods.substring$1(ref._uri, t1), base._schemeEnd, base._hostStart, base._portStart, base._pathStart, t1 + delta, t2 + delta, base._schemeCache);
+ }
+ t1 = ref._uri;
+ if (t2 < t1.length) {
+ t3 = base._fragmentStart;
+ return new P._SimpleUri(C.JSString_methods.substring$2(base._uri, 0, t3) + C.JSString_methods.substring$1(t1, t2), base._schemeEnd, base._hostStart, base._portStart, base._pathStart, base._queryStart, t2 + (t3 - t2), base._schemeCache);
+ }
+ return base.removeFragment$0();
+ }
+ t2 = ref._uri;
+ if (C.JSString_methods.startsWith$2(t2, "/", refStart)) {
+ t3 = base._pathStart;
+ delta = t3 - refStart;
+ return new P._SimpleUri(C.JSString_methods.substring$2(base._uri, 0, t3) + C.JSString_methods.substring$1(t2, refStart), base._schemeEnd, base._hostStart, base._portStart, t3, t1 + delta, ref._fragmentStart + delta, base._schemeCache);
+ }
+ baseStart = base._pathStart;
+ baseEnd = base._queryStart;
+ if (baseStart === baseEnd && base._hostStart > 0) {
+ for (; C.JSString_methods.startsWith$2(t2, "../", refStart);)
+ refStart += 3;
+ delta = baseStart - refStart + 1;
+ return new P._SimpleUri(C.JSString_methods.substring$2(base._uri, 0, baseStart) + "/" + C.JSString_methods.substring$1(t2, refStart), base._schemeEnd, base._hostStart, base._portStart, baseStart, t1 + delta, ref._fragmentStart + delta, base._schemeCache);
+ }
+ baseUri = base._uri;
+ for (baseStart0 = baseStart; C.JSString_methods.startsWith$2(baseUri, "../", baseStart0);)
+ baseStart0 += 3;
+ backCount = 0;
+ while (true) {
+ refStart0 = refStart + 3;
+ if (!(refStart0 <= t1 && C.JSString_methods.startsWith$2(t2, "../", refStart)))
+ break;
+ ++backCount;
+ refStart = refStart0;
+ }
+ for (insert = ""; baseEnd > baseStart0;) {
+ --baseEnd;
+ if (C.JSString_methods.codeUnitAt$1(baseUri, baseEnd) === 47) {
+ if (backCount === 0) {
+ insert = "/";
+ break;
+ }
+ --backCount;
+ insert = "/";
+ }
+ }
+ if (baseEnd === baseStart0 && base._schemeEnd <= 0 && !C.JSString_methods.startsWith$2(baseUri, "/", baseStart)) {
+ refStart -= backCount * 3;
+ insert = "";
+ }
+ delta = baseEnd - refStart + insert.length;
+ return new P._SimpleUri(C.JSString_methods.substring$2(baseUri, 0, baseEnd) + insert + C.JSString_methods.substring$1(t2, refStart), base._schemeEnd, base._hostStart, base._portStart, baseStart, t1 + delta, ref._fragmentStart + delta, base._schemeCache);
+ },
+ toFilePath$0: function() {
+ var t1, t2, windows, _this = this;
+ if (_this._schemeEnd >= 0 && !_this.get$_isFile())
+ throw H.wrapException(P.UnsupportedError$("Cannot extract a file path from a " + H.S(_this.get$scheme()) + " URI"));
+ t1 = _this._queryStart;
+ t2 = _this._uri;
+ if (t1 < t2.length) {
+ if (t1 < _this._fragmentStart)
+ throw H.wrapException(P.UnsupportedError$("Cannot extract a file path from a URI with a query component"));
+ throw H.wrapException(P.UnsupportedError$("Cannot extract a file path from a URI with a fragment component"));
+ }
+ windows = $.$get$_Uri__isWindowsCached();
+ if (H.boolConversionCheck(windows))
+ t1 = P._Uri__toWindowsFilePath(_this);
+ else {
+ if (_this._hostStart < _this._portStart)
+ H.throwExpression(P.UnsupportedError$("Cannot extract a non-Windows file path from a file URI with an authority"));
+ t1 = C.JSString_methods.substring$2(t2, _this._pathStart, t1);
+ }
+ return t1;
+ },
+ get$hashCode: function(_) {
+ var t1 = this._hashCodeCache;
+ return t1 == null ? this._hashCodeCache = C.JSString_methods.get$hashCode(this._uri) : t1;
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ if (this === other)
+ return true;
+ return type$.Uri._is(other) && this._uri === other.toString$0(0);
+ },
+ _toNonSimple$0: function() {
+ var _this = this, _null = null,
+ t1 = _this.get$scheme(),
+ t2 = _this.get$userInfo(),
+ t3 = _this._hostStart > 0 ? _this.get$host(_this) : _null,
+ t4 = _this.get$hasPort() ? _this.get$port(_this) : _null,
+ t5 = _this._uri,
+ t6 = _this._queryStart,
+ t7 = C.JSString_methods.substring$2(t5, _this._pathStart, t6),
+ t8 = _this._fragmentStart;
+ t6 = t6 < t8 ? _this.get$query() : _null;
+ return new P._Uri(t1, t2, t3, t4, t7, t6, t8 < t5.length ? _this.get$fragment() : _null);
+ },
+ toString$0: function(_) {
+ return this._uri;
+ },
+ $isUri: 1
+ };
+ P._DataUri.prototype = {};
+ W.ApplicationCacheErrorEvent.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.Blob.prototype = {$isBlob: 1};
+ W.DomError.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.DomException.prototype = {
+ toString$0: function(receiver) {
+ return String(receiver);
+ },
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.ErrorEvent.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.Event.prototype = {$isEvent: 1};
+ W.EventTarget.prototype = {
+ addEventListener$3: function(receiver, type, listener, useCapture) {
+ type$.dynamic_Function_Event._check(listener);
+ if (listener != null)
+ this._addEventListener$3(receiver, type, listener, false);
+ },
+ _addEventListener$3: function(receiver, type, listener, options) {
+ return receiver.addEventListener(type, H.convertDartClosureToJS(type$.dynamic_Function_Event._check(listener), 1), false);
+ },
+ _removeEventListener$3: function(receiver, type, listener, options) {
+ return receiver.removeEventListener(type, H.convertDartClosureToJS(type$.dynamic_Function_Event._check(listener), 1), false);
+ },
+ $isEventTarget: 1
+ };
+ W.File.prototype = {$isFile: 1};
+ W.Location.prototype = {
+ get$origin: function(receiver) {
+ if ("origin" in receiver)
+ return receiver.origin;
+ return H.S(receiver.protocol) + "//" + H.S(receiver.host);
+ },
+ toString$0: function(receiver) {
+ return String(receiver);
+ }
+ };
+ W.MediaError.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.MediaKeyMessageEvent.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.MessageEvent.prototype = {$isMessageEvent: 1};
+ W.MessagePort.prototype = {
+ addEventListener$3: function(receiver, type, listener, useCapture) {
+ type$.dynamic_Function_Event._check(listener);
+ if (type === "message")
+ receiver.start();
+ this.super$EventTarget$addEventListener(receiver, type, listener, false);
+ },
+ postMessage$1: function(receiver, message) {
+ type$.List_Object._check(null);
+ receiver.postMessage(new P._StructuredCloneDart2Js([], []).walk$1(message));
+ return;
+ },
+ $isMessagePort: 1
+ };
+ W.NavigatorUserMediaError.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.OverconstrainedError.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.PositionError.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.PresentationConnectionCloseEvent.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.SpeechRecognitionError.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ W.EventStreamProvider.prototype = {};
+ W._EventStream.prototype = {
+ get$isBroadcast: function() {
+ return true;
+ },
+ listen$4$cancelOnError$onDone$onError: function(onData, cancelOnError, onDone, onError) {
+ var t1 = this.$ti;
+ t1._eval$1("~(1)")._check(onData);
+ type$.void_Function._check(onDone);
+ H._checkBoolNullable(cancelOnError);
+ return W._EventStreamSubscription$(this._html$_target, this._eventType, onData, false, t1._precomputed1);
+ },
+ listen$3$onDone$onError: function(onData, onDone, onError) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, onDone, onError);
+ },
+ listen$1: function(onData) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, null, null);
+ }
+ };
+ W._EventStreamSubscription.prototype = {
+ cancel$0: function() {
+ var _this = this;
+ if (_this._html$_target == null)
+ return null;
+ _this._unlisten$0();
+ _this._html$_target = null;
+ _this.set$_html$_onData(null);
+ return null;
+ },
+ pause$1: function(resumeSignal) {
+ if (this._html$_target == null)
+ return;
+ ++this._pauseCount;
+ this._unlisten$0();
+ },
+ pause$0: function() {
+ return this.pause$1(null);
+ },
+ resume$0: function() {
+ var _this = this;
+ if (_this._html$_target == null || _this._pauseCount <= 0)
+ return;
+ --_this._pauseCount;
+ _this._tryResume$0();
+ },
+ _tryResume$0: function() {
+ var _this = this,
+ t1 = _this._html$_onData;
+ if (t1 != null && _this._pauseCount <= 0)
+ J.addEventListener$3$x(_this._html$_target, _this._eventType, t1, false);
+ },
+ _unlisten$0: function() {
+ var t3,
+ t1 = this._html$_onData,
+ t2 = t1 != null;
+ if (t2) {
+ t3 = this._html$_target;
+ t3.toString;
+ type$.dynamic_Function_Event._check(t1);
+ if (t2)
+ J._removeEventListener$3$x(t3, this._eventType, t1, false);
+ }
+ },
+ set$_html$_onData: function(_onData) {
+ this._html$_onData = type$.dynamic_Function_Event._check(_onData);
+ }
+ };
+ W._EventStreamSubscription_closure.prototype = {
+ call$1: function(e) {
+ return this.onData.call$1(type$.Event._check(e));
+ },
+ $signature: 61
+ };
+ P._StructuredClone.prototype = {
+ findSlot$1: function(value) {
+ var i,
+ t1 = this.values,
+ $length = t1.length;
+ for (i = 0; i < $length; ++i)
+ if (t1[i] === value)
+ return i;
+ C.JSArray_methods.add$1(t1, value);
+ C.JSArray_methods.add$1(this.copies, null);
+ return $length;
+ },
+ walk$1: function(e) {
+ var slot, t2, copy, _this = this, t1 = {};
+ if (e == null)
+ return e;
+ if (H._isBool(e))
+ return e;
+ if (typeof e == "number")
+ return e;
+ if (typeof e == "string")
+ return e;
+ if (e instanceof P.DateTime)
+ return new Date(e._value);
+ if (type$.RegExp._is(e))
+ throw H.wrapException(P.UnimplementedError$("structured clone of RegExp"));
+ if (type$.File._is(e))
+ return e;
+ if (type$.Blob._is(e))
+ return e;
+ if (type$.NativeByteBuffer._is(e) || type$.NativeTypedData._is(e) || type$.MessagePort._is(e))
+ return e;
+ if (type$.Map_dynamic_dynamic._is(e)) {
+ slot = _this.findSlot$1(e);
+ t2 = _this.copies;
+ if (slot >= t2.length)
+ return H.ioore(t2, slot);
+ copy = t1.copy = t2[slot];
+ if (copy != null)
+ return copy;
+ copy = {};
+ t1.copy = copy;
+ C.JSArray_methods.$indexSet(t2, slot, copy);
+ e.forEach$1(0, new P._StructuredClone_walk_closure(t1, _this));
+ return t1.copy;
+ }
+ if (type$.List_dynamic._is(e)) {
+ slot = _this.findSlot$1(e);
+ t1 = _this.copies;
+ if (slot >= t1.length)
+ return H.ioore(t1, slot);
+ copy = t1[slot];
+ if (copy != null)
+ return copy;
+ return _this.copyList$2(e, slot);
+ }
+ if (type$.JSObject._is(e)) {
+ slot = _this.findSlot$1(e);
+ t2 = _this.copies;
+ if (slot >= t2.length)
+ return H.ioore(t2, slot);
+ copy = t1.copy = t2[slot];
+ if (copy != null)
+ return copy;
+ copy = {};
+ t1.copy = copy;
+ C.JSArray_methods.$indexSet(t2, slot, copy);
+ _this.forEachObjectKey$2(e, new P._StructuredClone_walk_closure0(t1, _this));
+ return t1.copy;
+ }
+ throw H.wrapException(P.UnimplementedError$("structured clone of other type"));
+ },
+ copyList$2: function(e, slot) {
+ var i,
+ t1 = J.getInterceptor$asx(e),
+ $length = t1.get$length(e),
+ copy = new Array($length);
+ C.JSArray_methods.$indexSet(this.copies, slot, copy);
+ for (i = 0; i < $length; ++i)
+ C.JSArray_methods.$indexSet(copy, i, this.walk$1(t1.$index(e, i)));
+ return copy;
+ }
+ };
+ P._StructuredClone_walk_closure.prototype = {
+ call$2: function(key, value) {
+ this._box_0.copy[key] = this.$this.walk$1(value);
+ },
+ $signature: 6
+ };
+ P._StructuredClone_walk_closure0.prototype = {
+ call$2: function(key, value) {
+ this._box_0.copy[key] = this.$this.walk$1(value);
+ },
+ $signature: 6
+ };
+ P._AcceptStructuredClone.prototype = {
+ findSlot$1: function(value) {
+ var i,
+ t1 = this.values,
+ $length = t1.length;
+ for (i = 0; i < $length; ++i)
+ if (t1[i] === value)
+ return i;
+ C.JSArray_methods.add$1(t1, value);
+ C.JSArray_methods.add$1(this.copies, null);
+ return $length;
+ },
+ walk$1: function(e) {
+ var millisSinceEpoch, t1, proto, slot, copy, t2, l, $length, i, _this = this, _box_0 = {};
+ if (e == null)
+ return e;
+ if (H._isBool(e))
+ return e;
+ if (typeof e == "number")
+ return e;
+ if (typeof e == "string")
+ return e;
+ if (e instanceof Date) {
+ millisSinceEpoch = e.getTime();
+ if (Math.abs(millisSinceEpoch) <= 864e13)
+ t1 = false;
+ else
+ t1 = true;
+ if (t1)
+ H.throwExpression(P.ArgumentError$("DateTime is outside valid range: " + millisSinceEpoch));
+ return new P.DateTime(millisSinceEpoch, true);
+ }
+ if (e instanceof RegExp)
+ throw H.wrapException(P.UnimplementedError$("structured clone of RegExp"));
+ if (typeof Promise != "undefined" && e instanceof Promise)
+ return P.promiseToFuture(e, type$.dynamic);
+ proto = Object.getPrototypeOf(e);
+ if (proto === Object.prototype || proto === null) {
+ slot = _this.findSlot$1(e);
+ t1 = _this.copies;
+ if (slot >= t1.length)
+ return H.ioore(t1, slot);
+ copy = _box_0.copy = t1[slot];
+ if (copy != null)
+ return copy;
+ t2 = type$.dynamic;
+ copy = P.LinkedHashMap_LinkedHashMap$_empty(t2, t2);
+ _box_0.copy = copy;
+ C.JSArray_methods.$indexSet(t1, slot, copy);
+ _this.forEachJsField$2(e, new P._AcceptStructuredClone_walk_closure(_box_0, _this));
+ return _box_0.copy;
+ }
+ if (e instanceof Array) {
+ l = e;
+ slot = _this.findSlot$1(l);
+ t1 = _this.copies;
+ if (slot >= t1.length)
+ return H.ioore(t1, slot);
+ copy = t1[slot];
+ if (copy != null)
+ return copy;
+ t2 = J.getInterceptor$asx(l);
+ $length = t2.get$length(l);
+ copy = _this.mustCopy ? new Array($length) : l;
+ C.JSArray_methods.$indexSet(t1, slot, copy);
+ for (t1 = J.getInterceptor$ax(copy), i = 0; i < $length; ++i)
+ t1.$indexSet(copy, i, _this.walk$1(t2.$index(l, i)));
+ return copy;
+ }
+ return e;
+ },
+ convertNativeToDart_AcceptStructuredClone$2$mustCopy: function(object, mustCopy) {
+ this.mustCopy = true;
+ return this.walk$1(object);
+ }
+ };
+ P._AcceptStructuredClone_walk_closure.prototype = {
+ call$2: function(key, value) {
+ var t1 = this._box_0.copy,
+ t2 = this.$this.walk$1(value);
+ J.$indexSet$ax(t1, key, t2);
+ return t2;
+ },
+ $signature: 60
+ };
+ P._StructuredCloneDart2Js.prototype = {
+ forEachObjectKey$2: function(object, action) {
+ var t1, t2, _i, key;
+ type$.dynamic_Function_dynamic_dynamic._check(action);
+ for (t1 = Object.keys(object), t2 = t1.length, _i = 0; _i < t2; ++_i) {
+ key = t1[_i];
+ action.call$2(key, object[key]);
+ }
+ }
+ };
+ P._AcceptStructuredCloneDart2Js.prototype = {
+ forEachJsField$2: function(object, action) {
+ var t1, t2, _i, key;
+ type$.dynamic_Function_dynamic_dynamic._check(action);
+ for (t1 = Object.keys(object), t2 = t1.length, _i = 0; _i < t1.length; t1.length === t2 || (0, H.throwConcurrentModificationError)(t1), ++_i) {
+ key = t1[_i];
+ action.call$2(key, object[key]);
+ }
+ }
+ };
+ P._convertDataTree__convert.prototype = {
+ call$1: function(o) {
+ var convertedMap, key, convertedList,
+ t1 = this._convertedObjects;
+ if (t1.containsKey$1(o))
+ return t1.$index(0, o);
+ if (type$.Map_dynamic_dynamic._is(o)) {
+ convertedMap = {};
+ t1.$indexSet(0, o, convertedMap);
+ for (t1 = o.get$keys(), t1 = t1.get$iterator(t1); t1.moveNext$0();) {
+ key = t1.get$current();
+ convertedMap[key] = this.call$1(o.$index(0, key));
+ }
+ return convertedMap;
+ } else if (type$.Iterable_dynamic._is(o)) {
+ convertedList = [];
+ t1.$indexSet(0, o, convertedList);
+ C.JSArray_methods.addAll$1(convertedList, J.map$1$1$ax(o, this, type$.dynamic));
+ return convertedList;
+ } else
+ return o;
+ },
+ $signature: 18
+ };
+ P.promiseToFuture_closure.prototype = {
+ call$1: function(r) {
+ return this.completer.complete$1(this.T._eval$1("0/")._check(r));
+ },
+ $signature: 15
+ };
+ P.promiseToFuture_closure0.prototype = {
+ call$1: function(e) {
+ return this.completer.completeError$1(e);
+ },
+ $signature: 15
+ };
+ P.ByteBuffer.prototype = {};
+ P.ByteData.prototype = {};
+ P.Int8List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.Uint8List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.Uint8ClampedList.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.Int16List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.Uint16List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.Int32List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.Uint32List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.Float32List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.Float64List.prototype = {$isEfficientLengthIterable: 1, $isIterable: 1, $isList: 1};
+ P.SqlError.prototype = {
+ get$message: function(receiver) {
+ return receiver.message;
+ }
+ };
+ S.AsyncMemoizer.prototype = {
+ runOnce$1: function(computation) {
+ var t2, t3,
+ t1 = this.$ti;
+ t1._eval$1("1/()")._check(computation);
+ t2 = this._async_memoizer$_completer;
+ t3 = t2.future;
+ if (t3._state === 0)
+ t2.complete$1(P.Future_Future$sync(computation, t1._precomputed1));
+ return t3;
+ }
+ };
+ O.DelegatingSink.prototype = {$isSink: 1};
+ Y.DelegatingStreamSubscription.prototype = {
+ onData$1: function(handleData) {
+ this._stream_subscription$_source.onData$1(this.$ti._eval$1("~(1)")._check(handleData));
+ },
+ onError$1: function(_, handleError) {
+ this._stream_subscription$_source.onError$1(0, handleError);
+ },
+ onDone$1: function(handleDone) {
+ this._stream_subscription$_source.onDone$1(type$.void_Function._check(handleDone));
+ },
+ pause$1: function(resumeFuture) {
+ this._stream_subscription$_source.pause$1(resumeFuture);
+ },
+ pause$0: function() {
+ return this.pause$1(null);
+ },
+ resume$0: function() {
+ this._stream_subscription$_source.resume$0();
+ },
+ cancel$0: function() {
+ return this._stream_subscription$_source.cancel$0();
+ },
+ $isStreamSubscription: 1
+ };
+ F.FutureGroup.prototype = {
+ add$1: function(_, task) {
+ var t1, index, _this = this;
+ _this.$ti._eval$1("Future<1>")._check(task);
+ if (_this._future_group$_closed)
+ throw H.wrapException(P.StateError$("The FutureGroup is closed."));
+ t1 = _this._values;
+ index = t1.length;
+ C.JSArray_methods.add$1(t1, null);
+ ++_this._future_group$_pending;
+ task.then$1$1(new F.FutureGroup_add_closure(_this, index), type$.Null).catchError$1(new F.FutureGroup_add_closure0(_this));
+ },
+ close$0: function(_) {
+ var t1, _this = this;
+ _this._future_group$_closed = true;
+ if (_this._future_group$_pending !== 0)
+ return;
+ t1 = _this._future_group$_completer;
+ if (t1.future._state !== 0)
+ return;
+ t1.complete$1(_this._values);
+ },
+ $isSink: 1
+ };
+ F.FutureGroup_add_closure.prototype = {
+ call$1: function(value) {
+ var t2, t3,
+ t1 = this.$this;
+ t1.$ti._precomputed1._check(value);
+ t2 = t1._future_group$_completer;
+ if (t2.future._state !== 0)
+ return null;
+ --t1._future_group$_pending;
+ t3 = t1._values;
+ C.JSArray_methods.$indexSet(t3, this.index, value);
+ if (t1._future_group$_pending !== 0)
+ return null;
+ if (!t1._future_group$_closed)
+ return null;
+ t2.complete$1(t3);
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Null(1)");
+ }
+ };
+ F.FutureGroup_add_closure0.prototype = {
+ call$2: function(error, stackTrace) {
+ var t1 = this.$this._future_group$_completer;
+ if (t1.future._state !== 0)
+ return null;
+ t1.completeError$2(error, type$.StackTrace._check(stackTrace));
+ },
+ $signature: 6
+ };
+ S.NullStreamSink.prototype = {
+ add$1: function(_, data) {
+ this.$ti._precomputed1._check(data);
+ this._checkEventAllowed$0();
+ },
+ addStream$1: function(stream) {
+ var future, _this = this;
+ _this.$ti._eval$1("Stream<1>")._check(stream);
+ _this._checkEventAllowed$0();
+ _this._addingStream = true;
+ future = stream.listen$1(null).cancel$0();
+ if (future == null) {
+ future = new P._Future($.Zone__current, type$._Future_dynamic);
+ future._asyncComplete$1(null);
+ }
+ return future.whenComplete$1(new S.NullStreamSink_addStream_closure(_this));
+ },
+ _checkEventAllowed$0: function() {
+ if (this._null_stream_sink$_closed)
+ throw H.wrapException(P.StateError$("Cannot add to a closed sink."));
+ if (this._addingStream)
+ throw H.wrapException(P.StateError$("Cannot add to a sink while adding a stream."));
+ },
+ close$0: function(_) {
+ this._null_stream_sink$_closed = true;
+ return this.done;
+ },
+ $isEventSink: 1,
+ $isStreamConsumer: 1,
+ $isStreamSink: 1,
+ $isSink: 1,
+ get$done: function() {
+ return this.done;
+ }
+ };
+ S.NullStreamSink_addStream_closure.prototype = {
+ call$0: function() {
+ this.$this._addingStream = false;
+ },
+ $signature: 0
+ };
+ V.ErrorResult.prototype = {
+ complete$1: function(completer) {
+ completer.completeError$2(this.error, this.stackTrace);
+ },
+ addTo$1: function(sink) {
+ sink.addError$2(this.error, this.stackTrace);
+ },
+ get$hashCode: function(_) {
+ return (J.get$hashCode$(this.error) ^ J.get$hashCode$(this.stackTrace) ^ 492929599) >>> 0;
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof V.ErrorResult && J.$eq$(this.error, other.error) && this.stackTrace == other.stackTrace;
+ },
+ $isResult: 1
+ };
+ E.Result.prototype = {};
+ F.ValueResult.prototype = {
+ complete$1: function(completer) {
+ this.$ti._eval$1("Completer<1>")._check(completer).complete$1(this.value);
+ },
+ addTo$1: function(sink) {
+ this.$ti._eval$1("EventSink<1>")._check(sink).add$1(0, this.value);
+ },
+ get$hashCode: function(_) {
+ return (J.get$hashCode$(this.value) ^ 842997089) >>> 0;
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof F.ValueResult && J.$eq$(this.value, other.value);
+ },
+ $isResult: 1
+ };
+ Y.StreamCompleter.prototype = {
+ setSourceStream$1: function(sourceStream) {
+ var t1;
+ this.$ti._eval$1("Stream<1>")._check(sourceStream);
+ t1 = this._stream;
+ if (t1._sourceStream != null)
+ throw H.wrapException(P.StateError$("Source stream already set"));
+ t1.set$_sourceStream(t1.$ti._eval$1("Stream<1>")._check(sourceStream));
+ if (t1._stream_completer$_controller != null)
+ t1._linkStreamToController$0();
+ }
+ };
+ Y._CompleterStream.prototype = {
+ listen$4$cancelOnError$onDone$onError: function(onData, cancelOnError, onDone, onError) {
+ var t1, _this = this;
+ _this.$ti._eval$1("@(1)")._check(onData);
+ type$.void_Function._check(onDone);
+ H._checkBoolNullable(cancelOnError);
+ if (_this._stream_completer$_controller == null) {
+ t1 = _this._sourceStream;
+ if (t1 != null && !t1.get$isBroadcast())
+ return _this._sourceStream.listen$4$cancelOnError$onDone$onError(onData, cancelOnError, onDone, onError);
+ _this._createController$0();
+ if (_this._sourceStream != null)
+ _this._linkStreamToController$0();
+ }
+ t1 = _this._stream_completer$_controller;
+ t1.toString;
+ return new P._ControllerStream(t1, H._instanceType(t1)._eval$1("_ControllerStream<1>")).listen$4$cancelOnError$onDone$onError(onData, cancelOnError, onDone, onError);
+ },
+ listen$3$onDone$onError: function(onData, onDone, onError) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, onDone, onError);
+ },
+ listen$1: function(onData) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, null, null);
+ },
+ _linkStreamToController$0: function() {
+ var t1, t2, _this = this;
+ H.assertHelper(_this._stream_completer$_controller != null);
+ H.assertHelper(_this._sourceStream != null);
+ t1 = _this._stream_completer$_controller.addStream$2$cancelOnError(_this._sourceStream, false);
+ t2 = _this._stream_completer$_controller;
+ t1.whenComplete$1(t2.get$close(t2));
+ },
+ _createController$0: function() {
+ H.assertHelper(this._stream_completer$_controller == null);
+ this.set$_stream_completer$_controller(P.StreamController_StreamController(null, null, true, this.$ti._precomputed1));
+ },
+ set$_stream_completer$_controller: function(_controller) {
+ this._stream_completer$_controller = this.$ti._eval$1("StreamController<1>")._check(_controller);
+ },
+ set$_sourceStream: function(_sourceStream) {
+ this._sourceStream = this.$ti._eval$1("Stream<1>")._check(_sourceStream);
+ }
+ };
+ L.StreamGroup.prototype = {
+ add$1: function(_, stream) {
+ var t1, _this = this;
+ _this.$ti._eval$1("Stream<1>")._check(stream);
+ if (_this._stream_group$_closed)
+ throw H.wrapException(P.StateError$("Can't add a Stream to a closed StreamGroup."));
+ t1 = _this._stream_group$_state;
+ if (t1 === C._StreamGroupState_dormant)
+ _this._stream_group$_subscriptions.putIfAbsent$2(stream, new L.StreamGroup_add_closure());
+ else if (t1 === C._StreamGroupState_canceled)
+ return stream.listen$1(null).cancel$0();
+ else
+ _this._stream_group$_subscriptions.putIfAbsent$2(stream, new L.StreamGroup_add_closure0(_this, stream));
+ return null;
+ },
+ _onListen$0: function() {
+ this._stream_group$_state = C._StreamGroupState_listening;
+ this._stream_group$_subscriptions.forEach$1(0, new L.StreamGroup__onListen_closure(this));
+ },
+ _onCancelBroadcast$0: function() {
+ this._stream_group$_state = C._StreamGroupState_dormant;
+ this._stream_group$_subscriptions.forEach$1(0, new L.StreamGroup__onCancelBroadcast_closure(this));
+ },
+ _listenToStream$1: function(stream) {
+ var t1, subscription, _this = this;
+ _this.$ti._eval$1("Stream<1>")._check(stream);
+ t1 = _this._stream_group$_controller;
+ subscription = stream.listen$3$onDone$onError(t1.get$add(t1), new L.StreamGroup__listenToStream_closure(_this, stream), t1.get$addError());
+ if (_this._stream_group$_state === C._StreamGroupState_paused)
+ subscription.pause$0();
+ return subscription;
+ },
+ close$0: function(_) {
+ var t1, _this = this;
+ if (_this._stream_group$_closed)
+ return _this._stream_group$_controller._ensureDoneFuture$0();
+ _this._stream_group$_closed = true;
+ t1 = _this._stream_group$_subscriptions;
+ if (t1.get$isEmpty(t1))
+ _this._stream_group$_controller.close$0(0);
+ return _this._stream_group$_controller._ensureDoneFuture$0();
+ },
+ set$_stream_group$_controller: function(_controller) {
+ this._stream_group$_controller = this.$ti._eval$1("StreamController<1>")._check(_controller);
+ },
+ $isSink: 1
+ };
+ L.StreamGroup_add_closure.prototype = {
+ call$0: function() {
+ return null;
+ },
+ $signature: 0
+ };
+ L.StreamGroup_add_closure0.prototype = {
+ call$0: function() {
+ return this.$this._listenToStream$1(this.stream);
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("StreamSubscription<1>()");
+ }
+ };
+ L.StreamGroup__onListen_closure.prototype = {
+ call$2: function(stream, subscription) {
+ var t1 = this.$this,
+ t2 = t1.$ti;
+ t2._eval$1("Stream<1>")._check(stream);
+ if (t2._eval$1("StreamSubscription<1>")._check(subscription) != null)
+ return;
+ t1._stream_group$_subscriptions.$indexSet(0, stream, t1._listenToStream$1(stream));
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Null(Stream<1>,StreamSubscription<1>)");
+ }
+ };
+ L.StreamGroup__onCancelBroadcast_closure.prototype = {
+ call$2: function(stream, subscription) {
+ var t1 = this.$this,
+ t2 = t1.$ti;
+ t2._eval$1("Stream<1>")._check(stream);
+ t2._eval$1("StreamSubscription<1>")._check(subscription);
+ if (!stream.get$isBroadcast())
+ return;
+ subscription.cancel$0();
+ t1._stream_group$_subscriptions.$indexSet(0, stream, null);
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Null(Stream<1>,StreamSubscription<1>)");
+ }
+ };
+ L.StreamGroup__listenToStream_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ t2 = t1._stream_group$_subscriptions,
+ subscription = t2.remove$1(0, t1.$ti._eval$1("Stream<1>")._check(this.stream)),
+ future = subscription == null ? null : subscription.cancel$0();
+ if (t1._stream_group$_closed && t2.get$isEmpty(t2))
+ t1._stream_group$_controller.close$0(0);
+ return future;
+ },
+ $signature: 14
+ };
+ L._StreamGroupState.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ G.StreamQueue.prototype = {
+ get$next: function() {
+ var t1, t2, _this = this;
+ if (!_this._isClosed) {
+ t1 = _this.$ti;
+ t2 = new P._Future($.Zone__current, t1._eval$1("_Future<1>"));
+ _this._addRequest$1(new G._NextRequest(new P._AsyncCompleter(t2, t1._eval$1("_AsyncCompleter<1>")), t1._eval$1("_NextRequest<1>")));
+ return t2;
+ }
+ throw H.wrapException(_this._failClosed$0());
+ },
+ _updateRequests$0: function() {
+ var t1, t2, t3, t4, _this = this;
+ for (t1 = _this._requestQueue, t2 = _this._eventQueue; !t1.get$isEmpty(t1);) {
+ t3 = t1._head;
+ if (t3 === t1._tail)
+ H.throwExpression(H.IterableElementError_noElement());
+ t4 = t1._table;
+ if (t3 >= t4.length)
+ return H.ioore(t4, t3);
+ if (t4[t3].update$2(t2, _this._isDone))
+ t1.removeFirst$0();
+ else
+ return;
+ }
+ if (!_this._isDone)
+ _this._stream_queue$_subscription.pause$0();
+ },
+ _extractStream$0: function() {
+ var t1, wasPaused, _this = this, _null = null;
+ H.assertHelper(_this._isClosed);
+ if (_this._isDone)
+ return new P._EmptyStream(_this.$ti._eval$1("_EmptyStream<1>"));
+ _this._isDone = true;
+ t1 = _this._stream_queue$_subscription;
+ if (t1 == null)
+ return _this._stream_queue$_source;
+ _this.set$_stream_queue$_subscription(_null);
+ wasPaused = t1.get$isPaused();
+ t1.pause$0();
+ t1.onData$1(_null);
+ t1.onError$1(0, _null);
+ t1.onDone$1(_null);
+ if (wasPaused)
+ t1.resume$0();
+ return new T.SubscriptionStream(t1, _this.$ti._eval$1("SubscriptionStream<1>"));
+ },
+ _ensureListening$0: function() {
+ var t1, _this = this;
+ if (_this._isDone)
+ return;
+ t1 = _this._stream_queue$_subscription;
+ if (t1 == null)
+ _this.set$_stream_queue$_subscription(_this._stream_queue$_source.listen$3$onDone$onError(new G.StreamQueue__ensureListening_closure(_this), new G.StreamQueue__ensureListening_closure0(_this), new G.StreamQueue__ensureListening_closure1(_this)));
+ else
+ t1.resume$0();
+ },
+ _addResult$1: function(result) {
+ var t1, _this = this;
+ _this.$ti._eval$1("Result<1>")._check(result);
+ ++_this._eventsReceived;
+ t1 = _this._eventQueue;
+ t1._queue_list$_add$1(t1.$ti._precomputed1._check(result));
+ _this._updateRequests$0();
+ },
+ _failClosed$0: function() {
+ return new P.StateError("Already cancelled");
+ },
+ _addRequest$1: function(request) {
+ var t1, _this = this;
+ _this.$ti._eval$1("_EventRequest<1>")._check(request);
+ t1 = _this._requestQueue;
+ if (t1._head === t1._tail) {
+ if (request.update$2(_this._eventQueue, _this._isDone))
+ return;
+ _this._ensureListening$0();
+ }
+ t1._collection$_add$1(t1.$ti._precomputed1._check(request));
+ },
+ set$_stream_queue$_subscription: function(_subscription) {
+ this._stream_queue$_subscription = this.$ti._eval$1("StreamSubscription<1>")._check(_subscription);
+ }
+ };
+ G.StreamQueue__ensureListening_closure.prototype = {
+ call$1: function(data) {
+ var t1 = this.$this,
+ t2 = t1.$ti;
+ t1._addResult$1(new F.ValueResult(t2._precomputed1._check(data), t2._eval$1("ValueResult<1>")));
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Null(1)");
+ }
+ };
+ G.StreamQueue__ensureListening_closure1.prototype = {
+ call$2: function(error, stackTrace) {
+ this.$this._addResult$1(new V.ErrorResult(error, type$.StackTrace._check(stackTrace)));
+ },
+ $signature: 5
+ };
+ G.StreamQueue__ensureListening_closure0.prototype = {
+ call$0: function() {
+ var t1 = this.$this;
+ t1.set$_stream_queue$_subscription(null);
+ t1._isDone = true;
+ t1._updateRequests$0();
+ },
+ $signature: 0
+ };
+ G._EventRequest.prototype = {};
+ G._NextRequest.prototype = {
+ update$2: function(events, isDone) {
+ this.$ti._eval$1("QueueList<Result<1>>")._check(events);
+ if (events.get$length(events) !== 0) {
+ events.removeFirst$0().complete$1(this._completer);
+ return true;
+ }
+ if (isDone) {
+ this._completer.completeError$2(new P.StateError("No elements"), P.StackTrace_current());
+ return true;
+ }
+ return false;
+ },
+ $is_EventRequest: 1
+ };
+ G._RestRequest.prototype = {
+ update$2: function(events, isDone) {
+ var t2, controller, _this = this,
+ t1 = _this.$ti;
+ t1._eval$1("QueueList<Result<1>>")._check(events);
+ if (events.get$length(events) === 0) {
+ t1 = _this._streamQueue;
+ t2 = _this._completer;
+ if (t1._isDone) {
+ t1 = t2._stream;
+ t2 = t1._sourceStream == null;
+ if (!t2)
+ H.throwExpression(P.StateError$("Source stream already set"));
+ H.assertHelper(t2);
+ if (t1._stream_completer$_controller == null)
+ t1._createController$0();
+ t2 = t1._stream_completer$_controller;
+ t2.toString;
+ t1.set$_sourceStream(new P._ControllerStream(t2, H._instanceType(t2)._eval$1("_ControllerStream<1>")));
+ t1._stream_completer$_controller.close$0(0);
+ } else
+ t2.setSourceStream$1(t1._extractStream$0());
+ } else {
+ controller = P.StreamController_StreamController(null, null, false, t1._precomputed1);
+ for (t1 = new H.ListIterator(events, events.get$length(events), events.$ti._eval$1("ListIterator<ListMixin.E>")); t1.moveNext$0();)
+ t1.__internal$_current.addTo$1(controller);
+ controller.addStream$2$cancelOnError(_this._streamQueue._extractStream$0(), false).whenComplete$1(controller.get$close(controller));
+ _this._completer.setSourceStream$1(new P._ControllerStream(controller, H._instanceType(controller)._eval$1("_ControllerStream<1>")));
+ }
+ return true;
+ },
+ $is_EventRequest: 1
+ };
+ T.StreamSinkCompleter.prototype = {};
+ T._CompleterSink.prototype = {
+ get$_canSendDirectly: function() {
+ return this._stream_sink_completer$_controller == null && this._destinationSink != null;
+ },
+ get$done: function() {
+ var t1 = this._stream_sink_completer$_doneCompleter;
+ if (t1 != null)
+ return t1.future;
+ t1 = this._destinationSink;
+ if (t1 == null) {
+ t1 = new P._Future($.Zone__current, type$._Future_dynamic);
+ this._stream_sink_completer$_doneCompleter = new P._SyncCompleter(t1, type$._SyncCompleter_dynamic);
+ return t1;
+ }
+ return t1.get$done();
+ },
+ addStream$1: function(stream) {
+ var _this = this;
+ _this.$ti._eval$1("Stream<1>")._check(stream);
+ if (_this.get$_canSendDirectly())
+ return _this._destinationSink.addStream$1(stream);
+ _this._ensureController$0();
+ return _this._stream_sink_completer$_controller.addStream$2$cancelOnError(stream, false);
+ },
+ close$0: function(_) {
+ var _this = this;
+ if (_this.get$_canSendDirectly())
+ _this._destinationSink.close$0(0);
+ else {
+ _this._ensureController$0();
+ _this._stream_sink_completer$_controller.close$0(0);
+ }
+ return _this.get$done();
+ },
+ _ensureController$0: function() {
+ if (this._stream_sink_completer$_controller == null)
+ this.set$_stream_sink_completer$_controller(P.StreamController_StreamController(null, null, true, this.$ti._precomputed1));
+ },
+ _setDestinationSink$1: function(sink) {
+ var t1, _this = this;
+ _this.$ti._eval$1("StreamSink<1>")._check(sink);
+ H.assertHelper(_this._destinationSink == null);
+ _this.set$_destinationSink(sink);
+ t1 = _this._stream_sink_completer$_controller;
+ if (t1 != null)
+ sink.addStream$1(new P._ControllerStream(t1, H._instanceType(t1)._eval$1("_ControllerStream<1>"))).whenComplete$1(sink.get$close(sink)).catchError$1(new T._CompleterSink__setDestinationSink_closure());
+ t1 = _this._stream_sink_completer$_doneCompleter;
+ if (t1 != null)
+ t1.complete$1(sink.get$done());
+ },
+ set$_stream_sink_completer$_controller: function(_controller) {
+ this._stream_sink_completer$_controller = this.$ti._eval$1("StreamController<1>")._check(_controller);
+ },
+ set$_destinationSink: function(_destinationSink) {
+ this._destinationSink = this.$ti._eval$1("StreamSink<1>")._check(_destinationSink);
+ },
+ $isEventSink: 1,
+ $isStreamConsumer: 1,
+ $isStreamSink: 1,
+ $isSink: 1
+ };
+ T._CompleterSink__setDestinationSink_closure.prototype = {
+ call$1: function(_) {
+ },
+ $signature: 3
+ };
+ T.SubscriptionStream.prototype = {
+ listen$4$cancelOnError$onDone$onError: function(onData, cancelOnError, onDone, onError) {
+ var result, result0,
+ t1 = this.$ti;
+ t1._eval$1("~(1)")._check(onData);
+ type$.void_Function._check(onDone);
+ H._checkBoolNullable(cancelOnError);
+ result = this._subscription_stream$_source;
+ if (result == null)
+ throw H.wrapException(P.StateError$("Stream has already been listened to."));
+ this.set$_subscription_stream$_source(null);
+ result0 = true === cancelOnError ? new T._CancelOnErrorSubscriptionWrapper(result, t1._eval$1("_CancelOnErrorSubscriptionWrapper<1>")) : result;
+ result0.onData$1(onData);
+ result0.onError$1(0, onError);
+ result0.onDone$1(onDone);
+ result.resume$0();
+ return result0;
+ },
+ listen$3$onDone$onError: function(onData, onDone, onError) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, onDone, onError);
+ },
+ listen$1: function(onData) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, null, null);
+ },
+ set$_subscription_stream$_source: function(_source) {
+ this._subscription_stream$_source = this.$ti._eval$1("StreamSubscription<1>")._check(_source);
+ }
+ };
+ T._CancelOnErrorSubscriptionWrapper.prototype = {
+ onError$1: function(_, handleError) {
+ this.super$DelegatingStreamSubscription$onError(0, new T._CancelOnErrorSubscriptionWrapper_onError_closure(this, handleError));
+ }
+ };
+ T._CancelOnErrorSubscriptionWrapper_onError_closure.prototype = {
+ call$2: function(error, stackTrace) {
+ var cancelFuture, t1;
+ type$.StackTrace._check(stackTrace);
+ cancelFuture = this.$this.super$DelegatingStreamSubscription$cancel();
+ if (cancelFuture != null)
+ cancelFuture.whenComplete$1(new T._CancelOnErrorSubscriptionWrapper_onError__closure(this.handleError, error, stackTrace));
+ else {
+ t1 = this.handleError;
+ if (type$.dynamic_Function_dynamic_dynamic._is(t1))
+ t1.call$2(error, stackTrace);
+ else
+ t1.call$1(error);
+ }
+ },
+ $signature: 5
+ };
+ T._CancelOnErrorSubscriptionWrapper_onError__closure.prototype = {
+ call$0: function() {
+ var t1 = this.handleError,
+ t2 = this.error;
+ if (type$.dynamic_Function_dynamic_dynamic._is(t1))
+ t1.call$2(t2, this.stackTrace);
+ else
+ t1.call$1(t2);
+ },
+ $signature: 0
+ };
+ X.BooleanSelector.prototype = {};
+ X.All.prototype = {
+ evaluate$1: function(semantics) {
+ return true;
+ },
+ intersection$1: function(other) {
+ return other;
+ },
+ validate$1: function(isDefined) {
+ type$.bool_Function_String._check(isDefined);
+ },
+ toString$0: function(_) {
+ return "<all>";
+ },
+ $isBooleanSelector: 1
+ };
+ U.VariableNode.prototype = {
+ accept$1: function(visitor) {
+ return visitor.visitVariable$1(this);
+ },
+ toString$0: function(_) {
+ return this.name;
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof U.VariableNode && this.name == other.name;
+ },
+ get$hashCode: function(_) {
+ return J.get$hashCode$(this.name);
+ },
+ $isNode: 1,
+ get$span: function() {
+ return this.span;
+ }
+ };
+ U.NotNode.prototype = {
+ accept$1: function(visitor) {
+ return visitor.visitNot$1(this);
+ },
+ toString$0: function(_) {
+ var t1 = this.child;
+ return t1 instanceof U.VariableNode || t1 instanceof U.NotNode ? "!" + t1.toString$0(0) : "!(" + t1.toString$0(0) + ")";
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof U.NotNode && this.child.$eq(0, other.child);
+ },
+ get$hashCode: function(_) {
+ var t1 = this.child;
+ return ~t1.get$hashCode(t1) >>> 0;
+ },
+ $isNode: 1,
+ get$span: function() {
+ return this.span;
+ }
+ };
+ U.OrNode.prototype = {
+ get$span: function() {
+ return U._expandSafe(this.left.get$span(), this.right.get$span());
+ },
+ accept$1: function(visitor) {
+ return visitor.visitOr$1(this);
+ },
+ toString$0: function(_) {
+ var string2,
+ string1 = this.left;
+ if (string1 instanceof U.AndNode || string1 instanceof U.ConditionalNode)
+ string1 = "(" + string1.toString$0(0) + ")";
+ string2 = this.right;
+ if (string2 instanceof U.AndNode || string2 instanceof U.ConditionalNode)
+ string2 = "(" + string2.toString$0(0) + ")";
+ return H.S(string1) + " || " + H.S(string2);
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof U.OrNode && this.left.$eq(0, other.left) && this.right.$eq(0, other.right);
+ },
+ get$hashCode: function(_) {
+ var t1 = this.left,
+ t2 = this.right;
+ return (t1.get$hashCode(t1) ^ t2.get$hashCode(t2)) >>> 0;
+ },
+ $isNode: 1
+ };
+ U.AndNode.prototype = {
+ get$span: function() {
+ return U._expandSafe(this.left.get$span(), this.right.get$span());
+ },
+ accept$1: function(visitor) {
+ return visitor.visitAnd$1(this);
+ },
+ toString$0: function(_) {
+ var string2,
+ string1 = this.left;
+ if (string1 instanceof U.OrNode || string1 instanceof U.ConditionalNode)
+ string1 = "(" + string1.toString$0(0) + ")";
+ string2 = this.right;
+ if (string2 instanceof U.OrNode || string2 instanceof U.ConditionalNode)
+ string2 = "(" + string2.toString$0(0) + ")";
+ return H.S(string1) + " && " + H.S(string2);
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof U.AndNode && this.left.$eq(0, other.left) && this.right.$eq(0, other.right);
+ },
+ get$hashCode: function(_) {
+ var t1 = this.left,
+ t2 = this.right;
+ return (t1.get$hashCode(t1) ^ t2.get$hashCode(t2)) >>> 0;
+ },
+ $isNode: 1
+ };
+ U.ConditionalNode.prototype = {
+ get$span: function() {
+ return U._expandSafe(this.condition.get$span(), this.whenFalse.get$span());
+ },
+ accept$1: function(visitor) {
+ return visitor.visitConditional$1(this);
+ },
+ toString$0: function(_) {
+ var trueString,
+ conditionString = this.condition;
+ if (conditionString instanceof U.ConditionalNode)
+ conditionString = "(" + conditionString.toString$0(0) + ")";
+ trueString = this.whenTrue;
+ if (trueString instanceof U.ConditionalNode)
+ trueString = "(" + trueString.toString$0(0) + ")";
+ return H.S(conditionString) + " ? " + H.S(trueString) + " : " + this.whenFalse.toString$0(0);
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof U.ConditionalNode && this.condition.$eq(0, other.condition) && this.whenTrue.$eq(0, other.whenTrue) && this.whenFalse.$eq(0, other.whenFalse);
+ },
+ get$hashCode: function(_) {
+ var t1 = this.condition,
+ t2 = this.whenTrue,
+ t3 = this.whenFalse;
+ return (t1.get$hashCode(t1) ^ t2.get$hashCode(t2) ^ t3.get$hashCode(t3)) >>> 0;
+ },
+ $isNode: 1
+ };
+ T.Evaluator.prototype = {
+ visitVariable$1: function(node) {
+ return this._semantics.call$1(node.name);
+ },
+ visitNot$1: function(node) {
+ return !H.boolConversionCheck(node.child.accept$1(this));
+ },
+ visitOr$1: function(node) {
+ return H.boolConversionCheck(node.left.accept$1(this)) || H.boolConversionCheck(node.right.accept$1(this));
+ },
+ visitAnd$1: function(node) {
+ return H.boolConversionCheck(node.left.accept$1(this)) && H.boolConversionCheck(node.right.accept$1(this));
+ },
+ visitConditional$1: function(node) {
+ return H.boolConversionCheck(node.condition.accept$1(this)) ? node.whenTrue.accept$1(this) : node.whenFalse.accept$1(this);
+ },
+ $isVisitor: 1
+ };
+ Y.BooleanSelectorImpl.prototype = {
+ evaluate$1: function(semantics) {
+ var t1;
+ if (type$.Iterable_dynamic._is(semantics)) {
+ t1 = semantics.toSet$0(0);
+ t1 = t1.get$contains(t1);
+ } else {
+ type$.bool_Function_String._as(semantics);
+ t1 = semantics;
+ }
+ return this._selector.accept$1(new T.Evaluator(t1));
+ },
+ intersection$1: function(other) {
+ var t1 = J.getInterceptor$(other);
+ if (t1.$eq(other, C.C_All))
+ return this;
+ if (t1.$eq(other, C.C_None))
+ return other;
+ return other instanceof Y.BooleanSelectorImpl ? new Y.BooleanSelectorImpl(new U.AndNode(this._selector, other._selector)) : new R.IntersectionSelector(this, other);
+ },
+ validate$1: function(isDefined) {
+ this._selector.accept$1(new S.Validator(type$.bool_Function_String._check(isDefined)));
+ },
+ toString$0: function(_) {
+ return this._selector.toString$0(0);
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof Y.BooleanSelectorImpl && this._selector.$eq(0, other._selector);
+ },
+ get$hashCode: function(_) {
+ var t1 = this._selector;
+ return t1.get$hashCode(t1);
+ },
+ $isBooleanSelector: 1
+ };
+ R.IntersectionSelector.prototype = {
+ evaluate$1: function(semantics) {
+ return H.boolConversionCheck(this._selector1.evaluate$1(semantics)) && H.boolConversionCheck(this._selector2.evaluate$1(semantics));
+ },
+ intersection$1: function(other) {
+ return new R.IntersectionSelector(this, other);
+ },
+ validate$1: function(isDefined) {
+ type$.bool_Function_String._check(isDefined);
+ this._selector1.validate$1(isDefined);
+ this._selector2.validate$1(isDefined);
+ },
+ toString$0: function(_) {
+ return "(" + this._selector1.toString$0(0) + ") && (" + H.S(this._selector2) + ")";
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof R.IntersectionSelector && this._selector1.$eq(0, other._selector1) && J.$eq$(this._selector2, other._selector2);
+ },
+ get$hashCode: function(_) {
+ var t1 = this._selector1;
+ return (t1.get$hashCode(t1) ^ J.get$hashCode$(this._selector2)) >>> 0;
+ },
+ $isBooleanSelector: 1
+ };
+ O.None.prototype = {
+ evaluate$1: function(semantics) {
+ return false;
+ },
+ intersection$1: function(other) {
+ return this;
+ },
+ validate$1: function(isDefined) {
+ type$.bool_Function_String._check(isDefined);
+ },
+ toString$0: function(_) {
+ return "<none>";
+ },
+ $isBooleanSelector: 1
+ };
+ G.Parser.prototype = {
+ parse$0: function() {
+ var selector = this._conditional$0(),
+ t1 = this._parser0$_scanner,
+ t2 = t1.peek$0();
+ if (t2.get$type(t2) !== C.TokenType_wwi)
+ throw H.wrapException(G.SourceSpanFormatException$("Expected end of input.", t1.peek$0().get$span(), null));
+ return selector;
+ },
+ _conditional$0: function() {
+ var whenTrue, _this = this,
+ condition = _this._or$0(),
+ t1 = _this._parser0$_scanner;
+ if (!t1.scan$1(C.TokenType_69P))
+ return condition;
+ whenTrue = _this._conditional$0();
+ if (!t1.scan$1(C.TokenType_colon))
+ throw H.wrapException(G.SourceSpanFormatException$('Expected ":".', t1.peek$0().get$span(), null));
+ return new U.ConditionalNode(condition, whenTrue, _this._conditional$0());
+ },
+ _or$0: function() {
+ var left = this._and$0();
+ if (!this._parser0$_scanner.scan$1(C.TokenType_or))
+ return left;
+ return new U.OrNode(left, this._or$0());
+ },
+ _and$0: function() {
+ var left = this._simpleExpression$0();
+ if (!this._parser0$_scanner.scan$1(C.TokenType_and))
+ return left;
+ return new U.AndNode(left, this._and$0());
+ },
+ _simpleExpression$0: function() {
+ var child,
+ t1 = this._parser0$_scanner,
+ token = t1.next$0();
+ switch (token.get$type(token)) {
+ case C.TokenType_not:
+ child = this._simpleExpression$0();
+ return new U.NotNode(token.get$span().expand$1(0, child.get$span()), child);
+ case C.TokenType_e7P:
+ child = this._conditional$0();
+ if (!t1.scan$1(C.TokenType_31K))
+ throw H.wrapException(G.SourceSpanFormatException$('Expected ")".', t1.peek$0().get$span(), null));
+ return child;
+ case C.TokenType_identifier:
+ type$.IdentifierToken._as(token);
+ return new U.VariableNode(token.span, token.name);
+ default:
+ throw H.wrapException(G.SourceSpanFormatException$("Expected expression.", token.get$span(), null));
+ }
+ }
+ };
+ O.Scanner.prototype = {
+ peek$0: function() {
+ var t1 = this._scanner$_next;
+ return t1 == null ? this._scanner$_next = this._getNext$0() : t1;
+ },
+ next$0: function() {
+ var _this = this,
+ token = _this._scanner$_next;
+ if (token == null)
+ token = _this._getNext$0();
+ _this._endOfFileEmitted = token.get$type(token) === C.TokenType_wwi;
+ _this._scanner$_next = null;
+ return token;
+ },
+ scan$1: function(type) {
+ var t1 = this.peek$0();
+ if (t1.get$type(t1) !== type)
+ return false;
+ this.next$0();
+ return true;
+ },
+ _getNext$0: function() {
+ var t1, t2, _this = this;
+ if (_this._endOfFileEmitted)
+ throw H.wrapException(P.StateError$("No more tokens."));
+ _this._consumeWhitespace$0();
+ t1 = _this._scanner;
+ t2 = t1._string_scanner$_position;
+ if (t2 === t1.string.length)
+ return new L.Token(C.TokenType_wwi, t1.spanFrom$1(new S._SpanScannerState(t1, t2)));
+ switch (t1.peekChar$0()) {
+ case 40:
+ return _this._scanOperator$1(C.TokenType_e7P);
+ case 41:
+ return _this._scanOperator$1(C.TokenType_31K);
+ case 63:
+ return _this._scanOperator$1(C.TokenType_69P);
+ case 58:
+ return _this._scanOperator$1(C.TokenType_colon);
+ case 33:
+ return _this._scanOperator$1(C.TokenType_not);
+ case 124:
+ t2 = t1._string_scanner$_position;
+ t1.expect$1("||");
+ return new L.Token(C.TokenType_or, t1.spanFrom$1(new S._SpanScannerState(t1, t2)));
+ case 38:
+ t2 = t1._string_scanner$_position;
+ t1.expect$1("&&");
+ return new L.Token(C.TokenType_and, t1.spanFrom$1(new S._SpanScannerState(t1, t2)));
+ default:
+ t1.expect$2$name($.$get$_hyphenatedIdentifier0(), "expression");
+ t2 = t1.get$lastMatch().$index(0, 0);
+ if (t1.get$lastMatch() == null)
+ t1._lastSpan = null;
+ return new L.IdentifierToken(t1._lastSpan, t2);
+ }
+ },
+ _scanOperator$1: function(type) {
+ var t1 = this._scanner,
+ t2 = t1._string_scanner$_position,
+ t3 = t1.string;
+ if (t2 === t3.length)
+ t1.error$3$length$position(0, "expected more input.", 0, t2);
+ J.codeUnitAt$1$s(t3, t1._string_scanner$_position++);
+ return new L.Token(type, t1.spanFrom$1(new S._SpanScannerState(t1, t2)));
+ },
+ _consumeWhitespace$0: function() {
+ var success,
+ t1 = this._scanner;
+ while (true) {
+ success = t1.matches$1(0, $.$get$_whitespaceAndSingleLineComments());
+ if (success)
+ t1._lastMatchPosition = t1._string_scanner$_position = t1._lastMatch.get$end();
+ if (!(success || this._multiLineComment$0()))
+ break;
+ }
+ },
+ _multiLineComment$0: function() {
+ var success,
+ t1 = this._scanner;
+ if (!t1.scan$1("/*"))
+ return false;
+ while (true) {
+ success = t1.matches$1(0, $.$get$_multiLineCommentBody());
+ if (success)
+ t1._lastMatchPosition = t1._string_scanner$_position = t1._lastMatch.get$end();
+ if (!(success || this._multiLineComment$0()))
+ break;
+ }
+ t1.expect$1("*/");
+ return true;
+ }
+ };
+ L.Token.prototype = {
+ get$type: function(receiver) {
+ return this.type;
+ },
+ get$span: function() {
+ return this.span;
+ }
+ };
+ L.IdentifierToken.prototype = {
+ toString$0: function(_) {
+ return 'identifier "' + H.S(this.name) + '"';
+ },
+ $isToken: 1,
+ get$type: function() {
+ return C.TokenType_identifier;
+ },
+ get$span: function() {
+ return this.span;
+ }
+ };
+ L.TokenType.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ S.Validator.prototype = {
+ visitVariable$1: function(node) {
+ if (H.boolConversionCheck(this._isDefined.call$1(node.name)))
+ return;
+ throw H.wrapException(G.SourceSpanFormatException$("Undefined variable.", node.span, null));
+ }
+ };
+ B.RecursiveVisitor.prototype = {
+ visitNot$1: function(node) {
+ node.child.accept$1(this);
+ },
+ visitOr$1: function(node) {
+ node.left.accept$1(this);
+ node.right.accept$1(this);
+ },
+ visitAnd$1: function(node) {
+ node.left.accept$1(this);
+ node.right.accept$1(this);
+ },
+ visitConditional$1: function(node) {
+ node.condition.accept$1(this);
+ node.whenTrue.accept$1(this);
+ node.whenFalse.accept$1(this);
+ },
+ $isVisitor: 1
+ };
+ O.EmptyUnmodifiableSet.prototype = {
+ get$iterator: function(_) {
+ return C.C_EmptyIterator;
+ },
+ get$length: function(_) {
+ return 0;
+ },
+ contains$1: function(_, element) {
+ return false;
+ },
+ toSet$0: function(_) {
+ return P.LinkedHashSet_LinkedHashSet(this.$ti._precomputed1);
+ },
+ $isEfficientLengthIterable: 1,
+ $isSet: 1
+ };
+ Y.mapMap_closure.prototype = {
+ call$2: function(mapKey, _) {
+ this.K1._check(mapKey);
+ this.V1._check(_);
+ return this.K2._as(mapKey);
+ },
+ $signature: function() {
+ return this.K2._eval$1("@<0>")._bind$1(this.K1)._bind$1(this.V1)._eval$1("1(2,3)");
+ }
+ };
+ Y.mapMap_closure0.prototype = {
+ call$2: function(mapKey, mapValue) {
+ var t1, _this = this;
+ _this.K1._check(mapKey);
+ _this.V1._check(mapValue);
+ t1 = _this._box_0;
+ _this.result.$indexSet(0, t1.key.call$2(mapKey, mapValue), t1.value.call$2(mapKey, mapValue));
+ },
+ $signature: function() {
+ return this.K1._eval$1("@<0>")._bind$1(this.V1)._eval$1("Null(1,2)");
+ }
+ };
+ Y.mergeMaps_closure.prototype = {
+ call$2: function(key, mapValue) {
+ var t1, _this = this;
+ _this.K._check(key);
+ _this.V._check(mapValue);
+ t1 = _this.result;
+ t1.$indexSet(0, key, t1.containsKey$1(key) ? _this.value.call$2(t1.$index(0, key), mapValue) : mapValue);
+ },
+ $signature: function() {
+ return this.K._eval$1("@<0>")._bind$1(this.V)._eval$1("Null(1,2)");
+ }
+ };
+ Q.QueueList.prototype = {
+ toString$0: function(_) {
+ return P.IterableBase_iterableToFullString(this, "{", "}");
+ },
+ removeFirst$0: function() {
+ var t2, result, _this = this,
+ t1 = _this._queue_list$_head;
+ if (t1 === _this._queue_list$_tail)
+ throw H.wrapException(P.StateError$("No element"));
+ t2 = _this._queue_list$_table;
+ if (t1 >= t2.length)
+ return H.ioore(t2, t1);
+ result = t2[t1];
+ C.JSArray_methods.$indexSet(t2, t1, null);
+ _this._queue_list$_head = (_this._queue_list$_head + 1 & _this._queue_list$_table.length - 1) >>> 0;
+ return result;
+ },
+ get$length: function(_) {
+ return (this._queue_list$_tail - this._queue_list$_head & this._queue_list$_table.length - 1) >>> 0;
+ },
+ set$length: function(_, value) {
+ var delta, t1, newTail, t2, _this = this;
+ if (value < 0)
+ throw H.wrapException(P.RangeError$("Length " + value + " may not be negative."));
+ delta = value - _this.get$length(_this);
+ if (delta >= 0) {
+ if (_this._queue_list$_table.length <= value)
+ _this._preGrow$1(value);
+ _this._queue_list$_tail = (_this._queue_list$_tail + delta & _this._queue_list$_table.length - 1) >>> 0;
+ return;
+ }
+ t1 = _this._queue_list$_tail;
+ newTail = t1 + delta;
+ t2 = _this._queue_list$_table;
+ if (newTail >= 0)
+ C.JSArray_methods.fillRange$3(t2, newTail, t1, null);
+ else {
+ newTail += t2.length;
+ C.JSArray_methods.fillRange$3(t2, 0, t1, null);
+ t1 = _this._queue_list$_table;
+ C.JSArray_methods.fillRange$3(t1, newTail, t1.length, null);
+ }
+ _this._queue_list$_tail = newTail;
+ },
+ $index: function(_, index) {
+ var t1, t2, t3, _this = this;
+ H._checkIntNullable(index);
+ if (index < 0 || index >= _this.get$length(_this))
+ throw H.wrapException(P.RangeError$("Index " + index + " must be in the range [0.." + _this.get$length(_this) + ")."));
+ t1 = _this._queue_list$_table;
+ t2 = t1.length;
+ t3 = (_this._queue_list$_head + index & t2 - 1) >>> 0;
+ if (t3 < 0 || t3 >= t2)
+ return H.ioore(t1, t3);
+ return t1[t3];
+ },
+ $indexSet: function(_, index, value) {
+ var t1, _this = this;
+ H._checkIntNullable(index);
+ _this.$ti._precomputed1._check(value);
+ if (typeof index !== "number")
+ return index.$lt();
+ if (index < 0 || index >= _this.get$length(_this))
+ throw H.wrapException(P.RangeError$("Index " + index + " must be in the range [0.." + _this.get$length(_this) + ")."));
+ t1 = _this._queue_list$_table;
+ C.JSArray_methods.$indexSet(t1, (_this._queue_list$_head + index & t1.length - 1) >>> 0, value);
+ },
+ _queue_list$_add$1: function(element) {
+ var t2, t3, newTable, split, _this = this,
+ t1 = _this.$ti;
+ t1._precomputed1._check(element);
+ C.JSArray_methods.$indexSet(_this._queue_list$_table, _this._queue_list$_tail, element);
+ t2 = _this._queue_list$_tail;
+ t3 = _this._queue_list$_table.length;
+ t2 = (t2 + 1 & t3 - 1) >>> 0;
+ _this._queue_list$_tail = t2;
+ if (_this._queue_list$_head === t2) {
+ t2 = new Array(t3 * 2);
+ t2.fixed$length = Array;
+ newTable = H.setRuntimeTypeInfo(t2, t1._eval$1("JSArray<1>"));
+ t1 = _this._queue_list$_table;
+ t2 = _this._queue_list$_head;
+ split = t1.length - t2;
+ C.JSArray_methods.setRange$4(newTable, 0, split, t1, t2);
+ C.JSArray_methods.setRange$4(newTable, split, split + _this._queue_list$_head, _this._queue_list$_table, 0);
+ _this._queue_list$_head = 0;
+ _this._queue_list$_tail = _this._queue_list$_table.length;
+ _this.set$_queue_list$_table(newTable);
+ }
+ },
+ _writeToList$1: function(target) {
+ var t1, t2, t3, $length, firstPartSize, _this = this;
+ _this.$ti._eval$1("List<1>")._check(target);
+ H.assertHelper(target.length >= _this.get$length(_this));
+ t1 = _this._queue_list$_head;
+ t2 = _this._queue_list$_tail;
+ t3 = _this._queue_list$_table;
+ if (t1 <= t2) {
+ $length = t2 - t1;
+ C.JSArray_methods.setRange$4(target, 0, $length, t3, t1);
+ return $length;
+ } else {
+ firstPartSize = t3.length - t1;
+ C.JSArray_methods.setRange$4(target, 0, firstPartSize, t3, t1);
+ C.JSArray_methods.setRange$4(target, firstPartSize, firstPartSize + _this._queue_list$_tail, _this._queue_list$_table, 0);
+ return _this._queue_list$_tail + firstPartSize;
+ }
+ },
+ _preGrow$1: function(newElementCount) {
+ var newCapacity, t1, newTable, _this = this;
+ H.assertHelper(newElementCount >= _this.get$length(_this));
+ newCapacity = Q.QueueList__nextPowerOf2(newElementCount + C.JSInt_methods._shrOtherPositive$1(newElementCount, 1));
+ if (typeof newCapacity !== "number")
+ return H.iae(newCapacity);
+ t1 = new Array(newCapacity);
+ t1.fixed$length = Array;
+ newTable = H.setRuntimeTypeInfo(t1, _this.$ti._eval$1("JSArray<1>"));
+ _this._queue_list$_tail = _this._writeToList$1(newTable);
+ _this.set$_queue_list$_table(newTable);
+ _this._queue_list$_head = 0;
+ },
+ set$_queue_list$_table: function(_table) {
+ this._queue_list$_table = this.$ti._eval$1("List<1>")._check(_table);
+ },
+ $isEfficientLengthIterable: 1,
+ $isQueue: 1,
+ $isIterable: 1,
+ $isList: 1
+ };
+ Q._QueueList_Object_ListMixin.prototype = {};
+ M.UnionSet.prototype = {
+ get$length: function(_) {
+ var t1 = this._sets.fold$1$2(0, 0, new M.UnionSet_length_closure(this), type$.int);
+ return t1;
+ },
+ get$iterator: function(_) {
+ var t1 = this.get$_union_set$_iterable();
+ return t1.get$iterator(t1);
+ },
+ get$_union_set$_iterable: function() {
+ var t1 = this._sets,
+ t2 = this.$ti._precomputed1,
+ t3 = H._instanceType(t1),
+ t4 = t3._bind$1(t2)._eval$1("Iterable<1>(2)")._check(new M.UnionSet__iterable_closure(this));
+ return new H.ExpandIterable(t1, t4, t3._eval$1("@<1>")._bind$1(t2)._eval$1("ExpandIterable<1,2>"));
+ },
+ toSet$0: function(_) {
+ var t1,
+ result = P.LinkedHashSet_LinkedHashSet(this.$ti._precomputed1);
+ for (t1 = this._sets, t1 = P._LinkedHashSetIterator$(t1, t1._collection$_modifications, H._instanceType(t1)._precomputed1); t1.moveNext$0();)
+ result.addAll$1(0, t1._collection$_current);
+ return result;
+ }
+ };
+ M.UnionSet_length_closure.prototype = {
+ call$2: function($length, set) {
+ var t1;
+ H._checkIntNullable($length);
+ this.$this.$ti._eval$1("Set<1>")._check(set);
+ t1 = set.get$length(set);
+ if (typeof $length !== "number")
+ return $length.$add();
+ if (typeof t1 !== "number")
+ return H.iae(t1);
+ return $length + t1;
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("int(int,Set<1>)");
+ }
+ };
+ M.UnionSet__iterable_closure.prototype = {
+ call$1: function(set) {
+ return this.$this.$ti._eval$1("Set<1>")._check(set);
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("Set<1>(Set<1>)");
+ }
+ };
+ M._UnionSet_SetBase_UnmodifiableSetMixin.prototype = {};
+ Y.UnionSetController.prototype = {
+ set$_union_set_controller$_set: function(_set) {
+ this._union_set_controller$_set = this.$ti._eval$1("UnionSet<1>")._check(_set);
+ }
+ };
+ L.UnmodifiableSetView.prototype = {};
+ L.UnmodifiableSetMixin.prototype = {};
+ L._UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin.prototype = {};
+ M._DelegatingIterableBase.prototype = {
+ contains$1: function(_, element) {
+ return this._base.contains$1(0, element);
+ },
+ every$1: function(_, test) {
+ return this._base.every$1(0, H._instanceType(this)._eval$1("bool(1)")._check(test));
+ },
+ get$first: function(_) {
+ var t1 = this._base;
+ return t1.get$first(t1);
+ },
+ get$isEmpty: function(_) {
+ var t1 = this._base;
+ return t1.get$isEmpty(t1);
+ },
+ get$iterator: function(_) {
+ var t1 = this._base;
+ return t1.get$iterator(t1);
+ },
+ get$last: function(_) {
+ var t1 = this._base;
+ return t1.get$last(t1);
+ },
+ get$length: function(_) {
+ var t1 = this._base;
+ return t1.get$length(t1);
+ },
+ map$1$1: function(_, f, $T) {
+ return this._base.map$1$1(0, H._instanceType(this)._bind$1($T)._eval$1("1(2)")._check(f), $T);
+ },
+ toList$1$growable: function(_, growable) {
+ return this._base.toList$1$growable(0, true);
+ },
+ toList$0: function($receiver) {
+ return this.toList$1$growable($receiver, true);
+ },
+ toSet$0: function(_) {
+ return this._base.toSet$0(0);
+ },
+ where$1: function(_, test) {
+ return this._base.where$1(0, H._instanceType(this)._eval$1("bool(1)")._check(test));
+ },
+ toString$0: function(_) {
+ return this._base.toString$0(0);
+ },
+ $isIterable: 1
+ };
+ M.DelegatingIterable.prototype = {};
+ M.DelegatingSet.prototype = {
+ union$1: function(other) {
+ var t1 = H._instanceType(this)._eval$1("Set<1>");
+ t1._check(other);
+ return t1._check(this._base).union$1(other);
+ },
+ toSet$0: function(_) {
+ var t1 = H._instanceType(this);
+ return new M.DelegatingSet(t1._eval$1("Set<1>")._check(this._base).toSet$0(0), t1._eval$1("DelegatingSet<1>"));
+ },
+ $isEfficientLengthIterable: 1,
+ $isSet: 1
+ };
+ Y._IsTrue.prototype = {
+ matches$2: function(_, item, matchState) {
+ return J.$eq$(item, true);
+ },
+ describe$1: function(description) {
+ description._out._contents += "true";
+ return description;
+ }
+ };
+ Y._Predicate.prototype = {
+ typedMatches$2: function(item, matchState) {
+ return this._matcher.call$1(this.$ti._precomputed1._check(item));
+ },
+ describe$1: function(description) {
+ description._out._contents += this._core_matchers$_description;
+ return description;
+ }
+ };
+ E.StringDescription.prototype = {
+ get$length: function(_) {
+ return this._out._contents.length;
+ },
+ toString$0: function(_) {
+ var t1 = this._out._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ addDescriptionOf$1: function(value) {
+ if (value instanceof G.Matcher)
+ value.describe$1(this);
+ else
+ this._out._contents += Z.prettyPrint(value, 25, 80);
+ return this;
+ },
+ $isDescription: 1
+ };
+ D._StringEqualsMatcher.prototype = {
+ typedMatches$2: function(item, matchState) {
+ return this._equals_matcher$_value === H._checkStringNullable(item);
+ },
+ describe$1: function(description) {
+ return description.addDescriptionOf$1(this._equals_matcher$_value);
+ },
+ describeTypedMismatch$4: function(item, mismatchDescription, matchState, verbose) {
+ var buff, escapedItem, escapedValue, minLength, minLength0, minLength1, start, t1, i;
+ H._checkStringNullable(true);
+ buff = new P.StringBuffer("");
+ buff._contents = "is different.";
+ escapedItem = M.escape(true);
+ escapedValue = M.escape(this._equals_matcher$_value);
+ minLength = escapedItem.length;
+ minLength0 = escapedValue.length;
+ minLength1 = minLength < minLength0 ? minLength : minLength0;
+ for (start = 0; start < minLength1; ++start)
+ if (C.JSString_methods._codeUnitAt$1(escapedValue, start) !== C.JSString_methods._codeUnitAt$1(escapedItem, start))
+ break;
+ if (start === minLength1) {
+ t1 = buff._contents;
+ if (minLength0 < minLength) {
+ buff._contents = t1 + " Both strings start the same, but the actual value also has the following trailing characters: ";
+ D._StringEqualsMatcher__writeTrailing(buff, escapedItem, minLength0);
+ } else {
+ buff._contents = t1 + " Both strings start the same, but the actual value is missing the following trailing characters: ";
+ D._StringEqualsMatcher__writeTrailing(buff, escapedValue, minLength);
+ }
+ } else {
+ buff._contents += "\nExpected: ";
+ D._StringEqualsMatcher__writeLeading(buff, escapedValue, start);
+ D._StringEqualsMatcher__writeTrailing(buff, escapedValue, start);
+ buff._contents += "\n Actual: ";
+ D._StringEqualsMatcher__writeLeading(buff, escapedItem, start);
+ D._StringEqualsMatcher__writeTrailing(buff, escapedItem, start);
+ t1 = buff._contents += "\n ";
+ i = start > 10 ? 14 : start;
+ for (; i > 0; --i) {
+ t1 += " ";
+ buff._contents = t1;
+ }
+ buff._contents += "^\n Differ at offset " + start;
+ }
+ t1 = buff._contents;
+ mismatchDescription._out._contents += t1.charCodeAt(0) == 0 ? t1 : t1;
+ return mismatchDescription;
+ }
+ };
+ D._DeepMatcher.prototype = {
+ _compareIterables$5: function(expected, actual, matcher, depth, $location) {
+ var expectedIterator, actualIterator, index, expectedNext, actualNext, t1, newLocation, rp;
+ type$.List_String_Function_dynamic_dynamic_String_int._check(matcher);
+ if (type$.Iterable_dynamic._is(actual)) {
+ expectedIterator = J.get$iterator$ax(expected);
+ actualIterator = J.get$iterator$ax(actual);
+ for (index = 0; true; ++index) {
+ expectedNext = expectedIterator.moveNext$0();
+ actualNext = actualIterator.moveNext$0();
+ t1 = !expectedNext;
+ if (t1 && !actualNext)
+ return null;
+ newLocation = $location + "[" + index + "]";
+ if (t1)
+ return H.setRuntimeTypeInfo(["longer than expected", newLocation], type$.JSArray_String);
+ if (!actualNext)
+ return H.setRuntimeTypeInfo(["shorter than expected", newLocation], type$.JSArray_String);
+ rp = matcher.call$4(expectedIterator.get$current(), actualIterator.get$current(), newLocation, depth);
+ if (rp != null)
+ return rp;
+ }
+ } else
+ return H.setRuntimeTypeInfo(["is not Iterable", $location], type$.JSArray_String);
+ },
+ _compareSets$5: function(expected, actual, matcher, depth, $location) {
+ var other, t1, expectedElement, t2;
+ type$.List_String_Function_dynamic_dynamic_String_int._check(matcher);
+ if (type$.Iterable_dynamic._is(actual)) {
+ other = J.toSet$0$ax(actual);
+ for (t1 = expected.get$iterator(expected); t1.moveNext$0();) {
+ expectedElement = t1.get$current();
+ if (other.every$1(0, new D._DeepMatcher__compareSets_closure(matcher, expectedElement, $location, depth)))
+ return H.setRuntimeTypeInfo(["does not contain " + H.S(expectedElement), $location], type$.JSArray_String);
+ }
+ t1 = other.get$length(other);
+ t2 = expected.get$length(expected);
+ if (typeof t2 !== "number")
+ return H.iae(t2);
+ if (t1 > t2)
+ return H.setRuntimeTypeInfo(["larger than expected", $location], type$.JSArray_String);
+ else {
+ t1 = other.get$length(other);
+ t2 = expected.get$length(expected);
+ if (typeof t2 !== "number")
+ return H.iae(t2);
+ if (t1 < t2)
+ return H.setRuntimeTypeInfo(["smaller than expected", $location], type$.JSArray_String);
+ else
+ return null;
+ }
+ } else
+ return H.setRuntimeTypeInfo(["is not Iterable", $location], type$.JSArray_String);
+ },
+ _recursiveMatch$4: function(expected, actual, $location, depth) {
+ var e, t1, description, exception, err, key, t2, rp, _this = this;
+ if (expected instanceof G.Matcher) {
+ t1 = type$.dynamic;
+ if (expected.matches$2(0, actual, P.LinkedHashMap_LinkedHashMap$_empty(t1, t1)))
+ return null;
+ description = new E.StringDescription(new P.StringBuffer(""));
+ expected.describe$1(description);
+ return H.setRuntimeTypeInfo(["does not match " + description.toString$0(0), $location], type$.JSArray_String);
+ } else
+ try {
+ if (J.$eq$(expected, actual))
+ return null;
+ } catch (exception) {
+ e = H.unwrapException(exception);
+ t1 = H.setRuntimeTypeInfo(['== threw "' + H.S(e) + '"', $location], type$.JSArray_String);
+ return t1;
+ }
+ t1 = _this._limit;
+ if (depth > t1)
+ return H.setRuntimeTypeInfo(["recursion depth limit exceeded", $location], type$.JSArray_String);
+ if (depth === 0 || t1 > 1)
+ if (type$.Set_dynamic._is(expected))
+ return _this._compareSets$5(expected, actual, _this.get$_recursiveMatch(), depth + 1, $location);
+ else if (type$.Iterable_dynamic._is(expected))
+ return _this._compareIterables$5(expected, actual, _this.get$_recursiveMatch(), depth + 1, $location);
+ else {
+ t1 = type$.Map_dynamic_dynamic;
+ if (t1._is(expected)) {
+ if (!t1._is(actual))
+ return H.setRuntimeTypeInfo(["expected a map", $location], type$.JSArray_String);
+ err = expected.get$length(expected) == actual.get$length(actual) ? "" : "has different length and ";
+ for (t1 = expected.get$keys(), t1 = t1.get$iterator(t1); t1.moveNext$0();) {
+ key = t1.get$current();
+ if (!actual.containsKey$1(key))
+ return H.setRuntimeTypeInfo([err + "is missing map key '" + H.S(key) + "'", $location], type$.JSArray_String);
+ }
+ for (t1 = actual.get$keys(), t1 = t1.get$iterator(t1); t1.moveNext$0();) {
+ key = t1.get$current();
+ if (!expected.containsKey$1(key))
+ return H.setRuntimeTypeInfo([err + "has extra map key '" + H.S(key) + "'", $location], type$.JSArray_String);
+ }
+ for (t1 = expected.get$keys(), t1 = t1.get$iterator(t1), t2 = depth + 1; t1.moveNext$0();) {
+ key = t1.get$current();
+ rp = _this._recursiveMatch$4(expected.$index(0, key), actual.$index(0, key), $location + "['" + H.S(key) + "']", t2);
+ if (rp != null)
+ return rp;
+ }
+ return null;
+ }
+ }
+ t1 = new P.StringBuffer("");
+ if (depth > 0) {
+ t1._contents = "was ";
+ t2 = new E.StringDescription(t1).addDescriptionOf$1(actual);
+ t2._out._contents += " instead of ";
+ t2.addDescriptionOf$1(expected);
+ t1 = t1._contents;
+ return H.setRuntimeTypeInfo([t1.charCodeAt(0) == 0 ? t1 : t1, $location], type$.JSArray_String);
+ }
+ return H.setRuntimeTypeInfo(["", $location], type$.JSArray_String);
+ },
+ _equals_matcher$_match$3: function(expected, actual, matchState) {
+ var t1, t2, reason, innerState,
+ rp = this._recursiveMatch$4(expected, actual, "", 0);
+ if (rp == null)
+ return null;
+ t1 = J.getInterceptor$asx(rp);
+ t2 = t1.$index(rp, 0);
+ t2.toString;
+ if (J.get$length$asx(t2) !== 0) {
+ t2 = t1.$index(rp, 1);
+ t2.toString;
+ reason = J.get$length$asx(t2) !== 0 ? H.S(t1.$index(rp, 0)) + " at location " + H.S(t1.$index(rp, 1)) : t1.$index(rp, 0);
+ } else
+ reason = "";
+ t1 = type$.dynamic;
+ t2 = P.LinkedHashMap_LinkedHashMap$_literal(["reason", reason], t1, t1);
+ innerState = P.LinkedHashMap_LinkedHashMap$from(matchState, t1, t1);
+ matchState.clear$0(0);
+ matchState.$indexSet(0, "state", innerState);
+ matchState.addAll$1(0, t2);
+ return reason;
+ },
+ matches$2: function(_, item, matchState) {
+ return this._equals_matcher$_match$3(this._expected, item, matchState) == null;
+ },
+ describe$1: function(description) {
+ return description.addDescriptionOf$1(this._expected);
+ },
+ describeMismatch$4: function(item, mismatchDescription, matchState, verbose) {
+ var t1, t2, t3,
+ reason = H._asStringNullable(matchState.$index(0, "reason"));
+ if (reason == null)
+ reason = "";
+ t1 = reason.length === 0 && mismatchDescription._out._contents.length > 0;
+ t2 = mismatchDescription._out;
+ t3 = t2._contents;
+ if (t1) {
+ t2._contents = t3 + "is ";
+ mismatchDescription.addDescriptionOf$1(true);
+ } else
+ t2._contents = t3 + reason;
+ return mismatchDescription;
+ }
+ };
+ D._DeepMatcher__compareSets_closure.prototype = {
+ call$1: function(actualElement) {
+ var _this = this;
+ return _this.matcher.call$4(_this.expectedElement, actualElement, _this.location, _this.depth) != null;
+ },
+ $signature: 9
+ };
+ E.FeatureMatcher.prototype = {
+ matches$2: function(_, item, matchState) {
+ return this.super$TypeMatcher$matches(0, item, matchState) && H.boolConversionCheck(this.typedMatches$2(H._instanceType(this)._eval$1("FeatureMatcher.T")._check(item), matchState));
+ },
+ describeMismatch$4: function(item, mismatchDescription, matchState, verbose) {
+ if (H._instanceType(this)._eval$1("FeatureMatcher.T")._is(true))
+ return this.describeTypedMismatch$4(true, mismatchDescription, matchState, false);
+ mismatchDescription._out._contents += "not an ";
+ return this.super$TypeMatcher$describe(mismatchDescription);
+ },
+ describeTypedMismatch$4: function(item, mismatchDescription, matchState, verbose) {
+ H._instanceType(this)._eval$1("FeatureMatcher.T")._check(true);
+ return mismatchDescription;
+ }
+ };
+ G.Matcher.prototype = {
+ describeMismatch$4: function(item, mismatchDescription, matchState, verbose) {
+ return mismatchDescription;
+ }
+ };
+ Z.prettyPrint__prettyPrint.prototype = {
+ call$4: function(object, indent, seen, $top) {
+ var description, type, t2, strings, t3, singleLine, value, defaultToString, _this = this, t1 = {};
+ t1.seen = seen;
+ if (object instanceof G.Matcher) {
+ description = new E.StringDescription(new P.StringBuffer(""));
+ object.describe$1(description);
+ return "<" + description.toString$0(0) + ">";
+ }
+ if (seen.contains$1(0, object))
+ return "(recursive)";
+ t1.seen = seen.union$1(P.LinkedHashSet_LinkedHashSet$_literal([object], type$.dynamic));
+ t1 = new Z.prettyPrint__prettyPrint_pp(t1, _this, indent);
+ if (type$.Iterable_dynamic._is(object)) {
+ type = type$.List_dynamic._is(object) ? "" : Z._typeName(object) + ":";
+ t2 = type$.String;
+ strings = J.map$1$1$ax(object, t1, t2).toList$0(0);
+ t1 = strings.length;
+ t3 = _this.maxItems;
+ if (t1 > t3)
+ C.JSArray_methods.replaceRange$3(strings, t3 - 1, t1, H.setRuntimeTypeInfo(["..."], type$.JSArray_String));
+ singleLine = type + "[" + C.JSArray_methods.join$1(strings, ", ") + "]";
+ if (singleLine.length + indent <= _this.maxLineLength && !C.JSString_methods.contains$1(singleLine, "\n"))
+ return singleLine;
+ t1 = H._arrayInstanceType(strings);
+ return type + "[\n" + new H.MappedListIterable(strings, t1._eval$1("String(1)")._check(new Z.prettyPrint__prettyPrint_closure(indent)), t1._eval$1("MappedListIterable<1,String>")).join$1(0, ",\n") + "\n" + C.JSArray_methods.join$1(P.List_List$filled(indent, " ", t2), "") + "]";
+ } else if (type$.Map_dynamic_dynamic._is(object)) {
+ t2 = type$.String;
+ strings = object.get$keys().map$1$1(0, new Z.prettyPrint__prettyPrint_closure0(t1, object), t2).toList$0(0);
+ t1 = strings.length;
+ t3 = _this.maxItems;
+ if (t1 > t3)
+ C.JSArray_methods.replaceRange$3(strings, t3 - 1, t1, H.setRuntimeTypeInfo(["..."], type$.JSArray_String));
+ singleLine = "{" + C.JSArray_methods.join$1(strings, ", ") + "}";
+ if (singleLine.length + indent <= _this.maxLineLength && !C.JSString_methods.contains$1(singleLine, "\n"))
+ return singleLine;
+ t1 = H._arrayInstanceType(strings);
+ return "{\n" + new H.MappedListIterable(strings, t1._eval$1("String(1)")._check(new Z.prettyPrint__prettyPrint_closure1(indent)), t1._eval$1("MappedListIterable<1,String>")).join$1(0, ",\n") + "\n" + C.JSArray_methods.join$1(P.List_List$filled(indent, " ", t2), "") + "}";
+ } else {
+ t1 = type$.String;
+ if (typeof object == "string")
+ return "'" + new H.MappedListIterable(H.setRuntimeTypeInfo(object.split("\n"), type$.JSArray_String), type$.String_Function_String._check(Z.pretty_print___escapeString$closure()), type$.MappedListIterable_String_String).join$1(0, "\\n'\n" + C.JSArray_methods.join$1(P.List_List$filled(indent + 2, " ", t1), "") + "'") + "'";
+ else {
+ t2 = J.toString$0$(object);
+ t1 = C.JSArray_methods.join$1(P.List_List$filled(indent, " ", t1), "") + "\n";
+ t2.toString;
+ value = H.stringReplaceAllUnchecked(t2, "\n", t1);
+ defaultToString = C.JSString_methods.startsWith$1(value, "Instance of ");
+ if ($top)
+ value = "<" + value + ">";
+ if (typeof object == "number" || H._isBool(object) || type$.Function._is(object) || type$.RegExp._is(object) || object instanceof P.MapEntry || object instanceof P.Expando || object == null || defaultToString)
+ return value;
+ else
+ return Z._typeName(object) + ":" + value;
+ }
+ }
+ },
+ $signature: 55
+ };
+ Z.prettyPrint__prettyPrint_pp.prototype = {
+ call$1: function(child) {
+ return this._prettyPrint.call$4(child, this.indent + 2, this._box_0.seen, false);
+ },
+ $signature: 40
+ };
+ Z.prettyPrint__prettyPrint_closure.prototype = {
+ call$1: function(string) {
+ H._checkStringNullable(string);
+ return C.JSString_methods.$add(C.JSArray_methods.join$1(P.List_List$filled(this.indent + 2, " ", type$.String), ""), string);
+ },
+ $signature: 7
+ };
+ Z.prettyPrint__prettyPrint_closure0.prototype = {
+ call$1: function(key) {
+ var t1 = this.pp;
+ return H.S(t1.call$1(key)) + ": " + H.S(t1.call$1(this.object.$index(0, key)));
+ },
+ $signature: 40
+ };
+ Z.prettyPrint__prettyPrint_closure1.prototype = {
+ call$1: function(string) {
+ H._checkStringNullable(string);
+ return C.JSString_methods.$add(C.JSArray_methods.join$1(P.List_List$filled(this.indent + 2, " ", type$.String), ""), string);
+ },
+ $signature: 7
+ };
+ M.TypeMatcher.prototype = {
+ describe$1: function(description) {
+ var $name,
+ t1 = H._rtiToString(H.createRuntimeType(H._instanceType(this)._eval$1("TypeMatcher.T"))._rti, null),
+ t2 = $.$get$_dart2DynamicArgs();
+ t1.toString;
+ $name = H.stringReplaceAllUnchecked(t1, t2, "");
+ description._out._contents += "<Instance of '" + $name + "'>";
+ return description;
+ },
+ matches$2: function(_, item, matchState) {
+ return H._instanceType(this)._eval$1("TypeMatcher.T")._is(item);
+ }
+ };
+ M.wrapMatcher_closure.prototype = {
+ call$1: function(a) {
+ return H._checkBoolNullable(this.x.call$1(a));
+ },
+ $signature: 9
+ };
+ M.escape_closure.prototype = {
+ call$1: function(match) {
+ var mapped = C.Map_F9GZw.$index(0, match.$index(0, 0));
+ if (mapped != null)
+ return mapped;
+ return M._getHexLiteral(match.$index(0, 0));
+ },
+ $signature: 24
+ };
+ F.PackageConfigResolver.prototype = {$isSyncPackageResolver: 1,
+ get$packageRoot: function() {
+ return null;
+ },
+ get$packageConfigMap: function() {
+ return this.packageConfigMap;
+ }
+ };
+ F.PackageConfigResolver__normalizeMap_closure.prototype = {
+ call$2: function(_, uri) {
+ return B.ensureTrailingSlash(type$.Uri._check(uri));
+ },
+ $signature: 51
+ };
+ D.PackageRootResolver.prototype = {$isSyncPackageResolver: 1,
+ get$packageConfigMap: function() {
+ return null;
+ },
+ get$packageRoot: function() {
+ return this.packageRoot;
+ }
+ };
+ M.Context.prototype = {
+ absolute$7: function(_, part1, part2, part3, part4, part5, part6, part7) {
+ var t1;
+ M._validateArgList("absolute", H.setRuntimeTypeInfo([part1, part2, part3, part4, part5, part6, part7], type$.JSArray_String));
+ t1 = this.style;
+ t1 = t1.rootLength$1(part1) > 0 && !t1.isRootRelative$1(part1);
+ if (t1)
+ return part1;
+ t1 = this._context$_current;
+ return this.join$8(0, t1 != null ? t1 : D.current(), part1, part2, part3, part4, part5, part6, part7);
+ },
+ absolute$1: function($receiver, part1) {
+ return this.absolute$7($receiver, part1, null, null, null, null, null, null);
+ },
+ join$8: function(_, part1, part2, part3, part4, part5, part6, part7, part8) {
+ var parts = H.setRuntimeTypeInfo([part1, part2, part3, part4, part5, part6, part7, part8], type$.JSArray_String);
+ M._validateArgList("join", parts);
+ return this.joinAll$1(new H.WhereIterable(parts, type$.bool_Function_String._check(new M.Context_join_closure()), type$.WhereIterable_String));
+ },
+ join$2: function($receiver, part1, part2) {
+ return this.join$8($receiver, part1, part2, null, null, null, null, null, null);
+ },
+ joinAll$1: function(parts) {
+ var t1, t2, t3, needsSeparator, isAbsoluteAndNotRootRelative, t4, t5, parsed, path, t6;
+ type$.Iterable_String._check(parts);
+ for (t1 = parts.$ti, t2 = t1._eval$1("bool(Iterable.E)")._check(new M.Context_joinAll_closure()), t3 = parts.get$iterator(parts), t1 = new H.WhereIterator(t3, t2, t1._eval$1("WhereIterator<Iterable.E>")), t2 = this.style, needsSeparator = false, isAbsoluteAndNotRootRelative = false, t4 = ""; t1.moveNext$0();) {
+ t5 = t3.get$current();
+ if (t2.isRootRelative$1(t5) && isAbsoluteAndNotRootRelative) {
+ parsed = X.ParsedPath_ParsedPath$parse(t5, t2);
+ path = t4.charCodeAt(0) == 0 ? t4 : t4;
+ t4 = C.JSString_methods.substring$2(path, 0, t2.rootLength$2$withDrive(path, true));
+ parsed.root = t4;
+ if (t2.needsSeparator$1(t4))
+ C.JSArray_methods.$indexSet(parsed.separators, 0, t2.get$separator());
+ t4 = parsed.toString$0(0);
+ } else if (t2.rootLength$1(t5) > 0) {
+ isAbsoluteAndNotRootRelative = !t2.isRootRelative$1(t5);
+ t4 = H.S(t5);
+ } else {
+ t6 = t5.length;
+ if (t6 !== 0) {
+ if (0 >= t6)
+ return H.ioore(t5, 0);
+ t6 = t2.containsSeparator$1(t5[0]);
+ } else
+ t6 = false;
+ if (!t6)
+ if (needsSeparator)
+ t4 += t2.get$separator();
+ t4 += t5;
+ }
+ needsSeparator = t2.needsSeparator$1(t5);
+ }
+ return t4.charCodeAt(0) == 0 ? t4 : t4;
+ },
+ split$1: function(_, path) {
+ var parsed = X.ParsedPath_ParsedPath$parse(path, this.style),
+ t1 = parsed.parts,
+ t2 = H._arrayInstanceType(t1),
+ t3 = t2._eval$1("WhereIterable<1>");
+ parsed.set$parts(P.List_List$from(new H.WhereIterable(t1, t2._eval$1("bool(1)")._check(new M.Context_split_closure()), t3), true, t3._eval$1("Iterable.E")));
+ t1 = parsed.root;
+ if (t1 != null)
+ C.JSArray_methods.insert$2(parsed.parts, 0, t1);
+ return parsed.parts;
+ },
+ normalize$1: function(path) {
+ var parsed;
+ if (!this._needsNormalization$1(path))
+ return path;
+ parsed = X.ParsedPath_ParsedPath$parse(path, this.style);
+ parsed.normalize$0();
+ return parsed.toString$0(0);
+ },
+ _needsNormalization$1: function(path) {
+ var t1, root, i, start, previous, t2, t3, previousPrevious, codeUnit, t4;
+ path.toString;
+ t1 = this.style;
+ root = t1.rootLength$1(path);
+ if (root !== 0) {
+ if (t1 === $.$get$Style_windows())
+ for (i = 0; i < root; ++i)
+ if (C.JSString_methods._codeUnitAt$1(path, i) === 47)
+ return true;
+ start = root;
+ previous = 47;
+ } else {
+ start = 0;
+ previous = null;
+ }
+ for (t2 = new H.CodeUnits(path)._string, t3 = t2.length, i = start, previousPrevious = null; i < t3; ++i, previousPrevious = previous, previous = codeUnit) {
+ codeUnit = C.JSString_methods.codeUnitAt$1(t2, i);
+ if (t1.isSeparator$1(codeUnit)) {
+ if (t1 === $.$get$Style_windows() && codeUnit === 47)
+ return true;
+ if (previous != null && t1.isSeparator$1(previous))
+ return true;
+ if (previous === 46)
+ t4 = previousPrevious == null || previousPrevious === 46 || t1.isSeparator$1(previousPrevious);
+ else
+ t4 = false;
+ if (t4)
+ return true;
+ }
+ }
+ if (previous == null)
+ return true;
+ if (t1.isSeparator$1(previous))
+ return true;
+ if (previous === 46)
+ t1 = previousPrevious == null || t1.isSeparator$1(previousPrevious) || previousPrevious === 46;
+ else
+ t1 = false;
+ if (t1)
+ return true;
+ return false;
+ },
+ relative$2$from: function(path, from) {
+ var fromParsed, pathParsed, t2, t3, t4, t5, _this = this,
+ _s26_ = 'Unable to find a path to "',
+ t1 = from == null;
+ if (t1 && _this.style.rootLength$1(path) <= 0)
+ return _this.normalize$1(path);
+ if (t1) {
+ t1 = _this._context$_current;
+ from = t1 != null ? t1 : D.current();
+ } else
+ from = _this.absolute$1(0, from);
+ t1 = _this.style;
+ if (t1.rootLength$1(from) <= 0 && t1.rootLength$1(path) > 0)
+ return _this.normalize$1(path);
+ if (t1.rootLength$1(path) <= 0 || t1.isRootRelative$1(path))
+ path = _this.absolute$1(0, path);
+ if (t1.rootLength$1(path) <= 0 && t1.rootLength$1(from) > 0)
+ throw H.wrapException(X.PathException$(_s26_ + H.S(path) + '" from "' + H.S(from) + '".'));
+ fromParsed = X.ParsedPath_ParsedPath$parse(from, t1);
+ fromParsed.normalize$0();
+ pathParsed = X.ParsedPath_ParsedPath$parse(path, t1);
+ pathParsed.normalize$0();
+ t2 = fromParsed.parts;
+ t3 = t2.length;
+ if (t3 !== 0) {
+ if (0 >= t3)
+ return H.ioore(t2, 0);
+ t2 = J.$eq$(t2[0], ".");
+ } else
+ t2 = false;
+ if (t2)
+ return pathParsed.toString$0(0);
+ t2 = fromParsed.root;
+ t3 = pathParsed.root;
+ if (t2 != t3)
+ t2 = t2 == null || t3 == null || !t1.pathsEqual$2(t2, t3);
+ else
+ t2 = false;
+ if (t2)
+ return pathParsed.toString$0(0);
+ while (true) {
+ t2 = fromParsed.parts;
+ t3 = t2.length;
+ if (t3 !== 0) {
+ t4 = pathParsed.parts;
+ t5 = t4.length;
+ if (t5 !== 0) {
+ if (0 >= t3)
+ return H.ioore(t2, 0);
+ t2 = t2[0];
+ if (0 >= t5)
+ return H.ioore(t4, 0);
+ t4 = t1.pathsEqual$2(t2, t4[0]);
+ t2 = t4;
+ } else
+ t2 = false;
+ } else
+ t2 = false;
+ if (!t2)
+ break;
+ C.JSArray_methods.removeAt$1(fromParsed.parts, 0);
+ C.JSArray_methods.removeAt$1(fromParsed.separators, 1);
+ C.JSArray_methods.removeAt$1(pathParsed.parts, 0);
+ C.JSArray_methods.removeAt$1(pathParsed.separators, 1);
+ }
+ t2 = fromParsed.parts;
+ t3 = t2.length;
+ if (t3 !== 0) {
+ if (0 >= t3)
+ return H.ioore(t2, 0);
+ t2 = J.$eq$(t2[0], "..");
+ } else
+ t2 = false;
+ if (t2)
+ throw H.wrapException(X.PathException$(_s26_ + H.S(path) + '" from "' + H.S(from) + '".'));
+ t2 = type$.String;
+ C.JSArray_methods.insertAll$2(pathParsed.parts, 0, P.List_List$filled(fromParsed.parts.length, "..", t2));
+ C.JSArray_methods.$indexSet(pathParsed.separators, 0, "");
+ C.JSArray_methods.insertAll$2(pathParsed.separators, 1, P.List_List$filled(fromParsed.parts.length, t1.get$separator(), t2));
+ t1 = pathParsed.parts;
+ t2 = t1.length;
+ if (t2 === 0)
+ return ".";
+ if (t2 > 1 && J.$eq$(C.JSArray_methods.get$last(t1), ".")) {
+ C.JSArray_methods.removeLast$0(pathParsed.parts);
+ t1 = pathParsed.separators;
+ C.JSArray_methods.removeLast$0(t1);
+ C.JSArray_methods.removeLast$0(t1);
+ C.JSArray_methods.add$1(t1, "");
+ }
+ pathParsed.root = "";
+ pathParsed.removeTrailingSeparators$0();
+ return pathParsed.toString$0(0);
+ },
+ relative$1: function(path) {
+ return this.relative$2$from(path, null);
+ },
+ _isWithinOrEquals$2: function($parent, child) {
+ var relative, childIsRootRelative, parentIsRootRelative, result, exception, _this = this,
+ t1 = _this.style,
+ parentIsAbsolute = t1.rootLength$1(H._checkStringNullable($parent)) > 0,
+ childIsAbsolute = t1.rootLength$1(H._checkStringNullable(child)) > 0;
+ if (parentIsAbsolute && !childIsAbsolute) {
+ child = _this.absolute$1(0, child);
+ if (t1.isRootRelative$1($parent))
+ $parent = _this.absolute$1(0, $parent);
+ } else if (childIsAbsolute && !parentIsAbsolute) {
+ $parent = _this.absolute$1(0, $parent);
+ if (t1.isRootRelative$1(child))
+ child = _this.absolute$1(0, child);
+ } else if (childIsAbsolute && parentIsAbsolute) {
+ childIsRootRelative = t1.isRootRelative$1(child);
+ parentIsRootRelative = t1.isRootRelative$1($parent);
+ if (childIsRootRelative && !parentIsRootRelative)
+ child = _this.absolute$1(0, child);
+ else if (parentIsRootRelative && !childIsRootRelative)
+ $parent = _this.absolute$1(0, $parent);
+ }
+ result = _this._isWithinOrEqualsFast$2($parent, child);
+ if (result !== C._PathRelation_inconclusive)
+ return result;
+ relative = null;
+ try {
+ relative = _this.relative$2$from(child, $parent);
+ } catch (exception) {
+ if (H.unwrapException(exception) instanceof X.PathException)
+ return C._PathRelation_different;
+ else
+ throw exception;
+ }
+ if (t1.rootLength$1(H._checkStringNullable(relative)) > 0)
+ return C._PathRelation_different;
+ if (J.$eq$(relative, "."))
+ return C._PathRelation_equal;
+ if (J.$eq$(relative, ".."))
+ return C._PathRelation_different;
+ return J.get$length$asx(relative) >= 3 && J.startsWith$1$s(relative, "..") && t1.isSeparator$1(J.codeUnitAt$1$s(relative, 2)) ? C._PathRelation_different : C._PathRelation_within;
+ },
+ _isWithinOrEqualsFast$2: function($parent, child) {
+ var t1, parentRootLength, childRootLength, t2, t3, i, childIndex, parentIndex, lastCodeUnit, lastParentSeparator, parentCodeUnit, childCodeUnit, parentIndex0, t4, direction, _this = this;
+ if ($parent === ".")
+ $parent = "";
+ t1 = _this.style;
+ parentRootLength = t1.rootLength$1($parent);
+ childRootLength = t1.rootLength$1(child);
+ if (parentRootLength !== childRootLength)
+ return C._PathRelation_different;
+ for (t2 = J.getInterceptor$s($parent), t3 = J.getInterceptor$s(child), i = 0; i < parentRootLength; ++i)
+ if (!t1.codeUnitsEqual$2(t2._codeUnitAt$1($parent, i), t3._codeUnitAt$1(child, i)))
+ return C._PathRelation_different;
+ t2 = $parent.length;
+ childIndex = childRootLength;
+ parentIndex = parentRootLength;
+ lastCodeUnit = 47;
+ lastParentSeparator = null;
+ while (true) {
+ if (!(parentIndex < t2 && childIndex < child.length))
+ break;
+ c$0: {
+ parentCodeUnit = C.JSString_methods.codeUnitAt$1($parent, parentIndex);
+ childCodeUnit = t3.codeUnitAt$1(child, childIndex);
+ if (t1.codeUnitsEqual$2(parentCodeUnit, childCodeUnit)) {
+ if (t1.isSeparator$1(parentCodeUnit))
+ lastParentSeparator = parentIndex;
+ ++parentIndex;
+ ++childIndex;
+ lastCodeUnit = parentCodeUnit;
+ break c$0;
+ }
+ if (t1.isSeparator$1(parentCodeUnit) && t1.isSeparator$1(lastCodeUnit)) {
+ parentIndex0 = parentIndex + 1;
+ lastParentSeparator = parentIndex;
+ parentIndex = parentIndex0;
+ break c$0;
+ } else if (t1.isSeparator$1(childCodeUnit) && t1.isSeparator$1(lastCodeUnit)) {
+ ++childIndex;
+ break c$0;
+ }
+ if (parentCodeUnit === 46 && t1.isSeparator$1(lastCodeUnit)) {
+ ++parentIndex;
+ if (parentIndex === t2)
+ break;
+ parentCodeUnit = C.JSString_methods.codeUnitAt$1($parent, parentIndex);
+ if (t1.isSeparator$1(parentCodeUnit)) {
+ parentIndex0 = parentIndex + 1;
+ lastParentSeparator = parentIndex;
+ parentIndex = parentIndex0;
+ break c$0;
+ }
+ if (parentCodeUnit === 46) {
+ ++parentIndex;
+ if (parentIndex === t2 || t1.isSeparator$1(C.JSString_methods.codeUnitAt$1($parent, parentIndex)))
+ return C._PathRelation_inconclusive;
+ }
+ }
+ if (childCodeUnit === 46 && t1.isSeparator$1(lastCodeUnit)) {
+ ++childIndex;
+ t4 = child.length;
+ if (childIndex === t4)
+ break;
+ childCodeUnit = C.JSString_methods.codeUnitAt$1(child, childIndex);
+ if (t1.isSeparator$1(childCodeUnit)) {
+ ++childIndex;
+ break c$0;
+ }
+ if (childCodeUnit === 46) {
+ ++childIndex;
+ if (childIndex === t4 || t1.isSeparator$1(C.JSString_methods.codeUnitAt$1(child, childIndex)))
+ return C._PathRelation_inconclusive;
+ }
+ }
+ if (_this._pathDirection$2(child, childIndex) !== C._PathDirection_988)
+ return C._PathRelation_inconclusive;
+ if (_this._pathDirection$2($parent, parentIndex) !== C._PathDirection_988)
+ return C._PathRelation_inconclusive;
+ return C._PathRelation_different;
+ }
+ }
+ if (childIndex === child.length) {
+ if (parentIndex === t2 || t1.isSeparator$1(C.JSString_methods.codeUnitAt$1($parent, parentIndex)))
+ lastParentSeparator = parentIndex;
+ else if (lastParentSeparator == null)
+ lastParentSeparator = Math.max(0, parentRootLength - 1);
+ direction = _this._pathDirection$2($parent, lastParentSeparator);
+ if (direction === C._PathDirection_8Gl)
+ return C._PathRelation_equal;
+ return direction === C._PathDirection_ZGD ? C._PathRelation_inconclusive : C._PathRelation_different;
+ }
+ direction = _this._pathDirection$2(child, childIndex);
+ if (direction === C._PathDirection_8Gl)
+ return C._PathRelation_equal;
+ if (direction === C._PathDirection_ZGD)
+ return C._PathRelation_inconclusive;
+ return t1.isSeparator$1(C.JSString_methods.codeUnitAt$1(child, childIndex)) || t1.isSeparator$1(lastCodeUnit) ? C._PathRelation_within : C._PathRelation_different;
+ },
+ _pathDirection$2: function(path, index) {
+ var t1, t2, i, depth, reachedRoot, i0, t3;
+ for (t1 = path.length, t2 = this.style, i = index, depth = 0, reachedRoot = false; i < t1;) {
+ while (true) {
+ if (!(i < t1 && t2.isSeparator$1(C.JSString_methods.codeUnitAt$1(path, i))))
+ break;
+ ++i;
+ }
+ if (i === t1)
+ break;
+ i0 = i;
+ while (true) {
+ if (!(i0 < t1 && !t2.isSeparator$1(C.JSString_methods.codeUnitAt$1(path, i0))))
+ break;
+ ++i0;
+ }
+ t3 = i0 - i;
+ if (!(t3 === 1 && C.JSString_methods.codeUnitAt$1(path, i) === 46))
+ if (t3 === 2 && C.JSString_methods.codeUnitAt$1(path, i) === 46 && C.JSString_methods.codeUnitAt$1(path, i + 1) === 46) {
+ --depth;
+ if (depth < 0)
+ break;
+ if (depth === 0)
+ reachedRoot = true;
+ } else
+ ++depth;
+ if (i0 === t1)
+ break;
+ i = i0 + 1;
+ }
+ if (depth < 0)
+ return C._PathDirection_ZGD;
+ if (depth === 0)
+ return C._PathDirection_8Gl;
+ if (reachedRoot)
+ return C._PathDirection_FIw;
+ return C._PathDirection_988;
+ },
+ toUri$1: function(path) {
+ var t2,
+ t1 = this.style;
+ if (t1.rootLength$1(path) <= 0)
+ return t1.relativePathToUri$1(path);
+ else {
+ t2 = this._context$_current;
+ return t1.absolutePathToUri$1(this.join$2(0, t2 != null ? t2 : D.current(), path));
+ }
+ },
+ prettyUri$1: function(uri) {
+ var path, rel, _this = this,
+ typedUri = M._parseUri(uri);
+ if (typedUri.get$scheme() === "file" && _this.style == $.$get$Style_url())
+ return typedUri.toString$0(0);
+ else if (typedUri.get$scheme() !== "file" && typedUri.get$scheme() !== "" && _this.style != $.$get$Style_url())
+ return typedUri.toString$0(0);
+ path = _this.normalize$1(_this.style.pathFromUri$1(M._parseUri(typedUri)));
+ rel = _this.relative$1(path);
+ return _this.split$1(0, rel).length > _this.split$1(0, path).length ? path : rel;
+ }
+ };
+ M.Context_join_closure.prototype = {
+ call$1: function(part) {
+ return H._checkStringNullable(part) != null;
+ },
+ $signature: 4
+ };
+ M.Context_joinAll_closure.prototype = {
+ call$1: function(part) {
+ return H._checkStringNullable(part) !== "";
+ },
+ $signature: 4
+ };
+ M.Context_split_closure.prototype = {
+ call$1: function(part) {
+ return H._checkStringNullable(part).length !== 0;
+ },
+ $signature: 4
+ };
+ M._validateArgList_closure.prototype = {
+ call$1: function(arg) {
+ H._checkStringNullable(arg);
+ return arg == null ? "null" : '"' + arg + '"';
+ },
+ $signature: 7
+ };
+ M._PathDirection.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ M._PathRelation.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ B.InternalStyle.prototype = {
+ getRoot$1: function(path) {
+ var t1,
+ $length = this.rootLength$1(path);
+ if ($length > 0)
+ return J.substring$2$s(path, 0, $length);
+ if (this.isRootRelative$1(path)) {
+ if (0 >= path.length)
+ return H.ioore(path, 0);
+ t1 = path[0];
+ } else
+ t1 = null;
+ return t1;
+ },
+ relativePathToUri$1: function(path) {
+ var segments = M.Context_Context(this).split$1(0, path);
+ if (this.isSeparator$1(J.codeUnitAt$1$s(path, path.length - 1)))
+ C.JSArray_methods.add$1(segments, "");
+ return P._Uri__Uri(null, null, segments, null);
+ },
+ codeUnitsEqual$2: function(codeUnit1, codeUnit2) {
+ return codeUnit1 === codeUnit2;
+ },
+ pathsEqual$2: function(path1, path2) {
+ return path1 == path2;
+ }
+ };
+ X.ParsedPath.prototype = {
+ get$hasTrailingSeparator: function() {
+ var t1 = this.parts;
+ if (t1.length !== 0)
+ t1 = J.$eq$(C.JSArray_methods.get$last(t1), "") || !J.$eq$(C.JSArray_methods.get$last(this.separators), "");
+ else
+ t1 = false;
+ return t1;
+ },
+ removeTrailingSeparators$0: function() {
+ var t1, t2, _this = this;
+ while (true) {
+ t1 = _this.parts;
+ if (!(t1.length !== 0 && J.$eq$(C.JSArray_methods.get$last(t1), "")))
+ break;
+ C.JSArray_methods.removeLast$0(_this.parts);
+ C.JSArray_methods.removeLast$0(_this.separators);
+ }
+ t1 = _this.separators;
+ t2 = t1.length;
+ if (t2 !== 0)
+ C.JSArray_methods.$indexSet(t1, t2 - 1, "");
+ },
+ normalize$0: function() {
+ var t1, t2, leadingDoubles, _i, part, t3, newSeparators, _this = this,
+ newParts = H.setRuntimeTypeInfo([], type$.JSArray_String);
+ for (t1 = _this.parts, t2 = t1.length, leadingDoubles = 0, _i = 0; _i < t1.length; t1.length === t2 || (0, H.throwConcurrentModificationError)(t1), ++_i) {
+ part = t1[_i];
+ t3 = J.getInterceptor$(part);
+ if (!(t3.$eq(part, ".") || t3.$eq(part, "")))
+ if (t3.$eq(part, "..")) {
+ t3 = newParts.length;
+ if (t3 !== 0) {
+ if (0 >= t3)
+ return H.ioore(newParts, -1);
+ newParts.pop();
+ } else
+ ++leadingDoubles;
+ } else
+ C.JSArray_methods.add$1(newParts, part);
+ }
+ if (_this.root == null)
+ C.JSArray_methods.insertAll$2(newParts, 0, P.List_List$filled(leadingDoubles, "..", type$.String));
+ if (newParts.length === 0 && _this.root == null)
+ C.JSArray_methods.add$1(newParts, ".");
+ newSeparators = P.List_List$generate(newParts.length, new X.ParsedPath_normalize_closure(_this), true, type$.String);
+ t1 = _this.root;
+ C.JSArray_methods.insert$2(newSeparators, 0, t1 != null && newParts.length !== 0 && _this.style.needsSeparator$1(t1) ? _this.style.get$separator() : "");
+ _this.set$parts(newParts);
+ _this.set$separators(newSeparators);
+ t1 = _this.root;
+ if (t1 != null && _this.style === $.$get$Style_windows()) {
+ t1.toString;
+ _this.root = H.stringReplaceAllUnchecked(t1, "/", "\\");
+ }
+ _this.removeTrailingSeparators$0();
+ },
+ toString$0: function(_) {
+ var i, t2, _this = this,
+ t1 = _this.root;
+ t1 = t1 != null ? t1 : "";
+ for (i = 0; i < _this.parts.length; ++i) {
+ t2 = _this.separators;
+ if (i >= t2.length)
+ return H.ioore(t2, i);
+ t2 = t1 + H.S(t2[i]);
+ t1 = _this.parts;
+ if (i >= t1.length)
+ return H.ioore(t1, i);
+ t1 = t2 + H.S(t1[i]);
+ }
+ t1 += H.S(C.JSArray_methods.get$last(_this.separators));
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ set$parts: function(parts) {
+ this.parts = type$.List_String._check(parts);
+ },
+ set$separators: function(separators) {
+ this.separators = type$.List_String._check(separators);
+ }
+ };
+ X.ParsedPath_normalize_closure.prototype = {
+ call$1: function(_) {
+ return this.$this.style.get$separator();
+ },
+ $signature: 25
+ };
+ X.PathException.prototype = {
+ toString$0: function(_) {
+ return "PathException: " + this.message;
+ },
+ $isException: 1,
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ O.Style.prototype = {
+ toString$0: function(_) {
+ return this.get$name(this);
+ }
+ };
+ E.PosixStyle.prototype = {
+ containsSeparator$1: function(path) {
+ return C.JSString_methods.contains$1(path, "/");
+ },
+ isSeparator$1: function(codeUnit) {
+ return codeUnit === 47;
+ },
+ needsSeparator$1: function(path) {
+ var t1 = path.length;
+ return t1 !== 0 && C.JSString_methods.codeUnitAt$1(path, t1 - 1) !== 47;
+ },
+ rootLength$2$withDrive: function(path, withDrive) {
+ if (path.length !== 0 && C.JSString_methods._codeUnitAt$1(path, 0) === 47)
+ return 1;
+ return 0;
+ },
+ rootLength$1: function(path) {
+ return this.rootLength$2$withDrive(path, false);
+ },
+ isRootRelative$1: function(path) {
+ return false;
+ },
+ pathFromUri$1: function(uri) {
+ var t1;
+ if (uri.get$scheme() === "" || uri.get$scheme() === "file") {
+ t1 = uri.get$path(uri);
+ return P._Uri__uriDecode(t1, 0, t1.length, C.C_Utf8Codec, false);
+ }
+ throw H.wrapException(P.ArgumentError$("Uri " + uri.toString$0(0) + " must have scheme 'file:'."));
+ },
+ absolutePathToUri$1: function(path) {
+ var parsed = X.ParsedPath_ParsedPath$parse(path, this),
+ t1 = parsed.parts;
+ if (t1.length === 0)
+ C.JSArray_methods.addAll$1(t1, H.setRuntimeTypeInfo(["", ""], type$.JSArray_String));
+ else if (parsed.get$hasTrailingSeparator())
+ C.JSArray_methods.add$1(parsed.parts, "");
+ return P._Uri__Uri(null, null, parsed.parts, "file");
+ },
+ get$name: function() {
+ return "posix";
+ },
+ get$separator: function() {
+ return "/";
+ }
+ };
+ F.UrlStyle.prototype = {
+ containsSeparator$1: function(path) {
+ return C.JSString_methods.contains$1(path, "/");
+ },
+ isSeparator$1: function(codeUnit) {
+ return codeUnit === 47;
+ },
+ needsSeparator$1: function(path) {
+ var t1 = path.length;
+ if (t1 === 0)
+ return false;
+ if (C.JSString_methods.codeUnitAt$1(path, t1 - 1) !== 47)
+ return true;
+ return C.JSString_methods.endsWith$1(path, "://") && this.rootLength$1(path) === t1;
+ },
+ rootLength$2$withDrive: function(path, withDrive) {
+ var i, codeUnit, index, t2,
+ t1 = path.length;
+ if (t1 === 0)
+ return 0;
+ if (C.JSString_methods._codeUnitAt$1(path, 0) === 47)
+ return 1;
+ for (i = 0; i < t1; ++i) {
+ codeUnit = C.JSString_methods._codeUnitAt$1(path, i);
+ if (codeUnit === 47)
+ return 0;
+ if (codeUnit === 58) {
+ if (i === 0)
+ return 0;
+ index = C.JSString_methods.indexOf$2(path, "/", C.JSString_methods.startsWith$2(path, "//", i + 1) ? i + 3 : i);
+ if (index <= 0)
+ return t1;
+ if (!withDrive || t1 < index + 3)
+ return index;
+ if (!C.JSString_methods.startsWith$1(path, "file://"))
+ return index;
+ if (!B.isDriveLetter(path, index + 1))
+ return index;
+ t2 = index + 3;
+ return t1 === t2 ? t2 : index + 4;
+ }
+ }
+ return 0;
+ },
+ rootLength$1: function(path) {
+ return this.rootLength$2$withDrive(path, false);
+ },
+ isRootRelative$1: function(path) {
+ return path.length !== 0 && C.JSString_methods._codeUnitAt$1(path, 0) === 47;
+ },
+ pathFromUri$1: function(uri) {
+ return J.toString$0$(uri);
+ },
+ relativePathToUri$1: function(path) {
+ return P.Uri_parse(path);
+ },
+ absolutePathToUri$1: function(path) {
+ return P.Uri_parse(path);
+ },
+ get$name: function() {
+ return "url";
+ },
+ get$separator: function() {
+ return "/";
+ }
+ };
+ L.WindowsStyle.prototype = {
+ containsSeparator$1: function(path) {
+ return C.JSString_methods.contains$1(path, "/");
+ },
+ isSeparator$1: function(codeUnit) {
+ return codeUnit === 47 || codeUnit === 92;
+ },
+ needsSeparator$1: function(path) {
+ var t1 = path.length;
+ if (t1 === 0)
+ return false;
+ t1 = C.JSString_methods.codeUnitAt$1(path, t1 - 1);
+ return !(t1 === 47 || t1 === 92);
+ },
+ rootLength$2$withDrive: function(path, withDrive) {
+ var t2, index,
+ t1 = path.length;
+ if (t1 === 0)
+ return 0;
+ t2 = C.JSString_methods._codeUnitAt$1(path, 0);
+ if (t2 === 47)
+ return 1;
+ if (t2 === 92) {
+ if (t1 < 2 || C.JSString_methods._codeUnitAt$1(path, 1) !== 92)
+ return 1;
+ index = C.JSString_methods.indexOf$2(path, "\\", 2);
+ if (index > 0) {
+ index = C.JSString_methods.indexOf$2(path, "\\", index + 1);
+ if (index > 0)
+ return index;
+ }
+ return t1;
+ }
+ if (t1 < 3)
+ return 0;
+ if (!B.isAlphabetic(t2))
+ return 0;
+ if (C.JSString_methods._codeUnitAt$1(path, 1) !== 58)
+ return 0;
+ t1 = C.JSString_methods._codeUnitAt$1(path, 2);
+ if (!(t1 === 47 || t1 === 92))
+ return 0;
+ return 3;
+ },
+ rootLength$1: function(path) {
+ return this.rootLength$2$withDrive(path, false);
+ },
+ isRootRelative$1: function(path) {
+ return this.rootLength$1(path) === 1;
+ },
+ pathFromUri$1: function(uri) {
+ var path, t1;
+ if (uri.get$scheme() !== "" && uri.get$scheme() !== "file")
+ throw H.wrapException(P.ArgumentError$("Uri " + uri.toString$0(0) + " must have scheme 'file:'."));
+ path = uri.get$path(uri);
+ if (uri.get$host(uri) === "") {
+ if (path.length >= 3 && C.JSString_methods.startsWith$1(path, "/") && B.isDriveLetter(path, 1))
+ path = C.JSString_methods.replaceFirst$2(path, "/", "");
+ } else
+ path = "\\\\" + H.S(uri.get$host(uri)) + path;
+ t1 = H.stringReplaceAllUnchecked(path, "/", "\\");
+ return P._Uri__uriDecode(t1, 0, t1.length, C.C_Utf8Codec, false);
+ },
+ absolutePathToUri$1: function(path) {
+ var rootParts, t2,
+ parsed = X.ParsedPath_ParsedPath$parse(path, this),
+ t1 = parsed.root;
+ if (J.startsWith$1$s(t1, "\\\\")) {
+ rootParts = new H.WhereIterable(H.setRuntimeTypeInfo(t1.split("\\"), type$.JSArray_String), type$.bool_Function_String._check(new L.WindowsStyle_absolutePathToUri_closure()), type$.WhereIterable_String);
+ C.JSArray_methods.insert$2(parsed.parts, 0, rootParts.get$last(rootParts));
+ if (parsed.get$hasTrailingSeparator())
+ C.JSArray_methods.add$1(parsed.parts, "");
+ return P._Uri__Uri(rootParts.get$first(rootParts), null, parsed.parts, "file");
+ } else {
+ if (parsed.parts.length === 0 || parsed.get$hasTrailingSeparator())
+ C.JSArray_methods.add$1(parsed.parts, "");
+ t1 = parsed.parts;
+ t2 = parsed.root;
+ t2.toString;
+ t2 = H.stringReplaceAllUnchecked(t2, "/", "");
+ C.JSArray_methods.insert$2(t1, 0, H.stringReplaceAllUnchecked(t2, "\\", ""));
+ return P._Uri__Uri(null, null, parsed.parts, "file");
+ }
+ },
+ codeUnitsEqual$2: function(codeUnit1, codeUnit2) {
+ var upperCase1;
+ if (codeUnit1 === codeUnit2)
+ return true;
+ if (codeUnit1 === 47)
+ return codeUnit2 === 92;
+ if (codeUnit1 === 92)
+ return codeUnit2 === 47;
+ if ((codeUnit1 ^ codeUnit2) !== 32)
+ return false;
+ upperCase1 = codeUnit1 | 32;
+ return upperCase1 >= 97 && upperCase1 <= 122;
+ },
+ pathsEqual$2: function(path1, path2) {
+ var t1, t2, i;
+ if (path1 == path2)
+ return true;
+ t1 = path1.length;
+ if (t1 !== path2.length)
+ return false;
+ for (t2 = J.getInterceptor$s(path2), i = 0; i < t1; ++i)
+ if (!this.codeUnitsEqual$2(C.JSString_methods._codeUnitAt$1(path1, i), t2._codeUnitAt$1(path2, i)))
+ return false;
+ return true;
+ },
+ get$name: function() {
+ return "windows";
+ },
+ get$separator: function() {
+ return "\\";
+ }
+ };
+ L.WindowsStyle_absolutePathToUri_closure.prototype = {
+ call$1: function(part) {
+ return H._checkStringNullable(part) !== "";
+ },
+ $signature: 4
+ };
+ O.Pool.prototype = {
+ request$0: function(_) {
+ var t1, t2, _this = this;
+ if (_this._pool$_closeMemo._async_memoizer$_completer.future._state !== 0)
+ throw H.wrapException(P.StateError$("request() may not be called on a closed Pool."));
+ t1 = _this._allocatedResources;
+ if (t1 < _this._maxAllocatedResources) {
+ _this._allocatedResources = t1 + 1;
+ t1 = new P._Future($.Zone__current, type$._Future_PoolResource);
+ t1._asyncComplete$1(new O.PoolResource(_this));
+ return t1;
+ } else {
+ t1 = _this._onReleaseCallbacks;
+ if (!t1.get$isEmpty(t1))
+ return _this._runOnRelease$1(t1.removeFirst$0());
+ else {
+ t1 = new P._Future($.Zone__current, type$._Future_PoolResource);
+ t2 = _this._requestedResources;
+ t2._collection$_add$1(t2.$ti._precomputed1._check(new P._AsyncCompleter(t1, type$._AsyncCompleter_PoolResource)));
+ _this._resetTimer$0();
+ return t1;
+ }
+ }
+ },
+ withResource$1$1: function(callback, $T) {
+ $T._eval$1("0/()")._check(callback);
+ return this.withResource$body$Pool(callback, $T, $T);
+ },
+ withResource$body$Pool: function(callback, $T, $async$type) {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter($async$type),
+ $async$returnValue, $async$handler = 2, $async$currentError, $async$next = [], $async$self = this, resource, t1;
+ var $async$withResource$1$1 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1) {
+ $async$currentError = $async$result;
+ $async$goto = $async$handler;
+ }
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ if ($async$self._pool$_closeMemo._async_memoizer$_completer.future._state !== 0)
+ throw H.wrapException(P.StateError$("withResource() may not be called on a closed Pool."));
+ $async$goto = 3;
+ return P._asyncAwait($async$self.request$0(0), $async$withResource$1$1);
+ case 3:
+ // returning from await.
+ resource = $async$result;
+ $async$handler = 4;
+ $async$goto = 7;
+ return P._asyncAwait(callback.call$0(), $async$withResource$1$1);
+ case 7:
+ // returning from await.
+ t1 = $async$result;
+ $async$returnValue = t1;
+ $async$next = [1];
+ // goto finally
+ $async$goto = 5;
+ break;
+ $async$next.push(6);
+ // goto finally
+ $async$goto = 5;
+ break;
+ case 4:
+ // uncaught
+ $async$next = [2];
+ case 5:
+ // finally
+ $async$handler = 2;
+ resource.release$0();
+ // goto the next finally handler
+ $async$goto = $async$next.pop();
+ break;
+ case 6:
+ // after finally
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ case 2:
+ // rethrow
+ return P._asyncRethrow($async$currentError, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$withResource$1$1, $async$completer);
+ },
+ close$0: function(_) {
+ return this._pool$_closeMemo.runOnce$1(new O.Pool_close_closure(this));
+ },
+ _onResourceReleaseAllowed$1: function(onRelease) {
+ var t1, zone, t2, _this = this;
+ type$.dynamic_Function._check(onRelease);
+ _this._resetTimer$0();
+ t1 = _this._requestedResources;
+ if (!t1.get$isEmpty(t1))
+ t1.removeFirst$0().complete$1(_this._runOnRelease$1(onRelease));
+ else {
+ t1 = type$.dynamic;
+ if (_this._pool$_closeMemo._async_memoizer$_completer.future._state !== 0) {
+ _this._closeGroup.add$1(0, P.Future_Future$sync(onRelease, t1));
+ if (--_this._allocatedResources === 0)
+ _this._closeGroup.close$0(0);
+ } else {
+ zone = $.Zone__current;
+ t2 = _this._onReleaseCallbacks;
+ t2._collection$_add$1(t2.$ti._precomputed1._check(new O.Pool__onResourceReleaseAllowed_closure(zone, zone.registerCallback$1$1(onRelease, t1))));
+ }
+ }
+ },
+ _runOnRelease$1: function(onRelease) {
+ var t1, t2;
+ P.Future_Future$sync(type$.dynamic_Function._check(onRelease), type$.dynamic).then$1$1(new O.Pool__runOnRelease_closure(this), type$.Null).catchError$1(new O.Pool__runOnRelease_closure0(this));
+ t1 = new P._Future($.Zone__current, type$._Future_PoolResource);
+ t2 = this._onReleaseCompleters;
+ t2._collection$_add$1(t2.$ti._precomputed1._check(new P._SyncCompleter(t1, type$._SyncCompleter_PoolResource)));
+ return t1;
+ },
+ _resetTimer$0: function() {
+ var t2,
+ t1 = this._timer;
+ if (t1 == null)
+ return;
+ t2 = this._requestedResources;
+ if (t2._head === t2._tail)
+ t1._restartable_timer$_timer.cancel$0();
+ else {
+ t1._restartable_timer$_timer.cancel$0();
+ t1._restartable_timer$_timer = P.Timer_Timer(t1._restartable_timer$_duration, t1._callback);
+ }
+ }
+ };
+ O.Pool_close_closure.prototype = {
+ call$0: function() {
+ var t3, t4, callback,
+ t1 = this.$this,
+ t2 = t1._closeGroup;
+ if (t2 != null)
+ return t2._future_group$_completer.future;
+ t1._resetTimer$0();
+ t1._closeGroup = new F.FutureGroup(new P._AsyncCompleter(new P._Future($.Zone__current, type$._Future_List_dynamic), type$._AsyncCompleter_List_dynamic), H.setRuntimeTypeInfo([], type$.JSArray_dynamic), type$.FutureGroup_dynamic);
+ for (t2 = t1._onReleaseCallbacks, t3 = P._ListQueueIterator$(t2, t2.$ti._precomputed1), t4 = type$.dynamic; t3.moveNext$0();) {
+ callback = t3._collection$_current;
+ t1._closeGroup.add$1(0, P.Future_Future$sync(callback, t4));
+ }
+ t1._allocatedResources = t1._allocatedResources - t2.get$length(t2);
+ t2.clear$0(0);
+ if (t1._allocatedResources === 0)
+ t1._closeGroup.close$0(0);
+ return t1._closeGroup._future_group$_completer.future;
+ },
+ $signature: 50
+ };
+ O.Pool__onResourceReleaseAllowed_closure.prototype = {
+ call$0: function() {
+ return this.zone.run$1$1(this.registered, type$.void);
+ },
+ $signature: 1
+ };
+ O.Pool__runOnRelease_closure.prototype = {
+ call$1: function(value) {
+ var t1 = this.$this;
+ t1._onReleaseCompleters.removeFirst$0().complete$1(new O.PoolResource(t1));
+ },
+ $signature: 3
+ };
+ O.Pool__runOnRelease_closure0.prototype = {
+ call$2: function(error, stackTrace) {
+ type$.StackTrace._check(stackTrace);
+ this.$this._onReleaseCompleters.removeFirst$0().completeError$2(error, stackTrace);
+ },
+ $signature: 5
+ };
+ O.PoolResource.prototype = {
+ release$0: function() {
+ var t1, t2;
+ if (this._released)
+ throw H.wrapException(P.StateError$("A PoolResource may only be released once."));
+ this._released = true;
+ t1 = this._pool;
+ t1._resetTimer$0();
+ t2 = t1._requestedResources;
+ if (!t2.get$isEmpty(t2))
+ t2.removeFirst$0().complete$1(new O.PoolResource(t1));
+ else {
+ t2 = --t1._allocatedResources;
+ if (t1._pool$_closeMemo._async_memoizer$_completer.future._state !== 0 && t2 === 0)
+ t1._closeGroup.close$0(0);
+ }
+ }
+ };
+ O.mapStackTrace_closure.prototype = {
+ call$1: function(trace) {
+ var _this = this;
+ return Y.Trace_Trace$from(O.mapStackTrace(_this.sourceMap, type$.Trace._check(trace), _this.minified, _this._box_0.packageResolver, _this.sdkRoot));
+ },
+ $signature: 45
+ };
+ O.mapStackTrace_closure0.prototype = {
+ call$1: function(frame) {
+ var column, t1, t2, span, sourceUrl, t3, packageUrl, t4, _this = this;
+ type$.Frame._check(frame);
+ if (frame.get$line() == null)
+ return null;
+ column = frame.get$column() == null ? 0 : frame.get$column();
+ t1 = frame.get$line();
+ if (typeof t1 !== "number")
+ return t1.$sub();
+ if (typeof column !== "number")
+ return column.$sub();
+ t2 = frame.get$uri();
+ t2 = t2 == null ? null : t2.toString$0(0);
+ span = _this.sourceMap.spanFor$3$uri(t1 - 1, column - 1, t2);
+ if (span == null)
+ return null;
+ sourceUrl = J.toString$0$(span.get$sourceUrl());
+ if (_this.sdkRoot != null && $.$get$url()._isWithinOrEquals$2(_this.sdkLib, sourceUrl) === C._PathRelation_within)
+ sourceUrl = C.JSString_methods.$add("dart:", $.$get$url().relative$2$from(sourceUrl, _this.sdkLib));
+ else {
+ t1 = _this._box_0;
+ t2 = t1.packageResolver;
+ if (t2 != null)
+ if (t2.get$packageRoot() != null && $.$get$url()._isWithinOrEquals$2(J.toString$0$(t1.packageResolver.get$packageRoot()), sourceUrl) === C._PathRelation_within)
+ sourceUrl = C.JSString_methods.$add("package:", $.$get$url().relative$2$from(sourceUrl, J.toString$0$(t1.packageResolver.get$packageRoot())));
+ else if (t1.packageResolver.get$packageConfigMap() != null)
+ for (t2 = t1.packageResolver.get$packageConfigMap()._map.get$keys(), t2 = t2.get$iterator(t2); t2.moveNext$0();) {
+ t3 = t2.get$current();
+ packageUrl = J.toString$0$(t1.packageResolver.get$packageConfigMap()._map.$index(0, t3));
+ t4 = $.$get$url();
+ if (t4._isWithinOrEquals$2(packageUrl, sourceUrl) !== C._PathRelation_within)
+ continue;
+ sourceUrl = C.JSString_methods.$add("package:" + H.S(t3) + "/", t4.relative$2$from(sourceUrl, packageUrl));
+ break;
+ }
+ }
+ t1 = P.Uri_parse(sourceUrl);
+ t2 = span.get$start().get$line();
+ if (typeof t2 !== "number")
+ return t2.$add();
+ t3 = span.get$start().get$column();
+ if (_this.minified)
+ t4 = span.get$isIdentifier() ? span.get$text() : frame.get$member();
+ else
+ t4 = O._prettifyMember(frame.get$member());
+ return new A.Frame(t1, t2 + 1, t3 + 1, t4);
+ },
+ $signature: 46
+ };
+ O.mapStackTrace_closure1.prototype = {
+ call$1: function(frame) {
+ return type$.Frame._check(frame) != null;
+ },
+ $signature: 21
+ };
+ O._prettifyMember_closure.prototype = {
+ call$1: function(match) {
+ return C.JSString_methods.$mul(".<fn>", match.$index(0, 1).length);
+ },
+ $signature: 24
+ };
+ O._prettifyMember_closure0.prototype = {
+ call$1: function(match) {
+ return J.$add$ansx(match.$index(0, 1), ".");
+ },
+ $signature: 24
+ };
+ T.Mapping.prototype = {};
+ T.MultiSectionMapping.prototype = {
+ MultiSectionMapping$fromJson$3$mapUrl: function(sections, otherMaps, mapUrl) {
+ var t1, t2, t3, t4, t5, section, t6, line, column, url, map, _s6_ = "offset", _null = null;
+ for (t1 = J.get$iterator$ax(sections), t2 = this._maps, t3 = type$.Map_dynamic_dynamic, t4 = this._lineStart, t5 = this._columnStart; t1.moveNext$0();) {
+ section = t1.get$current();
+ t6 = J.getInterceptor$asx(section);
+ if (t6.$index(section, _s6_) == null)
+ throw H.wrapException(P.FormatException$("section missing offset", _null, _null));
+ line = J.$index$asx(t6.$index(section, _s6_), "line");
+ if (line == null)
+ throw H.wrapException(P.FormatException$("offset missing line", _null, _null));
+ column = J.$index$asx(t6.$index(section, _s6_), "column");
+ if (column == null)
+ throw H.wrapException(P.FormatException$("offset missing column", _null, _null));
+ C.JSArray_methods.add$1(t4, H._checkIntNullable(line));
+ C.JSArray_methods.add$1(t5, H._checkIntNullable(column));
+ url = t6.$index(section, "url");
+ map = t6.$index(section, "map");
+ t6 = url != null;
+ if (t6 && map != null)
+ throw H.wrapException(P.FormatException$("section can't use both url and map entries", _null, _null));
+ else if (t6) {
+ t6 = P.FormatException$("section contains refers to " + H.S(url) + ', but no map was given for it. Make sure a map is passed in "otherMaps"', _null, _null);
+ throw H.wrapException(t6);
+ } else if (map != null)
+ C.JSArray_methods.add$1(t2, T.parseJson(t3._check(map), mapUrl, otherMaps));
+ else
+ throw H.wrapException(P.FormatException$("section missing url or map", _null, _null));
+ }
+ if (t4.length === 0)
+ throw H.wrapException(P.FormatException$("expected at least one section", _null, _null));
+ },
+ _indexFor$2: function(line, column) {
+ var t1, t2, t3, t4, i, t5;
+ for (t1 = this._lineStart, t2 = t1.length, t3 = this._columnStart, t4 = t3.length, i = 0; i < t2; ++i) {
+ t5 = t1[i];
+ if (line < t5)
+ return i - 1;
+ if (line === t5) {
+ if (i >= t4)
+ return H.ioore(t3, i);
+ t5 = column < t3[i];
+ } else
+ t5 = false;
+ if (t5)
+ return i - 1;
+ }
+ return t2 - 1;
+ },
+ spanFor$4$files$uri: function(line, column, files, uri) {
+ var index, t1, t2, t3, _this = this;
+ type$.Map_String_SourceFile._check(files);
+ index = _this._indexFor$2(line, column);
+ t1 = _this._maps;
+ if (index < 0 || index >= t1.length)
+ return H.ioore(t1, index);
+ t1 = t1[index];
+ t2 = _this._lineStart;
+ if (index >= t2.length)
+ return H.ioore(t2, index);
+ t2 = t2[index];
+ t3 = _this._columnStart;
+ if (index >= t3.length)
+ return H.ioore(t3, index);
+ return t1.spanFor$3$files(line - t2, column - t3[index], files);
+ },
+ spanFor$3$uri: function(line, column, uri) {
+ return this.spanFor$4$files$uri(line, column, null, uri);
+ },
+ spanFor$3$files: function(line, column, files) {
+ return this.spanFor$4$files$uri(line, column, files, null);
+ },
+ toString$0: function(_) {
+ var t2, t3, t4, i, _this = this,
+ t1 = H.getRuntimeType(_this).toString$0(0) + " : [";
+ for (t2 = _this._lineStart, t3 = _this._columnStart, t4 = _this._maps, i = 0; i < t2.length; ++i) {
+ t1 = t1 + "(" + t2[i] + ",";
+ if (i >= t3.length)
+ return H.ioore(t3, i);
+ t1 = t1 + t3[i] + ":";
+ if (i >= t4.length)
+ return H.ioore(t4, i);
+ t1 = t1 + t4[i].toString$0(0) + ")";
+ }
+ t1 += "]";
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ }
+ };
+ T.MappingBundle.prototype = {
+ MappingBundle$fromJson$2$mapUrl: function(json, mapUrl) {
+ var t1, t2, t3, t4, t5;
+ for (t1 = J.get$iterator$ax(json), t2 = type$.Map_dynamic_dynamic, t3 = type$.SingleMapping, t4 = this._mappings; t1.moveNext$0();) {
+ t5 = t3._as(T.parseJson(t2._check(t1.get$current()), mapUrl, null));
+ t4.$indexSet(0, t5.targetUrl, t5);
+ }
+ },
+ toString$0: function(_) {
+ var t1, t2;
+ for (t1 = this._mappings.get$values(), t1 = t1.get$iterator(t1), t2 = ""; t1.moveNext$0();)
+ t2 += J.toString$0$(t1.get$current());
+ return t2.charCodeAt(0) == 0 ? t2 : t2;
+ },
+ spanFor$4$files$uri: function(line, column, files, uri) {
+ var separatorCodeUnits, t1, t2, onBoundary, i, candidate, $location;
+ type$.Map_String_SourceFile._check(files);
+ if (uri == null)
+ throw H.wrapException(P.ArgumentError$notNull("uri"));
+ separatorCodeUnits = H.setRuntimeTypeInfo([47, 58], type$.JSArray_int);
+ for (t1 = uri.length, t2 = this._mappings, onBoundary = true, i = 0; i < t1; ++i) {
+ if (onBoundary) {
+ candidate = C.JSString_methods.substring$1(uri, i);
+ if (t2.containsKey$1(candidate))
+ return t2.$index(0, candidate).spanFor$4$files$uri(line, column, files, candidate);
+ }
+ onBoundary = C.JSArray_methods.contains$1(separatorCodeUnits, C.JSString_methods._codeUnitAt$1(uri, i));
+ }
+ $location = V.SourceLocation$(line * 1000000 + column, column, line, P.Uri_parse(uri));
+ t1 = new G.SourceMapSpan(false, $location, $location, "");
+ t1.SourceSpanBase$3($location, $location, "");
+ return t1;
+ },
+ spanFor$3$uri: function(line, column, uri) {
+ return this.spanFor$4$files$uri(line, column, null, uri);
+ }
+ };
+ T.SingleMapping.prototype = {
+ SingleMapping$fromJson$2$mapUrl: function(map, mapUrl) {
+ var t5, source, t6, t7, tokenizer, entries, line, column, srcUrlId, srcLine, srcColumn, srcNameId, _this = this,
+ _s14_ = "sourcesContent",
+ _null = null,
+ sourcesContent = map.$index(0, _s14_) == null ? C.List_empty0 : P.List_List$from(type$.Iterable_dynamic._check(map.$index(0, _s14_)), true, type$.String),
+ t1 = type$.Uri,
+ t2 = _this.files,
+ t3 = _this.urls,
+ t4 = type$.JSArray_int,
+ i = 0;
+ while (true) {
+ t5 = t3.length;
+ if (!(i < t5 && i < sourcesContent.length))
+ break;
+ c$0: {
+ if (i >= sourcesContent.length)
+ return H.ioore(sourcesContent, i);
+ source = sourcesContent[i];
+ if (source == null)
+ break c$0;
+ H._checkStringNullable(source);
+ if (i >= t5)
+ return H.ioore(t3, i);
+ t5 = t3[i];
+ t6 = new H.CodeUnits(source);
+ t7 = H.setRuntimeTypeInfo([0], t4);
+ t7 = new Y.SourceFile(t1._check(typeof t5 == "string" ? P.Uri_parse(t5) : t5), t7, new Uint32Array(H._ensureNativeList(t6.toList$0(t6))));
+ t7.SourceFile$decoded$2$url(t6, t5);
+ C.JSArray_methods.$indexSet(t2, i, t7);
+ }
+ ++i;
+ }
+ t1 = H._checkStringNullable(map.$index(0, "mappings"));
+ t2 = t1.length;
+ tokenizer = new T._MappingTokenizer(t1, t2);
+ t1 = type$.JSArray_TargetEntry;
+ entries = H.setRuntimeTypeInfo([], t1);
+ t4 = _this.names;
+ t5 = t2 - 1;
+ t2 = t2 > 0;
+ t6 = _this.lines;
+ line = 0;
+ column = 0;
+ srcUrlId = 0;
+ srcLine = 0;
+ srcColumn = 0;
+ srcNameId = 0;
+ while (true) {
+ if (!(tokenizer.index < t5 && t2))
+ break;
+ c$1: {
+ if (tokenizer.get$nextKind().isNewLine) {
+ if (entries.length !== 0) {
+ C.JSArray_methods.add$1(t6, new T.TargetLineEntry(line, entries));
+ entries = H.setRuntimeTypeInfo([], t1);
+ }
+ ++line;
+ ++tokenizer.index;
+ column = 0;
+ break c$1;
+ }
+ if (tokenizer.get$nextKind().isNewSegment)
+ throw H.wrapException(_this._segmentError$2(0, line));
+ column += L.decodeVlq(tokenizer);
+ t7 = tokenizer.get$nextKind();
+ if (!(!t7.isNewLine && !t7.isNewSegment && !t7.isEof))
+ C.JSArray_methods.add$1(entries, new T.TargetEntry(column, _null, _null, _null, _null));
+ else {
+ srcUrlId += L.decodeVlq(tokenizer);
+ if (srcUrlId >= t3.length)
+ throw H.wrapException(P.StateError$("Invalid source url id. " + H.S(_this.targetUrl) + ", " + line + ", " + srcUrlId));
+ t7 = tokenizer.get$nextKind();
+ if (!(!t7.isNewLine && !t7.isNewSegment && !t7.isEof))
+ throw H.wrapException(_this._segmentError$2(2, line));
+ srcLine += L.decodeVlq(tokenizer);
+ t7 = tokenizer.get$nextKind();
+ if (!(!t7.isNewLine && !t7.isNewSegment && !t7.isEof))
+ throw H.wrapException(_this._segmentError$2(3, line));
+ srcColumn += L.decodeVlq(tokenizer);
+ t7 = tokenizer.get$nextKind();
+ if (!(!t7.isNewLine && !t7.isNewSegment && !t7.isEof))
+ C.JSArray_methods.add$1(entries, new T.TargetEntry(column, srcUrlId, srcLine, srcColumn, _null));
+ else {
+ srcNameId += L.decodeVlq(tokenizer);
+ if (srcNameId >= t4.length)
+ throw H.wrapException(P.StateError$("Invalid name id: " + H.S(_this.targetUrl) + ", " + line + ", " + srcNameId));
+ C.JSArray_methods.add$1(entries, new T.TargetEntry(column, srcUrlId, srcLine, srcColumn, srcNameId));
+ }
+ }
+ if (tokenizer.get$nextKind().isNewSegment)
+ ++tokenizer.index;
+ }
+ }
+ if (entries.length !== 0)
+ C.JSArray_methods.add$1(t6, new T.TargetLineEntry(line, entries));
+ map.forEach$1(0, new T.SingleMapping$fromJson_closure(_this));
+ },
+ _segmentError$2: function(seen, line) {
+ return new P.StateError("Invalid entry in sourcemap, expected 1, 4, or 5 values, but got " + seen + ".\ntargeturl: " + H.S(this.targetUrl) + ", line: " + line);
+ },
+ _findLine$1: function(line) {
+ var t2,
+ t1 = this.lines,
+ index = O.binarySearch(t1, new T.SingleMapping__findLine_closure(line));
+ if (index <= 0)
+ t1 = null;
+ else {
+ t2 = index - 1;
+ if (t2 >= t1.length)
+ return H.ioore(t1, t2);
+ t2 = t1[t2];
+ t1 = t2;
+ }
+ return t1;
+ },
+ _findColumn$3: function(line, column, lineEntry) {
+ var entries, index, t1;
+ if (lineEntry == null || lineEntry.entries.length === 0)
+ return null;
+ if (lineEntry.line !== line)
+ return C.JSArray_methods.get$last(lineEntry.entries);
+ entries = lineEntry.entries;
+ index = O.binarySearch(entries, new T.SingleMapping__findColumn_closure(column));
+ if (index <= 0)
+ t1 = null;
+ else {
+ t1 = index - 1;
+ if (t1 >= entries.length)
+ return H.ioore(entries, t1);
+ t1 = entries[t1];
+ }
+ return t1;
+ },
+ spanFor$4$files$uri: function(line, column, files, uri) {
+ var entry, url, t1, t2, start, t3, _this = this;
+ type$.Map_String_SourceFile._check(files);
+ entry = _this._findColumn$3(line, column, _this._findLine$1(line));
+ if (entry == null || entry.sourceUrlId == null)
+ return null;
+ url = C.JSArray_methods.$index(_this.urls, entry.sourceUrlId);
+ t1 = _this.sourceRoot;
+ if (t1 != null)
+ url = t1 + H.S(url);
+ t1 = _this._parser$_mapUrl;
+ t1 = t1 == null ? url : t1.resolve$1(url);
+ t2 = entry.sourceLine;
+ start = V.SourceLocation$(0, entry.sourceColumn, t2, t1);
+ t1 = entry.sourceNameId;
+ if (t1 != null) {
+ t2 = _this.names;
+ if (t1 >>> 0 !== t1 || t1 >= t2.length)
+ return H.ioore(t2, t1);
+ t1 = t2[t1];
+ t2 = t1.length;
+ t2 = V.SourceLocation$(start.offset + t2, start.column + t2, start.line, start.sourceUrl);
+ t3 = new G.SourceMapSpan(true, start, t2, t1);
+ t3.SourceSpanBase$3(start, t2, t1);
+ return t3;
+ } else {
+ t1 = new G.SourceMapSpan(false, start, start, "");
+ t1.SourceSpanBase$3(start, start, "");
+ return t1;
+ }
+ },
+ spanFor$3$uri: function(line, column, uri) {
+ return this.spanFor$4$files$uri(line, column, null, uri);
+ },
+ spanFor$3$files: function(line, column, files) {
+ return this.spanFor$4$files$uri(line, column, files, null);
+ },
+ toString$0: function(_) {
+ var _this = this,
+ t1 = H.getRuntimeType(_this).toString$0(0);
+ t1 + " : [";
+ t1 = t1 + " : [targetUrl: " + H.S(_this.targetUrl) + ", sourceRoot: " + H.S(_this.sourceRoot) + ", urls: " + H.S(_this.urls) + ", names: " + H.S(_this.names) + ", lines: " + H.S(_this.lines) + "]";
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ }
+ };
+ T.SingleMapping$fromJson_closure.prototype = {
+ call$2: function($name, value) {
+ if (J.startsWith$1$s($name, "x_"))
+ this.$this.extensions.$indexSet(0, H._checkStringNullable($name), value);
+ },
+ $signature: 6
+ };
+ T.SingleMapping__findLine_closure.prototype = {
+ call$1: function(e) {
+ return e.get$line() > this.line;
+ },
+ $signature: 9
+ };
+ T.SingleMapping__findColumn_closure.prototype = {
+ call$1: function(e) {
+ return e.get$column() > this.column;
+ },
+ $signature: 9
+ };
+ T.TargetLineEntry.prototype = {
+ toString$0: function(_) {
+ return H.getRuntimeType(this).toString$0(0) + ": " + this.line + " " + H.S(this.entries);
+ },
+ get$line: function() {
+ return this.line;
+ }
+ };
+ T.TargetEntry.prototype = {
+ toString$0: function(_) {
+ var _this = this;
+ return H.getRuntimeType(_this).toString$0(0) + ": (" + _this.column + ", " + H.S(_this.sourceUrlId) + ", " + H.S(_this.sourceLine) + ", " + H.S(_this.sourceColumn) + ", " + H.S(_this.sourceNameId) + ")";
+ },
+ get$column: function() {
+ return this.column;
+ }
+ };
+ T._MappingTokenizer.prototype = {
+ moveNext$0: function() {
+ return ++this.index < this._parser$_length;
+ },
+ get$current: function() {
+ var t2,
+ t1 = this.index;
+ if (t1 >= 0 && t1 < this._parser$_length) {
+ t2 = this._internal;
+ if (t1 < 0 || t1 >= t2.length)
+ return H.ioore(t2, t1);
+ t1 = t2[t1];
+ } else
+ t1 = null;
+ return t1;
+ },
+ get$hasTokens: function() {
+ var t1 = this._parser$_length;
+ return this.index < t1 - 1 && t1 > 0;
+ },
+ get$nextKind: function() {
+ var t1, t2, next;
+ if (!this.get$hasTokens())
+ return C._TokenKind_false_false_true;
+ t1 = this._internal;
+ t2 = this.index + 1;
+ if (t2 < 0 || t2 >= t1.length)
+ return H.ioore(t1, t2);
+ next = t1[t2];
+ if (next === ";")
+ return C._TokenKind_true_false_false;
+ if (next === ",")
+ return C._TokenKind_false_true_false;
+ return C._TokenKind_false_false_false;
+ },
+ toString$0: function(_) {
+ var t1, i, t2, t3, _this = this;
+ for (t1 = _this._internal, i = 0, t2 = ""; i < _this.index; ++i) {
+ if (i >= t1.length)
+ return H.ioore(t1, i);
+ t2 += t1[i];
+ }
+ t2 += "\x1b[31m";
+ t2 = t2 + H.S(_this.get$current() == null ? "" : _this.get$current()) + "\x1b[0m";
+ for (i = _this.index + 1, t3 = t1.length; i < t3; ++i) {
+ if (i < 0)
+ return H.ioore(t1, i);
+ t2 += t1[i];
+ }
+ t1 = t2 + (" (" + _this.index + ")");
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ $isIterator: 1
+ };
+ T._TokenKind.prototype = {};
+ G.SourceMapSpan.prototype = {
+ get$isIdentifier: function() {
+ return this.isIdentifier;
+ }
+ };
+ L.closure.prototype = {
+ call$0: function() {
+ var i,
+ map = P.LinkedHashMap_LinkedHashMap$_empty(type$.String, type$.int);
+ for (i = 0; i < 64; ++i)
+ map.$indexSet(0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i], i);
+ return map;
+ },
+ $signature: 93
+ };
+ Y.SourceFile.prototype = {
+ get$length: function(_) {
+ return this._decodedChars.length;
+ },
+ get$lines: function() {
+ return this._lineStarts.length;
+ },
+ SourceFile$decoded$2$url: function(decodedChars, url) {
+ var t1, t2, t3, i, c, j, t4;
+ for (t1 = this._decodedChars, t2 = t1.length, t3 = this._lineStarts, i = 0; i < t2; ++i) {
+ c = t1[i];
+ if (c === 13) {
+ j = i + 1;
+ if (j < t2) {
+ if (j >= t2)
+ return H.ioore(t1, j);
+ t4 = t1[j] !== 10;
+ } else
+ t4 = true;
+ if (t4)
+ c = 10;
+ }
+ if (c === 10)
+ C.JSArray_methods.add$1(t3, i + 1);
+ }
+ },
+ span$2: function(start, end) {
+ return Y._FileSpan$(this, start, end);
+ },
+ getLine$1: function(offset) {
+ var t1, _this = this;
+ if (offset < 0)
+ throw H.wrapException(P.RangeError$("Offset may not be negative, was " + offset + "."));
+ else if (offset > _this._decodedChars.length)
+ throw H.wrapException(P.RangeError$("Offset " + offset + " must not be greater than the number of characters in the file, " + _this.get$length(_this) + "."));
+ t1 = _this._lineStarts;
+ if (offset < C.JSArray_methods.get$first(t1))
+ return -1;
+ if (offset >= C.JSArray_methods.get$last(t1))
+ return t1.length - 1;
+ if (_this._isNearCachedLine$1(offset))
+ return _this._cachedLine;
+ return _this._cachedLine = _this._binarySearch$1(offset) - 1;
+ },
+ _isNearCachedLine$1: function(offset) {
+ var t2, t3, t4, _this = this,
+ t1 = _this._cachedLine;
+ if (t1 == null)
+ return false;
+ t2 = _this._lineStarts;
+ if (t1 >>> 0 !== t1 || t1 >= t2.length)
+ return H.ioore(t2, t1);
+ if (offset < t2[t1])
+ return false;
+ t1 = _this._cachedLine;
+ t3 = t2.length;
+ if (typeof t1 !== "number")
+ return t1.$ge();
+ if (t1 < t3 - 1) {
+ t4 = t1 + 1;
+ if (t4 < 0 || t4 >= t3)
+ return H.ioore(t2, t4);
+ t4 = offset < t2[t4];
+ } else
+ t4 = true;
+ if (t4)
+ return true;
+ if (t1 < t3 - 2) {
+ t4 = t1 + 2;
+ if (t4 < 0 || t4 >= t3)
+ return H.ioore(t2, t4);
+ t4 = offset < t2[t4];
+ t2 = t4;
+ } else
+ t2 = true;
+ if (t2) {
+ _this._cachedLine = t1 + 1;
+ return true;
+ }
+ return false;
+ },
+ _binarySearch$1: function(offset) {
+ var min, half,
+ t1 = this._lineStarts,
+ t2 = t1.length,
+ max = t2 - 1;
+ for (min = 0; min < max;) {
+ half = min + C.JSInt_methods._tdivFast$1(max - min, 2);
+ if (half < 0 || half >= t2)
+ return H.ioore(t1, half);
+ if (t1[half] > offset)
+ max = half;
+ else
+ min = half + 1;
+ }
+ return max;
+ },
+ getColumn$1: function(offset) {
+ var line, lineStart, _this = this;
+ if (offset < 0)
+ throw H.wrapException(P.RangeError$("Offset may not be negative, was " + offset + "."));
+ else if (offset > _this._decodedChars.length)
+ throw H.wrapException(P.RangeError$("Offset " + offset + " must be not be greater than the number of characters in the file, " + _this.get$length(_this) + "."));
+ line = _this.getLine$1(offset);
+ lineStart = C.JSArray_methods.$index(_this._lineStarts, line);
+ if (lineStart > offset)
+ throw H.wrapException(P.RangeError$("Line " + H.S(line) + " comes after offset " + offset + "."));
+ return offset - lineStart;
+ },
+ getOffset$2: function(line, column) {
+ var t1, t2, result, t3;
+ if (typeof line !== "number")
+ return line.$lt();
+ if (line < 0)
+ throw H.wrapException(P.RangeError$("Line may not be negative, was " + line + "."));
+ else {
+ t1 = this._lineStarts;
+ t2 = t1.length;
+ if (line >= t2)
+ throw H.wrapException(P.RangeError$("Line " + line + " must be less than the number of lines in the file, " + this.get$lines() + "."));
+ }
+ result = t1[line];
+ if (result <= this._decodedChars.length) {
+ t3 = line + 1;
+ t1 = t3 < t2 && result >= t1[t3];
+ } else
+ t1 = true;
+ if (t1)
+ throw H.wrapException(P.RangeError$("Line " + line + " doesn't have 0 columns."));
+ return result;
+ },
+ getOffset$1: function(line) {
+ return this.getOffset$2(line, null);
+ }
+ };
+ Y.FileLocation.prototype = {
+ get$sourceUrl: function() {
+ return this.file.url;
+ },
+ get$line: function() {
+ return this.file.getLine$1(this.offset);
+ },
+ get$column: function() {
+ return this.file.getColumn$1(this.offset);
+ },
+ get$offset: function(receiver) {
+ return this.offset;
+ }
+ };
+ Y._FileSpan.prototype = {
+ get$sourceUrl: function() {
+ return this.file.url;
+ },
+ get$length: function(_) {
+ return this._file$_end - this._file$_start;
+ },
+ get$start: function() {
+ return Y.FileLocation$_(this.file, this._file$_start);
+ },
+ get$end: function() {
+ return Y.FileLocation$_(this.file, this._file$_end);
+ },
+ get$text: function() {
+ return P.String_String$fromCharCodes(C.NativeUint32List_methods.sublist$2(this.file._decodedChars, this._file$_start, this._file$_end), 0, null);
+ },
+ get$context: function() {
+ var t2, _this = this,
+ t1 = _this.file,
+ endOffset = _this._file$_end,
+ endLine = t1.getLine$1(endOffset);
+ if (t1.getColumn$1(endOffset) === 0 && endLine !== 0) {
+ if (endOffset - _this._file$_start === 0) {
+ if (endLine === t1._lineStarts.length - 1)
+ t1 = "";
+ else {
+ t2 = t1.getOffset$1(endLine);
+ if (typeof endLine !== "number")
+ return endLine.$add();
+ t1 = P.String_String$fromCharCodes(C.NativeUint32List_methods.sublist$2(t1._decodedChars, t2, t1.getOffset$1(endLine + 1)), 0, null);
+ }
+ return t1;
+ }
+ } else if (endLine === t1._lineStarts.length - 1)
+ endOffset = t1._decodedChars.length;
+ else {
+ if (typeof endLine !== "number")
+ return endLine.$add();
+ endOffset = t1.getOffset$1(endLine + 1);
+ }
+ return P.String_String$fromCharCodes(C.NativeUint32List_methods.sublist$2(t1._decodedChars, t1.getOffset$1(t1.getLine$1(_this._file$_start)), endOffset), 0, null);
+ },
+ $eq: function(_, other) {
+ var _this = this;
+ if (other == null)
+ return false;
+ if (!type$.FileSpan._is(other))
+ return _this.super$SourceSpanMixin$$eq(0, other);
+ if (!(other instanceof Y._FileSpan))
+ return _this.super$SourceSpanMixin$$eq(0, other) && J.$eq$(_this.file.url, other.get$sourceUrl());
+ return _this._file$_start === other._file$_start && _this._file$_end === other._file$_end && J.$eq$(_this.file.url, other.file.url);
+ },
+ get$hashCode: function(_) {
+ return Y.SourceSpanMixin.prototype.get$hashCode.call(this, this);
+ },
+ expand$1: function(_, other) {
+ var start, _this = this,
+ t1 = _this.file;
+ if (!J.$eq$(t1.url, other.file.url))
+ throw H.wrapException(P.ArgumentError$('Source URLs "' + H.S(_this.get$sourceUrl()) + '" and "' + H.S(other.get$sourceUrl()) + "\" don't match."));
+ start = Math.min(_this._file$_start, other._file$_start);
+ return Y._FileSpan$(t1, start, Math.max(_this._file$_end, other._file$_end));
+ },
+ $isFileSpan: 1,
+ $isSourceSpanWithContext: 1
+ };
+ U.Highlighter.prototype = {
+ highlight$0: function() {
+ var t1, t2, lineStart, context, lines, t3, t4, lineNumber, _i, line, lastLineIndex, _this = this;
+ _this._writeSidebar$1$end($._glyphs.get$downEnd());
+ t1 = _this._highlighter$_buffer;
+ t1._contents += "\n";
+ t2 = _this._span;
+ lineStart = B.findLineStart(t2.get$context(), t2.get$text(), t2.get$start().get$column());
+ H.assertHelper(lineStart != null);
+ context = t2.get$context();
+ if (typeof lineStart !== "number")
+ return lineStart.$gt();
+ if (lineStart > 0) {
+ lines = C.JSString_methods.substring$2(context, 0, lineStart - 1).split("\n");
+ t3 = t2.get$start().get$line();
+ t4 = lines.length;
+ if (typeof t3 !== "number")
+ return t3.$sub();
+ lineNumber = t3 - t4;
+ for (t3 = _this._multiline, _i = 0; _i < t4; ++_i) {
+ line = lines[_i];
+ _this._writeSidebar$1$line(lineNumber);
+ t1._contents += C.JSString_methods.$mul(" ", t3 ? 3 : 1);
+ _this._writeText$1(line);
+ t1._contents += "\n";
+ ++lineNumber;
+ }
+ context = C.JSString_methods.substring$1(context, lineStart);
+ }
+ lines = H.setRuntimeTypeInfo(context.split("\n"), type$.JSArray_String);
+ t3 = t2.get$end().get$line();
+ t2 = t2.get$start().get$line();
+ if (typeof t3 !== "number")
+ return t3.$sub();
+ if (typeof t2 !== "number")
+ return H.iae(t2);
+ lastLineIndex = t3 - t2;
+ t2 = C.JSArray_methods.get$last(lines);
+ t2.toString;
+ if (J.get$length$asx(t2) === 0 && lines.length > lastLineIndex + 1) {
+ if (0 >= lines.length)
+ return H.ioore(lines, -1);
+ lines.pop();
+ }
+ _this._writeFirstLine$1(C.JSArray_methods.get$first(lines));
+ if (_this._multiline) {
+ _this._writeIntermediateLines$1(H.SubListIterable$(lines, 1, null, type$.String).take$1(0, lastLineIndex - 1));
+ if (lastLineIndex < 0 || lastLineIndex >= lines.length)
+ return H.ioore(lines, lastLineIndex);
+ _this._writeLastLine$1(lines[lastLineIndex]);
+ }
+ _this._writeTrailingLines$1(H.SubListIterable$(lines, lastLineIndex + 1, null, type$.String));
+ _this._writeSidebar$1$end($._glyphs.get$upEnd());
+ t1 = t1._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ _writeFirstLine$1: function(line) {
+ var t3, t4, startColumn, endColumn, textBefore, textInside, tabsBefore, tabsInside, _this = this, t1 = {},
+ t2 = _this._span;
+ _this._writeSidebar$1$line(t2.get$start().get$line());
+ t3 = t2.get$start().get$column();
+ t4 = line.length;
+ startColumn = t1.startColumn = Math.min(t3, t4);
+ t3 = t2.get$end();
+ t3 = t3.get$offset(t3);
+ t2 = t2.get$start();
+ endColumn = t1.endColumn = Math.min(startColumn + t3 - t2.get$offset(t2), t4);
+ textBefore = J.substring$2$s(line, 0, startColumn);
+ t2 = _this._multiline;
+ if (t2 && _this._isOnlyWhitespace$1(textBefore)) {
+ t1 = _this._highlighter$_buffer;
+ t1._contents += " ";
+ _this._colorize$1(new U.Highlighter__writeFirstLine_closure(_this, line));
+ t1._contents += "\n";
+ return;
+ }
+ t3 = _this._highlighter$_buffer;
+ t3._contents += C.JSString_methods.$mul(" ", t2 ? 3 : 1);
+ _this._writeText$1(textBefore);
+ textInside = C.JSString_methods.substring$2(line, startColumn, endColumn);
+ _this._colorize$1(new U.Highlighter__writeFirstLine_closure0(_this, textInside));
+ _this._writeText$1(C.JSString_methods.substring$1(line, endColumn));
+ t3._contents += "\n";
+ tabsBefore = _this._countTabs$1(textBefore);
+ tabsInside = _this._countTabs$1(textInside);
+ startColumn += tabsBefore * 3;
+ t1.startColumn = startColumn;
+ t1.endColumn = endColumn + (tabsBefore + tabsInside) * 3;
+ _this._writeSidebar$0();
+ if (t2) {
+ t3._contents += " ";
+ _this._colorize$1(new U.Highlighter__writeFirstLine_closure1(t1, _this));
+ } else {
+ t3._contents += C.JSString_methods.$mul(" ", startColumn + 1);
+ _this._colorize$1(new U.Highlighter__writeFirstLine_closure2(t1, _this));
+ }
+ t3._contents += "\n";
+ },
+ _writeIntermediateLines$1: function(lines) {
+ var t1, lineNumber, t2, t3, _this = this;
+ type$.Iterable_String._check(lines);
+ H.assertHelper(_this._multiline);
+ t1 = _this._span.get$start().get$line();
+ if (typeof t1 !== "number")
+ return t1.$add();
+ lineNumber = t1 + 1;
+ for (t1 = new H.ListIterator(lines, lines.get$length(lines), lines.$ti._eval$1("ListIterator<ListIterable.E>")), t2 = _this._highlighter$_buffer; t1.moveNext$0();) {
+ t3 = t1.__internal$_current;
+ _this._writeSidebar$1$line(lineNumber);
+ t2._contents += " ";
+ _this._colorize$1(new U.Highlighter__writeIntermediateLines_closure(_this, t3));
+ t2._contents += "\n";
+ ++lineNumber;
+ }
+ },
+ _writeLastLine$1: function(line) {
+ var t3, t4, endColumn, textInside, _this = this, t1 = {},
+ t2 = _this._multiline;
+ H.assertHelper(t2);
+ t3 = _this._span;
+ _this._writeSidebar$1$line(t3.get$end().get$line());
+ t3 = t3.get$end().get$column();
+ t4 = line.length;
+ endColumn = t1.endColumn = Math.min(t3, t4);
+ if (t2 && endColumn === t4) {
+ t1 = _this._highlighter$_buffer;
+ t1._contents += " ";
+ _this._colorize$1(new U.Highlighter__writeLastLine_closure(_this, line));
+ t1._contents += "\n";
+ return;
+ }
+ t2 = _this._highlighter$_buffer;
+ t2._contents += " ";
+ textInside = J.substring$2$s(line, 0, endColumn);
+ _this._colorize$1(new U.Highlighter__writeLastLine_closure0(_this, textInside));
+ _this._writeText$1(C.JSString_methods.substring$1(line, endColumn));
+ t2._contents += "\n";
+ t1.endColumn = endColumn + _this._countTabs$1(textInside) * 3;
+ _this._writeSidebar$0();
+ t2._contents += " ";
+ _this._colorize$1(new U.Highlighter__writeLastLine_closure1(t1, _this));
+ t2._contents += "\n";
+ },
+ _writeTrailingLines$1: function(lines) {
+ var t1, lineNumber, t2, t3, t4, _this = this;
+ type$.Iterable_String._check(lines);
+ t1 = _this._span.get$end().get$line();
+ if (typeof t1 !== "number")
+ return t1.$add();
+ lineNumber = t1 + 1;
+ for (t1 = new H.ListIterator(lines, lines.get$length(lines), lines.$ti._eval$1("ListIterator<ListIterable.E>")), t2 = _this._highlighter$_buffer, t3 = _this._multiline; t1.moveNext$0();) {
+ t4 = t1.__internal$_current;
+ _this._writeSidebar$1$line(lineNumber);
+ t2._contents += C.JSString_methods.$mul(" ", t3 ? 3 : 1);
+ _this._writeText$1(t4);
+ t2._contents += "\n";
+ ++lineNumber;
+ }
+ },
+ _writeText$1: function(text) {
+ var t1, t2, t3;
+ text.toString;
+ t1 = new H.CodeUnits(text);
+ t1 = new H.ListIterator(t1, t1.get$length(t1), type$.CodeUnits._eval$1("ListIterator<ListMixin.E>"));
+ t2 = this._highlighter$_buffer;
+ for (; t1.moveNext$0();) {
+ t3 = t1.__internal$_current;
+ if (t3 === 9)
+ t2._contents += C.JSString_methods.$mul(" ", 4);
+ else
+ t2._contents += H.Primitives_stringFromCharCode(t3);
+ }
+ },
+ _writeSidebar$2$end$line: function(end, line) {
+ this._colorize$2$color(new U.Highlighter__writeSidebar_closure(this, line, end), "\x1b[34m");
+ },
+ _writeSidebar$1$end: function(end) {
+ return this._writeSidebar$2$end$line(end, null);
+ },
+ _writeSidebar$1$line: function(line) {
+ return this._writeSidebar$2$end$line(null, line);
+ },
+ _writeSidebar$0: function() {
+ return this._writeSidebar$2$end$line(null, null);
+ },
+ _countTabs$1: function(text) {
+ var t1, count;
+ for (t1 = new H.CodeUnits(text), t1 = new H.ListIterator(t1, t1.get$length(t1), type$.CodeUnits._eval$1("ListIterator<ListMixin.E>")), count = 0; t1.moveNext$0();)
+ if (t1.__internal$_current === 9)
+ ++count;
+ return count;
+ },
+ _isOnlyWhitespace$1: function(text) {
+ var t1, t2;
+ for (t1 = new H.CodeUnits(text), t1 = new H.ListIterator(t1, t1.get$length(t1), type$.CodeUnits._eval$1("ListIterator<ListMixin.E>")); t1.moveNext$0();) {
+ t2 = t1.__internal$_current;
+ if (t2 !== 32 && t2 !== 9)
+ return false;
+ }
+ return true;
+ },
+ _colorize$2$color: function(callback, color) {
+ var t1, t2;
+ type$.void_Function._check(callback);
+ t1 = this._color;
+ t2 = t1 != null;
+ if (t2) {
+ t1 = color == null ? t1 : color;
+ this._highlighter$_buffer._contents += t1;
+ }
+ callback.call$0();
+ if (t2)
+ this._highlighter$_buffer._contents += "\x1b[0m";
+ },
+ _colorize$1: function(callback) {
+ return this._colorize$2$color(callback, null);
+ }
+ };
+ U.Highlighter__writeFirstLine_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ t2 = t1._highlighter$_buffer,
+ t3 = t2._contents += $._glyphs.glyphOrAscii$2("\u250c", "/");
+ t2._contents = t3 + " ";
+ t1._writeText$1(this.line);
+ },
+ $signature: 0
+ };
+ U.Highlighter__writeFirstLine_closure0.prototype = {
+ call$0: function() {
+ return this.$this._writeText$1(this.textInside);
+ },
+ $signature: 1
+ };
+ U.Highlighter__writeFirstLine_closure1.prototype = {
+ call$0: function() {
+ var t2,
+ t1 = this.$this._highlighter$_buffer;
+ t1._contents += $._glyphs.get$topLeftCorner();
+ t2 = t1._contents += C.JSString_methods.$mul($._glyphs.get$horizontalLine(), this._box_0.startColumn + 1);
+ t1._contents = t2 + "^";
+ },
+ $signature: 0
+ };
+ U.Highlighter__writeFirstLine_closure2.prototype = {
+ call$0: function() {
+ var t1 = this._box_0;
+ this.$this._highlighter$_buffer._contents += C.JSString_methods.$mul("^", Math.max(t1.endColumn - t1.startColumn, 1));
+ return null;
+ },
+ $signature: 1
+ };
+ U.Highlighter__writeIntermediateLines_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ t2 = t1._highlighter$_buffer,
+ t3 = t2._contents += $._glyphs.get$verticalLine();
+ t2._contents = t3 + " ";
+ t1._writeText$1(this.line);
+ },
+ $signature: 0
+ };
+ U.Highlighter__writeLastLine_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ t2 = t1._highlighter$_buffer,
+ t3 = t2._contents += $._glyphs.glyphOrAscii$2("\u2514", "\\");
+ t2._contents = t3 + " ";
+ t1._writeText$1(this.line);
+ },
+ $signature: 0
+ };
+ U.Highlighter__writeLastLine_closure0.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ t2 = t1._highlighter$_buffer,
+ t3 = t2._contents += $._glyphs.get$verticalLine();
+ t2._contents = t3 + " ";
+ t1._writeText$1(this.textInside);
+ },
+ $signature: 0
+ };
+ U.Highlighter__writeLastLine_closure1.prototype = {
+ call$0: function() {
+ var t2,
+ t1 = this.$this._highlighter$_buffer;
+ t1._contents += $._glyphs.get$bottomLeftCorner();
+ t2 = t1._contents += C.JSString_methods.$mul($._glyphs.get$horizontalLine(), this._box_0.endColumn);
+ t1._contents = t2 + "^";
+ },
+ $signature: 0
+ };
+ U.Highlighter__writeSidebar_closure.prototype = {
+ call$0: function() {
+ var t1 = this.line,
+ t2 = this.$this,
+ t3 = t2._highlighter$_buffer;
+ t2 = t2._paddingBeforeSidebar;
+ if (t1 != null)
+ t3._contents += C.JSString_methods.padRight$1(C.JSInt_methods.toString$0(t1 + 1), t2);
+ else
+ t3._contents += C.JSString_methods.$mul(" ", t2);
+ t1 = this.end;
+ t3._contents += t1 == null ? $._glyphs.get$verticalLine() : t1;
+ },
+ $signature: 0
+ };
+ V.SourceLocation.prototype = {
+ distance$1: function(other) {
+ var t1 = this.sourceUrl;
+ if (!J.$eq$(t1, other.get$sourceUrl()))
+ throw H.wrapException(P.ArgumentError$('Source URLs "' + H.S(t1) + '" and "' + H.S(other.get$sourceUrl()) + "\" don't match."));
+ return Math.abs(this.offset - other.get$offset(other));
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return type$.SourceLocation._is(other) && J.$eq$(this.sourceUrl, other.get$sourceUrl()) && this.offset === other.get$offset(other);
+ },
+ get$hashCode: function(_) {
+ return J.get$hashCode$(this.sourceUrl) + this.offset;
+ },
+ toString$0: function(_) {
+ var _this = this,
+ t1 = "<" + H.getRuntimeType(_this).toString$0(0) + ": " + _this.offset + " ",
+ source = _this.sourceUrl;
+ return t1 + (H.S(source == null ? "unknown source" : source) + ":" + (_this.line + 1) + ":" + (_this.column + 1)) + ">";
+ },
+ get$sourceUrl: function() {
+ return this.sourceUrl;
+ },
+ get$offset: function(receiver) {
+ return this.offset;
+ },
+ get$line: function() {
+ return this.line;
+ },
+ get$column: function() {
+ return this.column;
+ }
+ };
+ D.SourceLocationMixin.prototype = {
+ distance$1: function(other) {
+ if (!J.$eq$(this.file.url, other.get$sourceUrl()))
+ throw H.wrapException(P.ArgumentError$('Source URLs "' + H.S(this.get$sourceUrl()) + '" and "' + H.S(other.get$sourceUrl()) + "\" don't match."));
+ return Math.abs(this.offset - other.get$offset(other));
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return type$.SourceLocation._is(other) && J.$eq$(this.file.url, other.get$sourceUrl()) && this.offset === other.get$offset(other);
+ },
+ get$hashCode: function(_) {
+ return J.get$hashCode$(this.file.url) + this.offset;
+ },
+ toString$0: function(_) {
+ var t1 = this.offset,
+ t2 = "<" + H.getRuntimeType(this).toString$0(0) + ": " + t1 + " ",
+ t3 = this.file,
+ source = t3.url,
+ t4 = H.S(source == null ? "unknown source" : source) + ":",
+ t5 = t3.getLine$1(t1);
+ if (typeof t5 !== "number")
+ return t5.$add();
+ return t2 + (t4 + (t5 + 1) + ":" + (t3.getColumn$1(t1) + 1)) + ">";
+ },
+ $isSourceLocation: 1
+ };
+ V.SourceSpan.prototype = {};
+ V.SourceSpanBase.prototype = {
+ SourceSpanBase$3: function(start, end, text) {
+ var t3,
+ t1 = this.end,
+ t2 = this.start;
+ if (!J.$eq$(t1.get$sourceUrl(), t2.get$sourceUrl()))
+ throw H.wrapException(P.ArgumentError$('Source URLs "' + H.S(t2.get$sourceUrl()) + '" and "' + H.S(t1.get$sourceUrl()) + "\" don't match."));
+ else if (t1.get$offset(t1) < t2.get$offset(t2))
+ throw H.wrapException(P.ArgumentError$("End " + t1.toString$0(0) + " must come after start " + t2.toString$0(0) + "."));
+ else {
+ t3 = this.text;
+ if (t3.length !== t2.distance$1(t1))
+ throw H.wrapException(P.ArgumentError$('Text "' + t3 + '" must be ' + t2.distance$1(t1) + " characters long."));
+ }
+ },
+ get$start: function() {
+ return this.start;
+ },
+ get$end: function() {
+ return this.end;
+ },
+ get$text: function() {
+ return this.text;
+ }
+ };
+ G.SourceSpanException.prototype = {
+ get$message: function(_) {
+ return this._span_exception$_message;
+ },
+ toString$1$color: function(_, color) {
+ var t1 = this._span_exception$_span;
+ if (t1 == null)
+ return this._span_exception$_message;
+ return "Error on " + t1.message$2$color(0, this._span_exception$_message, color);
+ },
+ toString$0: function($receiver) {
+ return this.toString$1$color($receiver, null);
+ },
+ $isException: 1
+ };
+ G.SourceSpanFormatException.prototype = {$isFormatException: 1};
+ Y.SourceSpanMixin.prototype = {
+ get$sourceUrl: function() {
+ return this.get$start().get$sourceUrl();
+ },
+ get$length: function(_) {
+ var t2,
+ t1 = this.get$end();
+ t1 = t1.get$offset(t1);
+ t2 = this.get$start();
+ return t1 - t2.get$offset(t2);
+ },
+ message$2$color: function(_, message, color) {
+ var t2, highlight, _this = this,
+ t1 = _this.get$start().get$line();
+ if (typeof t1 !== "number")
+ return t1.$add();
+ t1 = "line " + (t1 + 1) + ", column " + (_this.get$start().get$column() + 1);
+ if (_this.get$sourceUrl() != null) {
+ t2 = _this.get$sourceUrl();
+ t2 = t1 + (" of " + H.S($.$get$context().prettyUri$1(t2)));
+ t1 = t2;
+ }
+ t1 += ": " + H.S(message);
+ highlight = _this.highlight$1$color(color);
+ if (highlight.length !== 0)
+ t1 = t1 + "\n" + highlight;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ message$1: function($receiver, message) {
+ return this.message$2$color($receiver, message, null);
+ },
+ highlight$1$color: function(color) {
+ var t2, t3, t4, newSpan, _this = this,
+ t1 = type$.SourceSpanWithContext._is(_this);
+ if (!t1 && _this.get$length(_this) === 0)
+ return "";
+ if (t1 && B.findLineStart(_this.get$context(), _this.get$text(), _this.get$start().get$column()) != null)
+ t1 = _this;
+ else {
+ t1 = _this.get$start();
+ t1 = V.SourceLocation$(t1.get$offset(t1), 0, 0, _this.get$sourceUrl());
+ t2 = _this.get$end();
+ t2 = t2.get$offset(t2);
+ t3 = _this.get$sourceUrl();
+ t4 = B.countCodeUnits(_this.get$text(), 10);
+ t3 = X.SourceSpanWithContext$(t1, V.SourceLocation$(t2, U.Highlighter__lastLineLength(_this.get$text()), t4, t3), _this.get$text(), _this.get$text());
+ t1 = t3;
+ }
+ newSpan = U.Highlighter__normalizeEndOfLine(U.Highlighter__normalizeTrailingNewline(U.Highlighter__normalizeNewlines(t1)));
+ return new U.Highlighter(newSpan, color, newSpan.get$start().get$line() != newSpan.get$end().get$line(), J.toString$0$(newSpan.get$end().get$line()).length + 1, new P.StringBuffer("")).highlight$0();
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return type$.SourceSpan._is(other) && this.get$start().$eq(0, other.get$start()) && this.get$end().$eq(0, other.get$end());
+ },
+ get$hashCode: function(_) {
+ var t2,
+ t1 = this.get$start();
+ t1 = t1.get$hashCode(t1);
+ t2 = this.get$end();
+ return t1 + 31 * t2.get$hashCode(t2);
+ },
+ toString$0: function(_) {
+ var _this = this;
+ return "<" + H.getRuntimeType(_this).toString$0(0) + ": from " + _this.get$start().toString$0(0) + " to " + _this.get$end().toString$0(0) + ' "' + _this.get$text() + '">';
+ },
+ $isSourceSpan: 1
+ };
+ X.SourceSpanWithContext.prototype = {
+ get$context: function() {
+ return this._context;
+ }
+ };
+ U.Chain.prototype = {
+ foldFrames$2$terse: function(predicate, terse) {
+ var t1 = this.traces,
+ t2 = H._arrayInstanceType(t1),
+ t3 = t2._eval$1("MappedListIterable<1,Trace>"),
+ foldedTraces = new H.MappedListIterable(t1, t2._eval$1("Trace(1)")._check(new U.Chain_foldFrames_closure(type$.bool_Function_Frame._check(predicate), true)), t3),
+ nonEmptyTraces = foldedTraces.super$Iterable$where(0, t3._eval$1("bool(ListIterable.E)")._check(new U.Chain_foldFrames_closure0(true)));
+ if (!nonEmptyTraces.get$iterator(nonEmptyTraces).moveNext$0() && !foldedTraces.get$isEmpty(foldedTraces))
+ return new U.Chain(P.List_List$unmodifiable(H.setRuntimeTypeInfo([foldedTraces.get$last(foldedTraces)], type$.JSArray_Trace), type$.Trace));
+ return new U.Chain(P.List_List$unmodifiable(nonEmptyTraces, type$.Trace));
+ },
+ toTrace$0: function() {
+ var t1 = this.traces,
+ t2 = H._arrayInstanceType(t1);
+ return new Y.Trace(P.List_List$unmodifiable(new H.ExpandIterable(t1, t2._eval$1("Iterable<Frame>(1)")._check(new U.Chain_toTrace_closure()), t2._eval$1("ExpandIterable<1,Frame>")), type$.Frame), new P._StringStackTrace(null));
+ },
+ toString$0: function(_) {
+ var t1 = this.traces,
+ t2 = H._arrayInstanceType(t1),
+ t3 = type$.int;
+ return new H.MappedListIterable(t1, t2._eval$1("String(1)")._check(new U.Chain_toString_closure(new H.MappedListIterable(t1, t2._eval$1("int(1)")._check(new U.Chain_toString_closure0()), t2._eval$1("MappedListIterable<1,int>")).fold$1$2(0, 0, H.instantiate1(P.math__max$closure(), t3), t3))), t2._eval$1("MappedListIterable<1,String>")).join$1(0, "===== asynchronous gap ===========================\n");
+ },
+ $isStackTrace: 1,
+ get$traces: function() {
+ return this.traces;
+ }
+ };
+ U.Chain_capture_closure.prototype = {
+ call$0: function() {
+ var error, stackTrace, t1, exception;
+ try {
+ t1 = this.callback.call$0();
+ return t1;
+ } catch (exception) {
+ error = H.unwrapException(exception);
+ stackTrace = H.getTraceFromException(exception);
+ $.Zone__current.handleUncaughtError$2(error, stackTrace);
+ return null;
+ }
+ },
+ $signature: function() {
+ return this.T._eval$1("0()");
+ }
+ };
+ U.Chain_Chain$current_closure.prototype = {
+ call$0: function() {
+ var t3,
+ t1 = this.chain,
+ t2 = C.JSArray_methods.get$first(t1.get$traces()).get$frames();
+ t2 = H.SubListIterable$(t2, this.level + 2, null, H._arrayInstanceType(t2)._precomputed1);
+ t3 = C.JSArray_methods.get$first(t1.get$traces()).get$original();
+ t3 = H.setRuntimeTypeInfo([new Y.Trace(P.List_List$unmodifiable(t2, type$.Frame), new P._StringStackTrace(t3._stackTrace))], type$.JSArray_Trace);
+ t1 = t1.get$traces();
+ C.JSArray_methods.addAll$1(t3, H.SubListIterable$(t1, 1, null, H._arrayInstanceType(t1)._precomputed1));
+ return new U.Chain(P.List_List$unmodifiable(t3, type$.Trace));
+ },
+ $signature: 16
+ };
+ U.Chain_Chain$forTrace_closure.prototype = {
+ call$0: function() {
+ return U.Chain_Chain$parse(J.toString$0$(this.trace));
+ },
+ $signature: 16
+ };
+ U.Chain_Chain$parse_closure.prototype = {
+ call$1: function(trace) {
+ H._checkStringNullable(trace);
+ return new Y.Trace(P.List_List$unmodifiable(Y.Trace__parseVM(trace), type$.Frame), new P._StringStackTrace(trace));
+ },
+ $signature: 42
+ };
+ U.Chain_Chain$parse_closure0.prototype = {
+ call$1: function(trace) {
+ return Y.Trace$parseFriendly(H._checkStringNullable(trace));
+ },
+ $signature: 42
+ };
+ U.Chain_foldFrames_closure.prototype = {
+ call$1: function(trace) {
+ return type$.Trace._check(trace).foldFrames$2$terse(this.predicate, this.terse);
+ },
+ $signature: 45
+ };
+ U.Chain_foldFrames_closure0.prototype = {
+ call$1: function(trace) {
+ type$.Trace._check(trace);
+ if (trace.get$frames().length > 1)
+ return true;
+ if (trace.get$frames().length === 0)
+ return false;
+ if (!this.terse)
+ return false;
+ return C.JSArray_methods.get$single(trace.get$frames()).get$line() != null;
+ },
+ $signature: 52
+ };
+ U.Chain_toTrace_closure.prototype = {
+ call$1: function(trace) {
+ return type$.Trace._check(trace).get$frames();
+ },
+ $signature: 53
+ };
+ U.Chain_toString_closure0.prototype = {
+ call$1: function(trace) {
+ var t1 = type$.Trace._check(trace).get$frames(),
+ t2 = H._arrayInstanceType(t1),
+ t3 = type$.int;
+ return new H.MappedListIterable(t1, t2._eval$1("int(1)")._check(new U.Chain_toString__closure0()), t2._eval$1("MappedListIterable<1,int>")).fold$1$2(0, 0, H.instantiate1(P.math__max$closure(), t3), t3);
+ },
+ $signature: 54
+ };
+ U.Chain_toString__closure0.prototype = {
+ call$1: function(frame) {
+ type$.Frame._check(frame);
+ return frame.get$location(frame).length;
+ },
+ $signature: 39
+ };
+ U.Chain_toString_closure.prototype = {
+ call$1: function(trace) {
+ var t1 = type$.Trace._check(trace).get$frames(),
+ t2 = H._arrayInstanceType(t1);
+ return new H.MappedListIterable(t1, t2._eval$1("String(1)")._check(new U.Chain_toString__closure(this.longest)), t2._eval$1("MappedListIterable<1,String>")).join$0(0);
+ },
+ $signature: 56
+ };
+ U.Chain_toString__closure.prototype = {
+ call$1: function(frame) {
+ type$.Frame._check(frame);
+ return J.padRight$1$s(frame.get$location(frame), this.longest) + " " + H.S(frame.get$member()) + "\n";
+ },
+ $signature: 38
+ };
+ A.Frame.prototype = {
+ get$isCore: function() {
+ return this.uri.get$scheme() === "dart";
+ },
+ get$library: function() {
+ var t1 = this.uri;
+ if (t1.get$scheme() === "data")
+ return "data:...";
+ return $.$get$context().prettyUri$1(t1);
+ },
+ get$$package: function() {
+ var t1 = this.uri;
+ if (t1.get$scheme() !== "package")
+ return null;
+ return C.JSArray_methods.get$first(t1.get$path(t1).split("/"));
+ },
+ get$location: function(_) {
+ var t2, _this = this,
+ t1 = _this.line;
+ if (t1 == null)
+ return _this.get$library();
+ t2 = _this.column;
+ if (t2 == null)
+ return H.S(_this.get$library()) + " " + H.S(t1);
+ return H.S(_this.get$library()) + " " + H.S(t1) + ":" + H.S(t2);
+ },
+ toString$0: function(_) {
+ return H.S(this.get$location(this)) + " in " + H.S(this.member);
+ },
+ get$uri: function() {
+ return this.uri;
+ },
+ get$line: function() {
+ return this.line;
+ },
+ get$column: function() {
+ return this.column;
+ },
+ get$member: function() {
+ return this.member;
+ }
+ };
+ A.Frame_Frame$parseVM_closure.prototype = {
+ call$0: function() {
+ var match, t2, t3, member, uri, lineAndColumn, line, _null = null,
+ t1 = this.frame;
+ if (t1 === "...")
+ return new A.Frame(P._Uri__Uri(_null, _null, _null, _null), _null, _null, "...");
+ match = $.$get$_vmFrame().firstMatch$1(t1);
+ if (match == null)
+ return new N.UnparsedFrame(P._Uri__Uri(_null, "unparsed", _null, _null), t1);
+ t1 = match._match;
+ if (1 >= t1.length)
+ return H.ioore(t1, 1);
+ t2 = t1[1];
+ t3 = $.$get$_asyncBody();
+ t2.toString;
+ t2 = H.stringReplaceAllUnchecked(t2, t3, "<async>");
+ member = H.stringReplaceAllUnchecked(t2, "<anonymous closure>", "<fn>");
+ if (2 >= t1.length)
+ return H.ioore(t1, 2);
+ uri = P.Uri_parse(t1[2]);
+ if (3 >= t1.length)
+ return H.ioore(t1, 3);
+ lineAndColumn = t1[3].split(":");
+ t1 = lineAndColumn.length;
+ line = t1 > 1 ? P.int_parse(lineAndColumn[1], _null, _null) : _null;
+ return new A.Frame(uri, line, t1 > 2 ? P.int_parse(lineAndColumn[2], _null, _null) : _null, member);
+ },
+ $signature: 17
+ };
+ A.Frame_Frame$parseV8_closure.prototype = {
+ call$0: function() {
+ var t2, t3, t4, _s4_ = "<fn>",
+ t1 = this.frame,
+ match = $.$get$_v8Frame().firstMatch$1(t1);
+ if (match == null)
+ return new N.UnparsedFrame(P._Uri__Uri(null, "unparsed", null, null), t1);
+ t1 = new A.Frame_Frame$parseV8_closure_parseLocation(t1);
+ t2 = match._match;
+ t3 = t2.length;
+ if (2 >= t3)
+ return H.ioore(t2, 2);
+ t4 = t2[2];
+ if (t4 != null) {
+ t2 = t2[1];
+ t2.toString;
+ t2 = H.stringReplaceAllUnchecked(t2, "<anonymous>", _s4_);
+ t2 = H.stringReplaceAllUnchecked(t2, "Anonymous function", _s4_);
+ return t1.call$2(t4, H.stringReplaceAllUnchecked(t2, "(anonymous function)", _s4_));
+ } else {
+ if (3 >= t3)
+ return H.ioore(t2, 3);
+ return t1.call$2(t2[3], _s4_);
+ }
+ },
+ $signature: 17
+ };
+ A.Frame_Frame$parseV8_closure_parseLocation.prototype = {
+ call$2: function($location, member) {
+ var t2, urlMatch, t3, _null = null,
+ t1 = $.$get$_v8EvalLocation(),
+ evalMatch = t1.firstMatch$1($location);
+ for (; evalMatch != null;) {
+ t2 = evalMatch._match;
+ if (1 >= t2.length)
+ return H.ioore(t2, 1);
+ $location = t2[1];
+ evalMatch = t1.firstMatch$1($location);
+ }
+ if ($location === "native")
+ return new A.Frame(P.Uri_parse("native"), _null, _null, member);
+ urlMatch = $.$get$_v8UrlLocation().firstMatch$1($location);
+ if (urlMatch == null)
+ return new N.UnparsedFrame(P._Uri__Uri(_null, "unparsed", _null, _null), this.frame);
+ t1 = urlMatch._match;
+ if (1 >= t1.length)
+ return H.ioore(t1, 1);
+ t2 = A.Frame__uriOrPathToUri(t1[1]);
+ if (2 >= t1.length)
+ return H.ioore(t1, 2);
+ t3 = P.int_parse(t1[2], _null, _null);
+ if (3 >= t1.length)
+ return H.ioore(t1, 3);
+ return new A.Frame(t2, t3, P.int_parse(t1[3], _null, _null), member);
+ },
+ $signature: 59
+ };
+ A.Frame_Frame$parseFirefox_closure.prototype = {
+ call$0: function() {
+ var uri, t2, t3, member, line, _null = null,
+ t1 = this.frame,
+ match = $.$get$_firefoxSafariFrame().firstMatch$1(t1);
+ if (match == null)
+ return new N.UnparsedFrame(P._Uri__Uri(_null, "unparsed", _null, _null), t1);
+ t1 = match._match;
+ if (3 >= t1.length)
+ return H.ioore(t1, 3);
+ uri = A.Frame__uriOrPathToUri(t1[3]);
+ t2 = t1.length;
+ if (1 >= t2)
+ return H.ioore(t1, 1);
+ t3 = t1[1];
+ if (t3 != null) {
+ if (2 >= t2)
+ return H.ioore(t1, 2);
+ t2 = C.JSString_methods.allMatches$1("/", t1[2]);
+ member = J.$add$ansx(t3, C.JSArray_methods.join$0(P.List_List$filled(t2.get$length(t2), ".<fn>", type$.String)));
+ if (member === "")
+ member = "<fn>";
+ member = C.JSString_methods.replaceFirst$2(member, $.$get$_initialDot(), "");
+ } else
+ member = "<fn>";
+ if (4 >= t1.length)
+ return H.ioore(t1, 4);
+ t2 = t1[4];
+ line = t2 === "" ? _null : P.int_parse(t2, _null, _null);
+ if (5 >= t1.length)
+ return H.ioore(t1, 5);
+ t1 = t1[5];
+ return new A.Frame(uri, line, t1 == null || t1 === "" ? _null : P.int_parse(t1, _null, _null), member);
+ },
+ $signature: 17
+ };
+ A.Frame_Frame$parseFriendly_closure.prototype = {
+ call$0: function() {
+ var t2, buffer, indices, uri, line, column, _null = null,
+ t1 = this.frame,
+ match = $.$get$_friendlyFrame().firstMatch$1(t1);
+ if (match == null)
+ throw H.wrapException(P.FormatException$("Couldn't parse package:stack_trace stack trace line '" + H.S(t1) + "'.", _null, _null));
+ t1 = match._match;
+ if (1 >= t1.length)
+ return H.ioore(t1, 1);
+ t2 = t1[1];
+ if (t2 === "data:...") {
+ buffer = new P.StringBuffer("");
+ indices = H.setRuntimeTypeInfo([-1], type$.JSArray_int);
+ P.UriData__writeUri(_null, _null, _null, buffer, indices);
+ C.JSArray_methods.add$1(indices, buffer._contents.length);
+ buffer._contents += ",";
+ P.UriData__uriEncodeBytes(C.List_CVk, C.C_AsciiCodec.encode$1(""), buffer);
+ t2 = buffer._contents;
+ uri = new P.UriData(t2.charCodeAt(0) == 0 ? t2 : t2, indices, _null).get$uri();
+ } else
+ uri = P.Uri_parse(t2);
+ if (uri.get$scheme() === "") {
+ t2 = $.$get$context();
+ uri = t2.toUri$1(t2.absolute$7(0, t2.style.pathFromUri$1(M._parseUri(uri)), _null, _null, _null, _null, _null, _null));
+ }
+ if (2 >= t1.length)
+ return H.ioore(t1, 2);
+ t2 = t1[2];
+ line = t2 == null ? _null : P.int_parse(t2, _null, _null);
+ if (3 >= t1.length)
+ return H.ioore(t1, 3);
+ t2 = t1[3];
+ column = t2 == null ? _null : P.int_parse(t2, _null, _null);
+ if (4 >= t1.length)
+ return H.ioore(t1, 4);
+ return new A.Frame(uri, line, column, t1[4]);
+ },
+ $signature: 17
+ };
+ X.LazyChain.prototype = {
+ get$_chain: function() {
+ var _this = this;
+ if (_this._lazy_chain$_inner == null)
+ _this.set$_lazy_chain$_inner(_this._thunk.call$0());
+ return _this._lazy_chain$_inner;
+ },
+ get$traces: function() {
+ return this.get$_chain().get$traces();
+ },
+ foldFrames$2$terse: function(predicate, terse) {
+ return new X.LazyChain(new X.LazyChain_foldFrames_closure(this, type$.bool_Function_Frame._check(predicate), true));
+ },
+ toTrace$0: function() {
+ return new T.LazyTrace(new X.LazyChain_toTrace_closure(this));
+ },
+ toString$0: function(_) {
+ return J.toString$0$(this.get$_chain());
+ },
+ set$_lazy_chain$_inner: function(_inner) {
+ this._lazy_chain$_inner = type$.Chain._check(_inner);
+ },
+ $isStackTrace: 1,
+ $isChain: 1
+ };
+ X.LazyChain_foldFrames_closure.prototype = {
+ call$0: function() {
+ return this.$this.get$_chain().foldFrames$2$terse(this.predicate, this.terse);
+ },
+ $signature: 16
+ };
+ X.LazyChain_toTrace_closure.prototype = {
+ call$0: function() {
+ return this.$this.get$_chain().toTrace$0();
+ },
+ $signature: 8
+ };
+ T.LazyTrace.prototype = {
+ get$_lazy_trace$_trace: function() {
+ var _this = this;
+ if (_this._lazy_trace$_inner == null)
+ _this.set$_lazy_trace$_inner(_this._lazy_trace$_thunk.call$0());
+ return _this._lazy_trace$_inner;
+ },
+ get$frames: function() {
+ return this.get$_lazy_trace$_trace().get$frames();
+ },
+ get$original: function() {
+ return this.get$_lazy_trace$_trace().get$original();
+ },
+ foldFrames$2$terse: function(predicate, terse) {
+ return new T.LazyTrace(new T.LazyTrace_foldFrames_closure(this, type$.bool_Function_Frame._check(predicate), true));
+ },
+ toString$0: function(_) {
+ return J.toString$0$(this.get$_lazy_trace$_trace());
+ },
+ set$_lazy_trace$_inner: function(_inner) {
+ this._lazy_trace$_inner = type$.Trace._check(_inner);
+ },
+ $isStackTrace: 1,
+ $isTrace: 1
+ };
+ T.LazyTrace_foldFrames_closure.prototype = {
+ call$0: function() {
+ return this.$this.get$_lazy_trace$_trace().foldFrames$2$terse(this.predicate, this.terse);
+ },
+ $signature: 8
+ };
+ O.StackZoneSpecification.prototype = {
+ chainFor$1: function(trace) {
+ var t2, previous, t3, t1 = {};
+ t1.trace = trace;
+ if (type$.Chain._is(trace))
+ return trace;
+ if (trace == null) {
+ trace = P.StackTrace_current();
+ t1.trace = trace;
+ t2 = trace;
+ } else
+ t2 = trace;
+ previous = this._chains.$index(0, t2);
+ if (previous == null)
+ previous = this._currentNode;
+ if (previous == null) {
+ t3 = type$.Trace;
+ if (t3._is(t2))
+ return new U.Chain(P.List_List$unmodifiable(H.setRuntimeTypeInfo([t2], type$.JSArray_Trace), t3));
+ return new X.LazyChain(new O.StackZoneSpecification_chainFor_closure(t1));
+ } else
+ return new O._Node(Y.Trace_Trace$from(!type$.Trace._is(t2) ? t1.trace = new T.LazyTrace(new O.StackZoneSpecification_chainFor_closure0(this, t2)) : t2), previous).toChain$0();
+ },
+ _stack_zone_specification$_registerCallback$1$4: function($self, $parent, zone, f, $R) {
+ var t1, t2;
+ $R._eval$1("0()")._check(f);
+ if (f == null || J.$eq$($.Zone__current.$index(0, $.$get$StackZoneSpecification_disableKey()), true))
+ return $parent.registerCallback$1$2(zone, f, $R);
+ t1 = this._currentTrace$1(2);
+ t2 = this._currentNode;
+ return $parent.registerCallback$1$2(zone, new O.StackZoneSpecification__registerCallback_closure(this, f, new O._Node(Y.Trace_Trace$from(t1), t2), $R), $R);
+ },
+ _stack_zone_specification$_registerCallback$4: function($self, $parent, zone, f) {
+ return this._stack_zone_specification$_registerCallback$1$4($self, $parent, zone, f, type$.dynamic);
+ },
+ _stack_zone_specification$_registerUnaryCallback$2$4: function($self, $parent, zone, f, $R, $T) {
+ var t1, t2;
+ $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._check(f);
+ if (f == null || J.$eq$($.Zone__current.$index(0, $.$get$StackZoneSpecification_disableKey()), true))
+ return $parent.registerUnaryCallback$2$2(zone, f, $R, $T);
+ t1 = this._currentTrace$1(2);
+ t2 = this._currentNode;
+ return $parent.registerUnaryCallback$2$2(zone, new O.StackZoneSpecification__registerUnaryCallback_closure(this, f, new O._Node(Y.Trace_Trace$from(t1), t2), $T, $R), $R, $T);
+ },
+ _stack_zone_specification$_registerUnaryCallback$4: function($self, $parent, zone, f) {
+ return this._stack_zone_specification$_registerUnaryCallback$2$4($self, $parent, zone, f, type$.dynamic, type$.dynamic);
+ },
+ _stack_zone_specification$_registerBinaryCallback$3$4: function($self, $parent, zone, f, $R, T1, T2) {
+ var t1, t2;
+ type$.Function._check(f);
+ if (f == null || J.$eq$($.Zone__current.$index(0, $.$get$StackZoneSpecification_disableKey()), true))
+ return $parent.registerBinaryCallback$3$2(zone, $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._check(f), $R, T1, T2);
+ t1 = this._currentTrace$1(2);
+ t2 = this._currentNode;
+ return $parent.registerBinaryCallback$3$2(zone, new O.StackZoneSpecification__registerBinaryCallback_closure(this, f, new O._Node(Y.Trace_Trace$from(t1), t2), T1, T2, $R), $R, T1, T2);
+ },
+ _stack_zone_specification$_registerBinaryCallback$4: function($self, $parent, zone, f) {
+ return this._stack_zone_specification$_registerBinaryCallback$3$4($self, $parent, zone, f, type$.dynamic, type$.dynamic, type$.dynamic);
+ },
+ _stack_zone_specification$_errorCallback$5: function($self, $parent, zone, error, stackTrace) {
+ var t1, t2, t3, asyncError, _this = this;
+ type$.StackTrace._check(stackTrace);
+ if (J.$eq$($.Zone__current.$index(0, $.$get$StackZoneSpecification_disableKey()), true))
+ return $parent.errorCallback$3(zone, error, stackTrace);
+ if (stackTrace == null) {
+ t1 = _this._currentTrace$1(3);
+ t2 = _this._currentNode;
+ stackTrace = new O._Node(Y.Trace_Trace$from(t1), t2).toChain$0();
+ } else {
+ t1 = _this._chains;
+ if (t1.$index(0, stackTrace) == null) {
+ t2 = _this._currentTrace$1(3);
+ t3 = _this._currentNode;
+ t1.$indexSet(0, stackTrace, new O._Node(Y.Trace_Trace$from(t2), t3));
+ }
+ }
+ asyncError = $parent.errorCallback$3(zone, error, stackTrace);
+ return asyncError == null ? new P.AsyncError(error, stackTrace) : asyncError;
+ },
+ _stack_zone_specification$_run$1$2: function(f, node, $T) {
+ var previousNode, stackTrace, t1, exception, t2, _this = this;
+ $T._eval$1("0()")._check(f);
+ previousNode = _this._currentNode;
+ _this._currentNode = node;
+ try {
+ t1 = f.call$0();
+ return t1;
+ } catch (exception) {
+ H.unwrapException(exception);
+ stackTrace = H.getTraceFromException(exception);
+ t1 = _this._chains;
+ t2 = stackTrace;
+ if (t1.$index(0, t2) == null)
+ t1.$indexSet(0, t2, node);
+ throw exception;
+ } finally {
+ _this.set$_currentNode(previousNode);
+ }
+ },
+ _currentTrace$1: function(level) {
+ var t1 = {};
+ t1.level = level;
+ return new T.LazyTrace(new O.StackZoneSpecification__currentTrace_closure(t1, this, P.StackTrace_current()));
+ },
+ _trimVMChain$1: function(trace) {
+ var text = J.toString$0$(trace),
+ index = J.getInterceptor$s(text).indexOf$1(text, "<asynchronous suspension>\n");
+ return index === -1 ? text : C.JSString_methods.substring$2(text, 0, index);
+ },
+ set$_currentNode: function(_currentNode) {
+ this._currentNode = type$._Node._check(_currentNode);
+ }
+ };
+ O.StackZoneSpecification_chainFor_closure.prototype = {
+ call$0: function() {
+ return U.Chain_Chain$parse(J.toString$0$(this._box_0.trace));
+ },
+ $signature: 16
+ };
+ O.StackZoneSpecification_chainFor_closure0.prototype = {
+ call$0: function() {
+ return Y.Trace_Trace$parse(this.$this._trimVMChain$1(this.original));
+ },
+ $signature: 8
+ };
+ O.StackZoneSpecification__registerCallback_closure.prototype = {
+ call$0: function() {
+ var _this = this;
+ return _this.$this._stack_zone_specification$_run$1$2(_this.f, _this.node, _this.R);
+ },
+ $signature: function() {
+ return this.R._eval$1("0()");
+ }
+ };
+ O.StackZoneSpecification__registerUnaryCallback_closure.prototype = {
+ call$1: function(arg) {
+ var _this = this,
+ t1 = _this.R;
+ return _this.$this._stack_zone_specification$_run$1$2(new O.StackZoneSpecification__registerUnaryCallback__closure(_this.f, _this.T._check(arg), t1), _this.node, t1);
+ },
+ $signature: function() {
+ return this.R._eval$1("@<0>")._bind$1(this.T)._eval$1("1(2)");
+ }
+ };
+ O.StackZoneSpecification__registerUnaryCallback__closure.prototype = {
+ call$0: function() {
+ return this.f.call$1(this.arg);
+ },
+ $signature: function() {
+ return this.R._eval$1("0()");
+ }
+ };
+ O.StackZoneSpecification__registerBinaryCallback_closure.prototype = {
+ call$2: function(arg1, arg2) {
+ var _this = this,
+ t1 = _this.R;
+ return _this.$this._stack_zone_specification$_run$1$2(new O.StackZoneSpecification__registerBinaryCallback__closure(_this.f, _this.T1._check(arg1), _this.T2._check(arg2), t1), _this.node, t1);
+ },
+ $signature: function() {
+ return this.R._eval$1("@<0>")._bind$1(this.T1)._bind$1(this.T2)._eval$1("1(2,3)");
+ }
+ };
+ O.StackZoneSpecification__registerBinaryCallback__closure.prototype = {
+ call$0: function() {
+ var _this = this;
+ return _this.R._check(_this.f.call$2(_this.arg1, _this.arg2));
+ },
+ $signature: function() {
+ return this.R._eval$1("0()");
+ }
+ };
+ O.StackZoneSpecification__currentTrace_closure.prototype = {
+ call$0: function() {
+ var text = this.$this._trimVMChain$1(this.stackTrace),
+ t1 = Y.Trace_Trace$parse(text).frames,
+ t2 = this._box_0.level;
+ if (typeof t2 !== "number")
+ return t2.$add();
+ return new Y.Trace(P.List_List$unmodifiable(H.SubListIterable$(t1, t2 + 2, null, H._arrayInstanceType(t1)._precomputed1), type$.Frame), new P._StringStackTrace(text));
+ },
+ $signature: 8
+ };
+ O._Node.prototype = {
+ toChain$0: function() {
+ var node,
+ nodes = H.setRuntimeTypeInfo([], type$.JSArray_Trace);
+ for (node = this; node != null;) {
+ C.JSArray_methods.add$1(nodes, node.trace);
+ node = node.previous;
+ }
+ return new U.Chain(P.List_List$unmodifiable(nodes, type$.Trace));
+ }
+ };
+ Y.Trace.prototype = {
+ foldFrames$2$terse: function(predicate, terse) {
+ var newFrames, t1, t2, _box_0 = {};
+ _box_0.predicate = predicate;
+ _box_0.predicate = new Y.Trace_foldFrames_closure(type$.bool_Function_Frame._check(predicate));
+ newFrames = H.setRuntimeTypeInfo([], type$.JSArray_Frame);
+ for (t1 = this.frames, t2 = H._arrayInstanceType(t1)._eval$1("ReversedListIterable<1>"), t1 = new H.ReversedListIterable(t1, t2), t2 = new H.ListIterator(t1, t1.get$length(t1), t2._eval$1("ListIterator<ListIterable.E>")); t2.moveNext$0();) {
+ t1 = t2.__internal$_current;
+ if (t1 instanceof N.UnparsedFrame || !H.boolConversionCheck(_box_0.predicate.call$1(t1)))
+ C.JSArray_methods.add$1(newFrames, t1);
+ else if (newFrames.length === 0 || !H.boolConversionCheck(_box_0.predicate.call$1(C.JSArray_methods.get$last(newFrames))))
+ C.JSArray_methods.add$1(newFrames, new A.Frame(t1.get$uri(), t1.get$line(), t1.get$column(), t1.get$member()));
+ }
+ newFrames = new H.MappedListIterable(newFrames, type$.Frame_Function_Frame._check(new Y.Trace_foldFrames_closure0(_box_0)), type$.MappedListIterable_Frame_Frame).toList$0(0);
+ if (newFrames.length > 1 && H.boolConversionCheck(_box_0.predicate.call$1(C.JSArray_methods.get$first(newFrames))))
+ C.JSArray_methods.removeAt$1(newFrames, 0);
+ return new Y.Trace(P.List_List$unmodifiable(new H.ReversedListIterable(newFrames, H._arrayInstanceType(newFrames)._eval$1("ReversedListIterable<1>")), type$.Frame), new P._StringStackTrace(this.original._stackTrace));
+ },
+ toString$0: function(_) {
+ var t1 = this.frames,
+ t2 = H._arrayInstanceType(t1),
+ t3 = type$.int;
+ return new H.MappedListIterable(t1, t2._eval$1("String(1)")._check(new Y.Trace_toString_closure(new H.MappedListIterable(t1, t2._eval$1("int(1)")._check(new Y.Trace_toString_closure0()), t2._eval$1("MappedListIterable<1,int>")).fold$1$2(0, 0, H.instantiate1(P.math__max$closure(), t3), t3))), t2._eval$1("MappedListIterable<1,String>")).join$0(0);
+ },
+ $isStackTrace: 1,
+ get$frames: function() {
+ return this.frames;
+ },
+ get$original: function() {
+ return this.original;
+ }
+ };
+ Y.Trace_Trace$current_closure.prototype = {
+ call$0: function() {
+ var t1 = this.trace,
+ t2 = t1.get$frames();
+ t2 = H.SubListIterable$(t2, this.level + 2, null, H._arrayInstanceType(t2)._precomputed1);
+ t1 = t1.get$original();
+ return new Y.Trace(P.List_List$unmodifiable(t2, type$.Frame), new P._StringStackTrace(t1._stackTrace));
+ },
+ $signature: 8
+ };
+ Y.Trace_Trace$from_closure.prototype = {
+ call$0: function() {
+ return Y.Trace_Trace$parse(this.trace.toString$0(0));
+ },
+ $signature: 8
+ };
+ Y.Trace__parseVM_closure.prototype = {
+ call$1: function(line) {
+ return A.Frame_Frame$parseVM(H._checkStringNullable(line));
+ },
+ $signature: 10
+ };
+ Y.Trace$parseV8_closure.prototype = {
+ call$1: function(line) {
+ return !J.startsWith$1$s(H._checkStringNullable(line), $.$get$_v8TraceLine());
+ },
+ $signature: 4
+ };
+ Y.Trace$parseV8_closure0.prototype = {
+ call$1: function(line) {
+ return A.Frame_Frame$parseV8(H._checkStringNullable(line));
+ },
+ $signature: 10
+ };
+ Y.Trace$parseJSCore_closure.prototype = {
+ call$1: function(line) {
+ return H._checkStringNullable(line) !== "\tat ";
+ },
+ $signature: 4
+ };
+ Y.Trace$parseJSCore_closure0.prototype = {
+ call$1: function(line) {
+ return A.Frame_Frame$parseV8(H._checkStringNullable(line));
+ },
+ $signature: 10
+ };
+ Y.Trace$parseFirefox_closure.prototype = {
+ call$1: function(line) {
+ H._checkStringNullable(line);
+ return line.length !== 0 && line !== "[native code]";
+ },
+ $signature: 4
+ };
+ Y.Trace$parseFirefox_closure0.prototype = {
+ call$1: function(line) {
+ return A.Frame_Frame$parseFirefox(H._checkStringNullable(line));
+ },
+ $signature: 10
+ };
+ Y.Trace$parseFriendly_closure.prototype = {
+ call$1: function(line) {
+ return !J.startsWith$1$s(H._checkStringNullable(line), "=====");
+ },
+ $signature: 4
+ };
+ Y.Trace$parseFriendly_closure0.prototype = {
+ call$1: function(line) {
+ return A.Frame_Frame$parseFriendly(H._checkStringNullable(line));
+ },
+ $signature: 10
+ };
+ Y.Trace_foldFrames_closure.prototype = {
+ call$1: function(frame) {
+ if (H.boolConversionCheck(this.oldPredicate.call$1(frame)))
+ return true;
+ if (frame.get$isCore())
+ return true;
+ if (frame.get$$package() === "stack_trace")
+ return true;
+ if (!J.contains$1$asx(frame.get$member(), "<async>"))
+ return false;
+ return frame.get$line() == null;
+ },
+ $signature: 21
+ };
+ Y.Trace_foldFrames_closure0.prototype = {
+ call$1: function(frame) {
+ var t1, t2;
+ type$.Frame._check(frame);
+ if (frame instanceof N.UnparsedFrame || !H.boolConversionCheck(this._box_0.predicate.call$1(frame)))
+ return frame;
+ t1 = frame.get$library();
+ t2 = $.$get$_terseRegExp();
+ t1.toString;
+ return new A.Frame(P.Uri_parse(H.stringReplaceAllUnchecked(t1, t2, "")), null, null, frame.get$member());
+ },
+ $signature: 46
+ };
+ Y.Trace_toString_closure0.prototype = {
+ call$1: function(frame) {
+ type$.Frame._check(frame);
+ return frame.get$location(frame).length;
+ },
+ $signature: 39
+ };
+ Y.Trace_toString_closure.prototype = {
+ call$1: function(frame) {
+ type$.Frame._check(frame);
+ if (frame instanceof N.UnparsedFrame)
+ return frame.toString$0(0) + "\n";
+ return J.padRight$1$s(frame.get$location(frame), this.longest) + " " + H.S(frame.get$member()) + "\n";
+ },
+ $signature: 38
+ };
+ N.UnparsedFrame.prototype = {
+ toString$0: function(_) {
+ return this.member;
+ },
+ $isFrame: 1,
+ get$uri: function() {
+ return this.uri;
+ },
+ get$line: function() {
+ return null;
+ },
+ get$column: function() {
+ return null;
+ },
+ get$isCore: function() {
+ return false;
+ },
+ get$library: function() {
+ return "unparsed";
+ },
+ get$$package: function() {
+ return null;
+ },
+ get$location: function() {
+ return "unparsed";
+ },
+ get$member: function() {
+ return this.member;
+ }
+ };
+ K.GuaranteeChannel.prototype = {
+ get$stream: function(_) {
+ var t1 = this._streamController;
+ t1.toString;
+ return new P._ControllerStream(t1, H._instanceType(t1)._eval$1("_ControllerStream<1>"));
+ },
+ get$sink: function() {
+ return this._sink;
+ },
+ GuaranteeChannel$3$allowSinkErrors: function(innerSink, allowSinkErrors, _box_0, $T) {
+ var _this = this;
+ _this.set$_sink(new K._GuaranteeSink(innerSink, _this, new P._AsyncCompleter(new P._Future($.Zone__current, type$._Future_dynamic), type$._AsyncCompleter_dynamic), allowSinkErrors, $T._eval$1("_GuaranteeSink<0>")));
+ _this.set$_streamController(P.StreamController_StreamController(null, new K.GuaranteeChannel_closure(_box_0, _this), true, $T));
+ },
+ _onSinkDisconnected$0: function() {
+ this._disconnected = true;
+ var t1 = this._subscription;
+ if (t1 != null)
+ t1.cancel$0();
+ this._streamController.close$0(0);
+ },
+ set$_sink: function(_sink) {
+ this._sink = this.$ti._eval$1("_GuaranteeSink<1>")._check(_sink);
+ },
+ set$_streamController: function(_streamController) {
+ this._streamController = this.$ti._eval$1("StreamController<1>")._check(_streamController);
+ },
+ set$_subscription: function(_subscription) {
+ this._subscription = this.$ti._eval$1("StreamSubscription<1>")._check(_subscription);
+ }
+ };
+ K.GuaranteeChannel_closure.prototype = {
+ call$0: function() {
+ var t2, t3,
+ t1 = this.$this;
+ if (t1._disconnected)
+ return;
+ t2 = this._box_0.innerStream;
+ t3 = t1._streamController;
+ t1.set$_subscription(t2.listen$3$onDone$onError(t3.get$add(t3), new K.GuaranteeChannel__closure(t1), t3.get$addError()));
+ },
+ $signature: 0
+ };
+ K.GuaranteeChannel__closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this;
+ t1._sink._onStreamDisconnected$0();
+ t1._streamController.close$0(0);
+ },
+ $signature: 0
+ };
+ K._GuaranteeSink.prototype = {
+ get$done: function() {
+ return this._doneCompleter.future;
+ },
+ add$1: function(_, data) {
+ var t1, _this = this;
+ _this.$ti._precomputed1._check(data);
+ if (_this._closed)
+ throw H.wrapException(P.StateError$("Cannot add event after closing."));
+ if (_this._addStreamSubscription != null)
+ throw H.wrapException(P.StateError$("Cannot add event while adding stream."));
+ if (_this._disconnected)
+ return;
+ t1 = _this._inner;
+ t1._async$_target.add$1(0, t1.$ti._precomputed1._check(data));
+ },
+ addError$2: function(error, stackTrace) {
+ var _this = this;
+ type$.StackTrace._check(stackTrace);
+ if (_this._closed)
+ throw H.wrapException(P.StateError$("Cannot add event after closing."));
+ if (_this._addStreamSubscription != null)
+ throw H.wrapException(P.StateError$("Cannot add event while adding stream."));
+ if (_this._disconnected)
+ return;
+ _this._addError$2(error, stackTrace);
+ },
+ addError$1: function(error) {
+ return this.addError$2(error, null);
+ },
+ _addError$2: function(error, stackTrace) {
+ var _this = this;
+ type$.StackTrace._check(stackTrace);
+ if (_this._allowErrors) {
+ _this._inner._async$_target.addError$2(error, stackTrace);
+ return;
+ }
+ _this._doneCompleter.completeError$2(error, stackTrace);
+ _this._onStreamDisconnected$0();
+ _this._channel._onSinkDisconnected$0();
+ _this._inner._async$_target.close$0(0).catchError$1(new K._GuaranteeSink__addError_closure());
+ },
+ _addError$1: function(error) {
+ return this._addError$2(error, null);
+ },
+ addStream$1: function(stream) {
+ var t1, t2, _this = this;
+ _this.$ti._eval$1("Stream<1>")._check(stream);
+ if (_this._closed)
+ throw H.wrapException(P.StateError$("Cannot add stream after closing."));
+ if (_this._addStreamSubscription != null)
+ throw H.wrapException(P.StateError$("Cannot add stream while adding stream."));
+ if (_this._disconnected) {
+ t1 = new P._Future($.Zone__current, type$._Future_void);
+ t1._asyncComplete$1(null);
+ return t1;
+ }
+ t1 = new P._SyncCompleter(new P._Future($.Zone__current, type$._Future_dynamic), type$._SyncCompleter_dynamic);
+ _this._addStreamCompleter = t1;
+ t2 = _this._inner;
+ _this.set$_addStreamSubscription(stream.listen$3$onDone$onError(t2.get$add(t2), t1.get$complete(), _this.get$_addError()));
+ return _this._addStreamCompleter.future.then$1$1(new K._GuaranteeSink_addStream_closure(_this), type$.void);
+ },
+ close$0: function(_) {
+ var _this = this;
+ if (_this._addStreamSubscription != null)
+ throw H.wrapException(P.StateError$("Cannot close sink while adding stream."));
+ if (_this._closed)
+ return _this._doneCompleter.future;
+ _this._closed = true;
+ if (!_this._disconnected) {
+ _this._channel._onSinkDisconnected$0();
+ _this._doneCompleter.complete$1(_this._inner._async$_target.close$0(0));
+ }
+ return _this._doneCompleter.future;
+ },
+ _onStreamDisconnected$0: function() {
+ var t1, _this = this;
+ _this._disconnected = true;
+ t1 = _this._doneCompleter;
+ if (t1.future._state === 0)
+ t1.complete$0();
+ t1 = _this._addStreamSubscription;
+ if (t1 == null)
+ return;
+ _this._addStreamCompleter.complete$1(t1.cancel$0());
+ _this._addStreamCompleter = null;
+ _this.set$_addStreamSubscription(null);
+ },
+ set$_addStreamSubscription: function(_addStreamSubscription) {
+ this._addStreamSubscription = this.$ti._eval$1("StreamSubscription<1>")._check(_addStreamSubscription);
+ },
+ $isEventSink: 1,
+ $isStreamConsumer: 1,
+ $isStreamSink: 1,
+ $isSink: 1
+ };
+ K._GuaranteeSink__addError_closure.prototype = {
+ call$1: function(_) {
+ },
+ $signature: 3
+ };
+ K._GuaranteeSink_addStream_closure.prototype = {
+ call$1: function(_) {
+ var t1 = this.$this;
+ t1._addStreamCompleter = null;
+ t1.set$_addStreamSubscription(null);
+ },
+ $signature: 3
+ };
+ D._MultiChannel.prototype = {
+ _MultiChannel$1: function(_inner, $T) {
+ var t2, _this = this,
+ t1 = _this._mainController;
+ _this._controllers.$indexSet(0, 0, t1);
+ t2 = t1._local._streamController;
+ t2.toString;
+ new P._ControllerStream(t2, H._instanceType(t2)._eval$1("_ControllerStream<1>")).listen$2$onDone(new D._MultiChannel_closure(_this, $T), new D._MultiChannel_closure0(_this));
+ t2 = _this._multi_channel$_inner._streamController;
+ t2.toString;
+ _this._innerStreamSubscription = new P._ControllerStream(t2, H._instanceType(t2)._eval$1("_ControllerStream<1>")).listen$3$onDone$onError(new D._MultiChannel_closure1(_this, $T), _this.get$_closeInnerChannel(), t1._local._sink.get$addError());
+ },
+ virtualChannel$1: function(id) {
+ var t2, t3, controller, _this = this, t1 = {};
+ t1.outputId = t1.inputId = null;
+ if (id != null) {
+ t1.inputId = id;
+ t1.outputId = id + 1;
+ t2 = id;
+ } else {
+ t2 = _this._nextId;
+ t3 = t1.inputId = t2 + 1;
+ t1.outputId = t2;
+ _this._nextId = t2 + 2;
+ t2 = t3;
+ }
+ if (_this._multi_channel$_inner == null) {
+ t1 = _this.$ti;
+ t3 = new P._Future($.Zone__current, type$._Future_dynamic);
+ t3._asyncComplete$1(null);
+ return new D.VirtualChannel(_this, t2, new P._EmptyStream(t1._eval$1("_EmptyStream<1>")), new S.NullStreamSink(t3, t1._eval$1("NullStreamSink<1>")), t1._eval$1("VirtualChannel<1>"));
+ }
+ if (_this._pendingIds.remove$1(0, t2))
+ controller = _this._controllers.$index(0, t2);
+ else {
+ t3 = _this._controllers;
+ if (t3.containsKey$1(t2) || _this._closedIds.contains$1(0, t2))
+ throw H.wrapException(P.ArgumentError$("A virtual channel with id " + H.S(id) + " already exists."));
+ else {
+ controller = B.StreamChannelController$(true, true, _this.$ti._precomputed1);
+ t3.$indexSet(0, t2, controller);
+ }
+ }
+ t2 = controller._local._streamController;
+ t2.toString;
+ new P._ControllerStream(t2, H._instanceType(t2)._eval$1("_ControllerStream<1>")).listen$2$onDone(new D._MultiChannel_virtualChannel_closure(t1, _this), new D._MultiChannel_virtualChannel_closure0(t1, _this));
+ t1 = t1.outputId;
+ t2 = controller._foreign;
+ t3 = t2._streamController;
+ t3.toString;
+ return new D.VirtualChannel(_this, t1, new P._ControllerStream(t3, H._instanceType(t3)._eval$1("_ControllerStream<1>")), t2._sink, _this.$ti._eval$1("VirtualChannel<1>"));
+ },
+ virtualChannel$0: function() {
+ return this.virtualChannel$1(null);
+ },
+ _closeChannel$2: function(inputId, outputId) {
+ var t1, t2, _this = this;
+ _this._closedIds.add$1(0, inputId);
+ t1 = _this._controllers;
+ t1.remove$1(0, inputId)._local._sink.close$0(0);
+ t2 = _this._multi_channel$_inner;
+ if (t2 == null)
+ return;
+ t2._sink.add$1(0, H.setRuntimeTypeInfo([outputId], type$.JSArray_int));
+ if (t1.get$isEmpty(t1))
+ _this._closeInnerChannel$0();
+ },
+ _closeInnerChannel$0: function() {
+ var t1, t2, t3, _i, _this = this;
+ _this._multi_channel$_inner._sink.close$0(0);
+ _this._innerStreamSubscription.cancel$0();
+ _this._multi_channel$_inner = null;
+ for (t1 = _this._controllers, t2 = P.List_List$from(t1.get$values(), true, type$.dynamic), t3 = t2.length, _i = 0; _i < t2.length; t2.length === t3 || (0, H.throwConcurrentModificationError)(t2), ++_i)
+ t2[_i].get$local()._sink.close$0(0);
+ t1.clear$0(0);
+ },
+ $isMultiChannel: 1
+ };
+ D._MultiChannel_closure.prototype = {
+ call$1: function(message) {
+ this.T._check(message);
+ return this.$this._multi_channel$_inner._sink.add$1(0, [0, message]);
+ },
+ $signature: function() {
+ return this.T._eval$1("~(0)");
+ }
+ };
+ D._MultiChannel_closure0.prototype = {
+ call$0: function() {
+ return this.$this._closeChannel$2(0, 0);
+ },
+ $signature: 1
+ };
+ D._MultiChannel_closure1.prototype = {
+ call$1: function(message) {
+ var t3, controller,
+ t1 = J.getInterceptor$asx(message),
+ id = t1.$index(message, 0),
+ t2 = this.$this;
+ if (t2._closedIds.contains$1(0, id))
+ return;
+ H._checkIntNullable(id);
+ t3 = this.T;
+ controller = t2._controllers.putIfAbsent$2(id, new D._MultiChannel__closure(t2, id, t3));
+ t2 = t1.get$length(message);
+ if (typeof t2 !== "number")
+ return t2.$gt();
+ if (t2 > 1)
+ controller._local._sink.add$1(0, t3._check(t1.$index(message, 1)));
+ else
+ controller._local._sink.close$0(0);
+ },
+ $signature: 3
+ };
+ D._MultiChannel__closure.prototype = {
+ call$0: function() {
+ this.$this._pendingIds.add$1(0, H._checkIntNullable(this.id));
+ return B.StreamChannelController$(true, true, this.T);
+ },
+ $signature: function() {
+ return this.T._eval$1("StreamChannelController<0>()");
+ }
+ };
+ D._MultiChannel_virtualChannel_closure.prototype = {
+ call$1: function(message) {
+ var t1 = this.$this;
+ t1.$ti._precomputed1._check(message);
+ return t1._multi_channel$_inner._sink.add$1(0, [this._box_0.outputId, message]);
+ },
+ $signature: function() {
+ return this.$this.$ti._eval$1("~(1)");
+ }
+ };
+ D._MultiChannel_virtualChannel_closure0.prototype = {
+ call$0: function() {
+ var t1 = this._box_0;
+ return this.$this._closeChannel$2(t1.inputId, t1.outputId);
+ },
+ $signature: 1
+ };
+ D.VirtualChannel.prototype = {$isMultiChannel: 1,
+ get$stream: function(receiver) {
+ return this.stream;
+ }
+ };
+ N.StreamChannelCompleter.prototype = {
+ set$_stream_channel_completer$_channel: function(_channel) {
+ this._stream_channel_completer$_channel = this.$ti._eval$1("StreamChannel<1>")._check(_channel);
+ }
+ };
+ B.StreamChannelController.prototype = {
+ get$local: function() {
+ return this._local;
+ },
+ set$_local: function(_local) {
+ this._local = this.$ti._eval$1("StreamChannel<1>")._check(_local);
+ },
+ set$_foreign: function(_foreign) {
+ this._foreign = this.$ti._eval$1("StreamChannel<1>")._check(_foreign);
+ }
+ };
+ R.StreamChannel.prototype = {};
+ R._StreamChannel.prototype = {
+ get$stream: function(receiver) {
+ return this.stream;
+ }
+ };
+ R.StreamChannelMixin.prototype = {$isStreamChannel: 1};
+ E.StringScannerException.prototype = {};
+ S.SpanScanner.prototype = {
+ spanFrom$1: function(startState) {
+ var endPosition = this._string_scanner$_position;
+ return this._sourceFile.span$2(startState.position, endPosition);
+ },
+ matches$1: function(_, pattern) {
+ var _this = this;
+ if (!_this.super$StringScanner$matches(0, pattern)) {
+ _this._lastSpan = null;
+ return false;
+ }
+ _this._lastSpan = _this._sourceFile.span$2(_this._string_scanner$_position, _this.get$lastMatch().get$end());
+ return true;
+ },
+ error$3$length$position: function(_, message, $length, position) {
+ var t1 = this.string;
+ B.validateErrorArgs(t1, null, position, $length);
+ throw H.wrapException(E.StringScannerException$(message, this._sourceFile.span$2(position, position + $length), t1));
+ }
+ };
+ S._SpanScannerState.prototype = {$isLineScannerState: 1};
+ X.StringScanner.prototype = {
+ get$lastMatch: function() {
+ var _this = this;
+ if (_this._string_scanner$_position !== _this._lastMatchPosition)
+ _this._lastMatch = null;
+ return _this._lastMatch;
+ },
+ peekChar$0: function() {
+ var index = this._string_scanner$_position;
+ if (index < 0 || index >= this.string.length)
+ return null;
+ return J.codeUnitAt$1$s(this.string, index);
+ },
+ scan$1: function(pattern) {
+ var _this = this,
+ success = _this.matches$1(0, pattern);
+ if (success)
+ _this._lastMatchPosition = _this._string_scanner$_position = _this._lastMatch.get$end();
+ return success;
+ },
+ expect$2$name: function(pattern, $name) {
+ var t1;
+ if (this.scan$1(pattern))
+ return;
+ if ($name == null)
+ if (type$.RegExp._is(pattern))
+ $name = "/" + pattern.pattern + "/";
+ else {
+ t1 = J.toString$0$(pattern);
+ t1 = H.stringReplaceAllUnchecked(t1, "\\", "\\\\");
+ $name = '"' + H.stringReplaceAllUnchecked(t1, '"', '\\"') + '"';
+ }
+ this.error$3$length$position(0, "expected " + $name + ".", 0, this._string_scanner$_position);
+ },
+ expect$1: function(pattern) {
+ return this.expect$2$name(pattern, null);
+ },
+ matches$1: function(_, pattern) {
+ var _this = this,
+ t1 = J.matchAsPrefix$2$s(pattern, _this.string, _this._string_scanner$_position);
+ _this._lastMatch = t1;
+ _this._lastMatchPosition = _this._string_scanner$_position;
+ return t1 != null;
+ }
+ };
+ A.AsciiGlyphSet.prototype = {
+ glyphOrAscii$2: function(glyph, alternative) {
+ return alternative;
+ },
+ get$horizontalLine: function() {
+ return "-";
+ },
+ get$verticalLine: function() {
+ return "|";
+ },
+ get$topLeftCorner: function() {
+ return ",";
+ },
+ get$bottomLeftCorner: function() {
+ return "'";
+ },
+ get$upEnd: function() {
+ return "'";
+ },
+ get$downEnd: function() {
+ return ",";
+ }
+ };
+ K.UnicodeGlyphSet.prototype = {
+ glyphOrAscii$2: function(glyph, alternative) {
+ return glyph;
+ },
+ get$horizontalLine: function() {
+ return "\u2500";
+ },
+ get$verticalLine: function() {
+ return "\u2502";
+ },
+ get$topLeftCorner: function() {
+ return "\u250c";
+ },
+ get$bottomLeftCorner: function() {
+ return "\u2514";
+ },
+ get$upEnd: function() {
+ return "\u2575";
+ },
+ get$downEnd: function() {
+ return "\u2577";
+ }
+ };
+ L.internalBootstrapBrowserTest_closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$returnValue, t1, serialized, formatter, manager, $async$temp1;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ manager = type$.SuiteChannelManager._as($.Zone__current.$index(0, $.$get$_currentKey()));
+ if (manager == null)
+ H.throwExpression(P.StateError$("suiteChannel() may only be called within a test worker."));
+ t1 = manager.connectOut$1("test.browser.mapper");
+ t1 = t1.get$stream(t1);
+ $async$temp1 = type$.Map_dynamic_dynamic;
+ $async$goto = 3;
+ return P._asyncAwait(t1.get$first(t1), $async$call$0);
+ case 3:
+ // returning from await.
+ serialized = $async$temp1._as($async$result);
+ if (serialized == null) {
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ t1 = E.JSStackTraceMapper_deserialize(serialized);
+ formatter = type$.StackTraceFormatter._as($.Zone__current.$index(0, $.$get$_currentKey0()));
+ if (formatter == null)
+ H.throwExpression(P.StateError$("setStackTraceMapper() may only be called within a test worker."));
+ formatter.configure$1$mapper(t1);
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ N.postMessageChannel_closure.prototype = {
+ call$1: function(message) {
+ var t1, t2;
+ type$.MessageEvent._check(message);
+ t1 = message.origin;
+ t2 = window.location;
+ return t1 === (t2 && C.Location_methods).get$origin(t2) && J.$eq$(new P._AcceptStructuredCloneDart2Js([], []).convertNativeToDart_AcceptStructuredClone$2$mustCopy(message.data, true), "port");
+ },
+ $signature: 69
+ };
+ N.postMessageChannel_closure0.prototype = {
+ call$1: function(message) {
+ var t2, t3, portSubscription,
+ t1 = type$.MessageEvent,
+ port = J.get$first$ax(t1._check(message).ports);
+ port.toString;
+ t2 = this.controller;
+ t3 = type$.void_Function_MessageEvent._check(new N.postMessageChannel__closure(t2));
+ type$.void_Function._check(null);
+ portSubscription = W._EventStreamSubscription$(port, "message", t3, false, t1);
+ t2 = t2._local._streamController;
+ t2.toString;
+ new P._ControllerStream(t2, H._instanceType(t2)._eval$1("_ControllerStream<1>")).listen$2$onDone(new N.postMessageChannel__closure0(port), new N.postMessageChannel__closure1(port, portSubscription));
+ },
+ $signature: 29
+ };
+ N.postMessageChannel__closure.prototype = {
+ call$1: function(message) {
+ type$.MessageEvent._check(message);
+ this.controller._local._sink.add$1(0, new P._AcceptStructuredCloneDart2Js([], []).convertNativeToDart_AcceptStructuredClone$2$mustCopy(message.data, true));
+ },
+ $signature: 29
+ };
+ N.postMessageChannel__closure0.prototype = {
+ call$1: function(data) {
+ C.MessagePort_methods.postMessage$1(this.port, P.LinkedHashMap_LinkedHashMap$_literal(["data", data], type$.String, type$.dynamic));
+ },
+ $signature: 3
+ };
+ N.postMessageChannel__closure1.prototype = {
+ call$0: function() {
+ var t1 = type$.String;
+ C.MessagePort_methods.postMessage$1(this.port, P.LinkedHashMap_LinkedHashMap$_literal(["event", "done"], t1, t1));
+ this.portSubscription.cancel$0();
+ },
+ $signature: 0
+ };
+ K.ClosedException.prototype = {
+ toString$0: function(_) {
+ return "This test has been closed.";
+ },
+ $isException: 1
+ };
+ X.Declarer.prototype = {
+ test$9$onPlatform$retry$skip$solo$tags$testOn$timeout: function($name, body, onPlatform, retry, skip, solo, tags, testOn, timeout) {
+ var newMetadata, metadata, t1, t2, _this = this;
+ type$.dynamic_Function._check(body);
+ type$.Map_String_dynamic._check(onPlatform);
+ _this._checkNotBuilt$1("test");
+ newMetadata = O.Metadata$parse(onPlatform, H.boolConversionCheck(_this._noRetry) ? 0 : retry, skip, tags, testOn, timeout);
+ newMetadata.validatePlatformSelectors$1(_this._platformVariables);
+ metadata = _this._metadata.merge$1(newMetadata);
+ t1 = _this._declarer$_name;
+ t1 = t1 == null ? $name : t1 + " " + $name;
+ t2 = H.boolConversionCheck(_this._collectTraces) ? Y.Trace_Trace$current(2) : null;
+ C.JSArray_methods.add$1(_this._entries, new U.LocalTest(t1, metadata, t2, false, new X.Declarer_test_closure(_this, body), false));
+ },
+ group$9$onPlatform$retry$skip$solo$tags$testOn$timeout: function($name, body, onPlatform, retry, skip, solo, tags, testOn, timeout) {
+ var t2, newMetadata, t3, metadata, t4, trace, t5, t6, t7, t8, t9, t10, t11, t12, declarer, _this = this, _null = null,
+ t1 = type$.void_Function;
+ t1._check(body);
+ type$.Map_String_dynamic._check(onPlatform);
+ _this._checkNotBuilt$1("group");
+ t2 = H.boolConversionCheck(_this._noRetry);
+ newMetadata = O.Metadata$parse(onPlatform, t2 ? 0 : retry, skip, tags, testOn, timeout);
+ t3 = _this._platformVariables;
+ newMetadata.validatePlatformSelectors$1(t3);
+ metadata = _this._metadata.merge$1(newMetadata);
+ t4 = H.boolConversionCheck(_this._collectTraces);
+ trace = t4 ? Y.Trace_Trace$current(2) : _null;
+ t5 = _this._declarer$_name;
+ t5 = t5 == null ? $name : t5 + " " + $name;
+ t6 = type$.JSArray_of_dynamic_Function;
+ t7 = H.setRuntimeTypeInfo([], t6);
+ t8 = H.setRuntimeTypeInfo([], t6);
+ t9 = H.setRuntimeTypeInfo([], t6);
+ t10 = P.Duration$(0, 12);
+ t6 = H.setRuntimeTypeInfo([], t6);
+ t11 = type$.JSArray_GroupEntry;
+ t12 = H.setRuntimeTypeInfo([], t11);
+ t11 = H.setRuntimeTypeInfo([], t11);
+ declarer = new X.Declarer(_this, t5, metadata, t3, trace, t4, t2, t7, t8, t9, new R.Timeout(t10, _null), t6, t12, t11);
+ t12 = type$.dynamic;
+ P.runZoned(t1._check(new X.Declarer_group_closure(body)), _null, _null, P.LinkedHashMap_LinkedHashMap$_literal([C.Symbol_Drw, declarer], t12, t12), type$.void);
+ t12 = _this._entries;
+ C.JSArray_methods.add$1(t12, declarer.build$0());
+ t1 = t11.length;
+ if (t1 !== 0)
+ C.JSArray_methods.add$1(_this._soloEntries, C.JSArray_methods.get$last(t12));
+ },
+ build$0: function() {
+ var t1, t2, _this = this;
+ _this._checkNotBuilt$1("build");
+ _this._built = true;
+ t1 = _this._entries;
+ t2 = H._arrayInstanceType(t1);
+ return O.Group$(_this._declarer$_name, new H.MappedListIterable(t1, t2._eval$1("GroupEntry(1)")._check(new X.Declarer_build_closure(_this)), t2._eval$1("MappedListIterable<1,GroupEntry>")).toList$0(0), _this._metadata, _this.get$_setUpAll(), _this.get$_tearDownAll(), _this._declarer$_trace);
+ },
+ _checkNotBuilt$1: function($name) {
+ if (!this._built)
+ return;
+ throw H.wrapException(P.StateError$("Can't call " + $name + "() once tests have begun running."));
+ },
+ _runSetUps$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.dynamic),
+ $async$self = this, t1;
+ var $async$_runSetUps$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = $async$self._declarer$_parent;
+ $async$goto = t1 != null ? 2 : 3;
+ break;
+ case 2:
+ // then
+ $async$goto = 4;
+ return P._asyncAwait(t1._runSetUps$0(), $async$_runSetUps$0);
+ case 4:
+ // returning from await.
+ case 3:
+ // join
+ $async$goto = 5;
+ return P._asyncAwait(P.Future_forEach($async$self._setUps, new X.Declarer__runSetUps_closure(), type$.dynamic_Function), $async$_runSetUps$0);
+ case 5:
+ // returning from await.
+ // implicit return
+ return P._asyncReturn(null, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$_runSetUps$0, $async$completer);
+ },
+ get$_setUpAll: function() {
+ return null;
+ },
+ get$_tearDownAll: function() {
+ var _this = this,
+ t1 = _this._tearDownAlls.length;
+ if (t1 === 0)
+ return null;
+ t1 = _this._declarer$_name;
+ t1 = t1 == null ? "(tearDownAll)" : t1 + " (tearDownAll)";
+ return new U.LocalTest(t1, _this._metadata.change$1$timeout(_this._timeout), null, true, new X.Declarer__tearDownAll_closure(_this), false);
+ }
+ };
+ X.Declarer_test_closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$returnValue, $async$self = this, declarer, declarer0, t1, t2, t3, t4, t5, _i, tearDown, t6, parents;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ $async$outer:
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ parents = H.setRuntimeTypeInfo([], type$.JSArray_Declarer);
+ for (declarer = $async$self.$this, declarer0 = declarer; declarer0 != null; declarer0 = declarer0._declarer$_parent)
+ C.JSArray_methods.add$1(parents, declarer0);
+ for (t1 = type$.ReversedListIterable_Declarer, t2 = new H.ReversedListIterable(parents, t1), t1 = new H.ListIterator(t2, t2.get$length(t2), t1._eval$1("ListIterator<ListIterable.E>")), t2 = type$.Invoker, t3 = type$.dynamic_Function, t4 = type$.Declarer; t1.moveNext$0();)
+ for (t5 = t1.__internal$_current._tearDowns, _i = 0; false; ++_i) {
+ if (_i >= 0) {
+ $async$returnValue = H.ioore(t5, _i);
+ // goto return
+ $async$goto = 1;
+ break $async$outer;
+ }
+ tearDown = t5[_i];
+ t6 = t2._as($.Zone__current.$index(0, C.Symbol_cQL));
+ t6.toString;
+ t3._check(tearDown);
+ if (H.boolConversionCheck(H._asBoolNullable($.Zone__current.$index(0, t6._closableKey))) && t6._onCloseCompleter.future._state !== 0)
+ H.throwExpression(K.ClosedException$());
+ if (t6._invoker$_controller._liveTest._live_test_controller$_controller._test.isScaffoldAll)
+ C.JSArray_methods.add$1(t4._as($.Zone__current.$index(0, C.Symbol_Drw))._tearDownAlls, tearDown);
+ else
+ C.JSArray_methods.add$1(t6._invoker$_tearDowns, tearDown);
+ }
+ t1 = type$.dynamic;
+ $async$goto = 3;
+ return P._asyncAwait(P.runZoned(new X.Declarer_test__closure(declarer, $async$self.body), null, null, P.LinkedHashMap_LinkedHashMap$_literal([C.Symbol_Drw, declarer], t1, t1), type$.Future_void), $async$call$0);
+ case 3:
+ // returning from await.
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ X.Declarer_test__closure.prototype = {
+ call$0: function() {
+ return type$.Invoker._as($.Zone__current.$index(0, C.Symbol_cQL)).waitForOutstandingCallbacks$1(new X.Declarer_test___closure(this.$this, this.body));
+ },
+ $signature: 13
+ };
+ X.Declarer_test___closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$self = this;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ $async$goto = 2;
+ return P._asyncAwait($async$self.$this._runSetUps$0(), $async$call$0);
+ case 2:
+ // returning from await.
+ $async$goto = 3;
+ return P._asyncAwait($async$self.body.call$0(), $async$call$0);
+ case 3:
+ // returning from await.
+ // implicit return
+ return P._asyncReturn(null, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ X.Declarer_group_closure.prototype = {
+ call$0: function() {
+ if (!type$.Future_dynamic._is(this.body.call$0()))
+ return;
+ throw H.wrapException(P.ArgumentError$("Groups may not be async."));
+ },
+ $signature: 0
+ };
+ X.Declarer_build_closure.prototype = {
+ call$1: function(entry) {
+ var t1;
+ type$.GroupEntry._check(entry);
+ t1 = this.$this._soloEntries;
+ return t1.length !== 0 && !C.JSArray_methods.contains$1(t1, entry) ? new U.LocalTest(entry.get$name(entry), entry.get$metadata().change$2$skip$skipReason(true, 'does not have "solo"'), null, false, null, true) : entry;
+ },
+ $signature: 22
+ };
+ X.Declarer__runSetUps_closure.prototype = {
+ call$1: function(setUp) {
+ return setUp.call$0();
+ },
+ $signature: 18
+ };
+ X.Declarer__tearDownAll_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ t2 = type$.dynamic;
+ return P.runZoned(new X.Declarer__tearDownAll__closure(t1), null, null, P.LinkedHashMap_LinkedHashMap$_literal([C.Symbol_Drw, t1], t2, t2), type$.Future_Null);
+ },
+ $signature: 2
+ };
+ X.Declarer__tearDownAll__closure.prototype = {
+ call$0: function() {
+ return type$.Invoker._as($.Zone__current.$index(0, C.Symbol_cQL)).unclosable$1$1(new X.Declarer__tearDownAll___closure(this.$this), type$.Future_Null);
+ },
+ $signature: 2
+ };
+ X.Declarer__tearDownAll___closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$returnValue, $async$self = this, t1, t2;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = $async$self.$this._tearDownAlls;
+ case 3:
+ // for condition
+ if (!(t2 = t1.length, t2 !== 0)) {
+ // goto after for
+ $async$goto = 4;
+ break;
+ }
+ if (0 >= t2) {
+ $async$returnValue = H.ioore(t1, -1);
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ $async$goto = 5;
+ return P._asyncAwait(V.errorsDontStopTest(t1.pop()), $async$call$0);
+ case 5:
+ // returning from await.
+ // goto for condition
+ $async$goto = 3;
+ break;
+ case 4:
+ // after for
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ O.Group.prototype = {
+ forPlatform$1: function(platform) {
+ var newMetadata, filtered, _this = this,
+ t1 = _this.metadata;
+ if (!H.boolConversionCheck(t1.testOn.evaluate$1(platform)))
+ return null;
+ newMetadata = t1.forPlatform$1(platform);
+ filtered = _this._group$_map$1(new O.Group_forPlatform_closure(platform));
+ if (filtered.length === 0 && _this.entries.length !== 0)
+ return null;
+ return O.Group$(_this.name, filtered, newMetadata, _this.setUpAll, _this.tearDownAll, _this.trace);
+ },
+ _group$_map$1: function(callback) {
+ var t1 = this.entries,
+ t2 = H._arrayInstanceType(t1),
+ t3 = t2._eval$1("MappedListIterable<1,GroupEntry>");
+ t3 = new H.MappedListIterable(t1, t2._eval$1("GroupEntry(1)")._check(new O.Group__map_closure(type$.GroupEntry_Function_GroupEntry._check(callback))), t3).super$Iterable$where(0, t3._eval$1("bool(ListIterable.E)")._check(new O.Group__map_closure0()));
+ return P.List_List$from(t3, true, t3.$ti._eval$1("Iterable.E"));
+ },
+ $isGroupEntry: 1,
+ get$name: function(receiver) {
+ return this.name;
+ },
+ get$metadata: function() {
+ return this.metadata;
+ }
+ };
+ O.Group_forPlatform_closure.prototype = {
+ call$1: function(entry) {
+ return entry.forPlatform$1(this.platform);
+ },
+ $signature: 22
+ };
+ O.Group__map_closure.prototype = {
+ call$1: function(entry) {
+ return this.callback.call$1(type$.GroupEntry._check(entry));
+ },
+ $signature: 22
+ };
+ O.Group__map_closure0.prototype = {
+ call$1: function(entry) {
+ return type$.GroupEntry._check(entry) != null;
+ },
+ $signature: 72
+ };
+ V.GroupEntry.prototype = {};
+ U.LocalTest.prototype = {
+ load$2$groups: function(suite, groups) {
+ var t1, invoker;
+ type$.Iterable_Group._check(groups);
+ t1 = new P._AsyncCompleter(new P._Future($.Zone__current, type$._Future_void), type$._AsyncCompleter_void);
+ invoker = new U.Invoker(this._guarded, new P.Object(), t1, H.setRuntimeTypeInfo([], type$.JSArray_Zone), new P.Object(), H.setRuntimeTypeInfo([], type$.JSArray_of_dynamic_Function), H.setRuntimeTypeInfo([], type$.JSArray_String));
+ t1 = V.LiveTestController$(suite, this, invoker.get$_invoker$_onRun(), t1.get$complete(), groups);
+ invoker._invoker$_controller = t1;
+ return t1._liveTest;
+ },
+ forPlatform$1: function(platform) {
+ var _this = this,
+ t1 = _this.metadata;
+ if (!H.boolConversionCheck(t1.testOn.evaluate$1(platform)))
+ return null;
+ return new U.LocalTest(_this.name, t1.forPlatform$1(platform), _this.trace, _this.isScaffoldAll, _this._body, _this._guarded);
+ },
+ get$name: function(receiver) {
+ return this.name;
+ },
+ get$metadata: function() {
+ return this.metadata;
+ }
+ };
+ U.Invoker.prototype = {
+ get$_outstandingCallbacks: function() {
+ var counter = type$._AsyncCounter._as($.Zone__current.$index(0, this._counterKey));
+ if (counter != null)
+ return counter;
+ throw H.wrapException(P.StateError$("Can't add or remove outstanding callbacks outside of a test body."));
+ },
+ addOutstandingCallback$0: function() {
+ if (H.boolConversionCheck(H._asBoolNullable($.Zone__current.$index(0, this._closableKey))) && this._onCloseCompleter.future._state !== 0)
+ throw H.wrapException(K.ClosedException$());
+ ++this.get$_outstandingCallbacks()._count;
+ },
+ waitForOutstandingCallbacks$1: function(fn) {
+ var t2, counter, t3, _this = this, t1 = {};
+ type$.FutureOr_void_Function._check(fn);
+ _this.heartbeat$0();
+ t1.zone = null;
+ t2 = new P._Future($.Zone__current, type$._Future_void);
+ counter = new U._AsyncCounter(new P._AsyncCompleter(t2, type$._AsyncCompleter_void));
+ t3 = type$.dynamic;
+ P.runZoned(new U.Invoker_waitForOutstandingCallbacks_closure(t1, _this, fn, counter), null, null, P.LinkedHashMap_LinkedHashMap$_literal([_this._counterKey, counter], t3, t3), type$.Future_Null);
+ return t2.whenComplete$1(new U.Invoker_waitForOutstandingCallbacks_closure0(t1, _this));
+ },
+ unclosable$1$1: function(fn, $T) {
+ var t1;
+ $T._eval$1("0()")._check(fn);
+ this.heartbeat$0();
+ t1 = type$.dynamic;
+ return P.runZoned(fn, null, null, P.LinkedHashMap_LinkedHashMap$_literal([this._closableKey, false], t1, t1), $T);
+ },
+ heartbeat$0: function() {
+ var t1, timeout, _this = this;
+ if (_this._invoker$_controller._liveTest._live_test_controller$_controller._live_test_controller$_state.status === C.Status_complete)
+ return;
+ t1 = _this._timeoutTimer;
+ if (t1 != null)
+ t1.cancel$0();
+ timeout = _this._invoker$_controller._liveTest._live_test_controller$_controller._test.metadata.timeout.apply$1(C.Duration_30000000);
+ if (timeout == null)
+ return;
+ _this._timeoutTimer = _this._invokerZone.createTimer$2(timeout, new U.Invoker_heartbeat_closure(_this, new U.Invoker_heartbeat_message(timeout), timeout));
+ },
+ _handleError$3: function(zone, error, stackTrace) {
+ var t2, t3, t4, shouldBeDone, _this = this, t1 = {};
+ t1.stackTrace = stackTrace;
+ if (_this._runCount !== zone.$index(0, C.Symbol_runCount))
+ return;
+ zone.run$1$1(new U.Invoker__handleError_closure(t1), type$.Null);
+ t2 = _this._invoker$_controller;
+ t3 = t2._liveTest._live_test_controller$_controller._live_test_controller$_state;
+ if (t3.status === C.Status_complete) {
+ t4 = t3.result;
+ shouldBeDone = t4 === C.Result_success || t4 === C.Result_skipped;
+ } else
+ shouldBeDone = false;
+ if (!(error instanceof G.TestFailure))
+ t2.setState$1(C.State_Status_complete_Result_error);
+ else if (t3.result !== C.Result_error)
+ t2.setState$1(C.State_Status_complete_Result_failure);
+ _this._invoker$_controller.addError$2(error, t1.stackTrace);
+ zone.run$1$1(new U.Invoker__handleError_closure0(_this), type$.void);
+ t2 = _this._invoker$_controller._liveTest._live_test_controller$_controller;
+ if (t2._test.metadata._chainStackTraces === false)
+ C.JSArray_methods.add$1(_this._printsOnFailure, "Consider enabling the flag chain-stack-traces to receive more detailed exceptions.\nFor example, 'pub run test --chain-stack-traces'.");
+ t2 = _this._printsOnFailure;
+ if (t2.length !== 0) {
+ P.print(C.JSArray_methods.join$1(t2, "\n\n"));
+ C.JSArray_methods.set$length(t2, 0);
+ }
+ if (!shouldBeDone)
+ return;
+ _this._invoker$_controller._liveTest._live_test_controller$_controller._live_test_controller$_suite.toString;
+ _this._handleError$3(zone, "This test failed after it had already completed. Make sure to use [expectAsync]\nor the [completes] matcher when testing async code.", t1.stackTrace);
+ },
+ _handleError$2: function(zone, error) {
+ return this._handleError$3(zone, error, null);
+ },
+ _invoker$_onRun$0: function() {
+ var t1, t2, _this = this;
+ _this._invoker$_controller.setState$1(C.State_Status_running_Result_success);
+ t1 = $.Zone__current;
+ ++_this._runCount;
+ t2 = _this._invoker$_controller._liveTest._live_test_controller$_controller;
+ U.Chain_capture(new U.Invoker__onRun_closure(_this, new U._AsyncCounter(new P._AsyncCompleter(new P._Future(t1, type$._Future_void), type$._AsyncCompleter_void))), false, t2._test.metadata._chainStackTraces !== false, type$.Null);
+ },
+ _runTearDowns$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.void),
+ $async$returnValue, $async$self = this, t1, t2;
+ var $async$_runTearDowns$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = $async$self._invoker$_tearDowns;
+ case 3:
+ // for condition
+ if (!(t2 = t1.length, t2 !== 0)) {
+ // goto after for
+ $async$goto = 4;
+ break;
+ }
+ if (0 >= t2) {
+ $async$returnValue = H.ioore(t1, -1);
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ $async$goto = 5;
+ return P._asyncAwait(V.errorsDontStopTest(t1.pop()), $async$_runTearDowns$0);
+ case 5:
+ // returning from await.
+ // goto for condition
+ $async$goto = 3;
+ break;
+ case 4:
+ // after for
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$_runTearDowns$0, $async$completer);
+ }
+ };
+ U.Invoker_guard_closure.prototype = {
+ call$5: function($self, _, zone, error, stackTrace) {
+ var invoker;
+ type$.StackTrace._check(stackTrace);
+ invoker = zone.$index(0, C.Symbol_cQL);
+ if (invoker != null)
+ $self.get$parent($self).run$1$1(new U.Invoker_guard__closure(invoker, zone, error, stackTrace), type$.dynamic);
+ else
+ $self.get$parent($self).handleUncaughtError$2(error, stackTrace);
+ },
+ $signature: 28
+ };
+ U.Invoker_guard__closure.prototype = {
+ call$0: function() {
+ var _this = this;
+ return _this.invoker._handleError$3(_this.zone, _this.error, _this.stackTrace);
+ },
+ $signature: 34
+ };
+ U.Invoker_waitForOutstandingCallbacks_closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$self = this, zone;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ zone = $.Zone__current;
+ $async$self._box_0.zone = zone;
+ C.JSArray_methods.add$1($async$self.$this._outstandingCallbackZones, zone);
+ $async$goto = 2;
+ return P._asyncAwait($async$self.fn.call$0(), $async$call$0);
+ case 2:
+ // returning from await.
+ $async$self.counter.decrement$0();
+ // implicit return
+ return P._asyncReturn(null, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ U.Invoker_waitForOutstandingCallbacks_closure0.prototype = {
+ call$0: function() {
+ C.JSArray_methods.remove$1(this.$this._outstandingCallbackZones, this._box_0.zone);
+ },
+ $signature: 0
+ };
+ U.Invoker_heartbeat_message.prototype = {
+ call$0: function() {
+ var message,
+ t1 = this.timeout._duration,
+ minutes = C.JSInt_methods._tdivFast$1(t1, 60000000),
+ seconds = C.JSInt_methods.$mod(C.JSInt_methods._tdivFast$1(t1, 1000000), 60),
+ decaseconds = C.JSInt_methods._tdivFast$1(C.JSInt_methods.$mod(C.JSInt_methods._tdivFast$1(t1, 1000), 1000), 100),
+ t2 = minutes !== 0,
+ t3 = t2 ? "" + minutes + " minutes" : "";
+ if (!t2 || seconds !== 0) {
+ t2 = t2 ? t3 + ", " : t3;
+ t2 += seconds;
+ t2 = (decaseconds !== 0 ? t2 + ("." + decaseconds) : t2) + " seconds";
+ } else
+ t2 = t3;
+ message = "Test timed out after " + (t2.charCodeAt(0) == 0 ? t2 : t2) + ".";
+ return t1 === 30000000 ? message + " See https://pub.dev/packages/test#timeouts" : message;
+ },
+ $signature: 74
+ };
+ U.Invoker_heartbeat_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this;
+ C.JSArray_methods.get$last(t1._outstandingCallbackZones).run$1$1(new U.Invoker_heartbeat__closure(t1, this.message, this.timeout), type$.Null);
+ },
+ $signature: 0
+ };
+ U.Invoker_heartbeat__closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this;
+ if (t1._invoker$_controller._liveTest._live_test_controller$_controller._live_test_controller$_state.status === C.Status_complete)
+ return;
+ t1._handleError$2($.Zone__current, new P.TimeoutException(this.message.call$0(), this.timeout));
+ },
+ $signature: 0
+ };
+ U.Invoker__handleError_closure.prototype = {
+ call$0: function() {
+ var t1 = this._box_0,
+ t2 = t1.stackTrace;
+ if (t2 == null)
+ t1.stackTrace = U.Chain_Chain$current();
+ else
+ t1.stackTrace = U.Chain_Chain$forTrace(t2);
+ },
+ $signature: 0
+ };
+ U.Invoker__handleError_closure0.prototype = {
+ call$0: function() {
+ var t1 = this.$this.get$_outstandingCallbacks()._invoker$_completer;
+ if (t1.future._state === 0)
+ t1.complete$0();
+ return null;
+ },
+ $signature: 1
+ };
+ U.Invoker__onRun_closure.prototype = {
+ call$0: function() {
+ var t1 = this.$this,
+ t2 = type$.void_Function._check(new U.Invoker__onRun__closure(t1, this.outstandingCallbacksForBody));
+ if (t1._guarded)
+ U.Invoker_guard(t2, type$.void);
+ else
+ t2.call$0();
+ },
+ $signature: 0
+ };
+ U.Invoker__onRun__closure.prototype = {
+ call$0: function() {
+ var _null = null,
+ t1 = this.$this,
+ t2 = type$.dynamic;
+ t2 = P.LinkedHashMap_LinkedHashMap$_literal([C.Symbol_cQL, t1, t1._counterKey, this.outstandingCallbacksForBody, t1._closableKey, true, C.Symbol_runCount, t1._runCount], t2, t2);
+ P.runZoned(new U.Invoker__onRun___closure(t1), _null, P._ZoneSpecification$(_null, _null, _null, _null, _null, new U.Invoker__onRun___closure0(t1), _null, _null, _null, _null, _null, _null, _null), t2, type$.Future_Null);
+ },
+ $signature: 0
+ };
+ U.Invoker__onRun___closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$returnValue, $async$self = this, t3, t4, t5, t6, t1, t2;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = $async$self.$this;
+ t2 = $.Zone__current;
+ t1._invokerZone = t2;
+ C.JSArray_methods.add$1(t1._outstandingCallbackZones, t2);
+ P.Future_Future(new U.Invoker__onRun____closure(t1), type$.void);
+ $async$goto = 3;
+ return P._asyncAwait(t1.get$_outstandingCallbacks()._invoker$_completer.future, $async$call$0);
+ case 3:
+ // returning from await.
+ t2 = t1._timeoutTimer;
+ if (t2 != null)
+ t2.cancel$0();
+ t2 = t1._invoker$_controller;
+ t3 = t2._liveTest._live_test_controller$_controller;
+ t4 = t3._live_test_controller$_state.result;
+ if (t4 !== C.Result_success) {
+ t5 = t1._runCount;
+ t6 = t3._test.metadata._retry;
+ t5 = t5 < (t6 == null ? 0 : t6) + 1;
+ } else
+ t5 = false;
+ if (t5) {
+ t2.message$1(0, new D.Message(C.MessageType_print, "Retry: " + H.S(t3._test.name)));
+ t1._invoker$_onRun$0();
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ t2.setState$1(new G.State(C.Status_complete, t4));
+ t1._invoker$_controller.completer.complete$0();
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ U.Invoker__onRun____closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$self = this, t1;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = $async$self.$this;
+ $async$goto = 2;
+ return P._asyncAwait(t1._invoker$_controller._liveTest._live_test_controller$_controller._test._body.call$0(), $async$call$0);
+ case 2:
+ // returning from await.
+ $async$goto = 3;
+ return P._asyncAwait(t1.unclosable$1$1(t1.get$_runTearDowns(), type$.Future_void), $async$call$0);
+ case 3:
+ // returning from await.
+ t1.heartbeat$0();
+ t1.get$_outstandingCallbacks().decrement$0();
+ // implicit return
+ return P._asyncReturn(null, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ U.Invoker__onRun___closure0.prototype = {
+ call$4: function(_, __, ___, line) {
+ H._checkStringNullable(line);
+ return this.$this._invoker$_controller.message$1(0, new D.Message(C.MessageType_print, line));
+ },
+ $signature: 37
+ };
+ U._AsyncCounter.prototype = {
+ decrement$0: function() {
+ if (--this._count !== 0)
+ return;
+ var t1 = this._invoker$_completer;
+ if (t1.future._state !== 0)
+ return;
+ t1.complete$0();
+ }
+ };
+ Z.LiveTest.prototype = {};
+ V._LiveTest.prototype = {
+ run$0: function() {
+ var t1 = this._live_test_controller$_controller;
+ if (t1._runCalled)
+ H.throwExpression(P.StateError$("LiveTest.run() may not be called more than once."));
+ else if ((t1._onErrorController._state & 4) !== 0)
+ H.throwExpression(P.StateError$("LiveTest.run() may not be called for a closed test."));
+ t1._runCalled = true;
+ t1._onRun.call$0();
+ return t1._liveTest._live_test_controller$_controller.completer.future;
+ }
+ };
+ V.LiveTestController.prototype = {
+ addError$2: function(error, stackTrace) {
+ var asyncError,
+ t1 = this._onErrorController;
+ if ((t1._state & 4) !== 0)
+ return;
+ asyncError = new P.AsyncError(error, U.Chain_Chain$forTrace(stackTrace));
+ C.JSArray_methods.add$1(this._errors, asyncError);
+ t1.add$1(0, asyncError);
+ },
+ setState$1: function(newState) {
+ var _this = this;
+ if ((_this._onErrorController._state & 4) !== 0)
+ return;
+ if (_this._live_test_controller$_state.$eq(0, newState))
+ return;
+ _this._live_test_controller$_state = newState;
+ _this._onStateChangeController.add$1(0, newState);
+ },
+ message$1: function(_, message) {
+ var t1 = this._onMessageController;
+ if (t1._firstSubscription != null)
+ t1.add$1(0, message);
+ else
+ H.printString(message.text);
+ },
+ _live_test_controller$_run$0: function() {
+ var _this = this;
+ if (_this._runCalled)
+ throw H.wrapException(P.StateError$("LiveTest.run() may not be called more than once."));
+ else if ((_this._onErrorController._state & 4) !== 0)
+ throw H.wrapException(P.StateError$("LiveTest.run() may not be called for a closed test."));
+ _this._runCalled = true;
+ _this._onRun.call$0();
+ return _this._liveTest._live_test_controller$_controller.completer.future;
+ },
+ _live_test_controller$_close$0: function() {
+ var _this = this,
+ t1 = _this._onErrorController;
+ if ((t1._state & 4) !== 0)
+ return _this.completer.future;
+ _this._onStateChangeController.close$0(0);
+ t1.close$0(0);
+ if (_this._runCalled)
+ _this._onClose.call$0();
+ else
+ _this.completer.complete$0();
+ return _this.completer.future;
+ }
+ };
+ D.Message.prototype = {};
+ D.MessageType.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ O.Metadata.prototype = {
+ _validateTags$0: function() {
+ var t1 = this.tags.where$1(0, new O.Metadata__validateTags_closure()),
+ t2 = t1.$ti,
+ t3 = t2._eval$1("MappedIterable<1,String>"),
+ invalidTags = P.List_List$from(new H.MappedIterable(t1, t2._eval$1("String(1)")._check(new O.Metadata__validateTags_closure0()), t3), true, t3._eval$1("Iterable.E"));
+ t1 = invalidTags.length;
+ if (t1 === 0)
+ return;
+ throw H.wrapException(P.ArgumentError$("Invalid " + B.pluralize("tag", t1) + " " + H.S(B.toSentence(invalidTags)) + ". Tags must be (optionally hyphenated) Dart identifiers."));
+ },
+ validatePlatformSelectors$1: function(validVariables) {
+ type$.Set_String._check(validVariables);
+ this.testOn.validate$1(validVariables);
+ this.onPlatform.forEach$1(0, new O.Metadata_validatePlatformSelectors_closure(validVariables));
+ },
+ merge$1: function(other) {
+ var t4, t5, t6, t7, t8, t9, t10, _this = this,
+ t1 = _this.testOn.intersection$1(other.testOn),
+ t2 = _this.timeout.merge$1(other.timeout),
+ t3 = other._skip;
+ if (t3 == null)
+ t3 = _this._skip;
+ t4 = other.skipReason;
+ if (t4 == null)
+ t4 = _this.skipReason;
+ t5 = other._verboseTrace;
+ if (t5 == null)
+ t5 = _this._verboseTrace;
+ t6 = other._chainStackTraces;
+ if (t6 == null)
+ t6 = _this._chainStackTraces;
+ t7 = other._retry;
+ if (t7 == null)
+ t7 = _this._retry;
+ t8 = _this.tags.union$1(other.tags);
+ t9 = type$.Metadata;
+ t10 = Y.mergeMaps(_this.onPlatform, other.onPlatform, new O.Metadata_merge_closure(), type$.PlatformSelector, t9);
+ return O.Metadata_Metadata(t6, Y.mergeMaps(_this.forTag, other.forTag, new O.Metadata_merge_closure0(), type$.BooleanSelector, t9), t10, t7, t3, t4, t8, t1, t2, t5);
+ },
+ change$4$onPlatform$skip$skipReason$timeout: function(onPlatform, skip, skipReason, timeout) {
+ var _this = this;
+ type$.Map_PlatformSelector_Metadata._check(onPlatform);
+ type$.Set_String._check(null);
+ type$.Map_BooleanSelector_Metadata._check(null);
+ if (timeout == null)
+ timeout = _this.timeout;
+ if (skip == null)
+ skip = _this._skip;
+ if (skipReason == null)
+ skipReason = _this.skipReason;
+ if (onPlatform == null)
+ onPlatform = _this.onPlatform;
+ return O.Metadata_Metadata(_this._chainStackTraces, _this.forTag, onPlatform, _this._retry, skip, skipReason, _this.tags, _this.testOn, timeout, _this._verboseTrace);
+ },
+ change$1$onPlatform: function(onPlatform) {
+ return this.change$4$onPlatform$skip$skipReason$timeout(onPlatform, null, null, null);
+ },
+ change$1$timeout: function(timeout) {
+ return this.change$4$onPlatform$skip$skipReason$timeout(null, null, null, timeout);
+ },
+ change$2$skip$skipReason: function(skip, skipReason) {
+ return this.change$4$onPlatform$skip$skipReason$timeout(null, skip, skipReason, null);
+ },
+ forPlatform$1: function(platform) {
+ var t1 = {},
+ t2 = this.onPlatform;
+ if (t2.get$isEmpty(t2))
+ return this;
+ t1.metadata = this;
+ t2.forEach$1(0, new O.Metadata_forPlatform_closure(t1, platform));
+ return t1.metadata.change$1$onPlatform(P.LinkedHashMap_LinkedHashMap$_empty(type$.PlatformSelector, type$.Metadata));
+ },
+ serialize$0: function() {
+ var t1, t2, t3, _this = this, serializedOnPlatform = [];
+ _this.onPlatform.forEach$1(0, new O.Metadata_serialize_closure(serializedOnPlatform));
+ t1 = _this.testOn._platform_selector$_inner;
+ t2 = J.getInterceptor$(t1);
+ t3 = t2.$eq(t1, C.C_All);
+ t1 = t3 ? null : t2.toString$0(t1);
+ t2 = type$.String;
+ return P.LinkedHashMap_LinkedHashMap$_literal(["testOn", t1, "timeout", _this._serializeTimeout$1(_this.timeout), "skip", _this._skip, "skipReason", _this.skipReason, "verboseTrace", _this._verboseTrace, "chainStackTraces", _this._chainStackTraces, "retry", _this._retry, "tags", _this.tags.toList$0(0), "onPlatform", serializedOnPlatform, "forTag", _this.forTag.map$2$1(0, new O.Metadata_serialize_closure0(), t2, type$.Map_String_dynamic)], t2, type$.dynamic);
+ },
+ _serializeTimeout$1: function(timeout) {
+ var t1;
+ if (timeout.$eq(0, C.Timeout_null_null))
+ return "none";
+ t1 = timeout.duration;
+ t1 = t1 == null ? null : t1._duration;
+ return P.LinkedHashMap_LinkedHashMap$_literal(["duration", t1, "scaleFactor", timeout.scaleFactor], type$.String, type$.num);
+ }
+ };
+ O.Metadata_Metadata__unresolved.prototype = {
+ call$0: function() {
+ var _this = this,
+ t1 = _this._box_0,
+ t2 = t1.tags;
+ return O.Metadata$_(_this.chainStackTraces, t1.forTag, _this.onPlatform, _this.retry, _this.skip, _this.skipReason, t2, _this.testOn, _this.timeout, _this.verboseTrace);
+ },
+ $signature: 77
+ };
+ O.Metadata_Metadata_closure.prototype = {
+ call$2: function(merged, selector) {
+ var t1, t2;
+ type$.Metadata._check(merged);
+ type$.BooleanSelector._check(selector);
+ t1 = this._box_0;
+ t2 = t1.tags;
+ if (!H.boolConversionCheck(selector.evaluate$1(t2.get$contains(t2))))
+ return merged;
+ return merged.merge$1(t1.forTag.remove$1(0, selector));
+ },
+ $signature: 78
+ };
+ O.Metadata$deserialize_closure.prototype = {
+ call$2: function(key, nested) {
+ return new P.MapEntry(new Y.BooleanSelectorImpl(new G.Parser(new O.Scanner(S.SpanScanner$(H._asStringNullable(key)))).parse$0()), O.Metadata$deserialize(nested), type$.MapEntry_BooleanSelector_Metadata);
+ },
+ $signature: 79
+ };
+ O.Metadata__validateTags_closure.prototype = {
+ call$1: function(tag) {
+ return !J.contains$1$asx(H._checkStringNullable(tag), $.$get$anchoredHyphenatedIdentifier());
+ },
+ $signature: 4
+ };
+ O.Metadata__validateTags_closure0.prototype = {
+ call$1: function(tag) {
+ return '"' + H.S(H._checkStringNullable(tag)) + '"';
+ },
+ $signature: 7
+ };
+ O.Metadata_validatePlatformSelectors_closure.prototype = {
+ call$2: function(selector, metadata) {
+ var t1;
+ type$.PlatformSelector._check(selector);
+ type$.Metadata._check(metadata);
+ t1 = this.validVariables;
+ selector.validate$1(t1);
+ metadata.validatePlatformSelectors$1(t1);
+ },
+ $signature: 19
+ };
+ O.Metadata_merge_closure.prototype = {
+ call$2: function(metadata1, metadata2) {
+ var t1 = type$.Metadata;
+ return t1._check(metadata1).merge$1(t1._check(metadata2));
+ },
+ $signature: 44
+ };
+ O.Metadata_merge_closure0.prototype = {
+ call$2: function(metadata1, metadata2) {
+ var t1 = type$.Metadata;
+ return t1._check(metadata1).merge$1(t1._check(metadata2));
+ },
+ $signature: 44
+ };
+ O.Metadata_forPlatform_closure.prototype = {
+ call$2: function(platformSelector, platformMetadata) {
+ var t1;
+ type$.PlatformSelector._check(platformSelector);
+ type$.Metadata._check(platformMetadata);
+ if (!H.boolConversionCheck(platformSelector.evaluate$1(this.platform)))
+ return;
+ t1 = this._box_0;
+ t1.metadata = t1.metadata.merge$1(platformMetadata);
+ },
+ $signature: 19
+ };
+ O.Metadata_serialize_closure.prototype = {
+ call$2: function(key, value) {
+ type$.PlatformSelector._check(key);
+ type$.Metadata._check(value);
+ C.JSArray_methods.add$1(this.serializedOnPlatform, [J.toString$0$(key), value.serialize$0()]);
+ },
+ $signature: 19
+ };
+ O.Metadata_serialize_closure0.prototype = {
+ call$2: function(selector, metadata) {
+ type$.BooleanSelector._check(selector);
+ type$.Metadata._check(metadata);
+ return new P.MapEntry(J.toString$0$(selector), metadata.serialize$0(), type$.MapEntry_of_String_and_Map_String_dynamic);
+ },
+ $signature: 82
+ };
+ N.OperatingSystem.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ N.OperatingSystem_find_closure.prototype = {
+ call$1: function(platform) {
+ return type$.OperatingSystem._check(platform).identifier === this.identifier;
+ },
+ $signature: 83
+ };
+ N.OperatingSystem_find_closure0.prototype = {
+ call$0: function() {
+ return null;
+ },
+ $signature: 0
+ };
+ E.PlatformSelector.prototype = {
+ validate$1: function(validVariables) {
+ type$.Set_String._check(validVariables);
+ if (this === C.PlatformSelector_All)
+ return;
+ E.PlatformSelector__wrapFormatException(new E.PlatformSelector_validate_closure(this, validVariables), null, type$.void);
+ },
+ evaluate$1: function(platform) {
+ return this._platform_selector$_inner.evaluate$1(new E.PlatformSelector_evaluate_closure(platform));
+ },
+ intersection$1: function(other) {
+ var t1 = other._platform_selector$_inner,
+ t2 = J.$eq$(t1, C.C_All);
+ if (t2)
+ return this;
+ return new E.PlatformSelector(this._platform_selector$_inner.intersection$1(t1));
+ },
+ toString$0: function(_) {
+ return J.toString$0$(this._platform_selector$_inner);
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof E.PlatformSelector && J.$eq$(this._platform_selector$_inner, other._platform_selector$_inner);
+ },
+ get$hashCode: function(_) {
+ return J.get$hashCode$(this._platform_selector$_inner);
+ }
+ };
+ E.PlatformSelector$parse_closure.prototype = {
+ call$0: function() {
+ return new Y.BooleanSelectorImpl(new G.Parser(new O.Scanner(S.SpanScanner$(this.selector))).parse$0());
+ },
+ $signature: 84
+ };
+ E.PlatformSelector_validate_closure.prototype = {
+ call$0: function() {
+ return this.$this._platform_selector$_inner.validate$1(new E.PlatformSelector_validate__closure(this.validVariables));
+ },
+ $signature: 1
+ };
+ E.PlatformSelector_validate__closure.prototype = {
+ call$1: function($name) {
+ return $.$get$_universalValidVariables().contains$1(0, $name) || this.validVariables.contains$1(0, $name);
+ },
+ $signature: 4
+ };
+ E.PlatformSelector_evaluate_closure.prototype = {
+ call$1: function(variable) {
+ var t1, t2, t3;
+ H._checkStringNullable(variable);
+ t1 = this.platform;
+ t2 = t1.runtime;
+ if (variable == t2.identifier)
+ return true;
+ t3 = t2.parent;
+ if (variable == (t3 == null ? null : t3.identifier))
+ return true;
+ t3 = t1.os;
+ if (variable === t3.identifier)
+ return true;
+ switch (variable) {
+ case "dart-vm":
+ return t2.isDartVM;
+ case "browser":
+ return t2.isBrowser;
+ case "js":
+ return t2.isJS;
+ case "blink":
+ return t2.isBlink;
+ case "posix":
+ return t3 !== C.OperatingSystem_Windows_windows && t3 !== C.OperatingSystem_none_none;
+ case "google":
+ return t1.inGoogle;
+ default:
+ return false;
+ }
+ },
+ $signature: 4
+ };
+ B.Runtime.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ B.Runtime_Runtime$deserialize_closure.prototype = {
+ call$1: function(platform) {
+ return type$.Runtime._check(platform).identifier === this.serialized;
+ },
+ $signature: 85
+ };
+ U.StackTraceFormatter.prototype = {
+ configure$3$except$mapper$only: function(except, mapper, only) {
+ var t1 = type$.Set_String;
+ t1._check(except);
+ t1._check(only);
+ if (mapper != null)
+ this._mapper = mapper;
+ if (except != null)
+ this.set$_except(except);
+ if (only != null)
+ this.set$_only(only);
+ },
+ configure$2$except$only: function(except, only) {
+ return this.configure$3$except$mapper$only(except, null, only);
+ },
+ configure$1$mapper: function(mapper) {
+ return this.configure$3$except$mapper$only(null, mapper, null);
+ },
+ formatStackTrace$2$verbose: function(stackTrace, verbose) {
+ var t2, t3, chain,
+ t1 = this._mapper;
+ if (t1 == null)
+ t1 = null;
+ else {
+ t2 = t1._mapping;
+ if (t2 == null) {
+ t2 = t1._mapContents;
+ t3 = t1._mapUrl;
+ t3 = t1._mapping = T.parseJsonExtended(C.C_JsonCodec.decode$2$reviver(t2, null), t3, null);
+ t2 = t3;
+ }
+ t1 = O.mapStackTrace(t2, stackTrace, false, t1._packageResolver, t1._sdkRoot);
+ }
+ chain = U.Chain_Chain$forTrace(t1 == null ? stackTrace : t1);
+ if (verbose)
+ return chain;
+ return chain.foldFrames$2$terse(new U.StackTraceFormatter_formatStackTrace_closure(this), true);
+ },
+ set$_except: function(_except) {
+ this._except = type$.Set_String._check(_except);
+ },
+ set$_only: function(_only) {
+ this._only = type$.Set_String._check(_only);
+ }
+ };
+ U.StackTraceFormatter_formatStackTrace_closure.prototype = {
+ call$1: function(frame) {
+ var t1 = this.$this,
+ t2 = t1._only;
+ if (t2._collection$_length !== 0)
+ return !t2.contains$1(0, frame.get$$package());
+ return t1._except.contains$1(0, frame.get$$package());
+ },
+ $signature: 21
+ };
+ G.State.prototype = {
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof G.State && this.status === other.status && this.result === other.result;
+ },
+ get$hashCode: function(_) {
+ return (H.Primitives_objectHashCode(this.status) ^ 7 * H.Primitives_objectHashCode(this.result)) >>> 0;
+ },
+ toString$0: function(_) {
+ var t1 = this.status;
+ if (t1 === C.Status_pending)
+ return "pending";
+ if (t1 === C.Status_complete)
+ return this.result.name;
+ t1 = this.result;
+ if (t1 === C.Result_success)
+ return "running";
+ return "running with " + t1.toString$0(0);
+ }
+ };
+ G.Status.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ G.Result0.prototype = {
+ toString$0: function(_) {
+ return this.name;
+ }
+ };
+ U.Suite.prototype = {};
+ E.SuitePlatform.prototype = {};
+ V.Test.prototype = {$isGroupEntry: 1};
+ G.TestFailure.prototype = {
+ toString$0: function(_) {
+ return this.message;
+ },
+ get$message: function(receiver) {
+ return this.message;
+ }
+ };
+ G._expect_closure0.prototype = {
+ call$5: function(actual, matcher, reason, matchState, verbose) {
+ var t1 = new P.StringBuffer("");
+ matcher.describeMismatch$4(true, new E.StringDescription(t1), matchState, false);
+ t1 = t1._contents;
+ return G.formatFailure(matcher, true, t1.charCodeAt(0) == 0 ? t1 : t1, reason);
+ },
+ $signature: 86
+ };
+ G._expect_closure.prototype = {
+ call$0: function() {
+ },
+ $signature: 0
+ };
+ R.Timeout.prototype = {
+ merge$1: function(other) {
+ var t1, t2;
+ if (this.$eq(0, C.Timeout_null_null) || other.$eq(0, C.Timeout_null_null))
+ return C.Timeout_null_null;
+ t1 = other.duration;
+ if (t1 != null)
+ return new R.Timeout(t1, null);
+ t1 = this.duration;
+ if (t1 != null) {
+ t2 = other.scaleFactor;
+ t1 = t1._duration;
+ if (typeof t2 !== "number")
+ return H.iae(t2);
+ return new R.Timeout(new P.Duration(C.JSNumber_methods.round$0(t1 * t2)), null);
+ }
+ t1 = this.scaleFactor;
+ t2 = other.scaleFactor;
+ if (typeof t1 !== "number")
+ return t1.$mul();
+ if (typeof t2 !== "number")
+ return H.iae(t2);
+ return new R.Timeout(null, t1 * t2);
+ },
+ apply$1: function(base) {
+ var t1;
+ if (this.$eq(0, C.Timeout_null_null))
+ return null;
+ t1 = this.duration;
+ if (t1 == null) {
+ t1 = this.scaleFactor;
+ if (typeof t1 !== "number")
+ return H.iae(t1);
+ t1 = new P.Duration(C.JSNumber_methods.round$0(base._duration * t1));
+ }
+ return t1;
+ },
+ get$hashCode: function(_) {
+ return (J.get$hashCode$(this.duration) ^ 5 * J.get$hashCode$(this.scaleFactor)) >>> 0;
+ },
+ $eq: function(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof R.Timeout && J.$eq$(other.duration, this.duration) && other.scaleFactor == this.scaleFactor;
+ },
+ toString$0: function(_) {
+ var t1 = this.duration;
+ if (t1 != null)
+ return t1.toString$0(0);
+ t1 = this.scaleFactor;
+ if (t1 != null)
+ return H.S(t1) + "x";
+ return "none";
+ }
+ };
+ S.RemoteListener.prototype = {
+ _serializeGroup$3: function(channel, group, parents) {
+ var t2, t3, t4, t5, t6, t1 = {};
+ t1.parents = parents;
+ type$.Iterable_Group._check(parents);
+ parents = H.setRuntimeTypeInfo(parents.slice(0), H._arrayInstanceType(parents));
+ C.JSArray_methods.add$1(parents, group);
+ t1.parents = parents;
+ t2 = group.metadata.serialize$0();
+ t3 = group.trace;
+ t3 = t3 == null ? null : J.toString$0$(t3.get$_lazy_trace$_trace());
+ t4 = group.entries;
+ t5 = H._arrayInstanceType(t4);
+ t6 = type$.dynamic;
+ return P.LinkedHashMap_LinkedHashMap$_literal(["type", "group", "name", group.name, "metadata", t2, "trace", t3, "setUpAll", this._serializeTest$3(channel, group.setUpAll, parents), "tearDownAll", this._serializeTest$3(channel, group.tearDownAll, parents), "entries", new H.MappedListIterable(t4, t5._eval$1("Map<@,@>(1)")._check(new S.RemoteListener__serializeGroup_closure(t1, this, channel)), t5._eval$1("MappedListIterable<1,Map<@,@>>")).toList$0(0)], t6, t6);
+ },
+ _serializeTest$3: function(channel, test, groups) {
+ var testChannel, t1, t2, t3, t4;
+ type$.Iterable_Group._check(groups);
+ if (test == null)
+ return null;
+ testChannel = channel.virtualChannel$0();
+ testChannel.stream.listen$1(new S.RemoteListener__serializeTest_closure(this, test, groups, channel));
+ t1 = test.name;
+ t2 = test.metadata.serialize$0();
+ t3 = test.trace;
+ t3 = t3 == null ? null : J.toString$0$(t3.get$_lazy_trace$_trace());
+ t4 = type$.dynamic;
+ return P.LinkedHashMap_LinkedHashMap$_literal(["type", "test", "name", t1, "metadata", t2, "trace", t3, "channel", testChannel.id], t4, t4);
+ },
+ _runLiveTest$2: function(liveTest, channel) {
+ var t1, t2;
+ channel.stream.listen$1(new S.RemoteListener__runLiveTest_closure(liveTest));
+ t1 = liveTest._live_test_controller$_controller;
+ t2 = t1._onStateChangeController;
+ new P._BroadcastStream(t2, H._instanceType(t2)._eval$1("_BroadcastStream<1>")).listen$1(new S.RemoteListener__runLiveTest_closure0(channel));
+ t2 = t1._onErrorController;
+ new P._BroadcastStream(t2, H._instanceType(t2)._eval$1("_BroadcastStream<1>")).listen$1(new S.RemoteListener__runLiveTest_closure1(channel, liveTest));
+ t1 = t1._onMessageController;
+ new P._BroadcastStream(t1, H._instanceType(t1)._eval$1("_BroadcastStream<1>")).listen$1(new S.RemoteListener__runLiveTest_closure2(this, channel));
+ t1 = type$.dynamic;
+ P.runZoned(new S.RemoteListener__runLiveTest_closure3(liveTest, channel), null, null, P.LinkedHashMap_LinkedHashMap$_literal([C.Symbol_MAi, channel], t1, t1), type$.Null);
+ }
+ };
+ S.RemoteListener_start_closure.prototype = {
+ call$4: function(_, __, ___, line) {
+ var t1;
+ H._checkStringNullable(line);
+ t1 = this.printZone;
+ if (t1 != null)
+ t1.print$1(0, line);
+ t1 = type$.String;
+ this.channel._mainController._foreign._sink.add$1(0, P.LinkedHashMap_LinkedHashMap$_literal(["type", "print", "line", line], t1, t1));
+ },
+ $signature: 87
+ };
+ S.RemoteListener_start_closure0.prototype = {
+ call$1: function(_) {
+ },
+ $signature: 3
+ };
+ S.RemoteListener_start_closure1.prototype = {
+ call$0: function() {
+ var _this = this,
+ t1 = type$.String,
+ t2 = P.LinkedHashSet_LinkedHashSet$_literal(["test", "stream_channel", "test_api"], t1),
+ t3 = type$.dynamic;
+ P.runZoned(type$.Null_Function._check(new S.RemoteListener_start__closure(_this._box_0, _this.getMain, _this.channel, _this.controller, _this.beforeLoad, _this.printZone, _this.spec)), null, null, P.LinkedHashMap_LinkedHashMap$_literal([$.$get$_currentKey0(), new U.StackTraceFormatter(t2, P.LinkedHashSet_LinkedHashSet$_empty(t1))], t3, t3), type$.Null);
+ },
+ $signature: 0
+ };
+ S.RemoteListener_start__closure.prototype = {
+ call$0: function() {
+ var _this = this,
+ t1 = _this._box_0,
+ t2 = _this.channel;
+ P.runZoned(new S.RemoteListener_start___closure(t1, _this.getMain, t2, _this.controller, _this.beforeLoad, _this.printZone), new S.RemoteListener_start___closure0(t1, t2), _this.spec, null, type$.Future_Null);
+ },
+ $signature: 0
+ };
+ S.RemoteListener_start___closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$returnValue, $async$next = [], $async$self = this, error, stackTrace, exception, t1, t2, queue, message, t3, metadata, declarer, t4, map, t5, t6, main;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ main = null;
+ try {
+ main = $async$self.getMain.call$0();
+ } catch (exception) {
+ t1 = H.unwrapException(exception);
+ if (type$.NoSuchMethodError._is(t1)) {
+ S.RemoteListener__sendLoadException($async$self.channel, "No top-level main() function defined.");
+ // goto return
+ $async$goto = 1;
+ break;
+ } else {
+ error = t1;
+ stackTrace = H.getTraceFromException(exception);
+ S.RemoteListener__sendError($async$self.channel, error, stackTrace, $async$self._box_0.verboseChain);
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ }
+ if (!type$.Function._is(main)) {
+ S.RemoteListener__sendLoadException($async$self.channel, "Top-level main getter is not a function.");
+ // goto return
+ $async$goto = 1;
+ break;
+ } else if (!type$.dynamic_Function._is(main)) {
+ S.RemoteListener__sendLoadException($async$self.channel, "Top-level main() function takes arguments.");
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ t1 = $async$self.channel;
+ t2 = t1._mainController._foreign._streamController;
+ t2.toString;
+ queue = new G.StreamQueue(new P._ControllerStream(t2, H._instanceType(t2)._eval$1("_ControllerStream<1>")), Q.QueueList$(type$.Result_dynamic), P.ListQueue$(type$._EventRequest_dynamic), type$.StreamQueue_dynamic);
+ $async$goto = 3;
+ return P._asyncAwait(queue.get$next(), $async$call$0);
+ case 3:
+ // returning from await.
+ message = $async$result;
+ t2 = J.getInterceptor$asx(message);
+ H.assertHelper(J.$eq$(t2.$index(message, "type"), "initial"));
+ if (queue._isClosed)
+ H.throwExpression(queue._failClosed$0());
+ t3 = new Y._CompleterStream(type$._CompleterStream_dynamic);
+ queue._isClosed = true;
+ queue._addRequest$1(new G._RestRequest(new Y.StreamCompleter(t3, type$.StreamCompleter_dynamic), queue, type$._RestRequest_dynamic));
+ t3.listen$1(new S.RemoteListener_start____closure($async$self.controller, t1));
+ t3 = H._asBoolNullable(t2.$index(message, "asciiGlyphs"));
+ if (t3 === true)
+ $._glyphs = C.C_AsciiGlyphSet;
+ metadata = O.Metadata$deserialize(t2.$index(message, "metadata"));
+ $async$self._box_0.verboseChain = metadata._verboseTrace === true;
+ t3 = P.LinkedHashSet_LinkedHashSet$from(type$.Iterable_dynamic._as(t2.$index(message, "platformVariables")), type$.String);
+ declarer = X.Declarer$(H._asBoolNullable(t2.$index(message, "collectTraces")), metadata, H._asBoolNullable(t2.$index(message, "noRetry")), t3);
+ t3 = type$.List_dynamic;
+ type$.StackTraceFormatter._as($.Zone__current.$index(0, $.$get$_currentKey0())).configure$2$except$only(S.RemoteListener__deserializeSet(t3._as(t2.$index(message, "foldTraceExcept"))), S.RemoteListener__deserializeSet(t3._as(t2.$index(message, "foldTraceOnly"))));
+ $async$goto = 4;
+ return P._asyncAwait($async$self.beforeLoad.call$0(), $async$call$0);
+ case 4:
+ // returning from await.
+ t3 = type$.dynamic;
+ $async$goto = 5;
+ return P._asyncAwait(P.runZoned(type$.void_Function._check(main), null, null, P.LinkedHashMap_LinkedHashMap$_literal([C.Symbol_Drw, declarer], t3, t3), type$.void), $async$call$0);
+ case 5:
+ // returning from await.
+ t4 = declarer.build$0();
+ map = type$.Map_dynamic_dynamic._as(t2.$index(message, "platform"));
+ t5 = B.Runtime_Runtime$deserialize(map.$index(0, "runtime"));
+ t6 = N.OperatingSystem_find(H._asStringNullable(map.$index(0, "os")));
+ t6 = E.SuitePlatform$(t5, H._asBoolNullable(map.$index(0, "inGoogle")), t6);
+ P.runZoned(new S.RemoteListener_start____closure0(new U.Suite(t6, H._asStringNullable(t2.$index(message, "path")), U.Suite__filterGroup(t4, t6)), $async$self.printZone, t1), null, null, P.LinkedHashMap_LinkedHashMap$_literal([C.Symbol_Drw, declarer], t3, t3), type$.Null);
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ S.RemoteListener_start____closure.prototype = {
+ call$1: function(message) {
+ var t2, t3, t4,
+ t1 = J.getInterceptor$asx(message);
+ if (J.$eq$(t1.$index(message, "type"), "close")) {
+ this.controller._local._sink.close$0(0);
+ return;
+ }
+ H.assertHelper(J.$eq$(t1.$index(message, "type"), "suiteChannel"));
+ t2 = type$.SuiteChannelManager._as($.Zone__current.$index(0, $.$get$_currentKey()));
+ t3 = H._asStringNullable(t1.$index(message, "name"));
+ t1 = this.channel.virtualChannel$1(H._asIntNullable(t1.$index(message, "id")));
+ t4 = t2._outgoingConnections;
+ if (t4.containsKey$1(t3)) {
+ t2 = t4.remove$1(0, t3);
+ t2.toString;
+ H.instanceType(t2)._eval$1("StreamChannel<1>")._check(t1);
+ if (t2._stream_channel_completer$_set)
+ H.throwExpression(P.StateError$("The channel has already been set."));
+ t2._stream_channel_completer$_set = true;
+ t2._streamCompleter.setSourceStream$1(t1.stream);
+ t2 = t2._sinkCompleter;
+ t3 = t2.$ti;
+ t1 = t3._eval$1("StreamSink<1>")._check(t1.sink);
+ t2 = t3._eval$1("_CompleterSink<1>")._check(t2.sink);
+ if (t2._destinationSink != null)
+ H.throwExpression(P.StateError$("Destination sink already set"));
+ t2._setDestinationSink$1(t1);
+ } else {
+ t2 = t2._incomingConnections;
+ if (t2.containsKey$1(t3))
+ H.throwExpression(P.StateError$('Duplicate RunnerSuite.channel() connection "' + H.S(t3) + '".'));
+ else
+ t2.$indexSet(0, t3, t1);
+ }
+ },
+ $signature: 3
+ };
+ S.RemoteListener_start____closure0.prototype = {
+ call$0: function() {
+ U.Invoker_guard(new S.RemoteListener_start_____closure(this.suite, this.printZone, this.channel), type$.void);
+ },
+ $signature: 0
+ };
+ S.RemoteListener_start_____closure.prototype = {
+ call$0: function() {
+ var t1 = this.suite,
+ t2 = this.channel;
+ t2._mainController._foreign._sink.add$1(0, P.LinkedHashMap_LinkedHashMap$_literal(["type", "success", "root", new S.RemoteListener(t1, this.printZone)._serializeGroup$3(t2, t1.group, H.setRuntimeTypeInfo([], type$.JSArray_Group))], type$.String, type$.Object));
+ return null;
+ },
+ $signature: 1
+ };
+ S.RemoteListener_start___closure0.prototype = {
+ call$2: function(error, stackTrace) {
+ S.RemoteListener__sendError(this.channel, error, type$.StackTrace._check(stackTrace), this._box_0.verboseChain);
+ },
+ $signature: 5
+ };
+ S.RemoteListener__serializeGroup_closure.prototype = {
+ call$1: function(entry) {
+ var t1, t2, t3;
+ type$.GroupEntry._check(entry);
+ t1 = this.$this;
+ t2 = this.channel;
+ t3 = this._box_0.parents;
+ return entry instanceof O.Group ? t1._serializeGroup$3(t2, entry, t3) : t1._serializeTest$3(t2, type$.Test._as(entry), t3);
+ },
+ $signature: 88
+ };
+ S.RemoteListener__serializeTest_closure.prototype = {
+ call$1: function(message) {
+ var t2, _this = this,
+ t1 = J.getInterceptor$asx(message);
+ H.assertHelper(J.$eq$(t1.$index(message, "command"), "run"));
+ t2 = _this.$this;
+ t2._runLiveTest$2(_this.test.load$2$groups(t2._suite, _this.groups), _this.channel.virtualChannel$1(H._asIntNullable(t1.$index(message, "channel"))));
+ },
+ $signature: 3
+ };
+ S.RemoteListener__runLiveTest_closure.prototype = {
+ call$1: function(message) {
+ H.assertHelper(J.$eq$(J.$index$asx(message, "command"), "close"));
+ this.liveTest._live_test_controller$_controller._live_test_controller$_close$0();
+ },
+ $signature: 3
+ };
+ S.RemoteListener__runLiveTest_closure0.prototype = {
+ call$1: function(state) {
+ var t1;
+ type$.State._check(state);
+ t1 = type$.String;
+ this.channel.sink.add$1(0, P.LinkedHashMap_LinkedHashMap$_literal(["type", "state-change", "status", state.status.name, "result", state.result.name], t1, t1));
+ },
+ $signature: 23
+ };
+ S.RemoteListener__runLiveTest_closure1.prototype = {
+ call$1: function(asyncError) {
+ var t1, t2, t3, t4;
+ type$.AsyncError._check(asyncError);
+ t1 = asyncError.error;
+ t2 = type$.StackTraceFormatter._as($.Zone__current.$index(0, $.$get$_currentKey0()));
+ t3 = asyncError.stackTrace;
+ t4 = this.liveTest._live_test_controller$_controller;
+ this.channel.sink.add$1(0, P.LinkedHashMap_LinkedHashMap$_literal(["type", "error", "error", U.RemoteException_serialize(t1, t2.formatStackTrace$2$verbose(t3, t4._test.metadata._verboseTrace === true))], type$.String, type$.Object));
+ },
+ $signature: 90
+ };
+ S.RemoteListener__runLiveTest_closure2.prototype = {
+ call$1: function(message) {
+ var t1;
+ type$.Message._check(message);
+ t1 = this.$this._printZone;
+ if (t1 != null)
+ t1.print$1(0, message.text);
+ t1 = type$.String;
+ this.channel.sink.add$1(0, P.LinkedHashMap_LinkedHashMap$_literal(["type", "message", "message-type", message.type.name, "text", message.text], t1, t1));
+ },
+ $signature: 27
+ };
+ S.RemoteListener__runLiveTest_closure3.prototype = {
+ call$0: function() {
+ this.liveTest._live_test_controller$_controller._live_test_controller$_run$0().then$1$1(new S.RemoteListener__runLiveTest__closure(this.channel), type$.void);
+ },
+ $signature: 0
+ };
+ S.RemoteListener__runLiveTest__closure.prototype = {
+ call$1: function(_) {
+ var t1 = type$.String;
+ return this.channel.sink.add$1(0, P.LinkedHashMap_LinkedHashMap$_literal(["type", "complete"], t1, t1));
+ },
+ $signature: 15
+ };
+ N.SuiteChannelManager.prototype = {
+ connectOut$1: function($name) {
+ var t2, completer,
+ t1 = this._incomingConnections;
+ if (t1.containsKey$1($name))
+ return t1.$index(0, $name);
+ else {
+ t1 = this._names;
+ if (t1.contains$1(0, $name))
+ throw H.wrapException(P.StateError$('Duplicate suiteChannel() connection "' + $name + '".'));
+ else {
+ t1.add$1(0, $name);
+ t1 = new Y._CompleterStream(type$._CompleterStream_dynamic);
+ t2 = new T._CompleterSink(type$._CompleterSink_dynamic);
+ completer = new N.StreamChannelCompleter(new Y.StreamCompleter(t1, type$.StreamCompleter_dynamic), new T.StreamSinkCompleter(t2, type$.StreamSinkCompleter_dynamic), type$.StreamChannelCompleter_dynamic);
+ completer.set$_stream_channel_completer$_channel(new R._StreamChannel(t1, t2, type$._StreamChannel_dynamic));
+ this._outgoingConnections.$indexSet(0, $name, completer);
+ return completer._stream_channel_completer$_channel;
+ }
+ }
+ }
+ };
+ O.IterableSet.prototype = {
+ get$length: function(_) {
+ var t1 = this._iterable_set$_base._collection$_source;
+ return t1.get$length(t1);
+ },
+ get$iterator: function(_) {
+ var t1 = this._iterable_set$_base;
+ return new H.ListIterator(t1, t1.get$length(t1), t1.$ti._eval$1("ListIterator<ListMixin.E>"));
+ },
+ toSet$0: function(_) {
+ var t1 = this._iterable_set$_base;
+ return t1.toSet$0(t1);
+ }
+ };
+ O._IterableSet_SetMixin_UnmodifiableSetMixin.prototype = {};
+ E.StackTraceMapper.prototype = {};
+ V.errorsDontStopTest_closure.prototype = {
+ call$0: function() {
+ P.Future_Future$sync(this.body, type$.dynamic).whenComplete$1(this.completer.get$complete());
+ },
+ $signature: 0
+ };
+ V.errorsDontStopTest_closure0.prototype = {
+ call$1: function(_) {
+ var t1 = type$.Invoker._as($.Zone__current.$index(0, C.Symbol_cQL));
+ t1.heartbeat$0();
+ t1.get$_outstandingCallbacks().decrement$0();
+ return null;
+ },
+ $signature: 92
+ };
+ B.closure0.prototype = {
+ call$0: function() {
+ var t1 = $.$get$context().style;
+ if (t1 == $.$get$Style_url())
+ return C.OperatingSystem_none_none;
+ if (t1 == $.$get$Style_windows())
+ return C.OperatingSystem_Windows_windows;
+ if ($._macOSDirectories.any$1(0, J.get$startsWith$s(D.current())))
+ return C.OperatingSystem_RkP;
+ return C.OperatingSystem_Linux_linux;
+ },
+ $signature: 115
+ };
+ O.Engine.prototype = {
+ get$_onUnpaused: function() {
+ var t1 = new P._Future($.Zone__current, type$._Future_dynamic);
+ t1._asyncComplete$1(null);
+ return t1;
+ },
+ get$success: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.bool),
+ $async$returnValue, $async$self = this;
+ var $async$get$success = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ $async$goto = 3;
+ return P._asyncAwait(P.Future_wait(H.setRuntimeTypeInfo([$async$self._group._future_group$_completer.future, $async$self._loadPool._pool$_closeMemo._async_memoizer$_completer.future], type$.JSArray_Future_dynamic), true, type$.dynamic), $async$get$success);
+ case 3:
+ // returning from await.
+ if (H.boolConversionCheck($async$self._closedBeforeDone)) {
+ $async$returnValue = null;
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ $async$returnValue = $async$self.get$liveTests().every$1(0, new O.Engine_success_closure());
+ // goto return
+ $async$goto = 1;
+ break;
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$get$success, $async$completer);
+ },
+ get$liveTests: function() {
+ var _this = this;
+ return new M.UnionSet(P.LinkedHashSet_LinkedHashSet$from(H.setRuntimeTypeInfo([_this._passedGroup._union_set_controller$_set, _this._skippedGroup._union_set_controller$_set, _this._failedGroup._union_set_controller$_set, new O.IterableSet(new P.UnmodifiableListView(_this._active, type$.UnmodifiableListView_LiveTest), type$.IterableSet_LiveTest)], type$.JSArray_Set_LiveTest), type$.Set_LiveTest), true, type$.UnionSet_LiveTest);
+ },
+ Engine$3$concurrency$coverage$maxSuites: function(concurrency, coverage, maxSuites) {
+ this._group._future_group$_completer.future.then$1$1(new O.Engine_closure(this), type$.Null).catchError$1(new O.Engine_closure0());
+ },
+ run$0: function() {
+ var t2, subscription, _this = this, t1 = {};
+ if (_this._engine$_runCalled)
+ throw H.wrapException(P.StateError$("Engine.run() may not be called more than once."));
+ _this._engine$_runCalled = true;
+ t1.subscription = null;
+ t2 = _this._suiteController;
+ subscription = new P._ControllerStream(t2, H._instanceType(t2)._eval$1("_ControllerStream<1>")).listen$2$onDone(new O.Engine_run_closure(_this), new O.Engine_run_closure0(t1, _this));
+ t1.subscription = subscription;
+ _this._engine$_subscriptions.add$1(0, subscription);
+ return _this.get$success();
+ },
+ _runGroup$3: function(suiteController, group, parents) {
+ type$.List_Group._check(parents);
+ return this._runGroup$body$Engine(suiteController, group, parents);
+ },
+ _runGroup$body$Engine: function(suiteController, group, parents) {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.dynamic),
+ $async$returnValue, $async$handler = 2, $async$currentError, $async$next = [], $async$self = this, suiteConfig, skipGroup, setUpAllSucceeded, liveTest, entries, entry, test, liveTest0, t1, skipGroup0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, _i, t16, t17, t18, invoker, t19, t20, result, t21;
+ var $async$_runGroup$3 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1) {
+ $async$currentError = $async$result;
+ $async$goto = $async$handler;
+ }
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ C.JSArray_methods.add$1(parents, group);
+ $async$handler = 3;
+ t1 = suiteController._liveSuite._live_suite_controller$_controller._live_suite_controller$_suite;
+ suiteConfig = t1._runner_suite$_controller._config;
+ suiteConfig.toString;
+ skipGroup0 = group.metadata._skip === true;
+ skipGroup = skipGroup0;
+ setUpAllSucceeded = true;
+ $async$goto = !H.boolConversionCheck(skipGroup) && group.setUpAll != null ? 6 : 7;
+ break;
+ case 6:
+ // then
+ liveTest = group.setUpAll.load$2$groups(t1, parents);
+ $async$goto = 8;
+ return P._asyncAwait($async$self._engine$_runLiveTest$3$countSuccess(suiteController, liveTest, false), $async$_runGroup$3);
+ case 8:
+ // returning from await.
+ t1 = liveTest._live_test_controller$_controller._live_test_controller$_state.result;
+ setUpAllSucceeded = t1 === C.Result_success || t1 === C.Result_skipped;
+ case 7:
+ // join
+ $async$goto = !$async$self._engine$_closed && H.boolConversionCheck(setUpAllSucceeded) ? 9 : 10;
+ break;
+ case 9:
+ // then
+ t1 = group.entries;
+ t1 = H.setRuntimeTypeInfo(t1.slice(0), H._arrayInstanceType(t1)._eval$1("JSArray<1>"));
+ entries = t1;
+ suiteConfig.toString;
+ t1 = entries, t2 = t1.length, t3 = type$.Group, t4 = type$.List_Group, t5 = type$._Future_void, t6 = type$._AsyncCompleter_void, t7 = type$._SyncBroadcastStreamController_Message, t8 = type$._SyncBroadcastStreamController_AsyncError, t9 = type$._SyncBroadcastStreamController_State, t10 = type$.Test, t11 = type$.Iterable_Group, t12 = type$.JSArray_Zone, t13 = type$.JSArray_of_dynamic_Function, t14 = type$.JSArray_String, t15 = type$.JSArray_AsyncError, _i = 0;
+ case 11:
+ // for condition
+ if (!(_i < t1.length)) {
+ // goto after for
+ $async$goto = 13;
+ break;
+ }
+ entry = t1[_i];
+ if ($async$self._engine$_closed) {
+ $async$next = [1];
+ // goto finally
+ $async$goto = 4;
+ break;
+ }
+ $async$goto = entry instanceof O.Group ? 14 : 16;
+ break;
+ case 14:
+ // then
+ $async$goto = 17;
+ return P._asyncAwait($async$self._runGroup$3(suiteController, entry, parents), $async$_runGroup$3);
+ case 17:
+ // returning from await.
+ // goto join
+ $async$goto = 15;
+ break;
+ case 16:
+ // else
+ suiteConfig.toString;
+ t16 = entry.get$metadata();
+ t16 = t16._skip === true;
+ $async$goto = t16 ? 18 : 20;
+ break;
+ case 18:
+ // then
+ $async$goto = 21;
+ return P._asyncAwait($async$self._runSkippedTest$3(suiteController, t10._as(entry), parents), $async$_runGroup$3);
+ case 21:
+ // returning from await.
+ // goto join
+ $async$goto = 19;
+ break;
+ case 20:
+ // else
+ test = t10._as(entry);
+ t16 = test;
+ t17 = suiteController._liveSuite._live_suite_controller$_controller;
+ t16.toString;
+ t11._check(parents);
+ t18 = new P._AsyncCompleter(new P._Future($.Zone__current, t5), t6);
+ invoker = new U.Invoker(t16._guarded, new P.Object(), t18, H.setRuntimeTypeInfo([], t12), new P.Object(), H.setRuntimeTypeInfo([], t13), H.setRuntimeTypeInfo([], t14));
+ t19 = H.setRuntimeTypeInfo([], t15);
+ t20 = $.Zone__current;
+ result = P.List_List$from(parents, false, t3);
+ result.fixed$length = Array;
+ result.immutable$list = Array;
+ t21 = t4._check(result);
+ t16 = new V.LiveTestController(t17._live_suite_controller$_suite, t21, t16, invoker.get$_invoker$_onRun(), t18.get$complete(), t19, C.State_Status_pending_Result_success, new P._SyncBroadcastStreamController(null, null, t9), new P._SyncBroadcastStreamController(null, null, t8), new P._SyncBroadcastStreamController(null, null, t7), new P._AsyncCompleter(new P._Future(t20, t5), t6));
+ t17 = new V._LiveTest(t16);
+ t16._liveTest = t17;
+ invoker._invoker$_controller = t16;
+ $async$goto = 22;
+ return P._asyncAwait($async$self._engine$_runLiveTest$2(suiteController, t17), $async$_runGroup$3);
+ case 22:
+ // returning from await.
+ case 19:
+ // join
+ case 15:
+ // join
+ case 12:
+ // for update
+ t1.length === t2 || (0, H.throwConcurrentModificationError)(t1), ++_i;
+ // goto for condition
+ $async$goto = 11;
+ break;
+ case 13:
+ // after for
+ case 10:
+ // join
+ $async$goto = !H.boolConversionCheck(skipGroup) && group.tearDownAll != null ? 23 : 24;
+ break;
+ case 23:
+ // then
+ liveTest0 = group.tearDownAll.load$2$groups(suiteController._liveSuite._live_suite_controller$_controller._live_suite_controller$_suite, parents);
+ $async$goto = 25;
+ return P._asyncAwait($async$self._engine$_runLiveTest$3$countSuccess(suiteController, liveTest0, false), $async$_runGroup$3);
+ case 25:
+ // returning from await.
+ $async$goto = $async$self._engine$_closed ? 26 : 27;
+ break;
+ case 26:
+ // then
+ $async$goto = 28;
+ return P._asyncAwait(liveTest0._live_test_controller$_controller._live_test_controller$_close$0(), $async$_runGroup$3);
+ case 28:
+ // returning from await.
+ case 27:
+ // join
+ case 24:
+ // join
+ $async$next.push(5);
+ // goto finally
+ $async$goto = 4;
+ break;
+ case 3:
+ // uncaught
+ $async$next = [2];
+ case 4:
+ // finally
+ $async$handler = 2;
+ C.JSArray_methods.remove$1(parents, group);
+ // goto the next finally handler
+ $async$goto = $async$next.pop();
+ break;
+ case 5:
+ // after finally
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ case 2:
+ // rethrow
+ return P._asyncRethrow($async$currentError, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$_runGroup$3, $async$completer);
+ },
+ _engine$_runLiveTest$3$countSuccess: function(suiteController, liveTest, countSuccess) {
+ return this._runLiveTest$body$Engine(suiteController, liveTest, countSuccess);
+ },
+ _engine$_runLiveTest$2: function(suiteController, liveTest) {
+ return this._engine$_runLiveTest$3$countSuccess(suiteController, liveTest, true);
+ },
+ _runLiveTest$body$Engine: function(suiteController, liveTest, countSuccess) {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.dynamic),
+ $async$returnValue, $async$self = this, t2, t3, subscription, t1;
+ var $async$_engine$_runLiveTest$3$countSuccess = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = {};
+ $async$goto = 3;
+ return P._asyncAwait($async$self.get$_onUnpaused(), $async$_engine$_runLiveTest$3$countSuccess);
+ case 3:
+ // returning from await.
+ t2 = $async$self._active;
+ t2._queue_list$_add$1(t2.$ti._precomputed1._check(liveTest));
+ t2.get$first(t2).toString;
+ t1.subscription = null;
+ t2 = liveTest._live_test_controller$_controller;
+ t3 = t2._onStateChangeController;
+ subscription = new P._BroadcastStream(t3, H._instanceType(t3)._eval$1("_BroadcastStream<1>")).listen$2$onDone(new O.Engine__runLiveTest_closure($async$self, liveTest), new O.Engine__runLiveTest_closure0(t1, $async$self));
+ t1.subscription = subscription;
+ $async$self._engine$_subscriptions.add$1(0, subscription);
+ suiteController.reportLiveTest$2$countSuccess(liveTest, countSuccess);
+ $async$goto = 4;
+ return P._asyncAwait(P.Future_Future$microtask(liveTest.get$run(), type$.dynamic), $async$_engine$_runLiveTest$3$countSuccess);
+ case 4:
+ // returning from await.
+ $async$goto = 5;
+ return P._asyncAwait(P.Future_Future(new O.Engine__runLiveTest_closure1(), type$.Null), $async$_engine$_runLiveTest$3$countSuccess);
+ case 5:
+ // returning from await.
+ t1 = $async$self._restarted;
+ if (!t1.contains$1(0, liveTest)) {
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ $async$goto = 6;
+ return P._asyncAwait($async$self._engine$_runLiveTest$3$countSuccess(suiteController, t2._test.load$2$groups(t2._live_test_controller$_suite, t2._groups), countSuccess), $async$_engine$_runLiveTest$3$countSuccess);
+ case 6:
+ // returning from await.
+ t1.remove$1(0, liveTest);
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$_engine$_runLiveTest$3$countSuccess, $async$completer);
+ },
+ _runSkippedTest$3: function(suiteController, test, parents) {
+ return this._runSkippedTest$body$Engine(suiteController, test, type$.List_Group._check(parents));
+ },
+ _runSkippedTest$body$Engine: function(suiteController, test, parents) {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.dynamic),
+ $async$returnValue, $async$self = this, skipped, controller, t1;
+ var $async$_runSkippedTest$3 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = {};
+ $async$goto = 3;
+ return P._asyncAwait($async$self.get$_onUnpaused(), $async$_runSkippedTest$3);
+ case 3:
+ // returning from await.
+ skipped = new U.LocalTest(test.name, test.metadata, test.trace, false, new O.Engine__runSkippedTest_closure(), true);
+ t1.controller = null;
+ controller = V.LiveTestController$(suiteController._liveSuite._live_suite_controller$_controller._live_suite_controller$_suite, skipped, new O.Engine__runSkippedTest_closure0(t1, skipped), new O.Engine__runSkippedTest_closure1(), parents);
+ t1.controller = controller;
+ $async$goto = 4;
+ return P._asyncAwait($async$self._engine$_runLiveTest$2(suiteController, controller._liveTest), $async$_runSkippedTest$3);
+ case 4:
+ // returning from await.
+ $async$returnValue = $async$result;
+ // goto return
+ $async$goto = 1;
+ break;
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$_runSkippedTest$3, $async$completer);
+ },
+ _addLiveSuite$1: function(liveSuite) {
+ var t1, t2, t3, _this = this;
+ _this._liveSuites.add$1(0, liveSuite);
+ _this._onSuiteStartedController.add$1(0, liveSuite);
+ t1 = liveSuite._live_suite_controller$_controller;
+ t2 = t1._onTestStartedController;
+ _this._onTestStartedGroup.add$1(0, new P._BroadcastStream(t2, H._instanceType(t2)._eval$1("_BroadcastStream<1>")));
+ t2 = _this._passedGroup;
+ t3 = type$.UnmodifiableSetView_LiveTest;
+ t2._union_set_controller$_sets.add$1(0, t2.$ti._eval$1("Set<1>")._check(new L.UnmodifiableSetView(t1._passed, t3)));
+ t2 = _this._skippedGroup;
+ t2._union_set_controller$_sets.add$1(0, t2.$ti._eval$1("Set<1>")._check(new L.UnmodifiableSetView(t1._skipped, t3)));
+ t2 = _this._failedGroup;
+ t2._union_set_controller$_sets.add$1(0, t2.$ti._eval$1("Set<1>")._check(new L.UnmodifiableSetView(t1._failed, t3)));
+ }
+ };
+ O.Engine_success_closure.prototype = {
+ call$1: function(liveTest) {
+ var t1 = type$.LiveTest._check(liveTest)._live_test_controller$_controller._live_test_controller$_state,
+ t2 = t1.result;
+ return (t2 === C.Result_success || t2 === C.Result_skipped) && t1.status === C.Status_complete;
+ },
+ $signature: 95
+ };
+ O.Engine_closure.prototype = {
+ call$1: function(_) {
+ var t1;
+ type$.List_dynamic._check(_);
+ t1 = this.$this;
+ t1._onTestStartedGroup.close$0(0);
+ t1._onSuiteStartedController.close$0(0);
+ if (t1._closedBeforeDone == null)
+ t1._closedBeforeDone = false;
+ },
+ $signature: 48
+ };
+ O.Engine_closure0.prototype = {
+ call$1: function(_) {
+ },
+ $signature: 3
+ };
+ O.Engine_run_closure.prototype = {
+ call$1: function(suite) {
+ var t1;
+ type$.RunnerSuite._check(suite);
+ t1 = this.$this;
+ t1._addedSuites.add$1(0, suite);
+ t1._onSuiteAddedController.add$1(0, suite);
+ t1._group.add$1(0, new O.Engine_run__closure(t1, suite).call$0());
+ },
+ $signature: 97
+ };
+ O.Engine_run__closure.prototype = {
+ call$0: function() {
+ return this.$call$body$Engine_run__closure();
+ },
+ $call$body$Engine_run__closure: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$self = this, controller, t1, t2, loadResource;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = {};
+ t2 = $async$self.$this;
+ $async$goto = 2;
+ return P._asyncAwait(t2._loadPool.request$0(0), $async$call$0);
+ case 2:
+ // returning from await.
+ loadResource = $async$result;
+ t1.controller = null;
+ controller = B.LiveSuiteController$($async$self.suite);
+ t1.controller = controller;
+ t2._addLiveSuite$1(controller._liveSuite);
+ $async$goto = 3;
+ return P._asyncAwait(t2._runPool.withResource$1$1(new O.Engine_run___closure(t1, t2, loadResource), type$.Null), $async$call$0);
+ case 3:
+ // returning from await.
+ // implicit return
+ return P._asyncReturn(null, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ O.Engine_run___closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$returnValue, $async$self = this, t2, t3, t1;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = $async$self.$this;
+ if (t1._engine$_closed) {
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ t2 = $async$self._box_0;
+ t3 = t2.controller;
+ $async$goto = 3;
+ return P._asyncAwait(t1._runGroup$3(t3, t3._liveSuite._live_suite_controller$_controller._live_suite_controller$_suite.group, H.setRuntimeTypeInfo([], type$.JSArray_Group)), $async$call$0);
+ case 3:
+ // returning from await.
+ t3 = t2.controller;
+ t3._onTestStartedController.close$0(0);
+ t3._onCompleteGroup.close$0(0);
+ t1 = $async$self.loadResource;
+ t1.toString;
+ t2 = type$.dynamic_Function._check(new O.Engine_run____closure(t2));
+ if (t1._released)
+ H.throwExpression(P.StateError$("A PoolResource may only be released once."));
+ t1._released = true;
+ t1._pool._onResourceReleaseAllowed$1(t2);
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ O.Engine_run____closure.prototype = {
+ call$0: function() {
+ return this._box_0.controller.close$0(0);
+ },
+ $signature: 14
+ };
+ O.Engine_run_closure0.prototype = {
+ call$0: function() {
+ var t1 = this.$this;
+ t1._engine$_subscriptions.remove$1(0, this._box_1.subscription);
+ t1._onSuiteAddedController.close$0(0);
+ t1._group.close$0(0);
+ t1._loadPool.close$0(0);
+ },
+ $signature: 0
+ };
+ O.Engine__runLiveTest_closure.prototype = {
+ call$1: function(state) {
+ var t1, t2;
+ if (type$.State._check(state).status !== C.Status_complete)
+ return;
+ t1 = this.$this;
+ t2 = t1._active;
+ t2.remove$1(t2, this.liveTest);
+ if (t2.get$length(t2) === 0 && t1._activeLoadTests._collection$_length !== 0) {
+ t1 = t1._activeLoadTests;
+ t2._queue_list$_add$1(t2.$ti._precomputed1._check(t1.get$first(t1)));
+ }
+ },
+ $signature: 23
+ };
+ O.Engine__runLiveTest_closure0.prototype = {
+ call$0: function() {
+ this.$this._engine$_subscriptions.remove$1(0, this._box_0.subscription);
+ },
+ $signature: 0
+ };
+ O.Engine__runLiveTest_closure1.prototype = {
+ call$0: function() {
+ },
+ $signature: 0
+ };
+ O.Engine__runSkippedTest_closure.prototype = {
+ call$0: function() {
+ },
+ $signature: 0
+ };
+ O.Engine__runSkippedTest_closure0.prototype = {
+ call$0: function() {
+ var t2,
+ t1 = this._box_0;
+ t1.controller.setState$1(C.State_Status_running_Result_success);
+ t1.controller.setState$1(C.State_Status_running_Result_skipped);
+ t2 = this.skipped.metadata.skipReason;
+ if (t2 != null)
+ t1.controller.message$1(0, new D.Message(C.MessageType_skip, "Skip: " + t2));
+ t1.controller.setState$1(C.State_Status_complete_Result_skipped);
+ t1.controller.completer.complete$0();
+ },
+ $signature: 0
+ };
+ O.Engine__runSkippedTest_closure1.prototype = {
+ call$0: function() {
+ },
+ $signature: 0
+ };
+ E.LiveSuite.prototype = {};
+ B._LiveSuite.prototype = {};
+ B.LiveSuiteController.prototype = {
+ LiveSuiteController$1: function(_suite) {
+ var _this = this;
+ _this._liveSuite = new B._LiveSuite(_this);
+ _this._onCompleteGroup._future_group$_completer.future.then$1$2$onError(new B.LiveSuiteController_closure(_this), new B.LiveSuiteController_closure0(), type$.Null);
+ },
+ reportLiveTest$2$countSuccess: function(liveTest, countSuccess) {
+ var t2, t3, _this = this,
+ t1 = _this._onTestStartedController;
+ if ((t1._state & 4) !== 0)
+ throw H.wrapException(P.StateError$("Can't call reportLiveTest() after noMoreTests()."));
+ t2 = liveTest._live_test_controller$_controller;
+ H.assertHelper(t2._live_test_controller$_suite == _this._live_suite_controller$_suite);
+ H.assertHelper(_this._live_suite_controller$_active == null);
+ _this._live_suite_controller$_active = liveTest;
+ t3 = t2._onStateChangeController;
+ new P._BroadcastStream(t3, H._instanceType(t3)._eval$1("_BroadcastStream<1>")).listen$1(new B.LiveSuiteController_reportLiveTest_closure(_this, liveTest, countSuccess));
+ t1.add$1(0, liveTest);
+ _this._onCompleteGroup.add$1(0, t2.completer.future);
+ },
+ close$0: function(_) {
+ return this._live_suite_controller$_closeMemo.runOnce$1(new B.LiveSuiteController_close_closure(this));
+ }
+ };
+ B.LiveSuiteController_closure.prototype = {
+ call$1: function(_) {
+ type$.List_dynamic._check(_);
+ },
+ $signature: 48
+ };
+ B.LiveSuiteController_closure0.prototype = {
+ call$1: function(_) {
+ },
+ $signature: 3
+ };
+ B.LiveSuiteController_reportLiveTest_closure.prototype = {
+ call$1: function(state) {
+ var t1, t2, _this = this;
+ type$.State._check(state);
+ if (state.status !== C.Status_complete)
+ return;
+ t1 = _this.$this;
+ t1._live_suite_controller$_active = null;
+ t2 = state.result;
+ if (t2 === C.Result_skipped)
+ t1._skipped.add$1(0, _this.liveTest);
+ else if (t2 !== C.Result_success) {
+ t2 = _this.liveTest;
+ t1._passed.remove$1(0, t2);
+ t1._failed.add$1(0, t2);
+ } else if (_this.countSuccess) {
+ t2 = _this.liveTest;
+ t1._passed.add$1(0, t2);
+ t1._failed.remove$1(0, t2);
+ }
+ },
+ $signature: 23
+ };
+ B.LiveSuiteController_close_closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$handler = 1, $async$currentError, $async$next = [], $async$self = this;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1) {
+ $async$currentError = $async$result;
+ $async$goto = $async$handler;
+ }
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ $async$handler = 2;
+ $async$goto = 5;
+ return P._asyncAwait($async$self.$this._live_suite_controller$_suite._runner_suite$_controller._runner_suite$_close$0(), $async$call$0);
+ case 5:
+ // returning from await.
+ $async$next.push(4);
+ // goto finally
+ $async$goto = 3;
+ break;
+ case 2:
+ // uncaught
+ $async$next = [1];
+ case 3:
+ // finally
+ $async$handler = 1;
+ $async$self.$this._live_suite_controller$_onCloseCompleter.complete$0();
+ // goto the next finally handler
+ $async$goto = $async$next.pop();
+ break;
+ case 4:
+ // after finally
+ // implicit return
+ return P._asyncReturn(null, $async$completer);
+ case 1:
+ // rethrow
+ return P._asyncRethrow($async$currentError, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ R.ExpandedReporter.prototype = {
+ _onTestStarted$1: function(liveTest) {
+ var t1, t2, t3, t4, _this = this;
+ type$.LiveTest._check(liveTest);
+ liveTest.toString;
+ t1 = _this._stopwatch;
+ t2 = t1._stop != null;
+ if (t2)
+ if (t2) {
+ t2 = t1._core$_start;
+ t3 = H._checkIntNullable($.Primitives_timerTicks.call$0());
+ t4 = t1._stop;
+ if (typeof t3 !== "number")
+ return t3.$sub();
+ if (typeof t4 !== "number")
+ return H.iae(t4);
+ t1._core$_start = t2 + (t3 - t4);
+ t1._stop = null;
+ }
+ t1 = _this._engine._active;
+ if (t1.get$length(t1) === 1)
+ _this._progressLine$1(_this._description$1(liveTest));
+ t1 = liveTest._live_test_controller$_controller._onStateChangeController;
+ _this._subscriptions.add$1(0, new P._BroadcastStream(t1, H._instanceType(t1)._eval$1("_BroadcastStream<1>")).listen$1(new R.ExpandedReporter__onTestStarted_closure(_this, liveTest)));
+ t1 = _this._subscriptions;
+ t2 = liveTest._live_test_controller$_controller;
+ t3 = t2._onErrorController;
+ t1.add$1(0, new P._BroadcastStream(t3, H._instanceType(t3)._eval$1("_BroadcastStream<1>")).listen$1(new R.ExpandedReporter__onTestStarted_closure0(_this, liveTest)));
+ t2 = t2._onMessageController;
+ t1.add$1(0, new P._BroadcastStream(t2, H._instanceType(t2)._eval$1("_BroadcastStream<1>")).listen$1(new R.ExpandedReporter__onTestStarted_closure1(_this, liveTest)));
+ },
+ _onStateChange$2: function(liveTest, state) {
+ var t1, t2, t3;
+ if (state.status !== C.Status_complete)
+ return;
+ t1 = this._engine._active;
+ t2 = type$.UnmodifiableListView_LiveTest;
+ t3 = new P.UnmodifiableListView(t1, t2);
+ if (t3.get$length(t3) !== 0) {
+ t1 = new P.UnmodifiableListView(t1, t2);
+ this._progressLine$1(this._description$1(t1.get$first(t1)));
+ }
+ },
+ _expanded$_onError$3: function(liveTest, error, stackTrace) {
+ var t1, _this = this;
+ if (liveTest._live_test_controller$_controller._live_test_controller$_state.status !== C.Status_complete)
+ return;
+ _this._progressLine$2$suffix(_this._description$1(liveTest), " " + _this._bold + _this._red + "[E]" + _this._noColor);
+ t1 = _this._expanded$_sink;
+ t1.writeln$1(B.indent(H.S(error), null));
+ t1.writeln$1(B.indent(H.S(stackTrace), null));
+ return;
+ },
+ _expanded$_onDone$1: function(success) {
+ var t1, t2, t3, t4, _this = this;
+ H._checkBoolNullable(success);
+ if (success == null)
+ return;
+ t1 = _this._engine;
+ t2 = t1.get$liveTests();
+ if (t2.get$length(t2) === 0)
+ _this._expanded$_sink.writeln$1("No tests ran.");
+ else if (!success) {
+ for (t2 = type$.UnmodifiableListView_LiveTest, t1 = new P.UnmodifiableListView(t1._active, t2), t2 = new H.ListIterator(t1, t1.get$length(t1), t2._eval$1("ListIterator<ListMixin.E>")), t1 = _this._bold, t3 = _this._red, t4 = _this._noColor; t2.moveNext$0();)
+ _this._progressLine$2$suffix(_this._description$1(t2.__internal$_current), " - did not complete " + t1 + t3 + "[E]" + t4);
+ _this._progressLine$2$color("Some tests failed.", t3);
+ } else {
+ t1 = t1._passedGroup._union_set_controller$_set;
+ if (t1.get$length(t1) === 0)
+ _this._progressLine$1("All tests skipped.");
+ else
+ _this._progressLine$1("All tests passed!");
+ }
+ },
+ _progressLine$3$color$suffix: function(message, color, suffix) {
+ var t4, t5, _this = this,
+ t1 = _this._engine,
+ t2 = t1._passedGroup,
+ t3 = t2._union_set_controller$_set;
+ if (t3.get$length(t3) == _this._lastProgressPassed) {
+ t3 = t1._skippedGroup._union_set_controller$_set;
+ if (t3.get$length(t3) == _this._lastProgressSkipped) {
+ t3 = t1._failedGroup._union_set_controller$_set;
+ if (t3.get$length(t3) == _this._lastProgressFailed)
+ if (message == _this._lastProgressMessage)
+ t3 = suffix == null || suffix === _this._lastProgressSuffix;
+ else
+ t3 = false;
+ else
+ t3 = false;
+ } else
+ t3 = false;
+ } else
+ t3 = false;
+ if (t3)
+ return;
+ t3 = t2._union_set_controller$_set;
+ _this._lastProgressPassed = t3.get$length(t3);
+ t3 = t1._skippedGroup;
+ t4 = t3._union_set_controller$_set;
+ _this._lastProgressSkipped = t4.get$length(t4);
+ t1 = t1._failedGroup;
+ t4 = t1._union_set_controller$_set;
+ _this._lastProgressFailed = t4.get$length(t4);
+ _this._lastProgressMessage = message;
+ _this._lastProgressSuffix = suffix;
+ if (suffix != null)
+ message = J.$add$ansx(message, suffix);
+ if (color == null)
+ color = "";
+ t4 = P.Duration$(_this._stopwatch.get$elapsedMicroseconds(), 0)._duration;
+ t4 = C.JSString_methods.padLeft$2(C.JSInt_methods.toString$0(C.JSInt_methods._tdivFast$1(t4, 60000000)), 2, "0") + ":" + C.JSString_methods.padLeft$2(C.JSInt_methods.toString$0(C.JSInt_methods.$mod(C.JSInt_methods._tdivFast$1(t4, 1000000), 60)), 2, "0") + " " + _this._green + "+";
+ t2 = t2._union_set_controller$_set;
+ t5 = _this._noColor;
+ t2 = t4 + H.S(t2.get$length(t2)) + t5;
+ t4 = t3._union_set_controller$_set;
+ if (t4.get$length(t4) !== 0) {
+ t2 = t2 + _this._yellow + " ~";
+ t3 = t3._union_set_controller$_set;
+ t3 = t2 + H.S(t3.get$length(t3)) + t5;
+ t2 = t3;
+ }
+ t3 = t1._union_set_controller$_set;
+ if (t3.get$length(t3) !== 0) {
+ t2 = t2 + _this._red + " -";
+ t1 = t1._union_set_controller$_set;
+ t1 = t2 + H.S(t1.get$length(t1)) + t5;
+ } else
+ t1 = t2;
+ t5 = t1 + ": " + color + H.S(message) + t5;
+ _this._expanded$_sink.writeln$1(t5.charCodeAt(0) == 0 ? t5 : t5);
+ },
+ _progressLine$2$suffix: function(message, suffix) {
+ return this._progressLine$3$color$suffix(message, null, suffix);
+ },
+ _progressLine$2$color: function(message, color) {
+ return this._progressLine$3$color$suffix(message, color, null);
+ },
+ _progressLine$1: function(message) {
+ return this._progressLine$3$color$suffix(message, null, null);
+ },
+ _description$1: function(liveTest) {
+ var t1 = liveTest._live_test_controller$_controller;
+ return t1._test.name;
+ }
+ };
+ R.ExpandedReporter__onTestStarted_closure.prototype = {
+ call$1: function(state) {
+ return this.$this._onStateChange$2(this.liveTest, type$.State._check(state));
+ },
+ $signature: 100
+ };
+ R.ExpandedReporter__onTestStarted_closure0.prototype = {
+ call$1: function(error) {
+ type$.AsyncError._check(error);
+ return this.$this._expanded$_onError$3(this.liveTest, error.error, error.stackTrace);
+ },
+ $signature: 101
+ };
+ R.ExpandedReporter__onTestStarted_closure1.prototype = {
+ call$1: function(message) {
+ var t1, text;
+ type$.Message._check(message);
+ t1 = this.$this;
+ t1._progressLine$1(t1._description$1(this.liveTest));
+ text = message.text;
+ if (message.type === C.MessageType_skip)
+ text = " " + t1._yellow + text + t1._noColor;
+ t1._expanded$_sink.writeln$1(text);
+ },
+ $signature: 27
+ };
+ Y.RunnerSuite.prototype = {};
+ Y.RunnerSuiteController.prototype = {
+ _runner_suite$_close$0: function() {
+ return this._closeMemo.runOnce$1(new Y.RunnerSuiteController__close_closure(this));
+ },
+ set$_runner_suite$_suite: function(_suite) {
+ type$.Future_RunnerSuite._check(_suite);
+ }
+ };
+ Y.RunnerSuiteController__close_closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$self = this;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ $async$goto = 2;
+ return P._asyncAwait($async$self.$this._onDebuggingController.close$0(0), $async$call$0);
+ case 2:
+ // returning from await.
+ // implicit return
+ return P._asyncReturn(null, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ T.RuntimeSelection.prototype = {};
+ U.SuiteConfiguration.prototype = {};
+ X.PrintSink.prototype = {
+ writeln$1: function(obj) {
+ this._print_sink$_buffer._contents += obj + "\n";
+ this._flush$0();
+ },
+ _flush$0: function() {
+ var t1 = this._print_sink$_buffer;
+ if (C.JSString_methods.endsWith$1(t1.toString$0(0), "\n")) {
+ P.print(t1);
+ t1._contents = "";
+ }
+ },
+ $isStringSink: 1
+ };
+ E.JSStackTraceMapper.prototype = {};
+ E.JSStackTraceMapper__deserializePackageConfigMap_closure.prototype = {
+ call$2: function(key, value) {
+ return new P.MapEntry(H._checkStringNullable(key), P.Uri_parse(H._checkStringNullable(value)), type$.MapEntry_String_Uri);
+ },
+ $signature: 102
+ };
+ R._declarer_closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ $async$returnValue, controller, suite, engine, t1, t2, t3, t4, $async$temp1;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = $.$get$SuiteConfiguration_empty();
+ t2 = $._globalDeclarer.build$0();
+ t3 = E.SuitePlatform$(C.Runtime_ql0, false, $.$get$currentOSGuess());
+ t4 = P.Uri_base();
+ t4 = $.$get$context().prettyUri$1(t4);
+ controller = new Y.RunnerSuiteController(t1, null, new P._AsyncBroadcastStreamController(null, null, type$._AsyncBroadcastStreamController_bool), P.LinkedHashSet_LinkedHashSet$_empty(type$.String), new S.AsyncMemoizer(new P._AsyncCompleter(new P._Future($.Zone__current, type$._Future_dynamic), type$._AsyncCompleter_dynamic), type$.AsyncMemoizer_dynamic));
+ suite = new Y.RunnerSuite(controller, t3, t4, U.Suite__filterGroup(t2, t3));
+ t1 = new P._Future($.Zone__current, type$._Future_RunnerSuite);
+ t1._asyncComplete$1(suite);
+ controller.set$_runner_suite$_suite(t1);
+ engine = O.Engine$();
+ t1 = engine._suiteController;
+ t1.add$1(0, H._instanceType(t1)._precomputed1._check(type$.RunnerSuite._check(suite)));
+ t1.close$0(0);
+ if ($.Stopwatch__frequency == null) {
+ H.Primitives_initTicker();
+ $.Stopwatch__frequency = $.Primitives_timerFrequency;
+ }
+ t1 = P.LinkedHashSet_LinkedHashSet$_empty(type$.StreamSubscription_dynamic);
+ t2 = new R.ExpandedReporter(true, "\x1b[32m", "\x1b[31m", "\x1b[33m", "\x1b[1;30m", "\x1b[1m", "\x1b[0m", engine, false, false, new P.Stopwatch(), t1, new X.PrintSink(new P.StringBuffer("")));
+ t3 = engine._onTestStartedGroup._stream_group$_controller;
+ t3.toString;
+ t1.add$1(0, new P._BroadcastStream(t3, H._instanceType(t3)._eval$1("_BroadcastStream<1>")).listen$1(t2.get$_onTestStarted()));
+ t3 = engine.get$success();
+ t3.toString;
+ t1.add$1(0, P.Stream_Stream$fromFuture(t3, t3.$ti._precomputed1).listen$1(t2.get$_expanded$_onDone()));
+ t2 = type$.dynamic;
+ $async$temp1 = H;
+ $async$goto = 3;
+ return P._asyncAwait(P.runZoned(new R._declarer__closure(engine), null, null, P.LinkedHashMap_LinkedHashMap$_literal([C.Symbol_Drw, $._globalDeclarer], t2, t2), type$.Future_bool), $async$call$0);
+ case 3:
+ // returning from await.
+ if ($async$temp1.boolConversionCheck($async$result)) {
+ $async$returnValue = null;
+ // goto return
+ $async$goto = 1;
+ break;
+ }
+ P.print("");
+ P.Future_Future$error("Dummy exception to set exit code.", null, type$.void);
+ case 1:
+ // return
+ return P._asyncReturn($async$returnValue, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ R._declarer__closure.prototype = {
+ call$0: function() {
+ return U.Invoker_guard(this.engine.get$run(), type$.Future_bool);
+ },
+ $signature: 31
+ };
+ G.main_closure0.prototype = {
+ call$0: function() {
+ R.test("sample test", new G.main__closure());
+ },
+ $signature: 0
+ };
+ G.main__closure.prototype = {
+ call$0: function() {
+ var $async$goto = 0,
+ $async$completer = P._makeAsyncAwaitCompleter(type$.Null),
+ res;
+ var $async$call$0 = P._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return P._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ res = G.method1();
+ if (res === 0)
+ G.method2();
+ G.expect(true, C.C__IsTrue, null);
+ // implicit return
+ return P._asyncReturn(null, $async$completer);
+ }
+ });
+ return P._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 2
+ };
+ R.main_closure.prototype = {
+ call$0: function() {
+ return G.main_test__main$closure();
+ },
+ $signature: 103
+ };
+ (function aliases() {
+ var _ = J.JavaScriptObject.prototype;
+ _.super$JavaScriptObject$toString = _.toString$0;
+ _ = P._BroadcastStreamController.prototype;
+ _.super$_BroadcastStreamController$_addEventError = _._addEventError$0;
+ _ = P.Iterable.prototype;
+ _.super$Iterable$where = _.where$1;
+ _.super$Iterable$skipWhile = _.skipWhile$1;
+ _ = W.EventTarget.prototype;
+ _.super$EventTarget$addEventListener = _.addEventListener$3;
+ _ = Y.DelegatingStreamSubscription.prototype;
+ _.super$DelegatingStreamSubscription$onError = _.onError$1;
+ _.super$DelegatingStreamSubscription$cancel = _.cancel$0;
+ _ = M.TypeMatcher.prototype;
+ _.super$TypeMatcher$describe = _.describe$1;
+ _.super$TypeMatcher$matches = _.matches$2;
+ _ = Y.SourceSpanMixin.prototype;
+ _.super$SourceSpanMixin$$eq = _.$eq;
+ _ = X.StringScanner.prototype;
+ _.super$StringScanner$matches = _.matches$1;
+ })();
+ (function installTearOffs() {
+ var _instance = hunkHelpers.installInstanceTearOff,
+ _static_0 = hunkHelpers._static_0,
+ _static_1 = hunkHelpers._static_1,
+ _static = hunkHelpers.installStaticTearOff,
+ _instance_0_u = hunkHelpers._instance_0u,
+ _instance_1_i = hunkHelpers._instance_1i,
+ _instance_0_i = hunkHelpers._instance_0i,
+ _instance_1_u = hunkHelpers._instance_1u,
+ _instance_2_u = hunkHelpers._instance_2u;
+ _instance(J.JSString.prototype, "get$startsWith", 1, 1, null, ["call$2", "call$1"], ["startsWith$2", "startsWith$1"], 57, 0);
+ _static_0(H, "_js_helper_Primitives_dateNow$closure", "Primitives_dateNow", 36);
+ _static_1(P, "async__AsyncRun__scheduleImmediateJsOverride$closure", "_AsyncRun__scheduleImmediateJsOverride", 20);
+ _static_1(P, "async__AsyncRun__scheduleImmediateWithSetImmediate$closure", "_AsyncRun__scheduleImmediateWithSetImmediate", 20);
+ _static_1(P, "async__AsyncRun__scheduleImmediateWithTimer$closure", "_AsyncRun__scheduleImmediateWithTimer", 20);
+ _static_1(P, "async_Future__kTrue$closure", "Future__kTrue", 9);
+ _static_0(P, "async___startMicrotaskLoop$closure", "_startMicrotaskLoop", 1);
+ _static_1(P, "async___nullDataHandler$closure", "_nullDataHandler", 11);
+ _static(P, "async___nullErrorHandler$closure", 1, null, ["call$2", "call$1"], ["_nullErrorHandler", function(error) {
+ return P._nullErrorHandler(error, null);
+ }], 12, 0);
+ _static_0(P, "async___nullDoneHandler$closure", "_nullDoneHandler", 1);
+ _static(P, "async___rootHandleUncaughtError$closure", 5, null, ["call$5"], ["_rootHandleUncaughtError"], 105, 0);
+ _static(P, "async___rootRun$closure", 4, null, ["call$1$4", "call$4"], ["_rootRun", function($self, $parent, zone, f) {
+ return P._rootRun($self, $parent, zone, f, type$.dynamic);
+ }], 106, 0);
+ _static(P, "async___rootRunUnary$closure", 5, null, ["call$2$5", "call$5"], ["_rootRunUnary", function($self, $parent, zone, f, arg) {
+ return P._rootRunUnary($self, $parent, zone, f, arg, type$.dynamic, type$.dynamic);
+ }], 107, 0);
+ _static(P, "async___rootRunBinary$closure", 6, null, ["call$3$6"], ["_rootRunBinary"], 108, 0);
+ _static(P, "async___rootRegisterCallback$closure", 4, null, ["call$1$4", "call$4"], ["_rootRegisterCallback", function($self, $parent, zone, f) {
+ return P._rootRegisterCallback($self, $parent, zone, f, type$.dynamic);
+ }], 35, 0);
+ _static(P, "async___rootRegisterUnaryCallback$closure", 4, null, ["call$2$4", "call$4"], ["_rootRegisterUnaryCallback", function($self, $parent, zone, f) {
+ return P._rootRegisterUnaryCallback($self, $parent, zone, f, type$.dynamic, type$.dynamic);
+ }], 33, 0);
+ _static(P, "async___rootRegisterBinaryCallback$closure", 4, null, ["call$3$4", "call$4"], ["_rootRegisterBinaryCallback", function($self, $parent, zone, f) {
+ return P._rootRegisterBinaryCallback($self, $parent, zone, f, type$.dynamic, type$.dynamic, type$.dynamic);
+ }], 109, 0);
+ _static(P, "async___rootErrorCallback$closure", 5, null, ["call$5"], ["_rootErrorCallback"], 32, 0);
+ _static(P, "async___rootScheduleMicrotask$closure", 4, null, ["call$4"], ["_rootScheduleMicrotask"], 110, 0);
+ _static(P, "async___rootCreateTimer$closure", 5, null, ["call$5"], ["_rootCreateTimer"], 111, 0);
+ _static(P, "async___rootCreatePeriodicTimer$closure", 5, null, ["call$5"], ["_rootCreatePeriodicTimer"], 112, 0);
+ _static(P, "async___rootPrint$closure", 4, null, ["call$4"], ["_rootPrint"], 37, 0);
+ _static_1(P, "async___printToZone$closure", "_printToZone", 113);
+ _static(P, "async___rootFork$closure", 5, null, ["call$5"], ["_rootFork"], 114, 0);
+ var _;
+ _instance_0_u(_ = P._BroadcastSubscription.prototype, "get$_onPause", "_onPause$0", 1);
+ _instance_0_u(_, "get$_onResume", "_onResume$0", 1);
+ _instance_1_i(_ = P._BroadcastStreamController.prototype, "get$add", "add$1", 11);
+ _instance(_, "get$addError", 0, 1, null, ["call$2", "call$1"], ["addError$2", "addError$1"], 12, 0);
+ _instance(P._AsyncCompleter.prototype, "get$complete", 0, 0, null, ["call$1", "call$0"], ["complete$1", "complete$0"], 47, 0);
+ _instance(P._SyncCompleter.prototype, "get$complete", 0, 0, null, ["call$1", "call$0"], ["complete$1", "complete$0"], 47, 0);
+ _instance(P._Future.prototype, "get$_completeError", 0, 1, null, ["call$2", "call$1"], ["_completeError$2", "_completeError$1"], 12, 0);
+ _instance_1_i(_ = P._StreamController.prototype, "get$add", "add$1", 11);
+ _instance(_, "get$addError", 0, 1, null, ["call$2", "call$1"], ["addError$2", "addError$1"], 12, 0);
+ _instance_0_i(_, "get$close", "close$0", 14);
+ _instance_1_u(_, "get$_add", "_add$1", 11);
+ _instance_2_u(_, "get$_async$_addError", "_async$_addError$2", 70);
+ _instance_0_u(_, "get$_close", "_close$0", 1);
+ _instance_0_u(_ = P._ControllerSubscription.prototype, "get$_onPause", "_onPause$0", 1);
+ _instance_0_u(_, "get$_onResume", "_onResume$0", 1);
+ _instance_1_i(P._StreamSinkWrapper.prototype, "get$add", "add$1", 11);
+ _instance_0_u(_ = P._BufferingStreamSubscription.prototype, "get$_onPause", "_onPause$0", 1);
+ _instance_0_u(_, "get$_onResume", "_onResume$0", 1);
+ _instance_0_u(P._DoneStreamSubscription.prototype, "get$_sendDone", "_sendDone$0", 1);
+ _instance_1_i(P._LinkedHashSet.prototype, "get$contains", "contains$1", 26);
+ _static_1(P, "core_Uri_decodeComponent$closure", "Uri_decodeComponent", 7);
+ _instance_0_i(S.NullStreamSink.prototype, "get$close", "close$0", 14);
+ _instance_0_u(_ = L.StreamGroup.prototype, "get$_onListen", "_onListen$0", 1);
+ _instance_0_u(_, "get$_onCancelBroadcast", "_onCancelBroadcast$0", 1);
+ _instance_1_i(M._DelegatingIterableBase.prototype, "get$contains", "contains$1", 26);
+ _instance(D._DeepMatcher.prototype, "get$_recursiveMatch", 0, 4, null, ["call$4"], ["_recursiveMatch$4"], 58, 0);
+ _static_1(Z, "pretty_print___escapeString$closure", "_escapeString", 7);
+ _static_1(M, "util___getHexLiteral$closure", "_getHexLiteral", 7);
+ _instance(Y.SourceSpanMixin.prototype, "get$message", 1, 1, null, ["call$2$color", "call$1"], ["message$2$color", "message$1"], 71, 0);
+ _instance(_ = O.StackZoneSpecification.prototype, "get$_stack_zone_specification$_registerCallback", 0, 4, null, ["call$1$4", "call$4"], ["_stack_zone_specification$_registerCallback$1$4", "_stack_zone_specification$_registerCallback$4"], 35, 0);
+ _instance(_, "get$_stack_zone_specification$_registerUnaryCallback", 0, 4, null, ["call$2$4", "call$4"], ["_stack_zone_specification$_registerUnaryCallback$2$4", "_stack_zone_specification$_registerUnaryCallback$4"], 33, 0);
+ _instance(_, "get$_stack_zone_specification$_registerBinaryCallback", 0, 4, null, ["call$3$4", "call$4"], ["_stack_zone_specification$_registerBinaryCallback$3$4", "_stack_zone_specification$_registerBinaryCallback$4"], 63, 0);
+ _instance(_, "get$_stack_zone_specification$_errorCallback", 0, 5, null, ["call$5"], ["_stack_zone_specification$_errorCallback$5"], 32, 0);
+ _instance(_ = K._GuaranteeSink.prototype, "get$addError", 0, 1, null, ["call$2", "call$1"], ["addError$2", "addError$1"], 12, 0);
+ _instance(_, "get$_addError", 0, 1, null, ["call$2", "call$1"], ["_addError$2", "_addError$1"], 66, 0);
+ _instance_0_i(_, "get$close", "close$0", 13);
+ _instance_0_u(D._MultiChannel.prototype, "get$_closeInnerChannel", "_closeInnerChannel$0", 1);
+ _instance_0_u(_ = U.Invoker.prototype, "get$_invoker$_onRun", "_invoker$_onRun$0", 1);
+ _instance_0_u(_, "get$_runTearDowns", "_runTearDowns$0", 13);
+ _instance_0_u(V._LiveTest.prototype, "get$run", "run$0", 13);
+ _instance_1_i(V.LiveTestController.prototype, "get$message", "message$1", 96);
+ _instance_0_u(O.Engine.prototype, "get$run", "run$0", 31);
+ _instance_1_u(_ = R.ExpandedReporter.prototype, "get$_onTestStarted", "_onTestStarted$1", 98);
+ _instance_1_u(_, "get$_expanded$_onDone", "_expanded$_onDone$1", 99);
+ _static_0(G, "main_test__main$closure", "main0", 34);
+ _static(P, "math__max$closure", 2, null, ["call$1$2", "call$2"], ["max", function(a, b) {
+ return P.max(a, b, type$.num);
+ }], 76, 0);
+ })();
+ (function inheritance() {
+ var _mixin = hunkHelpers.mixin,
+ _inherit = hunkHelpers.inherit,
+ _inheritMany = hunkHelpers.inheritMany;
+ _inherit(P.Object, null);
+ _inheritMany(P.Object, [H.JS_CONST, J.Interceptor, J.JSObject, J.ArrayIterator, P.Iterable, H.CastIterator, P.MapMixin, H.Closure, P._ListBase_Object_ListMixin, H.ListIterator, P.Iterator, H.ExpandIterator, H.EmptyIterator, H.FixedLengthListMixin, H.UnmodifiableListMixin, H.Symbol, H.ConstantMap, H.TypeErrorDecoder, P.Error, H.ExceptionAndStackTrace, H._StackTrace, H.LinkedHashMapCell, H.LinkedHashMapKeyIterator, H.JSSyntaxRegExp, H._MatchImplementation, H._AllMatchesIterator, H.StringMatch, H._StringAllMatchesIterator, H.Rti, H._FunctionParameters, H._Type, P._TimerImpl, P._AsyncAwaitCompleter, P.Stream, P._BufferingStreamSubscription, P._BroadcastStreamController, P.Future, P.TimeoutException, P.Completer, P._Completer, P._FutureListener, P._Future, P._AsyncCallbackEntry, P.StreamSubscription, P.StreamTransformerBase, P._StreamController, P._SyncStreamControllerDispatch, P._AsyncStreamControllerDispatch, P._StreamSinkWrapper, P._AddStreamState, P._PendingEvents, P._DelayedEvent, P._DelayedDone, P._DoneStreamSubscription, P._StreamIterator, P.Timer, P.AsyncError, P._ZoneFunction, P.ZoneSpecification, P._ZoneSpecification, P.ZoneDelegate, P.Zone, P._ZoneDelegate, P._Zone, P._HashMapKeyIterator, P._SetBase, P._LinkedHashSetCell, P._LinkedHashSetIterator, P.ListMixin, P._UnmodifiableMapMixin, P.MapView, P._ListQueueIterator, P.SetMixin, P._SetBase_Object_SetMixin, P.Codec, P._Utf8Encoder, P._Utf8Decoder, P.bool, P.DateTime, P.num, P.Duration, P.OutOfMemoryError, P.StackOverflowError, P._Exception, P.FormatException, P.Expando, P.Function, P.List, P.Map, P.MapEntry, P.Null, P.Pattern, P.Match, P.RegExpMatch, P.StackTrace, P._StringStackTrace, P.Stopwatch, P.String, P.RuneIterator, P.StringBuffer, P.Uri, P._Uri, P.UriData, P._SimpleUri, W.EventStreamProvider, P._StructuredClone, P._AcceptStructuredClone, P.ByteBuffer, P.ByteData, P.Int8List, P.Uint8List, P.Uint8ClampedList, P.Int16List, P.Uint16List, P.Int32List, P.Uint32List, P.Float32List, P.Float64List, S.AsyncMemoizer, O.DelegatingSink, Y.DelegatingStreamSubscription, F.FutureGroup, S.NullStreamSink, V.ErrorResult, E.Result, F.ValueResult, Y.StreamCompleter, L.StreamGroup, L._StreamGroupState, G.StreamQueue, G._EventRequest, G._NextRequest, G._RestRequest, T.StreamSinkCompleter, T._CompleterSink, X.BooleanSelector, X.All, U.VariableNode, U.NotNode, U.OrNode, U.AndNode, U.ConditionalNode, T.Evaluator, Y.BooleanSelectorImpl, R.IntersectionSelector, O.None, G.Parser, O.Scanner, L.Token, L.IdentifierToken, L.TokenType, B.RecursiveVisitor, Q._QueueList_Object_ListMixin, Y.UnionSetController, M._DelegatingIterableBase, L.UnmodifiableSetMixin, G.Matcher, E.StringDescription, F.PackageConfigResolver, D.PackageRootResolver, M.Context, M._PathDirection, M._PathRelation, O.Style, X.ParsedPath, X.PathException, O.Pool, O.PoolResource, T.Mapping, T.TargetLineEntry, T.TargetEntry, T._MappingTokenizer, T._TokenKind, Y.SourceSpanMixin, Y.SourceFile, D.SourceLocationMixin, U.Highlighter, V.SourceLocation, V.SourceSpan, G.SourceSpanException, U.Chain, A.Frame, X.LazyChain, T.LazyTrace, O.StackZoneSpecification, O._Node, Y.Trace, N.UnparsedFrame, R.StreamChannelMixin, K._GuaranteeSink, N.StreamChannelCompleter, B.StreamChannelController, R.StreamChannel, X.StringScanner, S._SpanScannerState, A.AsciiGlyphSet, K.UnicodeGlyphSet, K.ClosedException, X.Declarer, O.Group, V.GroupEntry, V.Test, U.Invoker, U._AsyncCounter, Z.LiveTest, V.LiveTestController, D.Message, D.MessageType, O.Metadata, N.OperatingSystem, E.PlatformSelector, B.Runtime, U.StackTraceFormatter, G.State, G.Status, G.Result0, U.Suite, E.SuitePlatform, G.TestFailure, R.Timeout, S.RemoteListener, N.SuiteChannelManager, E.StackTraceMapper, O.Engine, E.LiveSuite, B.LiveSuiteController, R.ExpandedReporter, Y.RunnerSuiteController, T.RuntimeSelection, U.SuiteConfiguration, X.PrintSink]);
+ _inheritMany(J.Interceptor, [J.JSBool, J.JSNull, J.JavaScriptObject, J.JSArray, J.JSNumber, J.JSString, H.NativeByteBuffer, H.NativeTypedData, W.Event, W.Blob, W.DomError, W.DomException, W.EventTarget, W.Location, W.MediaError, W.NavigatorUserMediaError, W.OverconstrainedError, W.PositionError, P.SqlError]);
+ _inheritMany(J.JavaScriptObject, [J.PlainJavaScriptObject, J.UnknownJavaScriptObject, J.JavaScriptFunction]);
+ _inherit(J.JSUnmodifiableArray, J.JSArray);
+ _inheritMany(J.JSNumber, [J.JSInt, J.JSDouble]);
+ _inheritMany(P.Iterable, [H._CastIterableBase, H.EfficientLengthIterable, H.MappedIterable, H.WhereIterable, H.ExpandIterable, H.SkipWhileIterable, H._ConstantMapKeyIterable, P.IterableBase, H._StringAllMatchesIterable, P.Runes]);
+ _inherit(H.CastIterable, H._CastIterableBase);
+ _inherit(H._EfficientLengthCastIterable, H.CastIterable);
+ _inherit(P.MapBase, P.MapMixin);
+ _inheritMany(P.MapBase, [H.CastMap, H.JsLinkedHashMap, P._HashMap, P._JsonMap]);
+ _inheritMany(H.Closure, [H.CastMap_forEach_closure, H.ConstantMap_map_closure, H.Instantiation, H.Primitives_initTicker_closure, H.unwrapException_saveStackTrace, H.TearOffClosure, H.JsLinkedHashMap_values_closure, H.JsLinkedHashMap_addAll_closure, H.initHooks_closure, H.initHooks_closure0, H.initHooks_closure1, P._AsyncRun__initializeScheduleImmediate_internalCallback, P._AsyncRun__initializeScheduleImmediate_closure, P._AsyncRun__scheduleImmediateJsOverride_internalCallback, P._AsyncRun__scheduleImmediateWithSetImmediate_internalCallback, P._TimerImpl_internalCallback, P._TimerImpl$periodic_closure, P._awaitOnObject_closure, P._awaitOnObject_closure0, P._wrapJsFunctionForAsync_closure, P._SyncBroadcastStreamController__sendData_closure, P._SyncBroadcastStreamController__sendError_closure, P._SyncBroadcastStreamController__sendDone_closure, P.Future_Future_closure, P.Future_Future$microtask_closure, P.Future_wait_handleError, P.Future_wait_closure, P.Future_forEach_closure, P.Future_doWhile_closure, P._Future__addListener_closure, P._Future__prependListeners_closure, P._Future__chainForeignFuture_closure, P._Future__chainForeignFuture_closure0, P._Future__chainForeignFuture_closure1, P._Future__asyncComplete_closure, P._Future__chainFuture_closure, P._Future__asyncCompleteError_closure, P._Future__propagateToListeners_handleWhenCompleteCallback, P._Future__propagateToListeners_handleWhenCompleteCallback_closure, P._Future__propagateToListeners_handleValueCallback, P._Future__propagateToListeners_handleError, P.Stream_Stream$fromFuture_closure, P.Stream_Stream$fromFuture_closure0, P.Stream_Stream$fromIterable_closure, P.Stream_pipe_closure, P.Stream_length_closure, P.Stream_length_closure0, P.Stream_first_closure, P.Stream_first_closure0, P.Stream_last_closure, P.Stream_last_closure0, P.Stream_firstWhere_closure, P.Stream_firstWhere__closure, P.Stream_firstWhere__closure0, P.Stream_firstWhere_closure0, P._StreamController__subscribe_closure, P._StreamController__recordCancel_complete, P._AddStreamState_makeErrorHandler_closure, P._AddStreamState_cancel_closure, P._BufferingStreamSubscription__sendError_sendError, P._BufferingStreamSubscription__sendDone_sendDone, P._PendingEvents_schedule_closure, P._cancelAndError_closure, P._cancelAndErrorClosure_closure, P._cancelAndValue_closure, P._CustomZone_bindCallback_closure, P._CustomZone_bindUnaryCallback_closure, P._CustomZone_bindCallbackGuarded_closure, P._CustomZone_bindUnaryCallbackGuarded_closure, P._rootHandleUncaughtError_closure, P._RootZone_bindCallback_closure, P._RootZone_bindCallbackGuarded_closure, P._RootZone_bindUnaryCallbackGuarded_closure, P.runZoned_closure, P.HashMap_HashMap$from_closure, P.LinkedHashMap_LinkedHashMap$from_closure, P.MapBase_mapToString_closure, P.Duration_toString_sixDigits, P.Duration_toString_twoDigits, P.Uri__parseIPv4Address_error, P.Uri_parseIPv6Address_error, P.Uri_parseIPv6Address_parseHex, P._Uri__Uri$notSimple_closure, P._Uri__checkNonWindowsPathReservedCharacters_closure, P._Uri__makePath_closure, P._createTables_closure, P._createTables_build, P._createTables_setChars, P._createTables_setRange, W._EventStreamSubscription_closure, P._StructuredClone_walk_closure, P._StructuredClone_walk_closure0, P._AcceptStructuredClone_walk_closure, P._convertDataTree__convert, P.promiseToFuture_closure, P.promiseToFuture_closure0, F.FutureGroup_add_closure, F.FutureGroup_add_closure0, S.NullStreamSink_addStream_closure, L.StreamGroup_add_closure, L.StreamGroup_add_closure0, L.StreamGroup__onListen_closure, L.StreamGroup__onCancelBroadcast_closure, L.StreamGroup__listenToStream_closure, G.StreamQueue__ensureListening_closure, G.StreamQueue__ensureListening_closure1, G.StreamQueue__ensureListening_closure0, T._CompleterSink__setDestinationSink_closure, T._CancelOnErrorSubscriptionWrapper_onError_closure, T._CancelOnErrorSubscriptionWrapper_onError__closure, Y.mapMap_closure, Y.mapMap_closure0, Y.mergeMaps_closure, M.UnionSet_length_closure, M.UnionSet__iterable_closure, D._DeepMatcher__compareSets_closure, Z.prettyPrint__prettyPrint, Z.prettyPrint__prettyPrint_pp, Z.prettyPrint__prettyPrint_closure, Z.prettyPrint__prettyPrint_closure0, Z.prettyPrint__prettyPrint_closure1, M.wrapMatcher_closure, M.escape_closure, F.PackageConfigResolver__normalizeMap_closure, M.Context_join_closure, M.Context_joinAll_closure, M.Context_split_closure, M._validateArgList_closure, X.ParsedPath_normalize_closure, L.WindowsStyle_absolutePathToUri_closure, O.Pool_close_closure, O.Pool__onResourceReleaseAllowed_closure, O.Pool__runOnRelease_closure, O.Pool__runOnRelease_closure0, O.mapStackTrace_closure, O.mapStackTrace_closure0, O.mapStackTrace_closure1, O._prettifyMember_closure, O._prettifyMember_closure0, T.SingleMapping$fromJson_closure, T.SingleMapping__findLine_closure, T.SingleMapping__findColumn_closure, L.closure, U.Highlighter__writeFirstLine_closure, U.Highlighter__writeFirstLine_closure0, U.Highlighter__writeFirstLine_closure1, U.Highlighter__writeFirstLine_closure2, U.Highlighter__writeIntermediateLines_closure, U.Highlighter__writeLastLine_closure, U.Highlighter__writeLastLine_closure0, U.Highlighter__writeLastLine_closure1, U.Highlighter__writeSidebar_closure, U.Chain_capture_closure, U.Chain_Chain$current_closure, U.Chain_Chain$forTrace_closure, U.Chain_Chain$parse_closure, U.Chain_Chain$parse_closure0, U.Chain_foldFrames_closure, U.Chain_foldFrames_closure0, U.Chain_toTrace_closure, U.Chain_toString_closure0, U.Chain_toString__closure0, U.Chain_toString_closure, U.Chain_toString__closure, A.Frame_Frame$parseVM_closure, A.Frame_Frame$parseV8_closure, A.Frame_Frame$parseV8_closure_parseLocation, A.Frame_Frame$parseFirefox_closure, A.Frame_Frame$parseFriendly_closure, X.LazyChain_foldFrames_closure, X.LazyChain_toTrace_closure, T.LazyTrace_foldFrames_closure, O.StackZoneSpecification_chainFor_closure, O.StackZoneSpecification_chainFor_closure0, O.StackZoneSpecification__registerCallback_closure, O.StackZoneSpecification__registerUnaryCallback_closure, O.StackZoneSpecification__registerUnaryCallback__closure, O.StackZoneSpecification__registerBinaryCallback_closure, O.StackZoneSpecification__registerBinaryCallback__closure, O.StackZoneSpecification__currentTrace_closure, Y.Trace_Trace$current_closure, Y.Trace_Trace$from_closure, Y.Trace__parseVM_closure, Y.Trace$parseV8_closure, Y.Trace$parseV8_closure0, Y.Trace$parseJSCore_closure, Y.Trace$parseJSCore_closure0, Y.Trace$parseFirefox_closure, Y.Trace$parseFirefox_closure0, Y.Trace$parseFriendly_closure, Y.Trace$parseFriendly_closure0, Y.Trace_foldFrames_closure, Y.Trace_foldFrames_closure0, Y.Trace_toString_closure0, Y.Trace_toString_closure, K.GuaranteeChannel_closure, K.GuaranteeChannel__closure, K._GuaranteeSink__addError_closure, K._GuaranteeSink_addStream_closure, D._MultiChannel_closure, D._MultiChannel_closure0, D._MultiChannel_closure1, D._MultiChannel__closure, D._MultiChannel_virtualChannel_closure, D._MultiChannel_virtualChannel_closure0, L.internalBootstrapBrowserTest_closure, N.postMessageChannel_closure, N.postMessageChannel_closure0, N.postMessageChannel__closure, N.postMessageChannel__closure0, N.postMessageChannel__closure1, X.Declarer_test_closure, X.Declarer_test__closure, X.Declarer_test___closure, X.Declarer_group_closure, X.Declarer_build_closure, X.Declarer__runSetUps_closure, X.Declarer__tearDownAll_closure, X.Declarer__tearDownAll__closure, X.Declarer__tearDownAll___closure, O.Group_forPlatform_closure, O.Group__map_closure, O.Group__map_closure0, U.Invoker_guard_closure, U.Invoker_guard__closure, U.Invoker_waitForOutstandingCallbacks_closure, U.Invoker_waitForOutstandingCallbacks_closure0, U.Invoker_heartbeat_message, U.Invoker_heartbeat_closure, U.Invoker_heartbeat__closure, U.Invoker__handleError_closure, U.Invoker__handleError_closure0, U.Invoker__onRun_closure, U.Invoker__onRun__closure, U.Invoker__onRun___closure, U.Invoker__onRun____closure, U.Invoker__onRun___closure0, O.Metadata_Metadata__unresolved, O.Metadata_Metadata_closure, O.Metadata$deserialize_closure, O.Metadata__validateTags_closure, O.Metadata__validateTags_closure0, O.Metadata_validatePlatformSelectors_closure, O.Metadata_merge_closure, O.Metadata_merge_closure0, O.Metadata_forPlatform_closure, O.Metadata_serialize_closure, O.Metadata_serialize_closure0, N.OperatingSystem_find_closure, N.OperatingSystem_find_closure0, E.PlatformSelector$parse_closure, E.PlatformSelector_validate_closure, E.PlatformSelector_validate__closure, E.PlatformSelector_evaluate_closure, B.Runtime_Runtime$deserialize_closure, U.StackTraceFormatter_formatStackTrace_closure, G._expect_closure0, G._expect_closure, S.RemoteListener_start_closure, S.RemoteListener_start_closure0, S.RemoteListener_start_closure1, S.RemoteListener_start__closure, S.RemoteListener_start___closure, S.RemoteListener_start____closure, S.RemoteListener_start____closure0, S.RemoteListener_start_____closure, S.RemoteListener_start___closure0, S.RemoteListener__serializeGroup_closure, S.RemoteListener__serializeTest_closure, S.RemoteListener__runLiveTest_closure, S.RemoteListener__runLiveTest_closure0, S.RemoteListener__runLiveTest_closure1, S.RemoteListener__runLiveTest_closure2, S.RemoteListener__runLiveTest_closure3, S.RemoteListener__runLiveTest__closure, V.errorsDontStopTest_closure, V.errorsDontStopTest_closure0, B.closure0, O.Engine_success_closure, O.Engine_closure, O.Engine_closure0, O.Engine_run_closure, O.Engine_run__closure, O.Engine_run___closure, O.Engine_run____closure, O.Engine_run_closure0, O.Engine__runLiveTest_closure, O.Engine__runLiveTest_closure0, O.Engine__runLiveTest_closure1, O.Engine__runSkippedTest_closure, O.Engine__runSkippedTest_closure0, O.Engine__runSkippedTest_closure1, B.LiveSuiteController_closure, B.LiveSuiteController_closure0, B.LiveSuiteController_reportLiveTest_closure, B.LiveSuiteController_close_closure, R.ExpandedReporter__onTestStarted_closure, R.ExpandedReporter__onTestStarted_closure0, R.ExpandedReporter__onTestStarted_closure1, Y.RunnerSuiteController__close_closure, E.JSStackTraceMapper__deserializePackageConfigMap_closure, R._declarer_closure, R._declarer__closure, G.main_closure0, G.main__closure, R.main_closure]);
+ _inherit(P.ListBase, P._ListBase_Object_ListMixin);
+ _inherit(H.UnmodifiableListBase, P.ListBase);
+ _inheritMany(H.UnmodifiableListBase, [H.CodeUnits, P.UnmodifiableListView]);
+ _inheritMany(H.EfficientLengthIterable, [H.ListIterable, H.LinkedHashMapKeyIterable, P._HashMapKeyIterable, P.Set]);
+ _inheritMany(H.ListIterable, [H.SubListIterable, H.MappedListIterable, H.ReversedListIterable, P.ListQueue, P._JsonMapKeyIterable]);
+ _inherit(H.EfficientLengthMappedIterable, H.MappedIterable);
+ _inheritMany(P.Iterator, [H.MappedIterator, H.WhereIterator, H.SkipWhileIterator]);
+ _inherit(H.ConstantStringMap, H.ConstantMap);
+ _inherit(H.Instantiation1, H.Instantiation);
+ _inheritMany(P.Error, [H.NullError, H.JsNoSuchMethodError, H.UnknownJsTypeError, H.TypeErrorImplementation, H.RuntimeError, P.AssertionError, H._Error, P.NullThrownError, P.ArgumentError, P.UnsupportedError, P.UnimplementedError, P.StateError, P.ConcurrentModificationError, P.CyclicInitializationError]);
+ _inheritMany(H.TearOffClosure, [H.StaticClosure, H.BoundClosure]);
+ _inherit(H._AssertionError, P.AssertionError);
+ _inheritMany(P.IterableBase, [H._AllMatchesIterable, O.EmptyUnmodifiableSet]);
+ _inheritMany(H.NativeTypedData, [H.NativeByteData, H.NativeTypedArray]);
+ _inheritMany(H.NativeTypedArray, [H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin, H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin]);
+ _inherit(H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin, H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin);
+ _inherit(H.NativeTypedArrayOfDouble, H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin);
+ _inherit(H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin, H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin);
+ _inherit(H.NativeTypedArrayOfInt, H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin);
+ _inheritMany(H.NativeTypedArrayOfDouble, [H.NativeFloat32List, H.NativeFloat64List]);
+ _inheritMany(H.NativeTypedArrayOfInt, [H.NativeInt16List, H.NativeInt32List, H.NativeInt8List, H.NativeUint16List, H.NativeUint32List, H.NativeUint8ClampedList, H.NativeUint8List]);
+ _inheritMany(H._Error, [H._CastError, H._TypeError]);
+ _inheritMany(P.Stream, [P._StreamImpl, P._EmptyStream, W._EventStream, Y._CompleterStream, T.SubscriptionStream]);
+ _inheritMany(P._StreamImpl, [P._ControllerStream, P._GeneratedStreamImpl]);
+ _inherit(P._BroadcastStream, P._ControllerStream);
+ _inherit(P._ControllerSubscription, P._BufferingStreamSubscription);
+ _inherit(P._BroadcastSubscription, P._ControllerSubscription);
+ _inheritMany(P._BroadcastStreamController, [P._SyncBroadcastStreamController, P._AsyncBroadcastStreamController]);
+ _inheritMany(P._Completer, [P._AsyncCompleter, P._SyncCompleter]);
+ _inheritMany(P._StreamController, [P._AsyncStreamController, P._SyncStreamController]);
+ _inherit(P._StreamControllerAddStreamState, P._AddStreamState);
+ _inheritMany(P._PendingEvents, [P._IterablePendingEvents, P._StreamImplEvents]);
+ _inheritMany(P._DelayedEvent, [P._DelayedData, P._DelayedError]);
+ _inheritMany(P._Zone, [P._CustomZone, P._RootZone]);
+ _inherit(P._IdentityHashMap, P._HashMap);
+ _inherit(P._LinkedHashSet, P._SetBase);
+ _inherit(P._UnmodifiableMapView_MapView__UnmodifiableMapMixin, P.MapView);
+ _inherit(P.UnmodifiableMapView, P._UnmodifiableMapView_MapView__UnmodifiableMapMixin);
+ _inherit(P.SetBase, P._SetBase_Object_SetMixin);
+ _inheritMany(P.Codec, [P.Encoding, P.Base64Codec, P._FusedCodec, P.JsonCodec]);
+ _inheritMany(P.Encoding, [P.AsciiCodec, P.Utf8Codec]);
+ _inherit(P.Converter, P.StreamTransformerBase);
+ _inheritMany(P.Converter, [P._UnicodeSubsetEncoder, P.Base64Encoder, P.JsonDecoder, P.Utf8Encoder, P.Utf8Decoder]);
+ _inherit(P.AsciiEncoder, P._UnicodeSubsetEncoder);
+ _inheritMany(P.num, [P.double, P.int]);
+ _inheritMany(P.ArgumentError, [P.RangeError, P.IndexError]);
+ _inherit(P._DataUri, P._Uri);
+ _inheritMany(W.Event, [W.ApplicationCacheErrorEvent, W.ErrorEvent, W.MediaKeyMessageEvent, W.MessageEvent, W.PresentationConnectionCloseEvent, W.SpeechRecognitionError]);
+ _inherit(W.File, W.Blob);
+ _inherit(W.MessagePort, W.EventTarget);
+ _inherit(W._EventStreamSubscription, P.StreamSubscription);
+ _inherit(P._StructuredCloneDart2Js, P._StructuredClone);
+ _inherit(P._AcceptStructuredCloneDart2Js, P._AcceptStructuredClone);
+ _inherit(T._CancelOnErrorSubscriptionWrapper, Y.DelegatingStreamSubscription);
+ _inherit(S.Validator, B.RecursiveVisitor);
+ _inherit(Q.QueueList, Q._QueueList_Object_ListMixin);
+ _inherit(M._UnionSet_SetBase_UnmodifiableSetMixin, P.SetBase);
+ _inherit(M.UnionSet, M._UnionSet_SetBase_UnmodifiableSetMixin);
+ _inherit(M.DelegatingIterable, M._DelegatingIterableBase);
+ _inherit(M.DelegatingSet, M.DelegatingIterable);
+ _inherit(L._UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin, M.DelegatingSet);
+ _inherit(L.UnmodifiableSetView, L._UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin);
+ _inheritMany(G.Matcher, [Y._IsTrue, M.TypeMatcher, D._DeepMatcher]);
+ _inherit(E.FeatureMatcher, M.TypeMatcher);
+ _inheritMany(E.FeatureMatcher, [Y._Predicate, D._StringEqualsMatcher]);
+ _inherit(B.InternalStyle, O.Style);
+ _inheritMany(B.InternalStyle, [E.PosixStyle, F.UrlStyle, L.WindowsStyle]);
+ _inheritMany(T.Mapping, [T.MultiSectionMapping, T.MappingBundle, T.SingleMapping]);
+ _inheritMany(Y.SourceSpanMixin, [V.SourceSpanBase, Y._FileSpan]);
+ _inheritMany(V.SourceSpanBase, [G.SourceMapSpan, X.SourceSpanWithContext]);
+ _inherit(Y.FileLocation, D.SourceLocationMixin);
+ _inherit(G.SourceSpanFormatException, G.SourceSpanException);
+ _inheritMany(R.StreamChannelMixin, [K.GuaranteeChannel, D._MultiChannel, D.VirtualChannel, R._StreamChannel]);
+ _inherit(E.StringScannerException, G.SourceSpanFormatException);
+ _inherit(S.SpanScanner, X.StringScanner);
+ _inherit(U.LocalTest, V.Test);
+ _inherit(V._LiveTest, Z.LiveTest);
+ _inherit(O._IterableSet_SetMixin_UnmodifiableSetMixin, P.SetMixin);
+ _inherit(O.IterableSet, O._IterableSet_SetMixin_UnmodifiableSetMixin);
+ _inherit(B._LiveSuite, E.LiveSuite);
+ _inherit(Y.RunnerSuite, U.Suite);
+ _inherit(E.JSStackTraceMapper, E.StackTraceMapper);
+ _mixin(H.UnmodifiableListBase, H.UnmodifiableListMixin);
+ _mixin(H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin, P.ListMixin);
+ _mixin(H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin, H.FixedLengthListMixin);
+ _mixin(H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin, P.ListMixin);
+ _mixin(H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin, H.FixedLengthListMixin);
+ _mixin(P._AsyncStreamController, P._AsyncStreamControllerDispatch);
+ _mixin(P._SyncStreamController, P._SyncStreamControllerDispatch);
+ _mixin(P._ListBase_Object_ListMixin, P.ListMixin);
+ _mixin(P._SetBase_Object_SetMixin, P.SetMixin);
+ _mixin(P._UnmodifiableMapView_MapView__UnmodifiableMapMixin, P._UnmodifiableMapMixin);
+ _mixin(Q._QueueList_Object_ListMixin, P.ListMixin);
+ _mixin(M._UnionSet_SetBase_UnmodifiableSetMixin, L.UnmodifiableSetMixin);
+ _mixin(L._UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin, L.UnmodifiableSetMixin);
+ _mixin(O._IterableSet_SetMixin_UnmodifiableSetMixin, L.UnmodifiableSetMixin);
+ })();
+ var init = {typeUniverse: {eC: new Map(), tR: {}, eT: {}, tPV: {}, sEA: []}, mangledGlobalNames: {int: "int", double: "double", num: "num", String: "String", bool: "bool", Null: "Null", List: "List"}, mangledNames: {}, getTypeFromName: getGlobalFromName, metadata: [], types: ["Null()", "~()", "Future<Null>()", "Null(@)", "bool(String)", "Null(@,StackTrace)", "Null(@,@)", "String(String)", "Trace()", "bool(@)", "Frame(String)", "~(Object)", "~(Object[StackTrace])", "Future<~>()", "Future<@>()", "~(@)", "Chain()", "Frame()", "@(@)", "Null(PlatformSelector,Metadata)", "~(~())", "bool(Frame)", "GroupEntry(GroupEntry)", "Null(State)", "String(Match)", "String(int)", "bool(Object)", "Null(Message)", "Null(Zone,ZoneDelegate,Zone,Object,StackTrace)", "Null(MessageEvent)", "Null(String)", "Future<bool>()", "AsyncError(Zone,ZoneDelegate,Zone,Object,StackTrace)", "0^(1^)(Zone,ZoneDelegate,Zone,0^(1^))<Object,Object>", "@()", "0^()(Zone,ZoneDelegate,Zone,0^())<Object>", "int()", "~(Zone,ZoneDelegate,Zone,String)", "String(Frame)", "int(Frame)", "String(@)", "~(Uint8List,String,int)", "Trace(String)", "Null(bool)", "Metadata(Metadata,Metadata)", "Trace(Trace)", "Frame(Frame)", "~([Object])", "Null(List<@>)", "bool()", "Future<List<@>>()", "Uri(@,@)", "bool(Trace)", "List<Frame>(Trace)", "int(Trace)", "String(@,int,Set<@>,bool)", "String(Trace)", "bool(Pattern[int])", "List<String>(Object,Object,String,int)", "Frame(@,@)", "@(@,@)", "@(Event)", "Uint8List(@,@)", "0^(1^,2^)(Zone,ZoneDelegate,Zone,Function)<Object,Object,Object>", "Uint8List(int)", "int(int,int)", "~(@[StackTrace])", "~(String[@])", "~(String,int)", "bool(MessageEvent)", "~(Object,StackTrace)", "String(String{color:@})", "bool(GroupEntry)", "Future<@>(@)", "String()", "_Future<@>(@)", "0^(0^,0^)<num>", "Metadata()", "Metadata(Metadata,BooleanSelector)", "MapEntry<BooleanSelector,Metadata>(@,@)", "Null(@[StackTrace])", "bool/()", "MapEntry<String,Map<String,@>>(BooleanSelector,Metadata)", "bool(OperatingSystem)", "BooleanSelector()", "bool(Runtime)", "String(@,Matcher,String,Map<@,@>,bool)", "Null(Zone,ZoneDelegate,Zone,String)", "Map<@,@>(GroupEntry)", "Null(int,@)", "Null(AsyncError)", "Null(~())", "~(~)", "Map<String,int>()", "@(String)", "bool(LiveTest)", "~(Message)", "Null(RunnerSuite)", "~(LiveTest)", "~(bool)", "~(State)", "~(AsyncError)", "MapEntry<String,Uri>(String,String)", "@()()", "@(@,String)", "~(Zone,ZoneDelegate,Zone,@,StackTrace)", "0^(Zone,ZoneDelegate,Zone,0^())<Object>", "0^(Zone,ZoneDelegate,Zone,0^(1^),1^)<Object,Object>", "0^(Zone,ZoneDelegate,Zone,0^(1^,2^),1^,2^)<Object,Object,Object>", "0^(1^,2^)(Zone,ZoneDelegate,Zone,0^(1^,2^))<Object,Object,Object>", "~(Zone,ZoneDelegate,Zone,~())", "Timer(Zone,ZoneDelegate,Zone,Duration,~())", "Timer(Zone,ZoneDelegate,Zone,Duration,~(Timer))", "~(String)", "Zone(Zone,ZoneDelegate,Zone,ZoneSpecification,Map<@,@>)", "OperatingSystem()"], interceptorsByTag: null, leafTags: null};
+ H._Universe_addRules(init.typeUniverse, JSON.parse('{"JavaScriptFunction":"JavaScriptObject","PlainJavaScriptObject":"JavaScriptObject","UnknownJavaScriptObject":"JavaScriptObject","AbortPaymentEvent":"Event","ExtendableEvent":"Event","Window":"EventTarget","JSBool":{"bool":[]},"JSNull":{"Null":[]},"JavaScriptObject":{"JSObject":[],"Function":[]},"JSArray":{"List":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"JSUnmodifiableArray":{"JSArray":["1"],"List":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"ArrayIterator":{"Iterator":["1"]},"JSNumber":{"double":[],"num":[]},"JSInt":{"int":[],"double":[],"num":[]},"JSDouble":{"double":[],"num":[]},"JSString":{"String":[],"Pattern":[]},"_CastIterableBase":{"Iterable":["2"]},"CastIterator":{"Iterator":["2"]},"CastIterable":{"_CastIterableBase":["1","2"],"Iterable":["2"],"Iterable.E":"2"},"_EfficientLengthCastIterable":{"CastIterable":["1","2"],"EfficientLengthIterable":["2"],"_CastIterableBase":["1","2"],"Iterable":["2"],"Iterable.E":"2"},"CastMap":{"MapMixin":["3","4"],"Map":["3","4"],"MapMixin.K":"3","MapMixin.V":"4"},"CodeUnits":{"UnmodifiableListMixin":["int"],"ListMixin":["int"],"List":["int"],"EfficientLengthIterable":["int"],"Iterable":["int"],"ListMixin.E":"int","UnmodifiableListMixin.E":"int"},"EfficientLengthIterable":{"Iterable":["1"]},"ListIterable":{"EfficientLengthIterable":["1"],"Iterable":["1"]},"SubListIterable":{"ListIterable":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"],"Iterable.E":"1","ListIterable.E":"1"},"ListIterator":{"Iterator":["1"]},"MappedIterable":{"Iterable":["2"],"Iterable.E":"2"},"EfficientLengthMappedIterable":{"MappedIterable":["1","2"],"EfficientLengthIterable":["2"],"Iterable":["2"],"Iterable.E":"2"},"MappedIterator":{"Iterator":["2"]},"MappedListIterable":{"ListIterable":["2"],"EfficientLengthIterable":["2"],"Iterable":["2"],"Iterable.E":"2","ListIterable.E":"2"},"WhereIterable":{"Iterable":["1"],"Iterable.E":"1"},"WhereIterator":{"Iterator":["1"]},"ExpandIterable":{"Iterable":["2"],"Iterable.E":"2"},"ExpandIterator":{"Iterator":["2"]},"SkipWhileIterable":{"Iterable":["1"],"Iterable.E":"1"},"SkipWhileIterator":{"Iterator":["1"]},"EmptyIterator":{"Iterator":["1"]},"UnmodifiableListBase":{"UnmodifiableListMixin":["1"],"ListMixin":["1"],"List":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"ReversedListIterable":{"ListIterable":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"],"Iterable.E":"1","ListIterable.E":"1"},"ConstantMap":{"Map":["1","2"]},"ConstantStringMap":{"ConstantMap":["1","2"],"Map":["1","2"]},"_ConstantMapKeyIterable":{"Iterable":["1"],"Iterable.E":"1"},"Instantiation":{"Closure":[],"Function":[]},"Instantiation1":{"Closure":[],"Function":[]},"NullError":{"NoSuchMethodError":[],"Error":[]},"JsNoSuchMethodError":{"NoSuchMethodError":[],"Error":[]},"UnknownJsTypeError":{"Error":[]},"_StackTrace":{"StackTrace":[]},"Closure":{"Function":[]},"TearOffClosure":{"Closure":[],"Function":[]},"StaticClosure":{"Closure":[],"Function":[]},"BoundClosure":{"Closure":[],"Function":[]},"TypeErrorImplementation":{"Error":[]},"RuntimeError":{"Error":[]},"_AssertionError":{"Error":[]},"JsLinkedHashMap":{"LinkedHashMap":["1","2"],"MapMixin":["1","2"],"Map":["1","2"],"MapMixin.K":"1","MapMixin.V":"2"},"LinkedHashMapKeyIterable":{"EfficientLengthIterable":["1"],"Iterable":["1"],"Iterable.E":"1"},"LinkedHashMapKeyIterator":{"Iterator":["1"]},"JSSyntaxRegExp":{"RegExp":[],"Pattern":[]},"_MatchImplementation":{"RegExpMatch":[],"Match":[]},"_AllMatchesIterable":{"Iterable":["RegExpMatch"],"Iterable.E":"RegExpMatch"},"_AllMatchesIterator":{"Iterator":["RegExpMatch"]},"StringMatch":{"Match":[]},"_StringAllMatchesIterable":{"Iterable":["Match"],"Iterable.E":"Match"},"_StringAllMatchesIterator":{"Iterator":["Match"]},"NativeByteBuffer":{"ByteBuffer":[]},"NativeByteData":{"NativeTypedData":[]},"NativeTypedArray":{"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[]},"NativeTypedArrayOfDouble":{"ListMixin":["double"],"JavaScriptIndexingBehavior":["@"],"List":["double"],"NativeTypedData":[],"EfficientLengthIterable":["double"],"FixedLengthListMixin":["double"],"Iterable":["double"]},"NativeTypedArrayOfInt":{"ListMixin":["int"],"List":["int"],"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[],"EfficientLengthIterable":["int"],"FixedLengthListMixin":["int"],"Iterable":["int"]},"NativeFloat32List":{"ListMixin":["double"],"JavaScriptIndexingBehavior":["@"],"List":["double"],"NativeTypedData":[],"EfficientLengthIterable":["double"],"FixedLengthListMixin":["double"],"Iterable":["double"],"ListMixin.E":"double"},"NativeFloat64List":{"ListMixin":["double"],"JavaScriptIndexingBehavior":["@"],"List":["double"],"NativeTypedData":[],"EfficientLengthIterable":["double"],"FixedLengthListMixin":["double"],"Iterable":["double"],"ListMixin.E":"double"},"NativeInt16List":{"ListMixin":["int"],"List":["int"],"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[],"EfficientLengthIterable":["int"],"FixedLengthListMixin":["int"],"Iterable":["int"],"ListMixin.E":"int"},"NativeInt32List":{"ListMixin":["int"],"List":["int"],"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[],"EfficientLengthIterable":["int"],"FixedLengthListMixin":["int"],"Iterable":["int"],"ListMixin.E":"int"},"NativeInt8List":{"ListMixin":["int"],"List":["int"],"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[],"EfficientLengthIterable":["int"],"FixedLengthListMixin":["int"],"Iterable":["int"],"ListMixin.E":"int"},"NativeUint16List":{"ListMixin":["int"],"List":["int"],"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[],"EfficientLengthIterable":["int"],"FixedLengthListMixin":["int"],"Iterable":["int"],"ListMixin.E":"int"},"NativeUint32List":{"Uint32List":[],"ListMixin":["int"],"List":["int"],"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[],"EfficientLengthIterable":["int"],"FixedLengthListMixin":["int"],"Iterable":["int"],"ListMixin.E":"int"},"NativeUint8ClampedList":{"ListMixin":["int"],"List":["int"],"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[],"EfficientLengthIterable":["int"],"FixedLengthListMixin":["int"],"Iterable":["int"],"ListMixin.E":"int"},"NativeUint8List":{"Uint8List":[],"ListMixin":["int"],"List":["int"],"JavaScriptIndexingBehavior":["@"],"NativeTypedData":[],"EfficientLengthIterable":["int"],"FixedLengthListMixin":["int"],"Iterable":["int"],"ListMixin.E":"int"},"_Type":{"Type":[]},"_Error":{"Error":[]},"_CastError":{"Error":[]},"_TypeError":{"Error":[]},"_TimerImpl":{"Timer":[]},"_AsyncAwaitCompleter":{"Completer":["1"]},"_BroadcastStream":{"_ControllerStream":["1"],"_StreamImpl":["1"],"Stream":["1"],"Stream.T":"1"},"_BroadcastSubscription":{"_ControllerSubscription":["1"],"_BufferingStreamSubscription":["1"],"_EventDispatch":["1"],"StreamSubscription":["1"],"_BufferingStreamSubscription.T":"1"},"_BroadcastStreamController":{"StreamController":["1"],"StreamSink":["1"],"EventSink":["1"],"_EventDispatch":["1"],"_StreamControllerLifecycle":["1"],"StreamConsumer":["1"],"Sink":["1"]},"_SyncBroadcastStreamController":{"_BroadcastStreamController":["1"],"StreamController":["1"],"StreamSink":["1"],"EventSink":["1"],"_EventDispatch":["1"],"_StreamControllerLifecycle":["1"],"StreamConsumer":["1"],"Sink":["1"]},"_AsyncBroadcastStreamController":{"_BroadcastStreamController":["1"],"StreamController":["1"],"StreamSink":["1"],"EventSink":["1"],"_EventDispatch":["1"],"_StreamControllerLifecycle":["1"],"StreamConsumer":["1"],"Sink":["1"]},"TimeoutException":{"Exception":[]},"_Completer":{"Completer":["1"]},"_AsyncCompleter":{"_Completer":["1"],"Completer":["1"]},"_SyncCompleter":{"_Completer":["1"],"Completer":["1"]},"_Future":{"Future":["1"]},"StreamTransformerBase":{"StreamTransformer":["1","2"]},"_StreamController":{"StreamController":["1"],"StreamSink":["1"],"EventSink":["1"],"_EventDispatch":["1"],"_StreamControllerLifecycle":["1"],"StreamConsumer":["1"],"Sink":["1"]},"_AsyncStreamController":{"_AsyncStreamControllerDispatch":["1"],"_StreamController":["1"],"StreamController":["1"],"StreamSink":["1"],"EventSink":["1"],"_EventDispatch":["1"],"_StreamControllerLifecycle":["1"],"StreamConsumer":["1"],"Sink":["1"]},"_SyncStreamController":{"_SyncStreamControllerDispatch":["1"],"_StreamController":["1"],"StreamController":["1"],"StreamSink":["1"],"EventSink":["1"],"_EventDispatch":["1"],"_StreamControllerLifecycle":["1"],"StreamConsumer":["1"],"Sink":["1"]},"_ControllerStream":{"_StreamImpl":["1"],"Stream":["1"],"Stream.T":"1"},"_ControllerSubscription":{"_BufferingStreamSubscription":["1"],"_EventDispatch":["1"],"StreamSubscription":["1"],"_BufferingStreamSubscription.T":"1"},"_StreamSinkWrapper":{"StreamSink":["1"],"EventSink":["1"],"StreamConsumer":["1"],"Sink":["1"]},"_StreamControllerAddStreamState":{"_AddStreamState":["1"]},"_BufferingStreamSubscription":{"_EventDispatch":["1"],"StreamSubscription":["1"],"_BufferingStreamSubscription.T":"1"},"_StreamImpl":{"Stream":["1"]},"_GeneratedStreamImpl":{"_StreamImpl":["1"],"Stream":["1"],"Stream.T":"1"},"_IterablePendingEvents":{"_PendingEvents":["1"]},"_DelayedData":{"_DelayedEvent":["1"]},"_DelayedError":{"_DelayedEvent":["@"]},"_DelayedDone":{"_DelayedEvent":["@"]},"_StreamImplEvents":{"_PendingEvents":["1"]},"_DoneStreamSubscription":{"StreamSubscription":["1"]},"_EmptyStream":{"Stream":["1"],"Stream.T":"1"},"AsyncError":{"Error":[]},"_ZoneSpecification":{"ZoneSpecification":[]},"_ZoneDelegate":{"ZoneDelegate":[]},"_Zone":{"Zone":[]},"_CustomZone":{"_Zone":[],"Zone":[]},"_RootZone":{"_Zone":[],"Zone":[]},"_HashMap":{"MapMixin":["1","2"],"Map":["1","2"],"MapMixin.K":"1","MapMixin.V":"2"},"_IdentityHashMap":{"_HashMap":["1","2"],"MapMixin":["1","2"],"Map":["1","2"],"MapMixin.K":"1","MapMixin.V":"2"},"_HashMapKeyIterable":{"EfficientLengthIterable":["1"],"Iterable":["1"],"Iterable.E":"1"},"_HashMapKeyIterator":{"Iterator":["1"]},"_LinkedHashSet":{"_SetBase":["1"],"LinkedHashSet":["1"],"Set":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"_LinkedHashSetIterator":{"Iterator":["1"]},"UnmodifiableListView":{"UnmodifiableListMixin":["1"],"ListMixin":["1"],"List":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"],"ListMixin.E":"1","UnmodifiableListMixin.E":"1"},"IterableBase":{"Iterable":["1"]},"ListBase":{"ListMixin":["1"],"List":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"MapBase":{"MapMixin":["1","2"],"Map":["1","2"]},"MapMixin":{"Map":["1","2"]},"MapView":{"Map":["1","2"]},"UnmodifiableMapView":{"_UnmodifiableMapView_MapView__UnmodifiableMapMixin":["1","2"],"MapView":["1","2"],"_UnmodifiableMapMixin":["1","2"],"Map":["1","2"]},"ListQueue":{"ListIterable":["1"],"Queue":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"],"Iterable.E":"1","ListIterable.E":"1"},"_ListQueueIterator":{"Iterator":["1"]},"SetMixin":{"Set":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"SetBase":{"SetMixin":["1"],"Set":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"_SetBase":{"Set":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"_JsonMap":{"MapMixin":["String","@"],"Map":["String","@"],"MapMixin.K":"String","MapMixin.V":"@"},"_JsonMapKeyIterable":{"ListIterable":["String"],"EfficientLengthIterable":["String"],"Iterable":["String"],"Iterable.E":"String","ListIterable.E":"String"},"AsciiCodec":{"Codec":["String","List<int>"],"Codec.S":"String"},"_UnicodeSubsetEncoder":{"Converter":["String","List<int>"],"StreamTransformer":["String","List<int>"]},"AsciiEncoder":{"Converter":["String","List<int>"],"StreamTransformer":["String","List<int>"]},"Base64Codec":{"Codec":["List<int>","String"],"Codec.S":"List<int>"},"Base64Encoder":{"Converter":["List<int>","String"],"StreamTransformer":["List<int>","String"]},"_FusedCodec":{"Codec":["1","3"],"Codec.S":"1"},"Converter":{"StreamTransformer":["1","2"]},"Encoding":{"Codec":["String","List<int>"]},"JsonCodec":{"Codec":["Object","String"],"Codec.S":"Object"},"JsonDecoder":{"Converter":["String","Object"],"StreamTransformer":["String","Object"]},"Utf8Codec":{"Codec":["String","List<int>"],"Codec.S":"String"},"Utf8Encoder":{"Converter":["String","List<int>"],"StreamTransformer":["String","List<int>"]},"Utf8Decoder":{"Converter":["List<int>","String"],"StreamTransformer":["List<int>","String"]},"double":{"num":[]},"AssertionError":{"Error":[]},"NullThrownError":{"Error":[]},"ArgumentError":{"Error":[]},"RangeError":{"Error":[]},"IndexError":{"Error":[]},"UnsupportedError":{"Error":[]},"UnimplementedError":{"Error":[]},"StateError":{"Error":[]},"ConcurrentModificationError":{"Error":[]},"OutOfMemoryError":{"Error":[]},"StackOverflowError":{"Error":[]},"CyclicInitializationError":{"Error":[]},"_Exception":{"Exception":[]},"FormatException":{"Exception":[]},"int":{"num":[]},"List":{"EfficientLengthIterable":["1"],"Iterable":["1"]},"RegExpMatch":{"Match":[]},"Set":{"EfficientLengthIterable":["1"],"Iterable":["1"]},"_StringStackTrace":{"StackTrace":[]},"String":{"Pattern":[]},"Runes":{"Iterable":["int"],"Iterable.E":"int"},"RuneIterator":{"Iterator":["int"]},"StringBuffer":{"StringSink":[]},"_Uri":{"Uri":[]},"_SimpleUri":{"Uri":[]},"_DataUri":{"Uri":[]},"ApplicationCacheErrorEvent":{"Event":[]},"ErrorEvent":{"Event":[]},"File":{"Blob":[]},"MediaKeyMessageEvent":{"Event":[]},"MessageEvent":{"Event":[]},"MessagePort":{"EventTarget":[]},"PresentationConnectionCloseEvent":{"Event":[]},"SpeechRecognitionError":{"Event":[]},"_EventStream":{"Stream":["1"],"Stream.T":"1"},"_EventStreamSubscription":{"StreamSubscription":["1"]},"Int8List":{"List":["int"],"EfficientLengthIterable":["int"],"Iterable":["int"]},"Uint8List":{"List":["int"],"EfficientLengthIterable":["int"],"Iterable":["int"]},"Uint8ClampedList":{"List":["int"],"EfficientLengthIterable":["int"],"Iterable":["int"]},"Int16List":{"List":["int"],"EfficientLengthIterable":["int"],"Iterable":["int"]},"Uint16List":{"List":["int"],"EfficientLengthIterable":["int"],"Iterable":["int"]},"Int32List":{"List":["int"],"EfficientLengthIterable":["int"],"Iterable":["int"]},"Uint32List":{"List":["int"],"EfficientLengthIterable":["int"],"Iterable":["int"]},"Float32List":{"List":["double"],"EfficientLengthIterable":["double"],"Iterable":["double"]},"Float64List":{"List":["double"],"EfficientLengthIterable":["double"],"Iterable":["double"]},"DelegatingSink":{"Sink":["1"]},"DelegatingStreamSubscription":{"StreamSubscription":["1"]},"FutureGroup":{"Sink":["Future<1>"]},"NullStreamSink":{"StreamSink":["1"],"EventSink":["1"],"StreamConsumer":["1"],"Sink":["1"]},"ErrorResult":{"Result":["Null"]},"ValueResult":{"Result":["1"]},"_CompleterStream":{"Stream":["1"],"Stream.T":"1"},"StreamGroup":{"Sink":["Stream<1>"]},"_NextRequest":{"_EventRequest":["1"]},"_RestRequest":{"_EventRequest":["1"]},"_CompleterSink":{"StreamSink":["1"],"EventSink":["1"],"StreamConsumer":["1"],"Sink":["1"]},"SubscriptionStream":{"Stream":["1"],"Stream.T":"1"},"_CancelOnErrorSubscriptionWrapper":{"DelegatingStreamSubscription":["1"],"StreamSubscription":["1"]},"All":{"BooleanSelector":[]},"VariableNode":{"Node":[]},"NotNode":{"Node":[]},"OrNode":{"Node":[]},"AndNode":{"Node":[]},"ConditionalNode":{"Node":[]},"Evaluator":{"Visitor":["bool"]},"BooleanSelectorImpl":{"BooleanSelector":[]},"IntersectionSelector":{"BooleanSelector":[]},"None":{"BooleanSelector":[]},"IdentifierToken":{"Token":[]},"Validator":{"Visitor":["@"]},"RecursiveVisitor":{"Visitor":["@"]},"EmptyUnmodifiableSet":{"Set":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"],"Iterable.E":"1"},"QueueList":{"ListMixin":["1"],"Queue":["1"],"List":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"],"ListMixin.E":"1"},"UnionSet":{"UnmodifiableSetMixin":["1"],"SetMixin":["1"],"Set":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"UnmodifiableSetView":{"_UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin":["1"],"DelegatingSet":["1"],"UnmodifiableSetMixin":["1"],"DelegatingIterable":["1"],"Set":["1"],"_DelegatingIterableBase":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"_DelegatingIterableBase":{"Iterable":["1"]},"DelegatingIterable":{"_DelegatingIterableBase":["1"],"Iterable":["1"]},"DelegatingSet":{"DelegatingIterable":["1"],"Set":["1"],"_DelegatingIterableBase":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"_IsTrue":{"Matcher":[]},"_Predicate":{"FeatureMatcher":["1"],"TypeMatcher":["1"],"Matcher":[],"TypeMatcher.T":"1","FeatureMatcher.T":"1"},"StringDescription":{"Description":[]},"_StringEqualsMatcher":{"FeatureMatcher":["String"],"TypeMatcher":["String"],"Matcher":[],"TypeMatcher.T":"String","FeatureMatcher.T":"String"},"_DeepMatcher":{"Matcher":[]},"FeatureMatcher":{"TypeMatcher":["1"],"Matcher":[]},"TypeMatcher":{"Matcher":[],"TypeMatcher.T":"1"},"PackageConfigResolver":{"SyncPackageResolver":[]},"PackageRootResolver":{"SyncPackageResolver":[]},"PathException":{"Exception":[]},"PosixStyle":{"InternalStyle":[]},"UrlStyle":{"InternalStyle":[]},"WindowsStyle":{"InternalStyle":[]},"MultiSectionMapping":{"Mapping":[]},"MappingBundle":{"Mapping":[]},"SingleMapping":{"Mapping":[]},"_MappingTokenizer":{"Iterator":["String"]},"SourceMapSpan":{"SourceSpan":[]},"FileLocation":{"SourceLocation":[]},"_FileSpan":{"FileSpan":[],"SourceSpanWithContext":[],"SourceSpan":[]},"SourceLocationMixin":{"SourceLocation":[]},"SourceSpanBase":{"SourceSpan":[]},"SourceSpanException":{"Exception":[]},"SourceSpanFormatException":{"FormatException":[],"Exception":[]},"SourceSpanMixin":{"SourceSpan":[]},"SourceSpanWithContext":{"SourceSpan":[]},"Chain":{"StackTrace":[]},"LazyChain":{"Chain":[],"StackTrace":[]},"LazyTrace":{"Trace":[],"StackTrace":[]},"Trace":{"StackTrace":[]},"UnparsedFrame":{"Frame":[]},"GuaranteeChannel":{"StreamChannelMixin":["1"],"StreamChannel":["1"]},"_GuaranteeSink":{"StreamSink":["1"],"EventSink":["1"],"StreamConsumer":["1"],"Sink":["1"]},"_MultiChannel":{"StreamChannelMixin":["1"],"MultiChannel":["1"],"StreamChannel":["1"]},"VirtualChannel":{"StreamChannelMixin":["1"],"MultiChannel":["1"],"StreamChannel":["1"]},"_StreamChannel":{"StreamChannelMixin":["1"],"StreamChannel":["1"]},"StreamChannelMixin":{"StreamChannel":["1"]},"StringScannerException":{"FormatException":[],"Exception":[]},"_SpanScannerState":{"LineScannerState":[]},"ClosedException":{"Exception":[]},"Group":{"GroupEntry":[]},"LocalTest":{"Test":[],"GroupEntry":[]},"_LiveTest":{"LiveTest":[]},"Test":{"GroupEntry":[]},"IterableSet":{"SetMixin":["1"],"UnmodifiableSetMixin":["1"],"Set":["1"],"EfficientLengthIterable":["1"],"Iterable":["1"]},"_LiveSuite":{"LiveSuite":[]},"RunnerSuite":{"Suite":[]},"PrintSink":{"StringSink":[]},"JSStackTraceMapper":{"StackTraceMapper":[]}}'));
+ H._Universe_addErasedTypes(init.typeUniverse, JSON.parse('{"UnmodifiableListBase":1,"StreamTransformerBase":2,"IterableBase":1,"ListBase":1,"MapBase":2,"SetBase":1,"_ListBase_Object_ListMixin":1,"_SetBase_Object_SetMixin":1,"_QueueList_Object_ListMixin":1,"_UnionSet_SetBase_UnmodifiableSetMixin":1,"_IterableSet_SetMixin_UnmodifiableSetMixin":1}'));
+ var type$ = (function rtii() {
+ var findType = H.findType;
+ return {
+ A_Function_2_B_and_C_Function_A_and_B_and_C_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function_2_B_and_C: findType("0^(1^,2^)(Zone,ZoneDelegate,Zone,0^(1^,2^))<Object,Object,Object>"),
+ A_Function_A_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function: findType("0^(Zone,ZoneDelegate,Zone,0^())<Object>"),
+ A_Function_A_and_B_5_Zone_and_ZoneDelegate_and_Zone_and_A_Function_B_and_B: findType("0^(Zone,ZoneDelegate,Zone,0^(1^),1^)<Object,Object>"),
+ A_Function_A_and_B_and_C_6_Zone_and_ZoneDelegate_and_Zone_and_A_Function_2_B_and_C_and_B_and_C: findType("0^(Zone,ZoneDelegate,Zone,0^(1^,2^),1^,2^)<Object,Object,Object>"),
+ A_Function_B_Function_A_and_B_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function_B: findType("0^(1^)(Zone,ZoneDelegate,Zone,0^(1^))<Object,Object>"),
+ A_Function_Function_A_4_Zone_and_ZoneDelegate_and_Zone_and_A_Function: findType("0^()(Zone,ZoneDelegate,Zone,0^())<Object>"),
+ AsyncError: findType("AsyncError"),
+ AsyncMemoizer_dynamic: findType("AsyncMemoizer<@>"),
+ Blob: findType("Blob"),
+ BooleanSelector: findType("BooleanSelector"),
+ Chain: findType("Chain"),
+ CodeUnits: findType("CodeUnits"),
+ Completer_PoolResource: findType("Completer<PoolResource>"),
+ Declarer: findType("Declarer"),
+ Duration: findType("Duration"),
+ EfficientLengthIterable_dynamic: findType("EfficientLengthIterable<@>"),
+ Error: findType("Error"),
+ Event: findType("Event"),
+ Exception: findType("Exception"),
+ Expando__Node: findType("Expando<_Node>"),
+ File: findType("File"),
+ FileSpan: findType("FileSpan"),
+ FormatException: findType("FormatException"),
+ Frame: findType("Frame"),
+ Frame_Function_Frame: findType("Frame(Frame)"),
+ Frame_Function_String: findType("Frame(String)"),
+ Function: findType("Function"),
+ FutureGroup_dynamic: findType("FutureGroup<@>"),
+ FutureOr_void_Function: findType("~/()"),
+ Future_Null: findType("Future<Null>"),
+ Future_RunnerSuite: findType("Future<RunnerSuite>"),
+ Future_bool: findType("Future<bool>"),
+ Future_dynamic: findType("Future<@>"),
+ Future_void: findType("Future<~>"),
+ Group: findType("Group"),
+ GroupEntry: findType("GroupEntry"),
+ GroupEntry_Function_GroupEntry: findType("GroupEntry(GroupEntry)"),
+ IdentifierToken: findType("IdentifierToken"),
+ Invoker: findType("Invoker"),
+ IterableSet_LiveTest: findType("IterableSet<LiveTest>"),
+ Iterable_Group: findType("Iterable<Group>"),
+ Iterable_String: findType("Iterable<String>"),
+ Iterable_dynamic: findType("Iterable<@>"),
+ Iterator_Match: findType("Iterator<Match>"),
+ JSArray_AsyncError: findType("JSArray<AsyncError>"),
+ JSArray_Declarer: findType("JSArray<Declarer>"),
+ JSArray_Frame: findType("JSArray<Frame>"),
+ JSArray_Future_dynamic: findType("JSArray<Future<@>>"),
+ JSArray_Group: findType("JSArray<Group>"),
+ JSArray_GroupEntry: findType("JSArray<GroupEntry>"),
+ JSArray_Mapping: findType("JSArray<Mapping>"),
+ JSArray_Set_LiveTest: findType("JSArray<Set<LiveTest>>"),
+ JSArray_SourceFile: findType("JSArray<SourceFile>"),
+ JSArray_String: findType("JSArray<String>"),
+ JSArray_TargetEntry: findType("JSArray<TargetEntry>"),
+ JSArray_TargetLineEntry: findType("JSArray<TargetLineEntry>"),
+ JSArray_Trace: findType("JSArray<Trace>"),
+ JSArray_Zone: findType("JSArray<Zone>"),
+ JSArray_dynamic: findType("JSArray<@>"),
+ JSArray_int: findType("JSArray<int>"),
+ JSArray_of_dynamic_Function: findType("JSArray<@()>"),
+ JSObject: findType("JSObject"),
+ JavaScriptFunction: findType("JavaScriptFunction"),
+ JavaScriptIndexingBehavior_dynamic: findType("JavaScriptIndexingBehavior<@>"),
+ JsLinkedHashMap_of_Stream_LiveTest_and_StreamSubscription_LiveTest: findType("JsLinkedHashMap<Stream<LiveTest>,StreamSubscription<LiveTest>>"),
+ List_Group: findType("List<Group>"),
+ List_Object: findType("List<Object>"),
+ List_String: findType("List<String>"),
+ List_String_Function_dynamic_dynamic_String_int: findType("List<String>(@,@,String,int)"),
+ List_dynamic: findType("List<@>"),
+ List_int: findType("List<int>"),
+ LiveSuite: findType("LiveSuite"),
+ LiveTest: findType("LiveTest"),
+ MapEntry_BooleanSelector_Metadata: findType("MapEntry<BooleanSelector,Metadata>"),
+ MapEntry_String_Uri: findType("MapEntry<String,Uri>"),
+ MapEntry_of_String_and_Map_String_dynamic: findType("MapEntry<String,Map<String,@>>"),
+ Map_BooleanSelector_Metadata: findType("Map<BooleanSelector,Metadata>"),
+ Map_PlatformSelector_Metadata: findType("Map<PlatformSelector,Metadata>"),
+ Map_String_SourceFile: findType("Map<String,SourceFile>"),
+ Map_String_dynamic: findType("Map<String,@>"),
+ Map_dynamic_dynamic: findType("Map<@,@>"),
+ MappedIterable_String_Frame: findType("MappedIterable<String,Frame>"),
+ MappedListIterable_Frame_Frame: findType("MappedListIterable<Frame,Frame>"),
+ MappedListIterable_String_String: findType("MappedListIterable<String,String>"),
+ MappedListIterable_String_Trace: findType("MappedListIterable<String,Trace>"),
+ MappedListIterable_String_dynamic: findType("MappedListIterable<String,@>"),
+ Message: findType("Message"),
+ MessageEvent: findType("MessageEvent"),
+ MessagePort: findType("MessagePort"),
+ Metadata: findType("Metadata"),
+ NativeByteBuffer: findType("NativeByteBuffer"),
+ NativeTypedData: findType("NativeTypedData"),
+ NativeUint8List: findType("NativeUint8List"),
+ NoSuchMethodError: findType("NoSuchMethodError"),
+ Null: findType("Null"),
+ Null_Function: findType("Null()"),
+ Object: findType("Object"),
+ OperatingSystem: findType("OperatingSystem"),
+ Pattern: findType("Pattern"),
+ PlatformSelector: findType("PlatformSelector"),
+ RegExp: findType("RegExp"),
+ Result_dynamic: findType("Result<@>"),
+ ReversedListIterable_Declarer: findType("ReversedListIterable<Declarer>"),
+ RunnerSuite: findType("RunnerSuite"),
+ Runtime: findType("Runtime"),
+ Set_LiveTest: findType("Set<LiveTest>"),
+ Set_String: findType("Set<String>"),
+ Set_dynamic: findType("Set<@>"),
+ SingleMapping: findType("SingleMapping"),
+ SourceLocation: findType("SourceLocation"),
+ SourceSpan: findType("SourceSpan"),
+ SourceSpanWithContext: findType("SourceSpanWithContext"),
+ StackTrace: findType("StackTrace"),
+ StackTraceFormatter: findType("StackTraceFormatter"),
+ StackZoneSpecification: findType("StackZoneSpecification"),
+ State: findType("State"),
+ StreamChannelCompleter_dynamic: findType("StreamChannelCompleter<@>"),
+ StreamChannel_dynamic: findType("StreamChannel<@>"),
+ StreamCompleter_dynamic: findType("StreamCompleter<@>"),
+ StreamGroup_LiveTest: findType("StreamGroup<LiveTest>"),
+ StreamQueue_dynamic: findType("StreamQueue<@>"),
+ StreamSinkCompleter_dynamic: findType("StreamSinkCompleter<@>"),
+ StreamSubscription_dynamic: findType("StreamSubscription<@>"),
+ String: findType("String"),
+ String_Function_Match: findType("String(Match)"),
+ String_Function_String: findType("String(String)"),
+ SuiteChannelManager: findType("SuiteChannelManager"),
+ Test: findType("Test"),
+ Timer: findType("Timer"),
+ Trace: findType("Trace"),
+ Trace_Function_String: findType("Trace(String)"),
+ Type: findType("Type"),
+ Uint8List: findType("Uint8List"),
+ UnionSet_LiveTest: findType("UnionSet<LiveTest>"),
+ UnknownJavaScriptObject: findType("UnknownJavaScriptObject"),
+ UnmodifiableListView_LiveTest: findType("UnmodifiableListView<LiveTest>"),
+ UnmodifiableMapView_BooleanSelector_Metadata: findType("UnmodifiableMapView<BooleanSelector,Metadata>"),
+ UnmodifiableMapView_PlatformSelector_Metadata: findType("UnmodifiableMapView<PlatformSelector,Metadata>"),
+ UnmodifiableMapView_String_Uri: findType("UnmodifiableMapView<String,Uri>"),
+ UnmodifiableSetView_LiveTest: findType("UnmodifiableSetView<LiveTest>"),
+ UnmodifiableSetView_String: findType("UnmodifiableSetView<String>"),
+ Uri: findType("Uri"),
+ WhereIterable_String: findType("WhereIterable<String>"),
+ Zone: findType("Zone"),
+ ZoneDelegate: findType("ZoneDelegate"),
+ ZoneSpecification: findType("ZoneSpecification"),
+ _AsyncBroadcastStreamController_LiveSuite: findType("_AsyncBroadcastStreamController<LiveSuite>"),
+ _AsyncBroadcastStreamController_RunnerSuite: findType("_AsyncBroadcastStreamController<RunnerSuite>"),
+ _AsyncBroadcastStreamController_bool: findType("_AsyncBroadcastStreamController<bool>"),
+ _AsyncCompleter_List_dynamic: findType("_AsyncCompleter<List<@>>"),
+ _AsyncCompleter_PoolResource: findType("_AsyncCompleter<PoolResource>"),
+ _AsyncCompleter_dynamic: findType("_AsyncCompleter<@>"),
+ _AsyncCompleter_void: findType("_AsyncCompleter<~>"),
+ _AsyncCounter: findType("_AsyncCounter"),
+ _CompleterSink_dynamic: findType("_CompleterSink<@>"),
+ _CompleterStream_dynamic: findType("_CompleterStream<@>"),
+ _DelayedEvent_dynamic: findType("_DelayedEvent<@>"),
+ _EventRequest_dynamic: findType("_EventRequest<@>"),
+ _EventStream_MessageEvent: findType("_EventStream<MessageEvent>"),
+ _FutureListener_dynamic_dynamic: findType("_FutureListener<@,@>"),
+ _Future_List_dynamic: findType("_Future<List<@>>"),
+ _Future_PoolResource: findType("_Future<PoolResource>"),
+ _Future_RunnerSuite: findType("_Future<RunnerSuite>"),
+ _Future_dynamic: findType("_Future<@>"),
+ _Future_int: findType("_Future<int>"),
+ _Future_void: findType("_Future<~>"),
+ _IdentityHashMap_dynamic_dynamic: findType("_IdentityHashMap<@,@>"),
+ _LinkedHashSetCell: findType("_LinkedHashSetCell"),
+ _Node: findType("_Node"),
+ _Predicate_Object: findType("_Predicate<Object>"),
+ _Predicate_dynamic: findType("_Predicate<@>"),
+ _RestRequest_dynamic: findType("_RestRequest<@>"),
+ _StreamChannel_dynamic: findType("_StreamChannel<@>"),
+ _SyncBroadcastStreamController_AsyncError: findType("_SyncBroadcastStreamController<AsyncError>"),
+ _SyncBroadcastStreamController_LiveTest: findType("_SyncBroadcastStreamController<LiveTest>"),
+ _SyncBroadcastStreamController_Message: findType("_SyncBroadcastStreamController<Message>"),
+ _SyncBroadcastStreamController_State: findType("_SyncBroadcastStreamController<State>"),
+ _SyncCompleter_PoolResource: findType("_SyncCompleter<PoolResource>"),
+ _SyncCompleter_dynamic: findType("_SyncCompleter<@>"),
+ _ZoneFunction_Function: findType("_ZoneFunction<Function>"),
+ _ZoneFunction_of_AsyncError_Function_Zone_ZoneDelegate_Zone_Object_StackTrace: findType("_ZoneFunction<AsyncError(Zone,ZoneDelegate,Zone,Object,StackTrace)>"),
+ _ZoneFunction_of_Timer_Function_5_Zone_and_ZoneDelegate_and_Zone_and_Duration_and_void_Function: findType("_ZoneFunction<Timer(Zone,ZoneDelegate,Zone,Duration,~())>"),
+ _ZoneFunction_of_Timer_Function_5_Zone_and_ZoneDelegate_and_Zone_and_Duration_and_void_Function_Timer: findType("_ZoneFunction<Timer(Zone,ZoneDelegate,Zone,Duration,~(Timer))>"),
+ _ZoneFunction_of_Zone_Function_5_Zone_and_ZoneDelegate_and_Zone_and_ZoneSpecification_and_Map_dynamic_dynamic: findType("_ZoneFunction<Zone(Zone,ZoneDelegate,Zone,ZoneSpecification,Map<@,@>)>"),
+ _ZoneFunction_of_void_Function_4_Zone_and_ZoneDelegate_and_Zone_and_void_Function: findType("_ZoneFunction<~(Zone,ZoneDelegate,Zone,~())>"),
+ _ZoneFunction_of_void_Function_Zone_ZoneDelegate_Zone_Object_StackTrace: findType("_ZoneFunction<~(Zone,ZoneDelegate,Zone,Object,StackTrace)>"),
+ _ZoneFunction_of_void_Function_Zone_ZoneDelegate_Zone_String: findType("_ZoneFunction<~(Zone,ZoneDelegate,Zone,String)>"),
+ bool: findType("bool"),
+ bool_Function_Frame: findType("bool(Frame)"),
+ bool_Function_Null: findType("bool(Null)"),
+ bool_Function_Object: findType("bool(Object)"),
+ bool_Function_String: findType("bool(String)"),
+ bool_Function_dynamic: findType("bool(@)"),
+ dynamic: findType("@"),
+ dynamic_Function: findType("@()"),
+ dynamic_Function_Event: findType("@(Event)"),
+ dynamic_Function_Object: findType("@(Object)"),
+ dynamic_Function_Object_Object: findType("@(Object,Object)"),
+ dynamic_Function_Object_StackTrace: findType("@(Object,StackTrace)"),
+ dynamic_Function_String: findType("@(String)"),
+ dynamic_Function_dynamic_dynamic: findType("@(@,@)"),
+ int: findType("int"),
+ num: findType("num"),
+ void: findType("~"),
+ void_Function: findType("~()"),
+ void_Function_MessageEvent: findType("~(MessageEvent)"),
+ void_Function_Object: findType("~(Object)"),
+ void_Function_Object_StackTrace: findType("~(Object,StackTrace)"),
+ void_Function_String_dynamic: findType("~(String,@)"),
+ void_Function_Timer: findType("~(Timer)")
+ };
+ })();
+ (function constants() {
+ var makeConstList = hunkHelpers.makeConstList;
+ C.Interceptor_methods = J.Interceptor.prototype;
+ C.JSArray_methods = J.JSArray.prototype;
+ C.JSInt_methods = J.JSInt.prototype;
+ C.JSNumber_methods = J.JSNumber.prototype;
+ C.JSString_methods = J.JSString.prototype;
+ C.JavaScriptFunction_methods = J.JavaScriptFunction.prototype;
+ C.Location_methods = W.Location.prototype;
+ C.MessagePort_methods = W.MessagePort.prototype;
+ C.NativeUint32List_methods = H.NativeUint32List.prototype;
+ C.NativeUint8List_methods = H.NativeUint8List.prototype;
+ C.PlainJavaScriptObject_methods = J.PlainJavaScriptObject.prototype;
+ C.UnknownJavaScriptObject_methods = J.UnknownJavaScriptObject.prototype;
+ C.AsciiEncoder_127 = new P.AsciiEncoder(127);
+ C.List_empty = H.setRuntimeTypeInfo(makeConstList([]), type$.JSArray_String);
+ C.C_All = new X.All();
+ C.C_AsciiCodec = new P.AsciiCodec();
+ C.C_AsciiGlyphSet = new A.AsciiGlyphSet();
+ C.C_Base64Encoder = new P.Base64Encoder();
+ C.C_Base64Codec = new P.Base64Codec();
+ C.C_EmptyIterator = new H.EmptyIterator(H.findType("EmptyIterator<Null>"));
+ C.C_EmptyUnmodifiableSet = new O.EmptyUnmodifiableSet(H.findType("EmptyUnmodifiableSet<String>"));
+ C.C_JS_CONST = function getTagFallback(o) {
+ var s = Object.prototype.toString.call(o);
+ return s.substring(8, s.length - 1);
+};
+ C.C_JS_CONST0 = function() {
+ var toStringFunction = Object.prototype.toString;
+ function getTag(o) {
+ var s = toStringFunction.call(o);
+ return s.substring(8, s.length - 1);
+ }
+ function getUnknownTag(object, tag) {
+ if (/^HTML[A-Z].*Element$/.test(tag)) {
+ var name = toStringFunction.call(object);
+ if (name == "[object Object]") return null;
+ return "HTMLElement";
+ }
+ }
+ function getUnknownTagGenericBrowser(object, tag) {
+ if (self.HTMLElement && object instanceof HTMLElement) return "HTMLElement";
+ return getUnknownTag(object, tag);
+ }
+ function prototypeForTag(tag) {
+ if (typeof window == "undefined") return null;
+ if (typeof window[tag] == "undefined") return null;
+ var constructor = window[tag];
+ if (typeof constructor != "function") return null;
+ return constructor.prototype;
+ }
+ function discriminator(tag) { return null; }
+ var isBrowser = typeof navigator == "object";
+ return {
+ getTag: getTag,
+ getUnknownTag: isBrowser ? getUnknownTagGenericBrowser : getUnknownTag,
+ prototypeForTag: prototypeForTag,
+ discriminator: discriminator };
+};
+ C.C_JS_CONST6 = function(getTagFallback) {
+ return function(hooks) {
+ if (typeof navigator != "object") return hooks;
+ var ua = navigator.userAgent;
+ if (ua.indexOf("DumpRenderTree") >= 0) return hooks;
+ if (ua.indexOf("Chrome") >= 0) {
+ function confirm(p) {
+ return typeof window == "object" && window[p] && window[p].name == p;
+ }
+ if (confirm("Window") && confirm("HTMLElement")) return hooks;
+ }
+ hooks.getTag = getTagFallback;
+ };
+};
+ C.C_JS_CONST1 = function(hooks) {
+ if (typeof dartExperimentalFixupGetTag != "function") return hooks;
+ hooks.getTag = dartExperimentalFixupGetTag(hooks.getTag);
+};
+ C.C_JS_CONST2 = function(hooks) {
+ var getTag = hooks.getTag;
+ var prototypeForTag = hooks.prototypeForTag;
+ function getTagFixed(o) {
+ var tag = getTag(o);
+ if (tag == "Document") {
+ if (!!o.xmlVersion) return "!Document";
+ return "!HTMLDocument";
+ }
+ return tag;
+ }
+ function prototypeForTagFixed(tag) {
+ if (tag == "Document") return null;
+ return prototypeForTag(tag);
+ }
+ hooks.getTag = getTagFixed;
+ hooks.prototypeForTag = prototypeForTagFixed;
+};
+ C.C_JS_CONST5 = function(hooks) {
+ var userAgent = typeof navigator == "object" ? navigator.userAgent : "";
+ if (userAgent.indexOf("Firefox") == -1) return hooks;
+ var getTag = hooks.getTag;
+ var quickMap = {
+ "BeforeUnloadEvent": "Event",
+ "DataTransfer": "Clipboard",
+ "GeoGeolocation": "Geolocation",
+ "Location": "!Location",
+ "WorkerMessageEvent": "MessageEvent",
+ "XMLDocument": "!Document"};
+ function getTagFirefox(o) {
+ var tag = getTag(o);
+ return quickMap[tag] || tag;
+ }
+ hooks.getTag = getTagFirefox;
+};
+ C.C_JS_CONST4 = function(hooks) {
+ var userAgent = typeof navigator == "object" ? navigator.userAgent : "";
+ if (userAgent.indexOf("Trident/") == -1) return hooks;
+ var getTag = hooks.getTag;
+ var quickMap = {
+ "BeforeUnloadEvent": "Event",
+ "DataTransfer": "Clipboard",
+ "HTMLDDElement": "HTMLElement",
+ "HTMLDTElement": "HTMLElement",
+ "HTMLPhraseElement": "HTMLElement",
+ "Position": "Geoposition"
+ };
+ function getTagIE(o) {
+ var tag = getTag(o);
+ var newTag = quickMap[tag];
+ if (newTag) return newTag;
+ if (tag == "Object") {
+ if (window.DataView && (o instanceof window.DataView)) return "DataView";
+ }
+ return tag;
+ }
+ function prototypeForTagIE(tag) {
+ var constructor = window[tag];
+ if (constructor == null) return null;
+ return constructor.prototype;
+ }
+ hooks.getTag = getTagIE;
+ hooks.prototypeForTag = prototypeForTagIE;
+};
+ C.C_JS_CONST3 = function(hooks) { return hooks; }
+;
+ C.C_JsonCodec = new P.JsonCodec();
+ C.C_None = new O.None();
+ C.C_OutOfMemoryError = new P.OutOfMemoryError();
+ C.C_UnicodeGlyphSet = new K.UnicodeGlyphSet();
+ C.C_Utf8Codec = new P.Utf8Codec();
+ C.C_Utf8Encoder = new P.Utf8Encoder();
+ C.C__DelayedDone = new P._DelayedDone();
+ C.C__IsTrue = new Y._IsTrue();
+ C.C__RootZone = new P._RootZone();
+ C.Duration_0 = new P.Duration(0);
+ C.Duration_30000000 = new P.Duration(30000000);
+ C.JsonDecoder_null = new P.JsonDecoder(null);
+ C.List_127_2047_65535_1114111 = H.setRuntimeTypeInfo(makeConstList([127, 2047, 65535, 1114111]), type$.JSArray_int);
+ C.List_2Vk = H.setRuntimeTypeInfo(makeConstList([0, 0, 32776, 33792, 1, 10240, 0, 0]), type$.JSArray_int);
+ C.List_CVk = H.setRuntimeTypeInfo(makeConstList([0, 0, 65490, 45055, 65535, 34815, 65534, 18431]), type$.JSArray_int);
+ C.List_JYB = H.setRuntimeTypeInfo(makeConstList([0, 0, 26624, 1023, 65534, 2047, 65534, 2047]), type$.JSArray_int);
+ C.List_empty1 = H.setRuntimeTypeInfo(makeConstList([]), H.findType("JSArray<Null>"));
+ C.List_empty0 = H.setRuntimeTypeInfo(makeConstList([]), type$.JSArray_dynamic);
+ C.List_gRj = H.setRuntimeTypeInfo(makeConstList([0, 0, 32722, 12287, 65534, 34815, 65534, 18431]), type$.JSArray_int);
+ C.Runtime_ql0 = new B.Runtime("VM", "vm", null, true, false, false, false, false);
+ C.Runtime_4e8 = new B.Runtime("Chrome", "chrome", null, false, true, true, true, false);
+ C.Runtime_IBZ = new B.Runtime("PhantomJS", "phantomjs", null, false, true, true, true, true);
+ C.Runtime_8Rg = new B.Runtime("Firefox", "firefox", null, false, true, true, false, false);
+ C.Runtime_ivT = new B.Runtime("Safari", "safari", null, false, true, true, false, false);
+ C.Runtime_Mzn = new B.Runtime("Internet Explorer", "ie", null, false, true, true, false, false);
+ C.Runtime_R5O = new B.Runtime("Node.js", "node", null, false, false, true, false, false);
+ C.List_m7e = H.setRuntimeTypeInfo(makeConstList([C.Runtime_ql0, C.Runtime_4e8, C.Runtime_IBZ, C.Runtime_8Rg, C.Runtime_ivT, C.Runtime_Mzn, C.Runtime_R5O]), H.findType("JSArray<Runtime>"));
+ C.List_nxB = H.setRuntimeTypeInfo(makeConstList([0, 0, 24576, 1023, 65534, 34815, 65534, 18431]), type$.JSArray_int);
+ C.OperatingSystem_Windows_windows = new N.OperatingSystem("Windows", "windows");
+ C.OperatingSystem_RkP = new N.OperatingSystem("OS X", "mac-os");
+ C.OperatingSystem_Linux_linux = new N.OperatingSystem("Linux", "linux");
+ C.OperatingSystem_Android_android = new N.OperatingSystem("Android", "android");
+ C.OperatingSystem_iOS_ios = new N.OperatingSystem("iOS", "ios");
+ C.List_opx = H.setRuntimeTypeInfo(makeConstList([C.OperatingSystem_Windows_windows, C.OperatingSystem_RkP, C.OperatingSystem_Linux_linux, C.OperatingSystem_Android_android, C.OperatingSystem_iOS_ios]), H.findType("JSArray<OperatingSystem>"));
+ C.List_qFt = H.setRuntimeTypeInfo(makeConstList([0, 0, 27858, 1023, 65534, 51199, 65535, 32767]), type$.JSArray_int);
+ C.List_qNA = H.setRuntimeTypeInfo(makeConstList([0, 0, 32754, 11263, 65534, 34815, 65534, 18431]), type$.JSArray_int);
+ C.List_qg40 = H.setRuntimeTypeInfo(makeConstList([0, 0, 32722, 12287, 65535, 34815, 65534, 18431]), type$.JSArray_int);
+ C.List_qg4 = H.setRuntimeTypeInfo(makeConstList([0, 0, 65490, 12287, 65535, 34815, 65534, 18431]), type$.JSArray_int);
+ C.List_F9h = H.setRuntimeTypeInfo(makeConstList(["\n", "\r", "\f", "\b", "\t", "\v", "\x7f"]), type$.JSArray_String);
+ C.Map_F9GZw = new H.ConstantStringMap(7, {"\n": "\\n", "\r": "\\r", "\f": "\\f", "\b": "\\b", "\t": "\\t", "\v": "\\v", "\x7f": "\\x7F"}, C.List_F9h, H.findType("ConstantStringMap<String,String>"));
+ C.List_empty2 = H.setRuntimeTypeInfo(makeConstList([]), H.findType("JSArray<BooleanSelector>"));
+ C.Map_empty0 = new H.ConstantStringMap(0, {}, C.List_empty2, H.findType("ConstantStringMap<BooleanSelector,Metadata>"));
+ C.Map_empty1 = new H.ConstantStringMap(0, {}, C.List_empty1, H.findType("ConstantStringMap<Null,Null>"));
+ C.List_empty3 = H.setRuntimeTypeInfo(makeConstList([]), H.findType("JSArray<PlatformSelector>"));
+ C.Map_empty = new H.ConstantStringMap(0, {}, C.List_empty3, H.findType("ConstantStringMap<PlatformSelector,Metadata>"));
+ C.MessageType_print = new D.MessageType("print");
+ C.MessageType_skip = new D.MessageType("skip");
+ C.OperatingSystem_none_none = new N.OperatingSystem("none", "none");
+ C.PlatformSelector_All = new E.PlatformSelector(C.C_All);
+ C.Result_error = new G.Result0("error");
+ C.Result_skipped = new G.Result0("skipped");
+ C.Result_success = new G.Result0("success");
+ C.Status_complete = new G.Status("complete");
+ C.State_Status_complete_Result_error = new G.State(C.Status_complete, C.Result_error);
+ C.Result_failure = new G.Result0("failure");
+ C.State_Status_complete_Result_failure = new G.State(C.Status_complete, C.Result_failure);
+ C.State_Status_complete_Result_skipped = new G.State(C.Status_complete, C.Result_skipped);
+ C.Status_pending = new G.Status("pending");
+ C.State_Status_pending_Result_success = new G.State(C.Status_pending, C.Result_success);
+ C.Status_running = new G.Status("running");
+ C.State_Status_running_Result_skipped = new G.State(C.Status_running, C.Result_skipped);
+ C.State_Status_running_Result_success = new G.State(C.Status_running, C.Result_success);
+ C.Symbol_Drw = new H.Symbol("test.declarer");
+ C.Symbol_MAi = new H.Symbol("test.runner.test_channel");
+ C.Symbol_cQL = new H.Symbol("test.invoker");
+ C.Symbol_runCount = new H.Symbol("runCount");
+ C.Timeout_null_1 = new R.Timeout(null, 1);
+ C.Timeout_null_null = new R.Timeout(null, null);
+ C.TokenType_31K = new L.TokenType("right paren");
+ C.TokenType_69P = new L.TokenType("question mark");
+ C.TokenType_and = new L.TokenType("and");
+ C.TokenType_colon = new L.TokenType("colon");
+ C.TokenType_e7P = new L.TokenType("left paren");
+ C.TokenType_identifier = new L.TokenType("identifier");
+ C.TokenType_not = new L.TokenType("not");
+ C.TokenType_or = new L.TokenType("or");
+ C.TokenType_wwi = new L.TokenType("end of file");
+ C.Type_ByteBuffer_RkP = H.typeLiteral("ByteBuffer");
+ C.Type_ByteData_zNC = H.typeLiteral("ByteData");
+ C.Type_Float32List_LB7 = H.typeLiteral("Float32List");
+ C.Type_Float64List_LB7 = H.typeLiteral("Float64List");
+ C.Type_Int16List_uXf = H.typeLiteral("Int16List");
+ C.Type_Int32List_O50 = H.typeLiteral("Int32List");
+ C.Type_Int8List_ekJ = H.typeLiteral("Int8List");
+ C.Type_JSObject_8k0 = H.typeLiteral("JSObject");
+ C.Type_Null_Yyn = H.typeLiteral("Null");
+ C.Type_String_k8F = H.typeLiteral("String");
+ C.Type_Uint16List_2bx = H.typeLiteral("Uint16List");
+ C.Type_Uint32List_2bx = H.typeLiteral("Uint32List");
+ C.Type_Uint8ClampedList_Jik = H.typeLiteral("Uint8ClampedList");
+ C.Type_Uint8List_WLA = H.typeLiteral("Uint8List");
+ C.Type_bool_lhE = H.typeLiteral("bool");
+ C.Type_double_K1J = H.typeLiteral("double");
+ C.Type_int_tHn = H.typeLiteral("int");
+ C.Type_num_cv7 = H.typeLiteral("num");
+ C._PathDirection_8Gl = new M._PathDirection("at root");
+ C._PathDirection_988 = new M._PathDirection("below root");
+ C._PathDirection_FIw = new M._PathDirection("reaches root");
+ C._PathDirection_ZGD = new M._PathDirection("above root");
+ C._PathRelation_different = new M._PathRelation("different");
+ C._PathRelation_equal = new M._PathRelation("equal");
+ C._PathRelation_inconclusive = new M._PathRelation("inconclusive");
+ C._PathRelation_within = new M._PathRelation("within");
+ C._StreamGroupState_canceled = new L._StreamGroupState("canceled");
+ C._StreamGroupState_dormant = new L._StreamGroupState("dormant");
+ C._StreamGroupState_listening = new L._StreamGroupState("listening");
+ C._StreamGroupState_paused = new L._StreamGroupState("paused");
+ C._TokenKind_false_false_false = new T._TokenKind(false, false, false);
+ C._TokenKind_false_false_true = new T._TokenKind(false, false, true);
+ C._TokenKind_false_true_false = new T._TokenKind(false, true, false);
+ C._TokenKind_true_false_false = new T._TokenKind(true, false, false);
+ C._ZoneFunction_3bB = new P._ZoneFunction(C.C__RootZone, P.async___rootCreatePeriodicTimer$closure(), type$._ZoneFunction_of_Timer_Function_5_Zone_and_ZoneDelegate_and_Zone_and_Duration_and_void_Function_Timer);
+ C._ZoneFunction_7G2 = new P._ZoneFunction(C.C__RootZone, P.async___rootRegisterBinaryCallback$closure(), type$._ZoneFunction_Function);
+ C._ZoneFunction_Eeh = new P._ZoneFunction(C.C__RootZone, P.async___rootRegisterUnaryCallback$closure(), type$._ZoneFunction_Function);
+ C._ZoneFunction_NMc = new P._ZoneFunction(C.C__RootZone, P.async___rootHandleUncaughtError$closure(), type$._ZoneFunction_of_void_Function_Zone_ZoneDelegate_Zone_Object_StackTrace);
+ C._ZoneFunction__RootZone__rootCreateTimer = new P._ZoneFunction(C.C__RootZone, P.async___rootCreateTimer$closure(), type$._ZoneFunction_of_Timer_Function_5_Zone_and_ZoneDelegate_and_Zone_and_Duration_and_void_Function);
+ C._ZoneFunction__RootZone__rootErrorCallback = new P._ZoneFunction(C.C__RootZone, P.async___rootErrorCallback$closure(), type$._ZoneFunction_of_AsyncError_Function_Zone_ZoneDelegate_Zone_Object_StackTrace);
+ C._ZoneFunction__RootZone__rootFork = new P._ZoneFunction(C.C__RootZone, P.async___rootFork$closure(), type$._ZoneFunction_of_Zone_Function_5_Zone_and_ZoneDelegate_and_Zone_and_ZoneSpecification_and_Map_dynamic_dynamic);
+ C._ZoneFunction__RootZone__rootPrint = new P._ZoneFunction(C.C__RootZone, P.async___rootPrint$closure(), type$._ZoneFunction_of_void_Function_Zone_ZoneDelegate_Zone_String);
+ C._ZoneFunction__RootZone__rootRegisterCallback = new P._ZoneFunction(C.C__RootZone, P.async___rootRegisterCallback$closure(), type$._ZoneFunction_Function);
+ C._ZoneFunction__RootZone__rootRun = new P._ZoneFunction(C.C__RootZone, P.async___rootRun$closure(), type$._ZoneFunction_Function);
+ C._ZoneFunction__RootZone__rootRunBinary = new P._ZoneFunction(C.C__RootZone, P.async___rootRunBinary$closure(), type$._ZoneFunction_Function);
+ C._ZoneFunction__RootZone__rootRunUnary = new P._ZoneFunction(C.C__RootZone, P.async___rootRunUnary$closure(), type$._ZoneFunction_Function);
+ C._ZoneFunction__RootZone__rootScheduleMicrotask = new P._ZoneFunction(C.C__RootZone, P.async___rootScheduleMicrotask$closure(), type$._ZoneFunction_of_void_Function_4_Zone_and_ZoneDelegate_and_Zone_and_void_Function);
+ C._ZoneSpecification_ALf = new P._ZoneSpecification(null, null, null, null, null, null, null, null, null, null, null, null, null);
+ })();
+ (function staticFields() {
+ $.printToZone = null;
+ $.Primitives_timerFrequency = null;
+ $.Primitives_timerTicks = null;
+ $.Closure_functionCounter = 0;
+ $.BoundClosure_selfFieldNameCache = null;
+ $.BoundClosure_receiverFieldNameCache = null;
+ $.getTagFunction = null;
+ $.alternateTagFunction = null;
+ $.prototypeForTagFunction = null;
+ $.dispatchRecordsForInstanceTags = null;
+ $.interceptorsForUncacheableTags = null;
+ $.initNativeDispatchFlag = null;
+ $._nextCallback = null;
+ $._lastCallback = null;
+ $._lastPriorityCallback = null;
+ $._isInCallbackLoop = false;
+ $.Zone__current = C.C__RootZone;
+ $._RootZone__rootDelegate = null;
+ $._toStringVisiting = [];
+ $.Expando__keyCount = 0;
+ $.Stopwatch__frequency = null;
+ $._currentUriBase = null;
+ $._current = null;
+ $._glyphs = C.C_UnicodeGlyphSet;
+ $._macOSDirectories = P.LinkedHashSet_LinkedHashSet$_literal(["/Applications", "/Library", "/Network", "/System", "/Users"], type$.String);
+ $._globalDeclarer = null;
+ $.x = 0;
+ })();
+ (function lazyInitializers() {
+ var _lazy = hunkHelpers.lazy;
+ _lazy($, "DART_CLOSURE_PROPERTY_NAME", "$get$DART_CLOSURE_PROPERTY_NAME", function() {
+ return H.getIsolateAffinityTag("_$dart_dartClosure");
+ });
+ _lazy($, "JS_INTEROP_INTERCEPTOR_TAG", "$get$JS_INTEROP_INTERCEPTOR_TAG", function() {
+ return H.getIsolateAffinityTag("_$dart_js");
+ });
+ _lazy($, "TypeErrorDecoder_noSuchMethodPattern", "$get$TypeErrorDecoder_noSuchMethodPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(H.TypeErrorDecoder_provokeCallErrorOn({
+ toString: function() {
+ return "$receiver$";
+ }
+ }));
+ });
+ _lazy($, "TypeErrorDecoder_notClosurePattern", "$get$TypeErrorDecoder_notClosurePattern", function() {
+ return H.TypeErrorDecoder_extractPattern(H.TypeErrorDecoder_provokeCallErrorOn({$method$: null,
+ toString: function() {
+ return "$receiver$";
+ }
+ }));
+ });
+ _lazy($, "TypeErrorDecoder_nullCallPattern", "$get$TypeErrorDecoder_nullCallPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(H.TypeErrorDecoder_provokeCallErrorOn(null));
+ });
+ _lazy($, "TypeErrorDecoder_nullLiteralCallPattern", "$get$TypeErrorDecoder_nullLiteralCallPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(function() {
+ var $argumentsExpr$ = '$arguments$';
+ try {
+ null.$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+ }());
+ });
+ _lazy($, "TypeErrorDecoder_undefinedCallPattern", "$get$TypeErrorDecoder_undefinedCallPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(H.TypeErrorDecoder_provokeCallErrorOn(void 0));
+ });
+ _lazy($, "TypeErrorDecoder_undefinedLiteralCallPattern", "$get$TypeErrorDecoder_undefinedLiteralCallPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(function() {
+ var $argumentsExpr$ = '$arguments$';
+ try {
+ (void 0).$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+ }());
+ });
+ _lazy($, "TypeErrorDecoder_nullPropertyPattern", "$get$TypeErrorDecoder_nullPropertyPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(H.TypeErrorDecoder_provokePropertyErrorOn(null));
+ });
+ _lazy($, "TypeErrorDecoder_nullLiteralPropertyPattern", "$get$TypeErrorDecoder_nullLiteralPropertyPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(function() {
+ try {
+ null.$method$;
+ } catch (e) {
+ return e.message;
+ }
+ }());
+ });
+ _lazy($, "TypeErrorDecoder_undefinedPropertyPattern", "$get$TypeErrorDecoder_undefinedPropertyPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(H.TypeErrorDecoder_provokePropertyErrorOn(void 0));
+ });
+ _lazy($, "TypeErrorDecoder_undefinedLiteralPropertyPattern", "$get$TypeErrorDecoder_undefinedLiteralPropertyPattern", function() {
+ return H.TypeErrorDecoder_extractPattern(function() {
+ try {
+ (void 0).$method$;
+ } catch (e) {
+ return e.message;
+ }
+ }());
+ });
+ _lazy($, "_AsyncRun__scheduleImmediateClosure", "$get$_AsyncRun__scheduleImmediateClosure", function() {
+ return P._AsyncRun__initializeScheduleImmediate();
+ });
+ _lazy($, "Future__nullFuture", "$get$Future__nullFuture", function() {
+ return P._Future$zoneValue(null, C.C__RootZone, type$.Null);
+ });
+ _lazy($, "_RootZone__rootMap", "$get$_RootZone__rootMap", function() {
+ var t1 = type$.dynamic;
+ return P.HashMap_HashMap(t1, t1);
+ });
+ _lazy($, "Utf8Decoder__decoder", "$get$Utf8Decoder__decoder", function() {
+ return P.Utf8Decoder__makeDecoder();
+ });
+ _lazy($, "_Base64Decoder__inverseAlphabet", "$get$_Base64Decoder__inverseAlphabet", function() {
+ return H.NativeInt8List__create1(H._ensureNativeList(H.setRuntimeTypeInfo([-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -1, -2, -2, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63, -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2], type$.JSArray_int)));
+ });
+ _lazy($, "_Uri__isWindowsCached", "$get$_Uri__isWindowsCached", function() {
+ return typeof process != "undefined" && Object.prototype.toString.call(process) == "[object process]" && process.platform == "win32";
+ });
+ _lazy($, "_Uri__needsNoEncoding", "$get$_Uri__needsNoEncoding", function() {
+ return P.RegExp_RegExp("^[\\-\\.0-9A-Z_a-z~]*$", false);
+ });
+ _lazy($, "_hasErrorStackProperty", "$get$_hasErrorStackProperty", function() {
+ return new Error().stack != void 0;
+ });
+ _lazy($, "_scannerTables", "$get$_scannerTables", function() {
+ return P._createTables();
+ });
+ _lazy($, "_whitespaceAndSingleLineComments", "$get$_whitespaceAndSingleLineComments", function() {
+ return P.RegExp_RegExp("([ \\t\\n]+|//[^\\n]*(\\n|$))+", false);
+ });
+ _lazy($, "_multiLineCommentBody", "$get$_multiLineCommentBody", function() {
+ return P.RegExp_RegExp("([^/*]|/[^*]|\\*[^/])+", false);
+ });
+ _lazy($, "_hyphenatedIdentifier", "$get$_hyphenatedIdentifier0", function() {
+ return P.RegExp_RegExp("[a-zA-Z_-][a-zA-Z0-9_-]*", false);
+ });
+ _lazy($, "_dart2DynamicArgs", "$get$_dart2DynamicArgs", function() {
+ return P.RegExp_RegExp("<dynamic(, dynamic)*>", false);
+ });
+ _lazy($, "_escapeRegExp", "$get$_escapeRegExp", function() {
+ return P.RegExp_RegExp("[\\x00-\\x07\\x0E-\\x1F" + C.Map_F9GZw.get$keys().map$1$1(0, M.util___getHexLiteral$closure(), type$.String).join$0(0) + "]", false);
+ });
+ _lazy($, "windows", "$get$windows", function() {
+ return M.Context_Context($.$get$Style_windows());
+ });
+ _lazy($, "url", "$get$url", function() {
+ return M.Context_Context($.$get$Style_url());
+ });
+ _lazy($, "context", "$get$context", function() {
+ return new M.Context($.$get$Style_platform(), null);
+ });
+ _lazy($, "Style_posix", "$get$Style_posix", function() {
+ return new E.PosixStyle(P.RegExp_RegExp("/", false), P.RegExp_RegExp("[^/]$", false), P.RegExp_RegExp("^/", false));
+ });
+ _lazy($, "Style_windows", "$get$Style_windows", function() {
+ return new L.WindowsStyle(P.RegExp_RegExp("[/\\\\]", false), P.RegExp_RegExp("[^/\\\\]$", false), P.RegExp_RegExp("^(\\\\\\\\[^\\\\]+\\\\[^\\\\/]+|[a-zA-Z]:[/\\\\])", false), P.RegExp_RegExp("^[/\\\\](?![/\\\\])", false));
+ });
+ _lazy($, "Style_url", "$get$Style_url", function() {
+ return new F.UrlStyle(P.RegExp_RegExp("/", false), P.RegExp_RegExp("(^[a-zA-Z][-+.a-zA-Z\\d]*://|[^/])$", false), P.RegExp_RegExp("[a-zA-Z][-+.a-zA-Z\\d]*://[^/]*", false), P.RegExp_RegExp("^/", false));
+ });
+ _lazy($, "Style_platform", "$get$Style_platform", function() {
+ return O.Style__getPlatformStyle();
+ });
+ _lazy($, "_digits", "$get$_digits", function() {
+ return new L.closure().call$0();
+ });
+ _lazy($, "MAX_INT32", "$get$MAX_INT32", function() {
+ return H._checkIntNullable(P.pow(2, 31) - 1);
+ });
+ _lazy($, "MIN_INT32", "$get$MIN_INT32", function() {
+ return H._checkIntNullable(-P.pow(2, 31));
+ });
+ _lazy($, "_specKey", "$get$_specKey", function() {
+ return new P.Object();
+ });
+ _lazy($, "_vmFrame", "$get$_vmFrame", function() {
+ return P.RegExp_RegExp("^#\\d+\\s+(\\S.*) \\((.+?)((?::\\d+){0,2})\\)$", false);
+ });
+ _lazy($, "_v8Frame", "$get$_v8Frame", function() {
+ return P.RegExp_RegExp("^\\s*at (?:(\\S.*?)(?: \\[as [^\\]]+\\])? \\((.*)\\)|(.*))$", false);
+ });
+ _lazy($, "_v8UrlLocation", "$get$_v8UrlLocation", function() {
+ return P.RegExp_RegExp("^(.*):(\\d+):(\\d+)|native$", false);
+ });
+ _lazy($, "_v8EvalLocation", "$get$_v8EvalLocation", function() {
+ return P.RegExp_RegExp("^eval at (?:\\S.*?) \\((.*)\\)(?:, .*?:\\d+:\\d+)?$", false);
+ });
+ _lazy($, "_firefoxSafariFrame", "$get$_firefoxSafariFrame", function() {
+ return P.RegExp_RegExp("^(?:([^@(/]*)(?:\\(.*\\))?((?:/[^/]*)*)(?:\\(.*\\))?@)?(.*?):(\\d*)(?::(\\d*))?$", false);
+ });
+ _lazy($, "_friendlyFrame", "$get$_friendlyFrame", function() {
+ return P.RegExp_RegExp("^(\\S+)(?: (\\d+)(?::(\\d+))?)?\\s+([^\\d].*)$", false);
+ });
+ _lazy($, "_asyncBody", "$get$_asyncBody", function() {
+ return P.RegExp_RegExp("<(<anonymous closure>|[^>]+)_async_body>", false);
+ });
+ _lazy($, "_initialDot", "$get$_initialDot", function() {
+ return P.RegExp_RegExp("^\\.", false);
+ });
+ _lazy($, "Frame__uriRegExp", "$get$Frame__uriRegExp", function() {
+ return P.RegExp_RegExp("^[a-zA-Z][-+.a-zA-Z\\d]*://", false);
+ });
+ _lazy($, "Frame__windowsRegExp", "$get$Frame__windowsRegExp", function() {
+ return P.RegExp_RegExp("^([a-zA-Z]:[\\\\/]|\\\\\\\\)", false);
+ });
+ _lazy($, "StackZoneSpecification_disableKey", "$get$StackZoneSpecification_disableKey", function() {
+ return new P.Object();
+ });
+ _lazy($, "_terseRegExp", "$get$_terseRegExp", function() {
+ return P.RegExp_RegExp("(-patch)?([/\\\\].*)?$", false);
+ });
+ _lazy($, "_v8Trace", "$get$_v8Trace", function() {
+ return P.RegExp_RegExp("\\n ?at ", false);
+ });
+ _lazy($, "_v8TraceLine", "$get$_v8TraceLine", function() {
+ return P.RegExp_RegExp(" ?at ", false);
+ });
+ _lazy($, "_firefoxSafariTrace", "$get$_firefoxSafariTrace", function() {
+ return P.RegExp_RegExp("^(([.0-9A-Za-z_$/<]|\\(.*\\))*@)?[^\\s]*:\\d*$", true);
+ });
+ _lazy($, "_friendlyTrace", "$get$_friendlyTrace", function() {
+ return P.RegExp_RegExp("^[^\\s<][^\\s]*( \\d+(:\\d+)?)?[ \\t]+[^\\s]+$", true);
+ });
+ _lazy($, "Metadata_empty", "$get$Metadata_empty", function() {
+ var _null = null;
+ return O.Metadata$_(_null, _null, _null, _null, _null, _null, _null, _null, _null, _null);
+ });
+ _lazy($, "_universalValidVariables", "$get$_universalValidVariables", function() {
+ var _i,
+ t1 = P.LinkedHashSet_LinkedHashSet(type$.String);
+ t1.add$1(0, "posix");
+ t1.add$1(0, "dart-vm");
+ t1.add$1(0, "browser");
+ t1.add$1(0, "js");
+ t1.add$1(0, "blink");
+ t1.add$1(0, "google");
+ for (_i = 0; _i < 7; ++_i)
+ t1.add$1(0, C.List_m7e[_i].identifier);
+ for (_i = 0; _i < 5; ++_i)
+ t1.add$1(0, C.List_opx[_i].identifier);
+ return t1;
+ });
+ _lazy($, "_currentKey", "$get$_currentKey0", function() {
+ return new P.Object();
+ });
+ _lazy($, "_currentKey0", "$get$_currentKey", function() {
+ return new P.Object();
+ });
+ _lazy($, "currentOSGuess", "$get$currentOSGuess", function() {
+ return new B.closure0().call$0();
+ });
+ _lazy($, "_hyphenatedIdentifier0", "$get$_hyphenatedIdentifier", function() {
+ return P.RegExp_RegExp("[a-zA-Z_-][a-zA-Z0-9_-]*", false);
+ });
+ _lazy($, "anchoredHyphenatedIdentifier", "$get$anchoredHyphenatedIdentifier", function() {
+ return P.RegExp_RegExp("^" + $.$get$_hyphenatedIdentifier().pattern + "$", false);
+ });
+ _lazy($, "SuiteConfiguration_empty", "$get$SuiteConfiguration_empty", function() {
+ var t1, _null = null;
+ U.SuiteConfiguration__list(_null, type$.String);
+ t1 = type$.Pattern;
+ L.UnmodifiableSetView$(P.LinkedHashSet_LinkedHashSet$_empty(t1), t1);
+ U.SuiteConfiguration__list(_null, H.findType("RuntimeSelection"));
+ t1 = H.findType("SuiteConfiguration");
+ U.SuiteConfiguration__map(_null, type$.BooleanSelector, t1);
+ U.SuiteConfiguration__map(_null, type$.PlatformSelector, t1);
+ $.$get$Metadata_empty();
+ return new U.SuiteConfiguration();
+ });
+ })();
+ (function nativeSupport() {
+ !function() {
+ var intern = function(s) {
+ var o = {};
+ o[s] = 1;
+ return Object.keys(hunkHelpers.convertToFastObject(o))[0];
+ };
+ init.getIsolateTag = function(name) {
+ return intern("___dart_" + name + init.isolateTag);
+ };
+ var tableProperty = "___dart_isolate_tags_";
+ var usedProperties = Object[tableProperty] || (Object[tableProperty] = Object.create(null));
+ var rootProperty = "_ZxYxX";
+ for (var i = 0;; i++) {
+ var property = intern(rootProperty + "_" + i + "_");
+ if (!(property in usedProperties)) {
+ usedProperties[property] = 1;
+ init.isolateTag = property;
+ break;
+ }
+ }
+ init.dispatchPropertyName = init.getIsolateTag("dispatch_record");
+ }();
+ hunkHelpers.setOrUpdateInterceptorsByTag({ArrayBuffer: H.NativeByteBuffer, ArrayBufferView: H.NativeTypedData, DataView: H.NativeByteData, Float32Array: H.NativeFloat32List, Float64Array: H.NativeFloat64List, Int16Array: H.NativeInt16List, Int32Array: H.NativeInt32List, Int8Array: H.NativeInt8List, Uint16Array: H.NativeUint16List, Uint32Array: H.NativeUint32List, Uint8ClampedArray: H.NativeUint8ClampedList, CanvasPixelArray: H.NativeUint8ClampedList, Uint8Array: H.NativeUint8List, ApplicationCacheErrorEvent: W.ApplicationCacheErrorEvent, Blob: W.Blob, DOMError: W.DomError, DOMException: W.DomException, ErrorEvent: W.ErrorEvent, AbortPaymentEvent: W.Event, AnimationEvent: W.Event, AnimationPlaybackEvent: W.Event, BackgroundFetchClickEvent: W.Event, BackgroundFetchEvent: W.Event, BackgroundFetchFailEvent: W.Event, BackgroundFetchedEvent: W.Event, BeforeInstallPromptEvent: W.Event, BeforeUnloadEvent: W.Event, BlobEvent: W.Event, CanMakePaymentEvent: W.Event, ClipboardEvent: W.Event, CloseEvent: W.Event, CompositionEvent: W.Event, CustomEvent: W.Event, DeviceMotionEvent: W.Event, DeviceOrientationEvent: W.Event, ExtendableEvent: W.Event, ExtendableMessageEvent: W.Event, FetchEvent: W.Event, FocusEvent: W.Event, FontFaceSetLoadEvent: W.Event, ForeignFetchEvent: W.Event, GamepadEvent: W.Event, HashChangeEvent: W.Event, InstallEvent: W.Event, KeyboardEvent: W.Event, MediaEncryptedEvent: W.Event, MediaQueryListEvent: W.Event, MediaStreamEvent: W.Event, MediaStreamTrackEvent: W.Event, MIDIConnectionEvent: W.Event, MIDIMessageEvent: W.Event, MouseEvent: W.Event, DragEvent: W.Event, MutationEvent: W.Event, NotificationEvent: W.Event, PageTransitionEvent: W.Event, PaymentRequestEvent: W.Event, PaymentRequestUpdateEvent: W.Event, PointerEvent: W.Event, PopStateEvent: W.Event, PresentationConnectionAvailableEvent: W.Event, ProgressEvent: W.Event, PromiseRejectionEvent: W.Event, PushEvent: W.Event, RTCDataChannelEvent: W.Event, RTCDTMFToneChangeEvent: W.Event, RTCPeerConnectionIceEvent: W.Event, RTCTrackEvent: W.Event, SecurityPolicyViolationEvent: W.Event, SensorErrorEvent: W.Event, SpeechRecognitionEvent: W.Event, SpeechSynthesisEvent: W.Event, StorageEvent: W.Event, SyncEvent: W.Event, TextEvent: W.Event, TouchEvent: W.Event, TrackEvent: W.Event, TransitionEvent: W.Event, WebKitTransitionEvent: W.Event, UIEvent: W.Event, VRDeviceEvent: W.Event, VRDisplayEvent: W.Event, VRSessionEvent: W.Event, WheelEvent: W.Event, MojoInterfaceRequestEvent: W.Event, ResourceProgressEvent: W.Event, USBConnectionEvent: W.Event, IDBVersionChangeEvent: W.Event, AudioProcessingEvent: W.Event, OfflineAudioCompletionEvent: W.Event, WebGLContextEvent: W.Event, Event: W.Event, InputEvent: W.Event, Window: W.EventTarget, DOMWindow: W.EventTarget, EventTarget: W.EventTarget, File: W.File, Location: W.Location, MediaError: W.MediaError, MediaKeyMessageEvent: W.MediaKeyMessageEvent, MessageEvent: W.MessageEvent, MessagePort: W.MessagePort, NavigatorUserMediaError: W.NavigatorUserMediaError, OverconstrainedError: W.OverconstrainedError, PositionError: W.PositionError, PresentationConnectionCloseEvent: W.PresentationConnectionCloseEvent, SpeechRecognitionError: W.SpeechRecognitionError, SQLError: P.SqlError});
+ hunkHelpers.setOrUpdateLeafTags({ArrayBuffer: true, ArrayBufferView: false, DataView: true, Float32Array: true, Float64Array: true, Int16Array: true, Int32Array: true, Int8Array: true, Uint16Array: true, Uint32Array: true, Uint8ClampedArray: true, CanvasPixelArray: true, Uint8Array: false, ApplicationCacheErrorEvent: true, Blob: false, DOMError: true, DOMException: true, ErrorEvent: true, AbortPaymentEvent: true, AnimationEvent: true, AnimationPlaybackEvent: true, BackgroundFetchClickEvent: true, BackgroundFetchEvent: true, BackgroundFetchFailEvent: true, BackgroundFetchedEvent: true, BeforeInstallPromptEvent: true, BeforeUnloadEvent: true, BlobEvent: true, CanMakePaymentEvent: true, ClipboardEvent: true, CloseEvent: true, CompositionEvent: true, CustomEvent: true, DeviceMotionEvent: true, DeviceOrientationEvent: true, ExtendableEvent: true, ExtendableMessageEvent: true, FetchEvent: true, FocusEvent: true, FontFaceSetLoadEvent: true, ForeignFetchEvent: true, GamepadEvent: true, HashChangeEvent: true, InstallEvent: true, KeyboardEvent: true, MediaEncryptedEvent: true, MediaQueryListEvent: true, MediaStreamEvent: true, MediaStreamTrackEvent: true, MIDIConnectionEvent: true, MIDIMessageEvent: true, MouseEvent: true, DragEvent: true, MutationEvent: true, NotificationEvent: true, PageTransitionEvent: true, PaymentRequestEvent: true, PaymentRequestUpdateEvent: true, PointerEvent: true, PopStateEvent: true, PresentationConnectionAvailableEvent: true, ProgressEvent: true, PromiseRejectionEvent: true, PushEvent: true, RTCDataChannelEvent: true, RTCDTMFToneChangeEvent: true, RTCPeerConnectionIceEvent: true, RTCTrackEvent: true, SecurityPolicyViolationEvent: true, SensorErrorEvent: true, SpeechRecognitionEvent: true, SpeechSynthesisEvent: true, StorageEvent: true, SyncEvent: true, TextEvent: true, TouchEvent: true, TrackEvent: true, TransitionEvent: true, WebKitTransitionEvent: true, UIEvent: true, VRDeviceEvent: true, VRDisplayEvent: true, VRSessionEvent: true, WheelEvent: true, MojoInterfaceRequestEvent: true, ResourceProgressEvent: true, USBConnectionEvent: true, IDBVersionChangeEvent: true, AudioProcessingEvent: true, OfflineAudioCompletionEvent: true, WebGLContextEvent: true, Event: false, InputEvent: false, Window: true, DOMWindow: true, EventTarget: false, File: true, Location: true, MediaError: true, MediaKeyMessageEvent: true, MessageEvent: true, MessagePort: true, NavigatorUserMediaError: true, OverconstrainedError: true, PositionError: true, PresentationConnectionCloseEvent: true, SpeechRecognitionError: true, SQLError: true});
+ H.NativeTypedArray.$nativeSuperclassTag = "ArrayBufferView";
+ H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin.$nativeSuperclassTag = "ArrayBufferView";
+ H._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin.$nativeSuperclassTag = "ArrayBufferView";
+ H.NativeTypedArrayOfDouble.$nativeSuperclassTag = "ArrayBufferView";
+ H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin.$nativeSuperclassTag = "ArrayBufferView";
+ H._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin.$nativeSuperclassTag = "ArrayBufferView";
+ H.NativeTypedArrayOfInt.$nativeSuperclassTag = "ArrayBufferView";
+ })();
+ Function.prototype.call$0 = function() {
+ return this();
+ };
+ Function.prototype.call$1 = function(a) {
+ return this(a);
+ };
+ Function.prototype.call$2 = function(a, b) {
+ return this(a, b);
+ };
+ Function.prototype.call$3$3 = function(a, b, c) {
+ return this(a, b, c);
+ };
+ Function.prototype.call$2$2 = function(a, b) {
+ return this(a, b);
+ };
+ Function.prototype.call$1$1 = function(a) {
+ return this(a);
+ };
+ Function.prototype.call$2$1 = function(a) {
+ return this(a);
+ };
+ Function.prototype.call$3 = function(a, b, c) {
+ return this(a, b, c);
+ };
+ Function.prototype.call$4 = function(a, b, c, d) {
+ return this(a, b, c, d);
+ };
+ Function.prototype.call$3$1 = function(a) {
+ return this(a);
+ };
+ Function.prototype.call$2$3 = function(a, b, c) {
+ return this(a, b, c);
+ };
+ Function.prototype.call$1$2 = function(a, b) {
+ return this(a, b);
+ };
+ Function.prototype.call$5 = function(a, b, c, d, e) {
+ return this(a, b, c, d, e);
+ };
+ Function.prototype.call$3$4 = function(a, b, c, d) {
+ return this(a, b, c, d);
+ };
+ Function.prototype.call$2$4 = function(a, b, c, d) {
+ return this(a, b, c, d);
+ };
+ Function.prototype.call$1$4 = function(a, b, c, d) {
+ return this(a, b, c, d);
+ };
+ Function.prototype.call$3$6 = function(a, b, c, d, e, f) {
+ return this(a, b, c, d, e, f);
+ };
+ Function.prototype.call$2$5 = function(a, b, c, d, e) {
+ return this(a, b, c, d, e);
+ };
+ Function.prototype.call$2$0 = function() {
+ return this();
+ };
+ convertAllToFastObject(holders);
+ convertToFastObject($);
+ (function(callback) {
+ if (typeof document === "undefined") {
+ callback(null);
+ return;
+ }
+ if (typeof document.currentScript != 'undefined') {
+ callback(document.currentScript);
+ return;
+ }
+ var scripts = document.scripts;
+ function onLoad(event) {
+ for (var i = 0; i < scripts.length; ++i)
+ scripts[i].removeEventListener("load", onLoad, false);
+ callback(event.target);
+ }
+ for (var i = 0; i < scripts.length; ++i)
+ scripts[i].addEventListener("load", onLoad, false);
+ })(function(currentScript) {
+ init.currentScript = currentScript;
+ if (typeof dartMainRunner === "function")
+ dartMainRunner(R.main, []);
+ else
+ R.main([]);
+ });
+})();
+
+//# sourceMappingURL=main_test.dart.browser_test.dart.js.map
diff --git a/pkgs/coverage/test/test_files/main_test.js.map b/pkgs/coverage/test/test_files/main_test.js.map
new file mode 100644
index 0000000..38669ba
--- /dev/null
+++ b/pkgs/coverage/test/test_files/main_test.js.map
@@ -0,0 +1 @@
+{"version":3,"engine":"v2","file":"main_test.dart.browser_test.dart.js","sourceRoot":"","sources":["google3:///third_party/dart_lang/v2/sdk/lib/internal/cast.dart","google3:///third_party/dart_lang/v2/sdk/lib/internal/internal.dart","google3:///third_party/dart_lang/v2/sdk/lib/internal/iterable.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/errors.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/constant_map.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/instantiation.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/js_helper.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/rti.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/native_helper.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/core_patch.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/js_rti.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/exceptions.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/interceptors.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/string_helper.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/iterable.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/js_names.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/js_primitives.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/js_array.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/js_string.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/async_patch.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/duration.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/future_impl.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/zone.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/future.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/timer.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/schedule_microtask.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/stream.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/stream_controller.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/stream_impl.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/stream_pipe.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/internal_patch.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/collection_patch.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/hash_map.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/iterable.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/linked_hash_map.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/linked_hash_set.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/maps.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/queue.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/convert_patch.dart","google3:///third_party/dart_lang/v2/sdk/lib/convert/base64.dart","google3:///third_party/dart_lang/v2/sdk/lib/convert/codec.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/date_time.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/list.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/map.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/print.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/string.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/uri.dart","google3:///third_party/dart_lang/v2/sdk/lib/convert/utf.dart","google3:///third_party/dart_lang/v2/sdk/lib/js_util/js_util.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/math_patch.dart","google3:///third_party/dart_lang/v2/sdk/lib/html/dart2js/html_dart2js.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.5/lib/src/span_scanner.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/file.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/remote_listener.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.0.0/lib/src/multi_channel.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.0.0/lib/src/stream_channel_controller.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/suite_channel_manager.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.0.0/lib/src/guarantee_channel.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/stack_trace_formatter.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/style.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/pool-1.4.0/lib/pool.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/async_memoizer.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-1.1.5/lib/source_map_stack_trace.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib/src/chain.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib/src/trace.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/stacktrace.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/group.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/metadata.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12/lib/src/unmodifiable_wrappers.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/frontend/timeout.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/src/runner/engine.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/future_group.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/stream_group.dart","google3:///third_party/dart_lang/v2/sdk/lib/async/broadcast_stream_controller.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.8/lib/src/utils.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12/lib/src/functions.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12/lib/src/union_set_controller.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12/lib/src/union_set.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib/src/lazy_trace.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/package_resolver-1.0.10/lib/src/package_config_resolver.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/location.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/live_test_controller.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/util/test.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/invoker.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.5/lib/src/exception.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/platform_selector.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/suite_platform.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/src/util/stack_trace_mapper.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/package_resolver-1.0.10/lib/src/package_root_resolver.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.8/lib/src/vlq.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.8/lib/parser.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test/lib/src/bootstrap/browser.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/src/runner/plugin/remote_platform_helpers.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.0.0/lib/stream_channel.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/span_exception.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/frontend/expect.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/src/description.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/utils.dart","file:///usr/local/google/home/grouma/Projects/sample-test/test/main_test.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/parsed_path.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/path_exception.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/span_with_context.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/declarer.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/ast.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/highlighter.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib/src/stack_zone_specification.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib/src/lazy_chain.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/suite.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/src/runner/suite.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/util/remote_exception.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/test_core.dart","","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/runtime.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/src/runner/live_suite_controller.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/package_resolver-1.0.10/lib/src/utils.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/utils.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/utils.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.5/lib/src/utils.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12/lib/src/queue_list.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/src/util.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/src/core_matchers.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/src/equals_matcher.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/context.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/path.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/src/pretty_print.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib/src/frame.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.9.3/lib/src/unparsed_frame.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test/lib/src/runner/browser/post_message_channel.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/operating_system.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/closed_exception.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/list.dart","google3:///third_party/dart_lang/v2/sdk/lib/_internal/js_runtime/lib/js_number.dart","google3:///third_party/dart_lang/v2/sdk/lib/internal/list.dart","google3:///third_party/dart_lang/v2/sdk/lib/internal/symbol.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/collections.dart","google3:///third_party/dart_lang/v2/sdk/lib/collection/set.dart","google3:///third_party/dart_lang/v2/sdk/lib/convert/ascii.dart","google3:///third_party/dart_lang/v2/sdk/lib/convert/json.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/object.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/expando.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/null.dart","google3:///third_party/dart_lang/v2/sdk/lib/core/stopwatch.dart","google3:///third_party/dart_lang/v2/sdk/lib/html/html_common/conversions_dart2js.dart","google3:///third_party/dart_lang/v2/sdk/lib/html/html_common/conversions.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/delegate/stream_subscription.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/null_stream_sink.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/result/error.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/result/value.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/stream_completer.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/stream_queue.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/subscription_stream.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/stream_sink_completer.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/all.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/evaluator.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/impl.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/intersection_selector.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/validator.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/none.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/parser.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/scanner.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.0.5/lib/src/string_scanner.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/token.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.5/lib/src/visitor.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12/lib/src/empty_unmodifiable_set.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/collection-1.14.12/lib/src/wrappers.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/src/feature_matcher.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/src/interfaces.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/src/type_matcher.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/internal_style.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/style/posix.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/style/url.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/path-1.6.4/lib/src/style/windows.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/restartable_timer.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.8/lib/src/source_map_span.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.1.0/lib/src/generated/top_level.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.1.0/lib/term_glyph.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/location_mixin.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/span.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/source_span-1.5.5/lib/src/span_mixin.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.0.0/lib/src/stream_channel_completer.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.1.0/lib/src/generated/ascii_glyph_set.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.1.0/lib/src/generated/unicode_glyph_set.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/live_test.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/state.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/backend/message.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_api/lib/src/util/iterable_set.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/src/runner/runner_suite.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/src/runner/reporter/expanded.dart","file:///usr/local/google/home/grouma/Projects/test/pkgs/test_core/lib/src/util/print_sink.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/delegate/sink.dart","file:///usr/local/google/home/grouma/.pub-cache/hosted/pub.dartlang.org/async-2.4.0/lib/src/result/result.dart"],"names":["CastIterable","hexDigitValue","SubListIterable","MappedIterable","IterableElementError.noElement","IterableElementError.tooMany","IterableElementError.tooFew","ConstantMap._throwUnmodifiable","instantiate1","Instantiation1","unminifyOrTag","isJsIndexable","S","Primitives.objectHashCode","Primitives.parseInt","Primitives.objectTypeName","Primitives._objectTypeNameNewRti","Primitives._saneNativeClassName","Primitives.dateNow","Primitives.initTicker","Primitives.currentUri","Primitives._fromCharCodeApply","Primitives.stringFromCodePoints","Primitives.stringFromCharCodes","Primitives.stringFromNativeUint8List","Primitives.stringFromCharCode","Primitives.lazyAsJsDate","Primitives.getYear","Primitives.getMonth","Primitives.getDay","Primitives.getHours","Primitives.getMinutes","Primitives.getSeconds","Primitives.getMilliseconds","Primitives.getProperty","Primitives.setProperty","iae","ioore","diagnoseIndexError","diagnoseRangeError","argumentErrorValue","checkNum","wrapException","toStringWrapper","throwExpression","throwConcurrentModificationError","TypeErrorDecoder.extractPattern","TypeErrorDecoder.provokeCallErrorOn","TypeErrorDecoder.provokePropertyErrorOn","NullError","JsNoSuchMethodError","unwrapException","getTraceFromException","objectHashCode","fillLiteralMap","getLength","fillLiteralSet","invokeClosure","Exception","convertDartClosureToJS","Closure.fromTearOff","Closure._computeSignatureFunctionNewRti","Closure.cspForwardCall","Closure.forwardCallTo","Closure.cspForwardInterceptedCall","Closure.forwardInterceptedCallTo","closureFromTearOff","BoundClosure.evalRecipe","evalInInstance","BoundClosure.evalRecipeIntercepted","BoundClosure.selfOf","BoundClosure.receiverOf","BoundClosure.computeFieldNamed","boolConversionCheck","extractFunctionTypeObjectFromInternal","TypeErrorImplementation","_typeDescription","assertTest","assertThrow","assertHelper","throwCyclicInit","RuntimeError","getIsolateAffinityTag","setRuntimeTypeInfo","getRuntimeTypeInfo","getRuntimeTypeArguments","runtimeTypeToString","_runtimeTypeToString","_getRuntimeTypeAsString","getFutureOrArgument","_functionRtiToString","isInterestingBound","_joinArguments","getRuntimeType","_isClosure","substitute","computeSignature","invokeOn","defineProperty","lookupAndCacheInterceptor","patchProto","patchInteriorProto","makeLeafDispatchRecord","makeDefaultDispatchRecord","initNativeDispatch","initNativeDispatchContinue","lookupInterceptor","initHooks","applyHooksTransformer","JSSyntaxRegExp.makeNative","_MatchImplementation","stringContainsUnchecked","escapeReplacement","stringReplaceFirstRE","quoteStringForRegExp","stringReplaceAllUnchecked","stringReplaceAllUncheckedString","_stringIdentity","stringReplaceAllFuncUnchecked","_AllMatchesIterable.iterator","stringReplaceFirstUnchecked","stringReplaceRangeUnchecked","_ensureNativeList","NativeInt8List._create1","_checkValidIndex","_checkValidRange","Rti._getFutureFromFutureOr","Rti._isUnionOfFunctionType","Rti._getInterfaceTypeArguments","Rti._getBindingArguments","Rti._getFunctionParameters","Rti._getGenericFunctionBounds","Rti._getCanonicalRecipe","findType","instantiatedGenericFunctionType","_instantiate","_Universe._canonicalRecipeOfStar","_Universe._canonicalRecipeOfQuestion","_Universe._canonicalRecipeOfFutureOr","_instantiateArray","_instantiateNamed","_instantiateFunctionParameters","_FunctionParameters.allocate","closureFunctionType","instanceOrFunctionType","instanceType","_isDartObject","_arrayInstanceType","_instanceType","_instanceTypeFromConstructor","_instanceTypeFromConstructorMiss","getTypeFromTypesTable","createRuntimeType","typeLiteral","_installSpecializedIsTest","Rti._getInterfaceName","_generalIsTestImplementation","_isTestViaProperty","_generalAsCheckImplementation","_generalTypeCheckImplementation","checkTypeBound","_Error.compose","_CastError.fromMessage","_CastError.forType","_TypeError.fromMessage","_TypeError.forType","_isTop","_asTop","_isBool","_asBoolNullable","_checkBoolNullable","_asDoubleNullable","_checkDoubleNullable","_isInt","_asIntNullable","_checkIntNullable","_isNum","_asNumNullable","_checkNumNullable","_isString","_asStringNullable","_checkStringNullable","_rtiArrayToString","Rti._getReturnType","_rtiToString","Rti._getGenericFunctionParameterIndex","_unminifyOrTag","_Universe.findRule","_Universe.findErasedType","_Universe.addRules","_Universe.addErasedTypes","_Universe.eval","_Universe.evalInEnvironment","_Universe.bind","_Universe._parseRecipe","_Universe._finishRti","_Universe._lookupTerminalRti","Rti.allocate","_Universe._createTerminalRti","_Universe._lookupUnaryRti","_Universe._createUnaryRti","_Universe._lookupGenericFunctionParameterRti","_Universe._createGenericFunctionParameterRti","_Universe._canonicalRecipeJoin","_Universe._canonicalRecipeJoinNamed","_Universe._lookupInterfaceRti","_Universe._createInterfaceRti","_Universe._lookupBindingRti","_Universe._canonicalRecipeOfBinding","_Universe._createBindingRti","_Universe._lookupFunctionRti","_Universe._canonicalRecipeOfFunction","_Universe._createFunctionRti","_Universe._lookupGenericFunctionRti","_Universe._canonicalRecipeOfGenericFunction","_Universe._createGenericFunctionRti","_Parser.create","_Parser.parse","_Parser.pushStackFrame","_Parser.handleTypeArguments","_Parser.collectArray","_Parser.handleFunctionArguments","_Parser.handleOptionalGroup","_Parser.handleNamedGroup","_Parser.collectNamed","_Parser.handleDigit","_Parser.handleIdentifier","_Universe.evalTypeVariable","_Parser.handleExtendedOperations","_Parser.toType","_Parser.toTypes","_Parser.toTypesNamed","_Parser.indexToType","_isSubtype","Rti._getStarArgument","Rti._getGenericFunctionBase","_isFunctionSubtype","_isInterfaceSubtype","typeEqual","Rti._getBindingBase","typesEqual","namedTypesEqual","isLegacyTopType","isTopType","_Utils.objectAssign","extractKeys","unmangleGlobalNameIfPreservedAnyways","printString","makeDispatchRecord","getNativeInterceptor","JSArray.fixed","JSArray.markFixed","JSArray.markFixedList","JSString._isWhitespace","JSString._skipLeadingWhitespace","JSString._skipTrailingWhitespace","_AsyncRun._initializeScheduleImmediate","_AsyncRun._scheduleImmediateJsOverride","_AsyncRun._scheduleImmediateWithSetImmediate","_AsyncRun._scheduleImmediateWithTimer","Timer._createTimer","_TimerImpl","_TimerImpl.periodic","_makeAsyncAwaitCompleter","_AsyncAwaitCompleter._future","_Future","_asyncStartSync","_asyncAwait","_asyncReturn","_asyncRethrow","_awaitOnObject","_wrapJsFunctionForAsync","Future","Future.microtask","Future.sync","_Future.value","_Future.zoneValue","_nonNullError","Future.error","_Future.immediateError","Future.wait","Future.value","_Future.immediate","Future.forEach","JSArray.iterator","Future._kTrue","Future.doWhile","_completeWithErrorCallback","_Future._chainForeignFuture","_Future._setPendingComplete","_Future._chainCoreFuture","_Future._setChained","_Future._propagateToListeners","_Future._error","_Future._removeListeners","_Future._cloneResult","_Future._setErrorObject","_registerErrorHandler","_microtaskLoop","_startMicrotaskLoop","_scheduleAsyncCallback","_schedulePriorityAsyncCallback","scheduleMicrotask","Stream.fromFuture","_StreamController.stream","Stream.fromIterable","StreamIterator","StreamController","_runGuarded","_AddStreamState.makeErrorHandler","_BufferingStreamSubscription","_BufferingStreamSubscription._zone","_nullDataHandler","_nullErrorHandler","_nullDoneHandler","_runUserCode","_cancelAndError","_cancelAndErrorClosure","_cancelAndValue","Timer","_ZoneSpecification","Zone._enter","_parentDelegate","_rootHandleUncaughtError","_rootRun","_rootRunUnary","_rootRunBinary","_rootRegisterCallback","_rootRegisterUnaryCallback","_rootRegisterBinaryCallback","_rootErrorCallback","_rootScheduleMicrotask","_rootCreateTimer","_rootCreatePeriodicTimer","Timer._createPeriodicTimer","_rootPrint","_printToZone","_rootFork","_CustomZone","runZoned","_runZoned","HashMap","_HashMap._getTableEntry","_HashMap._setTableEntry","_HashMap._newHashTable","JsLinkedHashMap.es6","LinkedHashMap","LinkedHashMap._literal","LinkedHashMap._empty","LinkedHashSet","LinkedHashSet._empty","LinkedHashSet._literal","_LinkedHashSet._newHashTable","_LinkedHashSetIterator","HashMap.from","IterableBase.iterableToShortString","IterableBase.iterableToFullString","_isToStringVisiting","_iterablePartsToStrings","LinkedHashMap.from","LinkedHashSet.from","MapBase.mapToString","ListQueue","_ListQueueIterator","_parseJson","_convertJsonToDartLazy","Utf8Decoder._convertIntercepted","Utf8Decoder._convertInterceptedUint8List","Utf8Decoder._useTextDecoderChecked","Utf8Decoder._useTextDecoderUnchecked","Utf8Decoder._unsafe","Utf8Decoder._makeDecoder","_scanOneByteCharacters","Base64Codec._checkPadding","int.parse","Error._objectToString","List.filled","List.from","List.unmodifiable","String.fromCharCodes","String.fromCharCode","String._stringFromIterable","RegExp","StringBuffer._writeAll","Uri.base","_Uri._uriEncode","JSSyntaxRegExp.hasMatch","StringBuffer.writeCharCode","StackTrace.current","DateTime._fourDigits","DateTime._threeDigits","DateTime._twoDigits","Duration","Error.safeToString","AssertionError","ArgumentError","ArgumentError.value","ArgumentError.notNull","RangeError","RangeError.value","RangeError.range","RangeError.checkValueInInterval","RangeError.checkValidRange","RangeError.checkNotNegative","IndexError","UnsupportedError","UnimplementedError","StateError","ConcurrentModificationError","FormatException","List.generate","Map.castFrom","print","_combineSurrogatePair","Uri.parse","Uri.decodeComponent","Uri._parseIPv4Address","Uri.parseIPv6Address","NativeUint8List","_Uri.notSimple","_Uri","JSString.isNotEmpty","_Uri._defaultPort","_Uri._fail","_Uri.file","_Uri._checkNonWindowsPathReservedCharacters","_Uri._checkWindowsPathReservedCharacters","ListIterable.iterator","_Uri._checkWindowsDriveLetter","_Uri._makeFileUri","_Uri._makeWindowsFileUrl","_Uri._makePort","_Uri._makeHost","_Uri._checkZoneID","_Uri._normalizeZoneID","StringBuffer.write","_Uri._normalizeRegName","_Uri._makeScheme","_Uri._canonicalizeScheme","_Uri._makeUserInfo","_Uri._makePath","JSArray.map","_Uri._normalizePath","_Uri._makeQuery","_Uri._makeFragment","_Uri._normalizeEscape","_Uri._escapeChar","_Uri._normalizeOrSubstring","_Uri._normalize","_Uri._mayContainDotSegments","_Uri._removeDotSegments","JSArray.isNotEmpty","_Uri._normalizeRelativePath","_Uri._escapeScheme","_Uri._toWindowsFilePath","_Uri._hexCharPairToByte","_Uri._uriDecode","JSString.codeUnits","Utf8Codec.decode","_Uri._isAlphabeticCharacter","UriData._writeUri","UriData._validateMimeType","UriData._parse","UriData._uriEncodeBytes","_createTables","_scan","_convertDataTree","promiseToFuture","_Completer.future","Completer","max","pow","_EventStreamSubscription","_wrapZone","SpanScanner","SourceFile.decoded","SourceFile.fromString","RemoteListener.start","SuiteChannelManager","RemoteListener._deserializeSet","RemoteListener._sendLoadException","_MultiChannel.sink","RemoteListener._sendError","StackTraceFormatter.current","Style._getPlatformStyle","Pool","Pool._closeMemo","mapStackTrace","Trace","_prettifyMember","Group","Metadata._parseOnPlatform","Metadata._parseTags","Metadata","Metadata._","Metadata.parse","Metadata.deserialize","Metadata._deserializeTimeout","Engine","FutureGroup","Engine._onTestStartedGroup","StreamGroup.broadcast","StreamController.broadcast","Engine._group","binarySearch","mapMap","mergeMaps","UnionSetController","FileLocation._","_FileSpan","Trace.current","Trace.from","Trace.parse","Trace.parseVM","Trace._parseVM","ListIterable.map","Trace.parseV8","Trace.parseJSCore","WhereIterable.map","JSArray.where","Trace.parseFirefox","Trace.parseFriendly","PackageConfigResolver._normalizeMap","SourceLocation","LiveTestController","errorsDontStopTest","Invoker.current","StringScannerException","PlatformSelector.parse","PlatformSelector._wrapFormatException","SuitePlatform","JSStackTraceMapper.deserialize","JSStackTraceMapper._deserializePackageConfigMap","UnmodifiableSetView","decodeVlq","internalBootstrapBrowserTest","StreamChannelMixin.pipe","GuaranteeChannel.stream","SourceSpanFormatException","expect","_expect","Invoker.closed","Invoker._closable","_Completer.isCompleted","fail","formatFailure","prettyPrint","StringDescription._out","StringDescription.toString","StringBuffer.writeln","method1","method2","main","parseJsonExtended","parseJson","MultiSectionMapping.fromJson","MappingBundle.fromJson","SingleMapping.fromJson","ParsedPath.parse","PathException","SourceSpanWithContext","Declarer","Declarer._","Declarer._timeout","_expandSafe","Highlighter._normalizeNewlines","Highlighter._normalizeTrailingNewline","Highlighter._normalizeEndOfLine","Highlighter._lastLineLength","Chain.capture","Expando","StackZoneSpecification._chains","Chain.current","Chain._currentSpec","StackZoneSpecification.currentChain","StackZoneSpecification._createNode","Chain.forTrace","Chain.parse","Invoker.guard","Suite._filterGroup","Group.root","SuiteConfiguration._list","SuiteConfiguration._map","RemoteException.serialize","_declarer","Declarer.current","test","group","StreamChannelController","_StreamController.sink","Runtime.deserialize","indent","toSentence","pluralize","prefixLines","LiveSuiteController","LiveSuiteController._onCompleteGroup","LiveSuiteController._closeMemo","asUri","ensureTrailingSlash","JSArray.toList","isAlphabetic","isDriveLetter","countCodeUnits","ListMixin.iterator","findLineStart","validateErrorArgs","QueueList","QueueList._nextPowerOf2","wrapMatcher","predicate","equals","escape","_getHexLiteral","JSString.runes","Context","_parseUri","_validateArgList","_StringEqualsMatcher._writeLeading","_StringEqualsMatcher._writeTrailing","_MultiChannel","current","_typeName","_escapeString","Frame.parseVM","Frame.parseV8","Frame.parseFirefox","Frame.parseFriendly","Frame._uriOrPathToUri","Frame._catchFormatException","UnparsedFrame","postMessageChannel","EventStreamProvider.forTarget","OperatingSystem.find","GuaranteeChannel","ClosedException","Interceptor.hashCode","Interceptor.==","Interceptor.toString","Interceptor.runtimeType","JSBool.toString","JSBool.hashCode","JSBool.runtimeType","JSNull.==","JSNull.toString","JSNull.hashCode","JSNull.runtimeType","JavaScriptObject.hashCode","JavaScriptObject.runtimeType","JavaScriptObject.toString","JavaScriptFunction.toString","JSArray.add","JSArray.removeAt","JSArray.insert","JSArray.insertAll","JSArray.removeLast","JSArray.remove","JSArray.addAll","JSArray.forEach","JSArray.join","JSArray.join[function-entry$0]","JSArray.fold","JSArray.firstWhere","JSArray.firstWhere[function-entry$1]","JSArray.elementAt","JSArray.sublist","JSArray.first","JSArray.last","JSArray.single","JSArray.setRange","JSArray.setRange[function-entry$3]","JSArray.fillRange","JSArray.replaceRange","JSArray.contains","JSArray.isEmpty","JSArray.toString","JSArray.toSet","JSArray.hashCode","JSArray.length","JSArray.[]","JSArray.[]=","ArrayIterator.current","ArrayIterator.moveNext","ArrayIterator._current","JSNumber.floor","JSNumber.round","JSNumber.toRadixString","JSNumber.toString","JSNumber.hashCode","JSNumber.%","JSNumber.~/","JSNumber._tdivFast","JSNumber._tdivSlow","JSNumber._shlPositive","JSNumber._shrOtherPositive","JSNumber._shrReceiverPositive","JSNumber._shrBothPositive","JSNumber.runtimeType","JSInt.runtimeType","JSDouble.runtimeType","JSString.codeUnitAt","JSString._codeUnitAt","JSString.allMatches","allMatchesInStringUnchecked","JSString.allMatches[function-entry$1]","JSString.matchAsPrefix","JSString.+","JSString.endsWith","JSString.splitMapJoin","JSString.replaceFirst","JSString.replaceRange","JSString.startsWith","JSString.startsWith[function-entry$1]","JSString.substring","JSString.substring[function-entry$1]","JSString.trim","JSString.*","JSString.padLeft","JSString.padRight","JSString.indexOf","JSString.indexOf[function-entry$1]","JSString.lastIndexOf","JSString.lastIndexOf[function-entry$1]","JSString.contains","JSString.toString","JSString.hashCode","JSString.runtimeType","JSString.length","JSString.[]","_CastIterableBase.iterator","_CastIterableBase.length","_CastIterableBase.isEmpty","_CastIterableBase.first","_CastIterableBase.last","_CastIterableBase.contains","_CastIterableBase.toString","CastIterator.moveNext","CastIterator.current","CastMap.cast","CastMap.containsKey","CastMap.[]","CastMap.remove","CastMap.forEach","CastMap.keys","CastMap.length","CastMap.isEmpty","CastMap.forEach.<anonymous function>","CastMap_forEach_closure","CodeUnits.[]","CodeUnits.length","ListIterable.isEmpty","ListIterable.first","ListIterable.last","ListIterable.contains","ListIterable.join","ListIterable.join[function-entry$0]","ListIterable.fold","ListIterable.toList","ListIterable.toList[function-entry$0]","ListIterable.toSet","SubListIterable._endIndex","SubListIterable._startIndex","SubListIterable.length","SubListIterable.elementAt","SubListIterable.take","ListIterator.current","ListIterator.moveNext","ListIterator._current","MappedIterable.iterator","MappedIterable.length","MappedIterable.isEmpty","MappedIterable.first","MappedIterable.last","MappedIterator.moveNext","MappedIterator.current","MappedIterator._current","MappedListIterable.length","MappedListIterable.elementAt","WhereIterable.iterator","WhereIterator.moveNext","WhereIterator.current","ExpandIterable.iterator","ExpandIterator","ExpandIterator.current","ExpandIterator.moveNext","ExpandIterator._currentExpansion","ExpandIterator._current","SkipWhileIterable.iterator","SkipWhileIterator.moveNext","SkipWhileIterator.current","EmptyIterator.moveNext","EmptyIterator.current","FixedLengthListMixin.length","UnmodifiableListMixin.[]=","UnmodifiableListMixin.length","ReversedListIterable.length","ReversedListIterable.elementAt","Symbol.hashCode","Symbol.toString","Symbol.==","ConstantMap.cast","ConstantMap.isEmpty","ConstantMap.toString","ConstantMap.remove","ConstantMap.map","ConstantMap.map.<anonymous function>","ConstantMap_map_closure","ConstantStringMap.length","ConstantStringMap.containsKey","ConstantStringMap.[]","ConstantStringMap._fetch","ConstantStringMap.forEach","ConstantStringMap.keys","_ConstantMapKeyIterable.iterator","_ConstantMapKeyIterable.length","Instantiation","Instantiation.toString","Primitives.initTicker.<anonymous function>","TypeErrorDecoder.matchTypeError","NullError.toString","JsNoSuchMethodError.toString","UnknownJsTypeError.toString","unwrapException.saveStackTrace","_StackTrace.toString","Closure.toString","StaticClosure.toString","BoundClosure.==","BoundClosure.hashCode","BoundClosure.toString","TypeErrorImplementation.toString","RuntimeError.toString","_AssertionError.toString","JsLinkedHashMap.keys","JsLinkedHashMap.length","JsLinkedHashMap.isEmpty","JsLinkedHashMap.values","JsLinkedHashMap.containsKey","JsLinkedHashMap.internalContainsKey","JsLinkedHashMap.addAll","JsLinkedHashMap.[]","JsLinkedHashMap.internalGet","JsLinkedHashMap.[]=","JsLinkedHashMap.internalSet","JsLinkedHashMap.putIfAbsent","JsLinkedHashMap.remove","JsLinkedHashMap.internalRemove","JsLinkedHashMap.clear","JsLinkedHashMap.forEach","JsLinkedHashMap._addHashTableEntry","JsLinkedHashMap._removeHashTableEntry","JsLinkedHashMap._modified","JsLinkedHashMap._newLinkedCell","JsLinkedHashMap._unlinkCell","JsLinkedHashMap.internalComputeHashCode","JsLinkedHashMap.internalFindBucketIndex","JsLinkedHashMap.toString","JsLinkedHashMap._getTableCell","JsLinkedHashMap._getTableBucket","JsLinkedHashMap._setTableEntry","JsLinkedHashMap._deleteTableEntry","JsLinkedHashMap._containsTableEntry","JsLinkedHashMap._newHashTable","JsLinkedHashMap.values.<anonymous function>","JsLinkedHashMap_values_closure","JsLinkedHashMap.addAll.<anonymous function>","JsLinkedHashMap_addAll_closure","LinkedHashMapKeyIterable.length","LinkedHashMapKeyIterable.isEmpty","LinkedHashMapKeyIterable.iterator","LinkedHashMapKeyIterable.contains","LinkedHashMapKeyIterator","LinkedHashMapKeyIterator.current","LinkedHashMapKeyIterator.moveNext","LinkedHashMapKeyIterator._current","initHooks.<anonymous function>","JSSyntaxRegExp.toString","JSSyntaxRegExp._nativeGlobalVersion","JSSyntaxRegExp._nativeAnchoredVersion","JSSyntaxRegExp.firstMatch","JSSyntaxRegExp.allMatches","JSSyntaxRegExp.allMatches[function-entry$1]","JSSyntaxRegExp._execGlobal","JSSyntaxRegExp._execAnchored","JSSyntaxRegExp.matchAsPrefix","_MatchImplementation.start","_MatchImplementation.end","_MatchImplementation.[]","_AllMatchesIterator.current","_AllMatchesIterator.moveNext","JSSyntaxRegExp.isUnicode","StringMatch.end","StringMatch.[]","_StringAllMatchesIterable.iterator","_StringAllMatchesIterable.first","_StringAllMatchesIterator.moveNext","_StringAllMatchesIterator.current","NativeByteBuffer.runtimeType","NativeByteData.runtimeType","NativeTypedArray.length","NativeTypedArrayOfDouble.[]","NativeTypedArrayOfDouble.[]=","NativeTypedArrayOfInt.[]=","NativeFloat32List.runtimeType","NativeFloat64List.runtimeType","NativeInt16List.runtimeType","NativeInt16List.[]","NativeInt32List.runtimeType","NativeInt32List.[]","NativeInt8List.runtimeType","NativeInt8List.[]","NativeUint16List.runtimeType","NativeUint16List.[]","NativeUint32List.runtimeType","NativeUint32List.[]","NativeUint32List.sublist","NativeUint8ClampedList.runtimeType","NativeUint8ClampedList.length","NativeUint8ClampedList.[]","NativeUint8List.runtimeType","NativeUint8List.length","NativeUint8List.[]","NativeUint8List.sublist","Rti._eval","Rti._bind","_Type.hashCode","_Type.==","_Type.toString","_Error.toString","_TypeError.message","_AsyncRun._initializeScheduleImmediate.internalCallback","_AsyncRun._initializeScheduleImmediate.<anonymous function>","_AsyncRun._scheduleImmediateJsOverride.internalCallback","_AsyncRun._scheduleImmediateWithSetImmediate.internalCallback","_TimerImpl.cancel","_TimerImpl.internalCallback","_TimerImpl.periodic.<anonymous function>","_AsyncAwaitCompleter.complete","_AsyncAwaitCompleter.completeError","_awaitOnObject.<anonymous function>","_wrapJsFunctionForAsync.<anonymous function>","_BroadcastStream.isBroadcast","_BroadcastSubscription._onPause","_BroadcastSubscription._onResume","_BroadcastSubscription._next","_BroadcastSubscription._previous","_BroadcastStreamController._mayAddEvent","_BroadcastStreamController._ensureDoneFuture","_BroadcastStreamController._removeListener","_BroadcastStreamController._subscribe","_DoneStreamSubscription","_BroadcastSubscription","_BroadcastStreamController._recordCancel","_BroadcastStreamController._recordPause","_BroadcastStreamController._recordResume","_BroadcastStreamController._addEventError","_BroadcastStreamController.add","_BroadcastStreamController.addError","_BroadcastStreamController.addError[function-entry$1]","_BroadcastStreamController.close","_BroadcastStreamController._addError","_BroadcastStreamController._close","_BroadcastStreamController._forEachListener","_BroadcastStreamController._callOnCancel","_BroadcastStreamController._firstSubscription","_BroadcastStreamController._lastSubscription","_BroadcastStreamController._addStreamState","_SyncBroadcastStreamController._mayAddEvent","_SyncBroadcastStreamController._addEventError","_SyncBroadcastStreamController._sendData","_SyncBroadcastStreamController._sendError","_SyncBroadcastStreamController._sendDone","_SyncBroadcastStreamController._sendData.<anonymous function>","_SyncBroadcastStreamController__sendData_closure","_SyncBroadcastStreamController._sendError.<anonymous function>","_SyncBroadcastStreamController__sendError_closure","_SyncBroadcastStreamController._sendDone.<anonymous function>","_SyncBroadcastStreamController__sendDone_closure","_AsyncBroadcastStreamController._sendData","_AsyncBroadcastStreamController._sendError","_AsyncBroadcastStreamController._sendDone","Future.<anonymous function>","Future.microtask.<anonymous function>","Future.wait.handleError","Future.wait.<anonymous function>","Future_wait_closure","Future.forEach.<anonymous function>","Future.doWhile.<anonymous function>","_asyncCompleteWithErrorCallback","TimeoutException.toString","_Completer.completeError","_Completer.completeError[function-entry$1]","_AsyncCompleter.complete","_AsyncCompleter.complete[function-entry$0]","_AsyncCompleter._completeError","_SyncCompleter.complete","_SyncCompleter.complete[function-entry$0]","_SyncCompleter._completeError","_FutureListener.matchesErrorTest","_FutureListener.handleError","_FutureListener.hasErrorCallback","_Future.then","_Future.then[function-entry$1]","_Future._thenAwait","_Future.catchError","_Future.whenComplete","_Future._addListener","_Future._prependListeners","_Future._reverseListeners","_Future._complete","_Future._setValue","_Future._completeWithValue","_Future._completeError","_Future._setError","_Future._completeError[function-entry$1]","_Future._asyncComplete","_Future._chainFuture","_Future._asyncCompleteError","_Future._addListener.<anonymous function>","_Future._prependListeners.<anonymous function>","_Future._chainForeignFuture.<anonymous function>","_Future._clearPendingComplete","_Future._chainForeignFuture[function-entry$1].<anonymous function>","_Future._asyncComplete.<anonymous function>","_Future._chainFuture.<anonymous function>","_Future._asyncCompleteError.<anonymous function>","_Future._propagateToListeners.handleWhenCompleteCallback","_FutureListener.handleWhenComplete","_Future._propagateToListeners.handleWhenCompleteCallback.<anonymous function>","_Future._propagateToListeners.handleValueCallback","_FutureListener.handleValue","_FutureListener._onValue","_Future._propagateToListeners.handleError","Stream.isBroadcast","Stream.pipe","Stream.length","Stream.first","Stream.last","Stream.firstWhere","Stream.fromFuture.<anonymous function>","Stream_Stream$fromFuture_closure","Stream.fromIterable.<anonymous function>","_IterablePendingEvents","Stream_Stream$fromIterable_closure","Stream.pipe.<anonymous function>","Stream.length.<anonymous function>","Stream_length_closure","Stream.first.<anonymous function>","Stream_first_closure","Stream.last.<anonymous function>","Stream_last_closure","Stream.firstWhere.<anonymous function>","Stream_firstWhere_closure","Stream.firstWhere.<anonymous function>.<anonymous function>","_StreamController._pendingEvents","_StreamController._ensurePendingEvents","_StreamController._subscription","_StreamController._badEventState","_StreamController.addStream","_AddStreamState","_StreamControllerAddStreamState","_StreamController.isPaused","_StreamController._ensureDoneFuture","_StreamController.add","_StreamController.addError","_StreamController.addError[function-entry$1]","_StreamController.close","_StreamController._closeUnchecked","_StreamController._add","_StreamController._addError","_StreamController._close","_StreamController._subscribe","_ControllerSubscription","_StreamController._recordCancel","_StreamController._recordPause","_StreamController._recordResume","_StreamController._subscribe.<anonymous function>","_StreamController._recordCancel.complete","_SyncStreamControllerDispatch._sendData","_SyncStreamControllerDispatch._sendError","_SyncStreamControllerDispatch._sendDone","_AsyncStreamControllerDispatch._sendData","_AsyncStreamControllerDispatch._sendError","_AsyncStreamControllerDispatch._sendDone","_ControllerStream._createSubscription","_ControllerStream.hashCode","_ControllerStream.==","_ControllerSubscription._onCancel","_ControllerSubscription._onPause","_ControllerSubscription._onResume","_StreamSinkWrapper.add","_AddStreamState.cancel","_AddStreamState.makeErrorHandler.<anonymous function>","_AddStreamState.cancel.<anonymous function>","_BufferingStreamSubscription._setPendingEvents","_BufferingStreamSubscription.onData","_BufferingStreamSubscription.onError","_BufferingStreamSubscription.onDone","_BufferingStreamSubscription.pause","_BufferingStreamSubscription.pause[function-entry$0]","_BufferingStreamSubscription.resume","_BufferingStreamSubscription.cancel","_BufferingStreamSubscription._mayResumeInput","_BufferingStreamSubscription.isPaused","_BufferingStreamSubscription._cancel","_BufferingStreamSubscription._add","_BufferingStreamSubscription._addError","_BufferingStreamSubscription._close","_BufferingStreamSubscription._onPause","_BufferingStreamSubscription._onResume","_BufferingStreamSubscription._onCancel","_BufferingStreamSubscription._addPending","_BufferingStreamSubscription._sendData","_BufferingStreamSubscription._sendError","_BufferingStreamSubscription._sendDone","_BufferingStreamSubscription._guardCallback","_BufferingStreamSubscription._checkState","_BufferingStreamSubscription._onData","_BufferingStreamSubscription._onDone","_BufferingStreamSubscription._pending","_BufferingStreamSubscription._sendError.sendError","_BufferingStreamSubscription._sendDone.sendDone","_StreamImpl.listen","_StreamImpl.listen[function-entry$1$onDone]","_StreamImpl.listen[function-entry$1$onDone$onError]","_StreamImpl.listen[function-entry$1]","_StreamImpl._createSubscription","_GeneratedStreamImpl._createSubscription","_IterablePendingEvents.isEmpty","_IterablePendingEvents.handleNext","_IterablePendingEvents._iterator","_DelayedEvent.next","_DelayedData.perform","_DelayedError.perform","_DelayedDone.perform","_DelayedDone.next","_PendingEvents.schedule","_PendingEvents.schedule.<anonymous function>","_StreamImplEvents.isEmpty","_StreamImplEvents.add","_StreamImplEvents.handleNext","_DoneStreamSubscription.isPaused","_DoneStreamSubscription._schedule","_DoneStreamSubscription.onData","_DoneStreamSubscription.onError","_DoneStreamSubscription.onDone","_DoneStreamSubscription.pause","_DoneStreamSubscription.pause[function-entry$0]","_DoneStreamSubscription.resume","_DoneStreamSubscription.cancel","_DoneStreamSubscription._sendDone","_DoneStreamSubscription._onDone","_EmptyStream.isBroadcast","_EmptyStream.listen","_EmptyStream.listen[function-entry$1$onDone$onError]","_EmptyStream.listen[function-entry$1]","_cancelAndError.<anonymous function>","_cancelAndErrorClosure.<anonymous function>","_cancelAndValue.<anonymous function>","AsyncError.toString","_ZoneDelegate.handleUncaughtError","_ZoneDelegate.registerCallback","_ZoneDelegate.registerUnaryCallback","_ZoneDelegate.registerBinaryCallback","_ZoneDelegate.errorCallback","_CustomZone._delegate","_CustomZone.errorZone","_CustomZone.runGuarded","_CustomZone.runUnaryGuarded","_CustomZone.runBinaryGuarded","_CustomZone.bindCallback","_CustomZone.bindUnaryCallback","_CustomZone.bindCallbackGuarded","_CustomZone.bindUnaryCallbackGuarded","_CustomZone.[]","_CustomZone.handleUncaughtError","_CustomZone.fork","_CustomZone.run","_CustomZone.runUnary","_CustomZone.runBinary","_CustomZone.registerCallback","_CustomZone.registerUnaryCallback","_CustomZone.registerBinaryCallback","_CustomZone.errorCallback","_CustomZone.scheduleMicrotask","_CustomZone.createTimer","_CustomZone.print","_CustomZone._run","_CustomZone._runUnary","_CustomZone._runBinary","_CustomZone._registerCallback","_CustomZone._registerUnaryCallback","_CustomZone._registerBinaryCallback","_CustomZone._errorCallback","_CustomZone._scheduleMicrotask","_CustomZone._createTimer","_CustomZone._createPeriodicTimer","_CustomZone._print","_CustomZone._fork","_CustomZone._handleUncaughtError","_CustomZone.bindCallback.<anonymous function>","_CustomZone_bindCallback_closure","_CustomZone.bindUnaryCallback.<anonymous function>","_CustomZone_bindUnaryCallback_closure","_CustomZone.bindCallbackGuarded.<anonymous function>","_CustomZone.bindUnaryCallbackGuarded.<anonymous function>","_CustomZone_bindUnaryCallbackGuarded_closure","_rootHandleUncaughtError.<anonymous function>","_RootZone._map","_RootZone._run","_RootZone._runUnary","_RootZone._runBinary","_RootZone._registerCallback","_RootZone._registerUnaryCallback","_RootZone._registerBinaryCallback","_RootZone._errorCallback","_RootZone._scheduleMicrotask","_RootZone._createTimer","_RootZone._createPeriodicTimer","_RootZone._print","_RootZone._fork","_RootZone._handleUncaughtError","_RootZone.parent","_RootZone._delegate","_RootZone.errorZone","_RootZone.runGuarded","_RootZone.runUnaryGuarded","_RootZone.runBinaryGuarded","_RootZone.bindCallback","_RootZone.bindCallbackGuarded","_RootZone.bindUnaryCallbackGuarded","_RootZone.[]","_RootZone.handleUncaughtError","_RootZone.fork","_RootZone.run","_RootZone.runUnary","_RootZone.runBinary","_RootZone.registerCallback","_RootZone.registerUnaryCallback","_RootZone.registerBinaryCallback","_RootZone.errorCallback","_RootZone.scheduleMicrotask","_RootZone.createTimer","_RootZone.print","_RootZone.bindCallback.<anonymous function>","_RootZone_bindCallback_closure","_RootZone.bindCallbackGuarded.<anonymous function>","_RootZone.bindUnaryCallbackGuarded.<anonymous function>","_RootZone_bindUnaryCallbackGuarded_closure","runZoned.<anonymous function>","_HashMap.keys","_HashMap.length","_HashMap.isEmpty","_HashMap.containsKey","_HashMap._containsKey","_HashMap.[]","_HashMap._get","_HashMap.[]=","_HashMap._set","_HashMap.remove","_HashMap._remove","_HashMap.forEach","_HashMap._computeKeys","_HashMap._addHashTableEntry","_HashMap._computeHashCode","_HashMap._getBucket","_HashMap._findBucketIndex","_IdentityHashMap._computeHashCode","_IdentityHashMap._findBucketIndex","_HashMapKeyIterable.length","_HashMapKeyIterable.isEmpty","_HashMapKeyIterable.iterator","_HashMapKeyIterable.contains","_HashMapKeyIterator.current","_HashMapKeyIterator.moveNext","_HashMapKeyIterator._current","_LinkedHashSet._newSet","_LinkedHashSet.iterator","_LinkedHashSet.length","_LinkedHashSet.isEmpty","_LinkedHashSet.contains","_LinkedHashSet._contains","_LinkedHashSet.first","_LinkedHashSet.last","_LinkedHashSet.add","_LinkedHashSet._add","_LinkedHashSet.remove","_LinkedHashSet._remove","_LinkedHashSet._addHashTableEntry","_LinkedHashSet._removeHashTableEntry","_LinkedHashSet._modified","_LinkedHashSet._newLinkedCell","_LinkedHashSet._unlinkCell","_LinkedHashSet._computeHashCode","_LinkedHashSet._findBucketIndex","_LinkedHashSetIterator.current","_LinkedHashSetIterator.moveNext","_LinkedHashSetIterator._current","UnmodifiableListView.length","UnmodifiableListView.[]","HashMap.from.<anonymous function>","LinkedHashMap.from.<anonymous function>","ListMixin.elementAt","ListMixin.isEmpty","ListMixin.first","ListMixin.last","ListMixin.map","ListMixin.toList","ListMixin.toList[function-entry$0]","ListMixin.toSet","ListMixin.remove","ListMixin._closeGap","ListMixin.fillRange","ListMixin.toString","MapBase.mapToString.<anonymous function>","MapMixin.cast","MapMixin.forEach","MapMixin.map","MapMixin.containsKey","MapMixin.length","MapMixin.isEmpty","MapMixin.toString","_UnmodifiableMapMixin.remove","MapView.cast","MapView.[]","MapView.containsKey","MapView.forEach","MapView.isEmpty","MapView.length","MapView.keys","MapView.remove","MapView.toString","MapView.map","UnmodifiableMapView.cast","ListQueue.iterator","ListQueue.isEmpty","ListQueue.length","ListQueue.first","ListQueue.last","ListQueue.elementAt","ListQueue.clear","ListQueue.toString","ListQueue.removeFirst","ListQueue._add","ListQueue._table","_ListQueueIterator.current","_ListQueueIterator.moveNext","_ListQueueIterator._current","SetMixin.isEmpty","SetMixin.map","SetMixin.toString","SetMixin.every","SetMixin.first","SetMixin.last","_SetBase.toSet","_SetBase.isEmpty","_SetBase.addAll","_SetBase.union","_SetBase.toList","_SetBase.toList[function-entry$0]","_SetBase.map","_SetBase.toString","_SetBase.where","_SetBase.fold","_SetBase.every","_SetBase.any","_SetBase.first","_SetBase.last","_JsonMap.[]","_JsonMap.length","_JsonMap.isEmpty","_JsonMap.keys","_JsonMap.containsKey","_JsonMap.remove","_JsonMap.forEach","_JsonMap._upgradedMap","_JsonMap._computeKeys","_JsonMap._upgrade","_JsonMap._process","_JsonMapKeyIterable.length","_JsonMapKeyIterable.elementAt","_JsonMapKeyIterable.iterator","_JsonMapKeyIterable.contains","AsciiCodec.encode","_UnicodeSubsetEncoder.convert","Base64Codec.normalize","JsonCodec.decode","JsonCodec.decoder","Utf8Codec.encoder","Utf8Encoder.convert","_Utf8Encoder._writeSurrogate","_Utf8Encoder._fillBuffer","Utf8Decoder.convert","_Utf8Decoder.flush","_Utf8Decoder.convert","DateTime.==","DateTime.hashCode","DateTime.toString","Duration.==","Duration.hashCode","Duration.toString","Duration.unary-","Duration.toString.sixDigits","Duration.toString.twoDigits","AssertionError.toString","NullThrownError.toString","ArgumentError._errorName","ArgumentError._errorExplanation","ArgumentError.toString","RangeError._errorName","RangeError._errorExplanation","IndexError._errorName","IndexError._errorExplanation","UnsupportedError.toString","UnimplementedError.toString","StateError.toString","ConcurrentModificationError.toString","OutOfMemoryError.toString","StackOverflowError.toString","CyclicInitializationError.toString","_Exception.toString","FormatException.toString","Expando.[]","Expando.[]=","Expando._setOnObject","Expando.toString","Iterable.map","Iterable.where","Iterable.contains","Iterable.join","Iterable.join[function-entry$0]","Iterable.toList","Iterable.toList[function-entry$0]","Iterable.toSet","Iterable.length","Iterable.isEmpty","Iterable.skipWhile","Iterable.first","Iterable.last","Iterable.elementAt","Iterable.toString","MapEntry.toString","Null.hashCode","Null.toString","Object.hashCode","Object.==","Object.toString","Object.runtimeType","_StringStackTrace.toString","Stopwatch.elapsedMicroseconds","Stopwatch.elapsedTicks","Runes.iterator","Runes.last","RuneIterator.current","RuneIterator.moveNext","StringBuffer.length","StringBuffer.toString","Uri._parseIPv4Address.error","Uri.parseIPv6Address.error","Uri.parseIPv6Address[function-entry$1].error","Uri.parseIPv6Address.parseHex","_Uri.userInfo","_Uri.host","_Uri.port","_Uri.query","_Uri.fragment","_Uri.replace","_Uri.replace[function-entry$0$path]","_Uri.replace[function-entry$0$pathSegments]","_Uri.pathSegments","_Uri._mergePaths","_Uri.resolve","_Uri.resolveUri","_Uri.hasEmptyPath","_Uri.hasAuthority","_Uri.hasPort","_Uri.hasQuery","_Uri.hasFragment","_Uri.hasAbsolutePath","_Uri.toFilePath","_Uri._toFilePath","_Uri.toString","_Uri._initializeText","_Uri._writeAuthority","_Uri.==","_Uri.hashCode","_Uri._pathSegments","_Uri.notSimple.<anonymous function>","_Uri._checkNonWindowsPathReservedCharacters.<anonymous function>","_Uri._makePath.<anonymous function>","UriData.uri","UriData.toString","_createTables.<anonymous function>","_createTables.build","_createTables.setChars","_createTables.setRange","_SimpleUri._isFile","_SimpleUri.hasAuthority","_SimpleUri.hasPort","_SimpleUri.hasQuery","_SimpleUri.hasFragment","_SimpleUri._isHttp","_SimpleUri._isHttps","_SimpleUri.hasAbsolutePath","_SimpleUri.scheme","_SimpleUri.userInfo","_SimpleUri.host","_SimpleUri.port","_SimpleUri.path","_SimpleUri.query","_SimpleUri.fragment","_SimpleUri.pathSegments","_SimpleUri._isPort","_SimpleUri.removeFragment","_SimpleUri.replace","_SimpleUri.replace[function-entry$0$path]","_SimpleUri.replace[function-entry$0$pathSegments]","_SimpleUri.resolve","_SimpleUri.resolveUri","_SimpleUri._simpleMerge","_SimpleUri.toFilePath","_SimpleUri._toFilePath","_SimpleUri.hashCode","_SimpleUri.==","_SimpleUri._toNonSimple","_SimpleUri.toString","DomException.toString","EventTarget.addEventListener","EventTarget._addEventListener","EventTarget._removeEventListener","Location.origin","Location.toString","MessagePort.addEventListener","MessagePort.postMessage","convertDartToNative_PrepareForStructuredClone","_EventStream.isBroadcast","_EventStream.listen","_EventStream.listen[function-entry$1$onDone$onError]","_EventStream.listen[function-entry$1]","_EventStreamSubscription.cancel","_EventStreamSubscription.pause","_EventStreamSubscription.pause[function-entry$0]","_EventStreamSubscription.resume","_EventStreamSubscription._tryResume","_EventStreamSubscription._unlisten","_EventStreamSubscription._onData","_EventStreamSubscription.<anonymous function>","_StructuredClone.findSlot","_StructuredClone.walk","convertDartToNative_DateTime","_StructuredClone.copyList","_StructuredClone.walk.<anonymous function>","_AcceptStructuredClone.findSlot","_AcceptStructuredClone.walk","DateTime._withValue","convertNativeToDart_DateTime","_AcceptStructuredClone.convertNativeToDart_AcceptStructuredClone","_AcceptStructuredClone.walk.<anonymous function>","_StructuredCloneDart2Js.forEachObjectKey","_AcceptStructuredCloneDart2Js.forEachJsField","_convertDataTree._convert","promiseToFuture.<anonymous function>","AsyncMemoizer.runOnce","AsyncMemoizer.hasRun","DelegatingStreamSubscription.onData","DelegatingStreamSubscription.onError","DelegatingStreamSubscription.onDone","DelegatingStreamSubscription.pause","DelegatingStreamSubscription.pause[function-entry$0]","DelegatingStreamSubscription.resume","DelegatingStreamSubscription.cancel","FutureGroup.add","FutureGroup.close","FutureGroup.add.<anonymous function>","FutureGroup_add_closure","NullStreamSink.add","NullStreamSink.addStream","NullStreamSink._checkEventAllowed","NullStreamSink.close","NullStreamSink.addStream.<anonymous function>","ErrorResult.complete","ErrorResult.addTo","ErrorResult.hashCode","ErrorResult.==","ValueResult.complete","ValueResult.addTo","ValueResult.hashCode","ValueResult.==","StreamCompleter.setSourceStream","_CompleterStream.listen","_CompleterStream.listen[function-entry$1$onDone$onError]","_CompleterStream.listen[function-entry$1]","_CompleterStream._linkStreamToController","_CompleterStream._createController","_CompleterStream._controller","_CompleterStream._sourceStream","StreamGroup.add","StreamGroup._onListen","StreamGroup._onCancelBroadcast","StreamGroup._listenToStream","StreamGroup.close","StreamGroup._controller","StreamGroup.add.<anonymous function>","StreamGroup_add_closure","StreamGroup._onListen.<anonymous function>","StreamGroup__onListen_closure","StreamGroup._onCancelBroadcast.<anonymous function>","StreamGroup__onCancelBroadcast_closure","StreamGroup._listenToStream.<anonymous function>","_StreamGroupState.toString","StreamQueue.next","StreamQueue._updateRequests","StreamQueue._extractStream","SubscriptionStream","StreamQueue._ensureListening","StreamQueue._addResult","StreamQueue._failClosed","StreamQueue._addRequest","StreamQueue._subscription","StreamQueue._ensureListening.<anonymous function>","StreamQueue__ensureListening_closure","Result.error","_NextRequest.update","ListMixin.isNotEmpty","_RestRequest.update","StreamCompleter.setEmpty","_CompleterStream._setEmpty","_CompleterSink._canSendDirectly","_CompleterSink.done","Completer.sync","_CompleterSink.addStream","_CompleterSink.close","_CompleterSink._ensureController","_CompleterSink._setDestinationSink","_CompleterSink._controller","_CompleterSink._destinationSink","_CompleterSink._setDestinationSink.<anonymous function>","SubscriptionStream.listen","SubscriptionStream.listen[function-entry$1$onDone$onError]","SubscriptionStream.listen[function-entry$1]","SubscriptionStream._source","_CancelOnErrorSubscriptionWrapper.onError","_CancelOnErrorSubscriptionWrapper.onError.<anonymous function>","_CancelOnErrorSubscriptionWrapper.onError.<anonymous function>.<anonymous function>","All.evaluate","All.intersection","All.validate","All.toString","VariableNode.accept","VariableNode.toString","VariableNode.==","VariableNode.hashCode","NotNode.accept","NotNode.toString","NotNode.==","NotNode.hashCode","OrNode.span","OrNode.accept","OrNode.toString","OrNode.==","OrNode.hashCode","AndNode.span","AndNode.accept","AndNode.toString","AndNode.==","AndNode.hashCode","ConditionalNode.span","ConditionalNode.accept","ConditionalNode.toString","ConditionalNode.==","ConditionalNode.hashCode","Evaluator.visitVariable","Evaluator.visitNot","Evaluator.visitOr","Evaluator.visitAnd","Evaluator.visitConditional","BooleanSelectorImpl.evaluate","BooleanSelectorImpl.intersection","BooleanSelectorImpl.validate","BooleanSelectorImpl.toString","BooleanSelectorImpl.==","BooleanSelectorImpl.hashCode","IntersectionSelector.evaluate","IntersectionSelector.intersection","IntersectionSelector.validate","IntersectionSelector.toString","IntersectionSelector.==","IntersectionSelector.hashCode","None.evaluate","None.intersection","None.validate","None.toString","Parser.parse","Parser._conditional","Parser._or","Parser._and","Parser._simpleExpression","Scanner.peek","Scanner.next","Scanner.scan","Scanner._getNext","StringScanner.isDone","SpanScanner.state","Scanner._scanOr","Scanner._scanAnd","Scanner._scanIdentifier","Scanner._scanOperator","StringScanner.readChar","Scanner._consumeWhitespace","Scanner._multiLineComment","IdentifierToken.toString","TokenType.toString","Validator.visitVariable","RecursiveVisitor.visitNot","RecursiveVisitor.visitOr","RecursiveVisitor.visitAnd","RecursiveVisitor.visitConditional","EmptyUnmodifiableSet.toSet","EmptyUnmodifiableSet.iterator","EmptyUnmodifiableSet.length","EmptyUnmodifiableSet.contains","mapMap.<anonymous function>","mapMap_closure","mergeMaps.<anonymous function>","mergeMaps_closure","QueueList.toString","QueueList.removeFirst","QueueList.length","QueueList.[]","QueueList.[]=","QueueList._add","QueueList._writeToList","QueueList._preGrow","QueueList._table","UnionSet.length","UnionSet.iterator","UnionSet._iterable","_SetBase.expand","UnionSet.toSet","UnionSet.length.<anonymous function>","UnionSet_length_closure","UnionSet._iterable.<anonymous function>","UnionSet__iterable_closure","UnionSetController._set","_DelegatingIterableBase.contains","_DelegatingIterableBase.every","_DelegatingIterableBase.first","_DelegatingIterableBase.isEmpty","_DelegatingIterableBase.iterator","_DelegatingIterableBase.last","_DelegatingIterableBase.length","_DelegatingIterableBase.map","_DelegatingIterableBase.toList","_DelegatingIterableBase.toList[function-entry$0]","_DelegatingIterableBase.toSet","_DelegatingIterableBase.where","_DelegatingIterableBase.toString","DelegatingSet.union","DelegatingSet.toSet","_IsTrue.matches","_IsTrue.describe","_Predicate.typedMatches","_Predicate.describe","StringDescription.length","StringDescription.addDescriptionOf","_StringEqualsMatcher.typedMatches","_StringEqualsMatcher.describe","_StringEqualsMatcher.describeTypedMismatch","_DeepMatcher._compareIterables","_DeepMatcher._compareSets","_DeepMatcher._recursiveMatch","_DeepMatcher._match","_DeepMatcher.matches","_DeepMatcher.describe","_DeepMatcher.describeMismatch","_DeepMatcher._compareSets.<anonymous function>","FeatureMatcher.matches","FeatureMatcher.describeMismatch","FeatureMatcher.describeTypedMismatch","Matcher.describeMismatch","prettyPrint._prettyPrint","prettyPrint._prettyPrint.pp","prettyPrint._prettyPrint.<anonymous function>","TypeMatcher.describe","_stripDynamic","TypeMatcher.matches","wrapMatcher.<anonymous function>","escape.<anonymous function>","PackageConfigResolver._normalizeMap.<anonymous function>","Context.absolute","Context.absolute[function-entry$1]","Context.join","Context.join[function-entry$2]","Context.joinAll","Context.split","Context.normalize","Context._needsNormalization","Context.relative","Context.isRelative","Context.relative[function-entry$1]","Context._isWithinOrEquals","Context._isWithinOrEqualsFast","Context._pathDirection","Context.toUri","Context.prettyUri","Context.join.<anonymous function>","Context.joinAll.<anonymous function>","Context.split.<anonymous function>","_validateArgList.<anonymous function>","_PathDirection.toString","_PathRelation.toString","InternalStyle.getRoot","InternalStyle.relativePathToUri","InternalStyle.codeUnitsEqual","InternalStyle.pathsEqual","ParsedPath.hasTrailingSeparator","ParsedPath.removeTrailingSeparators","ParsedPath.normalize","ParsedPath.toString","ParsedPath.parts","ParsedPath.separators","ParsedPath.normalize.<anonymous function>","PathException.toString","Style.toString","PosixStyle.containsSeparator","PosixStyle.isSeparator","PosixStyle.needsSeparator","PosixStyle.rootLength","PosixStyle.rootLength[function-entry$1]","PosixStyle.isRootRelative","PosixStyle.pathFromUri","PosixStyle.absolutePathToUri","UrlStyle.containsSeparator","UrlStyle.isSeparator","UrlStyle.needsSeparator","UrlStyle.rootLength","UrlStyle.rootLength[function-entry$1]","UrlStyle.isRootRelative","UrlStyle.pathFromUri","UrlStyle.relativePathToUri","UrlStyle.absolutePathToUri","WindowsStyle.containsSeparator","WindowsStyle.isSeparator","WindowsStyle.needsSeparator","WindowsStyle.rootLength","WindowsStyle.rootLength[function-entry$1]","WindowsStyle.isRootRelative","WindowsStyle.pathFromUri","WindowsStyle.absolutePathToUri","WindowsStyle.codeUnitsEqual","WindowsStyle.pathsEqual","WindowsStyle.absolutePathToUri.<anonymous function>","Pool.request","Pool.isClosed","Pool.withResource","Pool.close","Pool._onResourceReleaseAllowed","Pool._runOnRelease","Pool._resetTimer","Pool.close.<anonymous function>","Pool._onResourceReleaseAllowed.<anonymous function>","Pool._runOnRelease.<anonymous function>","PoolResource.release","Pool._onResourceReleased","mapStackTrace.<anonymous function>","_prettifyMember.<anonymous function>","MultiSectionMapping._indexFor","MultiSectionMapping.spanFor","MultiSectionMapping.spanFor[function-entry$2$uri]","MultiSectionMapping.spanFor[function-entry$2$files]","MultiSectionMapping.toString","MappingBundle.toString","MappingBundle.spanFor","SourceMapSpan","MappingBundle.spanFor[function-entry$2$uri]","SingleMapping._segmentError","SingleMapping._findLine","SingleMapping._findColumn","SingleMapping.spanFor","SourceMapSpan.identifier","SingleMapping.spanFor[function-entry$2$uri]","SingleMapping.spanFor[function-entry$2$files]","SingleMapping.toString","SingleMapping.fromJson.<anonymous function>","SingleMapping._findLine.<anonymous function>","SingleMapping._findColumn.<anonymous function>","TargetLineEntry.toString","TargetEntry.toString","_MappingTokenizer.moveNext","_MappingTokenizer.current","_MappingTokenizer.hasTokens","_MappingTokenizer.nextKind","_MappingTokenizer.toString","_digits.<anonymous function>","SourceFile.length","SourceFile.lines","SourceFile.span","SourceFile.getLine","SourceFile._isNearCachedLine","SourceFile._binarySearch","SourceFile.getColumn","SourceFile.getOffset","SourceFile.getOffset[function-entry$1]","FileLocation.line","FileLocation.sourceUrl","FileLocation.column","_FileSpan.start","_FileSpan.sourceUrl","_FileSpan.length","_FileSpan.end","_FileSpan.text","_FileSpan.context","_FileSpan.==","_FileSpan.hashCode","_FileSpan.expand","Highlighter.highlight","downEnd","upEnd","Highlighter._writeFirstLine","Highlighter._writeIntermediateLines","Highlighter._writeLastLine","Highlighter._writeTrailingLines","Highlighter._writeText","Highlighter._writeSidebar","Highlighter._writeSidebar[function-entry$0$end]","Highlighter._writeSidebar[function-entry$0$line]","Highlighter._writeSidebar[function-entry$0]","Highlighter._countTabs","Highlighter._isOnlyWhitespace","Highlighter._colorize","Highlighter._colorize[function-entry$1]","Highlighter._writeFirstLine.<anonymous function>","glyphOrAscii","topLeftCorner","horizontalLine","Highlighter._writeIntermediateLines.<anonymous function>","verticalLine","Highlighter._writeLastLine.<anonymous function>","bottomLeftCorner","Highlighter._writeSidebar.<anonymous function>","SourceLocation.distance","SourceLocation.==","SourceLocation.hashCode","SourceLocation.toString","SourceLocationMixin.distance","SourceLocationMixin.==","SourceLocationMixin.hashCode","SourceLocationMixin.toString","SourceLocationMixin.toolString","SourceSpanBase","SourceSpanException.message","SourceSpanException.toString","SourceSpanException.toString[function-entry$0]","SourceSpanMixin.sourceUrl","SourceSpanMixin.length","SourceSpanMixin.message","SourceSpanMixin.message[function-entry$1]","SourceSpanMixin.highlight","Highlighter","Highlighter._buffer","SourceSpanMixin.==","SourceSpanMixin.hashCode","SourceSpanMixin.toString","SourceSpanWithContext.context","Chain.foldFrames","Chain.toTrace","JSArray.expand","Chain.toString","Chain.capture.<anonymous function>","Chain_capture_closure","Chain.current.<anonymous function>","Chain.forTrace.<anonymous function>","Chain.parse.<anonymous function>","Chain.foldFrames.<anonymous function>","Chain.toTrace.<anonymous function>","Chain.toString.<anonymous function>","Chain.toString.<anonymous function>.<anonymous function>","Frame.isCore","Frame.library","Frame.package","Frame.location","Frame.toString","Frame.parseVM.<anonymous function>","Frame.parseV8.<anonymous function>","Frame.parseV8.<anonymous function>.parseLocation","Frame.parseFirefox.<anonymous function>","Frame.parseFriendly.<anonymous function>","UriData.fromString","Uri.dataFromString","fromUri","LazyChain._chain","LazyChain.traces","LazyChain.foldFrames","LazyChain.toTrace","LazyChain.toString","LazyChain._inner","LazyChain.foldFrames.<anonymous function>","LazyChain.toTrace.<anonymous function>","LazyTrace._trace","LazyTrace.frames","LazyTrace.original","LazyTrace.foldFrames","LazyTrace.toString","LazyTrace._inner","LazyTrace.foldFrames.<anonymous function>","StackZoneSpecification.chainFor","StackZoneSpecification._registerCallback","StackZoneSpecification._disabled","StackZoneSpecification._registerCallback[function-entry$4]","StackZoneSpecification._registerUnaryCallback","StackZoneSpecification._registerUnaryCallback[function-entry$4]","StackZoneSpecification._registerBinaryCallback","StackZoneSpecification._registerBinaryCallback[function-entry$4]","StackZoneSpecification._errorCallback","StackZoneSpecification._run","StackZoneSpecification._currentTrace","StackZoneSpecification._trimVMChain","StackZoneSpecification._currentNode","StackZoneSpecification.chainFor.<anonymous function>","StackZoneSpecification._registerCallback.<anonymous function>","StackZoneSpecification__registerCallback_closure","StackZoneSpecification._registerUnaryCallback.<anonymous function>","StackZoneSpecification__registerUnaryCallback_closure","StackZoneSpecification._registerUnaryCallback.<anonymous function>.<anonymous function>","StackZoneSpecification__registerUnaryCallback__closure","StackZoneSpecification._registerBinaryCallback.<anonymous function>","StackZoneSpecification__registerBinaryCallback_closure","StackZoneSpecification._registerBinaryCallback.<anonymous function>.<anonymous function>","StackZoneSpecification__registerBinaryCallback__closure","StackZoneSpecification._currentTrace.<anonymous function>","_Node.toChain","Trace.foldFrames","JSArray.reversed","Trace.toString","Trace.current.<anonymous function>","Trace.from.<anonymous function>","Trace._parseVM.<anonymous function>","Trace.parseV8.<anonymous function>","Trace.parseJSCore.<anonymous function>","Trace.parseFirefox.<anonymous function>","Trace.parseFriendly.<anonymous function>","Trace.foldFrames.<anonymous function>","Trace.toString.<anonymous function>","UnparsedFrame.toString","GuaranteeChannel.sink","GuaranteeChannel._onSinkDisconnected","GuaranteeChannel._sink","GuaranteeChannel._streamController","GuaranteeChannel._subscription","GuaranteeChannel.<anonymous function>","GuaranteeChannel.<anonymous function>.<anonymous function>","_GuaranteeSink.done","_GuaranteeSink.add","_GuaranteeSink.addError","_GuaranteeSink.addError[function-entry$1]","_GuaranteeSink._addError","_GuaranteeSink._addError[function-entry$1]","_GuaranteeSink.addStream","_GuaranteeSink.close","_GuaranteeSink._onStreamDisconnected","_GuaranteeSink._addStreamSubscription","_GuaranteeSink._addError.<anonymous function>","_GuaranteeSink.addStream.<anonymous function>","_MultiChannel.virtualChannel","_MultiChannel.virtualChannel[function-entry$0]","_MultiChannel._closeChannel","_MultiChannel._closeInnerChannel","_MultiChannel.<anonymous function>","_MultiChannel_closure","_MultiChannel.<anonymous function>.<anonymous function>","_MultiChannel__closure","_MultiChannel.virtualChannel.<anonymous function>","_MultiChannel_virtualChannel_closure","StreamChannelCompleter._channel","StreamChannelController.local","StreamChannelController._local","StreamChannelController._foreign","SpanScanner.spanFrom","SpanScanner.matches","SpanScanner.error","StringScanner.lastMatch","StringScanner.peekChar","StringScanner.scan","StringScanner.expect","StringScanner._fail","StringScanner.expect[function-entry$1]","StringScanner.matches","AsciiGlyphSet.glyphOrAscii","AsciiGlyphSet.horizontalLine","AsciiGlyphSet.verticalLine","AsciiGlyphSet.topLeftCorner","AsciiGlyphSet.bottomLeftCorner","AsciiGlyphSet.upEnd","AsciiGlyphSet.downEnd","UnicodeGlyphSet.glyphOrAscii","UnicodeGlyphSet.horizontalLine","UnicodeGlyphSet.verticalLine","UnicodeGlyphSet.topLeftCorner","UnicodeGlyphSet.bottomLeftCorner","UnicodeGlyphSet.upEnd","UnicodeGlyphSet.downEnd","internalBootstrapBrowserTest.<anonymous function>","suiteChannel","setStackTraceMapper","postMessageChannel.<anonymous function>","convertNativeToDart_AcceptStructuredClone","convertNativeToDart_SerializedScriptValue","postMessageChannel.<anonymous function>.<anonymous function>","ClosedException.toString","Declarer.test","Declarer.group","Declarer.build","Declarer._checkNotBuilt","Declarer._runSetUps","Declarer._setUpAll","Declarer._tearDownAll","Declarer.test.<anonymous function>","Invoker.addTearDown","Declarer.test.<anonymous function>.<anonymous function>","Declarer.test.<anonymous function>.<anonymous function>.<anonymous function>","Declarer.group.<anonymous function>","Declarer.build.<anonymous function>","Declarer._runSetUps.<anonymous function>","Declarer._tearDownAll.<anonymous function>","Declarer._tearDownAll.<anonymous function>.<anonymous function>","Declarer._tearDownAll.<anonymous function>.<anonymous function>.<anonymous function>","Group.forPlatform","Group._map","Group.forPlatform.<anonymous function>","Group._map.<anonymous function>","LocalTest.load","Invoker._closableKey","Invoker._","Invoker._counterKey","Invoker.liveTest","LocalTest.forPlatform","Invoker._outstandingCallbacks","Invoker.addOutstandingCallback","Invoker.waitForOutstandingCallbacks","Invoker.unclosable","Invoker.heartbeat","LiveTest.isComplete","Invoker._handleError","State.shouldBeDone","Invoker._handleError[function-entry$2]","Invoker._onRun","Invoker._runTearDowns","Invoker.guard.<anonymous function>","Invoker.guard.<anonymous function>.<anonymous function>","Invoker.waitForOutstandingCallbacks.<anonymous function>","Invoker.heartbeat.message","niceDuration","Invoker.heartbeat.<anonymous function>","Invoker.heartbeat.<anonymous function>.<anonymous function>","Invoker._handleError.<anonymous function>","_AsyncCounter.complete","Invoker._onRun.<anonymous function>","Invoker._onRun.<anonymous function>.<anonymous function>","Invoker._onRun.<anonymous function>.<anonymous function>.<anonymous function>","Invoker._onRun.<anonymous function>.<anonymous function>.<anonymous function>.<anonymous function>","Invoker._print","_AsyncCounter.decrement","_LiveTest.run","LiveTestController._run","LiveTestController._isClosed","_LiveTest.onComplete","LiveTestController.addError","LiveTestController.setState","LiveTestController.message","_BroadcastStreamController.hasListener","LiveTestController._close","MessageType.toString","Metadata._validateTags","Metadata.validatePlatformSelectors","Metadata.merge","Metadata.change","Metadata.change[function-entry$0$onPlatform]","Metadata.change[function-entry$0$timeout]","Metadata.change[function-entry$0$skip$skipReason]","Metadata.forPlatform","Metadata.serialize","Metadata._serializeTimeout","Metadata._unresolved","Metadata.<anonymous function>","Metadata.deserialize.<anonymous function>","BooleanSelectorImpl.parse","Parser","Metadata._validateTags.<anonymous function>","Metadata.validatePlatformSelectors.<anonymous function>","Metadata.merge.<anonymous function>","Metadata.forPlatform.<anonymous function>","Metadata.serialize.<anonymous function>","OperatingSystem.toString","OperatingSystem.find.<anonymous function>","PlatformSelector.validate","PlatformSelector.evaluate","PlatformSelector.intersection","PlatformSelector.toString","PlatformSelector.==","PlatformSelector.hashCode","PlatformSelector.parse.<anonymous function>","PlatformSelector.validate.<anonymous function>","PlatformSelector.validate.<anonymous function>.<anonymous function>","PlatformSelector.evaluate.<anonymous function>","Runtime.toString","Runtime.deserialize.<anonymous function>","StackTraceFormatter.configure","StackTraceFormatter.configure[function-entry$0$except$only]","StackTraceFormatter.configure[function-entry$0$mapper]","StackTraceFormatter.formatStackTrace","parseExtended","JSStackTraceMapper.mapStackTrace","StackTraceFormatter._except","StackTraceFormatter._only","StackTraceFormatter.formatStackTrace.<anonymous function>","_LinkedHashSet.isNotEmpty","State.==","State.hashCode","State.toString","Status.toString","Result.toString","TestFailure.toString","_expect.<anonymous function>","Timeout.merge","Duration.*","Timeout.apply","Timeout.hashCode","Timeout.==","Timeout.toString","RemoteListener._serializeGroup","RemoteListener._serializeTest","RemoteListener._runLiveTest","_BroadcastStreamController.stream","_LiveTest.onStateChange","_LiveTest.onError","_LiveTest.onMessage","RemoteListener.start.<anonymous function>","StackTraceFormatter","RemoteListener.start.<anonymous function>.<anonymous function>","RemoteListener.start.<anonymous function>.<anonymous function>.<anonymous function>","StreamQueue._","RemoteListener.start.<anonymous function>.<anonymous function>.<anonymous function>.<anonymous function>","SuiteChannelManager.current","SuiteChannelManager.connectIn","StreamChannelCompleter.setChannel","StreamSinkCompleter.setDestinationSink","RemoteListener.start.<anonymous function>.<anonymous function>.<anonymous function>.<anonymous function>.<anonymous function>","RemoteListener._listen","RemoteListener._serializeGroup.<anonymous function>","RemoteListener._serializeTest.<anonymous function>","RemoteListener._runLiveTest.<anonymous function>","RemoteListener._runLiveTest.<anonymous function>.<anonymous function>","SuiteChannelManager.connectOut","StreamCompleter._stream","StreamSinkCompleter.sink","StreamChannelCompleter._streamCompleter","StreamChannelCompleter._sinkCompleter","StreamChannelCompleter","StreamChannel","IterableSet.length","IterableSet.iterator","IterableSet.toSet","errorsDontStopTest.<anonymous function>","currentOSGuess.<anonymous function>","Engine._onUnpaused","Engine.success","Engine.liveTests","UnionSet.from","Engine.passed","Engine.skipped","Engine.failed","Engine.active","Engine.run","Engine._runGroup","JSArray._toListGrowable","Engine._runLiveTest","Engine._runLiveTest[function-entry$2]","Engine._runSkippedTest","Engine._addLiveSuite","_LiveSuite.onTestStarted","_LiveSuite.passed","_LiveSuite.skipped","_LiveSuite.failed","Engine.success.<anonymous function>","Engine.<anonymous function>","Engine.run.<anonymous function>","Engine.run.<anonymous function>.<anonymous function>","Engine_run__closure","Engine.run.<anonymous function>.<anonymous function>.<anonymous function>","Engine.run.<anonymous function>.<anonymous function>.<anonymous function>.<anonymous function>","Engine._runLiveTest.<anonymous function>","Engine._runSkippedTest.<anonymous function>","LiveSuiteController.reportLiveTest","LiveSuiteController.close","LiveSuiteController.<anonymous function>","LiveSuiteController.reportLiveTest.<anonymous function>","LiveSuiteController.close.<anonymous function>","ExpandedReporter._onTestStarted","Stopwatch.start","ExpandedReporter._onStateChange","ExpandedReporter._onError","ExpandedReporter._onDone","ExpandedReporter._progressLine","ExpandedReporter._timeString","ExpandedReporter._progressLine[function-entry$1$suffix]","ExpandedReporter._progressLine[function-entry$1$color]","ExpandedReporter._progressLine[function-entry$1]","ExpandedReporter._description","ExpandedReporter._onTestStarted.<anonymous function>","RunnerSuiteController._close","RunnerSuiteController._suite","RunnerSuiteController._close.<anonymous function>","PrintSink.writeln","PrintSink._flush","JSStackTraceMapper._deserializePackageConfigMap.<anonymous function>","_declarer.<anonymous function>","RunnerSuiteController._local","RunnerSuite._","DelegatingSink.add","Engine.suiteSink","DelegatingSink.close","Stopwatch","ExpandedReporter._","StreamGroup.stream","_declarer.<anonymous function>.<anonymous function>","main.<anonymous function>","main.<anonymous function>.<anonymous function>","_nullErrorHandler[function-entry$1]","_rootRun[function-entry$4]","_rootRunUnary[function-entry$5]","_rootRegisterCallback[function-entry$4]","_rootRegisterUnaryCallback[function-entry$4]","_rootRegisterBinaryCallback[function-entry$4]","max[function-entry$2]","DART_CLOSURE_PROPERTY_NAME","JS_INTEROP_INTERCEPTOR_TAG","TypeErrorDecoder.noSuchMethodPattern","TypeErrorDecoder.notClosurePattern","TypeErrorDecoder.nullCallPattern","TypeErrorDecoder.nullLiteralCallPattern","TypeErrorDecoder.undefinedCallPattern","TypeErrorDecoder.undefinedLiteralCallPattern","TypeErrorDecoder.nullPropertyPattern","TypeErrorDecoder.nullLiteralPropertyPattern","TypeErrorDecoder.undefinedPropertyPattern","TypeErrorDecoder.undefinedLiteralPropertyPattern","_AsyncRun._scheduleImmediateClosure","Future._nullFuture","_RootZone._rootMap","Utf8Decoder._decoder","_Base64Decoder._inverseAlphabet","_Uri._isWindowsCached","_Uri._needsNoEncoding","_hasErrorStackProperty","_scannerTables","_whitespaceAndSingleLineComments","_multiLineCommentBody","_hyphenatedIdentifier","_dart2DynamicArgs","_escapeRegExp","windows","url","context","createInternal","Style.posix","PosixStyle","Style.windows","WindowsStyle","Style.url","UrlStyle","Style.platform","_digits","MAX_INT32","MIN_INT32","_specKey","_vmFrame","_v8Frame","_v8UrlLocation","_v8EvalLocation","_firefoxSafariFrame","_friendlyFrame","_asyncBody","_initialDot","Frame._uriRegExp","Frame._windowsRegExp","StackZoneSpecification.disableKey","_terseRegExp","_v8Trace","_v8TraceLine","_firefoxSafariTrace","_friendlyTrace","Metadata.empty","_universalValidVariables","_currentKey","currentOSGuess","anchoredHyphenatedIdentifier","SuiteConfiguration.empty","patchInstance","main_closure","fromTearOff","StaticClosure","BoundClosure","functionCounter","forwardCallTo","_computeSignatureFunctionNewRti","CyclicInitializationError","NullThrownError","safeToString","_objectToString","Closure","objectTypeName","_objectTypeNameNewRti","Object","_saneNativeClassName","_getInterfaceTypeArguments","_getGenericFunctionBounds","","value","_getFunctionParameters","markFixed","JSArray","markFixedList","StringBuffer","iterableToFullString","_toStringVisiting","_writeAll","noElement","ArrayIterator","ListIterator","ListMixin","Iterable","initNativeDispatchFlag","getTagFunction","dispatchRecordsForInstanceTags","interceptorsForUncacheableTags","alternateTagFunction","JavaScriptIndexingBehavior","prototypeForTagFunction","initHooks_closure","forType","_TypeError","compose","_CastError","fromMessage","_isUnionOfFunctionType","eval","_parseRecipe","create","parse","handleDigit","handleIdentifier","toType","_lookupGenericFunctionParameterRti","_lookupTerminalRti","toTypes","_lookupInterfaceRti","_lookupGenericFunctionRti","_lookupBindingRti","handleExtendedOperations","_lookupUnaryRti","_FunctionParameters","_lookupFunctionRti","toTypesNamed","_canonicalRecipeJoin","_canonicalRecipeJoinNamed","Rti","_finishRti","int","double","num","String","bool","_AssertionError","_getBindingArguments","indexToType","findRule","_getCanonicalRecipe","evalInEnvironment","_getFutureFromFutureOr","bind","findErasedType","evalRecipeIntercepted","evalRecipe","forwardInterceptedCallTo","cspForwardCall","selfFieldNameCache","computeFieldNamed","selfOf","receiverFieldNameCache","cspForwardInterceptedCall","receiverOf","internalBootstrapBrowserTest_closure","start","_ControllerStream","_current","Null","Stream","AsyncError","_propagateToListeners","_Future__propagateToListeners_handleWhenCompleteCallback","_Future__propagateToListeners_handleValueCallback","_Future__propagateToListeners_handleError","_chainCoreFuture","_Future__prependListeners_closure","ExceptionAndStackTrace","_StackTrace","unwrapException_saveStackTrace","UnknownJsTypeError","StackOverflowError","extractPattern","TypeErrorDecoder","provokePropertyErrorOn","provokeCallErrorOn","_Future__propagateToListeners_handleWhenCompleteCallback_closure","_FutureListener","_RootZone_bindCallbackGuarded_closure","_rootHandleUncaughtError_closure","_nextCallback","_lastPriorityCallback","_lastCallback","_AsyncCallbackEntry","_enter","_isInCallbackLoop","_initializeScheduleImmediate","_AsyncRun__initializeScheduleImmediate_internalCallback","_AsyncRun__initializeScheduleImmediate_closure","_createTimer","Duration_toString_twoDigits","Duration_toString_sixDigits","_TimerImpl_internalCallback","_AsyncRun__scheduleImmediateWithSetImmediate_internalCallback","_AsyncRun__scheduleImmediateJsOverride_internalCallback","_Exception","_Future__addListener_closure","_PendingEvents","_chainForeignFuture","_Future__chainForeignFuture_closure","_StreamControllerLifecycle","StreamConsumer","Stream_pipe_closure","_GuaranteeSink","_EventStream","postMessageChannel_closure","_literal","_EventStreamSubscription_closure","_convertDataTree__convert","_IdentityHashMap","mapToString","MapBase_mapToString_closure","MapMixin","_getTableEntry","_HashMapKeyIterable","iterableToShortString","checkNotNegative","range","_HashMapKeyIterator","MappedIterator","Iterator","EfficientLengthMappedIterable","MappedListIterable","ListIterable","_newHashTable","_setTableEntry","JsLinkedHashMap","LinkedHashMapKeyIterable","LinkedHashMapCell","postMessageChannel__closure","_StructuredCloneDart2Js","DateTime","_StructuredClone_walk_closure","_AcceptStructuredCloneDart2Js","StreamSink","StreamSubscription","_empty","_AcceptStructuredClone_walk_closure","getYear","_fourDigits","getMonth","_twoDigits","getDay","getHours","getMinutes","getSeconds","getMilliseconds","_threeDigits","lazyAsJsDate","_AsyncCompleter","promiseToFuture_closure","_Future__asyncCompleteError_closure","_Future__asyncComplete_closure","_Future__chainFuture_closure","Stream_firstWhere__closure","_cancelAndErrorClosure_closure","_cancelAndError_closure","zoneValue","_cancelAndValue_closure","_StreamSinkWrapper","GuaranteeChannel_closure","_StreamImplEvents","_SyncCompleter","_GuaranteeSink_addStream_closure","_GuaranteeSink__addError_closure","GuaranteeChannel__closure","_SyncStreamController","_AsyncStreamController","_EventDispatch","_PendingEvents_schedule_closure","_BufferingStreamSubscription__sendDone_sendDone","_StreamController__subscribe_closure","_StreamController__recordCancel_complete","_AddStreamState_cancel_closure","_DelayedError","_BufferingStreamSubscription__sendError_sendError","_DelayedData","RemoteListener_start_closure","fromIterable","Map","runZoned_closure","_rootDelegate","_ZoneDelegate","printToZone","from","_ZoneFunction","_CustomZone_bindCallbackGuarded_closure","periodic","_TimerImpl$periodic_closure","_HashMap","HashMap_HashMap$from_closure","_LinkedHashSet","RemoteListener_start__closure","RemoteListener_start___closure","_sendError","serialize","TestFailure","forTrace","Chain_toString_closure","Chain_toString__closure","_Type","Chain","unmodifiable","LazyChain","Chain_Chain$forTrace_closure","Chain_Chain$parse_closure","Trace_toString_closure","parseFriendly","WhereIterable","Trace$parseFriendly_closure","_StringStackTrace","WhereIterator","Context_split_closure","List","ParsedPath","filled","ParsedPath_normalize_closure","generate","JSSyntaxRegExp","makeNative","_uriDecode","StringMatch","CodeUnits","_hexCharPairToByte","Utf8Decoder","UnmodifiableListMixin","_convertIntercepted","checkValidRange","fromCharCodes","_Utf8Decoder","stringFromCharCode","stringFromCharCodes","stringFromNativeUint8List","_stringFromIterable","stringFromCodePoints","_fromCharCodeApply","_convertInterceptedUint8List","_useTextDecoderChecked","_unsafe","_useTextDecoderUnchecked","_makeDecoder","checkValueInInterval","_StringAllMatchesIterable","_StringAllMatchesIterator","_AllMatchesIterable","_AllMatchesIterator","tooFew","fixed","Context_join_closure","Context_joinAll_closure","_validateArgList_closure","base","_currentUriBase","currentUri","_parse","_SimpleUri","notSimple","parseInt","_defaultPort","_toWindowsFilePath","_checkNonWindowsPathReservedCharacters","_Uri__checkNonWindowsPathReservedCharacters_closure","_checkWindowsDriveLetter","_checkWindowsPathReservedCharacters","fromCharCode","_removeDotSegments","_makePort","_normalizeRelativePath","_mayContainDotSegments","_escapeScheme","_isAlphabeticCharacter","_makeScheme","_fail","_makeUserInfo","_makeHost","_Uri__Uri$notSimple_closure","_makePath","_makeQuery","_makeFragment","_normalizeOrSubstring","_normalize","_normalizeEscape","_escapeChar","_Uri__makePath_closure","_normalizePath","_uriEncode","Codec","_Utf8Encoder","_checkZoneID","_normalizeZoneID","parseIPv6Address","_normalizeRegName","Uri_parseIPv6Address_error","Uri_parseIPv6Address_parseHex","_parseIPv4Address","Uri__parseIPv4Address_error","_canonicalizeScheme","_createTables_closure","_createTables_build","_createTables_setChars","_createTables_setRange","_DataUri","UriData","_checkPadding","_create1","_getPlatformStyle","Frame_Frame$parseFriendly_closure","_catchFormatException","_writeUri","_uriEncodeBytes","Frame","WindowsStyle_absolutePathToUri_closure","_validateMimeType","_skipLeadingWhitespace","_skipTrailingWhitespace","_isWhitespace","parseV8","parseJSCore","parseFirefox","_parseVM","Trace__parseVM_closure","parseVM","Frame_Frame$parseVM_closure","ExpandIterable","Chain_toTrace_closure","Trace$parseFirefox_closure","Frame_Frame$parseFirefox_closure","_uriOrPathToUri","file","_makeWindowsFileUrl","_makeFileUri","Trace$parseJSCore_closure","Frame_Frame$parseV8_closure","Frame_Frame$parseV8_closure_parseLocation","Trace$parseV8_closure","SkipWhileIterable","SkipWhileIterator","StackZoneSpecification_chainFor_closure","_Node","LazyTrace","Trace_Trace$from_closure","LazyChain_toTrace_closure","getProperty","StackTraceFormatter_formatStackTrace_closure","LazyChain_foldFrames_closure","Chain_foldFrames_closure","tooMany","LazyTrace_foldFrames_closure","Trace_foldFrames_closure","ReversedListIterable","mapStackTrace_closure","_prettifyMember_closure","fromJson","notNull","_lastLineLength","_normalizeNewlines","_normalizeTrailingNewline","_normalizeEndOfLine","_glyphs","Highlighter__writeSidebar_closure","Highlighter__writeLastLine_closure","Highlighter__writeIntermediateLines_closure","Highlighter__writeFirstLine_closure","SingleMapping__findColumn_closure","SingleMapping__findLine_closure","SingleMapping","SourceFile","_MappingTokenizer","TargetLineEntry","TargetEntry","SingleMapping$fromJson_closure","closure","MultiSectionMapping","MappingBundle","_JsonMap","_JsonMapKeyIterable","_sendLoadException","StreamQueue","_CompleterStream","_RestRequest","StreamCompleter","RemoteListener_start____closure","deserialize","_deserializeSet","find","Suite","_filterGroup","Symbol","makeErrorHandler","_AddStreamState_makeErrorHandler_closure","Result","_wrapJsFunctionForAsync_closure","_StreamIterator","_awaitOnObject_closure","_AsyncAwaitCompleter","RemoteListener_start_____closure","guard","Invoker_guard_closure","Invoker_guard__closure","RemoteListener","RemoteListener__serializeGroup_closure","RemoteListener__serializeTest_closure","VirtualChannel","_EmptyStream","NullStreamSink","MultiChannel","NullStreamSink_addStream_closure","_LinkedHashSetCell","RemoteListener__runLiveTest_closure","_BroadcastStream","RemoteListener__runLiveTest__closure","Invoker","State","Invoker__onRun_closure","_AsyncCounter","capture","_keyCount","StackZoneSpecification","setProperty","StackZoneSpecification__currentTrace_closure","Invoker__onRun__closure","Invoker__onRun___closure","Message","Invoker__onRun____closure","Future_Future_closure","errorsDontStopTest_closure","Invoker_waitForOutstandingCallbacks_closure","sync","Invoker_heartbeat_closure","Invoker_heartbeat_message","Invoker_heartbeat__closure","TimeoutException","Timeout","Invoker__handleError_closure","Chain_Chain$current_closure","_SyncBroadcastStreamController","_LiveTest","_BroadcastStreamController","Metadata_serialize_closure","MapEntry","PlatformSelector","Group_forPlatform_closure","GroupEntry","Group__map_closure","Metadata_forPlatform_closure","Metadata_Metadata__unresolved","_","Metadata_Metadata_closure","Metadata_merge_closure","Set","UnmodifiableMapView","_throwUnmodifiable","_ConstantMapKeyIterable","ConstantStringMap","DelegatingSet","Metadata__validateTags_closure","LinkedHashMap_LinkedHashMap$from_closure","PlatformSelector_evaluate_closure","OperatingSystem_find_closure","Runtime_Runtime$deserialize_closure","Runtime","Declarer_build_closure","LocalTest","Declarer__tearDownAll_closure","Declarer__tearDownAll__closure","Declarer__tearDownAll___closure","_deserializeTimeout","Metadata$deserialize_closure","BooleanSelectorImpl","Scanner","AndNode","IntersectionSelector","OrNode","ConditionalNode","Evaluator","Token","_SpanScannerState","IdentifierToken","SourceSpanMixin","FileLocation","NotNode","VariableNode","PlatformSelector$parse_closure","_wrapFormatException","_CompleterSink","_CompleterSink__setDestinationSink_closure","StreamSinkCompleter","_EventRequest","_CancelOnErrorSubscriptionWrapper","_CancelOnErrorSubscriptionWrapper_onError_closure","_CancelOnErrorSubscriptionWrapper_onError__closure","ErrorResult","ValueResult","EventSink","_NextRequest","_GeneratedStreamImpl","PackageRootResolver","_deserializePackageConfigMap","_normalizeMap","PackageConfigResolver","JSStackTraceMapper","castFrom","CastMap","CastIterator","EfficientLengthIterable","_EfficientLengthCastIterable","PackageConfigResolver__normalizeMap_closure","JSStackTraceMapper__deserializePackageConfigMap_closure","_StreamChannel","Declarer_group_closure","Trace_Trace$current_closure","Metadata_validatePlatformSelectors_closure","PlatformSelector_validate_closure","PlatformSelector_validate__closure","Validator","_parseOnPlatform","_parseTags","_globalDeclarer","_declarer_closure","RunnerSuiteController","_AsyncBroadcastStreamController","AsyncMemoizer","RunnerSuite","_frequency","initTicker","timerFrequency","ExpandedReporter","PrintSink","fromFuture","_declarer__closure","error","UnmodifiableListView","timerTicks","UnionSet","IterableSet","ExpandedReporter__onTestStarted_closure","Engine_run_closure","Pool_close_closure","Engine_run___closure","Engine_run____closure","Pool__onResourceReleaseAllowed_closure","Pool__runOnRelease_closure","PoolResource","LiveSuiteController_close_closure","RunnerSuiteController__close_closure","Engine__runSkippedTest_closure","Engine__runLiveTest_closure","microtask","Future_Future$microtask_closure","LiveSuiteController_reportLiveTest_closure","_nextPowerOf2","StreamGroup__listenToStream_closure","_LiveSuite","LiveSuiteController_closure","wait","Engine_success_closure","Future_wait_handleError","Primitives_initTicker_closure","StreamGroup","Engine_closure","_macOSDirectories","_list","_map","SuiteConfiguration","main__closure","Declarer_test_closure","Declarer_test__closure","Declarer_test___closure","Declarer__runSetUps_closure","forEach","Future_forEach_closure","doWhile","Future_doWhile_closure","_expect_closure","StringDescription","Matcher","prettyPrint__prettyPrint","prettyPrint__prettyPrint_pp","prettyPrint__prettyPrint_closure","escape_closure","Runes","RuneIterator","_Predicate","wrapMatcher_closure","_StringEqualsMatcher","_DeepMatcher","_DeepMatcher__compareSets_closure","TypeMatcher","FeatureMatcher","_writeTrailing","_writeLeading","x","objectAssign","JS_CONST","Interceptor","JSBool","JSNull","JSObject","JavaScriptObject","PlainJavaScriptObject","UnknownJavaScriptObject","Function","JavaScriptFunction","JSUnmodifiableArray","JSNumber","JSInt","JSDouble","Pattern","JSString","_CastIterableBase","EmptyIterator","FixedLengthListMixin","UnmodifiableListBase","ConstantMap","noSuchMethodPattern","notClosurePattern","nullCallPattern","nullLiteralCallPattern","undefinedCallPattern","undefinedLiteralCallPattern","nullPropertyPattern","nullLiteralPropertyPattern","undefinedPropertyPattern","undefinedLiteralPropertyPattern","NoSuchMethodError","StackTrace","TearOffClosure","RegExpMatch","Match","NativeByteBuffer","ByteBuffer","NativeTypedData","NativeByteData","NativeTypedArray","NativeTypedArrayOfDouble","NativeTypedArrayOfInt","NativeFloat32List","NativeFloat64List","NativeInt16List","NativeInt32List","NativeInt8List","NativeUint16List","Uint32List","NativeUint32List","NativeUint8ClampedList","Uint8List","Type","_Error","Sink","_Completer","StreamTransformer","StreamTransformerBase","_StreamController","_SyncStreamControllerDispatch","_AsyncStreamControllerDispatch","_StreamImpl","_DelayedEvent","_DelayedDone","Error","ZoneSpecification","ZoneDelegate","Zone","_Zone","_rootMap","_RootZone","IterableBase","ListBase","MapBase","_UnmodifiableMapMixin","MapView","Queue","SetMixin","SetBase","_SetBase","AsciiCodec","_UnicodeSubsetEncoder","AsciiEncoder","Base64Codec","Base64Encoder","_FusedCodec","Converter","Encoding","JsonCodec","JsonDecoder","Utf8Codec","Utf8Encoder","_decoder","OutOfMemoryError","StringSink","Uri","_isWindowsCached","_needsNoEncoding","AbortPaymentEvent","AnimationEvent","AnimationPlaybackEvent","ApplicationCacheErrorEvent","BackgroundFetchClickEvent","BackgroundFetchEvent","BackgroundFetchFailEvent","BackgroundFetchedEvent","BeforeInstallPromptEvent","BeforeUnloadEvent","Blob","BlobEvent","CanMakePaymentEvent","ClipboardEvent","CloseEvent","CompositionEvent","CustomEvent","DeviceMotionEvent","DeviceOrientationEvent","DomError","DomException","ErrorEvent","Event","EventTarget","ExtendableEvent","ExtendableMessageEvent","FetchEvent","File","FocusEvent","FontFaceSetLoadEvent","ForeignFetchEvent","GamepadEvent","HashChangeEvent","InstallEvent","KeyboardEvent","Location","MediaEncryptedEvent","MediaError","MediaKeyMessageEvent","MediaQueryListEvent","MediaStreamEvent","MediaStreamTrackEvent","MessageEvent","MessagePort","MidiConnectionEvent","MidiMessageEvent","MouseEvent","MutationEvent","NavigatorUserMediaError","NotificationEvent","OverconstrainedError","PageTransitionEvent","PaymentRequestEvent","PaymentRequestUpdateEvent","PointerEvent","PopStateEvent","PositionError","PresentationConnectionAvailableEvent","PresentationConnectionCloseEvent","ProgressEvent","PromiseRejectionEvent","PushEvent","RtcDataChannelEvent","RtcDtmfToneChangeEvent","RtcPeerConnectionIceEvent","RtcTrackEvent","SecurityPolicyViolationEvent","SensorErrorEvent","SpeechRecognitionError","SpeechRecognitionEvent","SpeechSynthesisEvent","StorageEvent","SyncEvent","TextEvent","TouchEvent","TrackEvent","TransitionEvent","UIEvent","VRDeviceEvent","VRDisplayEvent","VRSessionEvent","WheelEvent","Window","_MojoInterfaceRequestEvent","_ResourceProgressEvent","_USBConnectionEvent","EventStreamProvider","_StructuredClone","_AcceptStructuredClone","VersionChangeEvent","ByteData","Int8List","Uint8ClampedList","Int16List","Uint16List","Int32List","Float32List","Float64List","AudioProcessingEvent","OfflineAudioCompletionEvent","ContextEvent","SqlError","DelegatingSink","DelegatingStreamSubscription","_StreamGroupState","BooleanSelector","All","Node","Visitor","None","TokenType","RecursiveVisitor","EmptyUnmodifiableSet","UnmodifiableSetMixin","_DelegatingIterableBase","DelegatingIterable","_IsTrue","Description","SyncPackageResolver","_PathDirection","_PathRelation","InternalStyle","Style","Mapping","_TokenKind","FileSpan","SourceLocationMixin","SourceSpan","SourceSpanException","_uriRegExp","_windowsRegExp","disableKey","StreamChannelMixin","LineScannerState","StringScanner","AsciiGlyphSet","UnicodeGlyphSet","LiveTest","MessageType","empty","OperatingSystem","Status","Test","StackTraceMapper","LiveSuite","RuntimeSelection","_NativeTypedArrayOfDouble&NativeTypedArray&ListMixin","_NativeTypedArrayOfDouble&NativeTypedArray&ListMixin&FixedLengthListMixin","_NativeTypedArrayOfInt&NativeTypedArray&ListMixin","_NativeTypedArrayOfInt&NativeTypedArray&ListMixin&FixedLengthListMixin","_ListBase&Object&ListMixin","_SetBase&Object&SetMixin","_UnmodifiableMapView&MapView&_UnmodifiableMapMixin","_QueueList&Object&ListMixin","_UnionSet&SetBase&UnmodifiableSetMixin","_UnmodifiableSetView&DelegatingSet&UnmodifiableSetMixin","_IterableSet&SetMixin&UnmodifiableSetMixin","dateNow","addRules","addErasedTypes","_scheduleImmediateJsOverride","_scheduleImmediateWithSetImmediate","_scheduleImmediateWithTimer","_kTrue","decodeComponent","_scheduleImmediateClosure","_nullFuture","_inverseAlphabet","posix","platform","getInterceptor$","getInterceptor$asx","async___startMicrotaskLoop$closure","async__AsyncRun__scheduleImmediateJsOverride$closure","async__AsyncRun__scheduleImmediateWithSetImmediate$closure","async__AsyncRun__scheduleImmediateWithTimer$closure","async___nullDoneHandler$closure","async___nullErrorHandler$closure","async___nullDataHandler$closure","getInterceptor$ax","async___printToZone$closure","math__max$closure","getInterceptor$s","core_Uri_decodeComponent$closure","main_test__main$closure","_js_helper_Primitives_dateNow$closure","async_Future__kTrue$closure","pretty_print___escapeString$closure","util___getHexLiteral$closure","getInterceptor$x","getInterceptor$ansx","getInterceptor$n","async___rootHandleUncaughtError$closure","async___rootRun$closure","async___rootRunUnary$closure","async___rootRunBinary$closure","async___rootRegisterCallback$closure","async___rootRegisterUnaryCallback$closure","async___rootRegisterBinaryCallback$closure","async___rootErrorCallback$closure","async___rootScheduleMicrotask$closure","async___rootCreateTimer$closure","async___rootCreatePeriodicTimer$closure","async___rootPrint$closure","async___rootFork$closure","_captured_K1_1","_captured_this_1","dart.async#_box_0","_captured_matcher_0","future","_captured_V1_2","_captured_listener_2","_captured_frame_0","_captured_expectedElement_1","_captured_getMain_1","location","channel","_captured_depth_3","controller","matches","_captured_beforeLoad_4","_captured_f_1","line","_captured_printZone_5","_captured_R_3","end","_captured_transform_1","result","_captured_selector_0","handleError","_captured_body_1","_captured_elements_0","_captured_x_0","suite","_captured_T_3","index","_captured_validVariables_0","_captured_terse_2","addEventListener","stackTrace","timeout","_withValue","message","immediate","_captured_performance_0","trace","_captured_div_1","level","span","_captured_registered_1","where","toString","callback","decoded","groups","liveTest","_captured_engine_0","_captured_chain_0","completer","_captured_longest_0","dart.async#_box_1","skipWhile","_captured_fn_2","call","_captured_oldPredicate_0","_captured_counter_3","_captured_hasError_3","_captured_loadResource_2","describe","id","_captured_milliseconds_1","_captured_originalSource_0","stream","immediateError","_captured_outstandingCallbacksForBody_1","_captured_sourceResult_2","_captured_K_1","_captured_serializedOnPlatform_0","_captured_V_2","broadcast","onData","_captured_target_0","_captured_sourceMap_1","_captured_invoker_0","_captured_minified_4","zone","_captured_sdkRoot_2","_captured_streamConsumer_0","_captured_e_1","_captured_s_2","_captured_sdkLib_3","_addEventError","column","_captured_cleanUp_3","_captured_eagerError_4","iterator","identifier","port","_captured_action_1","_captured_node_2","_captured_T1_3","_captured_T2_4","withResource","_captured_portSubscription_1","_captured_serialized_0","_captured_doneSignal_2","_captured_arg1_1","_captured_pos_1","_captured_arg2_2","_captured_dispatch_1","_captured_getTag_0","testOn","_captured_getUnknownTag_0","skip","verboseTrace","_captured_prototypeForTag_0","chainStackTraces","_captured_argumentError_0","==","retry","_captured_arg_1","skipReason","_captured__convertedObjects_0","onPlatform","uri","_captured_portStart_1","skipped","_captured_textInside_1","_captured_maxItems_0","_captured_maxLineLength_1","original","_runGroup","host","_captured__prettyPrint_1","_runLiveTest","_captured_indent_0","_runSkippedTest","_captured_computation_1","_captured_orElse_1","_captured_countSuccess_2","_captured_K2_0","_captured_protected_0","_captured_spec_6","_captured_pp_0","onError","_captured_object_1","_captured_ex_0","subscription","cancel","_captured_bodyFunction_0","_captured_tables_0","data","stream_channel_controller.dart#_foreign","stack_zone_specification.dart#_disabled","expanded.dart#_onTestStarted","newDartList","configure","elapsedMicroseconds","dart.core#_captured_argumentError_0","platform_selector.dart#_captured_this_0","dart.async#_completeWithValue","source_maps.parser#_captured_this_0","dart.async#_isScheduled","hashMapCellKey","dart.async#_captured_future_1","multi_channel.dart#_closeChannel","encode","dart.async#_error","dart.core#_start","onClose","dart.async#_captured_callback_1","dart.async#_completeError","dart.async#_captured_doneSignal_2","_js_helper#_captured_result_2","separators","async_memoizer.dart#_completer","invoker.dart#_counterKey","functions.dart#_captured_V1_2","prettyUri","metadata.dart#_captured_serializedOnPlatform_0","equals_matcher.dart#_compareSets","fold","getRoot","dart.collection#_newSet","invoker.dart#_captured_stackTrace_3","dart.core#_isPort","catchError","*","parser.dart#_and","metadata.dart#_captured_verboseTrace_4","scanner.dart#_scanOperator","highlighter.dart#_writeFirstLine","dart.async#_handleUncaughtError","engine.dart#_failedGroup","rti#_kind","isOdd","source_maps.parser#_findLine","functions.dart#_captured_V_3","stack_zone_specification.dart#_currentNode","engine.dart#_onSuiteStartedController","stack_zone_specification.dart#_captured_f_0","pool.dart#_requestedResources","indexOf","rti#_precomputed4","source_maps.parser#_consumeValue","replaceAll","stream_queue.dart#_completer","tags","source_map_stack_trace.dart#_captured_sdkRoot_3","_js_helper#_previous","needsSeparatorPattern","dart.async#_run","replace","dart.collection#_add","_interceptors#_shlPositive","stream_sink_completer.dart#_ensureController","dart.dom.html#_location","dart.async#_mayAddListener","lazy_chain.dart#_captured_terse_2","queue_list.dart#_preGrow","evaluate","wrappers.dart#_base","context.dart#_isWithinOrEqualsFast","_js_helper#_modified","shouldBeDone","isBlink","dart.core#_currentCodePoint","stream_queue.dart#_addResult","source_map_stack_trace.dart#_box_0","typedMatches","moveNext","_js_helper#_execAnchored","duration","guarantee_channel.dart#_onSinkDisconnected","isCompleted","query","visitVariable","bindCallback","stack_zone_specification.dart#_currentTrace","sourceRoot","take","expanded.dart#_progressLine","listenerHasError","liveTests","createPeriodicTimer","live_suite_controller.dart#_onCloseCompleter","remote_listener.dart#_captured_controller_0","dart.async#_onCancel","pathsEqual","distance","dart.core#_position","asStream","abs","listenerValueOrError","dart.async#_decrementPauseCount","html_common#_captured_this_1","hasTrailingSeparator","stack_trace_formatter.dart#_captured_this_0","declarer.dart#_name","stack_zone_specification.dart#_registerBinaryCallback","dart.collection#_tail","asUint8List","isScaffoldAll","remote_listener.dart#_captured_test_1","isWithin","platform_selector.dart#_captured_validVariables_0","functions.dart#_box_0","live_suite_controller.dart#_passed","addTearDown","dart._internal#_iterator","hashMapCellValue","functions.dart#_captured_K1_1","lastSpan","runner_suite.dart#_environment","registerCallback","handleUncaughtError","stack_zone_specification.dart#_captured_this_1","allMatches","dart.collection#_position","_js_helper#_expr","dart.convert#_data","runner_suite.dart#_suiteChannel","engine.dart#_captured_suite_1","onListen","equals_matcher.dart#_recursiveMatch","highlighter.dart#_writeSidebar","stream_group.dart#_onCancelBroadcast","dart._internal#_iterable","dart.convert#_buffer","print_sink.dart#_flush","operating_system.dart#_captured_identifier_0","invoker.dart#_print","scan","onCancel","dart.async#_schedule","declarer.dart#_metadata","highlighter.dart#_colorize","source_map_stack_trace.dart#_captured_sdkRoot_2","_js_helper#_target","highlighter.dart#_multiline","highlighter.dart#_paddingBeforeSidebar","dart._internal#_startIndex","rti#_specializedTestResource","_interceptors#_isInt32","dart.collection#_contains","invoker.dart#_handleError","engine.dart#_runPool","dart.async#_setPendingComplete","parser.dart#_simpleExpression","dart.async#_rootRunUnary","dart.async#_cloneResult","stack_zone_specification.dart#_trimVMChain","live_test_controller.dart#_run","dart.collection#_first","metadata.dart#_serializeTimeout","relative","declarer.dart#_collectTraces","span_exception.dart#_message","live_test_controller.dart#_onRun","join","stack_zone_specification.dart#_errorCallback","stack_zone_specification.dart#_registerUnaryCallback","runner_suite.dart#_closeMemo","change","addAll","dart.async#_isPaused","previous","dart.async#_addError","source_map_stack_trace.dart#_captured_minified_4","dart.core#_queryStart","dart.async#_captured_eagerError_4","dart.async#_captured_T_2","whenComplete","position","_js_helper#_newLinkedCell","asCurrent","addDescriptionOf","dart.async#_captured_orElse_1","dart.async#_captured_subscription_0","invoker.dart#_count","rti#_eval","dart.async#_addEventError","rti#_optionalPositional","queue_list.dart#_writeToList","dart.async#_hasPending","live_test_controller.dart#_test","runner_suite.dart#_captured_this_0","pool.dart#_captured_zone_0","invoker.dart#_controller","setRange","write","pretty_print.dart#_captured_maxItems_0","stream_queue.dart#_isClosed","multi_channel.dart#_closeInnerChannel","invoker.dart#_closable","update","test.src.runner.browser.post_message_channel#_captured_controller_0","dart.collection#_current=","dart.async#_thenAwait","dart.convert#_upgrade","_js_helper#_fetch","isNewSegment","evaluator.dart#_semantics","internalFindBucketIndex","stack_zone_specification.dart#_registerCallback","file.dart#_cachedLine","live_suite_controller.dart#_controller","dart.async#_cancel","isPassing","source_maps.parser#_lineStart","expanded.dart#_noColor","dart.async#_forEachListener","runner_suite.dart#_isDebugging","fillRange","dart.convert#_second","removeTrailingSeparators","dart.core#_errorName","union_set_controller.dart#_set","visitAnd","pool.dart#_closeMemo","dart.async#_chainFuture","declare","needsSeparator","second","dart.async#_isCanceled","handleNext","union_set.dart#_disjoint","live_test_controller.dart#_liveTest","dart.async#_ensurePendingEvents","failed","context.dart#_parse","string_scanner.dart#_lastMatch","replaceRange","dart.convert#_carry","expand","stack_zone_specification.dart#_captured_this_0","isAbsolute","peek","pretty_print.dart#_captured_object_1","dart.async#_rootRegisterCallback","guarantee_channel.dart#_doneCompleter","isValue","_interceptors#_defaultSplit","_js_helper#_execGlobal","pool.dart#_onResourceReleaseAllowed","_interceptors#_shrBothPositive","chain.dart#_captured_longest_0","dart.core#_captured_error_0","dart.collection#_remove","dart._internal#_string","padRight","dart.async#_iterator","success","stack_zone_specification.dart#_captured_stackTrace_2","multi_channel.dart#_pendingIds","dart.core#_toNonSimple","remote_listener.dart#_captured_spec_6","readChar","scaleFactor","_js_helper#_string","stream_group.dart#_controller","remote_listener.dart#_serializeGroup","microsecond","declarer.dart#_checkNotBuilt","dart.collection#_computeKeys","binaryOnError","parser.dart#_or","dart.async#_captured_computation_1","dart.collection#_findBucketIndex","release","runner_suite.dart#_close","union","_interceptors#_iterable","dart.typed_data.implementation#_setRangeFast","live_suite_controller.dart#_captured_countSuccess_2","dart.collection#_map","internalSet","dart.collection#_checkModification","single","functions.dart#_captured_K_2","joinAll","dart.async#_isEmpty","load","pipe","identicalInJs","dart.async#_asyncCompleteError","lazy_trace.dart#_trace","hashCode","pool.dart#_pool","decrement","registerUnaryCallback","pool.dart#_maxAllocatedResources","isComplete","indexable","hasTokens","dart.dom.html#_onData","_js_helper#_strings","pathSegments","expanded.dart#_green","dart.async#_captured_registered_1","describeTypedMismatch","equals_matcher.dart#_expected","whenFalse","decode","dart._internal#_captured_f_1","any","convert","[]=","future_group.dart#_completer","dart.async#_add","matchTypeError","_js_helper#_last","unclosable","containsKey","engine.dart#_runGroup","queue_list.dart#_grow","chain.dart#_captured_predicate_0","minute","source_maps.parser#_length","declarer.dart#_setUpAllTrace","codeUnitAt","modifiedObject","dart.js_util#_captured_completer_0","newJsObject","active","expanded.dart#_lastProgressSuffix","future_group.dart#_captured_index_1","union_set.dart#_dedupIterable","live_suite_controller.dart#_captured_this_0","endsWith","dart.async#_captured_streamConsumer_0","removeLast","urls","dart.async#_captured_hasError_3","remote_listener.dart#_captured_this_1","dart.async#_varData","_js_helper#_name","engine.dart#_coverage","dart._internal#_endIndex","codeUnitsEqual","dart.async#_captured_s_2","toTrace","source_maps.parser#_segmentError","pool.dart#_closeGroup","bindUnaryCallback","dart.collection#_length","runner_suite.dart#_controller","dart.js_util#_captured_T_1","dart.async#_delegationTarget","storedCallback","declarer.dart#_solo","round","rti#_bind","errorCallback","functions.dart#_captured_V1_3","dart.convert#_allowMalformed","lastIndexOf","expanded.dart#_onError","declarer.dart#_setUpAll","core_matchers.dart#_description","restartable_timer.dart#_callback","metadata.dart#_skip","dart2jsArgs","subscription_stream.dart#_captured_error_1","dart.async#_resultOrListeners","relativeRootPattern","dart.async#_onError","stream_completer.dart#_createController","dart.collection#_previous","dart.async#_setError","file.dart#_isNearCachedLine","wrappers.dart#_setBase","equals_matcher.dart#_compareIterables","add","stream_group.dart#_listenToStream","html_common#_box_0","visitNot","complete","cast","engine.dart#_skippedGroup","type_matcher.dart#_name","dart.core#_errorExplanation","close","highlight","source_maps.parser#_mappings","putIfAbsent","_js_helper#_captured_performance_0","isFinite","runSkipped","isUnicode","addError","toChain","_js_helper#_map","dart.async#_captured_this_1","setUpAll","declarer.dart#_noRetry","spanFor","dart.async#_errorCallback=","dart.dom.html#_captured_onData_0","count","dart.async#_isComplete","dart.async#_captured_span_2","remote_listener.dart#_captured_groups_2","setAll","dart.async#_onValue","setDestinationSink","scanner.dart#_getNext","packageConfigMap","dart.core#_captured_tables_0","writeln","expanded.dart#_printPlatform","_js_helper#_trace","dart.async#_mayResumeInput","invalidValue","dart.async#_recordPause","stack_zone_specification.dart#_captured_T1_3","span_scanner.dart#_scanner","expanded.dart#_bold","file.dart#_start","noMoreLiveTests","dart.dom.html#_unlisten","engine.dart#_runCalled","string_scanner.dart#_position","removeFragment","pool.dart#_released","dart.async#_setValue","firstMatch","dart.async#_captured_originalSource_0","liveSuite","_js_helper#_next","source_maps.parser#_internal","dart.core#_isFile","isLoadSuite","guarantee_channel.dart#_streamController","dart.dom.html#_addEventListener","dart._internal#_endOrLength","resolveUri","_js_helper#_addHashTableEntry","whenTrue","isEmpty","scanner.dart#_multiLineComment","iterable_set.dart#_base","dart.async#_checkState","dart.async#_captured_future_3","dart.async#_inCallback","expanded.dart#_captured_this_0","files","splitMapJoin","toFilePath","internalRemove","toolString","stream_queue.dart#_failClosed","_interceptors#_toListFixed","group.dart#_captured_platform_0","lazy_trace.dart#_captured_this_0","remaining","dart.core#_captured_portStart_1","parser.dart#_conditional","equals_matcher.dart#_match","dart.core#_pathSegments","firstWhere","floor","padLeft","stack_zone_specification.dart#_captured_R_5","trace.dart#_captured_longest_0","onMessage","engine.dart#_addedSuites","dart.core#_captured_host_0","engine.dart#_captured_skipped_1","expanded.dart#_color","stack_zone_specification.dart#_run","dart.core#_mergePaths","getText","declarer.dart#_trace","subscription_stream.dart#_captured_handleError_1","dart.core#_isHttp","expanded.dart#_lastProgressPassed","month","apply","invoker.dart#_captured_outstandingCallbacksForBody_1","dart.async#_badEventState","metadata.dart#_captured_validVariables_0","canonicalizePart","toRadixString","dart.collection#_cell","dart.core#_simpleMerge","remote_listener.dart#_runLiveTest","stream_queue.dart#_addRequest","dart.collection#_removeHashTableEntry","validate","queue_list.dart#_table","future_group.dart#_pending","matchesErrorTest","dart.async#_removeListener","hasErrorTest","expanded.dart#_onDone","dart.async#_onPause","packageConfigUri","expanded.dart#_lastProgressSkipped","engine.dart#_box_0","rti#_check","isRelative","platform_selector.dart#_captured_selector_0","metadata.dart#_retry","_js_helper#_input","nextIteration","expanded.dart#_timeString","pointSpan","variableName","dart.core#_schemeCache","insert","day","lazy_trace.dart#_captured_predicate_1","putIntoMap","live_test_controller.dart#_state","lines","dart.async#_recordCancel","dart.async#_sendError","_js_helper#_newHashTable","removeFirst","pool.dart#_runOnRelease","source_maps.parser#_findColumn","dart.async#_removeListeners","trim","stream_queue.dart#_close","queue_list.dart#_head","_js_helper#_index","isDartVM","stream_sink_completer.dart#_sink","virtualChannel","listeners","dart.core#_host","stream_queue.dart#_subscription","bindCallbackGuarded","containsSeparator","inMinutes","endColumn","stream_channel_completer.dart#_streamCompleter","right","hasAbsolutePath","_js_helper#_re","varData","onComplete","dart.collection#_get","toUri","dart.core#_fragmentStart","suite_channel_manager.dart#_outgoingConnections","hasPort","dart.collection#_modified","runtime","getLine","highlighter.dart#_countTabs","_js_helper#_nativeAnchoredRegExp","dart.async#_waitsForCancel","run","_js_helper#_captured_ex_0","errorZone","foundResult","engine.dart#_onSuiteAddedController","dart.async#_captured_future_2","stream_completer.dart#_setSourceStream","suite_channel_manager.dart#_incomingConnections","declarer.dart#_setUpAlls","getColumn","dart.collection#_element","dart.async#_errorTest","_js_helper#_argumentsExpr","schedule","dart.collection#_captured_result_0","stream_channel_completer.dart#_sinkCompleter","dart.async#_eventScheduled","highlighter.dart#_writeTrailingLines","rootLength","live_suite_controller.dart#_captured_liveTest_1","normalize","invoker.dart#_closableKey","live_test_controller.dart#_controller","isSync","dart.convert#_parent","source","engine.dart#_runLiveTest","dart.async#_isPendingComplete","source_maps.parser#_captured_line_0","copyList","dart.convert#_writeSurrogate","remote_listener.dart#_serializeTest","dart.convert#_fillBuffer","toJson","highlighter.dart#_writeLastLine","addOutstandingCallback","_interceptors#_codeUnitAt","chainFor","~/","dart.collection#_addHashTableEntry","package","isHeadless","completeError","verboseChain","declarer.dart#_parent","stream_group.dart#_subscriptions","listen","describeMismatch","closed","stream_queue.dart#_streamQueue","declarer.dart#_runSetUps","pretty_print.dart#_captured_indent_0","dart.typed_data.implementation#_checkPosition","declarer.dart#_prefix","stream_completer.dart#_linkStreamToController","setSourceStream","targetUrl","_js_helper#_message","inMilliseconds","dart.async#_previous","dart.js_util#_captured__convertedObjects_0","declarer.dart#_entries","dart.async#_setPendingEvents","stack_zone_specification.dart#_captured_node_2","dart._internal#_length","invoker.dart#_guardIfGuarded","done","declarer.dart#_platformVariables","highlighter.dart#_isOnlyWhitespace","isJS","isEof","sourceLine","dart._internal#_f","isBroadcast","invoker.dart#_captured_invoker_0","remote_listener.dart#_box_0","declarer.dart#_tearDowns","dart.async#_close","multi_channel.dart#_nextId","remote_listener.dart#_captured_liveTest_0","engine.dart#_closed","highlighter.dart#_writeText","matchAsPrefix","invoker.dart#_guarded","lazy_trace.dart#_inner","_js_helper#_unlinkCell","live_suite_controller.dart#_failed","stack_zone_specification.dart#_box_0","lazy_chain.dart#_captured_this_0","relativePathToUri","dart.async#_isChained","newJsMap","pool.dart#_allocatedResources","highlighter.dart#_color","dart.async#_mayAddEvent","group.dart#_map","multi_channel.dart#_captured_this_1","dart.collection#_computeHashCode","dart.async#_complete","dart.async#_captured_result_2","dart.async#_captured_e_1","null_stream_sink.dart#_captured_this_0","remote_listener.dart#_captured_printZone_0","dart.async#_isAddingStream","dart.collection#_newLinkedCell","_interceptors#_shrReceiverPositive","fragment","dart.async#_sendData","dart.dom.html#_pauseCount","runUnary","dart.convert#_upgradedMap","scanner.dart#_scanner","precompiledPath","dart.dom.html#_target","dart.core#_hashCodeCache","runGuarded","span_scanner.dart#_lastSpan","toList","metadata.dart#_verboseTrace","dart.async#_whenCompleteAction","replaceAllMapped","rti#_as","invoker.dart#_captured_counter_3","_js_helper#_nativeGlobalRegExp","declarer.dart#_soloEntries","addSubscription","increment","stack_zone_specification.dart#_captured_R_4","pool.dart#_onResourceReleased","dart.collection#_strings","dart.async#_handle","hasListener","dart.async#_ensureDoneFuture","stack_zone_specification.dart#_handleUncaughtError","remote_listener.dart#_captured_printZone_1","invoker.dart#_invokerZone","_js_helper#_captured_transform_1","pause","runUnaryGuarded","spanFrom","runner_suite.dart#_config","runner_suite.dart#_onClose","dart.async#_zone","stream_sink_completer.dart#_controller","highlighter.dart#_captured_textInside_1","[]","expanded.dart#_lastProgressMessage","invoker.dart#_captured_fn_2","lastPendingEvent","inMicroseconds","visitConditional","dart._internal#_index","stream_sink_completer.dart#_doneCompleter","inSeconds","live_test_controller.dart#_onStateChangeController","rti#_cachedRuntimeType","dart.async#_captured_controller_0","packageResolver","dart.async#_captured_eagerError_2","stack_zone_specification.dart#_captured_T2_4","live_test_controller.dart#_onClose","live_test_controller.dart#_groups","dart.core#_duration","file.dart#_decodedChars","parents","parent","_js_helper#_jsObject","dart.async#_captured_test_0","stream_group.dart#_state","startsWith","dart.collection#_set","absolute","foreign","dart.async#_hasError","merge","handleValue","resolve","rti#_message","stream_queue.dart#_updateRequests","dart.async#_delegateCache","hasFragment","traces","isScheduled","union_set.dart#_iterable","invoker.dart#_onCloseCompleter","isNotEmpty","test.dart#_captured_body_0","hasScheme","engine.dart#_closedBeforeDone","span_exception.dart#_span","dart.async#_captured_cleanUp_1","dart._internal#_source","fuse","live_suite_controller.dart#_suite","invoker.dart#_runTearDowns","dart.async#_captured_elements_0","addStream","rti#_precomputed3","null_stream_sink.dart#_checkEventAllowed","chain.dart#_captured_terse_0","patterns","stream_completer.dart#_setEmpty","dart.core#_fragment","createTimer","variables","runner_suite.dart#_onDebuggingController","dart.async#_captured_protected_0","every","trace.dart#_captured_trace_0","perform","dart.async#_captured_bodyFunction_0","dart.convert#_allowInvalid","pool.dart#_captured_this_0","outputId","dart.async#_onResume","dart.convert#_extraUnits","toUpperCase","equals_matcher.dart#_value","dart.async#_controller","multi_channel.dart#_captured_this_0","engine.dart#_group","guarantee_channel.dart#_addStreamSubscription","queue_list.dart#_add","forEachJsField","_js_helper#_regExp","_js_helper#_nums","_js_helper#_getTableBucket","dart.convert#_computeKeys","stack_trace_mapper.dart#_mapping","millisecondsSinceEpoch","_js_helper#_cell","connectOut","union_set.dart#_sets","engine.dart#_onUnpaused","_js_helper#_genericClosure","stack_trace_mapper.dart#_mapContents","pretty_print.dart#_captured_indent_2","multi_channel.dart#_innerStreamSubscription","substring","entries","multi_channel.dart#_inner","hasRun","stack_zone_specification.dart#_onError","elapsedTicks","engine.dart#_onTestStartedGroup","tearDownAll","core_matchers.dart#_matcher","expanded.dart#_engine","dart.async#_captured_future_0","_js_helper#_captured_getTag_0","names","internalContainsKey","dart.async#_captured_start_2","dart.async#_addStreamState","stream_queue.dart#_extractStream","setState","clear","dart.core#_stop","stream_group.dart#_closed","os","hasPartialInput","dart.collection#_getBucket","declarer.dart#_timeout","parts","context.dart#_pathDirection","findSlot","dart.async#_scheduleMicrotask","engine.dart#_loadPool","stream_sink_completer.dart#_canSendDirectly","local","hour","packageRoot","scanner.dart#_endOfFileEmitted","dart.async#_captured_callback_0","chain.dart#_captured_terse_1","future_group.dart#_closed","dart.convert#_value","readSlot","fork","elementAt","dart.async#_runUnary","writeAll","dart.async#_captured_callback_3","stack_zone_specification.dart#_captured_arg_1","writeSlot","dart.async#_next","rti#_hashCode","stream_group.dart#_onListen","dart.async#_captured_sourceResult_2","runOnce","dart.convert#_reviver","invoker.dart#_captured_this_1","innerStream","lazy_chain.dart#_thunk","stream_queue.dart#_ensureListening","stack_zone_specification.dart#_chains","dart.async#_captured_listener_1","startColumn","status","dart.async#_removeAfterFiring","multi_channel.dart#_box_0","dart.dom.html#_eventType","dart.collection#_head","resume","_js_helper#_removeHashTableEntry","_js_helper#_match","dart.async#_isFiring","includeTags","_interceptors#_current=","intersection_selector.dart#_selector2","rti#_rti","dart.async#_asyncComplete","request","expanded.dart#_gray","stack_trace_formatter.dart#_except","engine.dart#_subscriptions","subscription_stream.dart#_source","stack_trace_mapper.dart#_sdkRoot","dart.async#_recordResume","scheme","dart.convert#_expectedUnits","source_maps.parser#_captured_column_0","dart.collection#_closeGap","highlighter.dart#_buffer","sink.dart#_sink","map","parser.dart#_scanner","rti#_bindCache","dart._internal#_name","stack_trace_formatter.dart#_only","removeEventListener","_js_helper#_setTableEntry","live_test_controller.dart#_close","dart.core#_queryParameters","_js_helper#_length","engine.dart#_captured_this_1","pretty_print.dart#_box_0","addMapping","description.dart#_out","dart.async#_captured_R_3","dart.async#_isClosed","flush","remote_listener.dart#_captured_getMain_1","expanded.dart#_onStateChange","functions.dart#_captured_K1_2","toLowerCase","heartbeat","registerBinaryCallback","_js_helper#_method","dart.collection#_writeToList","contains","removeOutstandingCallback","functions.dart#_captured_value_1","dart.async#_prependListeners","dart.core#_data","chain.dart#_captured_callback_0","guarantee_channel.dart#_inner","dart.async#_fork","_js_helper#_nextIndex","dart.core#_captured_uri_0","source_maps.parser#_maps","dart.convert#_bufferIndex","expanded.dart#_red","dart.collection#_unlinkCell","forEachObjectKey","isRootRelative","engine.dart#_restarted","platform_selector.dart#_captured_validVariables_1","dart.async#_doneFuture","dart.convert#_original","dart.async#_registerCallback=","foldFrames","remote_listener.dart#_captured_channel_3","live_test_controller.dart#_onMessageController","separatorPattern","dart.convert#_isFirstCharacter","stack_zone_specification.dart#_errorZone","addStreamFuture","declarer.dart#_built","rti#_requiredPositional","dart.async#_captured_test_2","dart.collection#_table","_js_helper#_deleteTableEntry","split","group.dart#_captured_callback_0","remote_listener.dart#_listen","source_maps.parser#_mapUrl","validatePlatformSelectors","dart.async#_map","hasEmptyPath","sublist","stream_completer.dart#_stream","invoker.dart#_onRun","dart.async#_subscribe","util.dart#_captured_x_0","stream_completer.dart#_sourceStream","metadata.dart#_chainStackTraces","stream_sink_completer.dart#_setDestinationSink","addTearDownAll","live_suite_controller.dart#_isComplete","dart.async#_captured_result_0","equals_matcher.dart#_captured_expectedElement_1","package_config_resolver.dart#_uri","dart.async#_reverseListeners","dart.collection#_last","invoker.dart#_captured_timeout_0","walk","dart.core#_userInfo","formatStackTrace","remove","dart.async#_captured_listener_2","_js_helper#_keys","dart.convert#_encoder","runBinary","dart.async#_cancelFuture","future_group.dart#_captured_this_0","handlesComplete","trace.dart#_box_0","dart.async#_captured_pos_1","invoker.dart#_test","metadata.dart#_captured_timeout_2","guarantee_channel.dart#_box_0","cancelSchedule","sourceNameId","runtimeType","dart.collection#_modifications","then","pretty_print.dart#_captured_maxLineLength_1","dart.convert#_subsetMask","testRandomizeOrderingSeed","visitOr","expanded.dart#_lastProgressFailed","dart.convert#_first","millisecond","highlighter.dart#_captured_this_1","dart.async#_rootRegisterUnaryCallback","dart.async#_captured_f_1","remote_listener.dart#_captured_this_0","reversed","dart.core#_queryParameterLists","hasErrorCallback","metadata.dart#_captured_testOn_1","left","live_test_controller.dart#_isClosed","highlighter.dart#_captured_this_0","dart.dom.html#_start","lazy_chain.dart#_chain","null_stream_sink.dart#_addingStream","_js_helper#_getTableCell","forTarget","source_map_stack_trace.dart#_captured_minified_2","peekChar","dart.collection#_next","build","dart.convert#_process","rti#_precomputed2","lastMatch","expanded.dart#_description","metadata.dart#_captured_chainStackTraces_5","remote_listener.dart#_captured_printZone_5","decoder","hasAuthority","unaryOnError","context.dart#_needsNormalization","onResume","expanded.dart#_printPath","_interceptors#_tdivSlow","_js_helper#_rest","expanded.dart#_paused","declarer.dart#_tearDownAll","dart.async#_captured_result_3","lazy_trace.dart#_thunk","waitForOutstandingCallbacks","dart.async#_mayComplete","dart.async#_captured_T_5","function","dart.collection#_offset","dart.async#_captured_value_1","bindUnaryCallbackGuarded","dart.async#_sendDone","invoker.dart#_outstandingCallbacks","extensions","dart.async#_closeUnchecked","_interceptors#_toListGrowable","highlighter.dart#_captured_end_2","invoker.dart#_captured_this_0","codeUnits","rti#_precomputed1","stack_zone_specification.dart#_captured_f_1","internalGet","suite_channel_manager.dart#_names","pattern","dart.async#_captured_stackTrace_1","live_suite_controller.dart#_liveSuite","source_maps.parser#_consumeNewLine","metadata.dart#_box_0","suiteSink","dart.core#_port","engine.dart#_passedGroup","dart.core#_hostStart","context.dart#_isWithinOrEquals","expanded.dart#_captured_liveTest_1","live_suite_controller.dart#_closeMemo","dart.async#_captured_target_0","dart.core#_captured_host_1","dart.core#_uriCache","_js_helper#_nativeAnchoredVersion","scanner.dart#_consumeWhitespace","scanner.dart#_scanOr","dart.dom.html#_tryResume","runner_suite.dart#_suite=","toSet","chain.dart#_captured_level_1","sourceColumn","dart.async#_nextListener","connectIn","_js_helper#_isCaseSensitive","invoker.dart#_body","encoder","metadata","dart.async#_isInputPaused","inHours","allowRelease","_js_helper#_captured_getUnknownTag_0","invoker.dart#_completer","intersection","state","dart.async#_state","reportLiveTest","dart.async#_clearPendingComplete","invoker.dart#_captured_timeout_2","stack_trace_mapper.dart#_mapUrl","multi_channel.dart#_controllers","declarer.dart#_tearDownAllTrace","chain.dart#_captured_T_1","highlighter.dart#_box_0","multi_channel.dart#_captured_T_2","expanded.dart#_subscriptions","dart.collection#_captured_V_2","stack_zone_specification.dart#_captured_original_1","subscription_stream.dart#_captured_this_0","stream_queue.dart#_captured_this_0","live_test_controller.dart#_runCalled","group.dart#_testCount","onDone","dart.async#_isInitialState","isEven","_js_helper#_types","root","highlighter.dart#_writeIntermediateLines","library","dart.core#_hasValue","member","dart.async#_lastSubscription=","dartException","dart.core#_schemeEnd","_js_helper#_captured_this_0","isPosix","dart._internal#_hasSkipped","dart.convert#_isUpgraded","dart.async#_print=","dart.async#_rootRegisterBinaryCallback","dart.dom.html#_useCapture","test.src.runner.browser.post_message_channel#_captured_port_0","type","scanner.dart#_scanIdentifier","dart.async#_onDone","origin","multi_channel.dart#_parent","%","_js_helper#_keysArray","span_scanner.dart#_sourceFile","metadata.dart#_captured_skip_3","insertAll","platform_selector.dart#_inner","pretty_print.dart#_captured_pp_0","engine.dart#_captured_this_0","dart.async#_eventState","child","forTag","guarantee_channel.dart#_channel","dart.async#_captured_iterator_0","checkMutable","remote_listener.dart#_captured_controller_3","replaceFirst","file.dart#_binarySearch","transform","stack_trace_formatter.dart#_mapper","_interceptors#_tdivFast","trace.dart#_captured_oldPredicate_0","_js_helper#_exception","stack_zone_specification.dart#_captured_arg2_2","remote_listener.dart#_suite","isIdentifier","rti#_primary","removeAt","dart.async#_captured_div_1","dart._internal#_current=","_js_helper#_current=","dart.dom.html#_removeEventListener","rti#_optionalNamed","dart.async#_isSent","_js_helper#_receiver","forPlatform","dart.async#_delegate","firstPendingEvent","inSameErrorZone","frames","highlighter.dart#_span","remote_listener.dart#_captured_channel_2","dart._internal#_currentExpansion","union_set_controller.dart#_sets","dart.async#_captured_this_0","_js_helper#_isUnicode","lazy_trace.dart#_captured_terse_2","span_exception.dart#_source","dart._internal#_start","_js_helper#_modifications","dart.core#_nextPosition","dart.convert#_toEncodable","hasMatch","dart.async#_canFire","postMessage","internalComputeHashCode","invoker.dart#_outstandingCallbackZones","invoker.dart#_captured_zone_1","rootPattern","multi_channel.dart#_captured_id_1","platform_selector.dart#_span","isUtc","dart.dom.html#_postMessage_2","set","pathFromUri","dart.async#_hasOneListener","engine.dart#_activeLoadTests","_js_helper#_containsTableEntry","restartable_timer.dart#_timer","dart.async#_pendingEvents","guarantee_channel.dart#_addError","_js_helper#_captured_prototypeForTag_0","dart.async#_nullErrorHandler","dart.async#_captured_cleanUp_3","+","dart.async#_chainSource","dart.core#_portStart","remote_listener.dart#_printZone","multi_channel.dart#_captured_T_1","frame.dart#_captured_frame_0","source_maps.parser#_columnStart","functions.dart#_captured_result_0","engine.dart#_addLiveSuite","_js_helper#_pattern","guarantee_channel.dart#_onStreamDisconnected","dart.core#_stackTrace","elapsed","accept","dart.async#_subscription","stack_trace_mapper.dart#_packageResolver","stream_queue.dart#_eventsReceived","_js_helper#_isMultiLine","live_test_controller.dart#_errors","_interceptors#_index","onZero","chain.dart#_captured_chain_0","engine.dart#_runSkippedTest","pretty_print.dart#_captured__prettyPrint_1","removeAll","stack_zone_specification.dart#_captured_arg1_1","dart.async#_callOnCancel","live_suite_controller.dart#_onCompleteGroup","last","runner_suite.dart#_channelNames","sourceUrl","dart.async#_onListen","pool.dart#_resetTimer","engine.dart#_liveSuites","stream_channel_completer.dart#_set","file.dart#_end","dart.async#_captured_value_2","runner_suite.dart#_gatherCoverage","dart.core#_isHttps","dart.collection#_captured_result_1","multi_channel.dart#_closedIds","remote_listener.dart#_captured_channel_0","isNewLine","invoker.dart#_runCount","union_set.dart#_captured_this_0","suite.dart#_runSkipped","live_suite_controller.dart#_skipped","stack_zone_specification.dart#_captured_R_2","dart.core#_isPackage","dart.async#_expectsEvent","metadata.dart#_validateTags","copy","invoker.dart#_captured_error_2","dart.async#_addPending","dart.convert#_stringSink","remainder","guarantee_channel.dart#_inAddStream","pool.dart#_captured_registered_1","runtime.dart#_captured_serialized_0","pool.dart#_onReleaseCompleters","functions.dart#_captured_result_1","inGoogle","runBinaryGuarded","guarantee_channel.dart#_allowErrors","declarer.dart#_captured_body_0","dart.async#_createSubscription","condition","checkGrowable","absolutePathToUri","suite.dart#_runtimes","engine.dart#_captured_loadResource_2","dart.collection#_rest","dart.async#_setRemoveAfterFiring","guarantee_channel.dart#_sink","metadata.dart#_captured_retry_6","context.dart#_current","dart.async#_registerBinaryCallback=","stream_completer.dart#_controller","isCore","highlighter.dart#_captured_line_1","getOffset","dart.async#_createPeriodicTimer","pool.dart#_timeout","mustCopy","dart.async#_firstSubscription","scanner.dart#_next","onTestStarted","scanner.dart#_scanAnd","dart.async#_once","dart.core#_query","config","dart.async#_future","next","style","invoker.dart#_tearDowns","_js_helper#_getBucket","expanded.dart#_stopwatch","engine.dart#_active","dart.async#_rootRun","dart.async#_guardCallback","live_suite_controller.dart#_onTestStartedController","path","dart.async#_target","functions.dart#_captured_K2_0","suite.dart#_knownTags","dart.async#_tick","pool.dart#_onReleaseCallbacks","remote_listener.dart#_captured_suite_0","dart.core#_pathStart","platform_selector.dart#_captured_platform_0","restartable_timer.dart#_duration","test.src.runner.browser.post_message_channel#_captured_portSubscription_1","guarantee_channel.dart#_captured_this_0","setEmpty","dart.typed_data.implementation#_invalidPosition","dart.collection#_containsKey","string_scanner.dart#_lastMatchPosition","metadata.dart#_captured_onPlatform_8","lazy_chain.dart#_captured_predicate_1","dart.async#_addListener","multi_channel.dart#_mainController","guarantee_channel.dart#_captured_this_1","invoker.dart#_box_0","_interceptors#_length","nextKind","dart.collection#_box_0","guarantee_channel.dart#_subscription","addTo","dart.core#_uri","isDone","dart.async#_stateData","setChannel","dart.async#_captured_R_2","stream_channel_completer.dart#_channel=","runes","dart.core#_jsWeakMapOrKey","dart.collection#_queue","null_stream_sink.dart#_closed","file.dart#_lineStarts","stream_queue.dart#_eventQueue","isSeparator","_js_helper#_arguments","guarantee_channel.dart#_disconnected","span_with_context.dart#_context","stream_group.dart#_captured_stream_1","source_maps.parser#_indexFor","dart.async#_cancelOnError","rest","rti#_rest","dart.async#_captured_stackTrace_2","stream_subscription.dart#_source","dart.core#_toFilePath","sourceUrlId","_interceptors#_shrOtherPositive","guarantee_channel.dart#_closed","future_group.dart#_onIdleController","dart.core#_value","dart.async#_captured_error_1","writeCharCode","declarer.dart#_tearDownAlls","source_map_stack_trace.dart#_captured_sourceMap_1","_js_helper#_self","onStateChange","invoker.dart#_timeoutTimer","currentChain","print_sink.dart#_buffer","live_test_controller.dart#_suite","string","engine.dart#_captured_liveTest_1","isBrowser","engine.dart#_suiteController","rti#_canonicalRecipe","dart.dom.html#_canceled","_js_helper#_nativeGlobalVersion","dart.async#_pending","queue_list.dart#_tail","dart.async#_createTimer","passed","dart.async#_onData","dart.async#_captured_action_1","declarer.dart#_captured_body_1","stream_group.dart#_captured_this_0","remote_listener.dart#_captured_liveTest_1","remote_listener.dart#_captured_beforeLoad_4","invoker.dart#_printsOnFailure","dart.core#_writeAuthority","pool.dart#_onTimeout","startChunkedConversion","handleWhenComplete","guarantee_channel.dart#_addStreamCompleter","dart.collection#_captured_K_1","inputId","cloneNotRequired","first","shuffle","engine.dart#_pauseCompleter","newJsList","dart.async#_registerUnaryCallback=","key","_js_helper#_first","dart.async#_captured_T_1","name","dart.dom.html#_postMessage_1","dart.collection#_keys","onPause","dart.async#_captured_data_1","hasQuery","dart.collection#_nums","dart.async#_setErrorObject","dart.collection#_source","handlesValue","stack_zone_specification.dart#_captured_R_3","remote_listener.dart#_captured_channel_1","seen","lazy_chain.dart#_inner","intersection_selector.dart#_selector1","source_maps.parser#_consumeNewSegment","dart.convert#_urlSafe","input","subscription_stream.dart#_captured_stackTrace_2","isRunning","trace.dart#_captured_level_1","impl.dart#_selector","stream_queue.dart#_pause","dart.core#_isScheme","parsed_path.dart#_captured_this_0","declarer.dart#_captured_this_0","stream_completer.dart#_isSourceStreamSet","stream_channel_controller.dart#_local","length","separator","stack_zone_specification.dart#_captured_T_3","subscription_stream.dart#_captured_handleError_0","dart.async#_setChained","expanded.dart#_yellow","equals_matcher.dart#_captured_location_2","cleanupSlots","equals_matcher.dart#_captured_depth_3","suite.dart#_jsTrace","dart.async#_captured_dispatch_1","dart.collection#_end","equals_matcher.dart#_captured_matcher_0","dart.collection#_modificationCount","dart.convert#_processed","pool.dart#_timer","dart.core#_writeString","metadata.dart#_captured_platform_1","string_scanner.dart#_fail","isClosed","keys","isPaused","test_core#_captured_engine_0","declarer.dart#_setUps","expanded.dart#_sink","dart.collection#_grow","text","live_test_controller.dart#_onErrorController","dart.core#_text","dart._internal#_captured_this_0","handlesError","dart.core#_contents","dart.async#_captured_milliseconds_1","source_map_stack_trace.dart#_captured_sdkLib_3","dart.core#_initializeText","chain.dart#_captured_trace_0","rti#_evalCache","equals_matcher.dart#_limit","dart.async#_toggleEventId","live_suite_controller.dart#_active","stack_zone_specification.dart#_createNode","toSpec","userInfo","excludeTags","dart.core#_separatorIndices","test.dart#_captured_completer_1","rti#_is","dart.async#_isUsed","highlighter.dart#_paddingAfterSidebar","code","sink","metadata.dart#_captured_skipReason_7","stream_sink_completer.dart#_destinationSink","future_group.dart#_values","suite.dart#_metadata","engine.dart#_addLoadSuite","invoker.dart#_captured_message_1","values","_js_helper#_nativeRegExp","validator.dart#_isDefined","stream_queue.dart#_isDone","_js_helper#_isDotAll","offset","putIntoObject","copies","dart.async#_runBinary","_js_helper#_start","stream_queue.dart#_source","year","stream_queue.dart#_requestQueue","$le","$indexSet","$index","$xor","$or","$eq","$mod","$shr","$and","$ge","$gt","$lt","$mul","$not","$shl","$div","$sub","$add","$negate","$tdiv","checkString","instanceTypeName","constructorNameFallback","isJsArray","getIndex","selfFieldName","receiverFieldName","_rtiEval","extractFunctionTypeObjectFrom","rawRtiToJsConstructorName","isGenericFunctionTypeParameter","isDartFunctionType","isDartFutureOrType","isNotIdentical","_instanceFunctionType","instanceOf","invoke","setDispatchProperty","propertyGet","regExpGetGlobalNative","stringReplaceJS","checkNull","regExpGetNative","_getFutureOrArgument","_lookupFutureRti","_setPrecomputed1","_getBindCache","_setBindCache","_getGenericFunctionBase","_getKind","_lookupStarRti","_canonicalRecipeOfStar","_Universe._lookupStarRti","_lookupQuestionRti","_canonicalRecipeOfQuestion","_Universe._lookupQuestionRti","_lookupFutureOrRti","_canonicalRecipeOfFutureOr","_Universe._lookupFutureOrRti","_getInterfaceName","_getBindingBase","_getReturnType","_getGenericFunctionParameterIndex","asString","allocate","_setRequiredPositional","_setOptionalPositional","_setOptionalNamed","_setCachedRuntimeType","_setTypeCheckFunction","_setAsCheckFunction","_getPrimary","_setSpecializedTestResource","_setIsTestFunction","isLegacySubtype","_getSpecializedTestResource","_getStarArgument","_getQuestionArgument","_lookupErasedRti","_getEvalCache","_setEvalCache","_cacheSet","_createTerminalRti","_setKind","_setCanonicalRecipe","_createUnaryRti","_setPrimary","_createGenericFunctionParameterRti","_canonicalRecipeOfInterface","_createInterfaceRti","_setRest","_canonicalRecipeOfBinding","_createBindingRti","_canonicalRecipeOfFunction","_canonicalRecipeOfFunctionParameters","_createFunctionRti","_canonicalRecipeOfGenericFunction","_createGenericFunctionRti","charCodeAt","toGenericFunctionParameter","_lookupDynamicRti","_lookupVoidRti","pushStackFrame","push","setPosition","handleTypeArguments","collectArray","arraySplice","handleFunctionArguments","handleOptionalGroup","handleNamedGroup","collectNamed","isDigit","evalTypeVariable","_lookupNeverRti","_lookupAnyRti","_castToRti","stringLessThan","functionParametersEqual","lookupInterceptorByConstructor","cacheInterceptorOnConstructor","_future","_setValue","_isComplete","_setPendingComplete","_mayComplete","_mayAddListener","_chainSource","_setChained","_hasError","_error","_zone","_removeListeners","_cloneResult","_setErrorObject","_scheduleImmediate","_leave","_createPeriodicTimer","printToConsole","es6","tryParse","objectToHumanReadableString","makeListFixedLength","makeFixedListUnmodifiable","_stringFromJSArray","_stringFromUint8List","_writeOne","_startsWithData","_checkLength","_internal","_stringOrNullLength","_writeString","_isZoneIDChar","_isRegNameChar","_isGeneralDelimiter","_isSchemeCharacter","_isUnreservedChar","fromString","_lineStarts","fromList","_incomingConnections","_outgoingConnections","_names","_requestedResources","_onReleaseCallbacks","_onReleaseCompleters","_closeMemo","_completer","AsyncMemoizer._completer","factor","_group","_values","FutureGroup._completer","_suiteController","_onTestStartedGroup","_state","_subscriptions","StreamGroup._subscriptions","_passedGroup","_skippedGroup","_failedGroup","_active","_addedSuites","_onSuiteAddedController","Engine._onSuiteAddedController","_liveSuites","_onSuiteStartedController","Engine._onSuiteStartedController","_restarted","_activeLoadTests","_sets","_errors","LiveTestController.completer","_onStateChangeController","LiveTestController._onStateChangeController","_onErrorController","LiveTestController._onErrorController","_onMessageController","LiveTestController._onMessageController","serializeSuite","_closable","_out","myInlinedMethod","_lineStart","_columnStart","_maps","_mappings","_setUps","_tearDowns","_setUpAlls","_timeout","_tearDownAlls","_entries","_soloEntries","_isTextAtEndOfContext","_chains","_createKey","_currentSpec","_createNode","withGuarantees","_child","_onCompleteGroup","_onCloseCompleter","LiveSuiteController._onCloseCompleter","_onTestStartedController","LiveSuiteController._onTestStartedController","_passed","_skipped","_failed","_toListGrowable","_mainController","_controllers","_pendingIds","_closedIds","Window.onMessage","jsify","listToString","_handleIEtoString","_codeUnitAt","_currentExpansion","_types","_getBucket","_isMultiLine","_isUnicode","_isTrailSurrogate","_rtiBind","_addListener","_isFiring","_setRemoveAfterFiring","_isEmpty","_isAddingStream","_expectsEvent","_hasOneListener","_errorTest","_onError","thenAwait","_setError","_isPendingComplete","_clearPendingComplete","_whenCompleteAction","_onValue","_isInitialState","_mayAddEvent","_isCanceled","_isPaused","_isClosed","_isInputPaused","_hasPending","_inCallback","_waitsForCancel","_eventScheduled","_isScheduled","_rethrow","_hasTableEntry","identityHashCode","checkValidIndex","_grow","_checkModification","_isUpgraded","parseHexByte","withBufferSize","unary-","_microseconds","_checkType","_getFromObject","_setOnObject","_now","_isWindows","_toFilePath","_initializeText","_writeAuthority","_isPackage","convertDartToNative_SerializedScriptValue","_canceled","fromMillisecondsSinceEpoch","isJavaScriptSimpleObject","_isSourceStreamSet","_setSourceStream","_NextRequest._completer","_pause","_close","_setEmpty","_scanOr","_scanAnd","_scanIdentifier","_setBase","StringDescription.add","addStateInfo","_indent","reset","_onResourceReleased","_consumeValue","glyphs","_paddingAfterSidebar","_normalizeContext","_buffer","Highlighter._","dataFromString","_disabled","_doneCompleter","_GuaranteeSink._doneCompleter","_inAddStream","MessageEvent.data","_prefix","_solo","Declarer._solo","Invoker._onCloseCompleter","_closableKey","_outstandingCallbackZones","_counterKey","_printsOnFailure","_AsyncCounter._completer","_guardIfGuarded","_print","_run","jsonDecode","_except","_only","_MultiChannel.stream","_eventQueue","_requestQueue","ascii","_sink","_listen","_streamCompleter","_stream","_sinkCompleter","markGrowable","_timeString","_local","_channelNames","watch","ExpandedReporter.watch","_stopwatch","ExpandedReporter._stopwatch","_initTicker","Engine.onTestStarted","provokeCallErrorOnNull","provokeCallErrorOnUndefined","provokePropertyErrorOnNull","provokePropertyErrorOnUndefined"],"mappings":"A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAuEUA;mDACKA;QACTA,OAUJA,uHAPAA;MADEA,OANFA,uFAOAA;K;mBCmBEC;MAAaA;;MAKHA;MACZA;QAAgBA,YAIlBA;MAHgBA;MACdA;QAAgCA,kBAElCA;MADEA,SACFA;K;sBCuIEC;MACaA;MACXA;QACaA;QACXA;UACEA,kBAAUA;;MALhBA;IAQAA,C;mCA6GQC;MACOA;QACXA,OAsBJA,sIAnBAA;MADEA,OAGFA,wGAFAA;K;oCAmhBkBC;MAAeA,OCjWjCA,8BDiW6DA;K;kCAE3CC;MAAaA,OCnW/BA,qCDmWkEA;K;iCAEhDC;MAAYA,OCrW9BA,oCDqWgEA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCEv0BpDC;MACVA,sBAAUA;IACZA,C;kBC+KYC;MA/LZA;MAAAC;MAgMAD,SACFA;K;mBC1GOE;MACcA;MACnBA;QAAyBA,gBAG3BA;MADEA,mBACFA;K;mBA6GKC;MACHA;;uBAEMA;QAAJA;UAAoBA,aAGxBA;;MADEA,OAAcA,oDAChBA;K;OAEOC;MACLA;;QAAqBA,YAgBvBA;MAfEA;QACEA;UAEEA,iBAYNA;aAVSA;QACLA,aASJA;WARSA;QACLA,cAOJA;WANSA;QACLA,aAKJA;MAHYA;MACVA;QAAoBA,sBAAMA;MAC1BA,UACFA;K;+BAmIaC;uBAELA;MAAJA;;;;MAIAA,WACFA;K;yBAEWC;MAAQA;MAs5BnBA;QAAsBA,kBAAMA;MA94BtBA;MAAJA;QAIEA,YA0DJA;MAxDwBA;gCAAKA;MAApBA,2CAAeA;MACtBA;QACEA;UAEEA,2BAoDNA;iBAlDQA;UAEFA,2BAgDNA;QA9CIA,YA8CJA;;MAxCEA;QACEA,sBAAUA;MAEZA;QAEEA,2BAmCJA;MA/BEA;;mCAmBSA;;4BAEwBA,gBAA/BA;UACsBA;YAElBA,YAORA;;MADEA,8BACFA;K;+BAiDcC;MAEHA;MAAPA,SAKJA;K;sCAyEcC;MACRA;MC6FCA,uBD3FoCA;QACvCA,sBCyFMA,6BDvDVA;MA/BoBA,2DAEPA;QAiBgBA,gBEpXDA;QFoXpBA;UAAoCA,mBAY5CA;6BAV6CA;QAAzCA;wCAEMA;UACAA;YACFA,sBAMRA;;;MADEA,OCyDKA,eADGA,6BDvDVA;K;qCAEYC;MACRA;eAA8CA;K;wBAQvCC;MAAaA,iBAAwBA;K;2BAEpCC;MACVA;WAAIA;QAAwBA,MAY9BA;;MATeA;MACbA;QAAgDA,MAQlDA;MANMA;MAAJA;QAAoBA,MAMtBA;2BAJMA;MAAJA;QAAyBA,MAI3BA;;QAH6DA,MAG7DA;;MADeA;IACfA,C;2BAKcC;;QAIVA,yBAIJA;MADEA,WACFA;K;mCAOcC;MAEIA;;MAChBA;QACEA,6CAcJA;MAXEA;QACkBA;QAOZA;;;MAENA,aACFA;K;qCAEcC;MACOA;;MACnBA,4BAAcA,4CAAdA;;;UACiBA,sBAAMA;QACrBA;UACEA;aACKA;UACLA,oCAAqBA;UACrBA;;UAEAA,sBAAMA;;MAGVA,OAAOA,kCACTA;K;oCAEcC;MACZA;MAAcA,oDAAdA;;;UACiBA,sBAAMA;QACrBA;UAAWA,sBAAMA;QACjBA;UAAgBA,OAAOA,4CAG3BA;;MADEA,OAAOA,gCAAmBA,qCAC5BA;K;0CAGcC;MAGZA;wDAAuDA;QACrDA,iDAcJA;MAXEA;QACkBA;QAOZA;;;MAENA,aACFA;K;mCAEcC;MACZA;MAAMA;;MAANA;QACEA;UACEA,oCAYNA;QATIA;UACaA;UAGXA,oCADqBA,0EAM3BA;;;MADEA,sBAAUA;IACZA,C;6BAyFOC;;yCGphB2BA;MHyhBhCA,oBACFA;K;wBAmBOC;MAEwCA;MAD7CA,SAGFA;K;yBAKOC;MAEwCA;MAD7CA,SAGFA;K;uBAKOC;MAEyCA;MAD9CA,SAGFA;K;yBAKOC;MAE0CA;MAD/CA,SAGFA;K;2BAKOC;MAE4CA;MADjDA,SAGFA;K;2BAKOC;MAE4CA;MADjDA,SAGFA;K;gCAKOC;MAGgDA;MAFrDA,SAIFA;K;4BAoBOC;MACwBA;QAC3BA,sBAAMA;MAERA,kBACFA;K;4BAEYC;MACmBA;QAC3BA,sBAAMA;;IAGVA,C;SA0QFC;MACEA,sBAAMA;IACRA,C;WAQAC;MACEA;QAA+BA;MAC/BA,sBAAMA;IACRA,C;wBAKMC;MACJA;;QAAmBA,OHpkCnBA,4CG6kCFA;MARMA,8BAAmBA;MAGvBA;QAAiBA;+BAAMA;QAANA;;QAAjBA;;QACEA,OAAWA,oDAIfA;MADEA,OAAWA,+BACbA;K;wBAKMC;MACJA;MAGAA;QACEA,OHhgCFA,yDG4gCFA;MAVEA;QAIEA;UACEA,OHvgCJA,yDG4gCFA;MADEA,OHlmCAA,2CGmmCFA;K;wBAOcC;MACZA,OH3mCAA,6CG4mCFA;K;cAQIC;MACFA;QAAmBA,sBAAMA;MACzBA,YACFA;K;mBAsBAC;MACEA;;QH1rCAA;MG6rCkCA;;MAElCA;;;;QAqBOC;MAPPD,cACFA;K;qBAGAC;MAGEA,wCACFA;K;qBAMAC;YACwBA;IACxBA,C;sCAmCAC;MACEA,sBAAUA;IACZA,C;qCAqJSC;MAAcA;MAcTA,iCAAqBA;MAO3BA;MAAJA;QAA2BA;MA2BvBA;MAAWA;MAAeA;MAAMA;MAAQA;MAD5CA,OArHFA,+SAsHwDA,uHACxDA;K;yCAMcC;MAmDZA,OAA8BA;;;;;;;mBAChCA;K;6CAkCcC;MASZA,OAA8BA;;;;;;mBAChCA;K;gBAmCAC;;IACgEA,C;0BAahEC;;;;IAGuEA,C;qBAmCzEC;MAIgBA;;MAYdA;QAAgBA,YAkHlBA;MAhHWA;QAAPA,mBAAyBA,eAgH7BA;MA9GEA;QAA6CA,SA8G/CA;MA5GEA;QACEA,OAAOA,2BA2GXA;WA1GSA;QACLA,SAyGJA;kBAhFwCA;;mBATlBA;;QACMA;UAKtBA;;cAEIA,OAAOA,UACCA,uBAAsBA,sDAgFxCA;;;cA7EUA,OAAOA,UACCA,aAAYA,sDA4E9BA;;;MAvEEA;QAI8BA;QACMA;QACFA;QACOA;QACNA;QACOA;QACJA;QACOA;QACNA;QACOA;QAC/BA;QAAbA;UACEA,OAAOA,UAAmBA,uBAAoBA,wCAwDpDA;;UAvDwBA;UAAbA;YAMEA;YAAPA,iBAA0BA,uBAAoBA,wCAiDpDA;;YAhDwBA;YAAbA;cACMA;cADNA;gBAEMA;gBAFNA;kBAGMA;kBAHNA;oBAIMA;oBAJNA;sBAKMA;sBALNA;wBAMMA;wBANNA;0BAOMA;0BAPNA;;;;;;;;;;;;;;;;cAQLA,OAAOA,UAAmBA,aAAUA,wCAwC1CA;;;QAlCIA,OAAOA,UApHTA,oEAsJFA;;MA9BEA;;UAEIA,OH3yCEA,0BGu0CRA;;;;;;;SApBQA;QAGJA,OAAOA,UH7tDTA,wHG8uDFA;;MAbEA;QAIEA;UACEA,OH/zCEA,0BGu0CRA;MADEA,SACFA;K;2BAqBWC;MACTA;;QACEA,gBAAiBA,WAOrBA;MALEA;QAAuBA,OAUvBA,4BALFA;uBAHMA;MAAJA;QAAmBA,YAGrBA;MADEA,gCAMAA,4BALFA;K;oBAmBIC;MACFA;QACEA,OAAcA,uBAIlBA;;QAFIA,OAAkBA,mCAEtBA;K;oBAIAC;MIz3BeC;;MAPFD;;MJq4BXA;QACoCA;QIp5B9BA;2BJs5BGA;QAD6BA;QIr5BhCA;QJs5BJA,sCAAcA;;MAEhBA,aACFA;K;oBAGAE;MIv4BeD;;MAPFC;;MJk5BXA;QIh6BMA;QJi6BJA;;MAEFA,aACFA;K;mBAEAC;MAIaA;MAFHA;;UAEJA,OAAOA,gBAWbA;;UATMA,OAAOA,oBASbA;;UAPMA,OAAOA,0BAObA;;UALMA,OAAOA,gCAKbA;;UAHMA,OAAOA,sCAGbA;;MADEA,sBK18DAC;IL28DFD,C;4BAIAE;MACEA;;QAAqBA,WAkBvBA;yBAhByBA;MAAvBA;QAAkCA,gBAgBpCA;;;;;OAF0CA;;MACxCA,gBACFA;K;yBA+CSC;;6BAwB2CA;4BAiFlBA;8CAoY5BA,6DA0BJA;;;;;;;cAzbcA;QACAA;0BAAeA;;;;;;;MAU3BA;QACeA;;;;QAcOA;;MANhBA;;;MAQNA,uDAA8BA,SAA9BA;wBACaA;2BAGPA;QAAJA;UAC2BA;;;QAG3BA;;;;;;;;MAaFA,mBACFA;K;6CAyCOC;MAELA;;QAOEA;;;;gDA4BJA;MApBEA;QAEEA;UAEEA;;QAKFA;;;;uCAWJA;;MADEA;IACFA,C;4BAEOC;qBAeGA;MAVRA;;UAEIA;;;;8BAsENA;;UA5DMA;;;;8BA4DNA;;UAlDMA;;;;8BAkDNA;;UAxCMA;;;;8BAwCNA;;UA9BMA;;;;8BA8BNA;;UApBMA;;;;8BAoBNA;;UAVMA;;;;+BAUNA;;K;2BAIOC;MACLA;;QAAmBA,OAAOA,uDAmC5BA;0BAhCkDA;uBAOpBA;iCAFYA;MAApBA;MAEPA;MAAbA;QACEA,OAAOA,yDAwBXA;MArBEA;cAE2BA;;0BAAeA;;QAK1BA;;cAyQZA;QA7QFA,8EA8QqBA,+EAzQMA,yBAa/BA;;MApCoBA;;YA6BFA;;wBAAeA;;MAA/BA;;YAkQIA;MAjQJA,8EAkQuBA,uDA9P+BA,2CAExDA;K;uCAEOC;qBAoBGA;uBACAA;MAfRA;;UAIIA,sBAAUA;;UAEVA;;;;wCA+ENA;;UApEMA;;;;wCAoENA;;UAzDMA;;;;wCAyDNA;;UA9CMA;;;;wCA8CNA;;UAnCMA;;;;wCAmCNA;;UAxBMA;;;;wCAwBNA;;UAbMA;;;;;;4CAaNA;;K;sCAEOC;;cA4JDA;MAAJA;QACuBA;YAQnBA;MAAJA;QAC2BA;0BAhKqBA;uBAOpBA;iCAFYA;MAApBA;MAEPA;MAAbA;QACEA,OAAOA,oEAuBXA;MArBEA;QAKwBA,wDAAWA,2BAAeA;cACrCA;;0BAAeA;;QAL1BA,oCAoBJA;;MArC+BA;+EAtG7BF,AAuIsBE;MACAA,0EAAWA,2BAAeA;YACrCA;;wBAAeA;;MAL1BA,oCAOFA;K;wBAqBFC;MAEEA,OAAeA,oHAQjBA;K;6BAmESC;MACLA,OCttEeC,iDAmBDD,sBDmsEuBA,gBACvCA;K;wCAEOE;MACLA,OC1tEeD,iDAmBDC,sBDusEuBA,oBACvCA;K;yBAGOC;MAAgCA,cAAQA,MAAKA;K;6BAK7CC;MAAoCA,cAAQA,UAASA;K;oCAwB9CC;MA1EdA;;gBA4EsBA;qBAEMA,gBAA1BA;qBACaA;;UAETA,YAGNA;;K;yBAgGFC;MAEEA;QAAmBA;MACnBA,YACFA;K;2CAqNAC;MACMA;MACJA;qBAEyCA;QAAvCA;UACEA,kBAAeA,+BAMrBA;;UAJMA,qBAINA;;MADEA,WACFA;K;8BA2EEC;2DACoCA,2CACtBA,6EAFdA;IAEyEA,C;sBAoBpEC;MACLA;;QAhHOA,6DADWA;QAmHhBA;UACEA,OAAOA,yCAKbA;QAHIA,gBAGJA;;MADEA,OAAkBA,kCACpBA;K;gBAYKC;MAEHA;QAAuBA,YAGzBA;MAFgBA;QAASA,iBAEzBA;MADEA,sBAAUA;IACZA,C;iBAIKC;MACHA,sBAqXAA;IApXFA,C;kBAKKC;MACCA;QAAuBA,sBAAUA;IACvCA,C;qBAYKC;MACHA,sBHnhFAA;IGohFFA,C;mBAKEC;;IAA0BA,C;2BA4CrBC;MAELA,gCACFA;K;wBIvjGOC;MACLA;;MAOAA,aACFA;K;wBAMAC;MACEA;QAAoBA,WAGtBA;MADEA,iBACFA;K;6BAGAC;MAGEA,OAAOA,wBAAWA,SADgCA,wBAClBA,6BAClCA;K;yBAuDOC;MACLA,OAAOA,iCACTA;K;0BAEOC;MACLA;;QACEA,gBAiCJA;MA/BEA;QACEA,aA8BJA;MAg3BeA;QA14BXA,OArBiBA,mBJ5C8CC,GAAjEA,SI6CoBD,wCA8CtBA;MAxBEA;QAEEA,OAAOA,mBJrETA,MI2FFA;MApBEA;QACEA,gBAmBJA;MAsrBmCA;MAvsBjCA;QACMA;sEAC+DA;UACjEA,wCAcNA;2BAZ4CA;QAAOA;QAArCA;4CAAcA;QAAxBA,OAAUA,uBAYdA;;MJzHuBA;;QAGwBA;;QIs+BhCC;MJz+BQD;MI+GrBA;QAEEA,OAAOA,4CAQXA;MJ9GuBA;QAGwBA;;QI29BhCC;MJ99BQD;MIwGrBA;QJxGqBE;UAGwBA;;UI29BhCD;QJ99BQC;QIgfGF;QAtYtBA,qBAAmBA,6EAIvBA;;MADEA,6BACFA;K;2BAaOG;MACEA;MAIPA;uBAQeA;QANbA;UAC2BA;;;6CAEWA;+BAEVA;0BACLA,iBAAvBA;UACEA;QAKFA;UACEA;6BACgDA;UAAOA;UAArCA;8CAAcA;UAAhCA,uEAAkBA;8BAEHA;gDAi2ByCC;YA91BpCD;;QAGtBA;;QAoEQA;;;MA1DSA,8DAAqBA;MAQxCA;wBAEuBA;4BAArBA;;UAEmBA;;;QAUnBA;QAAmBA;;MAFrBA;+BAIuBA;QAFrBA;mCAEAA;;UAEmBA;;QAGnBA;;MAMFA;4BAIkCA;QAFhCA;QAEoBA,gDAApBA;;UAEmBA,6GAEGA;;QAGtBA;;MAGFA;;MASAA,sEACFA;K;oBASOE;MACLA;;QAAmBA,SAerBA;MAwuBeA;MAxvBMA;MDoOnBA;MC9NAA,4DA2uBWA,0CA3uBXA;;QA6tBMA;wBAztBAA;QAAJA;;QAGaA;;MAEfA,aAAUA,0BACZA;K;oBA6CKC;MHmVoBA,6BAsiEaC;MGx3EJD,OHoWzBA,kCADoCA,6BGjW7CA;K;gBAMAE;MACEA;QAA0BA,iBAiB5BA;MAlBUA;2CAkrBKA;MAtCwBA;MAvoBrCA;QAA0BA,WAa5BA;MAgqBeA;QAvqBXA,mBAOJA;MALEA;QAEEA,OA6nBmCA,0CA1nBvCA;MADEA,iBACFA;K;sBAoHAC;MAIEA,OAAOA,+BAvaAA,aAoaWA,0BApaAA,SADgCA,mBAClBA,+BAwalCA;K;cAqgBOC;MAAQA;2CAkCAA;MA/BbA,4CACFA;K;oBFn+BKC;;IAQLA,C;+BAoEAC;MAAyBA;;MAEhBA,6BAAMA;gBAIYA,+BACrBA;MAAJA;;QAAoBA,eAkEtBA;;qBAjEgCA,+BAC1BA;MAAJA;QAAyBA,kBAgE3BA;+CA3DMA;MAAJA;QACEA,6BAAMA;QACNA;oBAEuBA,+BACjBA;UAAJA;;YAAoBA,eAsD1BA;;yBArDgCA,+BACtBA;UAAJA;YAAyBA,kBAoD/BA;;;;MA9CEA;QAQEA,WAsCJA;oCA9BoCA;gBAD9BA;MAAJA;QACWA;SACGA;;QACZA,eA4BJA;;MAzBEA;SACcA;QACZA,kBAuBJA;;MApBEA;QACyBA;8BIvHrBC;QJuHFD,WAmBJA;;MAhBEA;QACEA,OAAOA,sCAeXA;MAZEA;QAEEA,sBAAUA;;QAMaA;8BItIrBC;QJsIFD,WAIJA;;QAFIA,OAAOA,sCAEXA;K;wBAYAE;MAE+CA;sEAAhCA;MAEbA,kBACFA;K;4BAEAC;MAGEA,OAAOA,2FACTA;K;+BAEAC;wCAIkCA;MAAvBA;QAAPA,4CAIJA;;QAFIA,OAAOA,oDAEXA;K;wBAeKC;oBACSA;QAAwBA,MAGtCA;;MADEA;IACFA,C;gCAGKC;MAA0BA;;;MAI7BA;gBA7PyBC,AAmQwCD;;MAEjEA;;;;QAGEA,oBAAyBA,SAAzBA;oBACYA;UACEA;UACZA;YAEeA,6CAA+BA;YAC5CA;;;;;;;MAYNA,oBAAyBA,SAAzBA;kBAEyCA;;gCAEQA;;;;;;;;IAOnDA,C;eAmCKE;MAOiEA;iBAL1CA;MAiBlBA,iCACJA,cALIA,yBAAsBA,cAFtBA,yBADsBA,cAAtBA,yBAAsBA,cADtBA,yBAAsBA,cADtBA,yBAAsBA,cAHtBA,wBAAsBA,CAD1BA,cAA+CA;MAqBnDA;QAE2CA;QAAzCA;UAGyCA;;UACvCA;sCAE2CA;YAAzCA;cAoBkBA;;;;;;MATPA;MAEbA;MAEAA;IACNA,C;2BAEAC;MAEEA,OAAwBA,2BAC1BA;K;+BK3USC;;;;;;;;;;;;SA0BiCA;MAAtCA;QAA+CA,aAKjDA;MADEA,sBAAUA,gDAA0CA;IACtDA,C;2BAuEAC;MAAoBA;qBAEkBA;MAFtCA;IAGAA,C;6BC3EFC;MACEA;;QACEA,+CAOJA;;QAL0BA;kBDOUA;QCPhCA,kBAKJA;;QAFWA,6BADMA;QACbA,QCqUsBA,kBDnU1BA;;K;uBAOOC;;QASHA,yCAGJA;MADEA,kBACFA;K;0BAEAC;MACcA;MACZA;QAAmBA,eAIrBA;MADEA,OAAOA,6CD6C6DA,OC7CvBA,QAD7BA,6BAElBA;K;0BAIAC;;QAIIA,oDAGJA;MADEA,aACFA;K;+BAEAC;MAAyBA;MAEvBA;QACEA,OAAOA,iEAWXA;;QD1J4BA;;QCoJxBA,sCA5CEA,iCAkDNA;;MR8mCEA;QAAoBA,kBAAMA;MQ/mC1BA;IACFA,C;qCAMOC;MAELA;;QACEA;UACEA,kBA+BNA;0BA5B0BA;QAEtBA;4BACeA;QAGfA,sCAsBJA;;MAhBQA;MACJA;QAAeA,eAenBA;kBARiBA;QAEXA,gDAMNA;MADEA,wBAAiCA,WAFpBA,uCAxFTA,iCA2FNA;K;qBAOOC;MAAkCA,aAAMA;K;mCAE/CC;MACEA;MASYA;QACVA,sBAAUA;MAIQA,kDDcpBC,4BAT4BD,QAAKA,wBAASA,mCCL1CA;eDgB2BA;eCfoCA;;QL6U9CA,cK7UFA,kBAAWA,6DL6UTA,IK5UFA;;;ML4UEA,cKzUJA,kBAAWA;MACxBA,sCACFA;K;iCAmDAE;MACEA;;QACMA;QACJA;UAAeA,eAcnBA;QAZIA,OAAOA,8DADmBA,qBAa9BA;;;QATIA,kDDvS6CA,gBCkH3CA,oCAuLIA,kEAOVA;MRk+BEA;QAAoBA,kBAAMA;MQt+BAA;MAAVA,sCAAmDA;MAC9DA;QAAoBA,eAG3BA;MAFwBA;MACtBA,OAAOA,4CAA4BA,mBAAaA,6BAClDA;K;iCAcOC;MAIIA;iBAAmBA;MAA5BA,oCACFA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBE8CKC;MACsBA,WAM3BA;K;6BAkhBwBC;MAClBA,yBAA6CA;K;sBAo3B9CC;MACHA;QACEA,sBAAMA;IAEVA,C;sBASIC;MACFA;;;UAEUA;;UAFVA;;;;QAIEA,sBAAMA;MAERA;QAAiBA,cAEnBA;MADEA,UACFA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCT7pDaC;MAAsBA;;kBAG3BA;MAAJA;QAoI6BA;QA46C2BA,YAhkDpDA,yEAmkDYA;;MA/iDhBA,aACFA;K;gCAyDYC;oBAENA;MAAJA;QACEA,OAAOA,0CAGXA;MADEA,iCACFA;K;oCAqCeC;MAA0BA;MAIvCA,gBACFA;K;8BAOeC;MAAoBA;MAEjCA,gBACFA;K;gCAsB2BC;MAAsBA;MAE/CA,gBACFA;K;mCAOeC;MAAyBA;MAEtCA,gBACFA;K;6BAiDcC;iBACGA;MADgBA;;MAG/BA,QACFA;K;cA8DEC;MACFA,OAAiBA,2CACnBA;K;qCAeIC;MAMFA;;QAAgCA,WAiBlCA;MAhBmBA;MACOA;MARSA;gCA9FWA;MA0G5CA;QAEwCA,0BA1GlCA;0BAUWA;MADgBA;;MAoGAA;MAC7BA;MAAJA;QAAmBA,YAKrBA;MAnKoCA;MA+JxBA;;MAGVA,UACFA;K;kBAUIC;;;gBAzR+CA;;MA2RjDA;;;;;;UAMIA,UAsENA;;wBAlEiCA;UAAvBA;UACJA;YAAwDA,UAiE9DA;kCAjMmBC;UADgBA;;UAkI7BD,OAonCiDA,uEApjCvDA;;wBA5DiCA;UAAvBA;UACJA;YAAwDA,UA2D9DA;kCAjMmBE;UADgBA;;UAwI7BF,OAinCqDA,uEAvjC3DA;;wBAtDiCA;UAAvBA;UACJA;YAAwDA,UAqD9DA;kCAjMmBG;UADgBA;;UA8I7BH,OAinCqDA,uEA7jC3DA;;UAlD0CA;UACQA;UAE5CA;YAEEA,UA6CRA;UA1SiCA;UA8P3BA,OAAiBA,2FA4CvBA;;UA9R4BA;oBAsPwBA;UAAvBA;UACAA;UAEnBA;UACJA;YAC0DA,UAmChEA;UAlCMA,OAAiBA,gFAkCvBA;;UArQ2BA;0BAwOMA;UAAvBA;UACyCA;UAEzCA;UAEJA;YAE6DA,UAsBnEA;UArBMA,OAAiBA,gGAqBvBA;;UAlB0BA;;UAGhBA;UA5O0BA;oBA8OgBA;UAAvBA;UACvBA;YACgDA,UAWtDA;UAVMA,OAAiBA,qFAUvBA;;UAjP8CA;qBA2OpCA;UAAJA;YAAmBA,WAMzBA;UALMA,mCAKNA;;UAHMA,sBAAMA;;IAGZA,C;uBAEOI;;;;MAKLA;sBAE+CA;QAAvBA;QACtBA;;;;MAKFA,kCACFA;K;uBAEOC;;4BAIEA;MAJeA;;MAMtBA;uBAutEsDA;wBAptEPA;QAAvBA;QACtBA;;;;;MAMFA,oCACFA;K;oCAGoBC;MAKdA;+CAA4BA;;+CAIAA;yCAA5BA;0CAI4BA;oCAA5BA;MACJA;QAGEA,yBAQJA;MAtPMC;YAUSD;YAQAA;YAiBAA;MAkNbA,aACFA;K;yBAWIE;6BAGEA;MAAJA;QACEA;UACEA,OAAOA,kCAKbA;QAHIA,2BAGJA;;MADEA,WACFA;K;4BAOIC;MACFA;MAAQA;+BAypE4BlD;UAppEtBkD;UACVA;YAAiBA,UAIvBA;;MADEA,OAAOA,sBACTA;K;kBAKIC;MASFA;6BAioEoCC;QA7kEGD,YAAhCA;QAnDLA,iEASJA;;;QALIA,OAAOA,4BAKXA;MADEA,OAAOA,+BADWA,0BAEpBA;K;wBAIIE;sBAqBEA;;MAAJA;QAAiBA,iBAUnBA;;QALIA,iBAKJA;MADEA,UACFA;K;mBAKIC;MAEqCA,gBAAhCA;MAAPA,iEACFA;K;kCAOIC;iCAE0BA;4BACxBA;MAAJA;QAAmBA,YAErBA;MADEA,OAAOA,0DACTA;K;sCAGIC;MAckBA,gDA+iEgBxD;;;MA5iEpCwD,UACFA;K;2BASIC;;;oBAGwBA;oBACNA;MAApBA;QAtViBA;;QAyVfA,UAGJA;;MADEA,WACFA;K;uBAQKC;oBAECA;MAAJA;QAAkBA,WAOpBA;MADEA,UA/lBMA,sBA4mBNA,gBAZFA;K;iBAGKC;MACHA,OAAOA,oBAjXUA,4CAkXnBA;K;+BAiCKC;;oBA3nB8CA;;MAkjFpBA;;eAtpFvBA,iBAJAA,QA+uB6BA;aAE5BA;mBAneUA;QADgBA;;QAueUA;QAAzCA;;aAEOA;;aAEAA;;aAEAA;;aAEAA;;;UAvlBsBA;sBAnBWC;UA8mBlBD;mBA3qBlBA;;;;;aA7EAA;MAwwBNA,0BACFA;K;kCAGKE;MAGCA;MAGJA,OA08COA,gCA58CSA,qEAGlBA;K;wBAGKC;oBA7sBUA;MA0tBKA,uBAy5DkBX;QA55DlCW,oBAKJA;MADEA,uCACFA;K;mCAGAC;MACEA;;QAAoBA,aAUtBA;MANmBA;;QAAkBA,aAMrCA;MADEA,sBAAiBA,yBADNA,yBAFKA,2CAEsBA;IAExCA,C;qCAGAC;MACEA;;QAAoBA,aAUtBA;MANmBA;;QAAkBA,aAMrCA;MADEA,sBAAiBA,yBADNA,yBAFKA,2CAEsBA;IAExCA,C;oBAGAC;MAEEA;MAs5COA;QAt5C2CA,WAKpDA;MADEA,sBAAiBA,iDAHsBA,uFACOA,mFACaA;IAE7DA,C;oBAOgBC;MACqBA;gCAEFA,mCADjBA;MAEdA,wCACcA,8DACoBA,iCACpCA;K;4BAOAC;;IAAqEA,C;mCAE7DC;MACNA,OAHFA,iCAGuCA,qCACvCA;K;4BAIAC;;IAAqEA,C;mCAE7DC;MACNA,OAHFA,iCAGuCA,qCACvCA;K;YAaGC;MACHA,WACFA;K;YAIQC;MACNA,aACFA;K;aAIKC;MACHA,0CACFA;K;qBAIWC;MACTA;QAAqBA,aAGvBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;wBAIWC;MACTA;QAAqBA,aAGvBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;uBAIaC;MACXA;QAAoBA,aAGtBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;0BAIaC;MACXA;QAAoBA,aAGtBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;YAIKC;MACHA,iEAEFA;K;oBAIUC;;QACYA,aAGtBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;uBAIUC;;QACYA,aAGtBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;YAIKC;MACHA,gCACFA;K;oBAIUC;MACRA;QAAoBA,aAGtBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;uBAIUC;MACRA;QAAoBA,aAGtBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;eAIKC;MACHA,gCACFA;K;uBAIaC;MACXA;QAAuBA,aAGzBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;0BAIaC;MACXA;QAAuBA,aAGzBA;MAFEA;QAAoBA,aAEtBA;MADEA,sBAAiBA;IACnBA,C;uBAEOC;MACEA;MACPA;QACOA,kCACDA;MAGNA,QACFA;K;0BAEO5F;MAEEA;MAGPA;6BAQeA;QANbA;UAC2BA;;;6CAEWA;+BAEVA;QAC5BA;UACEA;QAKFA;UACEA;6BACoDA;UAAOA;UAArCA;8CAAcA;UAApCA,+EAAsBA;2BAGDA;UAooDIA;YAloDPA,2DAAEA;;QAItBA;;QA8DQA;;;MAh5BeA;uBAxDiB6F;MA+4BL7F;qCAGaA;;qCAGAA;mDAG3CA;gCADsCA;yCACLA;MA5CfA;MA8CDA;MAIxBA;QACmBA,8CACbA;MAKNA;QACEA;QAEAA;UACmBA,8CACbA;QAINA;;MAGFA;QACEA;QAEAA;UACmBA,8CACbA;QAMNA;;MAGFA;QASqDA;MAArDA,+EACFA;K;kBAEO8F;;gBAr/B4CA;;MAw/BjDA;QAA4BA,eAgD9BA;MA/CEA;QAA6BA,gBA+C/BA;MA9CEA;QAA0BA,aA8C5BA;MA7CEA;QAA2BA,cA6C7BA;MA5CEA;QAAyBA,YA4C3BA;MA1CEA;QA36B2BA;QA66BzBA,OAAUA,sBAAaA,iCAwC3BA;;MArCEA;QA36B+BA;QA66B7BA,OAAUA,sBAAaA,iCAmC3BA;;MAhCEA;QA36B+BA;QA66B7BA,qBAAmBA,sBAAaA,iCA8BpCA;;MA3BEA;QAh9B+BA;QAk9BtBA,4BAAeA;QACFA;QAIpBA,iBAHcA,+BACEA,8DAsBpBA;;MAjBEA;QACEA,OAAOA,iDAgBXA;MAbEA;QA/6BkCA;QAk7BhCA,OAAOA,0BAAqBA,2BADRA,qCAWxBA;;MANEA;QA56B4CA;gBA5EFC;2BA0/BHD;QAAOA;QAArCA;4CAAcA;QAArBA,qBAAOA,IAIXA;;MADEA,UACFA;K;oBAEOE;MACcA;MACnBA;QAAuBA,gBAEzBA;MADEA,mBACFA;K;wBAqKgBC;;aAEZA;;MAGAA,WACFA;K;8BAEWC;;2BAEiBA;wBACtBA;MAAJA;QACEA,OAAOA,+BAcXA;WAbSA;;QAuJAA;;QAnJLA;;QAGgBA;QAYTC;QAVPD,iBAIJA;;QAFIA,YAEJA;K;wBAKYC;MACRA,gDAA+CA;K;8BAEvCC;MACRA,OAAOA,yCAA0CA;K;oBAS1CC;MAGLA;wBADkBA;;MACtBA;QAAmBA,YAIrBA;MAHYA;;MAEVA,UACFA;K;iCAEWC;;2BAloCiCA;MAqoC1CA;QAEiCA,mBAroC7BA;MAwoCAA;MAAJA;QAAmBA,YAIrBA;MAHYA;;MAEVA,UACFA;K;oBAEWC;;2BA5nCiCA;MA8nC1CA;QAEiCA,mBA9nC7BA;sBAUWA;MADgBA;;MAwnCFA;MACzBA;MAAJA;QAAmBA,YAUrBA;MAHYA,uFAJaA;;MAMvBA,UACFA;K;4BA2BWC;MAESA,0BADMA;MAEPA,UAEnBA;K;0BAEWC;iBApqCMA;MADgBA;;cA2pCTA;SAx6ClBA,QA87CyBA;SA17CzBA,WA27C2BA;SAv7C3BA,QAw7CwBA;MAC5BA,UACFA;K;kCAmDWC;MAGLA;wBADkBA;MACtBA;QAAmBA,YAErBA;MA5gDIC;SA4HEC;MAs5CGF,GA5uCHE;MAquCJF,4CACFA;K;+BAwBWG;MAILA;wBADkBA;MACtBA;QAAmBA,YAErBA;MA1iDIF;SA4HEG;SA0CAA;MA44CGD,GA5wCHC;MAmwCJD,4CACFA;K;kDAWWE;MAILA;;wBADkBA;MACtBA;QAAmBA,YAErBA;MA3jDIJ;SA4HEK;SA0CAA;MA65CGD,GA7xCHC;MAoxCJD,4CACFA;K;oCAWcE;;;MAGZA;uBAE6CA,GA3yC9BA;QADgBA;;QA6yC7BA;;MAGFA,QACFA;K;yCAEcC;;4BAGLA;MAH8BA;MAIrCA;uBA0nCoDA;uBAvnCPA,OAzzC9BA;QADgBA;;QA2zC7BA;;MAGFA,QACFA;K;mCAcWC;MAEFA;MAdgCA;MAKrCA;oBADEA;QAEEA;MAWFA,gBADkBA;MACtBA;QAAmBA,YAErBA;MAnnDIR;SA4HES;SA0CAA;SAcAA;oBAw8CAD;WAzjDAC,2BAAgBA;MA6jDbD,GA11CHC;MA40CJD,4CACFA;K;iCAgCWE;;iBAzhDsCA;MA4hD/CA;QAn9CwBA;;QAs9CKA;;QAEmBA;QAATA;;iBA33CxBC;MADgBA;;MA82C3BD;MAiBAA,gBADkBA;MACtBA;QAAmBA,YAErBA;MAhqDIV;SA4HEY;SA0CAA;SAcAA;MAq/CGF,GAn4CHE;MAy3CJF,4CACFA;K;kCAoDWG;;sBAp7CMC;MADgBA;;qCAu5CmBA;mDAYnCA;qCATmCA;mDAG3CA;gCADsCA;yCACLA;MAVQA;MAa5CA;MAEJA;QAIMA;MAINA;QAIMA;MA/BAD;MA2CFA,gBADkBA;MACtBA;QAAmBA,YAErBA;MA3tDIb;SA4HEe;SA0CAA;SAcAA;MAgjDGF,GA97CHE;MAo7CJF,4CACFA;K;yCAmBWG;;4BA98CMC;MADgBA;;MA48C7BD;MAQEA,gBADkBA;MACtBA;QAAmBA,YAErBA;MArvDIhB;SA4HEkB;SA0CAA;SAcAA;MA0kDGF,GAx9CHE;MA88CJF,4CACFA;K;oBAuIcG;MACZA,4DAYFA;K;mBAmBWC;;;uBAP4DA;;sBAWnDA,gBAAlBA;QAEqBA;QAAnBA;UACMA;aACCA;UACDA;aACCA;UACDA;;UAEJA;UACAA;;cAEIA;;cAGAA;;yBAIIA;cACJA;;yBAmSJA;cAFgBA;cADeA;yBAElBA;cA7RTA;;yBAxcDA,qCACHA;cA2cIA;;yBAvcDA,qCACHA;cA0cIA;;yBAtcDA,qCAAmBA;cA0clBA;;+BA9CmBC;8BALDA;cAuDlBD;;+BAmHoCA;cAgFWE,2BA0mBjBC;cA1mBtCD;cA1P0BC;cAwKNH;cAApBA;2BAEwBA;;gBAEXA;;;+BAIOA;oBACdA;;+BAGsBA;oBACtBA;;;cA1HEA;;cAGAA;cACAA;;wBAOQA;cAAGA;oBAxrDJjF;cADgBA;;yBAsvCoBiF;cAoc3CA;;wBAOQA;cAAGA;oBAhsDJhF;cADgBA;;yBAyvCwBgF;cAyc/CA;;wBAOQA;cAAGA;oBAxsDJ/E;cADgBA;;yBA+vCwB+E;cA2c/CA;;+BAlFmBC;8BALDA;cA2FlBD;;+BAqG4CA;cAxyDlD3E;;;cA4yDe2E;cAAjBA;gBAEEA;;;oBAGIA;;;oBAIAA;;;oBAIAA;;;;cAyCiDI,2BA0mBjBD;cA1mBtCC;cA1P0BD;wBA9lDfC;wBAQAA;wBAiBAA;yBAiyDWJ,yCADLA;cA5HTA;;+BA1FmBC;8BALDA;cAmGlBD;;cAuJ+CK,2BA0mBjBF;cA1mBtCE;cA1P0BF;;;cAuGlBH;;+BAlGmBC;8BALDA;cA2GlBD;;cAsJoDM,2BAmmBtBC;cAnmBtCD;cAjQ0BC;;;cA+GlBP;;;;;;MAQ6CA;MAArDA,OAAOA,0CACTA;K;yBAOWQ;MACLA;;sBACcA,SAAlBA;QAEsBA;QAApBA;UAAyBA;QACXA;;;MAGhBA,QACFA;K;8BAEWC;MAELA;;sBACcA,SAAlBA;QAEMA;QAAJA;UACEA;YAAeA;;;UAEVA;YUhhEsBA;;YVghEtBA;;YAGLA;;;MAQ6CA;MAJjDA;mBA5nBiCA;4BANTA;wBA/yCuBC;QAgzC/CD;UAvuCwBC;;;QAZKA;QAwvCLD,2CAAmBA;QAPlBA;qBAUrBA;QAAJA;UACEA,+CAA4BA;mBAEbA;;;MA8nBjBA,QACFA;K;sCAyEYE;MAEDA;MAATA;mBAhoBOA,qCACHA;QAioBFA,MAOJA;;MALEA;mBA/nBOA,qCAAmBA;QAioBxBA,MAGJA;;MADEA,sBAAMA,qDAA+CA;IACvDA,C;oBAkBWC;MACTA;QAEEA,OAAiBA,6DAOrBA;WALSA;QACLA,OAAeA,kDAInBA;;QAFIA,WAEJA;K;qBAEYC;;;MAEVA;QAEaA,wDAA8BA;IAG7CA,C;0BAEYC;;uBAEHA;MAFeA;MAGtBA;QAEaA,wDAA8BA;IAG7CA,C;yBAEWC;;wBA/jEsCA;;MAikE/CA;QACEA;UAz/DsBA;UAy/DNA,2BAsBpBA;;QArB4BA;2BAEXA;QAAbA;UACEA,+BAkBNA;QAfIA;QAhgEsBA;iCAkgEFA;;aAEpBA;QAAgBA,kBAWpBA;MATEA;QACEA,sBAAMA;MAEgBA;gCAEXA;QACXA,+BAGJA;MADEA,sBAAMA,mDAAsCA;IAC9CA,C;gBAkEGC;MAEHA;;QAA8BA,WAyJhCA;MAtJMA;QAAwBA,WAsJ9BA;eAnJMA;MAAJA;QAA0BA,WAmJ5BA;MAhJMA;QAAwBA,YAgJ9BA;;QA5IuBA,WA4IvBA;MAtI0BA;MACxBA;QA1jE4CA;QA6jEtCA,+BAAqBA,EADmBA;UACcA,WAkI9DA;;YArzEmDA;MA4rE3CA;MAqBNA;QA9nE2BA;QA+nEzBA,OAAOA,uDAmGXA;;MA9FEA;QApoE2BA;QAqoElBA,MA9qEiCC;QA8qExCD,sDA6FJA;;MAjFEA;QAvoE+BA;QAwoExBA;UAEHA,YA8ENA;QA5EIA,OAAOA,uBAAyBA,+DA4EpCA;;MAvEEA;QAtpE+BA;QAypEzBA;QAFJA,SAsEJA;;MA1DEA;QA9pE+BA;QA+pEzBA;UAEFA,WAuDNA;QArDIA,OAAOA,gCACCA,sDAoDZA;;MAhDEA;QA7qE+BA;QAgrEzBA;QAFJA,SA+CJA;;MAtCEA;QAAsBA,YAsCxBA;MAnCEA;;QAEEA,WAiCJA;MA3BEA;;UAC2BA,WA0B7BA;QAzBIA;UAAsCA,YAyB1CA;QAvBsBA;QACAA;QACbA;UAAwCA,YAqBjDA;;;QAzsEoCA;cAlEQE;QAkERF;QAyrEhCA,OAAOA,gEAgBXA;;MAbEA;;UAC2BA,WAY7BA;QAXIA;UAA+BA,YAWnCA;QAVIA,OAAOA,sDAUXA;;MANEA;QACEA;UAAgCA,YAKpCA;QAJIA,OAAOA,uDAIXA;;MADEA,YACFA;K;wBAGKG;MAAkBA;;;MAttEIA;YAxDiBrD;MAwDjBqD;MA4tEpBA,uCAAwCA;QAC3CA,YAuEJA;MApEwCA;MACAA;uCAMaA;uCACAA;qDAC/CA;qDAA4BA;MAAhCA;QAA2DA,YA2D7DA;MAzDMA;uCAM+CA;uCACAA;qDACnBA;qDACAA;MADhCA;QAC2DA,YAgD7DA;MA9CEA;gCAsPkCA;QAnP3BA,+CAAqBA;UACxBA,YA0CNA;;MAtCEA;gCA8OkCA;QA1O3BA,+CAAqBA;UACxBA,YAiCNA;;MA7BEA;gCAqOkCA;QAjO3BA,+CAAqBA;UACxBA,YAwBNA;;kCAlBgDA;kCACAA;;;MAE9CA;8BAkR4BA;;UA9QxBA;YAA+BA,YAWrCA;gCARmCA;UAD7BA;iBAHFA;QAKAA;UAAyCA,YAO7CA;2BAwMoCA;QA5M3BA,0CAAqBA;UAAqCA,YAInEA;;MADEA,WACFA;K;yBAEKC;MACIA;MA50EwBA;eAg1E3BA;MAh1E2BA;eAg1ElBA;MAAbA;QACkBA;QACAA;uBAETA;QAJTA;QAcEA;oBAmLgCA;;UArJvBA;YACHA,YAiCVA;;QA7BIA,WA6BJA;;MAhB0BA;MACxBA;QAAkBA,YAepBA;0BAbMA;MAAJA;QAA2BA,YAa7BA;6BAVSA;MADSA;MAxEMA;MA0EtBA;QAIOA,4BAFwBA,wDAA+BA,iBAEdA;UAC5CA,YAINA;MADEA,WACFA;K;eAOKC;MACHA;;QAA8BA,WAyChCA;MAvCMA;QAAwBA,OAAOA,oBAuCrCA;YA5gFmDA;MAy+E7CA;qBAASA;QAAOA,YAmCtBA;MAjCEA;;;;UAIIA,OAAOA,yCA6BbA;;UA/8EiCA;gBAnBWnF;UAmBXmF;UAu7EpBA;YADmDA,YAyBhEA;UAxBMA,oBAAsBA,qCACdA,0CAuBdA;;UAn8E4BA;gBA/BgBC;UA+BhBD;UA+6EtBA,OAAOA,qCAEHA,aAAeA,+BAA6BA,oCAkBtDA;;UA16E2BA;gBAxDiBvD;UAwDjBuD;UA45EdA;YAEyBA;YACpBA;YA0CdA,2EAEAA,sEAEAA;;YAjDEA;mBAcNA;;UAh6EoCA;gBAlEQH;UAkERG;UAw5E9BA,OAAOA,qCAEHA,aAAeA,oCACPA,yCAKlBA;;UAFMA,YAENA;;K;gBAEKE;;wBAGCA;4BAAWA;QAASA,YAM1BA;MALEA;QACOA;UACiDA,YAG1DA;MADEA,WACFA;K;qBAEKC;;wBAGIA;wBACAA;MAJWA;;MAKlBA;QAAwBA,YAQ1BA;MAPEA;;UAEkDA,YAKpDA;QAJqDA;QAA5CA;UACqDA,YAG9DA;;MADEA,WACFA;K;qBAYKC;MAA0BA,2BAAkBA;K;eAE5CC;MACHA;;QACuBA,WAWzBA;YAjkFmDA;MA2jF1CA;MAAPA;QACSA;UACAA;YACAA;cAHTA;gBA99E+BA;gBAm+EvBA;;gBALRA;;cANIA;;;;;;;MAMJA,SAMFA;K;yBAmCcC;MAGeA;;;MACzBA;kBAE2BA;;;IAE7BA,C;;;;;;;;;;;;;;;;;;;;;;;MW3oFWC;;iBAFRA;MAEHA,oFACFA;K;0CAWOC;MAELA,WAA4CA,0BAC9CA;K;iBCxIKC;MACHA;;QAGEA,MAyBJA;;;;QAlBIA,MAkBJA;;MAdEA;QACEA,MAaJA;MATEA;;QAEEA,MAOJA;;;K;;;wBPyCAC;MA6BEA,gEAEFA;K;0BASAC;;uBAGMA;MAAJA;aACMA;UACFA;;;MAKJA;sBAEeA;QAAbA;UAAoBA,eAuDxBA;QAtDIA;UAAmBA,aAsDvBA;QApDqCA;QAAjCA;UACEA,eAmDNA;kBA/C8BA;UAKxBA,sBAAUA,kDAA4CA;;2BAOTA;MA2CfA;MA1ClCA;QAAyBA,kBAkC3BA;MA9BgBA;MACdA;QAAyBA,kBA6B3BA;MAvBEA;QAIEA,QAAOA,2BAmBXA;MAhB8BA;MAA5BA;QAEEA,QAOOA,8BAOXA;;QAPIA,QAAOA,8BAOXA;MALEA;4CAiB4BA,8CAhBiBA;QAC3CA,QAD2CA,gCAI/CA;;MADEA,QAH6CA,gCAI/CA;K;2BQnKUC;;QAKJA,sBAAUA;MAKZA;QACEA,sBAAUA;MAEZA,OAAWA,mDACbA;K;+BA+BQC;MACJA,+BAA0CA,2DAA8BA;K;2BAKhEC;;MAKVA,WACFA;K;4BCiGYC;MAGVA;QACEA;;;;;;;;;YASIA,WA4BRA;;YA1BQA,YA0BRA;;MAvBEA;;;;;;;;;;;;;;;;;;;UAmBIA,WAINA;;UAFMA,YAENA;;K;qCAIWC;MAAsBA;sBAGTA,SAAtBA;QACiBA;QAGVA;UACHA;QAEFA;;MAEFA,YACFA;K;sCAIWC;MAAuBA;aAGhCA;QACmCA;QAAlBA;QAGVA;UACHA;;MAIJA,YACFA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CCnOgBC;MAA4BA;MAGjCA;QAAPA,+DAgCJA;;QAf0DA;;;QAAVA,0BADxCA,yBAPYA;QAUhBA,OAAOA,mEAaXA;aAJWA;QAAPA,qEAIJA;MADEA,OAAOA,uDACTA;K;4CAEYC;6BAMNA,yBALYA;IAMlBA,C;kDAEYC;wBAMNA,yBALYA;IAMlBA,C;2CAEYC;MACJA,sBAAsBA,aAAMA;IACpCA,C;wBAeaC;MCoGaA,uDDnGIA;MAE5BA,OAAWA,4DACbA;K;iBAgBAC;;;;IAaAA,C;yBAEAC;;;;IAsBAA,C;8BA0DWC;MACXA,OA1BAA,2BEuBAC,eCyE2BC,gBDzE3BD,2BFvBAD,sCA2BFA;K;qBAUQG;MAENA;eACUA;MACVA,gBAvBwBA,QAwB1BA;K;iBASQC;MACNA;IACFA,C;kBAQQC;MACNA;IACFA,C;mBAOQC;MAENA,0BACIA,2BAAyBA;IAC/BA,C;oBASKC;MAECA;;wBAEqBA;;QASvBA;;;QACgBA;UAChBA;;UE3EFA,wBCyE2BL;gBDqDzBK;gBACAA;UF/CAA;;;IAEJA,C;6BAIkBC;;;;;;;;;;;;;MAwBhBA,OAAYA,CGrCeA,0CHqCgBA,wFAG7CA;K;mBIlKUC;MFiDRA,4BCyE2BP,gBDzE3BO;MGlIMA,eAAeA,aDmFTA;MAOVA,aACFA;K;6BAgBQC;MFuBRA,4BCyE2BR,gBDzE3BQ;MErBEA,oBAAkBA;MAOlBA,aACFA;K;wBAcQC;MAAWA;;QAEFA;oCACFA;UACTA,aAeNA;;UAbkCA;UFUlCA,oBCwD2BC,gBDxD3BD;YA6GEE;YACAA;UExHIF,SAaNA;;;QAnBmBA;QAQfA;cDgEuBT;QDzE3BS;QEWkCA;QAC9BA;0BAEgCA;;YvB1GpCG;UuByGMH,4CACkDA;;UAElDA;QAEFA,aAEJA;;K;yBAgCQI;;cDqBmBA;kBCnBIA;QACGA;QAC9BA;6BACoCA;;YvBrJxCD;kCuBsJ+BC;;;MF/C/BA,oBC8D2BC,gBD9D3BD;MAEEC;MEgDAD,SACFA;K;iBAuEuBE;MFrIvBA;;gCCyE2Bf;;YCgErBe;;MAOOA;;yBA4BTA;;UACMA;UACJA,wBAAYA;;;QAwBdA;UFpMJC,oBCuE2BC;UDtEzBA,qBEoM4BF;UAAxBA,SAuBNA;;QArBiBA;;cAAbA;;QApE0BA;QAqE1BA;QAUaA;QAAXA,SAUNA;;MADEA,aACFA;K;oBA6CcG;MAEZA,OAAOA,iBAAQA,6BN6NjBC,iCAxGgCD,+BAwGhCC,sCMvNAD;K;mBAGYE;MAAaA,WAAIA;K;oBAwBfC;MF9SdA;cCyE2BrB;;;MC4OJqB,gDAAiCA;QAAtDA;MAmBAA;MACAA,iBACFA;K;gCAqWGC;MAC2BA,mBDvmBHA;MCwmB3BA;2BACoCA;;UvB9wBpCV;gCuB+wB2BU;;MAE3BA;IACFA,C;uBF/qBEX;;MAwHuBA;QADrBA;QACAA;MAxHFA;IAEAA,C;iCA+NYY;MAAmBA;2BAjNPA;MAiNOA;MAjIPA,qBApFCC;YAsFvBD;;QAsIEA,wBAAYA,mDAYCA;;QAnBcA;QAuB3BA;QAKAA,oBAAkBA;;IAItBA,C;8BAIYE;MAAgBA;2BAvPAA;kDAyPZA;QAxJSA;QAEvBA,yBAAOA;;MAyJPA;QAC8BA;QAC5BA;QACAA;;QAEgBA,+DAAmBA;QAvOvBA,qBA1BYC;cA4B1BD;cACAA;QAsOEA;;IAEJA,C;mCAuFYE;;;yGACVA;;yBA3VsBA;mBA6VJA;qBA5VEA;QA6VlBA;UACEA;YAnQJA,yBAAOA;YAqQMA,yCAC6BA,kBAAkBA;;UAExDA,MA2JNA;;qCAtJqBA,oCAAjBA;mBAGWA;UACTA,sCAAsBA;;mBAGHA;yBAAOA;cAQvBA;cACDA;QAKJA;;wBArgBsBA;UAqgBGA;;UCiCXA;QDjCdA;wBAvgBcA;mBAAOA;UAygBnBA;mBAAwBA;YCqMdA,6CAAqBA;;YArK5BA;UDhCHA;uBAE0BA;YAxSVA,iBAzFAC;YA2FpBD,yBAAOA;YAuSMA,MAAPA,OAAOA,uCAC6BA,kBAAkBA;YACtDA,MA0HRA;;gBC7c2BA;UDuVrBA;YCsBYA;wBAGAA;;YD0DRA;;;wBAhmBmBA;UAmlBvBA;YA/D+BA,oGAgEHA;eACrBA;YACLA;cA9BsBA,yFA+BDA;iBAGrBA;YAzBcA,2EA0BDA;UAKfA;;qBAIIA;UAAqBA;kBAhePA;cAwLQA,iBAxLRE;cA4LNF,sBAAUA;gBAC1BA;cACOA;cAtEQA,iBAxHOG;cAwHPH,iBAxHOG;gBA2HtBH,YAAgBA;gBAChBA,wBAA4BA;oBA6WlBA;cACAA;;cAEAA;YAKJA,MAcRA;;;0BAX8BA;QA5TEA,qBAxLRE;QA4LNF,0BAAUA;cAC1BA;QACOA;mBAwTAA;mBAGqBA;mBAzfNI;QAsfpBJ;UA9YmBA;UAHTA;gBAEZA;gBACAA;;UAiZeA;UA9YGA;gBAElBA;gBACAA;;cA+YEA;;;IAEJA,C;2BAgDOK;MACUA;QACfA,OAAOA,4FAWXA;MARmBA;QACfA,OAAOA,yEAOXA;MALEA,sBAAUA;IAKZA,C;oBI3wBKC;MACHA;mBAAOA;;eAGiBA;;QACtBA;;QACOA;;IAEXA,C;yBAEKC;;;QAKDA;;;;aAIIA;UN3BJA,6CAAyBA,OM4BMA;;IAGnCA,C;4BAQKC;MAtDHA;WAwDIA;;cAEGA;UN3CLA,6CAAyBA,OM4CMA;;2BAG/BA,cAAcA;IAGlBA,C;oCAUKC;;cACCA;MAAJA;QACEA;mCACwBA;QACxBA,MAcJA;;MA7FEA;YAkFIA;MAAJA;aACQA;;;aAGAA,UAA6BA;oCACbA;iBAEZA;;;IAIdA,C;uBA2BKC;;uBHgKwBA;WG9JbA;QAGZA,wCAHYA;QAIZA,MAUJA;;MAR6CA,KAN7BA,qDAO0BA;QH0qBxBA,MGjrBFA,iCHirBuBA;;QG1qBrCA;;QAEEA,oDAC6BA;QAC7BA,MAGJA;;YHgJ6BA;MGjJtBA,uBAA+BA;IACtCA,C;8BCiBUC;MC+nBJA;;;MDznBFA,wBAAYA,wDAGAA;MAIZA,OCmoBFC,uEDloBAD;K;gCA6DQE;MACNA,OEqQFA,2BFpQMA,wDEoQNA,sCFnQAA;K;mCAg6DQC;;QEtsCsBA,kBAAoBA;MF0sC9CA,OE3sCJA,uDF2sCkCA;K;uCCzkE1BC;MAMNA;oBAgtBEA,wGAHAA,uGA1sBJA;K;iBAktBGC;MACHA;;QAAiCA,MAMnCA;;QAJIA;;QAHYA;QAIZA;QACKA,CL1gBoBA;;IK4gB7BA,C;sCAmFSC;MAA2CA,iEAG7CA;K;mCCxxBLC;gBNsL2BC;;MMtL3BD;;;IAMAA,C;sBAqcGE;IAAgCA,C;uBAGhCC;MACqCA;MAAnCA,CNzRsBA;IM0R7BA,C;sBAGKC;IAAoBA,C;kBCzjBzBC;MAAeA;;QAGXA,iBAAUA;;QAHCA;QAIXA;QAC8BA,ePuRLA;QOtRzBA;UACEA;;8BAEsCA;U7B8G1CtC;kC6B7GiCsC;UAC7BA;;;IAGNA,C;qBAIKC;MAEgBA;MACyCA;QAC1DA,4BAA0BA;;QAE1BA;IAEJA,C;4BAeeC;MAEbA,OAAOA,0DAGTA;K;qBAIKC;MACgBA;MACyCA;QAC1DA,4BAA0BA;;QAE1BA;IAEJA,C;iBLpBUC;gBFuPmBA;MEnPXA,YAHWA;QAGvBA,2CAIJA;MAFEA,OAAYA,2BACoBA,mCAClCA;K;yBFmGMC;;IAaSA,C;iBA4eHC;MAAMA;;+BAEQA;kBACRA;;MAEhBA,eACFA;K;qBA0BWC;MACFA;QAAgBA,WAE3BA;MADEA,OAAYA,sBAAOA,eACrBA;K;8BAgaKC;MAAwBA;;MAE3BA,iCAA+BA;IAKjCA,C;cAIEC;;;;;MACqBA;;MAAaA,KAAzBA;QAAkBA,iBAQ7BA;MANkBA;;QAEPA;QAAPA,SAIJA;;QAFgBA;QAxcIA;;;IA0cpBA,C;mBAEEC;;;;;MAEqBA;;;MAAaA,KAAzBA;QAAkBA,oBAQ7BA;MANkBA;;QAEPA;QAAPA,SAIJA;;QAFgBA;QApdIA;;;IAsdpBA,C;oBAEEC;;;;;MAEqBA;;;;MAAaA,KAAzBA;QAAkBA,2BAQ7BA;MANkBA;;QAEPA;QAAPA,SAIJA;;QAFgBA;QAheIA;;;IAkepBA,C;2BAEgBC;MAEdA,yBAAOA,SACTA;K;gCAEwBC;MAEtBA,sDAAOA,SACTA;K;iCAE8BC;MAE5BA,oEAAOA,SACTA;K;wBAEWC;;MAEPA,WAAIA;K;4BAEHC;MAEHA;MAGiCA;YAHlBA;MAAfA;QAhWgBA,cAgWDA,iCAhWsBA,wBAmW7BA,gCAEAA;MAKRA;IACFA,C;sBAEMC;MAKsBA;MAFbA,iCAAkBA;MAE/BA,OAAaA,wCACfA;K;8BAEMC;MAEJA;MAIkCA;MAFrBA,sCAAuCA;MFl+B1BC,mDD3FID;MG+jC9BA,OH7jCaA,oEG8jCfA;K;gBAEKE;MQ/oCHA,cRgpCeA;IACjBA,C;kBAEKC;MACEA,CAt5BsBA;IAu5B7BA,C;eAEKC;MAASA;MAORA;MAOAA;MATUA;MAEdA;yBACwBA;MAMxBA;QAEoBA;;;QAKHA;;MAnXjBA;MAMeC;MAFbA;MAKaA;MAFbA;MAKaA;MAFbA;wBAGmCA;MAAnCA,sCAxzBIA,4DA0zBSA;wBAC2BA;MAAxCA,2CA3zBIA,4DA6zBSA;wBAC4BA;MAAzCA,4CA9zBIA,4DAi0BSA;wBACmBA;MAAhCA,mCAl0BIA,mHAq0BSA;MAIAA;MAHbA;MAMaA;MAFbA;MAMaA;MAHbA;wBAIwBA;MAAxBA,2BAj1BIA,kGAm1BSA;MAGAA;MAFbA;wBAGsCA;MAAtCA,yCAv1BIA,6GA01BSA;MAsUfD,SACFA;K;cA+NEE;MAEAA;;QACEA,OAAOA,oDA+CXA;;MA3CcA;UACVA;WACiBA;UACjBA;;QAEAA,sBAAUA;MAG8BA;MAiB1CA;QAEUA;;QAEuCA;eAv2CzBA;eACUA;eACEA;eACcA;eAETA;eAECA;eACEA;gBACQA;gBACZA;gBACgBA;gBAC5BA;QAdfA,0DAeaA;;;QA81CjBA;QAAPA,SAUJA;;QAlDaA;QAyCTA;eACIA;QAAJA;UACEA;;UADFA,iBAGSA;UACPA;;;MAGJA,YACFA;K;eAGEC;MACEA,OAAKA,CAtsCoBA,0EAwsCpBA,iBAAYA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MSv5CnBC;;qBAvDQA;MAOAA,sBAgDRA,wDA3BAA;K;6BAmROC;uBAIwBA;MAA7BA,qCACFA;K;6BAEYC;MAIVA;;;;IAQFA,C;4BAoBOC;MAQUA;MAAfA;MCjVFC;MDmVED,YACFA;K;iCA2HQE;MAOAA,6BCtdRD,+DD2eAC;K;0CAOQC;MACNA,2EAAOA,gCCnfTF,uFDofAE;K;wCAMQC;MACNA,OC3fFH,qFD4fAG;K;iCA2pBQC;MAOAA,OA6ERA,qDAxDAA;K;wCASQC;MAA0BA,OA+ClCA,qDA/CyDA;K;0CAIjDC;MACJA,sEA0CJA,uDA1CmDA;K;kCA6T5CC;MAQUA;MAhCSA;;;MAkCxBA,YACFA;K;6BAwGAC;;QACEA,yBAAaA;MADfA;IAEAA,C;0BExjDQC;MACaA;MACnBA,mBAAcA;MAGdA,aACFA;K;wCCsHcC;MAEZA;MAAIA;QACFA;UAEEA,cAgBNA;QAdIA,6CAcJA;;MAZ+BA;MAC7BA;;QAEEA;;QAZ+BA,eAcIA,4BAJrCA;QAKEA,UALFA;UAKEA,gBALFA,uBAKoBA;QAAlBA,CALFA;;M5ByVYA,6CAAqBA;M4BlVjCA,sCAIFA;K;uCAYcC;MAEZA;MAAIA;QACFA,6CAYJA;M5BkSAA;M4B3SEA;;QAEEA;Q5B0TUA,EAAZA,wCAAsBA;;Q4BlUUA,eAUKA,4BAJrCA;QAKEA,UALFA;UAKEA,gBALFA,uBAKoBA;QAAlBA,CALFA;;;iB5B0U4CA;M4BlU5CA,sCACFA;K;yBAOGC;MACHA;iBAAoBA,kBAAkBA,gBAAtCA;mBAAoBA,kBACDA;UAAuBA,WAG5CA;MADEA,YACFA;K;6BAGKC;MAyBoBA;;;MAGvBA;;;QACOA;UAAeA,MAoFxBA;QAnFwBA;QACpBA;uBACeA;QACfA;;MAUGA;QACHA;UAAoCA,MAqExCA;QApEqBA;mCAAMA;QAANA;QACGA;mCAAMA;QAANA;;QAEHA;QACjBA;QACKA;UACHA;YACEA,+BAAYA;YACZA,MA4DRA;;UA1DyBA;UACCA;qCAAMA;UAANA;mCACKA;;UAEXA;UACdA;UAVFA;iBAaSA,iBAAPA;YAEgBA;YACdA;YACAA;cAQEA;;;gBAEYA;2CAAMA;gBAANA,sBAAmBA;gBAC7BA;;cAEFA;cACAA,MAgCVA;;;UA7B4BA;UACHA;mCACMA,2BAA2BA;;;uBAOtCA;QAEhBA;;;;MAMFA;mCAAqCA;;QACzBA;mCAAMA;QAANA,sBAAmBA;QAC7BA;UAEEA;;;;MAGJA;QACEA;MAEFA;MACAA;IACFA,C;sCC5TUC;MACuBA;MAC7BA,mBAAcA;MAGdA,aACFA;K;sCCMQC;MACoBA;;MAC1BA;QACEA,gBAAWA,UADbA;MAGAA,aACFA;K;yBClFcC;MAEZA;MAAIA;QACFA,cAwBJA;M/BmgBAA;;Q+BthBIA;;UAEKA;QACLA,eAAUA;;;QAXWA,eAsBcA,4BAAlBA;QACjBA,UADiBA;UACjBA,gBADiBA,uBACCA;QAAlBA,CADiBA;;iB/BuiByBA;M+BniB5CA,sCACFA;K;gBCudAC;;aASWA;;MAATA,cAASA;MATXA;IAUAA,C;yBAmVAC;kDAEmBA,aACcA,0BACTA,QAJxBA;IAI6BA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBC50B/BC;MACEA;;QAAuBA,sBAAMA;;;;;QADrBA;QAQIA;QAAVA;;MAIOA;MAAPA,SAIJA;K;4BAiDAC;MAEEA;;QAAoBA,WAyBtBA;MAtBEA;QACEA,aAqBJA;;QAdIA,OA8BFA,2CAhBFA;MAVEA;QAO8BA,2CAAuBA;MAErDA,aACFA;K;qCAiRgBC;MAIZA;QAGEA,OAAOA,wEAGXA;MADEA,WACFA;K;8CAEcC;MAeEA;;MACdA;QAAqBA,WAcvBA;MAbQA;MAANA;QACEA,OAAOA,wDAYXA;yBATyBA;MACNA;MAEjBA;QACEA,OAAOA,wDAKXA;MAFEA,OAAOA,6EAETA;K;wCAEcC;MACRA;QAAoBA,WAE1BA;MADEA,OAAOA,0DACTA;K;0CAEcC;MAAwBA;;;QAKlCA,SAGJA;;QARsCA;;MAOpCA,WACFA;K;yBAcYC;;yBAEYA;MACtBA;qBACcA;wBAEEA;YACgBA,WAIlCA;MADEA,YACFA;K;8BAKOC;MAAYA;;;QAOfA,SAGJA;;QAVmBA;;MASjBA,WACFA;K;4BAIEC;MACIA;MAESA,iDADfA;QACeA;QACRA;4BAAKA;QAAVA;UAAsCA,eAG1CA;;MADEA,sBACFA;K;+BCpTcC;MAENA;QACFA,sBAAMA;MAMRA;QACEA,sBAAMA;MAGRA;QACEA,sBAAMA;IAKVA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;elC1DWC;MAUSA;MAPlBA;QAAmBA,YAGrBA;MAFEA;QAAqBA,OAAOA,sBAE9BA;MADEA,sBAAUA;IACZA,C;2BAiDcC;MAEkBA;QAAPA,2BAEzBA;MADEA,yBHybsBA,IADRA,0CGvbhBA;K;sBA6MQC;MAGIA;;MACVA;QACEA,sBAA2BA,SAA3BA;UACEA;MAGJA,aACFA;K;oBAGQC;MACYA;;MAClBA;QACEA,8BADFA;MAGAA;QAAcA,WAEhBA;MADEA,OwB3YFA,6BAAeA,8BxB4YfA;K;4BASQC;MACYA;;MwBjZpBA;MxBkZEA,6BwBlZFA,cxBmZAA;K;iCAeQC;MAENA;MAAcA;QACCA;uBAeAA;QACMA;QAfnBA,OAmBgBA,0DAFTA,+DAXXA;;MAJgBA;QACZA,OAuBgBA,yDADGA,kDADDA,SAlBtBA;MADEA,OAAOA,mDACTA;K;gCAGQC;MACNA,OAAkBA,yCACpBA;K;gCAkBcC;MAEZA;;QAAeA,sBAAUA,6BAAqCA;MAC1DA;MAAJA;QACEA,sBAAUA,+BAAuCA;MAEhCA;MACnBA;QACOA;UACHA,sBAAUA;;MAIdA;eACSA;UAAeA,UAAYA;;QAElCA;UACOA;YACHA,sBAAUA;UAEZA,UAAYA;;MAGhBA,OAAkBA,sCACpBA;K;mBAaQC;MAKJA,OI7eJA,6BAM2BA,0EJ2eJA;K;4BAwDTC;MACgBA;MACvBA;QAAqBA,aAa5BA;mBYzLoBA;;UZ4LgCA,cAbVA;eAC7BA;;QAYuCA,cAVZA;eAC7BA;UASyCA,kCAPVA;;MAGxCA,aACFA;K;cA8EeC;MACWA;MACxBA;QAAiBA,OAAWA,gBAE9BA;MADEA,sBAAUA;IACZA,C;qBAuBcC;MAEZA;;wBAAwBA;QAASA;QH4lBnCC;UAAsBA,kBAAMA;;;QG5lB1BD;;QACEA,WAsBJA;mDmCrtBqCA;MAAhBA,+BAAQA;qBnCssBDA,yBAA1BA;oBACaA;QACXA;UACqBA;UAAfA;8CAAcA;8BAAdA;;UADNA;;UA7PgBE;;uEAqQDF,yBACAA;;MAGjBA,sCACFA;K;wBASsBG;MACpBA;gCAAIA;QACFA,OAAOA,oCASXA;;QAJIA;;QAP0BA;QAQ1BA;QACAA,iBAEJA;;K;0BoC9OcC;MACDA;;MAEXA;QAAkBA,aAIpBA;MAHEA;QAAiBA,wBAGnBA;MAFEA;QAAgBA,yBAElBA;MADEA,0BACFA;K;2BAUcC;MACZA;QAAcA,aAGhBA;MAFEA;QAAaA,cAEfA;MADEA,eACFA;K;yBAEcC;MACZA;QAAaA,aAEfA;MADEA,cACFA;K;etB7cMC;MAUoCA;kCACUA;MAX9CA;IAYiBA,C;wBpB5BTC;MACgBA;QAC1BA,OAAOA,qBAMXA;MAJEA;QACEA,6BAGJA;MADEA,OAAOA,+BACTA;K;qBAiBAC;;IAA8BA,C;oBAkD9BC;;IAGiBA,C;yBAgBjBC;;IAEsBA,C;2BAKtBC;;IAGyBA,C;iBA4CzBC;MAAUA;MAAVA;IAGoBA,C;sBASpBC;;IAI0EA,C;sBAiB1EC;;IAK4EA,C;qCAsBhEC;MAEVA;QACEA,sBAAiBA;IAErBA,C;gCAuCWC;MAITA;QAEEA,sBAAiBA;MAEnBA;QACEA;UAEEA,sBAAiBA;QAEnBA,UAGJA;;MADEA,cACFA;K;iCAOYC;MACNA;0BAAMA;MAAVA;QAAeA,sBAAiBA;IAClCA,C;iBA+CAC;MAGkBA,+CAAsBA;MAHxCA;IAK6DA,C;uBAuG7DC;;IAA8BA,C;yBAgB9BC;;IAAkCA,C;iBAclCC;;IAAwBA,C;kCAexBC;;IAAkDA,C;sBQ3d5CC;;IAA8DA,C;wBmC0E5DC;MAIQA;;MAAIA;MAIlBA;QACEA,uCAAYA;MAEdA,aACFA;K;kBCOmBC;MACfA,O/CoFJA,yG+CpFiCA;K;WCrK9BC;MACaA;cACZA;MAAJA;Qf4BAA;;QezBEA;IAEJA,C;2BC4oBIC;MACFA,oDACFA;K;eCkEaC;;iBAyDGA;MAGZA;QA44HWA,gDACJA,iDACAA,gDACAA,iDACAA;QA94HLA;UAGEA,OAAeA,6BAD0BA,6DACLA,SAgO1CA;aA/NWA;UACLA,OAAeA,iBAAOA,uDAAwCA,SA8NpEA;;MAtNgBA;;;MAKdA;;;;;;;;MASYA;QAIVA;yBAEcA;MACZA;8BAAUA;MAAdA;QAEUA;;kBAaMA;MAAOA;wBAAkBA;MAAlBA;yBACPA;yBACAA;0BACCA;6BACGA;MAMhBA;kCAAcA;MAAdA;gCAAcA;MAAlBA;QAOcA;MAHVA;8BAAUA;MAAdA;QAYuCA;WARhCA;QAEOA;MAMVA;8BAAUA;MAAdA;QAGoBA;MA5INA;;;;;;kBAkJEA;MAAOA;uBAAkBA;MAAlBA;MAEvBA;QAIEA;;UAxFMA;;UA6FKA;UAAJA;;YA7FDA;;YAmGMA;cAEJA;;cA5GVA;YAwGSA;;cAjGDA;;cAgHJA;gBAEMA;kBAEFA;oBAKOA;sBAICA;sBA+wHOA;;sBA/wHPA;sBA8wHOA;;oBA9wHMA;oBACnBA;oBAIcA;oBAAdA;oBACAA;6BAEUA;oBAjHfA;;;yBAkHUA;oBAIHA;oBACAA;oBAFMA;oBAGNA;;;;uBAcKA;kBAKLA;oBAGAA;oBACAA;oBACAA;oBAHMA;oBAINA;;;;;;mBAe6BA;gBAK/BA;kBAGAA;kBACAA;kBACAA;kBAHMA;kBAINA;;;;;;cAtMVA;;;;;QAmOiCA;MAXjCA;gBAC6BA;QAA3BA;UACQA;UACNA;UACAA;UACAA;UACAA;UACAA;UACAA;;QAEFA,OAitGJA,oGA3sGAA;;MAFEA,OAAYA,iHAEdA;K;yBA+FcC;MAERA;MADJA,OAAYA,uDAC8BA,UAAQA,oBACpDA;K;2BAmFiBC;MACLA;;;;;wEAOVA;QACaA;QACXA;UACEA;YAEEA;;UAGFA;YACEA;UAEaA,mBAAMA;UACjBA;6BAAKA;UAATA;YACEA;UAEKA;UAAPA;6CAAMA;;UACMA;;;;MAIhBA;QACEA;MAGaA,mBAAMA;MACjBA;yBAAKA;MAATA;QACEA;MAEFA;yCAAMA;;MAENA,aACFA;K;0BAmBiBC;MAULA;;mBAKEA;cAWHA;QAAYA;MACHA;MAMlBA;QACaA;QACXA;UACEA;YAEEA;YACIA;cACFA;YAIAA;;UAAJA;YAEEA;cACEA;YAGFA;YlC/7BMC;;YkCk8BND,+BAAUA;UAEAA;eACPA;UlCr8BGC;;ekCy8BFD;QAAaA;MACTA;MACeA;MAC7BA;QACEA;MAEFA;QACEA;UACEA,+BAAUA;;UAEOA;UACjBA,oCAAUA,eAAeA;UACzBA,oCAAUA,eAAeA;;MAG7BA;iBACYA;UACRA;sBAEaA;QACfA;;qBAGmCA,uEAArCA;qBACcA;QACZA;UAEEA;YACEA;0CAAKA;;YACCA;YAANA;uCAAKA;;YACLA;;;UAGaA;UAAfA;wCAAKA;;UACCA;UAANA;qCAAKA;;UACLA;;;MAGJA,YACFA;K;yBAyFQE;MAWNA;;QAEEA;UACWA;;UACJA;YACLA;;;MAMJA;QACsBA;QAEPA;QAENA;QACHA;QAKKA,yCAHIA,YAAMA,qCAAkDA;;QAgBzBA;;QAAhBA;;MAT1BA;MAGMA;MAMVA,OAtDFA,4EAoDeA,0DAGfA;K;eAGQC;MAAIA;MAUDA,kEAysG4CA;MAxsG1CA;MACJA,wDAusG8CA;MApsG7CA;MACGA;MACJA;MACQA;MACfA;qB7BjkCkBC;;Q6B4jCdD;MAKJA;QAGqBA;;MAAhBA;MACEA,wDA4rG8CA;iB7BjwInCA;M6BukCqBA;QAE9BA;;QAEAA;MAKTA,OA5FFA,mCAyFsBA,qFAItBA;K;uBAqCWE;MACTA;QAAsBA,SAGxBA;MAFEA;QAAuBA,UAEzBA;MADEA,QACFA;K;gBA6CYC;MACVA,sBAAMA;IACRA,C;oBAuEQC;MAENA,iBACMA,0CACAA,gCACRA;K;iDAWOC;MAELA,sCAAiBA;IASnBA,C;8CAEOC;MAGLA;M9Bp6CWA,+GlB4CbC,uBAEyBA,mBAFzBA,iDgDw3CED;ehDn3CeA;QgDo3CTA,yBAAiBA;UACnBA;YACEA,sBAAMA;;YAENA,sBAAMA;;IAIdA,C;mCAEOE;MACLA;;;;;;;QAEEA,MASJA;MAPEA;QACEA,sBAAMA,yBAC+BA;;QAErCA,sBAAMA,4BAC+BA;IAEzCA,C;uBAEOC;MAEUA;;MAIXA;QAEFA,OAAOA,2CAKXA;;QAFIA,OAAOA,0CAEXA;K;8BAEOC;MACLA;MAAIA;QACEA;UACKA;;UAEAA;UAEHA,QADKA,mEAELA;YACFA,sBAAMA;;;Q7BlrDLA;e6B0rDEA;MAAcA;QACrBA,gCAAyBA;QACDA;UACtBA,sBAAMA;QAGWA;QAInBA;QACAA,OAAOA,6CAoCXA;;MAjCMA;QACEA;UAEcA;UAEXA;UAAiBA,0DAAoBA;UAEvBA,+CADsBA,qDACbA;UAC5BA;UAIAA,OAAOA,gDAqBbA;;UAlByBA;UAInBA;UACAA,OAAOA,6CAabA;;;QATuBA;QACnBA;QAMAA,OAAOA,8CAEXA;;K;oBAsHWC;MAEmBA;QAAsBA,WAEpDA;MADEA,WACFA;K;oBAacC;MAEZA;;QAAkBA,WAmCpBA;MAlCEA;QAAkBA,SAkCpBA;MAhCMA;QACkBA;QAAhBA;UACFA;QAG6BA;QAAnBA;QACZA;UAE6BA;UAClBA,uCADJA;;UAK6CA;QAFhDA;QAEJA,OAAOA,+EAmBXA;;MAfIA;QACMA;UAmBIA;UAELA;UAlBDA;YAE6BA;YAClBA,uCADJA;;YAIqCA;UADxCA;UACJA,aAAWA,iEAKnBA;;MADEA,OAAOA,0CACTA;K;uBAIWC;MACGA;MAEZA,kDACFA;K;2BAccC;MzCr7CdA;;MyCg8CEA;QACaA;QACXA;UACuBA;UACjBA;UAAJA;YACEA;YACAA;;;YzCt8CRA;UyCy8CqBA;UAGfA;YACgBA;eACTA;YACLA;gBzC76CNC;UyCg7CID;;;;UAxCJA;YAAmCA;YAAbA;4CAAYA;mBAAZA;;YAAtBA;UA2CSA;YACLA;;gBzCt9CNA;cyCy9CQA;gBACeA;;;;;YAKjBA;;YAGAA;cACaA;cACXA;gBACiBA;;;;;cAQVA;;czC7+CfA;YyC0+CqBA;YAEFA;YACbA;;;;;MAIJA;QAAoBA,OAAOA,gDAM7BA;MALEA;QACiBA;iBzCp9C2BA;MyCu9C5CA,sCACFA;K;4BAacE;MACCA;MAMbA;QACaA;QACXA;UAEuBA;UACjBA;UAAJA;YACEA;YACAA;;;YzClhDRA;UyCqhDqBA;;UAIfA;YACgBA;YAMPA;iBALFA;;;;;gBzCz/CXD;UyC8/CIC;;;;UAtCJA;YAAoCA;YAAdA;4CAAaA;mBAAbA;;YAAtBA;UAyCSA;YACLA;;gBzCpiDNA;cyCuiDQA;gBACeA;;;;;YAKjBA;;YAgUJA;cAC0BA;cAApBA;8CAAmBA;qBAAnBA;;cADNA;YA/TSA;cACLA;;cAGAA;gBACaA;gBACXA;kBACiBA;;;;;gBASVA;;gBzC9jDfA;cyC0jDqBA;;cAGFA;cACbA;;;;;;MAIJA;QAAoBA,OAAOA,gDAO7BA;MANEA;QACiBA;;;iBzCriD2BA;MyCyiD5CA,sCACFA;K;sBAOcC;MACZA;;QAAkBA,SAkBpBA;MAhBOA,mCADqBA,2BAAOA;QAE/BA;MAGFA;QACuBA;QAiRvBA;UAAkCA;UAAbA;0CAAYA;iBAAZA;;UAArBA;QAhREA;UACEA;QAEFA;;;MAIOA;MAETA,OAAOA,6EACTA;K;8BAKcC;MACZA;QAAsBA,aAKxBA;MAJEA;QAAsBA,aAIxBA;MAHEA;QAAuBA,cAGzBA;MAFEA;QAAyBA,gBAE3BA;MADEA,aACFA;K;wBAEcC;MACZA;QAAsBA,SAExBA;MADEA,OAAOA,oDAA4CA,iBACrDA;K;oBAEcC;MAEPA;;;;MAELA;QAA0CA,wBAoB5CA;MAnBEA;;QACEA,sBAAMA;MAGRA;QACWA,yDAAwCA;;oBAGxCA;;QhD1xDbC,wEkBrJ4CD,O8Bg7D/BA,iChD3xDbC,4CgD4xDSD;;gB7BzwDWA;Q6B4wDhBA;UAAYA,UAMhBA;aALoCA;QACnBA;MAGfA,OADSA,mDAEXA;K;yBAOcE;qBACDA;MAA6BA;QACtCA,OAAOA,wDAGXA;MADEA,OAAOA,+BACTA;K;qBAEcC;MAEZA;QAIEA,OAAOA,iDAAyCA,gBA6BpDA;MA1B+BA,WA0B/BA;K;wBAEcC;MACZA;QAAsBA,WAGxBA;MAFEA,OAAOA,oDAA4CA,gBAErDA;K;2BAecC;MAAgBA;qBACrBA;MACHA;sBAAoBA;QACtBA,UAuBJA;MArBmBA;MACCA;MACIA;MACCA;MACvBA;QACEA,UAgBJA;MAd8BA;MA4oB5BA;QACuBA;QAAjBA;wCAAgBA;eAAhBA;;QADNA;MA3oBAA;QAIEA,OzCxzDgBA,qGyCi0DpBA;MAPEA;QAEEA,OAAOA,sEAKXA;MADEA,WACFA;K;sBAEcC;MAAWA;;;MAGvBA;QAEcA;;;QACZA;QACAA,0CAAeA;QACfA,0CAAeA;;QAKfA;UAGEA;;;;;;;;;UAKmBA;;QAATA;;;QAEZA;UACeA;UACbA;UACAA,kDAAuBA;UACvBA,kDAAuBA;UACvBA;;;MAIJA,OAAcA,iDAChBA;K;gCAQcC;MAGLA;MAAPA,oBAEIA,0DACNA;K;qBAacC;MAGCA;MAIbA;QACaA;QACXA;UAA6BA;UAAVA;yCAASA;yBAATA;;UAAnBA;;UACEA;;UAIAA;YACgBA;YAEdA;cACEA;cACAA;;YAGFA;;;;;;YAMKA;cAsCXA;gBAC0BA;gBAApBA;gDAAmBA;uBAAnBA;;gBADNA;;cAtCWA;;cACLA;;;;cAGAA;gBAEMA;gBAAJA;kBACaA;kBACXA;oBAGiBA;;;;;;;;cAIPA;;;;YzCt1DtBA;UyCy1DmBA;UzCl1DFA;UyCo1DXA;sCAAMA;UAANA;;;;MAIJA;QACEA,YAMJA;MAJEA;QACeA;iBzCp0D6BA;MyCs0D5CA,sCACFA;K;iCAsDYC;MACNA;QAAsBA,WAG5BA;MADEA,OADYA,+CAEdA;K;6BAOcC;MACZA;MAAKA;QAA8BA,WAsBrCA;MAvBgCA,mB7B5iEZ7B;M6B+iEI6B;MAECA,kCAAvBA;;QAEMA;qB9Bv5DYC;U8Bw5DdD;YACEA;wCAAOA;YAAPA;sB9Bz5DYA;c8B25DVA;;UANRA;eAUSA;UAVTA;;UAaIA;;;;MAGJA;QAAiBA;MACjBA,OAAOA,qCACTA;K;iCAacE;MAAsBA;sBAC1BA;MACHA;QAEHA,sBADyBA,iCA2B7BA;MA9BoCA,mB7BhlEhB/B;M6BulEI+B;MAECA,kCAAvBA;;QAEEA;UACgCA,U9Bh8DhBA;Y8Bi8DZA;wCAAOA;YAAPA;YAJNA;;YAOMA;;;aAEGA;UATTA;;UAYIA;;;;iB9Bz8DcA;M8B48DlBA;;UAA6CA;qCAAMA;qBAANA,GAAUA;;UAAvDA;;QAfAA;MAeAA;QACEA,WAKJA;MAH4BA;QAAcA;MACxCA;QAA4CA;mCAAMA;QAAhCA,uCAAYA,2BAAcA;;MAC5CA,OAAOA,qCACTA;K;wBAGcC;;iBACHA;MAAeA,6CAAuBA;QAC7CA;UACaA;UACXA;YACEA,OAAUA,qDAA0BA,2CAS5CA;UAPMA;YACmBA;YAAbA;4CAAYA;mBAAZA;;YADNA;;YAEEA;;MAINA,WACFA;K;6BAoJcC;MAEOA;;qBACNA;MACGA,uCAAZA,cACQA,yBAARA;QACuBA;qCAAQA;QAAjCA,gCAAiCA,yBAARA;QACzBA;QAM0BA;;QAH1BA;QAG0BA;;MAApBA;MACAA;QACSA;gBACNA;;;MzC7oECA;;MyCqpEZA,sCACFA;K;6BAgHWC;MACLA;MACJA;QACiBA;QACfA;UACmBA;;UAGjBA;UACAA;YACmBA;;YAEjBA,sBAAMA;;;MAIZA,WACFA;K;qBAccC;MAAUA;;eAIHA;MAJGA;MASLA;MADGA;MAApBA;;UARsBA;;;QASLA;QACfA;UACaA;YANRA;;YALeA;;;QAUpBA;UALKA;UASHA;;QANyBA;;MAU7BA;aACMA;UAdCA;;UALeA;QAmBpBA;UACEA,OAAOA,gCAyBbA;;UjDn1FAC,wBiD4zFcD;;QAGFA;QACRA;UACiBA;UACfA;YACEA,sBAAMA;UAERA;YACEA;cACEA,sBAAMA;YAERA,+BAAUA;YACVA;;YAIAA;;;MCv1FqDA;MD21F3DA,OCtnFIE,yBArO+CF,gBD41FrDA;K;iCAEYG;MACNA;MACJA,0CACFA;K;uBA6bYC;MAEVA;MAGAA;czCxwFAzB,mBAA6CA;;QyC2wF1ByB;QACjBA;UACEA,sBAAoBA;QzCxyFTA,6ByC0yFKA,mBACdA,WAAiBA,oDAAmCA;czChxF1DzB;QA3BeyB,wByC6yFKA,mBAFdA,WAGiBA,qDAHmCA;;IA4B5DA,C;+BAWWC;MACLA;wBACyBA,iCAA7BA;QACaA;UACSA;QACpBA;;UAEEA;;QAEFA,SAGJA;;MADEA,iBACFA;K;oBA0PeC;MAAMA;;;qCAEIA;MAOHA;oBAIJA,kDAAhBA;QACSA;QACPA;UAAwCA;QACxCA;UACEA;;YAEEA;;UAEFA,sBAAMA;;;MAGVA;QAGEA,sBAAMA;aAERA;QAEEA;QACAA;QAEAA;UACSA;UACPA;YACEA;;iBACKA;YACLA;;QAGJA;UACEA;;UAG4BA;UAGvBA;YACHA,sBAAMA;UAERA;;;MAGJA;MAGgCA;kBAFRA;QAEfA;;QAKSA,wCAAqCA;QAErDA;UACSA;;MAGXA,OAveFA,uCAweAA;K;6BAOYC;MAINA;;MACsBA,oFAA1BA;QACaA;QACXA;4BAAOA;QAAPA;QACAA;UACqBA;UAAfA;8CAAcA;8BAAdA;;UADNA;mBzClpG2C5E;QyCkpG3C4E;UzCxwGgB5E,MAsHlBA;;UAtHkBA;gBAsHlBA;UAtHkBA,sCyC6wGO4E,wCAAsBA;gBzCvpG/C5E;UAtHkBA,MAsHlBA,kDyCwpGyB4E;;;MAGzBA;QACEA,YAA0BA,0BAA1BA;UACaA;UACPA;6BAAKA;UAATA;YACEA,sBAAoBA;;IAI5BA,C;mBAgMcC;MAmDHA;;;0CAAuCA;aAInCA;aAOFA;aAaAA;aAWJA,UADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGAA,UAASA,UADLA;MAIKA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MACAA;MAGSA,eADLA;MACJA;MACAA;MAKAA,UAASA,UADLA;MAIKA,eADLA;MACJA;MACAA;MACAA;MAEAA,aACFA;K;WAWIC;MACWA;;MADNA,yBAEWA;MAILA,8CAHbA;QACcA;uCAAMA;sBAANA;QAEDA;QAEXA;UACuBA;QAANA;qCAAKA;0BAALA;QACTA;QACRA;;MAEFA,YACFA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MEnpIUC;;sBAHVA;MAwBEA,uClBsUIA,gEkBtUWA,YACjBA;K;qBAoFUC;M5B0ERC,wBCyE2B3M,gBDzE3B2M;oBAtLIC;qB4B+GYF,yBAAuBA,kDACzBA,yBAAuBA;MAGrCA,SACFA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SCvIEG;;MAGWA;MACAA;MAJqBA,gBAG9BA,eACAA,cAAYA;K;SAkCZC;MAGFA,4BACFA;K;;;+BCyzlCEC;MAIYA,6CAAiBA;MAJ7BA;MAKEA;MALFA;IAMAA,C;eAo4GeC;gB7B39rCYA;M6B+9rCfA,YAFaA;QAAMA,eAGjCA;MADEA,oDACFA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBC3ssCEC;MAAWA;YCGaA;MvDQxBjB;MuDrCyBkB;MA4BzBD,gDxC44BaC,oBwC93BiCC;MAd9CA;MDFAF;IAE6DA,C;;;;;;;;;;;;;;0BEdxCG;MAMfA;;;kBCUgDA,2BC5BxBA;QFqBxBA;mBhC8OqBA;MgC3OdA,gEAAyBA;MAO7BA,qCAAiBA,SAAOA,uCAAQA;;MG/BrCA,WAASA,2BHiCqBA,mHGjCHA,wCAACA,sBAtB5BA,0BAGgDC,uEAISA,gFAGtCA;MH0HrBD,iBEvG8BA,SFwGhCA;K;oCAGmBE;MACjBA;QAAkBA,WAGpBA;MAFWA;QAASA,WAEpBA;MADEA,OAAWA,sDACbA;K;uCAKYC;;MACFA,OC/DgBA,gBCtDMC,SEvBNA,gBJ4IPD;IACnBA,C;+BAGYE;MAEFA,OCrEgBA,gBCtDMD,SEvBNA,gBJkJPC,kEAEUA,mCKpICA,8BAArBA,CrCmQkBC,yBqCnQVD,wBLuIJA;IAEbA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BMtIaE;MAKHA,iBAAKA;QAAkBA,OAAaA,kBAI9CA;MAHWA;MAAKA;QAAoBA,OAAaA,kBAGjDA;MAFMA,yCAAiBA;QAAwBA,OAAaA,sBAE5DA;MADEA,OAAaA,oBACfA;K;;;WCkCAC;MAzD4BA;;;aAMAA;MAOCA;YvCiQF5N;MuCpNzB4N;QACEA,kBAAoBA;MAFxBA,sDCpDIC,oBzCUAjB,sBAsLJD,uGwC5IAiB;IAWAA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBEnESE;MAKTA;;MASeA;QACeA;;QAA5BA,OCkJFA,YAA6CA,yBjEoO7C9C,oDkBrJ4C8C,O8CjOHA,6DhEsXzC9C,yDgErTF8C;;MAzDMA;MAAsCA;MAKFA;MAExBA,oCACOA;;MhEsWvB9C;MgEtWA8C,OEiLAA,YACmBA,yBlEoLnB9C,oDkBrJ4C8C,O8CjNVA,0EhEwHeA,2DAAMA,OgExE9CA,gDG5CTC,8BH6CFD;K;qBAGOE;MAGeA;;YAFbA;M7C7CEA;M6CiDWA;;M7C7CNA,+CAJLA,yC6CoDGA,mD7ChD8BA,U6CmDlCA;MAEYA;M7CzDXA;M6C2DWA;M7C3DXA;M6C6DWA;M7C7DXA;M6CgEWA;MAnBpBA,O7CzCcA,0CAJLA,yC6CqEGA,2C7CjE8BA,U6CiEFA,kCAC1CA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YIlFEC;MAEcA;MAFdA;IAGuCA,C;;;;;;;;;;;;;;MCmBNC;;;;+BAFMA;MAEbA,mFAuC1BA;K;yBAKmBC;MACCA,OAAOA,kDAY3BA;K;uBASQC;MAYNA;;;MAAoBA;MAcpBA;QAAoCA,OAAOA,WAe7CA;MAdaA,EAAXA;;MACaA,EAAbA,+CAAkBA;MAKGA;MACDA,OAAPA;MAAYA,oCxDkOzBA,8EwDlO8CA;MAK9CA;QAAqBA,OAAOA,WAE9BA;MADEA,OAAOA,eAAaA,YACtBA;K;gBAKAC;MAiBgDA,2BANNA;gCACTA;iFAKoBA;mCAEtBA,a/B2K/BA;+B+B1KgCA,c/B0KhCA;M+B9LAA,8EC3FAA;MDgHEA;QAA8BA;MAC9BA;MAtBFA;IAuBAA,C;oBAMAC;MAkBmBA;gCANcA;;;;MAZjCA,qBAU6BA,oDAShBA,yCACEA;MACuBA;MAIpCA;QAA8BA;MAE9BA;MA3BFA;IA4BAA,C;0BAGAC;MACeA;;wDACcA,wBACAA,yBAA2BA,oBAArBA;aACnBA,+BAAoBA;aACHA,kBAAnBA;aAC8BA,oBAAzBA;aAC8BA,kBAA3BA;aACmCA,kBAA/BA;aACSA,iBAApBA;;cACEA,mCAAwBA,OAAnBA;;cACHA;MACXA,4BAA2BA,UAAVA,uCAAjBA;;QAC8BA;QAFnBA,iBAEQA,yBAAiBA,oBAANA,uBACfA,uBAAiBA;;MAdxCA,4DAgBqCA,8BAArBA,iCAA6BA,WAAIA,kEAhBjDA;IAkBwCA,C;kCAGzBC;MACTA;;;QAAsBA,QAAeA,kBAI3CA;MAHoBA;MAClBA;QAAyBA,OE7NrBA,oBF6NuDA,8BAE7DA;MADEA,OEjOIA,cFiOWA,YAA8CA,iBAAvBA,6CACxCA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aGnDAC;MCpKgBC;clD6OW1O;;;aiD7KFyO;aEpCzBE,mBA7C+BC,4BzCK/B5J;MyCyCE4J,iCC+QFC,qCD9QgBD,oBAAqBA;;MF8FhBH;MAICA;MAIDA;MAILA;MA6BCA;MADjBA,uBAEkBA,YC1MdK,kBnDkBAlC,sBAsLJD,oHkD9G2C8B,4EAiBTA,0CG0RlCI,wGHrQ+BJ,uDGqQ/BI,2HHnN6BJ,0CAMMA;MAgBnCA;;IAWAA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBI3NEM;MACFA;cAASA;QAAaA,SAexBA;gCAdMA,eAAaA;QAAQA,QAc3BA;iCAbOA,eAAaA;QAAOA,WAAYA,OAavCA;gBAViBA;MACfA;QACyBA;QACXA;oCAAIA;kCAAZA,mBAAQA;;;UAGJA;;MAGVA,UACFA;K;;;;;;;;;;;;YCbYC;MAEyBA;;;;MAA3BA,EAARA;MAGqBA;MACrBA,iBAAYA;MAGZA,aACFA;K;eAOUC;MAEGA;MAGXA,kBAAaA;MAIbA,aACFA;K;;;;;;;;;;;;;;;;;;;;yBCNEC;MAPcA;aAOdA;MACEA,kCCNFA;MDKAA;IAEAA,C;;;;;;;;;;;;;oBxBoMAC;MACEA;QACEA,kBAAUA;4BAtMIA,cAAcA;QAwM5BA,kBAAUA,wGAC6BA;MAL3CA;IAOAA,C;gBAsFAC;MACEA;QACEA,kBAAUA;0BAnSIA,cAAcA;QAqS5BA,kBAAUA,mGAC6BA;WAClCA;QACLA,kBAAUA;MAPdA;IASAA,C;;;;;;;;;;;;;;;M0B/TAC;;;;yBd+DQA;MAONA,uBAAqBA,kCADLA,mBAAsBA,gCAOxCA;K;sBAMQC;MAINA;QACEA,sBAAUA;MAGFA;QAAUA,YAGtBA;MAFYA;QAAUA,OAAOA,iBAE7BA;MADEA,Oc5FFA,gBd4FuBA,sCACvBA;K;uBAOQC;MACNA;;iBACYA;UAkHKA,8BAlH4BA;UAAxBA,OAiHvBA,gBC7KAxB,8BD8EAwB;;QAjBQA,yCAAeA;UAAsBA;UAAXA,SAiBlCA;;QAhBQA;UAAoCA;UAAXA,SAgBjCA;;QAfQA,yCAAeA;UACNA;UAAXA,SAcNA;;QAZQA;UAAqCA,gCAAmBA;UAA9BA,SAYlCA;;QAXQA,yCAAeA;UACNA;UAAXA,SAUNA;;QAgGmBC,8BA7FgBD;QAP/BA,OAOJA,gBCjFAxB,+BD8EAwB;;QAnBEA;QAgBEA;;UACAA,sBAAUA,mBAAyBA,mDAAyBA;;UAjB9DA;;IAmBFA,C;oBAKmBE;MAGLA;;gBAAaA,qB/ClFlBA,mE+CkF6CA;MhDmIzCA,uCgDjIKA;;MlE0QlBC,2EA5OyED,OkE7B9DA,iClEyQXC,wDkExQOD;MAGMA;QACTA,iCAAeA,sBAAoBA;MAGrCA,cACFA;K;mBAGAE;MhD4HaA;gCgD1HHA;MlE4C2CA,2EAAUA,OkEtCtCA;;MARzBA;yBAyEmBA,yBrDrCaA,oEAA2BA,OqD3BxCA,iCrD2BaA,oCsDzIhC5B,+BDqGA4B;IAU0BA,C;uBAG1BC;yBA4DmBA,yBlEmInBC,qBA6DAC,oBkE1PUF,+DhDwD0BA,kCgDtDfA,iElE6PkDA,mCkE5PpDA,uFCvHnB7B,+BDkHA6B;IAM0BA,C;wBAS1BG;yBA6CmBA,yBlEmInBF,qBA6DAC,oBkE1OeC,qBADLA,iCAEKA,oChDuCqBA,kCgDtCfA,kElE6OkDA,mCkE5OpDA,wFCvInBhC,+BDiIAgC;IAO0BA,C;yBAwB1BC;MAGgBA,cADAA,gElE+IhBH,qBA6DAC,oBkEzMmBE,qBADHA,iCAEGA,oChDMiBA,kCgDJXA,mElE2M8CA,mCkE1MhDA;MATvBA,mBAcmBA,2CC9KnBjC,+BDgKAiC;IAU0BA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCe1LFC;M3C4UxBA;;M2C3UIA,iCACIA,cAAmBA,2GAAsCA;K;;;;;;;;;;;;;;;;;;qBCDjEC;MAC4CA;;MAA5BA;MAEHA;;MACEA;;MACbA;QACEA,kBAAUA;WACLA;QACLA,kBAAUA,iDAA2CA;WAChDA;QACLA,kBAAUA,mDAA6CA;MAV3DA;IAYAA,C;;;;;;;;;;;;;;yBCkFAC;MAjD4BA;;c5D4MDnQ;a4DrJ2BmQ;MANtDA,qEA9CmBA,sCRwQnBtB,uSrD9TIjC,sBAsLJD;M6DtKAwD,EA2FEA;MAPFA;IAQAA,C;;;;;;;;;;;;;;;;;;;;;;wBCnIKC;M9D6MLzD,UCyE2B3M;;;M8DxJUoQ,OAAvBA,cAAQA,cD3HNA;MC2HqBA,OAAvBA,C9DwJaC,0B8DxJLD,cD1HNA,8BAA4BA,uC9DmBxCxD,2D8DjBDwD,SAAKA;MAERA,SACFA;K;;;;;;;;;;;;;;;MEPEE;;;;IACkCA,C;;;MCyBlCC;;;oCAEUA,wCAAqBA,6EAF/BA;IAGkBA,C;2CAQTC;MACkBA;MAAPA,SAOpBA;K;;;;;;;;;;;;;;;;;oBCpCAC;6BACiCA;uCACnBA,uBADmBA;QAE7BA,kBAAMA,0DAAoDA;MAH9DA;IAKAA,C;;;;;;;;;;oCC0BwBC;MAEsBA;;0CAA1BA;;QAGGA;MAF+BA,yBAA1BA;MACTA,iBAA4BA,oBAAtBA;qBtEmXL9G;QuE1ZpB8G,+BACoBA,sBAAoBA,QDyCtBA,YAAgCA,oBAA1BA;;;QR1BCA,2CQ2BcA,kDACOA,8BAA/BA,0CACIA;QR9BnBA;;MQuBEA,OAhCFA,qCAwCkBA,YAA2BA,oBAArBA,iCACxBA;K;qDAYwBC;MAGtBA,OAAOA,sBAAeA,yFACxBA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MnBSAC;;;;IAAoDA,C;;;;;;;;;;;;;;;;;;eqB5BlDC;MACEA;qBCyjByBA,4BAESA,kDDxjBtCA;;QACEA;UAAuBA,sBAAUA;;UCujBGA;kCAASA;mBAATA;;UDrjBXA;QAApBA;;UACHA,sBAAUA,2DAAqDA;QAErDA;QACJA;6BAAMA;;QAEHA;QACXA;;MAYOA;MAILA;MAASA,4CAAsBA;QACjCA,sBAAUA;MAGZA,aACFA;K;;;kCE3FKC;MCwBcA;kDDtB0CA;aAM3DA;yCEsIcA;MAAZA,kBAAOA,cpCtIiBC;kBAHFA;QAAkBA;M/BuyB1CxO,4BAvV4ByO,oBAuV5BzO,iCmE7pBeuO,OAAKA;IFtItBA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MGyBEG;;;;IAC0BA,C;;;;;;;;;;;;;;;;;YCSvBC;MAKHA;IAEFA,C;aAiBOC;;;MZ+DgCA,WAAvBA,C9DwJad,0B8DxJLc;QYpDpBA,sBAAMA;MZoD6BA,YAAvBA,C9DwJad,0B8DxJLc;gCAxD2BC,kBAAtBA,C9DgNAC,2B0EzMPF,sBZOYA,kB/DhEPC,OA4MAE;Q2EnJGH,sBAAMA;MAMxBA;;MAyCOA;;QAEFA;UACGA,0BAAKA;UAAnBA,SAMNA;;;;QAREA;QAIEA;QACaA,wCAAMA;;MAErBA,OAnEcA,yBAmEAA;IAChBA,C;UAKKI;MAAwBA,yBAvI3BA,2BAuIqDA;K;mBAIhDC;MC/ILC;qC3FuiBAC,wB4FzPsBF,4BDrSDC,K3F6jByBE;M0Frb/BH;MCjJfC,6B3FuiBAC,wB4FzPsBF,wBDrSDC,K3F6jByBE;M0Fpb/BH;MACsBA,U9E+QjB5H;M8E9QpB4H;Q1Fqb0DI;M0Fpb1DJ,sCACFA;K;;;;;;;;aG1JIK;MAEFA,cANAA,MAOFA;K;aAGIC;MAEFA,cAZAA,MAaFA;K;WAEAC;MACEA,mBAAiBA;IAanBA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBROQC;MAEGA;QACPA,OAAWA,+BAAqCA,+BAGpDA;MADEA,OAAOA,YAAeA,gDACxBA;K;eAOQC;MACNA;MAAOA,YAAHA;QACFA,sBAAUA,qDAAgDA;MAIxDA;QACEA,qCACAA,gCACAA;UACFA,sBAAUA;QAGZA,OAAWA,+BAAgCA,0BAAHA,wCAI5CA;;MADEA,OAAWA,qCACbA;K;kCAiCEC;;qCAVkCA,8BAGEA,8BAICA;MAGrCA;;IAoCAA,C;4BA0CAC;mCAJuCA;MAIvCA;;IAIAA,C;4BAwJAC;MACgBA;oCAAEA;;;aACDA,iBAAqBA,UAAHA;MACjBA,sBAAqBA,UAAHA;MACEA,0CAAfA;MAALA;;;;;MACDA,4BAAEA;MACYA;MACQA;MAPvCA,iDAOcA,sBACKA;MARnBA;;IAqFAA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCShYQC;MAEKA;;MACUA;MACrBA;QAAyBA,iCAAoBA;;MAGzBA;MACKA;eAIhBA;MAAcA,oCAAkBA;QACxBA;iCAAIA;QAAnBA,wCAAeA;QAMJA;;QAHXA;QAGWA;;MAAbA;QACMA,wBAAkBA;UACpBA,+BAAUA;UACVA,wCAAeA;UACPA;;MAKZA;QACEA,+BAAUA;QACVA;;MAGFA,OAGFA,gDAFAA;K;;;;;;;;;MCjEAC;;;;IAA2BA,C;;;;4BCc3BC;;;MAGOA;QACHA,kBAAUA;MAIRA,oCAAmCA;QACrCA,kBAAUA,yEACUA;MAVxBA;IAYAA,C;;;;;;;;;;;;;;;;;;;;;;eC0EAC;MAQsBA;;0CACeA;;;MATrCA,2EAzDoCC,8BAGGA,8BAGAA,8BjCbjCC,ciCgBmBD,4BAUSA,8BASLA,8BAMIA,6BAuBjCD;IAYkBA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCsDXG;MACPA;QAAkCA,WAGpCA;MADSA,SADGA,aAAYA;QAAMA,WAE9BA;MADEA,6BACFA;K;;;;;;;;;;;;;;;;;;;;;;oCCzF+BC;MACXA;;MACXA;QAAuBA,WAiB9BA;MAfuBA;MAAIA;oBACAA,oBAAzBA;QACMA,wDAA6BA;UAC/BA;MAKKA;MAEeA;MACLA,oBAAIA;MAFfA,kCAGaA,eAAIA;MvF3ClBA;MuF6CEA;MAPTA,OAAWA,qCvFtCJA,8CuF8CTA;K;2CAM6BC;MAE3BA;MAAUA;QAAwBA,WAmBpCA;MAfWA;QAAuBA,WAelCA;MAbqBA,gEAA0BA,kBAAQA;MACrCA;MACCA;MACFA;MACNA;QA8CPA,qBAAmBA,oBAAcA,iBAAWA,iBAAMA;QACzCA,sBAAMA;QADfA;0BAA0DA;QAEjDA,yCACJA,kBAAQA;QAjDcA;;;MAA7BA;QACcA,0DAAuBA,eAAKA;QACVA;QAAIA;QACdA;QACLA,oBAAIA;;0BAAKA;QAFdA,gCAGEA;QACCA;QAAMA;QAAeA;QAAIA,yCAAoBA;;MAE5DA,OAAWA,mDACbA;K;qCAI6BC;MAC3BA;MAASA,mBAAIA;QAAaA,WAa5BA;MAZWA,mBAAIA,cAAaA,iBAAMA;QAAMA,WAYxCA;MAVkBA,0DAAuBA,eAAKA;MAGnCA;MACmBA;MAAIA;MACRA;MACLA,oBAAIA;;wBAAKA;MAJ5BA,OAAWA,6BAEHA,0BAGQA,wDAEPA,mBACXA;K;iCAIWC;mBvFkRSA;MuFjRlBA;QAAkBA,QAUpBA;MAPMA;QACFA,2BAEoBA,wDAIxBA;;QAFIA,YAAqBA,gDAEzBA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBzChGSC;MAIPA;MAKAA;QAYEA,OAAOA,6CAeXA;;;;c1DkC+CC;;;;MoG7E/CD,oCpGuCAE;M0DPSF;MAAPA,kBAAgBA,kD0C3BLA,oCAKQA,0EADSA,8DAFNA,wDACKA,0F1CkCXA,wCAACA,yBAAuCA,gEAC1DA;K;yBA6BQG;MAzFuDA,U1CoPpCC;;;M0CpPuBD,cAAKA;QAALA,eAAKA,C1CoP5BC;QoFjGbC;QAwDdC,OAxDwCD;Q1CzDZF,mB0CiH2BG,4BAxKOH,W1CkE9DA;;MAREA,O2C3HFA,gB3C2HuBA,kCADLA,uBAA0BA,4BAS5CA;K;0BAUQI;MACNA;MAAUA;QAAUA,YAItBA;Y1CgI2BH;M0CpPoCG;;MAAbA,cAAKA;QAiH3BA,OAjHsBA,UAAKA,C1CoP5BH,8B0CnIqBG,iBAGhDA;;MAFYA;QAAUA,OAsBtBA,YAA6CA,yBAtBNA,wDAEvCA;MADEA,O2CjJFA,gB3CiJuBA,0CACvBA;K;uBAOQC;MACNA;;MAYFA,SAZYA;QAASA,mBAYwBA,yBAZPA,4DAStCA;MARMA;QACFA,OAUJA,YAA6CA,yBjEoO7CxI,yBiE7OQwI,gE/CwFoCA,mC+CxFRA,yFAMpCA;MAJOA;QAA0BA,OAOjCA,YAA6CA,yBAPKA,sBAAKA,gEAIvDA;MAFEA,OAKFA,YAA6CA,yBjEoO7CxI,yBiExOMwI,gE/CmFsCA,mC+CnFZA,0FAChCA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBoBpCSC;MACLA;yCAAsCA,kDAIbA,kGAOtBA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBwBtHMC;MACIA;;MACfA;QAAsBA,eAExBA;MzCScC,8ByCVMD;MAAlBA,OzCfFA,wByCewCA,mCACxCA;K;;;;;;8BC+KeE;MACMA,WAIrBA;K;6BAGiBC;MACqBA,QAAOA,WAE7CA;K;;;+BCvM4BC;MACnBA;MACPA;QACEA;;;UAGkBA;;UAChBA,iCAFFA;;;;MAWcA;MAFhBA,OAAOA,oEAESA,0BAAYA,mDAEdA,oCACQA,gFAExBA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eCTWC;MRiDiDA;sCAAxBA,CjFyMTC,0BiFzMiBD;MQ/C5CA;QAAsBA,eA0BxBA;YAzBMA;MAAJA;QAA6BA,SAyB/BA;MAnBoBA;MAClBA,oBAAkBA;MAiBlBA,QAAOA,gBACTA;K;UA0DKE;MAeYA;MAPfA,cAAUA;MAYVA,MAEFA;K;WAwDKC;MAeYA;MAPfA,cAAUA;MAYVA,MAEFA;K;;;;;;UCjOanC;MACHA,+BAA6BA;IAC/BA,C;;;;;;;8BxDgDNoC;;;mCACiCA;mCACAA;a7BuaLA;aAKEA;M6B3a5BA,csC8BEA,oBnE+tBJ5R,uFA0CA6R;M6BryBED,gBsC4BEA,oBnE+tBJ5R,uFA0CA6R;M6B1yBAD;IAQAA,C;;;;;iCyDmCQE;MACNA;;;QACEA,OAAOA,2CACSA,sDAoBpBA;MAjBuBA;MACRA;MACbA;QAKoCA,yBAAZA;QAAyCA,yBAAlBA;QACjCA;QADZA,OAtBJA,4BACwBA,aACCA,cACLA,SACGA,YACGA,YA2B1BA;;MANEA,OAlCIA,cAkCuBA,oBAAZA,+BAAyCA,oBAAlBA,oCACRA,kBAAhBA,mCACkBA,kBAAjBA,oCACOA,kBAAZA,+BACkBA,kBAAfA,kCACqBA,kBAAlBA,oCAClBA;K;;;;;;;;;;;;;;;YfZKC;MAEEA,oCAD4BA;MACnCA,6BAA2BA,0CAC7BA;K;gBAOOC;;iBACIA;MAATA;QAAsBA,OAAYA,gDAKpCA;MjFwJeA,uFiF3J2BA;cAC/BA;QAAYA;MACrBA,0BAA+CA,qCACjDA;K;eAMOC;MACLA;QAAiBA,YAGnBA;MADEA,kBACFA;K;iBA8JOC;MAEWA;;QAELA;;MAECA;eACFA;QAAaA,oBAUzBA;MAR2CA;MjFjB5BA,2DiFoBkBA,eAAWA,mBnGwB1CvK,uBAEyBA,mBAFzBA,iDmGxBAuK;QAC0BA,qBnG4BTA;MmG1BUA;MAC3BA,sCACFA;K;;;0BgB5MEC;M1CjDgBhG,UlD6OW1O;;;;;;M4F5L3B0U,uC1CrFIC,kBnDkBA/H,sBAsLJD,oHAtLIC,sBAsLJD,4BqDwIAkC,iGwC5Q0B6F,0CAGCA,0CAGDA,0CpDlEtBE,oBzCUAhI,sBAsLJD;M6FnHA+H;;IAMAA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WC3CEG;MACMA;QAAQA,UAIlBA;MADEA,sBAAUA;IACZA,C;yBAKIC;MACFA;MAAQA,0BlG6fYA;QkG7fUA,OAAOA,0BAGvCA;MAFuBA,gCAAbA;QAAkBA;MjGgWNA;QiGhWeA,UAErCA;MADuCA;6ClGsgB7BC;MkGtgB0CD;MAAlDA,OAAOA,iCACTA;K;kBC1EKE;MACDA;MAA+CA;QACzBA;;QADyBA;MAA/CA,SAC8CA;K;mBAO7CC;mBACMA;;MAATA;QAA6BA,YAK/BA;MAJOA,oBAAaA;QAAyBA,YAI7CA;MAHMA;QAA2CA,YAGjDA;MAFEA;QAA8BA,WAEhCA;MADEA,OAAOA,gDACTA;K;oBCRIC;MACEA;MvHqDJlJ,wCCmQAmJ,uBAEyBA,mBAFzBA,kEsHvTAD;ctH4TiBA;UsH3TkBA;MAEnCA,YACFA;K;mBAMIE;MAGFA;cnGkZoBA;QmGhZlBA;UACcA;UACZA;YACEA,cAAeA,4DAmBvBA;UAdMA;YAAuCA,sBAc7CA;UAbwBA;;MAIVA;aACZA;QAEmCA;QAEjCA;UAA0BA,gBAI9BA;QAHYA;;MAEVA,WACFA;K;uBC/CKC;MACHA;MAKEA;QACEA,sBAAMA;gCACqBA;QAC3BA,sBAAMA;sCAS2DA;MAArEA;QACEA,sBAAMA;IAGVA,C;;;gBCOEC;;aASWA;;MAATA,0BAASA;MATXA;IAUAA,C;6BAkJWC;MACTA;;MACiBA;mBACjBA;QACmBA;QACjBA;UAAqBA,aAGzBA;;K;;;;;;;;;;;;;;;;;;;;;;;;;;iBClKMC;MACNA;;QACEA,QAYJA;WAXeA;QAEXA,OCkRFC,mDDzQFD;WAReA;QAIXA,OC6QFC,iBD7QmBD,8DAIrBA;;QAFIA,8BErBFE,gCA2EAA,0BFpDFF;K;YAMOG;MtGSSA,GsGRRA;MACNA,iDtGGSA,gDsGHmBA,wBtGOcA,mCsGPCA,wBAK7CA;K;oBAGOC;MACDA;MAAOA;WAAMA;M1E4jBjBC;MlCzFmBD;MACZA;QAAeA,kBAA2BA;MACjCA;MACVA;QAAeA,kBAA2BA;M4GrehDA,eAAsCA,6BAAvBA,sDACjBA;K;;;;;;qBG5CUE;MAGUA;MAMhBA;QACgBA;MAMhBA,OAQFA,6BAPAA;K;eAw/BEC;MAEMA;QAAQA,UAElBA;MADEA,sBAAoBA;IACtBA,C;sBAIKC;MACHA;yBAAyBA,gBAAzBA;gBAEMA,mBAAmBA;UAAqBA;eAG5CA;UACWA;kBAALA;YAA2BA;;QrH9fnCA;QAOiBA;eA2BftL;QWnUWsL;;QlByIbtG,4EA5OyEsG,O4H04B9DA,mC5H9pBXtG,yD4H+pBOsG;erHreLtL;;QqHueAsL,sBAAMA,iBAAcA;;IAExBA,C;;;;;;;;;;;;;;;;;;;;;wCD/+BcC;mBpHsgBmCvL;MoHrgB7CuL;QpH0eeA;YA2BfvL;QoHngBauL,IpHmgBbvL;;QoHjgBauL,IpHigBbvL;IoH/fFuL,C;yCAEYC;;iBpH6fmCxL;gBoH5f1BwL;QACNA,IpH2fbxL;;QoHzfawL;YpHyfbxL;;;IoHtfFwL,C;;;;;;;;;;;;;;;;;;;;oBnEqCAC;;uCApCwBA,4CAI8BA,oFAIlCA,mCAIDA,mCAwBnBA;;;IAmCAA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aqEvFSC;MAKLA;;QAEQA;;QACVA,wBAFFA;gBAGMA;UAAJA;YAAsBA,SAqB1BA;UApBIA;;UAJFA;;MASIA,iBAAOA;QAAiBA,QAAOA,SAerCA;;MAZYA,+BAAkBA;QAE1BA,oBADWA,mBAAiBA,aAWhCA;;QAReA;iBAGUA;;QACdA;yCAAIA;iBAAJA;QAAPA;QAEAA,6CADmCA,kDAGvCA;;K;;;iBC/FO3E;MAqGLA,OApGmBA,wDAoGAA,kBAAoBA,yDACzCA;K;eAMO4E;MACCA;QAASA,aAKjBA;MAJQA;QAAQA,YAIhBA;MAHQA;QAAQA,YAGhBA;MADEA,OAAYA,mCACdA;K;mBAOOC;MAAgCA,kBAAOA;MAAPA,O3G3E5BA,2C2G2EiEA;K;;;;;;;;;;;;;;;;;;MCRnCC;;;;;;yBAA/BA;MAA+BA,4CAA6BA,yCAuB9DA;K;yBAGEC;MAA+BA,4CAA6BA,yCAwC9DA;K;8BAYEC;MAAoCA,4CAA6BA,8CAyBnEA;K;+BAcEC;MAAqCA,4CAA6BA,+CAoBpEA;K;2BAUKC;MACLA,oCAAUA,sBAASA;QACrBA,OAAWA,sBAYfA;WAXaA,6CAAmBA;QAC5BA,OAAWA,iCAUfA;WATaA;QACTA,OAAWA,kCAQfA;MAFMA;QAA0BA,OAAYA,iBAAQA,kBAEpDA;MADEA,OAAWA,sBACbA;K;iCAMaC;MACXA;;QACSA;QAAPA,SAIJA;;QAHIA,8BAFFA;UAGEA,OCzRJA,oBAVoBC,gDDqSpBD;;UALEA;;IAKFA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBE5RYE;MACKA;;M7EqvlCjBC,8E6E/ulCiBD,gBAAWA,oCAMzBA,SAAKA;MAiBiBA,2D7Euz7BAA,S6Evz7ByBA;M/Ef3CA;iBEs07BkBA;oE6Etz7BLA;MAEpBA,iBxEXgCA,SwEYlCA;K;;;;;;;;;;;;;;MCTME;;0BADmBA;MACnBA,yDAAeA,gDACHA,sCAAWA;K;;;;;;;;;;;;;;;;;uBvEX3BC;MAE0EA;;MAF1EA;;;IAwBAA,C;;;;;;;;;;;;;;;;;;;;;;;;;;;MwEnDAC;;;;;;IAAiBA,C;;;;;;;;EzH+TcC;SAFjBC;MAAaA,yBAAsBA;K;kBAEzCD;MAAYA,4CAA+BA;K;gBAE5CE;MAAcA,yBNuUGA,IADRA,4CMtUiDA;K;qBAqBxDC;MAAeA,iCAAoBA;K;;;gBAQrCC;MAAcA,uBAAgCA;K;kBAU7CC;MAAYA,iCAAwCA;K;qBAEnDC;MAAeA,sBAAIA;K;;;;SAWdC;MAAaA,oBAAsBA;K;gBAG1CC;MAAcA,aAAMA;K;kBAEnBC;MAAYA,QAACA;K;qBAKZC;MAAeA,sBAAIA;K;;;;;kBAgCpBC;MAAYA,QAACA;K;qBAEZC;MAAeA,0BAAQA;K;gBAGzBC;MAAcA,uBAA+BA;K;;;;;;gBAwB7CC;MACiCA,0BAClCA;MAAJA;QAAyBA,OAAaA,8CAExCA;MADEA,oCAAkCA,+BACpCA;K;;;;;;;WQrUKC;mDAE4BA;;QAP7BA,kBAAMA;;IAQVA,C;gBAEEC;MAAQA;;QAVNA,kBAAMA;mBAakBA;MAA1BA;QACEA,sBAAUA;MAEZA,mCACFA;K;cAEKC;MAAMA;mDAMqCA;;QAzB5CA,kBAAMA;mBAsBiBA;MAAzBA;QACEA,sBAAUA;;IAGdA,C;iBAEKC;MAASA;4DAGRA;;QA/BFA,kBAAMA;mBA8BuCA;MAApCA;gCAIoBA;MAC1BA;MACKA;MACLA,uCAAmBA;MACnBA;IACPA,C;kBAUEC;;QAjDEA,kBAAMA;kBAmDJA;QAAaA,sBAAMA;MACvBA,qBACFA;K;cAEKC;MAAMA;;QAvDPA,kBAAMA;MAyDRA,wBAAyBA,SAAzBA;QACUA;;UAENA,WAINA;;MADEA,YACFA;K;cAiDKC;MACCA;4DAEQA;kBAFCA;;QAlHXA,kBAAMA;MAoHRA;;QAEMA;QAFNA,6BAEkBA,WAAWA,kBAAUA;;;IAGzCA,C;eAMKC;MACCA;;oBAAWA;MACfA;QAIEA,iBAAEA;oBACOA;UAAeA,sBAAUA;;IAEtCA,C;aAEYzN;;MACVA,OlBqJFA,kEkBrJ4CA,WlBqJ5CA,kEkBpJAA;K;YAEO0N;MACUA;iCAAUA;;MACzBA,wBAAyBA,SAAzBA;QACEA,wBAAiBA;MAEnBA,2BACFA;K;YANOC;;K;cAsCLC;MACIA;MAAQA;;wBACMA;MAClBA;QAIUA,sCAAeA;oBACdA;UAAkBA,sBAAUA;;MAEvCA,YACFA;K;yBAEEC;;;;;oBACeA;MACfA;0BAIWA;kCAALA;UAAeA,cAKvBA;oBAJaA;UAAeA,sBAAUA;;MAEpCA;QAAoBA,OAAOA,eAE7BA;MADEA,sBAA2BA;IAC7BA,C;kBAXEC;;K;iBAoDAC;MACWA;;MAAXA,eAAWA,OACbA;K;eAEQC;uCAGmBA;QACvBA,sBAAUA,qCAA2BA;uCAMZA;QACvBA,sBAAUA,uCAA6BA;MAG3CA;QAAkBA,OAAUA,wDAG9BA;MAFEA,wDAAWA,+BAEbA;K;eAOMC;kBACAA;QAAYA,eAAWA,GAE7BA;MADEA,sBAA2BA;IAC7BA,C;cAEMC;uBACAA;MAAJA;QAAgBA,eAAWA,QAE7BA;MADEA,sBAA2BA;IAC7BA,C;gBAEMC;uBACAA;MAAJA;QAA4BA;;QAAXA,eAAWA,GAG9BA;;MAFEA;QAAiBA,sBAA2BA;MAC5CA,sBAA2BA;IAC7BA,C;gBASKC;;;gCAWCA;;QAzTFA,kBAAMA;MAiTGA,iDAAiCA;MAC/BA;MACbA;QAAiBA,MAiCnBA;MAhCaA;MAMTA;MAMkCA;;QAClCA,sBAA2BA;MAE7BA;QAIEA;UAIcA;;QAIdA;UACcA;IAIlBA,C;gBAtCKC;;K;iBAwCAC;MAASA;;;QAtVVA,kBAAMA;MAwVGA,iDAAiCA;MAC5CA;;IAIFA,C;oBAEKC;MAAYA;4DAGXA;;QA5VFA,kBAAMA;mBA2VoCA;MAAjCA;MAIQA;MAIDA;MAFlBA;QACcA;QAESA;QAChBA;QACLA;UACOA;UACAA;;;QAIcA;QAEhBA;QACAA;QACAA;;IAETA,C;gBAsFKC;MACHA;8BAAoBA,SAApBA;QACUA;UAAcA,WAG1BA;MADEA,YACFA;K;iBAESC;MAAWA,4BAAWA;K;gBAIxBC;MAAcA,OkH9iBJA,uDlH8iB+BA;K;aAYzCC;MAAWA,OAAIA,0FAAiBA;K;kBAEvBxY;MAAYA,OAwG5BA,sCAEyBA,SA1GOA,+BAwGhCA,4BAxGsDA;K;kBAE9CyY;MAAYA,OAAWA,qCAAoBA;K;gBAE3CC;MAAUA,sBAAiCA;K;gBAE/CA;MAAMA;;QAveNA,kBAAMA;;QA0eNA,sBAAUA;MAGZA;QACEA,sBAAUA;;IAKdA,C;YAEWC;MACLA;;QAAeA,sBAAMA;2BACZA;QAAqBA,sBAAMA;MACxCA,sBACFA;K;eAEcC;MAERA;mDAEiCA;;QArgBnCA,kBAAMA;;QAmgBWA,sBAAMA;2BACZA;QAAqBA,sBAAMA;;IAE1CA,C;;;;;;;iBA8EMC;MAAWA,oBAAQA;K;gBAEpBC;;kBACUA;oBAAUA;eAKnBA;QACFA,sBAAMA;gBAGJA;MAAJA;QACEA;QACAA,YAKJA;;MAHEA,qBAAWA;;MAEXA,WACFA;K;kBA1BEC;;K;;;;amHxlBEC;MACFA;;QACEA;UACEA,mBAcNA;aAXIA;QAEiBA;QAAfA,yDASNA;;MALiCA;;QAC7BA,QAIJA;MADEA,sBAAUA;IACZA,C;aAEIC;MACFA;QAGEA;UACEA,2BAYNA;aAVSA;QAMLA,mCAIJA;MADEA,sBAAUA;IACZA,C;qBAkEOC;MAAaA;MAElBA;QACEA,sBAAUA;MAIRA;wDAAyBA;QAC3BA,aAGJA;MAOMA;MAAJA;QAEEA,kBAAUA;;MAEeA;gCAAKA;oBAGCA;MAFFA;gCAAKA;uBAALA;gBAC3BA;MAAJA;;QAIoBA;;MAlBpBA,sDACFA;K;gBAqBOC;MACLA;QACEA,aAIJA;;QAFIA,oBAEJA;K;kBAEQC;MACFA;;MAGJA;QAAsBA,2BA6BxBA;MAvB4CA;MAC/BA;MAI4BA;MAUvBA;MAOhBA,kHACFA;K;UAwBkBC;MAChBA;MAGAA;QAAiBA,QAOnBA;MANEA;QAAgBA,aAMlBA;MALEA;QACEA,qBAIJA;;QAFIA,qBAEJA;K;WAIaC;MAGXA;QACEA;UACEA,2BAINA;MADEA,OAAOA,iCACTA;K;iBAEIC;MAEFA,4DAEMA,iCACRA;K;iBAEIC;MACEA;MACJA;QAEEA,mBAgBJA;MAdEA;QAGEA;UACEA,2BAUNA;aARSA;QAELA,0BAMJA;MAFEA,sBAAUA,0DAC6BA,uBAA0BA;IACnEA,C;oBAaIC;MAGFA,+CAGFA;K;yBASIC;MACFA;;QACMA;;;;;MADNA,SAOFA;K;4BAEIC;MACFA;QAA+BA,sBAAMA;MACrCA,OAAOA,wCACTA;K;wBAEIC;MACFA,0CASFA;K;qBAqCSC;MAAeA,qBAAGA;K;;;;;qBAoPlBC;MAAeA,qBAAGA;K;;;;qBAOlBC;MAAeA,wBAAMA;K;;;kBlH7qB1BC;MAEFA;QAAeA,sBAAMA;2BAKRA;QAAQA,kBAAMA;MAJ3BA,iCACFA;K;mBAEIC;2BACWA;QAAQA,sBAAMA;MAC3BA,iCACFA;K;kBAEgBC;MAAUA;MfqxC1BA;QAAsBA,kBAAMA;iBelxCMA;MAAhCA;QACEA,sBAAUA;MAEZA,OPiCFC,wDOhCAD;K;kBAPgBE;;K;qBASVC;MACJA;qCAAgCA;QAC9BA,sBAAUA,mCAAkCA;mBAE7BA;6BAAgBA;QAAQA,YAQ3CA;MALQA,6CADNA;QACMA,2CAAqCA;UACvCA,YAINA;MADEA,OPjBIA,kCOkBNA;K;UAEgBC;MACdA;QAAsBA,sBAAUA;MAChCA,uBACFA;K;gBAEKC;6BAEqBA;qBACNA;MAAlBA;QAA0BA,YAE5BA;MADEA,iBAAgBA,4CAClBA;K;4BAUOC;MAELA,OAAOA,gDAA0CA,6CAASA,0CAC5DA;K;oBAEOC;MAGMA,gDAAyCA;MACpDA,OAAOA,oDACTA;K;oBAsBOC;MAGYA,uDAAiCA;MAElDA,OAAOA,gEACTA;K;kBA8BKC;MAAUA;MAKTA;uCAH0BA;QAC5BA,sBAAUA,qCAAgCA;MAE5CA;kCAE0BA;+BAETA;UAAQA,YAI3BA;QAHIA,sDAGJA;;MADEA,OAAOA,qDACTA;K;kBAbKC;;K;iBAeEC;MAELA;2BAAiCA;MAEjCA;QAAoBA,sBAAUA;MAC9BA;QAA2BA,sBAAUA;6BACtBA;QAAQA,sBAAUA;MACjCA,+CACFA;K;iBAROC;;K;YAkHAC;MAMDA;;yBAAOA;MAAXA;QAAwBA,aAiB1BA;MAhBkBA;QAGDA;QACbA;UAAiCA,SAYrCA;;QAFMA;MAJ6BA;MAAlBA,oDAEFA;MAEbA;QAAkDA,aAEpDA;MADEA,8CACFA;K;UA0DgBC;MACdA;;QAAgBA,SAelBA;iCAdyBA;QAAaA,eActCA;MAbEA;QAEEA,uBAAYA;MAIdA;QACEA;UAA6BA;QAEzBA;QAAJA;UAAgBA;QAChBA;;MAEFA,aACFA;K;eAEOC;kCACoBA;MACzBA;QAAgBA,eAElBA;MADEA,OAAOA,oCACTA;K;gBAEOC;MACDA;MAAQA;2BAAMA;8BAAOA;MACzBA;QAAgBA,eAElBA;MADEA,kBAAcA,qBAChBA;K;eAMIC;MAAOA;uCAGqBA;QAC5BA,sBAAUA,qCAAgCA;MAG1CA;eAWJA;K;eAlBIC;;K;mBAoBAC;MAAWA;MAEbA;wBACUA;4CAG2BA;QACnCA,sBAAUA,qCAAgCA;kBAIxBA;mBAAcA;MAAhCA;QACeA;MAEfA,2CAMJA;K;mBApBIC;;K;gBAsBCC;Mfm3BLA;QAAoBA,kBAAMA;Me92BxBA,OAAOA,6CACTA;K;gBAYOC;MAAcA,eAAIA;K;kBAMjBC;MAGFA;wBACgBA,0BAApBA;;QAEoBA;;;MAGFA;MAEGA;MAArBA,gDACFA;K;qBAESC;MAAeA,wBAAMA;K;gBAEtBC;MAAUA,sBAA4BA;K;YAE9BC;MACVA;2BACSA;QAAqBA,sBAAMA;MACxCA,sBACFA;K;;;;;kBrBzcgBC;MAAgBA,aAAmBA;;MAAvBA,OAgD5BA,mBAhD2DA,qBAgD3DA,6BAhDgCA,WAgDhCA,6BAhDoEA;K;gBAuB5DC;MAAkBA,aAARA;8BAAcA;K;iBACvBC;MAAmBA,aAARA;+BAAeA;K;eAO7BC;MAAuBA,aAAdA;kCAAcA,cAANA,iBAAUA;K;cAC3BC;MAAqBA,aAAbA;kCAAaA,cAALA,gBAASA;K;gBAG1BC;MAA0BA,wCAAuBA;K;gBAQ/CC;MAAcA,iCAAkBA;K;;EAMpBC;gBAAdA;MAAcA,gCAAkBA;K;iBAC/BC;MAAWA,OAAgBA,sBAARA,IAARA,uBAAoBA;K;;;;;;cAqMzBC;MAFZA;MAE8BA,yBAA4BA,UAF1DA,6BAEkCA,mCAFlCA,4BAEkEA;K;mBAI7DC;MAA2BA,sCAAwBA;K;YAE7CC;MAAkBA,OAAaA,sBAAbA,4BAAiBA;K;cAa5CC;MAAsBA,OAAoBA,sBAApBA,8BAAwBA;K;eAM3CC;MACHA,0BAAgBA;IAGlBA,C;cAEgBC;MAAYA;MAAJA,mCAAgCA,IAARA,uBAApBA,4BAAiCA;K;gBAIrDC;MAAkBA,aAARA;8BAAcA;K;iBAEvBC;MAAmBA,aAARA;+BAAeA;K;;;YAXjBC;;MACZA;MAAUA;MAAZA,cAAMA,sBAAYA;IACnBA,C;gBAFeC;;K;;ECtNQC;gBADlBC;MAAUA,mBAAQA,OAAMA;K;YACnBD;MAAaA,qDAAmBA,uBAAEA;K;;;;kBCrC/BjU;MAAYA;aAqS5BA,0BAEyBA,yBAvSOA,uBAqShCA,wCArSqDA;K;iBAY5CmU;MAAWA,kCAAWA;K;eAEzBC;MACAA;QAAaA,sBAA2BA;MAC5CA,OAAOA,sBACTA;K;cAEMC;MACJA;MAAIA;QAAaA,sBAA2BA;MAC5CA,OAAOA,qBAAUA,4BACnBA;K;gBAQKC;MACeA;;MAClBA;QACMA;UAAyBA,WAMjCA;QALuBA;UACjBA,sBAAUA;;MAGdA,YACFA;K;YAwEOC;MACaA;;mBmB6RAA;QnB3RhBA;UAAiBA,SAwBrBA;QAvBsBA;QACCA;UACjBA,sBAAUA;QAGZA;UOiaaA,0BP/ZEA;UACMA;YACjBA,sBAAUA;;QAGdA,sCAWJA;;QARIA;UOuZaA,UPtZEA;UACMA;YACjBA,sBAAUA;;QAGdA,sCAEJA;;K;YA3BOC;;K;aA+BKhP;;MAA0BA,OA4OtCA,2EA5OyEA,WA4OzEA,+EA5O2EA;K;cAezEiP;MACIA;MAAQA;;MACMA;MAClBA;QACUA,8BAAeA;QACJA;UACjBA,sBAAUA;;MAGdA,YACFA;K;uBAUQC;MAGQA;;MAAIA,qCAASA;MAI3BA,YAAoBA,6BAApBA;QACEA,uCAAYA;MAEdA,aACFA;K;cAXQC;;K;aAaDC;MACeA;;MACpBA,YAAoBA,6BAApBA;QACEA,gBAAWA;MAEbA,aACFA;K;;;mBAmBQC;MACiBA,mCAAVA;iBACTA;MAAJA;QAAmDA,cAErDA;MADEA,SACFA;K;qBAEQC;MACiBA,mCAAVA;iBACTA;MAAJA;QAAqBA,cAEvBA;MADEA,SACFA;K;gBAEQC;MACiBA;uCAAVA;iBACTA;MAAJA;QAAsBA,QAKxBA;eAJMA;MAAJA;QACEA,mBAGJA;MADSA;wBAAaA;MAApBA,cACFA;K;iBAEEC;MACgBA;;MAChBA;QAA8BA;QAAbA;0BAAUA;QAAVA;;QAAjBA;;QACEA,sBAAUA;MAEZA,OAAOA,uDACTA;K;YAWYC;MAAIA;MACHA;gBACPA;gBAGWA;;MAHfA;QACEA,OAAWA,wBAAmBA,4CAAnBA,eAMfA;;QAHIA;UAA2BA,YAG/BA;QAFIA,OAAWA,wBAAmBA,4CAAnBA,eAEfA;;K;;;iBAoCMC;MAAWA,+BAAQA;K;gBAGpBC;MACoBA;kBAAVA;;kBAAUA;eACnBA;QACFA,sBAAUA;gBAERA;MAAJA;QACEA;QACAA,YAKJA;;MAHEA,8BAAWA;;MAEXA,WACFA;K;6BAtBEC;;K;;;;kBAwCcC;MAAgBA;MAAJA,OAwB5BA,qBAxB+DA,sBAAVA,4BAAoBA,KAwBzEA,6BAxBgCA,WAwBhCA,+BAxB4EA;K;gBAGpEC;MAAUA,OAAUA,qBAAVA,sBAAgBA;K;iBACzBC;MAAWA,OAAUA,sBAAVA,sBAAiBA;K;eAG/BC;MAASA,sBAAaA,mBAAVA,uBAAgBA;K;cAC5BC;MAAQA,sBAAaA,kBAAVA,uBAAeA;K;;;;gBAkB3BC;;kBACCA;;QACFA,8BAAWA,gBAAaA;QACxBA,WAIJA;;MAFEA;MACAA,YACFA;K;iBAEMC;MAAWA,+BAAQA;K;6BAfvBC;;K;;EA6BwBC;gBAAlBA;MAAUA,qCAAcA;K;iBAC9BC;MAAwBA,sBAAGA,sCAAyBA;K;;EAqBtDC;kBAVgBA;MAAYA,2BAA+BA,sBAAVA,4BAAoBA,KAUrEA,qCAVwEA;K;aAG5DpQ;MAlEZA;MAkEsCA,iEAAiCA,WAlEvEA,8DAkEyEA;K;;;gBASpEqQ;MACHA;oBAAOA,qBACDA,KADCA;kCACDA,UAAaA;UACfA,WAINA;MADEA,YACFA;K;iBAEMC;MAAWA,OAAUA,IAAVA,wBAAiBA;K;;;kBAWlBC;MAYhBA;MAZ4BA,4BAAmCA,sBAAVA,4BAAoBA,MASnCC,kBAGtCD,6BAZgCA,WAYhCA,+BAZ4EA;K;;;iBActEE;MAAWA,+BAAQA;K;gBAEpBC;MACHA;eAAIA;QAA2BA,YAcjCA;qBAP6BA,sBAAHA,KANhBA;QACNA;QACIA;UAGFA;UACAA,4BAA0CA,kBAAtBA,UAAaA;;UAEjCA,YAKNA;;MAFEA,8BAA6BA,KAAlBA;MACXA,WACFA;K;2BAtBYC;;K;6BACVC;;K;;;EAkMFC;kBAVgBA;MACdA,+BAA0CA,sBAAVA,4BAAoBA,KAStDA,yCARAA;K;;;gBAUKC;MACHA;gBAAKA;aACHA;uBACOA,sBACAA,KADAA;qCACAA,UAAaA;YAAUA,WAIlCA;;MADEA,OAAOA,4BACTA;K;iBAEMC;MAAWA,OAAUA,IAAVA,wBAAiBA;K;;;gBA0F7BC;MAAcA,YAAKA;K;iBAClBC;MAAWA,WAAIA;K;;;;gBsI/uBjBC;MACFA,sBAAUA;IAEZA,C;;;eAwEcC;;;MACZA,sBAAUA;IACZA,C;gBAGIC;MACFA,sBAAUA;IAEZA,C;;;EA6J0BC;gBAAlBA;MAAUA,qCAAcA;K;iBAE9BC;MAAkDA,aAA1BA;;gCAA0BA,8BAAmBA;K;;;kBvG9O/DC;qBAEFA;MAAJA;QAAkBA,WAKpBA;MAH8CA,gDAANA;MAMhBC;MAJtBD,WACFA;K;gBAGAC;MAAcA,4BAAUA,yBAAQA;K;SwGoFlBC;MAAEA;oBAAkDA;MAAvCA,wCAAmBA,0BAAeA,iBAAKA;K;;;crI9DtDC;MAAsBA;MAAJA,OAAIA,2DAA4BA;K;iBACrDC;MAAWA,kCAAWA;K;gBAIxBC;MAAcA,OAAQA,2BAAiBA;K;cAQ5CC;MAAsBA,yCAAoBA;K;aAYhCC;MACWA;MAChBA,kBAAQA;MAIbA,aACFA;K;;;;YALeC;;gBACCA,sBAAUA,8BAAKA;MAC3BA,8BAAaA,WAAaA;IAC3BA,C;gBAHYC;;K;;;gBAgCPC;MAAUA,+BAA4BA;K;mBAOzCC;MACHA;QAAoBA,YAGtBA;MAFEA;QAAwBA,YAE1BA;MADEA,WAAwBA,8BAC1BA;K;YAEWC;MACJA;QAAkBA,WAEzBA;MADEA,yBACFA;K;cAGAC;MAAeA,WAAiBA,WAAWA,4BAAIA;K;eAE1CC;;;;;oBAKsBA,gBAEhBA,kBAFTA;kBACYA;QACVA,cAAOA;;IAEXA,C;cAEgBC;MACdA,OA4BFA,oCA5BaA,sBA4BbA,sCA3BAA;K;;;kBA6BgBC;MgByhBhBjhB,ahBzhB4BihB,iBgBibIA;MhBjbJA,iCgB2hBHjhB,SA1GOihB,yBAwGhCjhB,4BhBzhBoDihB;K;gBAE5CC;MAAUA,8CAAgBA,OAAMA;K;;;qBCnKxCC;MAOEA;QAIIA;IAKNA,C;gBAKOC;MACWA,4CAWCA;MARjBA,OAASA,4CACXA;K;;;;;;;;;;;;;EC0nB2BC;YAAZA;MAAMA,6CAA6BA,mBAAqBA;K;;;;sBAy0BvEC;;gCAEyDA,WACnDA;MAAJA;QAAmBA,WAmBrBA;MAhBqCA;gBAD/BA;MAAJA;;gBAGIA;MAAJA;;gBAGIA;MAAJA;;gBAGIA;MAAJA;;gBAGIA;MAAJA;;MAIAA,aACFA;K;;;gBAqNOC;mBACDA;MAAJA;QAAqBA,+BAA4BA,8BAEnDA;MADEA,kEACFA;K;;;;gBAaOC;;;kBACDA;MAAJA;QAAqBA,+BAA4BA,+BAMnDA;gBALMA;MAAJA;QACEA,4BAA0DA,qCAI9DA;MAFEA,4CACoDA,qCACtDA;K;;;;gBAQOC;mBAAcA;een0CDA,wCfm0CgDA;K;;;;YAsBpEC;MACYA;iBAEJA;qCACyCA;MAG/CA,YACFA;K;;;;gBA2JOC;;iBACDA;MAAJA;QAAoBA,SAQtBA;eAL+BA;;MAI7BA,WAAOA,oCACTA;K;;;;gBA6kBOC;MAMcA,uBAFfA;;MAEJA,6EACFA;K;;;;;;;;;;;gBAoBOC;sBAGDA;MAAJA;QAAkBA,yCAEpBA;MADEA,qBAAmBA,4BACrBA;K;;;SAsBcC;MACZA;MADcA;oBAMhBA;MALEA;QAA4BA,WAK9BA;;QAJ8BA,YAI9BA;MAHEA,YAA6BA,gBAAaA,eAChBA,kBAAeA,iBACfA,oBAAiBA,UAC7CA;K;kBAEQC;;iBAEFA;MAAJA;QAGgCA,mDAAeA;;QAIhBA,kEAICA;MAEhCA,2BAAqCA,gCAAeA,gBACtDA;K;gBAEAC;yBACiBA;;QAGGA,eAHiBA;MAGnCA,6BAAkBA,uCAv8DIA,IADRA,6CA08DhBA;K;;;gBAucOC;MAAcA,mBAAOA;K;;;;;EA2ESC;gBAA9BA;MAAcA,kCAAgBA,SAAQA;K;;;;;EA2VKC;gBAA3CA;MAAcA,uDAA0CA,SAAQA;K;;E6B/jGvEC;gBAhVQC;MAAUA,+BAAOA;K;iBAChBC;MAAWA,qCAAYA;K;cAGhBF;MACdA,4CAAWA,sBA2UbA,uCA1UAA;K;gBAEgBG;MACHA;MAAXA,OAAWA,gCAAqBA,iBAAMA,8CAA3BA,4BACbA;K;mBAEKC;MACHA;;uBACgBA;QACdA;UAAqBA,YASzBA;QARIA,OAAOA,yCAQXA;aAPSA;oBACMA;QACXA;UAAkBA,YAKtBA;QAJIA,OAAOA,sCAIXA;;QAFIA,OAAOA,gCAEXA;K;2BAEKC;;oBACQA;MACXA;QAAkBA,YAGpBA;MADEA,OAAOA,gCAmNAA,8BADIA,gDAjNbA;K;cAMKC;gDACHA,cAAMA,aAAQA;IAGhBA,C;YAEWC;MACTA;;uBACgBA;QACdA;UAAqBA,YAWzBA;QAV6BA;wCACqBA;QAA9CA,SASJA;aARSA;oBACMA;QACXA;UAAkBA,YAMtBA;QAL6BA;QAGlBA,gCAFuCA;QAA9CA,SAIJA;;QAFIA,+BAEJA;K;mBAEEC;;oBACWA;MACXA;QAAkBA,WAMpBA;MA8KSA,uCADIA;MAjLCA;MACZA;QAAeA,WAGjBA;MADEA,aAAmBA,wBACrBA;K;eAEcC;;;MACKA;MAGkBA;MAHnCA;uBACgBA;QAEdA,8DADqBA,wBAAqBA;aAErCA;oBACMA;QAEXA,2DADkBA,qBAAeA;;QAGjCA;IAEJA,C;mBAEKC;;;MAGgCA;MAGYA;kBALpCA;MACXA;QAAiCA,YAAfA;MACPA;MACEA;MACbA;QAEEA,oCADyBA;;QAGbA;QACZA;gBAEEA,OAAKA;;sBAEoBA;;IAI/BA,C;mBAEEC;;;MACgBA;wBACNA;MADNA;QAAkBA,OAAWA,oBAInCA;MAHYA;MACNA;MACJA,YACFA;K;cAEEC;MACAA;;QACEA,OAAOA,+CAAsBA,2BAMjCA;WALSA;QACLA,OAAOA,+CAAsBA,wBAIjCA;;QAFIA,OAAOA,2BAEXA;K;sBAEEC;;oBACWA;MACXA;QAAkBA,WAcpBA;MAbaA;MACEA;MACDA;MACZA;QAAeA,WAUjBA;oCANcA;MAAZA;;QAGEA;MAEFA,4BACFA;K;aAEKC;MACHA;eAAIA;aACFA,6BAAWA,0BAAQA,0BAAQA,eAASA;aACpCA;QACAA;;IAEJA,C;eAEKC;MACeA;;kBAAOA;2BACLA;aACpBA;QAGEA,kBAAOA,qBAAKA;mCACSA;UACnBA,sBAAUA;mBAEAA;;IAEhBA,C;sCAEKC;;;MAC2CA;MAEGA;MAFxBA;MACzBA;QACEA,mCAA2BA;;YAEtBA;IAETA,C;yCAEEC;MACAA;;QAAmBA,WAMrBA;MAL2BA;MACzBA;QAAkBA,WAIpBA;MAHEA;MACAA;MACAA,4BACFA;K;iBAEKC;UAKHA,sBAAkBA;IACpBA,C;sBAGkBC;;;eAgJlBA,wBA/IiDA,8BAAKA;eAChDA;aACFA,eAASA;;oBAEgBA;YACpBA;aACLA,aAAaA;;;MAGfA;MACAA,WACFA;K;+BAGKC;;uBAC+BA;mBACJA;MAC9BA;oCACiBA;aACfA;;gBAESA;MAEXA;oCACiBA;aACfA;;YAEKA;;MAGPA;IACFA,C;+BAaIC;MAIFA,OAAsCA,gCACxCA;K;+BAOIC;MACFA;;QAAoBA,SAOtBA;;MALEA;QAEWA,iBAALA,GAAKA;UAAuBA,QAGpCA;MADEA,SACFA;K;gBAEOC;MAAcA,OAAQA,2BAAiBA;K;qBAE5BC;MAChBA,iBACFA;K;uBAEwBC;MACtBA,iBACFA;K;sBAEKC;MAAcA;;IAGnBA,C;yBAEKC;MAKsBC;IAH3BD,C;2BAEKC;MAEHA,+CACFA;K;qBAEAC;MAQiBA;;MAAfA;MACAA;MACAA,YACFA;K;;;;YAxRwCC;MAAcA;MAAJA,sDAAKA,aAAKA;K;gBAApBC;;K;;;YA6BxBC;;;MACRA,gBAACA,8BAAOA;IACbA,C;gBAFaC;;K;;;;gBA4SRC;MAAUA,4BAAKA,oBAAOA;K;iBACrBC;MAAWA,4BAAKA,0BAAYA;K;kBAErBC;MA2BhBA,aA1ByCA;kDAAWA,iBA0BpDA;MAtBSC,EAuBPC,WAAaA;MA3BbF,SACFA;K;gBAEKC;MACHA,WAAOA,wCACTA;K;;;iBAyBME;MAAWA,gCAAQA;K;gBAEpBC;;kBACmBA;eAAlBA,sBAAuBA;QACzBA,sBAAUA;;kBACDA;QAAJA;UACLA;UACAA,YAMJA;;UAJIA;eACAA,cAAQA,MAAMA;UACdA,WAEJA;;;K;8BAnBEC;;K;;;;Y3BnBeC;MAAOA,WAA0BA,UAAUA;K;;;;YAExDA;MAAmBA,WAA6BA,sBAAsBA;K;;;;YAEtEA;MAAgBA,WAAeA,iBAAiBA,4BAAIA;K;;;;gBKvWjDC;MACHA,uBAASA,qBAAoCA,oBAAcA;K;8BAW3DC;;kBACEA;MAAJA;QAAiCA,SAGnCA;MAF+BA,UAeoBA;MAfjDA,YAAOA,wDACHA,oEACNA;K;gCAEIC;;kBACEA;MAAJA;QAAmCA,SAQrCA;MAFiCA,UAIkBA;MAJjDA,YAAOA,0DAAqCA,4EAE9CA;K;kBAwCYC;MACLA;MP8rCPA;QAAsBA,kBAAMA;MO5rCtBA,QAFgDA;MAEpDA;QAAeA,WAEjBA;MADEA,OAAWA,gCACbA;K;kBAYsBC;qBAGYA;MAAhCA;QACEA,sBAAUA;MAEZA,OAwGFA,8CAvGAA;K;kBAPsBC;;K;mBASVC;MACMA;;;MAGZA;MAAJA;QAAmBA,WAErBA;MADEA,OAAWA,oCACbA;K;qBAEYC;MACMA;;;MAGZA;MAAJA;QAAmBA,WAKrBA;MAFMA;iCAAMA;MAANA;QAA4BA,WAElCA;MADEA,OAAWA,oCACbA;K;qBAEYC;qCACsBA;QAC9BA,sBAAUA,mCAAkCA;MAE9CA,OAAOA,mCACTA;K;;;;;eA0BQC;MACJA,WAAgEA,aAAOA;K;aAEnEC;mBAF4DA;MAGhEA,8BAEWA;K;YAMCC;MAAiBA;MAAMA;eAFWA;;iCAAMA;MAEvBA,gBAAYA;K;;;;EAmD7C/vB;kBAV0BA;MACtBA,qCAAwBA,UAAKA,0BAASA,QAAOA;K;;;iBAWjCgwB;MAAWA,gCAAQA;K;gBAU9BC;;kBACCA;MAAJA;QAAqBA,YAyBvBA;gBAxBMA;kBAAsBA;kBACZA;;QACZA;eACEA;UACsBA;mBAhFwCA;kBAjHrBC;wBAuMnCD;;wBAAiBA;yBAAQA;gBACRA,4BAAQA;gBAAzBA;kBACkBA;kBAjB5BA;;kBAgBUA;;gBADeA;;cADnBA;YAMAA;;eAEFA;UACAA,WAMNA;;;WAFEA,4BADAA;MAEAA,YACFA;K;;;;aClQQE;MAAOA,wBAAQA,QAAQA,OAAMA;K;YACrBC;MAAmBA;MAIjCA;QACEA,kBAAUA;MALeA,WAOpBA,QAP4BA;K;;;;;;EAqDrCC;kBAlBoBA;MAChBA,2CAA8BA,aAAQA,eAAUA,oBAAOA;K;eAEjDC;MACJA,aAA6CA;oBAARA,wBAAkBA;MAC3DA;QACEA,OA5CEA,4BA+CNA;MADEA,sBAA2BA;IAC7BA,C;;;gBAWKC;;kBACCA;kBAASA;eAASA;kBAASA;eAAOA;MAAtCA;aACEA;QACAA,YAcJA;;MAXMA;MAAJA;aACEA;aACAA;QACAA,YAQJA;;MANYA;MArENA,KAsEJA;WAGAA,mCADWA;MAEXA,WACFA;K;iBAEUC;MAAWA,gCAAQA;K;;;;qBE3EpBC;MAAeA,4BAAUA;K;;;;;;qBA2XzBC;MAAeA,0BAAQA;K;;;gBAwQxBC;MAAUA,sBAAgCA;K;;;;YA2BlCC;MACGA;MAAjBA,4CAAmCA;MACnCA,sBACFA;K;eAEcC;MACKA;MACmBA;MADpCA,4CAAmCA;;IAErCA,C;;;;;;eAkBcC;MACKA;MACmBA;MADpCA,4CAAmCA;;IAErCA,C;;;;;;qBA4BSC;MAAeA,6BAAWA;K;;;qBAkC1BC;MAAeA,6BAAWA;K;;;qBAiC1BC;MAAeA,2BAASA;K;YAEpBC;MACMA;MAAjBA,4CAAmCA;MACnCA,sBACFA;K;;;qBAiCSC;MAAeA,2BAASA;K;YAEpBC;MACMA;MAAjBA,4CAAmCA;MACnCA,sBACFA;K;;;qBAiCSC;MAAeA,0BAAQA;K;YAEnBC;MACMA;MAAjBA,4CAAmCA;MACnCA,sBACFA;K;;;qBAiCSC;MAAeA,4BAAUA;K;YAErBC;MACMA;MAAjBA,4CAAmCA;MACnCA,sBACFA;K;;;qBAiCSC;MAAeA,4BAAUA;K;YAErBC;MACMA;MAAjBA,4CAAmCA;MACnCA,sBACFA;K;eAEWC;MAGTA,uBAAgBA,yBAFVA,uCAAkCA,UAG1CA;K;;;;qBA4BSC;MAAeA,kCAAgBA;K;gBAEhCC;MAAUA,sBAAgCA;K;YAErCC;MACMA;MAAjBA,4CAAmCA;MACnCA,sBACFA;K;;;qBA0CSC;MAAeA,2BAASA;K;gBAEzBC;MAAUA,sBAAgCA;K;YAErCC;MACMA;MAAjBA,4CAAmCA;MACnCA,sBACFA;K;eAEUC;MAGRA,sBAAgBA,yBAFVA,uCAAkCA,UAG1CA;K;;;;;;;;ETlrBiBC;aA/SbA;MAEFA,qEACFA;K;aAKIC;MAAsBA,OA+STA,qBA05DC/vB,AAAAI,iCAzsE+C2vB;K;;;;kBAgrBzDC;;iBAAYA;;gBAAsCA,KA7bzCA;QADgBA;;QA8b+BA,SAA5CA;;eAAoDA;K;SAG1DC;MAAEA;oBAEhBA;MADEA,uCAAqCA,cAAYA,KACnDA;K;gBAGOC;MAAcA,0BAAaA,YAAWA;K;;;;gBAiJtCC;MAAcA,oBAAQA;K;;;;iBAmBlBC;MAAWA,oBAAQA;K;;;Ye34B1BC;;cACUA;QACRA;MACAA;IACFA,C;;;;YAMOC;;MAEYA;;MAFZA,iBACEA;QACPA;eAG4DA;eACxDA;;IACLA,C;;;;YASHC;MACEA;IACFA,C;;;;YAOAC;MACEA;IACFA,C;;;;kBA2CF/pB;;YAQIA,2BACIA,yBAPiBA;;QASrBA,sBAAUA;IAEdA,C;2BAEAC;;YAIIA,4BAGIA,yBAAuBA;;QAa3BA,sBAAUA;IAEdA,C;cASK+pB;;qBAEGA;QAAJA;UAAqBA,MAUzBA;gBATQA;;;;YAKJA;;QAEAA,sBAAUA;IAEdA,C;;;;YAxDIC;mBACEA;;QACKA;MACLA;IACFA,C;;;;YAgB2BC;;kBACLA;;kBACZA;MAAJA;qCAC2CA;QACzCA;UACSA;;QAGNA;MACLA;IACDA,C;;;;gBAwCJC;;;uBACYA;gBAAVA,mCAAgBA;eACnBA;MADFA;QACEA;;QAEAA,wBAA2BA;IAE/BA,C;qBAEKC;mBAEDA;cADEA;QACFA;;QAEAA;IAEJA,C;;;EAqEgBC;YAAZA;MAAYA,0CAA+CA;K;;;;YAEtCA;MAGvBA,4BhB69CFA,oCgB99CwCA;IAEvCA,C;;;;YA0C0CC;UACvBA,YAAWA;IAC9BA,C;;;;qBuDhUQC;MAAeA,WAAIA;K;;;gBAuCvBC;IAAYA,C;iBAIZC;IAAaA,C;sBA/BQC;;K;0BACAC;;K;;;sBAgIjBC;MAAgBA,WAACA,WAAuBA;K;yBAEzCC;mBACFA;MAAJA;QAAyBA,SAE3BA;MADEA,WAAOA,erD+DTA,eCyE2BzqB,sCoDvI3ByqB;K;uBAsBKC;MAAeA;kEACDA;MADCA,2BACYA;MADZA,2BAEaA;6BACmBA;yBACJA;MAC9CA;QAEEA;;QAESA;MAEXA;QAEEA;;QAEKA;MAG2BA;MAArBA;IACfA,C;kBAIsBC;;;yBAOVA;MAJRA;gBAjFkBA;;UAiFPA;Q9C8gBfA,oCNvb2BC,wBMub3BD;QACEC;Q8C9gBED,SAUJA;;YpD4E2B7nB;;MoD1Q3B6nB;;MAAAE,sFAsL2CF;MAnLjCE;MAARA;MAwIiBF;MADFA,2BACeA;kBACjBA,oBAAeA;qBAEQA;MACpCA;MACaA;MACAA;MACbA;QACEA;;QAEQA;eAoCIA,4BAAoBA;QAEhCA,mBAAYA;MAEdA,mBACFA;K;qBAEOG;;;MACqBA,yFAAeA;aAEdA;QAAsBA,WAYnDA;eAnMuBA;MAwLrBA;QAtLwBA;;;QAyLtBA;kBA7EmBA,2BAaFA;UAoEfA;;MAGJA,WACFA;K;oBAEKC;;IAAkDA,C;qBAClDC;;IAAmDA,C;sBAIlDC;mBApHgBA;MAqHpBA;QACEA,O1EySJA,6D0ErSAA;MANoBA;MAKlBA,O1EsSFA,kE0ErSAA;K;WAEKC;MACHA;2CACUA;MADLA;QAAcA,sBAAMA;MACzBA;IACFA,C;gBAEKC;MAAQA;MAGgDA;;Q1EjI7DvqB;M0EgIOuqB;QAAcA,sBAAMA;MACKA,epDoCLA;MoDnCzBA;2BACoCA;;U1EnItCvqB;gC0EoI6BuqB;;MAE3BA;IACFA,C;gBATKC;;K;aAWEC;MACLA;gBA7IoBA;QA6IpBA,oBACSA;QACPA,YAAOA,YAOXA;;MALOA;QAAcA,sBAAMA;;MAELA;MACpBA;MACAA,iBACFA;K;wBAgBKC;MACHA,yBAAkBA;IACpBA,C;cAEKC;MAAMA;2BAhJkBA;sBAkJAA;MAC3BA;;M/C2nBAA,Q+CznBAA;IACFA,C;wBAGKC;MAEHA;;gBA7JqBA;MA6JrBA;QACEA,sBAAUA;0BAjJOA;MAoJnBA;QAAcA,MAgChBA;MA7BYA;WAOVA;aAEAA;yBAjSkCA;QAkShCA;sBACeA;UACbA;;6BAE8CA;UAC9CA;YACEA;;;;qCAK0BA;;;eA5KbA;QAkLjBA;IAEJA,C;qBAEKC;MACIA;MADSA,oBAtLGA;gBArCCA,2BA6NJA,YAAYA;QAE1BA;MAEFA,mBAAYA;IACdA,C;4BApR0BC;;K;2BACAC;;K;yBAGPC;;K;;;;;;;;;EA0RYC;sBAAtBA;MAAgBA,kFApNFA,kBAoNkCA;K;sBAEzDC;M1EiLAA,S0EvYuBA;QAwNnBA,uFAIJA;MADEA,OAAaA,sDACfA;K;iBAEKC;MACHA;MAIoBA;eAtNDA;QAkNLA,MAchBA;gBAjPmBA;qBAAoBA;;QAuOnCA;;iBAtNiBA;UAyNfA;QAEFA,MAKJA;;MAHEA,yBAAiBA;IAGnBA,C;kBAEKC;cAlOgBA;QAmOLA,MAIhBA;MAHEA,wBAAiBA;IAGnBA,C;iBAEKC;MACEA;eA1OcA;QA2OjBA,yBAAiBA;;QADnBA,oBAKSA;QALTA,oBAMSA,YAAYA;QACnBA;;IAEJA,C;;;YAtBmBC;gEACfA,qBAAaA,WAAKA;IACnBA,C;gBAFgBC;;K;;;YAOAC;gEACfA,qBAAaA,uBAAUA,YAAOA;IAC/BA,C;gBAFgBC;;K;;;YAOEC;gEACfA,qBAAaA;IACdA,C;gBAFgBC;;K;;;iBAiBhBC;;;;M9CiLLA,wB8ChLgDA,yDAA9CA,iDAEgCA;QAC9BA,2B9C6KJA;I8C3KAA,C;kBAEKC;MACHA;8BAA8CA,qBAA9CA,iDAEgCA;QAC9BA,2B9CgLJA;I8C9KAA,C;iBAEKC;;4BA5QgBA;MA6QnBA;eACEA,iDAEgCA;UAC9BA,4BAA+BA;;QAJnCA,oBAOSA;QAPTA,oBAQSA,YAAYA;QACnBA;;IAEJA,C;;;;YnD7QYC;;;QAENA,wBAAiBA;;QAFXA;QAGNA;QACAA,iCAA2BA;;IAE9BA,C;;;;YAoBiBC;;;QAEdA,wBAAiBA;;QAFHA;QAGdA;QACAA,iCAA2BA;;IAE9BA,C;;;;YA+JDC;MAAWA;;;;YAELA;UAWFA;cACIA,yBAAkBA;UACpBA;;YAEAA;YACAA;;mCAE0BA;QAC5BA,gCAAsBA,UAAOA;IAEjCA,C;;;;YAOgBC;;;;;aAENA;MAAJA;QACEA,qCAAOA;cACHA;UACFA,oCAA0BA;mBASxBA,0BAAmBA;QACrBA,gCAAsBA,UAAOA;IAGlCA,C;gBAlBWC;;K;;;YA+FDC;;iBACRA;;QAAqBA,YAI3BA;MAHcA,8BNgOAA;MM/NFA;QAAWA,OAAOA,gBAAYA,4CAE1CA;MADCA,WACDA;K;;;;YAmCqDC;MACpDA;;6CAGaA;;;;;UAHbA;UAIIA;UAG4CA;UAAOA;UA8X7BA,eDlnBHC;UCmnB3BD;+BACoCA;;cvBzxBpCrsB;oCuB0xB2BqsB;;YAEOA;YAAPA;;UAA3BA,KAnYwCA;UAChCA,MASLA;;QAPcA;UACTA,oCAAYA,gBAAmCA,KAAXA;UACpCA,MAKLA;;QAHGA;;MAEFA;IACDA,C;;;;gBA0KIE;MAEmDA,aAApDA;+GACqCA;MACzCA,aACFA;K;;;;;;;;qBF9rBKC;MAAaA;;QrB4GlBxsB;cqB1GOwsB,OAyNkBA;QAzNGA,sBAAUA;MACNA,eC8QLA;MD7QzBA;2BACoCA;;UrBuGtCxsB;gCqBtG6BwsB;;MAE3BA;IACFA,C;qBATKC;;K;;;;gBAmBAC;MACHA;6BACsBA;eADjBA;YAuMkBA;QAvMGA,sBAAUA;MACpCA;IACFA,C;gBAHKC;;K;sBAKAC;MACHA;IACFA,C;;;gBAIKC;MACHA;6BACiBA;eADZA;YA4LkBA;QA5LGA,sBAAUA;MACpCA;IACFA,C;gBAHKC;;K;sBAKAC;MACHA;IACFA,C;;;wBAqFKC;MAEIA,SAlCiBA;QAiCLA,WAErBA;MADEA,WAtCgBA,OAAOA,oBAgBvBA,sCAAOA,sBAsBoDA,iCAC7DA;K;mBAEYC;;mBAtCcA;MAsCHA;QAdGA;kBAdDC;;QA4BFD;;2BAEIA;;;MAIvBA;gBA/CcA,OAAOA;MA8CLA;QAChBA,iBAAOA,0CACuBA,kBAAkBA,uCAKpDA;;QAPEA,eAIuBA;QACrBA,iBAAOA,yCAA0DA,gBAErEA;;K;;;sBAkHUE;;;sCAGgDA;qBCiB/BA;2BDlBGA;QACtBA;QACJA;UAIYA;;MA7DhBA,wBCyE2B/tB,gBDzE3B+tB;;MAiEEA,oBAvMFA;MAwMEA,aACFA;K;cAdUC;;K;oBAsBAC;;;sCAGiDA;MA9E3DA,wBCyE2BjuB,gBDzE3BiuB;MA8EEA,oBA9MFA;MA+MEA,aACFA;K;kBAEUC;MACGA;MAGLA;;YCbmBluB;MDzE3BkuB;kBAoF+BA;QACjBA;MAGZA,oBAjNFA,6EAiNmBA,gBAjNnBA;MAkNEA,aACFA;K;oBAEUC;MACGA;MAEuCA;;YCtBzBnuB;MDzE3BmuB;kBA8F+BA;QACXA;MAElBA,oBAvNFA,4EAuNmBA,gBAvNnBA;MAwNEA,aACFA;K;oBA4CKrsB;MAAYA,mBAxHOA;MAwHPA,qBAxHOA;UA2HtBA,gBAAgBA;UAChBA,4BAA4BA;IAC9BA,C;oBAEKssB;MAAYA;6BACCA;gBAlIUA;MAmI1BA;QACWA,2EAAgBA;aACzBA;;QAEAA;UApCFA,2CAAOA;oBAyCSA;YACVA;YACAA,MAURA;;UARMA;;QAbJA,oBAjIsBA;QAkJpBA,gCAAwBA;;IAI5BA,C;yBAEKC;MACHA;;;QAAuBA,MA6BzBA;gBAxL4BA;MA4J1BA;QACkBA,sEAAoBA;sBACpCA;QACAA;iCAEgBA,iCAAdA;;gBAGOA;;;QAGTA;UApEFA,2CAAOA;oBAyESA;YACVA;YACAA,MAURA;;UARMA;;QApBJA,oBA1JsBA;QAiLRA,MAAZA;QACAA,gCAAwBA;;IAI5BA,C;wBAEgBxsB;MAAgBA;0BAxLRA;MA4LNA,4DAAUA;MAEnBA,KADPA;MACAA,yCACFA;K;yBAEgBysB;MACEA;MAEhBA;sBACiCA;eACvBA;;MAIVA,WACFA;K;iBA0DKC;;;uBAECA;MAFQA,oBArQUA;kCAuQZA;QACEA;UACRA;;UAEAA;;QAG0BA;QAClBA;QA1KAA,oBArGUC;aAuGtBD;aACAA;QAwKEA;;IAEJA,C;0BAEKE;;;MAEIA;MAFcA,oBApRCA;MAoRDA,wCAERA;MAEeA;MAnLhBA,oBArGUD;WAuGtBC;WACAA;MAkLAA;IACFA,C;sBAEKC;MAAcA;MAIAA;MAJAA,oBA7RKA;MAgSMA;MArLVC,oBA3GI5sB;WA6GtB4sB;MCnTFA,KDoTEA;MAoLAD;IACFA,C;sBANKE;;K;sBAQAC;;;uBAaCA;MAbaA,oBArSKA;kCAkTZA;QACRA;QACAA,MAMJA;;MA1OwBA,oBApFCrtB;WAsFvBqtB;MAqOAA,gCAAwBA;IAG1BA,C;oBAEKC;;;8BACCA;MAAMA;iBA5TUA;UA+EEA,oBApFCttB;eAsFvBstB;UA+OIA,gCAAwBA;;UAIxBA;QAEFA,MAIJA;;MADEA;IACFA,C;2BAEKC;MAAmBA;;0BA7UAA;MAgFAA,oBApFCvtB;WAsFvButB;MA+PAA,gCAAwBA;IAG1BA,C;;;;YAlM4BC;MACtBA,gDAA4BA;IAC7BA,C;;;;YA8BuBC;MACtBA,uDAA4BA;IAC7BA,C;;;;YAoCWC;mBACHA;MADGA,iBA3NeA;MAwFLA,iBAxFKC;QA0F7BD;MAuIIA;IACDA,C;;;;YAKYA;;;eACJA;MADIA,iBAvOcA;MAyOzBA;IACDA,C;YAHYE;;K;;;;YASKF;MAChBA,iCAAsBA,QAAGA;IAC1BA,C;;;;YAwEqBG;mBACtBA;8BAAmBA;IACpBA,C;;;;YAQ2BC;MACtBA,+BAAiBA,YAAjBA;IACDA,C;;;;YAcmBC;MACtBA,gCAAeA,YAAOA;IACvBA,C;;;;YA6DGC;;kBAIUA;eA3hBUA;MAuhBWA;MAthBLA;MAshBKA;;;QAleXA;QApCYC;QAsC7BD,mBAzDSC,OAAOA,eAqBvBA,gCAAOA;;QAogB4BD;QAS3BA;iBACIA;2BAAsBA;UAhUdA,iBAzFA5tB;UA2FpB4tB,+BAAOA,oBA8TyCA;UAAOA;UAA/BA;UAAhBA;;;;;2BACyBA;UAjUbA,iBAzFA5tB;UA2FpB4tB,EA+TUA,kDA/THA;;UClSTA,EDmmBYA;UAEFA;QACAA,MAkBJA;;MAhBqBA;iEAlaHA;4BACFA;YAoaeA;YA3UfA,iBAzFA5tB;;YA2FpB4tB,EAyUYA,kDAzULA;cA0UKA;;UAGFA,MASNA;;qCAJyBA;;QACEA,EAAvBA,gDAA2CA;UAC3CA;;IAEJA,C;;;;YAH+CE;MAAOA,0BAAcA;K;;;;YAKpEC;MAAwBA;;kBAEGA;;;QA9hBiBA,oBA8hBIA;QAvjBpBC,kBANRC;QA+BjBF,YA8hBCA,0BA/jBQC,OAAOA,oBAUvBA,6BAAOA;;QAmjBqBD;QAGpBA;;QC7nBVA,ED8nBUA;UACAA;;IAEJA,C;;;;YAEAG;MAAgBA;;yBAEYA;QArWZA,iBAzFAluB;QA2FpBkuB,uCAAOA;kBAoWKA;;UA9iBYA,kBAxBAhC;iBAUDA;;UA4jBfgC;;;UAEyBA,EAAvBA;YACAA;;;QANUA;QAQZA;;eACcA;QA5WFA,iBAzFAluB;;QA2FpBkuB,iBAAOA,oBA0W6BA;QAAOA;;QAAnCA;iBACyBA;UA7WbA,iBAzFAluB;UA2FpBkuB,EA2WUA,oCA3WHA;;UClSTA,ED+oBYA;UAEFA;;IAEJA,C;;;;;qBK1UGC;MAAeA,YAAKA;K;YAwTtBC;gEACEA;MAAPA,OAAOA,iCAA+BA,SAAKA,yDAC7CA;K;gBA0SgBC;ML9vBhBA;gCCyE2BjwB;QIurBrBiwB;MACCA,2CACDA,6CAIQA,0CADQA;MAKpBA,aACFA;K;eAwPcC;MLngCdA;gCCyE2BlwB,gBI27BDkwB,sBLpgC1BA;;MKsgCsBA,EAApBA,2DACIA,oDAIQA,qCADQA;MASpBA,aACFA;K;cAYcC;MLhiCdA;gCCyE2BnwB,gBIw9BDmwB,sBLjiC1BA;;QKmiCOA;MACLA,2CACIA,2CAKQA,wCADQA;MAapBA,aACFA;K;kBAwEUC;;;;;ML/nCVA,wBCyE2BpwB,gBDzE3BowB;;MKkoCsBA,EAApBA,4DACIA,gEAQQA,uDADQA;MAapBA,aACFA;K;;;YAxsCcC;mBACVA;gBAAgBA;MAChBA;IACDA,C;gBAHWC;;K;;;YAGAD;mBACVA;mCAA4BA;MAC5BA;IACDA,C;;;;YAiEGE;MEsRNA,aFtR0CA;MAA9BA,oCTmdZpvB,2BAxGgCqvB,yBAwGhCrvB,8BW7LAovB,IFtRgBA,wCAAmCA;K;gBAA7CE;;K;;EA4b8CC;YAAPA;MAAOA,qCAAsBA;K;;;;YA+SpEC;;;IAECA,C;gBAFDC;;K;;;YAIQD;MACNA,mCAAiBA;IAClBA,C;;;;YA+PDE;sDACwCA;MAAtCA,6BAAgBA,mBAAcA;IAC/BA,C;gBAFDC;;K;;;YAIQD;;;QAEuBA;QAA3BA;;QAFIA;QAGJA;QACAA,iCAA2BA;;IAE9BA,C;;;;YAoBDE;;sDAEWA;;QADTA;QACAA;IACDA,C;gBAHDC;;K;;;YAKQD;;;YACFA;QACFA,0BAAiBA;QACjBA,MAOHA;;;QAJ8BA;QAA3BA;;QANIA;QAOJA;QACAA,iCAA2BA;;IAE9BA,C;;;;YA+EDE;;;;;MACEA,eAAaA,qDAAmBA,kDAI7BA,2BAAuBA;IAC3BA,C;gBANDC;;K;;EACqBC;YAANA;MAAMA,4BAAKA,OAAMA;K;;;;YAAEA;gCAC1BA;QACFA,6BAAgBA,mBAAcA,aAAQA;IAEzCA,C;;;;YAGKF;MACNA;;QAK6BA;QAA3BA;;QANIA;QAOJA;QACAA,iCAA2BA;;IAE9BA,C;;;;;;wBC52BeG;MAAeA;2BAnBhCA;MAsBDA,UAfyBA;QAezBA,uEAAOA,UAIXA;MAFqCA;MACnCA,8CADmCA,6DAAQA,UAC9BA,SACfA;K;4BAGqBC;MAAoBA;2BA7BpCA;gBAOwBA;kBAyBzBA;;UC2JAA,UD3JAA,oCAAiBA,uBC2JjBA;QD1JAA,wEAKJA;;MAHqCA;2EAAQA;gBACjCA;MAAVA;QCuJEA,UDvJ+BA,mCCuJ/BA;MDtJFA,oDACFA;K;8BAK+BC;MAAcA;2BA/CpBA;gBAWIA;QAuCUA;QACnCA,uDADmCA,6DAAWA,UAC9BA,SAGpBA;;MADEA,gFAAOA,UACTA;K;sBAOMC;mBAvDgBA;MAwDpBA;QACEA,O3BjBJA,kD2BqBAA;MANoBA;MAKlBA,O3BpBFA,0D2BqBAA;K;+BAGOC;;;8BAKmBA;gBA7DAA;MAyDxBA;QAAmBA,sBAAMA;MACzBA;QNxVFA,oBCuE2BvwB;QDtEzBA;QMuViBuwB,SAOnBA;;gBAJgBA;MAwXgBA;MNrtBhCC,oBCyE2BzxB;MK0lBX0xB,sDACWA;MAHHA,kDAAyBA,sBAIpBA;gBAnZJC;MASPD,sDAAcA;QA4b5BA;MAJJF,KArXEA,8DAqXFA;;MAnXEA,SACFA;K;yBAWOI;mBACLA;;QAAqCA,SAArCA,oBA9FuBA,mDN/QzBA,eCyE2B5xB;MKqSzB4xB,SACFA;K;WAKKC;MACHA;2CACKA;eAtFmBA;QAqFLA,sBAAMA;MACzBA;IACFA,C;gBAKKC;MACHA;MAE2DA;cA/FnCA;QA6FLA,sBAAMA;;Q3Bzd3BlxB;M2B2dgCkxB,eLtTLA;MKuTzBA;2BACoCA;;U3B7dtClxB;gC2B8d6BkxB;;MAE3BA;IACFA,C;gBATKC;;K;aAyBEC;;kBA7HeA;MA8HpBA;QACEA,OAAOA,2BAKXA;MAHEA;QAAmBA,sBAAMA;MACzBA;MACAA,OAAOA,2BACTA;K;uBAEKC;;MAEHA;QACEA;WACKA;QACLA,8BAAuBA,UAAUA;IAErCA,C;YAKKC;;;MAESA;gBA1JWA;MAyJvBA;QACEA;WACKA;QACLA,+BAAuBA,SC3D3BA;ID6DAA,C;wBAEKC;MACHA;MACoBA;eAlKGA;MAiKvBA;QACEA;WACKA;QACLA,8BAAuBA,SCxD3BA;ID0DAA,C;cAEKC;MAAMA;2BA7JkBA;MAgKQA,4FAAWA;WAC9CA,oBAAoBA;;MA2QpBA;IAxQFA,C;kBAIsBC;;;yBAMVA;MAAiBA;gBArLxBA;QAkLDA,sBAAUA;YL/XavvB;;MKuiB3BuvB;MAAAC,sFAtKgDD;MAGZA;;MAElCA;QACqCA,wEAAWA;gBACrCA;QAiOXA;;aA9NEA;MAEFA;MACAA,8BAA4BA;MAI5BA,mBACFA;K;qBAEOE;;;;;gBAjMsBA;QA4MUA,sEAAWA,WAC5BA;WAEpBA;WACAA,eACKA;gBAEDA;MAAJA;QACEA;;YAIIA,qCAASA;;YAJbA;YAKIA;YNtfRA,yBCyE2BvyB;YKibNuyB;YAAbA;;;UAIOA;MAIAA;MAMbA;QACWA;;QAETA;MAGFA,aACFA;K;oBAEKC;;;;gBApPwBA;QAsPUA,6DAAWA,UAC9CA,iBA0JcA;MAxJhBA,mBAAYA;IACdA,C;qBAEKC;;;;gBA5PwBA;QA8PUA,6DAAWA,UAC9CA,iBAsJcA;MApJhBA,mBAAYA;IACdA,C;;;;;;;;;;YAxE8BC;MAC1BA,kBAAYA;IACbA,C;;;;YAyCDC;mBACMA;0BNhfiBA;QMifnBA;IAEJA,C;;;;iBAiCGC;MACgBA;MAAnBA,gCAAcA;IAChBA,C;kBAEKC;MACHA,gCAAcA;IAChBA,C;iBAEKC;MACHA,gCAAcA;IAChBA,C;;;iBAKKC;;MAC2CA;MAA9CA,gCAAcA,cCpMhBA;IDqMAA,C;kBAEKC;MACHA,gCAAcA,cC7LhBA;ID8LAA,C;iBAEKC;MACHA,gCAAcA,eAAkBA;IAClCA,C;;;;EA8BIC;2BAFkBA;MAElBA,2EAAuBA,yBAAiBA,kDAAsBA;K;kBAM1DC;MAAYA,QrBvwBWA,gCqBuwBXA,gCAAiCA;K;SAEvCC;MAAEA;oBAIhBA;MAHEA;QAA4BA,WAG9BA;MAFEA,oDACoBA,qBAAkBA,YACxCA;K;;EAWSC;iBADFA;MACLA,WAAOA,kCACTA;K;gBAEKC;MACHA;IACFA,C;iBAEKC;MACHA;IACFA,C;;;WAOKC;MACHA,6BAAYA;IACdA,C;;;;;;;cAsDOC;MACQA;MACbA;QACEA;QACAA,WAKJA;;MAHEA,OAAOA,sBAAoBA,2CAG7BA;K;;;YA9BkDC;mBAC5CA;+BAAwBA;MACxBA;IACDA,C;;;;YAwBwBC;MACzBA;IACDA,C;;;;;oCClzBH9wB;MAGOA;MACAA;MACAA;IACPA,C;yBAQK+wB;MAAiBA;uFAEhBA;MAFgBA,oBACbA;MACPA;QAA2BA,MAM7BA;MALEA;MACmBA;aACjBA;QACAA;;IAEJA,C;cAIKC;;sDACHA;;QAAeA;MAGfA,iBAAUA;IACZA,C;eAEKC;MAAOA;;QACMA;MACAA;QACHA,KAAXA,iBAAWA;WAEUA;QACVA,KAAXA,iBAAWA;;QAEXA,sBAAUA;IAGdA,C;cAEKC;MACHA;;QAAeA;MACfA,iBAAUA;IACZA,C;aAEKC;;kBAgEoBA;MA/DvBA;QAAiBA,MAQnBA;MAJmBA;WAAjBA;2BAEkBA;kBAAkBA;;YA0fnBA;;MAzfjBA;QAAqCA,uBAAeA;IACtDA,C;aATKC;;K;cAWAC;;kBAqDoBA;MApDvBA;QAAiBA,MAcnBA;MAbEA;;QAEEA;UACEA;sBAAoBA;YAASA;;YAA7BA;;YAEEA;;YAFFA,eAISA;uBACPA;;YACAA;cAAkBA,uBAAeA;;;;IAIzCA,C;cAEOC;;mBAILA;;MACAA;QACEA;MAE6BA,UAAxBA;MAAPA,oDACFA;K;yBAiCSC;cAFaA;qBAGHA;QAA6BA;;QAA5CA;eAAoDA;K;kBAG/CC;MAAYA,WANCA,cAMQA;K;eAEzBC;;kBACHA;MACAA;kBACEA;;YAkbeA;;MAhbjBA;QAAkBA;MACFA,KAAhBA;IACFA,C;YAgBKC;;;mDAISA;MAJLA,qBApCcA;gBACEA;MAqCvBA;QAAiBA,MAMnBA;MALEA;QACEA;;QAEAA,oBAoUJA;IAlUAA,C;wBAEKC;mBA7CoBA;MA8CvBA;QAAiBA,MAMnBA;MALEA;QACEA;;QAEAA,mBAsUJA;IApUAA,C;cAEKC;MAAMA;2BAvDYA;gBACEA;MAwDvBA;QAAiBA,MAOnBA;MANEA;;MACAA;QACEA;;QAEAA,qBAAkBA;IAEtBA,C;gBAMKC;MAAQA,oBAvEeA;IAyE5BA,C;iBAEKC;MAASA,oBA3EcA;IA6E5BA,C;iBAEOC;MAASA,oBA7ESA;MA+EvBA,WACFA;K;mBAUKC;MACkBA;;iCAAUA;MAC/BA;QA+WEA;QA9WUA;;MAEZA;gBA5FuBA;MA6FvBA;QACEA;;QACAA;UACEA;;IAGNA,C;iBAIKC;;;MAM4BA;MANnBA,qBA1GWA;MA0GXA,oBAtGQA;MAsGRA,qBAxGWA;gBAJGA;WAiH1BA;MACAA,qCAAsBA;WACtBA;MACAA;IACFA,C;kBAEKC;MAAUA;;2BArHUA;MAqHVA,oBAjHOA;MAiHPA,qBAnHUA;gBAJGA;MA6HZA;MAgBdA;aACEA;QACAA;kBACIA;QACiCA;UACnCA;;UAEAA;;QAGFA;QAEAA;;IAEJA,C;iBAEKC;MAASA;2BA3JWA;MA2JXA,oBAvJQA;MAuJRA,qBAzJWA;MA8JVA;MASbA;WACAA;gBACIA;MACiCA;QACnCA;;QAEAA;IAEJA,C;sBASKC;MAAcA;MAIjBA;MAJiBA,qBAxLMA;gBAJGA;WA+L1BA;MACAA;WACAA;MACAA;IACFA,C;mBAYKC;MAAWA;2BA3MSA;gBACAA;kBA4MJA;QAASA;;QAA5BA;;mBACEA;;QACsBA;eACpBA;;mBAKJA;kBAvNuBA;QAwNrBA;UACEA;UACAA,MAgBNA;;QA5O2BA;QA+NvBA;UAAqCA;aACrCA;QACAA;UACEA;;UAEAA;aAEFA;;gBAjOqBA;MAoOvBA;QACEA;IAEJA,C;iBAhXgBC;;K;iBAEHC;;K;kBAeKC;;K;;;;;YAgPhBC;;iBAGMA;eA9HiBA;MA8HrBA;QAAqCA,MAWvCA;QAVEA;kBAEcA;eAK4BA;;aAAxCA;MAJUA;QACVA,yCAA2DA;;;QAD7DA,eAGkBA;QAChBA,uBAA8BA;;QAEhCA;IACFA,C;;;;YAuBAC;mBAGOA;eAlKoBA;MAkKzBA;QAAsBA,MAIxBA;QAHEA;MACAA,wBAAiBA;QACjBA;IACFA,C;;;EAiFIC;2CAJgBA;MAMpBA,wEAFwBA,yBAAiBA,6CAFTA,oCAKlCA;K;qBAPsBC;;K;6BAAAC;;K;cAAAC;;K;2BAWAC;;MAEpBA,OAAWA,mDACPA,yBAAiBA,qDADVA,eAEbA;K;;;2BAoBsBC;;;yBAKhBA;MAAiBA;eAHjBA;QAASA,sBAAUA;WACvBA;MACWA;6BAEWA;MAFtBA,SAGFA;K;;;iBAWSC;MAAWA,oCAAiBA;K;kBAEhCC;MACHA;;gBAAIA;MAAJA;QACEA,sBAAUA;;;QAUAA;;UAERA,qBAA6BA,KAAVA;;UAEnBA;UACAA;;;QAjBSA;QAmBXA;QACAA;UAGEA,4BAAkBA;UAClBA;;UAGAA;;IAGNA,C;0BApCYC;;K;;;cAgEEC;;K;;;;;;eASTC;4CACHA,iBAASA,gBAAUA;IACrBA,C;;;eASKC;MACHA,0BAAoBA,YAAOA;IAC7BA,C;;;eAMKC;MACHA;IACFA,C;cAEkBC;MAAQA,WAAIA;K;cAErBA;MACPA,sBAAUA;IACZA,C;;;;gBAsCKC;MACHA;;eAVsBA;QAULA,MAcnBA;MAfaA,gBAEHA;gBAVkBA;MAW1BA;;aAEEA;QACAA,MASJA;;MAPEA,oBAAkBA;WAMlBA;IACFA,C;;;YAPoBC;mBACDA;;QACfA;MACAA;QAAiCA,MAElCA;MADCA,oBAAWA;IACZA,C;;;;iBAsBMC;MAAWA,oCAAwBA;K;WAEvCC;;kBACCA;MAAJA;aACEA,0BAAoBA;;QAEgBA;aAApCA;;IAEJA,C;kBAEKC;MAAUA;6CAOCA;MAPDA,oBAtDSA;oBAwDAA;MACIA;WAA1BA;MACAA;aACEA;MAEFA;IACFA,C;;;kBA4BSC;MAAYA,uBAAiBA;K;iBAEjCC;MACCA;gBAJoBA;QAINA,MAGpBA;MAFEA,gCAAwBA;WACxBA;IACFA,C;cAEKC;;IAAiCA,C;eACjCC;IAA+BA,C;cAC/BC;MACHA,iBAAUA;IACZA,C;aAEKC;;IAGLA,C;aAHKC;;K;cAKAC;mBAnBgBA;MAoBnBA;iBACEA;QACAA;UACEA;;IAGNA,C;cAEOC;MAAYA,OAAOA,2BAAWA;K;iBAUhCC;;kBACHA;MACAA;QAAcA,MAGhBA;WAFEA;gBACIA;MAAJA;QAAqBA;IACvBA,C;iBAnDaC;;K;;;;;qBA0UJC;MAAeA,WAAIA;K;2CACNC;;;MAEkBA;;MA3UxCA,oCNvb2B3M,wBMub3B2M;MACE3M;MA0UA2M,SACFA;K;6BAHsBC;;K;cAAAC;;K;;ECtgCYC;YAANA;MAAMA,wCAAsBA,YAAOA,YAAWA;K;;;;YAqBnEC;MACLA,sBAAgBA,mBAAcA,gBAAeA;IAC9CA,C;;;EAQiCC;YAANA;MAAMA,mCAAiBA,OAAMA;K;;;;EPflCC;gBAAhBA;MAAcA,eAAEA,OAAMA;K;;;;;;;;;2BA6oBxBC;MACCA;MAIkDA;MAJfA,qBAAlBA;MAGdA,yBAFyBA;MAEhCA,qBADoDA,4BAEtCA,qDAChBA;K;0BAuBgBC;MACVA;wBAGsDA;MAHnBA,qBAAlBA;MAEGA,yBADQA;MAEhCA,wGADiDA,YACnCA,mBAAWA,yCAC3BA;K;+BAEwBC;MAClBA;qDAGsDA;MAHnBA,qBAAlBA;MAEQA,yBADGA;MAEhCA,kHADsDA,YACxCA,mBAAWA,6CAC3BA;K;gCAE8BC;MAExBA;mEAGsDA;MAHnBA,qBAAlBA;MAESA,yBADEA;MAEhCA,wIADuDA,YACzCA,mBAAWA,iDAC3BA;K;qBAEWC;MAC8BA,yBAAlBA;iCACWA;MAGzBA,kBAFiBA;QAAYA,WAItCA;MAFEA,qBAD8CA,4BAEhCA,qDAChBA;K;;;;;mBAoGiBC;mBACXA;MAAJA;QAA4BA,SAG9BA;MADEA,WADAA,kBAlKFA,yBAoKAA;K;mBA0DSC;MAAaA,gCAAqBA,KAAIA;K;kBAE1CC;MAAUA;;;QAEXA;;QAFWA;QAGXA;QACAA;;IAEJA,C;yBAEKC;MAAkBA;;;;QAEnBA;;QAFmBA;QAGnBA;QACAA;;IAEJA,C;0BAEKC;MAAwBA;;;;;QAEzBA;;QAFyBA;QAGzBA;QACAA;;IAEJA,C;sBAEgBC;MAEdA,OAAOA,6CADUA,4CAAiBA,mBAEpCA;K;2BAEwBC;MAEtBA,OAAOA,kDADUA,8EAAsBA,2BAEzCA;K;2BAQgBC;MAEdA,OAAOA,oDADUA,0BAAiBA,2CAEpCA;K;kCAEiBC;MAEfA,OAAOA,yDADUA,kDAAsBA,+BAEzCA;K;YAQSC;MACMA;;;MACSA;QAAuBA,aAe/CA;MARgBA;MACZA;QACEA;MAEFA,YAIJA;K;2BAIKC;MACCA;MAKkDA;2BAL5BA;MADJA;yBAGuCA;MAA/BA;MAE9BA,OAAOA,cAD6CA,8DAGtDA;K;qCAEKC;;6BACuBA;MADnBA;yBAGsDA;MAA/BA;MAE9BA,OAAOA,cAD8BA,sEAGvCA;K;aAEEC;MACIA;wBAIsDA;2BAJhCA;MADpBA;yBAGuDA;MAA/BA;MAE9BA,OADWA,wFAAyBA,YACtBA,yCAChBA;K;kBAEEC;MACIA;qDAIsDA;MAAGA;2BAJnCA;MADZA;yBAG+CA;MAA/BA;MAE9BA,OADgBA,sGAAyBA,YAC3BA,kDAChBA;K;mBAEEC;MACIA;mEAIsDA;MAAGA;MAAMA;2BAJzCA;MADNA;yBAGyCA;MAA/BA;MAE9BA,OADiBA,0HAAyBA,YAC5BA,6DAChBA;K;0BAEgBC;MACVA;wBAIsDA;2BAJhCA;MADOA;yBAG4BA;MAA/BA;MAE9BA,OADwBA,iGAAyBA,YACnCA,gDAChBA;K;+BAEwBC;MAClBA;qDAIsDA;2BAJhCA;MADuBA;yBAGYA;MAA/BA;MAE9BA,OAD6BA,2GAAyBA,YACxCA,oDAChBA;K;gCAE8BC;MAExBA;mEAIsDA;2BAJhCA;MAFmCA;yBAIAA;MAA/BA;MAE9BA,OAD8BA,iIAAyBA,YACzCA,wDAChBA;K;qBAEWC;MACLA;MAM4DA;2BANtCA;MADJA;yCAGyBA;kCACbA;QAAYA,WAIhDA;MAHsCA;MAEpCA,OAAOA,cADuCA,8EAEhDA;K;yBAEKC;MACCA;MAIsDA;2BAJhCA;MADNA;yBAGyCA;MAA/BA;MAE9BA,OAAOA,cAD2CA,8CAEpDA;K;mBAEMC;MACAA;MAIgEA;2BAJ1CA;MADXA;yBAG8CA;MAA/BA;MAE9BA,OAAOA,cADqCA,wDAE9CA;K;aAUKC;;6BACuBA;MADlBA;yBAGqDA;MAA/BA;MAE9BA,OAAOA,cAD+BA,iDAExCA;K;cAjRwBC;;K;mBACAC;;K;oBACAC;;K;2BACAC;;K;gCACAC;;K;iCACAC;;K;wBACYC;;K;4BACIC;;K;sBACNC;;K;8BACQC;;K;gBACdC;;K;eACDC;;K;8BACeC;;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuGtBC;YAAXA;MAAMA,WAAKA,mBAAIA,oBAAWA;K;gBAA1BC;;K;;;YAKAC;MAAcA;;MAALA,YAAKA,yBAASA,aAAYA,4BAAIA;K;gBAAvCC;;K;;EAWWC;YAAXA;MAAMA,WAAKA,wBAAWA,YAAWA;K;;;;YAKjCC;MAAcA;MAALA,WAAKA,+BAAgBA,aAAYA,mBAAIA;K;gBAA9CC;;K;;;YA8IsBC;;;eAC7BA;MtBx9BFA,oBsBw9BEA;eACIA;MAAJA;QAAwBA;MHralBA;MACyBA;;IGsahCA,C;;;EAoKeC;cApCYC;MACxBA,QAAMA,iCAA4CA;K;mBAC1BC;MACxBA,QAAMA,sCAAiDA;K;oBAC/BC;MACxBA,QAAMA,uCAAkDA;K;2BAChCC;MACxBA,QAAMA,8CAAyDA;K;gCACvCC;MACxBA,QAAMA,kBAA8DA;K;iCAC5CC;MACxBA,QAAMA,kBAA+DA;K;wBACjCC;MACpCA,QAAMA,2CAAkEA;K;4BAChCC;MACxCA,QAAMA,+CACgCA;K;sBACJC;MAClCA,QAAMA,yCAA8DA;K;8BAC1BC;MAC1CA,QAAMA,kBACkCA;K;gBACZC;MAC5BA,QAAMA,mCAAkDA;K;eAC7BC;MAC3BA,QAAMA,kCAAgDA;K;8BACZC;MAC1CA,QAAMA,kBACkCA;K;gBAGlCC;MAAUA,WAAIA;K;qBAKhBd;MAAQA,kCAAQA;K;mBAMPe;gBACXA;MAAJA;QAA2BA,SAE7BA;MADEA,mCA7kBFA,yBA8kBAA;K;mBAQSC;MAAaA,WAAIA;K;kBAIrBC;MAAUA;;;aAEGA,kBAAgBA;UAC5BA;UACAA,MAMNA;;QAJIA;;QANWA;QAOXA;QA4DFA,kDAAkDA;;IAzDpDA,C;yBAEKC;MAAkBA;;;;aAELA,kBAAgBA;UAC5BA;UACAA,MAMNA;;QAJIA;;QANmBA;QAOnBA;QAgDFA,kDAAkDA;;IA7CpDA,C;0BAEKC;MAAwBA;;;;;aAEXA,kBAAgBA;UAC5BA;UACAA,MAMNA;;QAJIA;;QANyBA;QAOzBA;QAoCFA,kDAAkDA;;IAjCpDA,C;sBAEgBC;MACdA,OAAOA,2EACTA;K;2BAWgBC;MACdA,OAAOA,gFACTA;K;kCAEiBC;MACfA,OAAOA,wFACTA;K;YAOSC;MAAkBA,WAAIA;K;2BAI1BC;MACHA,oDAAkDA;IACpDA,C;qCAEKC;MACHA,OAAOA,wDACTA;K;aAEEC;wBACgDA;WAA7BA,oBAAUA;QAAYA,iBAE3CA;MADEA,OAAOA,mCACTA;K;kBAEEC;qDACgDA;MAAEA;MAAFA,KAA7BA,oBAAUA;QAAYA,oBAE3CA;MADEA,OAAOA,iDACTA;K;mBAEEC;mEACgDA;MAAEA;MAAMA;MAARA,KAA7BA,oBAAUA;QAAYA,2BAE3CA;MADEA,OAAOA,6DACTA;K;0BAEgBC;MAA8BA,kCAACA;K;+BAEvBC;MAA2CA,+DAACA;K;gCAEtCC;MAE1BA,6EAACA;K;qBAEMC;;MAAsDA,WAAIA;K;yBAEhEC;MACHA,2CAAyCA;IAC3CA,C;mBAEMC;MACJA,OAAaA,+BAAuBA,8BACtCA;K;aAMKC;MQ51CLA;IR81CAA,C;;EA5EoBC;YAAXA;MAAMA,WAAKA,mBAAOA,WAAEA;K;gBAApBC;;K;;EAaWC;YAAXA;MAAMA,WAAKA,wBAAWA,GAAEA;K;;;;YAIxBC;MAAcA;MAALA,WAAKA,+BAAgBA,IAAGA,mBAAIA;K;gBAArCC;;K;;;YA0HiCC;;;;;;;;cAGlCA;UACGA,wBAAOA,gBAAUA;;UADxBA,iBAGSA;UACFA,wBAAOA,eAASA;;;QAPeA;QAStCA;QACcA;QAAdA;UACEA;;UAEAA;;IAGLA,C;;;ESjhCDC;gBA3WQC;MAAUA,+BAAOA;K;iBAChBC;MAAWA,qCAAYA;K;cAGhBF;MACdA,uCAAWA,sBAsWbA,kCArWAA;K;mBAMKG;MACHA;;sBACgBA;QACdA,wCAoOKA,aA7NTA;aANSA;QAIEA,WAHIA;QACXA,kCAiOKA,aA7NTA;;QAFIA,+BAEJA;K;oBAEKC;qBACQA;MACXA;QAAkBA,YAGpBA;MADEA,OAAOA,wBADMA,uCAEfA;K;YAYWC;MACTA;;sBACgBA;QAC8BA;QAA5CA,SAOJA;aANSA;mBACMA;QAC8BA;QAAzCA,SAIJA;;QAFIA,OAAOA,gBAEXA;K;YAEEC;;mBACWA;MACXA;QAAkBA,WAIpBA;MAHeA;MACDA;MACZA,2CACFA;K;eAEcC;;;MACKA;MAGkBA;MAHnCA;uBACgBA;QAEdA,kDADqBA,YAAqBA;aAErCA;oBACMA;QAEXA,+CADkBA,SAAeA;;QAGjCA;IAEJA,C;YAEKC;;;MAGyBA;MAG0BA;kBAL3CA;MACXA;QAAiCA,YAAfA;MACPA;mBAEPA;MAAJA;QACEA;;aAEAA;;QAEYA;QACZA;;;;;eAKEA;;;IAGNA,C;cASEC;MAMSA;MAAPA,SAEJA;K;eAEEC;;oBACWA;MACXA;QAAkBA,WAcpBA;MAbaA;mBAEkBA;MAAjBA;MACZA;QAAeA,WAUjBA;;WAREA;sCAOOA;;;MAAPA,aACFA;K;eASKC;;;;MACSA;yBACkBA,gBAErBA,uBAFTA;kBAESA;QAAPA,cAAOA,gBAASA;0BACgBA;UAC9BA,sBAAUA;;IAGhBA,C;oBAEKC;;kBACCA;MAAJA;QAAmBA,SAgDrBA;MA/CoBA,wBAAKA;;qBAITA;MACdA;QAEsCA;;QACpCA;+BAEwCA;UACtCA;;;;kBAKOA;MACXA;QAEsCA;;QACpCA;;UAKEA;;;kBAKOA;MACXA;QAEsCA;;QACpCA;uBAGqCA,MADEA;;UAErCA;kCAEwCA;YACtCA;;;;MA3CSA,8BA+CCA;MAChBA,YAAOA,eACTA;K;0BAEKC;;MACwBA;MAIAA;eAsCpBA;;YAxCLA;;MAEFA;IACFA,C;wBAyBIC;MAIFA,OAA8BA,iCAChCA;K;kBAmCKC;MAEHA,aADWA,6BAEbA;K;wBAEIC;MACFA;;QAAoBA,SAMtBA;;MAJEA;QACMA;UAAqCA,QAG7CA;MADEA,SACFA;K;;EzBnUqCC;wByBoVjCA;MAIFA,yCACFA;K;wBAEIC;MACFA;;QAAoBA,SAMtBA;;MAJEA;;QACEA;UAAkDA,QAGtDA;;MADEA,SACFA;K;;;gBAmDQC;MAAUA,gBAAKA,oBAAOA;K;iBACrBC;MAAWA,gBAAKA,0BAAYA;K;kBAErBC;MAyBhBA,aAxBoCA;MAAlCA,qCAAwCA,qBAwB1CA,2CAvBAA;K;gBAEKC;MACHA,OAAOA,gCACTA;K;;;iBAqBMC;MAAWA,gCAAQA;K;gBAEpBC;;oBACQA;sBACEA;kBACmBA;qBAAKA;QACnCA,sBAAUA;;QAEVA;QACAA,YASJA;;QAPIA;aAIAA;QACAA,WAEJA;;K;8BAtBEC;;K;;;EAwzBFC;eAEOA;MAAaA,4BAAIA,sBAFxBA,6BAE2CA;K;kBAQ3BC;MA4XhBA;sDA3X0CA,6BAA7BA,uBA2XbA;QACE35B,0BAAaA;MA5Xb25B,SACFA;K;gBAEQC;MAAUA,+BAAOA;K;iBAChBC;MAAWA,qCAAYA;K;gBAG3BC;MACHA;;sBACgBA;QACdA;UAAqBA,YAWzBA;QATIA,OADmBA,wDAUvBA;aARSA;mBACMA;QACXA;UAAkBA,YAMtBA;QAJIA,OADmBA,qDAKvBA;;QAFIA,OAAOA,wBAEXA;K;iBAEKC;qBACQA;MACXA;QAAkBA,YAGpBA;MADEA,OAAOA,4BAAiBA,CA+NbA,8CA9NbA;K;eA+BMC;mBACAA;MAAJA;QAAoBA,sBAAUA;MAC9BA,oDAAcA,UAChBA;K;cAEMC;mBACAA;MAAJA;QAAmBA,sBAAUA;MAC7BA,oDAAaA,UACfA;K;WAGKC;MACHA;2CAAqBA;MAArBA;QAGSA,eAFOA;QAEdA,yDADqBA,YAAqBA,oDAS9CA;aAPSA;QAGEA,YAFIA;QAEXA,sDADkBA,SAAeA,iDAKrCA;;QAFIA,OAAOA,iCAEXA;K;wBAEKC;MACCA;2CAEwBA;kBAFjBA;MACXA;QAAiCA,YAAfA;MACPA;mBAEPA;MAAJA;QAC4BA;QAsJJA;;;QAnJVA;UACIA,YAKpBA;oBAJ8BA;;MAG5BA,WACFA;K;cAEKC;MACHA;;QACEA,OAAOA,mCAAsBA,kBAMjCA;WALSA;QACLA,OAAOA,mCAAsBA,eAIjCA;;QAFIA,OAAOA,uBAEXA;K;eAEKC;;oBACQA;MACXA;QAAkBA,YAYpBA;MAXaA;mBAEkBA;MAAjBA;MACZA;QAAeA,YAQjBA;oCAFcA;;;MAAZA;MACAA,WACFA;K;0BAiCKC;0CAC6CA;MAA7BA;QACDA,YAGpBA;MAFiCA;MAC/BA,WACFA;K;6BAEKC;MACHA;;QAAmBA,YAMrBA;MALqBA;MACnBA;QAAkBA,YAIpBA;MAHEA;;MAEAA,WACFA;K;6BAEKC;UAIHA,+CAA4BA;IAC9BA,C;kCAGmBC;MA2LnBA;6EA1LmDA;eAC7CA;aACFA,2BAASA;;oBAEiBA;YACrBA;aACLA,yBAAaA;;;MAGfA;MACAA,WACFA;K;mBAGKC;;uBACgCA;mBACJA;MAC/BA;oCACiBA;aACfA;;gBAESA;MAEXA;oCACiBA;aACfA;;YAEKA;;MAGPA;IACFA,C;wBAcIC;MAKFA,OAAkCA,qCACpCA;K;wBAoBIC;MACFA;;QAAoBA,SAOtBA;;MALEA;QAEWA,iBAALA,GAAKA;UAAqBA,QAGlCA;MADEA,SACFA;K;;;;;iBAyHMC;MAAWA,gCAAQA;K;gBAEpBC;;kBACmBA;eAAlBA,kCAAuBA;QACzBA,sBAAUA;;kBACDA;QAAJA;UACLA;UACAA,YAMJA;;UAJIA,gEAAiBA;eACjBA,0BAAQA,kBAAMA;UACdA,WAEJA;;;K;8BAnBEC;;K;;;;gBwGroDMC;MAAkBA,aAARA;8BAAcA;K;YAErBC;MAAiBA,OJoCEA,IIpCFA,+BAAkBA,2BAAMA;K;;;YtGiFpCC;MACZA,yBAAOA,kBAAKA;IACbA,C;;;;;YElBaC;MACZA,yBAAOA,kBAAKA;IACbA,C;;;;EpC6OHxrB;kBoI9QgBA;MAAYA,oCpIgRHA,2BoIhRGA,yBpI8Q5BA,qCoI9QiDA;K;iBAE/CyrB;MAAwBA,OAAIA,4BAAOA;K;iBAgB5BC;MAAWA,sCAAWA;K;eAIzBC;MACAA;QAAaA,sBAA2BA;MAC5CA,OAAWA,wBACbA;K;cAOMC;MACAA;QAAaA,sBAA2BA;MAC5CA,OAAWA,sBAACA,8BACdA;K;aAwGYC;;MAA0BA,OpIwNtCA,4EoIxNqEA,WpIwNrEA,4EoIxNuEA;K;uBA0C/DC;MAGQA;;MAAIA,qCAASA;MAI3BA,YAAoBA,+BAApBA;QACEA,uCAAgBA;MAElBA,aACFA;K;cAXQC;;K;aAaDC;MACWA;;MAChBA,YAAoBA,+BAApBA;QACEA,gBAAeA;MAEjBA,aACFA;K;cAiBKC;MACHA;kBAAyBA,+BAAzBA;QACUA;UACDA;UACLA,WAINA;;MADEA,YACFA;K;iBAIKC;MACeA;;MADNA;;MAKDA;MACXA;QACMA,oCAAiBA;MAElBA;IACPA,C;iBAmGKC;MAASA;;MACDA,yCAAiCA;MAC5CA;QACMA;IAERA,C;gBA0IOC;MAAcA,OAAaA,uDAAoCA;K;;;;Y9FzfxDC;;;aACHA;YACHA;QAEFA;eACAA;M/BqhBWA;QA2Bf92B;MA3Be82B;I+BlhBZA,C;;;;cAwEOC;MAAsBA;MAAJA,OAAIA,gFAA4BA;K;eACzDC;MACHA;;MAAcA,gCAAdA;;QACEA,mBAAgBA;;IAEpBA,C;aA0CYC;MACNA;;MAAiBA;MACAA,gCAArBA;;QACcA,8BAAmBA;QAC/BA,yBAAaA,WAAaA;;MAE5BA,aACFA;K;mBAkBKC;MAA2BA,uBAAKA,kBAAaA;K;gBAC1CC;MAAUA;aAAKA,iBAAMA;K;iBACpBC;MAAWA;aAAKA,kBAAOA;K;gBAGzBC;MAAcA,OAAQA,2BAAiBA;K;;;;cA2F5CC;MACAA,sBAAMA;IACRA,C;;EAkC8BC;cAAlBA;MAAkBA,oCAAmBA;K;YACtCC;MAAkBA,+BAASA;K;mBAcjCC;MAA2BA,mCAAqBA;K;eAEhDC;MACHA,+DAAaA;IACfA,C;iBAESC;MAAgBA,aAALA;+BAAYA;K;gBAExBC;MAAeA,aAALA;8BAAWA;K;cACbC;MAAQA,OAAKA,IAALA,gBAASA;K;cAC/BC;MAAsBA,iCAAgBA;K;gBACjCC;MAAcA,8BAAeA;K;aASxBC;MACRA,wGAAiBA,0BAAUA;K;;;EAqB/BC;cAEYA;MACRA,iCAA4BA,+BAHhCA,mEAGoDA;K;;;kBCyMpCC;MAAYA;aAmS5BA,qCAEmBA,aACcA,0BACTA,QAJxBA,2CAnSuDA;K;iBAU9CC;MAAWA,0BAASA,MAAKA;K;gBAE1BC;MAAUA,YAACA,aAAQA,aAAUA,OAAOA,kBAAWA;K;eAEjDC;;iBACAA;qBAASA;QAAOA,sBAA2BA;eACxCA;;8BAAMA;MAAbA,SAAOA,IACTA;K;cAEMC;;iBACAA;iBAASA;MAAbA;QAAoBA,sBAA2BA;eACxCA;aAA6BA;MAAfA;MAAdA;8BAAMA;MAAbA,SAAOA,IACTA;K;iBAQEC;MtC/SqBA;;MAErBA;QAEEA,kBAAiBA;gBsC6SZA;aAAiCA;iBAAzBA;MAARA;8BAAMA;MAAbA,SAAOA,IACTA;K;aA4FKC;;iBACCA;qBAASA;0BACcA,0BAAsBA,OAAOA;UACpDA;aAEFA,cAAQA;QAKsBC;;IAFlCD,C;gBAEOC;MAAcA,0DAAiDA;K;mBAepEC;;kBACIA;sBAASA;QAAOA,sBAA2BA;;gBAEpCA;;8BAAMA;iBAANA;MACXA;WACAA,eAASA,kBAAcA,OAAOA;MAC9BA,aACFA;K;wBAyCKC;;;MACaA;MAAhBA,+CAAOA;gBACEA;gBAAcA,OAAOA;MAAfA;WAAfA;eACIA;QA0CeA;;;kBACPA;kBAAgBA;kBAATA;QACnBA;QACAA,2DAAiCA,aAAOA;aACxCA;aACAA,cAAQA,OAAOA;QACfA;;;IA9CFA,C;gBA9QQC;;K;;;;iBA4WFC;MAAWA,gCAAQA;K;gBAEpBC;;kBACHA;eAA0BA,0BA5GOA;QAC/BA,kBAAMA;gBA4GJA;sBAAaA;QACfA;QACAA,YAKJA;;aAHoBA;;8BAAMA;MAAxBA,iCAAkBA;WAClBA,mBAAaA,mBAAyBA,OAAOA;MAC7CA,WACFA;K;8BAnBEC;;K;;;EkGzzBkBC;iBAAXA;MAAWA,kCAAWA;K;aAkFnBC;;MACRA,OzI+PJA,yEyI/P8CA,WzI+P9CA,6EyI/PgDA;K;gBAUzCC;MAAcA,OAAaA,mDAAoCA;K;aAgCjEC;MACHA;;;mCACOA,SADPA;UACmBA,YAGrBA;MADEA,WACFA;K;eA2CMC;MACaA;MACZA;QACHA,sBAA2BA;MAE7BA,OAAUA,gBACZA;K;cAEMC;MACaA;;MACZA;QACHA,sBAA2BA;;QAIfA;aACLA;MACTA,aACFA;K;;;;;;;aAkHOC;MAAWA;;eAAuBA;K;iBAKhCC;MAAWA,WzGo8BFA,0ByGp8BaA;K;cAa1BC;MACHA;mDAAkBA;MAAlBA;QAA4BA,cAA5BA;IACFA,C;aAuCOC;MACLA;8CAAuBA;MAAhBA;;MAAPA,SACFA;K;uBAEQC;;;iBAC0BA;MAAIA,0CzGy4BpBA;MAHLA,gDAA6BA,+BAA7BA,wByGp4BXA;QAA+BA;QAAPA,yCzGmwCTA;;MyGlwCfA,aACFA;K;cALQC;;K;aAOIC;;MACRA,OzItCJA,yEyIsC8CA,WzItC9CA,6EyIsCgDA;K;gBAUzCC;MAAcA,OAAaA,mDAAoCA;K;aAE1DC;;MAA4BA,OzINxCA,gDyIM+DA,WzIN/DA,+ByIMiEA;K;cAqB/DC;MACIA;MAAQA;;;MzG61BDA,8CAA6BA,+BAA7BA,uCyG51BXA;QAAgCA,gCzG2tCjBA;MyG1tCfA,YACFA;K;aAEKC;;;MzGw1BQA,8CAA6BA,+BAA7BA,iByGv1BXA;mCACOA,WzGqtCQA;UyGrtCIA,YAGrBA;MADEA,WACFA;K;WAoBKC;;;MzG+zBQA,8CAA6BA,+BAA7BA,iByG9zBXA;kCACMA,czG4rCSA;UyG5rCMA,WAGvBA;MADEA,YACFA;K;eAkBMC;MzGwyBOA,6CAA6BA,6BAA7BA;MyGtyBNA;QACHA,sBAA2BA;MAE7BA,SzGkqCeA,qByGjqCjBA;K;cAEMC;MzGgyBOA;iDAA6BA,6BAA7BA;MyG9xBNA;QACHA,sBAA2BA;;mBzG4pCdA;ayGvpCNA;MACTA,aACFA;K;;;;;;;;;YjGhYSC;;iBAwHeA;MAvHtBA;QACEA,OAAOA,wBAAYA,cAQvBA;WAPSA;QACLA,WAMJA;;QAHyCA,WAAlBA;QACnBA,mEAEJA;;K;gBAEQC;MAAUA;cA4GMA;QA5GQA;QAAaA;;QAASA,mCAAeA;MAAnDA,SAAyDA;K;iBAElEC;MAAWA,kCAAWA;K;cAGVC;MACKA,QAsGFA;QAtGLA,+BAAoBA,UAEvCA;MADEA,OA8KFA,+BA7KAA;K;mBAsCKC;MACqBA,QA6DFA;QA7DLA,+BAAoBA,kBAGvCA;MAFEA;QAAoBA,YAEtBA;MADEA,gDAAoBA,gBACtBA;K;cASAC;MACuBA,QAgDCA;QAhDiBA,WAEzCA;MADEA,OAAOA,kBAAWA,gBACpBA;K;eAiBKC;MACHA;MAA6CA;MAArBA,SA4BFA;QA5BLA,gCAAoBA,eAsBvCA;MArBsBA;MACpBA,oBAAyBA,SAAzBA;kBACeA;qBAIYA,WACNA;QAAnBA;UACUA,sCAAoCA;eAC/BA;;QAIfA;0BAIqBA;UACnBA,sBAAUA;;IAGhBA,C;sBAQyBC;MAAaA,mBAFdA;MAOtBA,iBACFA;K;6BAEaC;MAAYA;0BAVDA;MAYjBA,sCAAOA;MACZA;QACqBA,YAAZA,+CAAoDA;MAE7DA,WACFA;K;gBAEqBC;MACnBA;MAAwBA,SApBFA;QAoBLA,+BA0BnBA;MAtBgCA;MACVA;MACpBA,qBAAyBA,iBAAzBA;kBACeA;QACbA,yBAAkBA;;MAMpBA;QACEA;;QtB9CFA;WsBqDAA,kBAAYA;MAGZA,YAFAA,eAGFA;K;gBAEAC;MACEA;oDAAkBA;QAAiBA,WAGrCA;MAFeA,sCAAoCA;MACjDA,WAAoBA,yBACtBA;K;;;gBAuBQC;MAAkBA,aAARA;8BAAcA;K;iBAEzBC;mBACEA;YA9EeA;QA+ERA,mBAAKA;;QACbA;QAAQA;mCAAcA;eAAdA;;MAFdA,SAGFA;K;kBAKqBC;mBACZA;YAvFeA;QAwFRA;QAAKA;;QACbA;QtByWRxkC,+BAEyBA,SA1GOwkC,yBAwGhCxkC;;MsB3WEwkC,SAGFA;K;gBAIKC;MAAwBA,sCAAwBA;K;;EkGxTlBC;cAAzBA;MAAyBA,QAmBDA,mCAnBwBA;K;;;eAqChDC;MACJA;MAAeA;MACFA,sDADSA;;MAKTA,mCACEA,sDAFnBA;QACiBA;QACfA;UACEA,sBAAoBA;QAGtBA;mCAAMA;;;MAERA,aACFA;K;;;;iBjGIOC;;;mBAC+CA;MAAnCA;MAMoBA;MAIrCA;QAE+BA;QAAlBA;QAGXA;UACMA;UAAJA;Y1CJQA;YAEDA,yBAAcA;YACdA,yBAAcA;YACRA;Y0CKXA;cAaiCA;;;;;UAL5BA;QAATA;UACcA;kDAAeA;iCAAfA;UACZA;YACSA;YACPA;cAA0BA;YAeLA;;YAdhBA;cAELA;mDlCkbUA,UAAUA;;;gBkChbmBA;;;cAGvCA;cAEAA;gBAA4BA;;YAKPA;;UAHvBA;;clCsaNA;YkCpaqBA;YlCgVDr+B,MAsHlBA;;YkCncMq+B;;;QAGJA,sBAAMA;;MAERA;QACeA;elC8ZWA;QkC7ZxBA;UAIEA;;UAIgCA;UAChCA;YAEEA,sBAAMA;iBAERA;YlCoZWA;kBA2Bfr7B;YkC7aMq7B;;;QAGGA,WlCuamCA;QkCva1CA,6FAoBJA;;MAjBeA;MACbA;QACEA;;QAIgBA;QAChBA;UAEEA,sBAAMA;QAERA;UAEWA;;MAGbA,aACFA;K;;;;;;;;sBkG3CQC;MAAMA;MACZA;MAuV+BA,0BAtVHA,kBAsVqBA;MAtV5BA,SAEvBA;K;iBAsBgBC;MACQA,QAAaA,iBAErCA;K;;;;iB1FpHgBC;MAAWA,QAAMA,cAAaA;K;;;eAgBpCC;MACJA;MAAeA;MACFA,kDADSA;MAEbA;MACbA;QAAiBA,wBAkBnBA;;MA0BAA;MAxCoBA;MACIA;MATPA;MAUfA;QAIqBA;QAJrBA;wBAQoBA;;MAGpBA,OAAeA,kDAA2BA,cAC5CA;K;;;uBAyCKC;;kBAODA;;MANFA;QAsOQA;QAtORA;;kBAMUA;;QAARA;gCAAOA;;kBACCA;QAARA;gCAAOA;;kBACCA;QAARA;gCAAOA;;aACCA;QAARA;gCAAOA;;QACPA,WAYJA;;kBALYA;;QAARA;gCAAOA;;kBACCA;QAARA;gCAAOA;;aACCA;QAARA;gCAAOA;;QACPA,YAEJA;;K;mBASIC;MACFA;MAAqCA;QAGnCA;MAIeA,eAqBXA,6EAtBNA;QACiBA;QAEfA;oBACMA;UAAJA;YAAoCA;eAC5BA;;eACHA;mBACDA;YAAoCA;UAGNA;UAChBA,sCADCA;;eAKnBA;oBACMA;;UAAJA;YAAwCA;eAChCA;UAARA;kCAAOA;;eACCA;;;UAHVA;oBAMMA;UAAJA;YAAwCA;oBAChCA;UAARA;kCAAOA;;oBACCA;UAARA;kCAAOA;;eACCA;UAARA;kCAAOA;;;;MAIbA,kBACFA;K;;;eA0FOC;MAGDA;MAA8CA;MAArCA;MACbA;QACEA,aA0BJA;MAtBmBA,4CADMA;MAIRA;MAGfA;QACyBA;QAEvBA;UACEA,gBAYNA;Q1C0OAA;Q0C7O6BA;QA4D7BA;;QArF+DA;QAAOA;QAwBxCA;;;Q1C8O9BA;M0CjLAA;aA7DUA;MACRA;MACAA;iB1C2Q4CA;M0C1Q5CA,sCACFA;K;;;aAgFKC;MACHA;MAG2CA;cAzBjBA;QAwBhBA;QAANA;;IAQNA,C;eAEKC;MACCA;;;mBAAQA;2BACQA;wBACHA;WAGjBA,oBADAA,uBADAA;;QAqEeA,qDALTA,8BA1DNA;;YAEEA;;gBAEIA;kBACEA;gBAESA;gBACNA;oCAAKA;gBAAVA;kBAGUA,gCACsBA;kBAD5BA;;kBASaA;kBACfA;kBACAA;;uBAnBJA;cAsBqBA;cAARA;iEAAOA;4BAAPA;gBAIHA,oDACwBA;gBAD9BA;;cAQJA;gBAEUA,sEAEGA;gBAFTA;;wBAQCA;gB1CAS9+B;mB0CGd8+B;;UAGFA;YACiBA;YACfA;mBACEA;cACOA;cAFTA;cAG2BA;cAGzBA;gBAAmBA;;cAEAA;;YAAVA;YAMPA;+BAAKA;YAATA;cAGUA,0DAC+BA;cADrCA;;cAHJA;cAWEA;gBACUA;;;gBAERA;;cAEFA;gBACUA;;;gBAERA;;cAGFA;gBACUA;;;gBAERA;;cAGMA,gCACsBA;cAD5BA;;;UAWNA;;MAEFA;aACEA;aACAA;aACAA;;IAEJA,C;;;;S1CzLcC;MAAEA;oBAGQA;MAFpBA,0CACAA,iBAnC8BA,eAoCVA;K;kBoC8HhBC;MAAuBA,aAAVA;MAADA,sEAAsCA;K;gBA2EnDC;MACMA;mCpCxOcA;YoCyOdA,sBpCtOeA;YoCuOfA,sBpCpOaA;YoCqObA,sBpClOcA;coCmOZA,sBpChOcA;coCiOdA,sBpC9NcA;aoC+NfA,wBpC5NoBA;;MoC+N9BA,SAIJA;K;;;;StB7WcC;MAAEA;oBAC0CA;MAAtDA,0CAAqBA,oBANCA,UAMgCA;K;kBAElDC;MAAYA,OAAUA,iCAAVA,WAAkBA;K;gBAwB/BC;MAUWA;;iBA1CQA;MA+CxBA;QACEA,aAtJEC,oCA6JND;MAL2BA,4BArENA;MAsEMA,4BA/DNA;MA6CHA,iDAoBHA;MACbA,YAhFiBA,oDAgFCA,6BAAiBA,6BAAiBA,eACtDA;K;;;YAtBEE;MACEA;QAAiBA,aAMnBA;MALEA;QAAgBA,cAKlBA;MAJEA;QAAeA,eAIjBA;MAHEA;QAAcA,gBAGhBA;MAFEA;QAAaA,iBAEfA;MADEA,kBACFA;K;;;;YAEAC;MACEA;QAAaA,aAEfA;MADEA,cACFA;K;;;;;gBpBxJKC;mBACDA;MAAJA;QACEA,8BAAkCA,wBAGtCA;MADEA,yBACFA;K;;;;;;gBAmBOC;MAAcA,uBAAgBA;K;;;oBAgE1BC;MAAcA,kCAAoBA,wBAAwBA;K;2BAC1DC;MAAqBA,SAAEA;K;gBAE3BC;;kBAEDA;;gBAGgBA;MAAkCA;MACpCA;gBACbA;QAAWA,aAKlBA;MAHuBA;MACKA,uCAAaA;MACvCA,+CACFA;K;;;;;;oBAqJWC;MAAcA,mBAAYA;K;2BAC1BC;MAAkBA;0BACpBA;gBAEHA;MAAJA;kBACMA;QAC0CA;;kBAGrCA;QAAJA;UAC0CA;aAC1CA;UAC0BA,mDAAQA;;UAKDA;;MAExCA,kBACFA;K;;;oBAoCWC;MAAcA,mBAAYA;K;2BAC1BC;MAAkBA;yBACpBA;MACHA,uCAAoBA;MACpBA;iCAAaA;MAAjBA;QACEA,qCAMJA;eAJMA;MAAJA;QACEA,+BAGJA;MADEA,wCAAqCA,OACvCA;K;;;;;;gBAuFOC;MAAcA,uCAAyBA,QAAQA;K;;;;;;gBAgB/CC;mBAAoBA;MAANA,sEAEMA;K;;;;;;gBAYpBC;MAAcA,2BAAaA,QAAQA;K;;;;;;gBAgBnCC;mBACDA;MAAJA;QACEA,kDAIJA;MAFEA,sDACaA,8BACfA;K;;;gBAMOC;MAAcA,sBAAeA;K;;;;gBAQ7BC;MAAcA,uBAAgBA;K;;;;gBAgB9BC;mBAAcA;gJAEoDA;K;;;gBQnjBlEC;MAELA,2BAAoBA,QACtBA;K;;;;;;;gBA8DOC;MAGiBA;iBADlBA;;qBAGcA;2BACSA;MAC3BA;QAEEA;kDAAqDA;;UAArDA;;UAIIA;QAAJA;UAEaA,qBADAA;UAGXA,6BAgENA;;QA3DIA;UACaA;UACXA;YACEA;cACEA;YAEUA;;iBAEPA;YACLA;YACYA;;;;QAyCPA;8BAhCYA;QACrBA;UACaA;UACXA;YAKWA;YAHTA;;;QAQJA;UAIEA;YACQA;;;;;YAEDA;cACGA;;;;cAIAA;cACFA;;;;;;UAI6BA;UAAPA;UACEA;UACLA;;QAFdA;QAEfA,kDAA4CA,oDADHA,gBAS7CA;;QAFIA,mDAF0BA,2BAI9BA;K;;;;;;;YFlEWC;;iBACLA;MAAJA;QAiCAA;UAA+CA;;UAAlBA;QAA7BA;UACEA,kBAAUA;QAhCVA,qBAGJA;;MAY0BA;MACoBA;MAd5CA,wCACFA;K;eAGcC;MACZA;;MACqDA;eADjDA;MAAJA;;;QAawBA;QACxBA;UqIzGIC;UrI2GSD;;QAEFA;;IAbbA,C;gBsInFOE;MAAcA,wBAAUA,KAAKA;K;;;;;ahIwJxBC;;MAAoBA,qFAA2BA,WAA3BA,6BAA6BA;K;aAgBjDC;;MAA+BA,ObqN3CA,yDarNkEA,cbqNlEA,wCarNuEA;K;gBAsDlEC;MACHA;;QACMA,WADNA;UACoBA,WAGtBA;MADEA,YACFA;K;YA0FOC;MACuBA;;MACvBA;QAAqBA,SAc5BA;MAZEA;QNwMkDA;;UMtMrBA;eAClBA;;QAEgBA;eAClBA;UAEoBA;;MAG7BA,sCACFA;K;YAhBOC;;K;uBAqCCC;MACNA,gFACFA;K;cAFQC;;K;aAaDC;MAAWA,OAAHA,qFAAoBA;K;gBAS3BC;MAAOA;sBACDA;MAEEA;MACdA,gBAAOA;QACLA;MAEFA,YACFA;K;iBAOSC;MAAWA,QAACA,wBAASA,YAAUA;K;iBAsE5BC;;MACVA,ObiJFA,6DajJoCA,cbiJpCA,4CahJAA;K;eASMC;MACaA;MACZA;QACHA,sBAA2BA;MAE7BA,OAAUA,gBACZA;K;cAYMC;MACaA;;MACZA;QACHA,sBAA2BA;;QAIfA;aACLA;MACTA,aACFA;K;iBAiGEC;MAASA;MAEEA;MAEXA;;QACEA;UAA2BA,cAI/BA;QAHIA;;MAEFA,sBAAiBA;IACnBA,C;gBAkBOC;MAAcA,OAAaA,oDAAqCA;K;;;;;EgCxQvCC;gBAAzBA;MAAcA,6BAAWA,eAAMA,qBAAOA;K;;EtCzUnBC;kBAAlBA;MAAYA,uDAAcA;K;gBuInD3BC;MAAcA,aAAMA;K;;;EvIiCIC;SAHjBC;MAAaA,qBAAsBA;K;kBAGzCD;MAAYA,wCAA+BA;K;gBAG5CE;MAAcA,yBHmlBGA,IADRA,wCGllBiDA;K;qBASxDC;MAAeA,6BAAoBA;K;;;;;;;;;;;gB4DTrCC;MAAcA,uBAAWA;K;;;;6B5DiVxBC;;iBwIhTEA;;QxI6SWC,yBAAWA;ewI7SHD;MAAFA;;;YxIkTrBA;MAAJA;QAA2BA,YAG7BA;MAL4BA;MAI1BA,mBACFA;K;;;EwCiSAE;kBAhDiBA;MAAYA,8BAAaA,QAAOA;K;cAEzCC;;iBACFA;eAAOA;MAAXA;QACEA,sBAAMA;MAGGA;MACXA;QACqBA;QACnBA;UACEA,OAAOA,2CAIbA;;MADEA,WACFA;K;;;iBA4GQC;MAAWA,6BAAiBA;K;gBAuB/BC;;kBACHA,wBAAYA;kBACKA;eAAOA;MAAxBA;aACEA;QACAA,YAeJA;;MAbiBA;MACIA;MACnBA;QACqBA;QACnBA;eACEA;UACoBA,KAApBA;UACAA,WAMNA;;;WAHEA;WACAA;MACAA,WACFA;K;;;;gBxChPQC;MAAUA,qBAAUA,OAAMA;K;gBA4B3BC;mBAAuCA;MAAzBA,sCAAmCA;K;;;;;YyCmmBtDC;MACEA,sBAAMA,uDAA8CA;IACtDA,C;;;;YAiEAC;MACEA,sBAAMA,uDAA8CA;IACtDA,C;YAFAC;;K;;;;YAKAC;MACEA;;QACEA;MAEcA,oBAAMA;MAClBA;0BAAMA;MAAVA;QACEA;MAEFA,YACFA;K;;;;kBA8QSC;MAAYA,qBAASA;K;cAErBC;mBACLA;MAAJA;QAAmBA,SAKrBA;MAJMA;QACFA,OAAOA,wCAAyBA,YAGpCA;MADEA,SACFA;K;cAEQC;mBACFA;MAAJA;QAAmBA,OAAOA,wBAAaA,QAEzCA;MADEA,SACFA;K;eASWC;mBAASA;iCAAYA;K;kBAErBC;mBAAYA;iCAAeA;K;iCA4PlCC;MAaGA;MA+BeA;MAWCA;oBArCLA;MAEDA;sBAIGA;kBAKJA;kBAi0BSA;MAzzBhBA;uBAEaA;MAIfA;MACDA;MAAJA;QACSA,8CA01F4CA;;oBAv1FvCA;QACZA;mC7B36CgBA;;U6Bw4CdA;QAoCGA;UACQA;;MAgBfA,OAzcFA,oDAgciBA,cAMGA,WAIpBA;K;oBApEIC;;K;4BAAAC;;K;sBA2EaC;;qBACFA;MACbA;QAAoBA,aAYtBA;wBAVoBA;MACYA,e7B18CZvhC;Q6B28CFuhC;MAIZA,+BADEA,uChDj+CRngC,yBgDm+CUmgC,oE9BxnDkCA,qC8BwnDHA;MACvCA;MACAA,aACFA;K;mBAwiBOC;MAEDA;MAGJA,kCAAOA;QACLA;QACAA;;MAIYA;MAEdA;;;QACeA;QACbA;UACEA;QAEUA;QAGZA;;UACIA;YACeA;;YADaA;;UADhCA;;UAGEA;QAGFA;QAdKA;;MAgBPA,OAAOA,2DACgBA,oEACzBA;K;eAuGIC;MACFA,OAAOA,kBAAeA,uBACxBA;K;kBAEIC;MAEKA;MAMOA,0BAAOA;QACMA;QACXA;UACeA;UACJA;UACAA,uCAAoBA;;;;;;QAEhCA,uCAA6BA;QAC5BA,yCACYA;;4BAGNA;QACNA;UACeA;UACJA;UAEnBA,8BAAoBA,0BAAoBA;UAC/BA,uCAA6BA;UAC5BA,yCAAkCA;;gCAE1BA;4BACJA;4BACAA;UACJA;8BACMA;YACJA,yCACYA,6BAELA;;YAGPA;cACCA,uCAA6BA;;wBAkD3BA;oB7BhuELC;gB6BkrERD;kBAG2BA,yBAiCVA,gDA7BAA,0BAA6BA;;kBAI/BA,6CAAmCA;;gBAGjCA,qCAAiCA;iCAsBjCA;gBAYDA;kBAhCDA;;kBAMAA;;;YAKLA,yCAAkCA;;;;MAKtDA,OA9tCFA,0FA6tC8BA,8BAAwBA,iCAGtDA;K;sBAISE;MAAgBA,yBAAaA;K;iBAE7BC;MAAWA,yBAAaA;K;kBAExBC;MAAYA,0BAAcA;K;qBAE1BC;MAAeA,6BAAiBA;K;yBAIhCC;MAAmBA,sDAAoBA;K;kBAkBzCC;;kBACDA;MAAJA;QACEA,sBAAMA,2DAAqDA;gBA1nC3CA;MA4nClBA;QACEA,sBAAMA;gBA3nCaA;MA8nCrBA;QACEA,sBAAMA;MzC5+DoBA;;QyCg/DXA;;QAIGA,SA7CGC;UA8CrBD,kBAAMA;QAKgBA;QACxBA;QzCtnEYC,8ByC4kEcA;;;MA+B1BD,SACFA;K;gBAsEOE;;kBACEA;;kBAMHA;eAAOA;kBAvHYC;;QAwHvBD;;oBA7BIC;gBAAUA;;UAIdA;;oBACIA;UAAJA;YzC5qEeC;;;mByC0sENF;kBACLA;QAAJA;;kBACIA;QAAJA;;kBAfOA;;MAAPA,SACFA;K;SAkBcG;MACZA;MADcA;oBAahBA;MAZEA;QAA4BA,WAY9BA;MAXeA;QACOA,SAAhBA;UACsBA,SAxIHA;YAyIDA,SA3vCDA;cA4vCjBA,6BAAcA;gBACdA,6BAAcA;kBACAA,SAAdA;8BAxIeA;;oBAyIGA;;;sBACHA;kCAxIGA;;wBAyIGA;;;0BACHA;;0BADNA;;wBADNA;;sBADGA;;oBADJA;;kBADAA;;gBADAA;;cADIA;;YADIA;;UADNA;;QADXA;eAWFA;K;kBAEQC;MAC+BA,aAA9BA;MAAPA,wBAAOA,kDAAmBA,wBAC5BA;K;uBAx5CaC;;K;;;;;;;;;;YAqE4DC;MACjEA,sBAAMA,uCAAgCA,UAAKA;IAC5CA,C;;;;YAsOYC;MACfA;MAAIA;;gBACEA;UACFA,sBAAMA;;UAENA,sBAAMA;IAGXA,C;;;EA8fiBC;YAAPA;MAAOA,0BAAWA,YAAgBA,4BAAGA,oBAAYA;K;;;;aAsxCtDC;;kBACFA;MAAJA;QAAuBA,SAezBA;gBAZmBA;;6BAAiBA;gBACjBA;aADAA;MACAA;cACDA;MAChBA;QACeA,+DACwBA;QAIZA;;QACMA;MACjCA,YADAA,aA4rCFA,4CA9rCcA,2CACyBA,gCAGvCA;K;gBA8ROC;;iBACFA;;6BAAiBA;eAA2BA;MAA7CA,SAACA,8BAA0DA;K;;;YAgPbC;MAAOA,yBAAaA;K;;;;YAItEC;mBACIA;;iCAAMA;aAANA;MAAMA;MAANA,SAAkDA;K;;;;YAMtDC;MACEA;qBAA0BA,oCAA1BA;QACaA;QACXA;oCAAMA;;;IAEVA,C;;;;YAQAC;MACEA;MAAaA,yDAAyBA,gEAAtCA;QACSA;QAAPA;oCAAMA;;;IAEVA,C;;;EAoNuCC;sBAN9BC;MAAgBA,0BAAcA;K;iBAE9BC;MAAWA,kCAAkBA,sBAAiBA,WAAUA;K;kBACxDC;MAAYA,8BAAcA,eAAcA;K;qBACxCC;MAAeA,iCAAiBA,KAAKA,OAAMA;K;iBAE3CJ;MAAWA,oEAAmBA,cAAuBA;K;iBACrDK;MAAWA,gCAAmBA,kDAAuBA;K;kBACrDC;MAAYA,gCAAmBA,mDAAwBA;K;yBAOvDC;MAAmBA,2DAAqBA,YAAWA;K;gBAWjDC;;;kBACLA;MAAJA;QAAqBA,SAcvBA;gBAbMA;MAAJA;QAA0BA,SAa5BA;MAZMA;kBACFA;WACSA;aACTA;;aACSA;aACTA;;aAzBsCA;aA2BtCA;;;QAEeA;aAAfA;;MAEFA,SACFA;K;kBAIWC;MACLA,aADkBA;iBAAaA;MAAdA,oDACjBA,uBACEA;K;cACGC;MACUA,aAAjBA;yDAAiBA,eAA2BA,iBAAgBA;K;cACxDC;MACNA;MAAIA;QAASA,OAAWA,YAAMA,gDAAeA,sBAAgBA,yBAI/DA;MAHMA;QAASA,SAGfA;MAFMA;QAAUA,UAEhBA;MADEA,QACFA;K;cAEWC;MAAQA,qDAAeA,iBAAYA,aAAYA;K;eAC/CC;MACLA,aADeA;iBAAcA;MAAfA,oDACdA,uBACEA;K;kBACGC;MAC0BA,aAAhCA;iBAAiBA;MAAlBA,cAAuBA,yDAAiDA;K;sBAwB3DC;;oBACHA;kBACFA;iBACNA;;QAA6BA;MACjCA;QAAkBA,QAAOA,WAW3BA;MAVuBA;MACrBA;QACaA;UAETA,+BAAUA;UACFA;;MAGZA,+BAAUA;MACVA,oDACFA;K;eAiBKC;MAGCA,yBAFiBA;MACrBA,4BAA6BA,gBAAUA,mDACnCA,4BACNA;K;sBAIIC;;kBA1HoBA;kBAAiBA;MAfzCA,YAe8CA;QA2H1BA,YAGpBA;MAFEA,wBAAkBA,gDAAmCA,kBAAYA,kBAC7DA,kBAAYA,kBAAYA,uBAA6BA,cAC3DA;K;iCAEIC;MAUGA;MAiCeA;MAWCA;MAvCLA;MAEDA;gBAGJA;MACEA,oEAAeA;MAOdA,6BAAeA;gBAQlBA;MAAJA;QACEA,2DAA2BA;;uB7Bh9HlBpkC;M6Bq9HbokC;MACDA;MAAJA;QACcA,8CA0SuCA;;QAvS5CA,uDAAeA,kBAAYA;QAClCA;mC7B39HgBA;;U6Bs7HdA;QAsCGA;UACQA;;gBAOJA;gBAAcA;MACfA;gBAKCA;gBAAiBA;MACfA,kBADoBA;MAIjCA,OA1/FFA,+DA2/FAA;K;oBApEIC;;K;4BAAAC;;K;eAsEAC;MACFA,OAAOA,kBAAeA,uBACxBA;K;kBAEIC;MAEOA;QAAPA,2CAGJA;MADEA,OAAOA,sBAAeA,uBACxBA;K;oBAOIC;;gBA3NkBA;MA4NpBA;QAAmBA,UA4KrBA;cAvYyBA;MA4NvBA;iBA7NoBA;QA8NlBA;UAAqBA,UA0KzBA;QAxKaA;wBA/MYA,mBAAcA;aAiNnBA;UACFA;;UACEA,oCACFA;QAEdA;UACmBA;UAGjBA,OArPNA,iBAmPwBA,sDACVA,qEAKAA,wBACAA,wBACAA,yBACAA,6BACCA,cAqJfA;;UAlJMA,OAAOA,sBAAeA,iBAkJ5BA;;oBAvXyBA;cAAcA;MAwOrCA;gBArPiCA;QAsP/BA;mBACmBA;;UAGjBA,OAxQNA,iBAsQwBA,mDACVA,kDAGCA,iBACAA,iBACAA,iBACAA,yCAGAA,cAkIfA;;gBAnYyCA;mBAAKA;UAf9CA,SAmRuBA;UAGjBA,wBAFkBA,mDACVA,4CAGCA,iBACAA,iBACAA,iBACAA,iBACAA,kCAEAA,cAoHfA;;QAlHIA,OAAOA,uBAkHXA;;cAxX4BA;;iBAyQPA;;QAGjBA,OAtSJA,iBAoSsBA,mDACVA,kDAGCA,iBACAA,iBACAA,gCAGDA,6BACCA,cAoGbA;;sBAvXyBA;oBAAcA;uCAhBdA;eAySVA;UACTA;QAE0BA;QAG5BA,OA1TJA,iBAwTyBA,gEACVA,kDAGFA,iBACAA,iBACAA,uCAGDA,6BACCA,cAgFbA;;oBAnEwBA;MAItBA,6BAAOA;QAAsCA;MAY3CA;MAFFA;QAAOA;QAA0BA;;QAE/BA;QAFKA;;MAePA;QACEA;QACWA;UAGTA;;YAAoBA;;UACpBA;;;;MAxVsBA,kCAhBNA;QAwXlBA;QAG+BA;;MArYnCA,mCAqY0CA;MAIxCA,wBAHqBA,+DACVA,kDAIFA,iBACAA,iBACAA,uCAGDA,6BACCA,cACXA;K;kBAEOC;MACLA;MAAwBA,SAApBA;QACFA,sBAAMA,2DAAqDA;gBAEzDA;gBAAcA;iBAAKA;sBACHA;UAChBA,sBAAMA;QAGRA,sBAAMA;;MzCx6HoBA;;QyC46HNA;;iBAIlBA,mBAAaA;UAEfA,kBAAMA;QAnWSC,6CAAeA;;MA6VhCD,SACFA;K;kBAiBQE;MAAoCA,aAAxBA;oFAAmBA,WAAaA;K;SAEtCC;MAAEA;oBAGhBA;MAFEA;QAA4BA,WAE9BA;MADEA,OAAaA,4BAAUA,UAAQA,mBACjCA;K;oBAEIC;MAEOA;;aACAA;kBAlbcA,kBAmbMA;aACpBA,sBAAeA;kBA3XPA;kBAA2BA;aAA3BA,wCAAeA;kBAtDCA;MAmbRA;MANzBA,OAnuGFA,0CAuzF8CA,UAmbhBA,6BAC9BA;K;gBAEOC;MAAcA,gBAAIA;K;;;;;;;;;;;;;;;;gBI4uKlBC;MAAcA,uBAA+BA;K;;;;;;;;;;;;wBAo5J/CC;MAKCA;MAAJA;QACEA;IAEJA,C;yBAkBKC;MAAiBA,yHACZA;K;4BAKLC;MAAoBA,4HACfA;K;;;;;gBA8pICC;MACTA;QACEA,sBAGJA;MADEA,OAAeA,gCAAkBA,kBACnCA;K;gBAEOC;MAAcA,uBAA+BA;K;;;;;;;;;;;;;;wBAonC/CC;MAQ0BA;MAJ7BA;QACEA;MAGIA;IACRA,C;mBAkBKC;MACCA;MAMJA,qB4FrjoBEC,sCCiHSA;M7Fq8nBXD,MACFA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAiqdSE;MAAeA,WAAIA;K;2CAKNC;;yBAGeA;;;MADnCA,OAAWA,gCACFA,oBAAcA,8BADZA,eAEbA;K;6BAJsBC;;K;cAAAC;;K;;;cAyGfC;MACDA;eASgBA;QATLA,WAOjBA;MALEA;WAEAA;MACAA;MACAA,WACFA;K;aAoBKC;cAlBiBA;QAmBLA,MAOjBA;;MALEA;IAKFA,C;aARKC;;K;cAYAC;MACCA;eA/BgBA,+BA4BDA;QAGSA,MAG9BA;;MADEA;IACFA,C;kBAEKC;;kBACCA;6BATeA;QAUjBA,iDAAyBA;IAE7BA,C;iBAEKC;;iBACCA;;MAAJA;iBACEA;;QAppoBEA;QAAJA;UACEA,mCAmpoB4BA;;IAEhCA,C;uBA5EcC;;K;;EAgB8BC;YAAfA;MAAOA,WAACA,eAAmBA,sBAAEA;K;;;;gB6F3zlCtDC;;iBACWA;oBAAOA;MACpBA;cACgBA;UAAmBA,QAKrCA;MAHEA;MACAA;MACAA,cACFA;K;YAiBAC;MACEA;;QAAeA,QAkEjBA;MAjEQA;QAASA,QAiEjBA;MAhEEA;QAAcA,QAgEhBA;MA/DEA;QAAiBA,QA+DnBA;;QA7DIA,iB1I6O8BC,Q0IhLlCD;MA3DQA;QAEJA,sBAAUA;MAUNA;QAASA,QA+CjBA;MA9CQA;QAASA,QA8CjBA;MDlFOA,qCAAyBA,gCAAwBA;QCyC7BA,QAyC3BA;MAvCQA;QACOA;kBA5CIA;;kCAAMA;iBA6CjBA,UA7CWA;QA8CfA;UAAkBA,WAoCtBA;;UAnCIA;QA7CFA;QA+CEA,eAAUA;QAGVA,SAAOA,KA8BXA;;MA3BQA;QAMOA;kBA7DIA;;kCAAMA;iBA+DjBA;QAAJA;UAAkBA,WAmBtBA;QAjBIA,OADOA,yBAkBXA;;MAdQA;QACOA;kBArEIA;;kCAAMA;iBAsEjBA,UAtEWA;QAuEfA;UAAkBA,WAWtBA;;UAVIA;QAtEFA;QAyEEA,4BAAoBA;QAGpBA,SAAOA,KAIXA;;MADEA,sBAAUA;IACZA,C;gBAEKE;MAEYA;;;eAECA;MAtFhBA;MAuFAA;QACEA,qCAAUA,YAAKA;MAEjBA,WACFA;K;;;YA5CcC;MACcA,WAAXA,iBAAWA;IACvBA,C;;;;YAwBmBA;MACOA,WAAXA,iBAAWA;IAC1BA,C;;;;gBAiDDC;;iBACWA;oBAAOA;MACpBA;cACoBA;UAAmBA,QAKzCA;MAHEA;MACAA;MACAA,cACFA;K;YAiBAC;MACEA;;QAAeA,QAoDjBA;MAnDQA;QAASA,QAmDjBA;MAlDEA;QAAcA,QAkDhBA;MAjDEA;QAAiBA,QAiDnBA;MA/CEA;QD7L6CA;QrG4VzCC;UAAJA;;UpC7IuDC;QoC6IvDD;UAGEA,kBAAMA;QsGjKND,O1IcJE,sC0IgCAF;;MA3CEA;QAEEA,sBAAUA;MAGZA;QACEA,OAAOA,mCAqCXA;MDxL4CA;;QCyJ7BA;kBAlCIA;;kCAAMA;qBAmCjBA,UAnCWA;QAoCfA;UAAkBA,WA6BtBA;;QA5BWA;cAAPA;QAnCFA;QAsCEA,0BAAkBA;QAClBA,aAAOA,KAwBXA;;MArBEA;QAEsBA;QAATA;kBA9CIA;;kCAAMA;iBAgDjBA;QAAJA;UAAkBA,WAiBtBA;QAfmBA;;oBAGRA;QAnDTA;QAuDIA,4CADFA;UACEA,sBAAUA,aAAKA;QAEjBA,WAMJA;;MADEA,QACFA;K;0DAEAG;MAEaA,IADNA;MAELA,0BACFA;K;;;YA/BsBC;MAA4BA,oBAAZA;iBAAYA;MAAZA;eAAuBA;K;;;;wBDjMxDC;MACHA;;;;QAEEA;;IAEJA,C;;;sBAiBKC;MACHA;;;;QACEA;;IAEJA,C;;;Y9F7CAC;;iBACMA;;QACFA,OAAOA,eAiBXA;MAfQA;QAEmBA;QAAvBA;QACkBA,6BAAlBA;;UAC6CA,gCAASA;;QAEtDA,mBASJA;aAReA;QAEYA;QAAvBA;QACAA,0CAAqBA;QACrBA,oBAIJA;;QAFIA,QAEJA;K;;;EA0F8CC;YAAPA;MAAOA,iCAAmBA,+BAAEA;K;;;EACvBA;YAAPA;MAAOA,wCAA0BA;K;;;;;;;;;;;;;;;;;;;;ea7G5DC;;;yBACqCA;eAN5BA;azCDMC;YA4MA3/B;QyCrMV0/B,cAA2BA;MACxCA,SACFA;K;;;;cmFdKE;MACHA,oEAAeA;IACjBA,C;eAEKC;MACHA;IACFA,C;cAEKC;MACHA,2CAAeA;IACjBA,C;aAEKC;MACHA;IACFA,C;aAFKC;;K;cAIAC;MACHA;IACFA,C;cAEOC;MAAYA,mDAAgBA;K;;;;WzES9BC;MACHA;qCASAA;eATIA;QAASA,sBAAMA;gBAKPA;gBAAQA;MACpBA;;MAGAA,cAAUA,yDAYPA,aAAWA;IAIhBA,C;aAIKC;MACWA;WAAdA;eACIA;QAAeA,MAGrBA;gBAFMA;YnDzDmBA,OA4MApgC;QmDnJKogC,MAE9BA;MADEA,mBAAoBA;IACtBA,C;;;;YAzBYC;;;MAISA;aAHbA;YnDnCiBA,OA4MArgC;QmDzKOqgC,WAW7BA;;aARCA;0CAAQA;YAEJA;QAAeA,WAMpBA;aAHMA;QAASA,WAGfA;MADCA;IACDA,C;gBAZSC;;K;;;YAYID;mBACRA;YnD/CiBA,OA4MArgC;QmD7JOqgC,WAE7BA;MADCA,0BAAgCA;IACjCA,C;;;;W0E5BEE;;MACHA;IACFA,C;iBAMOC;MACeA;qCAGPA;MAHbA;WAEAA;MACaA,+BAAoBA;;Q7H0JnC9wC,wBCuE2BC;QDtEzBA;;M6H1JA6wC,OAAOA,sBAAoBA,8CAG7BA;K;0BAIKC;cACCA;QAASA,sBAAMA;cACfA;QACFA,sBAAMA;IAEVA,C;aAEOC;UACLA;MACAA,WAAOA,KACTA;K;;;;;;;;;;YAjB6BC;UACzBA;IACDA,C;;;;gBC/CEC;MACHA,8BAAwBA,YAAOA;IACjCA,C;aAEKC;MACHA,oBAAcA,YAAOA;IACvBA,C;kBAkBQC;MAAYA,QAAMA,oBAANA,UAA4BA,oBAAXA,+BAAgCA;K;SAGvDC;MAAEA;oBAGkBA;MAF9BA,yCACAA,wBAAeA,eACfA,oBAAoBA,WAAUA;K;;;;;gBCjC7BC;uCACHA,kBAAUA,eAASA;IACrBA,C;aAEKC;uCACHA,aAAKA,aAAIA;IACXA,C;kBAIQC;MAAYA,QAAMA,oBAANA,0BAA2BA;K;SAEjCC;MAAEA;oBACgCA;MAA5CA,yCAAwBA,wBAAeA,OAAKA;K;;;;uBCyC3CC;MACHA;oCAGyBA;eAHrBA;YA+DyBA;QA9D3BA,sBAAMA;MAwERA,iDAAgBA;YACZA;QAEFA;IAxEJA,C;;;2CAsCsBC;MAEpBA;gCAIgCA;MACEA;MAAuBA;eALrDA;kBACEA;QAAwCA;UAG1CA,OAAOA,iGAUbA;QAPIA;iBACIA;UACFA;;gBAGGA;M1HkrBTpwC,E0HlrBqBowC;MAAnBA,mC1H2V0BA,oBAuV5BpwC,iC0HlrB4BowC,6EAE5BA;K;6BAhBsBC;;K;cAAAC;;K;+BAuCjBC;MACHA;0BAAOA;MACPA,oBAAOA;MACPA,wEACeA;gBACGA;MADbA,kBACyBA;IAChCA,C;yBAgBKC;MACHA,mBAAOA;MACPA,uCAAcA;IAChBA,C;uCAxEoBC;;K;uBAMVC;;K;;;W5EfHC;MACLA;qCAK6BA;eALzBA;QACFA,sBAAMA;gBAGJA;kBAA4BA;QAC9BA,yDAAmCA;WAK5BA,YAJ8BA;QAIrCA,6BAA2BA,UAM/BA;;QAJIA,yDAAmCA;MAGrCA,WACFA;K;iBAuBKC;UACHA,yBAA2BA;MAC3BA,+CAAuBA;IAOzBA,C;0BAoCKC;UACHA,yBAA2BA;MAE3BA,+CAAuBA;IASzBA,C;uBAKsBC;MAChBA;qCAAeA;gBAAcA;MAAdA,8CAA0BA,gBACFA,0DAAlBA;eACrBA,2BAA4BA;QAAQA;MACxCA,mBACFA;K;aAQOC;MACLA;MC4DiBA,SD5DbA;QAASA,YAAOA,gDAMtBA;WAJEA;gBACIA;MAAeA;QAASA;MAE5BA,OCuDiBA,KDvDVA,gDACTA;K;mCAhMoBC;;K;;;;YA4EmBC;MAAMA,WAAIA;K;;;EAOJA;YAANA;MAAMA,wCAAgBA,QAAOA;K;gBAA7BC;;K;;;YA6BdC;;;8BAKNA;8CADXA;QAAsBA,MAE3BA;MADCA,qDAAyBA;IAC1BA,C;gBANsBC;;K;;;YA8CAC;;;8BAKhBA;0CACLA;MADYA;QAAaA,MAG1BA;MAFCA;MACAA;IACDA,C;gBARsBC;;K;;;YAgBoBC;MAzExBA,aAyE8BA;eAzE9BA;kEAAsBA,WAyEeA;+CAxEbA;MACbA,MAA1BA;QAAmCA;MAuEUA,aAAcA;K;;;;gBAyD1DC;MAAcA,gBAAIA;K;;;c6E3FXC;MACZA;gBAAKA;;QjIgDPrnC,oBCyE2B3M,gBDzE3B2M;QiI9CIqnC,oBAwgBJA,mBjIhpBIpnC,6DiIgpBJonC;QAvgBIA,SAGJA;;MADEA,sBAAMA;IACRA,C;uBAqPKC;MACHA;qBAAOA,0BAC0BA,c1IiBXA;e0BwJlBA;qBAASA;UAAOA,kBAA2BA;eACxCA;;gCAAMA;QgH1KOA,MhH0KbA,uBgH1KuCA;UAC1CA;;UAEAA,MAONA;;gBAHOA;QAuCLA;IApCFA,C;sBAQUC;MACRA;0BAAOA;M1HumBHA,S0HtmBAA;QACFA,0B1HqmBEA,qC0HplBNA;WAfEA;gBAEIA;MAAJA;QACEA,YAAOA,sBAYXA;MAREA;MAE6BA;MCxa7BC;MAEAA;MACAA;MACAA;MDwaAD;QAAeA;MACfA,OC/aFA,wEDgbAA;K;wBAgBKE;MACHA;eAAIA;QAASA,MAafA;gBAZMA;MAAJA;QACEA,sCAAgBA,oDAAeA,mDAIpBA,oDAFCA;;QAOZA;IAEJA,C;kBAiBKC;MACcA;qCACDA;;gBAAhBA;M/B3bAA,sBAAKA;M+B4bLA;IACFA,C;mBAgBMC;MACJA,OtJSFA,qCsJRAA;K;mBAMKC;MACHA;4CACMA;gBADFA;YhHkDcA,aAASA;QgHjDrBA,0BAAeA,mBAAaA;UAAUA,MAI9CA;QAHIA;;MhHuFFA,sBAAKA;IgHpFPA,C;qCAvcsBC;;K;;;YAyYaC;;;MAC7BA,gBFhdNA,kBEgd8BA,+BFhd9BA;IEidKA,C;gBAF8BC;;K;;;YAEnBD;MACVA,wBH/cNE,yBG+cqCF;IAChCA,C;;;;YAAUA;mBACTA;;QAgCJA;MACAA;IA/BGA,C;;;;;cAiNAG;+CACCA;MnB/mBcC;QmBgnBhBD,uBAAqBA,eAASA;QAC9BA,WAOJA;;MALEA;QACEA,gCtJpKJA,iCsJoKmEA;QAC/DA,WAGJA;;MADEA,YACFA;K;;;;cAoLKE;;;yCACCA;MnB7yBcA;kBmB8yBZA;kBACFA;cADeA;iBDnyBfA;iBAoDyBC;UApD7BD;YACEA,kBAAMA;UAkFRC;gBACIA;YACFA;iBAEcA;YAAYA;UAA5BA,qB1HwoBFxyC,4BAvV4ByyC,oBAuV5BzyC;U0HvoBEwyC;;UC8sBID,qBAA2BA;;QAKZA;QvJ1jBrB3/B,qCAEyBA,2BAFzBA,kDuJ2jBI2/B;UACEA,EvJvjBWA;QuJyjBbA,qCACeA,8CACVA,eAAwBA;QAC7BA,mC3HnFJvyC,oCAvV4BuyC,4BAuV5BvyC;;M2HqFEuyC,WACFA;K;;;;;0BE1yBSG;MAAoBA,8DAAuBA,yBAAwBA;K;cAEjEC;mBACLA;MAAJA;QAA4BA,SAAsBA,OAMpDA;eALMA;MAAJA;QnIsHFvoC,oBCyE2B3M;QDpPvBm1C,ImIsDAD;QACAA,SAGJA;;MADEA,OAAwBA,aAC1BA;K;iBAoBOE;MACLA;qCAAwDA;MAApDA;QAAkBA,OAAOA,0CAI/BA;MAFEA;MACAA,OAAOA,iFACTA;K;aAEOC;MACLA;MAAIA;QACFA;;QAEAA;QACAA;;MAEFA,OAAOA,gBACTA;K;yBAGKC;cACCA;QAAqBA,4CAAcA;IACzCA,C;2BAQKC;MACHA;yCACmBA;MADnBA,oBAAOA;MACPA;gBAIIA;MAAJA;QAGEA,iB7HkpBJhzC,4BAvV4BgzC,oBAuV5BhzC,kC6HhpBSgzC,eAAkBA,sBAClBA,aAAWA;gBAKdA;MAAJA;QACEA,cAA6BA;IAEjCA,C;4CA5FoBC;;K;0BAWNC;;K;;;;;;;YAyEMC;IAAMA,C;;;;2CD/HJC;;;yBAYNA;MAEAA;MATWA;mBAHrBA;MAAJA;QACEA,sBAAMA;MAIRA;MAqBFA;MAhBEA;MACAA;MACAA;MACAA;MACAA,cACFA;K;6BAjBsBC;;K;cAAAC;;K;sCApBAC;;K;;;eAmDjBC;MAEGA,mDAAQA;IAmBhBA,C;;;YAnBgBC;MACRA;MAYmBA;MAZEA;MACzBA;QAEEA,4BAA0BA;;iBAQtBA;QAAYA;UACdA;;UAEAA;;IAGLA,C;;;;YAd6BC;mBACpBA;iBAGUA;MAHEA;QACdA,kBAAmBA;;QAEnBA;IAEHA,C;;;;;gBErEFC;MAAuBA,WAAIA;K;oBAEhBC;MAAuCA,YAAKA;K;gBAIvDC;;IAA2CA,C;gBAEzCC;MAAcA,cAAOA;K;;;EjDeDC;cAA3BA;MAA2BA,oCAA2BA;K;gBAE/CC;MAAcA,gBAAIA;K;SAEXC;MAAEA;oBAAsDA;MAA3CA,8CAAyBA,cAAcA,KAAIA;K;kBAE9DC;MAAYA,OAAKA,oBAALA,MAAaA;K;;;;;;EAcNC;cAA3BA;MAA2BA,+BAAsBA;K;gBAE1CC;MAC4CA,aAA/CA;uGAA4DA,sBAAOA;K;SAEzDC;MAAEA;oBAAmDA;MAAxCA,qCAAoBA,uBAAeA,OAAKA;K;kBAE3DC;MAAmBA,aAANA;MAADA,iCAAeA;K;;;;;;EAKdC;cAARA;MAAQA,qBAAiBA,IAALA,kBAAiBA,IAANA,kBAAWA;K;cAevDC;MAA2BA,8BAAqBA;K;gBAEzCC;;sBACSA;;QAAgDA;oBAE1DA;;QAAkDA;MAEtDA,OAASA,wBAAYA,YACvBA;K;SAEcC;MAAEA;oBACiDA;MAA7DA,oCAAmBA,sBAAcA,UAAQA,uBAAeA,OAAKA;K;kBAEzDC;MAAiBA,aAALA;iBAAgBA;MAAhBA,8BAAsBA,0BAAQA;K;;;EAK7BC;cAARA;MAAQA,qBAAiBA,IAALA,kBAAiBA,IAANA,kBAAWA;K;cAevDC;MAA2BA,+BAAsBA;K;gBAE1CC;;sBACSA;;QAA+CA;oBAEzDA;;QAAiDA;MAErDA,OAASA,wBAAYA,YACvBA;K;SAEcC;MAAEA;oBACkDA;MAA9DA,qCAAoBA,sBAAcA,UAAQA,uBAAeA,OAAKA;K;kBAE1DC;MAAiBA,aAALA;iBAAgBA;MAAhBA,8BAAsBA,0BAAQA;K;;;EAK7BC;cAARA;MAAQA,qBAAsBA,IAAVA,uBAA0BA,IAAVA,sBAAeA;K;cAmBhEC;MAA2BA,uCAA8BA;K;gBAElDC;;8BAEDA;;QAAkCA;uBACrBA;;QAAiCA;MAClDA,OAASA,+BAAmBA,0BAAcA,4BAC5CA;K;SAEcC;MAAEA;oBAIgBA;MAH5BA,6CACAA,2BAAmBA,eACnBA,0BAAkBA,cAClBA,2BAAmBA,WAASA;K;kBAExBC;MACMA,aAAVA;iBAAqBA;iBAAoBA;MAAzCA,8BAA8BA,sBAAqBA,0BAAQA;K;;;EkDtJtBC;qBAApCA;MAAoCA,kCAAgBA,MAAKA;K;gBAEzDC;MAA0BA,8BAAMA,0BAAkBA;K;eAElDC;MACDA,6BAAKA,mDAA0BA,0BAAkBA;K;gBAEhDC;MACDA,6BAAKA,mDAA0BA,0BAAkBA;K;wBAEhDC;MAA0CA,6BAAKA,iCACzCA,+BACAA,6BAAsBA;K;;;;gBCA5BC;MAAuBA;MDhBCA;QACjBA;QAAkBA;;QACRA;;;MCcMA,+BDjB5BA,oBCiBkEA;K;oBAElDC;MACVA;yBAAyBA;QAAKA,WAKpCA;MAJMA,mBAAyBA;QAAMA,YAIrCA;MAHEA,gDATFA,0BnDuFAA,kBmD7EsCA,iBAAiBA,eCrBvDA,uCDuBAA;K;gBAUKC;MACHA,wBEpCFA,gBFoC6BA;IAC7BA,C;gBAEOC;MAAcA,mCAAoBA;K;SAE3BC;MAAEA;oBACgDA;MAA5DA,iDAAgCA,2BAAmBA,WAASA;K;kBAExDC;MAAsBA,aAAVA;gCAAkBA;K;;;;gBCxCjCC;MACDA,6FAAkCA,sCAA8BA;K;oBAEpDC;MACZA,OANJA,uCAMqCA;K;gBAIhCC;MACiBA;MAApBA;MACAA;IACFA,C;gBAEOC;MAAcA,aAAGA,2CAAiBA,0BAAYA;K;SAEvCC;MAAEA;oBAGkBA;MAF9BA,kDACAA,4BAAoBA,gBACpBA,6BAAoBA,YAAUA;K;kBAE1BC;MAAuBA,aAAXA;oCAAiCA,oBAAXA,mBAAmBA;K;;;;gBEzBxDC;MAAuBA,YAAKA;K;oBAEjBC;MAAuCA,WAAIA;K;gBAItDC;;IAA2CA,C;gBAEzCC;MAAcA,eAAQA;K;;;;aCGxBC;MACYA;iBAEXA;;MAAgBA,yBAAkBA;QACpCA,sBAAMA,uDACwBA,YAAgBA;MAGhDA,eACFA;K;oBAOKC;MACaA;;kBACXA;sBAAwBA;QAAeA,gBAS9CA;MAPiBA;MACVA,gBAAwBA;QAC3BA,sBAAMA,8CAA2CA,YAAgBA;MAInEA,OvDqGFA,2CuDtGkBA,uBAElBA;K;WAMKC;MACQA;MACNA,oCAAwBA;QAAKA,WAEpCA;MADEA,OvDqBFA,mBuDrBsBA,aACtBA;K;YAMKC;MACQA;MACNA,oCAAwBA;QAAMA,WAErCA;MADEA,OvD4CFA,oBuD5CuBA,cACvBA;K;yBAQKC;MACSA;;;MACEA;;UAEEA;UACZA,OvD9BNA,cuD8BkCA,iBAAKA,YAAaA,yBAgBpDA;;UAbkBA;UACPA,gBAAwBA;YAC3BA,sBAAMA,8CACeA,YAAgBA;UAEvCA,YAQNA;;UALiCA;UAA3BA,OvD7DNA,wBuD6DiEA,YAAZA,MAKrDA;;UAFMA,sBAAMA,qDAAwDA;;IAEpEA,C;;;YC3DMC;MACuBA,aAAvBA;MACJA,wBADmBA,wCAErBA;K;YAMMC;;qBACQA;;QAAgBA;MACFA,KAA1BA,gDAA4CA;WAC5CA;MACAA,YACFA;K;YAOKC;MACCA;MAAOA;QAAcA,YAG3BA;MAFEA;MACAA,WACFA;K;gBAGMC;MACJA;eAAIA;QAAmBA,sBAAMA;MAE7BA;gBACIA;aCnDcC;MCLpBD,aDkC+BA,OAAOA;QDuBlCA,oBAAuBA,gBAAWA,c5G+CtCE,iC4G1BAF;MAlBUA;;UAEJA,OAAOA,uBAAwBA,eAgBrCA;;UAdMA,OAAOA,uBAAwBA,eAcrCA;;UAZMA,OAAOA,uBAAwBA,eAYrCA;;UAVMA,OAAOA,uBAAwBA,iBAUrCA;;UARMA,OAAOA,uBAAwBA,eAQrCA;;iBCzEoBE;UD0FlBF;UAvBIA,OExENG,aFgGyBH,eAAIA,c5GQ7BE,iC4G1BAF;;iBCzEoBE;UDmGlBF;UA9BIA,OE1ENI,aFyGyBJ,gBAAKA,c5GD9BE,iC4G1BAF;;UAgCEA,iBAAgBA;UACgBA,wBAASA;U5GxFrCK;Y8GZNA,E9GYyBA;U4GqDnBL,+B5GpDGK,e4GsDTL;;K;qBAMMM;mBACQA;eChFMJ;eA6BWK;mBAAOA;QAgKpCA;MA7IOD;MDkCPA,OEvFFA,kBFuFqBA,c5GiBrBJ,iC4GhBAI;K;0BA4BKE;;iBACIA;MAAPA;QCVcA,0BDUOA;QCTrBA;UACyBA,EACvBA,wBADAA,+BAAYA;QDSVA;;;IAGNA,C;yBAKKC;;iBACEA;;QAAqBA,YAQ5BA;MANEA;QCtBcA,0BDsBOA;QCrBrBA;UACyBA,EACvBA,wBADAA,+BAAYA;QDoBiCA;;;MAG/CA;MAEAA,WACFA;K;;;;;;;;;;EE1HmCC;gBAA5BA;MAAcA,gCAAcA,YAAMA;K;;;;;;;;;;gBAqClCC;MAAcA,gBAAIA;K;;;qBLnDpBC;gCACCA,2BAAgBA;QAAOA,MAE7BA;MADEA,sBAAMA,wDAAsDA;IAC9DA,C;;;gBMIKC;MACEA;IACPA,C;eAEKC;MACEA;MACAA;IACPA,C;gBAEKC;MACEA;MACAA;IACPA,C;wBAEKC;MACEA;MACAA;MACAA;IACPA,C;;;ECXkBC;kBAdFC;MAAYA,QrK2pBMA,gBqK3pBsBA;K;gBAChDC;MAAUA,QAACA;K;gBAKdC;MAA4BA,YAAKA;K;aAQ/BH;MAAWA,4DAAKA;K;;;;;YxFdfI;MAAeA;;aAAOA,mBAAKA;K;gBAA3BC;;K;;;YAIID;MAC6CA;MAA5CA;MAAQA;;MAAnBA,0BAAOA,iCAAyBA;IACjCA,C;gBAFWC;;K;;;YAgBCC;MAE0DA;MAD9DA;MAC0CA;gBADjDA;2BACIA,wBAA0BA,mBAAMA;IACrCA,C;gBAHYC;;K;;E2CsEqBC;gBAA3BA;MAAcA,0DAAiDA;K;mBAcpEC;;kBACIA;sBAASA;QAAOA,sBAAMA;gBACfA;;8BAAMA;iBAANA;MACXA;WACAA,2BAASA,8BAAcA,mBAAOA;MAC9BA,aACFA;K;gBAYQC;MAAUA,YAACA,yBAAQA,yBAAUA,mBAAOA,kBAAWA;K;gBAEnDA;MACFA;;QAAeA,sBAAMA;MAEDA;MACpBA;iBACMA,mBAAOA;UACTA;aAEFA,2BAASA,kCAAkBA,mBAAOA;QAClCA,MAYJA;;gBATgBA;;gBAEZA;MADFA;QACEA;;qBAEkBA;QAClBA;kBACAA;qDAAiCA;;WAEnCA;IACFA,C;YAEWC;MACTA;MAAIA;MAAsBA;QACxBA,sBAAMA,gEAAmDA;gBAGpDA;aAAiCA;iBAAzBA;MAARA;8BAAMA;MAAbA,SAAOA,IACTA;K;eAEcC;MACZA;MAAIA;MAI4CA;MAJ5CA;0BAAMA;MAAgBA;QACxBA,sBAAMA,gEAAmDA;gBAG3DA;4CAAQA,+BAAyBA;IACnCA,C;wBAyBKC;;;MACaA;MAAhBA,2DAAOA;gBACEA;gBAAcA,mBAAOA;MAAfA;WAAfA;eACIA;QAKeA;;;kBACPA;kBAAgBA;kBAATA;QACnBA;QACAA,2DAAiCA,yBAAOA;aACxCA;aACAA,0BAAQA,mBAAOA;QACfA;;IAVFA,C;oBAaIC;MACFA;mCAAOA;MAAPA,qBAAcA,WAAUA;gBACpBA;gBAASA;gBAKSA;MALtBA;QACeA;QACbA;QACAA,cAOJA;;0BAL+BA;QAC3BA;QACAA,yEAA+CA,yBAAOA;QACtDA,YAAOA,kCAEXA;;K;gBAGKC;MACHA;wCAA0BA;MAKRA,0DADCA;MAEAA;;;;;MACXA,KAARA;MACAA;WACAA;IACFA,C;4BA1NQC;;K;;;;;;;;gBzCkBAC;MACFA,mCAAcA;MADFA,SAEIA;K;kBAENC;MAAYA;aAAUA,mBAAQA;K;8BAG9BC;mBACAA;qB0D4XZA;;sDAA2BA,O1D5XFA;MAAzBA,O/EmZJC,2F+EnZ2DD;K;aA0BpDE;MACQA;;M/CitCFA,c+ChtCKA,6C/CgtCwBA,6BAA7BA,oC+ChtCXA;QACEA,qB/C8kDaA;M+C5kDfA,aACFA;K;;;YAvCoBC;MAAiBA;;uCAASA;MAAIA;MAAbA;6BAAOA;MAAPA;wBAAOA;MAAPA,mBAAmBA;K;gBAApCC;;K;;;YAOSC;MAASA,mDAAGA;K;gBAAZC;;K;;;;oCD5BjBC;;K;;;;;EwFFqBC;gBAA5BA;MAA4BA,wCAAuBA;K;aAInDC;MAA+BA,sEAAYA,aAAKA;K;eAI/CC;MAAeA,aAANA;6BAAWA;K;iBAYjBC;MAAiBA,aAANA;+BAAaA;K;kBAIjBC;MAAkBA,aAANA;gCAAcA;K;cAIpCC;MAAcA,aAANA;4BAAUA;K;gBAKhBC;MAAgBA,aAANA;8BAAYA;K;aAElBC;MAA0BA,+EAAUA,cAAEA;K;uBAqB1CC;MAAkCA,4CAAgCA;K;cAAlEC;;K;aAEDC;MAAWA,4BAAaA;K;aAEnBC;MAA+BA,sEAAYA,aAAKA;K;gBAIrDC;MAAcA,+BAAgBA;K;;;;;aAgO9BC;;MAAsCA;MAAfA,OA3CPA,sBA2CgBA,cAAYA;K;aAE5CC;MA7CgBA;MA6CLA,OA7DZA,oBAgBiBA,wCA6CqBA,YA7DtCA,+BA6D8CA;K;;;;E5CxPdC;eAAjCA;MAAiCA,yBAAYA;K;gBAEtCC;iBxBxCVA;MwBwC+CA,kBAAuBA;K;;EA4P3BC;oBAAxCA;MAAwCA,4BAASA,oCAAKA;K;gBAG/CC;iBxBvSVA,uBwBwSkBA;MAAhBA,kBAA6BA;K;;;gBxBjTzBC;MAAUA,gB3FqiBAA,UAAUA,O2FriBCA;K;gBAItB9rC;mBAAcA,K3F6jByBA;M2F7jBzBA,sCAAeA;K;wBAqBxB+rC;;QAERA;;QAEIA,IApBNA;MAsBAA,WACFA;K;;;EyBnB4DC;oBAAvDA;MAA6CA,mEAAcA;K;gBAGpDC;MACRA,0CAA6BA,wBAAOA;K;6BAG5BC;MAENA;MAEqBA;MpH0gB3BA;UAkCEnzC;MoH5iBkBmzC;MACCA,4BAAOA;6BACEA;+BAAsBA;;MAIlDA;QACMA,8DAAkCA;UACpCA;MAGJA;iBpHiiB6CnzC;QoHhiB3CmzC;cpHgiBFnzC;UoH7hBImzC;;cpH6hBJnzC;UoHzhBImzC;;;;QAIFA;QACAA;;QAEAA;QACAA;;;eAEAA;UpHofaA;cA2BfnzC;;;;eAH4CmzC;yB2FxjB5CA;MyBkDAA,0BACFA;K;;;yBA4BaC;MAEXA;;MAAWA;QACuBA;QACJA;QAC5BA;UAEqBA;UACFA;UAGbA;UAAJA;YAAkCA,WAexCA;UAXyDA;UAAnDA;YAAmBA,OAAOA,iFAWhCA;UAVMA;YAAiBA,OAAOA,kFAU9BA;UAPeA,oBAAyBA,gCAAwBA;UAE1DA;YAAgBA,SAKtBA;;;QAFIA,OAAOA,0EAEXA;K;oBAEaC;MAEXA;;MAAWA;QACGA;QAEZA;;UACMA,qBAAYA;YAEdA,OAAOA,4CAAoBA,uDAcnCA;;QAVcA;QAAkBA;QAAlBA;0BAAOA;QAAjBA;UACEA,OAAOA,+EASbA;;UARqBA;UAAkBA;UAAlBA;4BAAOA;UAAjBA;YACLA,OAAOA,gFAObA;;YALMA,WAKNA;;;QAFIA,OAAOA,0EAEXA;K;uBAEaC;MAGXA;;;QAEMA,kCADaA;UACyBA,WAmE9CA;QzBzNAA,sC3FuiBAtsC;QoH9YIssC;QACAA,OAAOA,0CAAkBA,4DA+D7BA;;;UA3DUA;YAAoBA,WA2D9BA;;UA5DIA;UAISA,0CAAaA;UAApBA,SAwDNA;;gBApDcA;MAAZA;QAAoBA,OAAOA,yFAoD7BA;MAjDEA;QACeA;UACXA,OAAOA,uCACeA,kDA8C5BA;aA7CwBA;UAClBA,OAAOA,4CACeA,kDA2C5BA;;;UA1CwBA;YACPA;cAASA,OAAOA,yEAyCjCA;YAtCoBA,uCAAcA;YACHA,oCAAzBA;;cACOA;gBACHA,OAAOA,qDAA6BA,iDAmC9CA;;YA/B0BA,kCAApBA;;cACOA;gBACHA,OAAOA,oDAA4BA,iDA6B7CA;;YAzB+BA,oCAAzBA;;cACWA,6BACLA,yBAAeA,0CAAuBA;cAC1CA;gBAAgBA,SAsBxBA;;YAnBMA,WAmBNA;;;MpH8UAtsC;MoHzVEssC;UpH2XAtzC;Q2FzkBFszC,iCyBiNSA;UzBnMPA;QyBoMOA;QAEEA,OpHkXmCrsC;QoHlX1CqsC,+FAKJA;;MADEA,OAAOA,2DACTA;K;8BAEOC;MACIA;;MACTA;QAAgBA,WAclBA;MAZMA;;QAAMA;MxGmMQr0C;QwGlMZq0C;UAAMA;QxGkMMr0C,sCwGjMFq0C,0CAAqBA,wBAExBA;;QAMuBA;;MAAXA;MF5NNA;MACrBA;MACAA;MACAA;ME0NEA,aACFA;K;eAGKC;MACDA,yCAAOA,qCAAoCA;K;gBAGnCC;MACRA,0CAA6BA,WAAUA;K;wBAG/BC;MAEwBA;qCAArBA;;QAKTA;iBxGqKcA,oC+E7ZFA,K3FqiBAX,UAAUA;8B2F5hB1BW;a3F2jB6C1zC;MoH5U7C0zC;UpH4UA1zC;QoH3UsB0zC;;UpH2UtB1zC;MoHvUA0zC,0BACFA;K;;;YApIsBC;MACZA;uCAAQA,sCAAgCA,gBAAUA,eAAcA;K;;;E4C/HhEC;eADLA;MACDA,oFAAmCA,oBAAaA,4EAAiBA;K;wBAKzDC;4DAEDA;QACPA,OAAOA,0EAKXA;MADeA,mBrECbA;MqEDAA,2DACFA;K;6BAEYC;;MAERA,0BAAmBA;K;;;wBCwBXC;MAERA,0BAAmBA;K;;;Y1CxCvBC;MAEEA;;;Q5BNFA,sC3FuiBAhtC;QuH/hBIgtC;QACAA,aAAUA,+BA6FdA;;MAzFMA;QAAuBA,oBAyF7BA;MAxFSA,EAAPA,qBAAkBA;MACTA;MAEEA;QAESA,6CAAeA;;QAGnBA,uCAAeA;oBACGA;kBAASA;QAAzCA;UACEA,sDAAmDA;QAK3BA;QAGrBA,cADcA,yBAAmBA;UAEpCA,iBAqENA;;QAjEIA,sB9H0WJ1zC,0DkBrJ4C0zC,O4GpNxBA,iD9HyWpB1zC,4C8HvWW0zC,0BAmEsBA,uEALjCA;aA1DoBA;;QAEKA,4BAAKA,WAAIA,yDAE3BA;oBAG6BA;kBAASA;QAAzCA;UACEA,sDAAmDA;QAKhCA;QAGhBA,cADcA,yBAAmBA;UAEpCA,iBAyCNA;;QArCIA,e9H8UJ1zC,0DkBrJ4C0zC,O4GxLxBA,kD9H6UpB1zC,4C8H3UW0zC,0BAuCsBA,uEALjCA;;;QA9BSA;UAGLA,a9HoUJ1zC,yB8HrUgB0zC,gE5GgL4BA,oC4G9K1BA,kFAAeA,qBA+BAA,kFALjCA;;UAvBgBA;UA4BiBA;YA5BVA;U3G9BdA;U2G+BiBA;UAItBA;YAaSA;UAPEA,sDACAA,8BACAA;YAKTA,YAKNA;;YAHMA,OAAUA,iCAGhBA;;;K;;;EAvFsBC;YAApBA;MAAoBA,2CAAoBA,wBAAYA,aAAYA;K;;;;YAuB9CC;MACmBA;MAA7BA,OAAOA,wBAoEgBA,gDApERA,6CAChBA;K;;;;YAMyBA;MAClBA;MAAVA,WAAUA,yBAAYA,cAAGA,4BAC1BA;K;;;;YAkBeA;MACmBA;MAA7BA,OAAOA,wBAwCgBA,gDAxCRA,6CAChBA;K;;;;gB2CIGC;MpKgsBSC;4BoK/rBeD,mEpK+rBFC;aoK9qBLD;QAAtBA;MtJzCEC;iB+EnCPD;MuE4DAA,kBACFA;K;eAGKE;MAAwCA,sDAAKA,SAAIA;K;;EhD5C5BC;YAAPA;MAAOA,4BAAGA,IAAFA,aAAgBA;K;;;;YAYAC;MAC5BA,mCAAWA;MACxBA;QAAoBA,aAErBA;MADCA,OAAOA,iBAAeA,mBACvBA;K;;;;;;;;;;;ExCnBsCC;YAAZA;MAAYA,6BAAoBA,sBAAIA;K;;;;;;;;;;;;gB2C6BxDC;MAQ6DA;MADlEA,+BACgBA;eAmGcA;0CAgBIA;MA/GlCA;QACEA,YAIJA;MADSA,SA7BaA;MA6BpBA,wCA7BoDA,6DA8BtDA;K;gBAjBOC;;K;YA0IAC;MAQeA;MAUpBA;MACAA,OAAOA,e5HkMTvvC,2BkBlMoCuvC,kC0GAPA,2DAC7BA;K;YApBOC;;K;eAoCAC;MACDA;MAIaA;+D/GzC+CA,O+GyCnCA,uC5H8K4BA,gCAU3Dt/B,+E4H1JqBs/B,+EA9BnBA;Q5HmMyBA;Q4H3PSA;UAy1BSA;;UA1xBnCA,6CAAkBA;gBADfA;UAEHA;YACKA,kDAAsBA;UAGlBA;eApFaA;UAgBIA;UrHuXnBA;;iBqH5SFA;UAAWA;YAA2BA;mCAAIA;YAA5BA,8BAAwBA;;YAA3BA;UAApBA;YAEOA;cAjNiBA;;;QA0NTA;;MAGnBA,sCACFA;K;aAoBaC;MA2uBgCA,qDAAYA;mBAxuBjCA;;a5HmHxB1vC;M4HnHS0vC,iB/GyFPA,iBb0BF1vC,8CkBlMoC0vC,O0G+EAA,2C/GyFlCA;iB+GxFWA;MAAXA;QAAgCA;MAChCA,aAAcA,MAChBA;K;iBA+BOC;MACLA;MAAKA;QAA2BA,WAKlCA;MAgsB6CA,iDAAYA;MAlsBvDA;MACAA,OAAOA,oBACTA;K;2BAGKC;MACCA;UACiBA;eAOVA;;MACXA;QAMqBA;UACjBA;Y7H1SoBA;c6H2SeA,WA6CzCA;QAxCeA;QAXMA;;QAWNA;;;M7HnTf1zC,+BAEkB0zC,iBAAQA,6C6HiTxBA;Q7HhTwBA;Q6HkTlBA;UAEiBA;YAAoCA,WAoC7DA;UAjC8BA;YAA6BA,WAiC3DA;UA3BmCA;YAGrBA;;YAHqBA;UAA7BA;YAIEA,WAuBRA;;;MAdEA;QAAsBA,WAcxBA;MAXMA;QAA6BA,WAWnCA;MAR+BA;QAErBA;;QAFqBA;MAA7BA;QAIEA,WAIJA;MADEA,YACFA;K;qBAkCOC;MAELA;;;MA/Q8BC;QA+QaD,OAAOA,uBA6EpDA;;kBApdsBA;QAAgCA;;QAyYpBA;gBAjRFC;wCAAAD;QAqR5BA,OAAOA,uBAuEXA;MA5VgCC,kCAgBID;QA2QzBA;MA3RqBC,kCAAAD;QAiS5BA,sBAAMA,yBAA0CA,yBAAaA;MAwkBpBA;MArkB1BA;MAqkB0BA;MApkB1BA;qBAEFA;a1GgHGj0C;M0GhHci0C;QAAcA;+BAAKA;sBAALA;;QAAdA;MAAhCA;QACEA,OAAOA,wBAoDXA;qBA7CiBA;qBAAmBA;MAAKA;QAE9BA;;QAF8BA;MAAvCA;QAGEA,OAAOA,wBA0CXA;MAtCEA;uBAAkBA;e1GiGAj0C;Q0GhGci0C;yBAAjBA;iB1GgGGj0C;U0GhGGi0C;YACWA;mCAAKA;mBAALA;YAAqBA;mCAAKA;YAAtDA,2BAAiDA;YADhCA;;;;UAAWA;;;QAEnBA;QACAA;QACAA;QACAA;;qBAMEA;a1GqFGj0C;M0GrFci0C;QAAcA;+BAAKA;sBAALA;;QAAdA;MAAhCA;QACEA,sBAAMA,yBAA0CA,yBAAaA;;MAEpDA,mDAAwBA,6BAAkBA,MAAMA;MAChDA;MACAA,wDACYA,6BAAkBA,MAAMA,SAAcA;qBAG9CA;a1G4EGA;M0G5ElBA;QAA8BA,UAiBhCA;MAbsDA;QACvCA;uBACAA;;;;;gBAOFA;MACXA;MAEAA,OAAOA,wBACTA;K;gBA/EOE;;K;yBAsGOC;MAnXkBA;;2CAAiBA;0BAAjBA,gBAAiBA;MAyX/CA;QACUA;QACJA;UAAuCA;aACtCA;QACIA;QACLA;UAAqCA;aACpCA;QACqBA;QACCA;QAE3BA;UACUA;aACHA;UACIA;;MAIAA;sBACeA;QAAcA,aAmB5CA;;;QAfeA;;QADbA;UAKEA,QAAqBA,wBAWzBA;;UAhBEA;;MA9Y8BF,oBAMiBE;QAgZfA,QAHTA,wBAWzBA;MAPMA;QAAiBA,QAAqBA,oBAO5CA;MANMA;QAAkBA,QALCA,wBAWzBA;MALEA,OAAiBA,mCACTA,oCACAA,iBAAkBA,kCARHA,4BAUHA,qBACtBA;K;6BAIcC;MAGZA;;QAEwCA;gBAAjBA;;MACDA;MAQtBA;QAAyCA,QAAqBA,wBAoLhEA;MA7KyBA,4CACDA,kCAFtBA;QAGOA,yBAFgBA,8BACDA;UAElBA,QAV0DA,wBAoLhEA;kBA3J8BA;MAAUA;MAA/BA;MARkBA;;MAQzBA;oDAAyDA;;;UAClCA;UACDA;UAChBA;YACEA;;YAKJA;YACAA;;;;UAKEA,wCACAA;YAEFA;;;;iBAESA,uCACPA;YACFA;;;UAUoCA;YACpCA;YAIAA;cAAkCA;YACjBA;YAGbA;cAEFA;;;;;YAMFA;cACEA;cAEIA,2CAAkBA;gBACpBA,QAAqBA,2BAsG/BA;;;UA5FyCA;YACnCA;sBACwBA;YAAxBA;cAAgCA;YAChBA;YAEZA;cACFA;;;YAIFA;cACEA;cAEIA,0CAAkBA;gBACpBA,QAxBqBA,2BAsG/BA;;;UArEyBA,mDACgBA;YACnCA,QAnCyBA,2BAsG/BA;UAhE0BA,sDAJeA;YAMnCA,QAxCyBA,2BAsG/BA;UA3DIA,QAzH4DA,wBAoLhEA;;;8BAlD0BA;QAElBA,2CAAkBA;UAOKA;;;QAAvBA;2BAC4BA;UAAQA,QAAqBA,oBAwCjEA;QAvCIA,sBAAmCA,uBA/DRA,+BA9EiCA,wBAoLhEA;;MA/BkBA;yBATkBA;QAkBMA,QAlBuBA,oBAwCjEA;MAJUA,mBAnC6BA;QA0BnCA,QAzF2BA,2BAsG/BA;MAJEA,wBAA0BA,uDAClBA,kCACYA,yBAlL0CA,wBAoLhEA;K;sBAeeC;MACTA;oBAGYA,kBAWaA,mDAX7BA;QAEEA;UAA0BA,iCAAkBA;;UAC1CA;;QAIFA;UAAsBA;QAIfA;QAAPA;UAA2BA,mCAAkBA;;UAC3CA;;QAIEA;QAAkBA;UAGlBA,mEACAA;YAEFA;YAGAA;cAAeA;YAIfA;;;YAGAA;QAIFA;UAAsBA;QAGtBA;;MAGFA;QAAeA,QAAsBA,mBAIvCA;MAHEA;QAAgBA,QAAsBA,mBAGxCA;MAFEA;QAAiBA,QAAsBA,mBAEzCA;MADEA,QAAsBA,mBACxBA;K;aAgJIC;;iBArzB4BL;;QAuzB5BK,OAAOA,4BAIXA;;QAFWA,SAj7BWA;QAi7BlBA,8BAA+BA,iCAj7BmBA,mBAm7BtDA;;K;iBA2BOC;MACUA;;MACFA,6CAAoBA,UAAeA;QAC9CA,OAAOA,sBAcXA;WAbsBA,wCACPA,qCACTA,UAAeA;QACjBA,OAAOA,sBAUXA;MAPaA,yBA7DUA,0BAAkBA;MA8D7BA;MAKVA,OAAOA,qBAAWA,UAASA,sBAAYA,oBACzCA;K;;EArzBuCC;YAAVA;MAAUA,2CAAYA;K;;;EAsBVC;YAAVA;MAAUA,0CAAUA;K;;;EAyDLC;YAAVA;MAAUA,mCAAKA,aAAUA;K;;;;YAqwBlDC;MAASA;mDAA+BA;K;;;;gBA+B5CC;MAAcA,gBAAIA;K;;;gBA4BlBC;MAAcA,gBAAIA;K;;;e8C3kClBC;MACQA;;MACbA;QAAgBA,OAAOA,iCAEzBA;MADSA;QAAuBA;iCAAIA;iBAAJA;;;MAA9BA,SACFA;K;yBAWIC;M7GNmBA,uC6GOEA;MAInBA,uBAAYA,2BAAqBA;QAAcA;MACnDA,OAAOA,uCACTA;K;sBAOKC;MAAgDA,8BAAsBA;K;kBAMtEC;MAA0CA,qBAAcA;K;;;8BrEUpDC;mBACLA;YnFmfgBn1C;QmFnfWm1C,oDAAyBA,sCAAXA;;QAAxBA;MAAjBA,SAA+DA;K;gCAE9DC;MACHA;;kBAAOA;QAA0BA,QnFgffp1C,wBmFhfeo1C;;QAC/BA;QACAA;;gBAEEA;anF4ecp1C;MmF5elBo1C;QAA2BA;IAC7BA,C;iBAEKC;MAGoBA;;qBACNA,eAAjBA;;QACMA;mCAAeA;UAERA;yBnFkeKr1C;YmFhedq1C;cACEA;4CAASA;cAATA;;cAGAA;;YAGFA;;eA7EiBA;QAmFnBA,2CAA2BA;kBnFmdXA,sBmFtiBGA;QAwFnBA;MAIgBA,6CACLA,SAAQA;gBA7FAA;MA+FrBA,mEnFuckBr1C,iBmFrcuBq1C,mCACzBA,KAANA;MAGVA;MACAA;gBAGIA;MAA+BA,uBAAfA;UAEXA;QlFlFFA,KkFkFLA;;MAEFA;IACFA,C;gBAEOC;;kBAEDA;;MACJA,qBAAoBA,MAAMA,SAA1BA;kBACgBA;;+BAAUA;Q9FkaXA,gB8FlaCA;kBACAA;;+BAAKA;Q9FiaNA,gB8FjaCA;;M9FiaDA,U8F/ZUA,gCAAXA;MAEdA,sCACFA;K;eAxIaC;;K;oBAOAC;;K;;EAoGuBC;YAAbA;MAAOA,uCAAeA;K;;;;gBCxHtCC;MAAcA,+BAAiBA,QAAQA;K;;;;;;EzCyEzBC;gBAAdA;MAAcA,0BAAIA;K;;E8G7DcC;yBAAlCA;MAAkCA,+CAAkBA;K;mBAEpDC;MAA6BA,sBAAuBA;K;sBAEpDC;MAC+BA,aAA3BA;MAALA,uEAAiEA;K;4BAEjEC;MACiCA,QAA1BA;QAA+CA,QAE1DA;MADEA,QACFA;K;kBAHIC;;K;sBAKCC;MAA+BA,YAAKA;K;mBAIlCC;MACLA;MAAQA,+BAAoBA;QACKA;QAA/BA,O3HwjCUA,2BAC8BA,UAAQA,oB2HtjCpDA;;MADEA,sBAAMA,0BAAoBA;IAC5BA,C;yBAEIC;MACsBA;mBACbA;YzJ4hBOA;QyJxhBTA,+BAAaA;WACJA;QAGTA;MAGTA,OAAOA,8BAAyCA,eAClDA;K;;;;;;;;ECrCuCC;yBAAlCA;MAAkCA,+CAAkBA;K;mBAEpDC;MAA6BA,sBAAuBA;K;sBAEpDC;mBACMA;MAATA;QAAkBA,YAQpBA;MALmBA;QAAmCA,WAKtDA;MADEA,OAAOA,8CAAwBA,8BACjCA;K;4BAEIC;;iBACOA;MAATA;QAAkBA,QAyBpBA;MAxBkBA;QAAqBA,QAwBvCA;MAtBEA;QACiBA;QACfA;UAA2BA,QAoB/BA;QAnBIA;UACEA;YAAYA,QAkBlBA;UAbkBA,gDADRA;UAEJA;YAAgBA,SAYtBA;UARMA;YAA2CA,YAQjDA;UAPWA;YAA4BA,YAOvCA;UANWA;YAAgCA,YAM3CA;UAL4BA;UAAtBA,iCAKNA;;;MADEA,QACFA;K;kBA1BIC;;K;sBA4BCC;MACDA,WAAKA,iBAA0BA,gDAAmBA;K;mBAI/CC;MAAwBA,yBAAcA;K;yBAEzCC;MAAkCA,OAAIA,iBAAWA;K;yBACjDC;MAAkCA,OAAIA,iBAAWA;K;;;;;;;;EC9CdC;yBAAlCA;MAAkCA,+CAAkBA;K;mBAEpDC;MACDA,yCAAsDA;K;sBAErDC;mBACMA;MAATA;QAAkBA,YAEpBA;MADsBA;MAApBA,gCACFA;K;4BAEIC;;iBACOA;MAATA;QAAkBA,QAuBpBA;MAtBMA;MAAJA;QAAuCA,QAsBzCA;MArBEA;QACyBA;UAAuCA,QAoBlEA;QAjBgBA;QACZA;UACUA;UACRA;YAAeA,YAcrBA;;QAZIA,SAYJA;;MAREA;QAAqBA,QAQvBA;MANOA;QAAkCA,QAMzCA;MAJMA;QAAmCA,QAIzCA;MAFmBA;MAAjBA;QAAsCA,QAExCA;MADEA,QACFA;K;kBAxBIC;;K;sBA0BCC;MAA+BA,oCAAqBA;K;mBAQlDC;MACLA;MAAQA,+BAAoBA;QAC1BA,sBAAMA,0BAAoBA;MAGbA;MACPA;QAIkBA,QAAfA,8DAAuCA;UACvCA;;QAISA;M1JxBbA;M0J0BPA,O7HwgCYA,2BAC8BA,UAAQA,oB6HxgCpDA;K;yBAEIC;MACsBA;;mBACbA;;Q7K2UbhzC,gC6KtU2BgzC,4D3JoISA,kC2JpIcA;QACvCA,4CAA0BA;QAEtBA;UAGFA;QAGTA,OAAOA,YAC6BA,4CAA4BA,eAmBpEA;;QAXuCA,UAAxBA,M3JudKA;U2JtdPA;mBAKFA;mBACeA;;Q1J7DjBA;Q0J4DEA,kC1J5DFA;Q0J+DLA,OAAOA,8BAAyCA,eAEpDA;;K;sBAEKC;MACHA;;QAA4BA,WAa9BA;MAVEA;QAA8BA,uBAUhCA;MATEA;QAAkCA,uBASpCA;MALEA;QAA4CA,YAK9CA;MAFmBA;MACjBA,4CACFA;K;kBAEKC;MACHA;;QAA6BA,WAQ/BA;gBAPYA;sBAAgBA;QAAQA,YAOpCA;MAL6CA,4CAD3CA;QACOA,2BAAeA,4CAAqBA;UACvCA,YAINA;MADEA,WACFA;K;;;;;;;;EAxD4DC;YAAVA;MAAUA,0CAAUA;K;;;;e/GFjDC;MACnBA;eAjCmBA,iBC7BFC,2BzCDMlS,OA4MA3/B;QwC5IrB4xC,sBAAMA;gBAGJA;oBAAsBA;aACxBA;QxCuHJliD,oBCuE2BC;QDtEzBA,oBwCyHFiiD;QAhPIA,SASJA;;kBARaA;QjDiVWA;UiDhVpBA,OAAOA,sBAAcA,mBAOzBA;;UxC2GAv2C,oBCyE2B3M;oBuCxLvBkjD;UvBugBFA,sBAAKA,4BjB9kBHt2C;UwCwEAs2C;UACAA,SAEJA;;;K;sBAMUE;;MACRA;IAUFA,C;4BAXUA;MACRA;;;8DADQA;QACRA;;;;;;;;;gBACEA,sBAAMA;cAGOA;mCAAMA,kDAANA;;;;;cAENA;mCAAMA,2CAANA;;;;cAAPA;;;;;;;;;;;;;;;cAEAA;;;;;;;;cATMA;;;;;;MACRA;IADQA,C;aAyHHC;MAAWA,uCAAmBA,+BAe/BA;K;iCAkBDC;MACUA;MAIoBA;MAJjCA;gBAEIA;MjDsKkBA;QiDrKNA,mBACNA,WAASA;;;iBArNAA,iBC7BFH,2BzCDMlS,OA4MA3/B;UwCyCrBgyC,2BAAuBA;;YAEOA;;kBvCWPA;oBuCPvBA;UvBsVFA,sBAAKA,4BuBtVqBA,mDADPA;;;IAGrBA,C;qBAOqBC;MAKjBA;MAJKA,qBAAKA,yDAAWA,SAAKA,oDAEzBA,aAAWA;MxC9EhB52C,oBCyE2B3M;euCUzBujD;MvBqUAA,sBAAKA,4BjBnkBHpO;MwC+PFoO,SACFA;K;mBAGKC;;iBACCA;MAAJA;QAAoBA,MAOtBA;eALMA;YvBsRcA,aAASA;QuIniB3BA;;QALAA;QACSA,EAATA,6CAAeA,iCAAWA;;IhHsR5BA,C;;;YA5EqCC;;iBAC3BA;;MAAJA;QAAyBA,SWjNDA,yBAAWA,OX+NpCA;MAZCA;MW/NFA,EXiOEA,iCxC/MF72C,sBAsLJD,eCyE2B3M,kFkD7OX0O;MlC2gBY+0C,YuB7UDA,2DvB6UCA,qCuB7UtBA;qBvBsnBWA;QuBrnBTA,wBAAuBA;;MAGkBA,EAA3CA;MACAA;YAEIA;QAA0BA;MAC9BA,SAAOA,YAAYA,yBW9NgBA,OX+NpCA;K;;;EA+B6BC;YAANA;MAAMA,6BAASA,wBAAWA;K;;;;YAUxBC;mBAC1BA;8CAAmCA,WA+CvCA;IA9CGA,C;;;;YAAaA;MAC4CA;MAAxDA,gDAAmCA;IACpCA,C;;;;eAgDEC;MACHA;cAAIA;QACFA,sBAAMA;UAERA;eACAA;MA7FAA;aAEIA;MjDoLkBC;QiDnLND,mBACNA,WAgFZC;;;cAvRqBA,iBC7BFV,2BzCDMlS,OA4MA3/B;UwC4BqBsyC;;IAuF9CA,C;;;YE3TyCE;MACrCA;aAAWA,mBAAWA,qBAAcA,YAAWA,gCACjCA,uBACOA,uBACRA,UACdA;K;;;;YAW+BA;MAGhCA;MAAIA;MAAMA;QAAcA,WA6CzBA;MA1CoBA,0CAA2BA;MAIXA;;wBAAKA;MAAKA;4BAAOA;MACrCA;;MADJA;MAKXA;QAAkBA,WAiCnBA;MA/BsBA;MACIA,SAArBA,iC4DidFA,yB5DjdoCA,yB4DidcA;Q5DhdtCA,6CAAYA,aAAIA,gCAA0BA;;;eAC7CA;QAAJA;UACeA,oCACdA,a4D6cNA,oB5D7cmCA,gBAAhBA,qD4D6c+BA;Y5D5cpCA,gDACNA,aAAIA,2BACoBA,gBAAhBA;eACWA,MAAhBA;YAC2BA,YAAhBA,uCAAiCA,M1BoQ9BA,iB0BpQvBA;;cACmDA,2BAAhBA,EAAhBA,uCAAgBA,M1B4ORA;c0B3OlBA;c4DscXA,uDAAkDA;gB5DtcFA;cAGpBA,iDAAVA,eAAcA;cAC5BA;;;MAMEA;MACCA,sBAAMA;;wBAAKA;MACXA,sBAAMA;eAIXA;QACYA,+BAAoBA,kBAAaA;;QACvCA,uBAAsBA;MAThCA,O+DoNFA,mC/D1MCA;K;;;EAAmBA;YAAXA;MAAWA,wCAAaA;K;;;EAedC;YAAXA;MAAWA,wCAAUA,kBAASA,QAAMA;K;;;EAcYA;YAAhBA;MAAWA,2CAAcA;K;;;;;2C4B3BjE7xC;MAEEA;sDA0BIA,iDAhBFA,sBACAA,eAXFA;;QACeA;;UACOA,sBAAUA;QAEZA,oBAAPA;QACXA;UAAkBA,sBAAUA;QAERA,sBAAPA;QACbA;UAAoBA,sBAAUA;QAE9BA,4BAAeA;QACfA,4BAAiBA;QAEPA;QACAA;QAEFA;QAARA;UACEA,sBAAUA;aACLA;UAEOA,wDACuBA;UADjCA;eAKGA;UACLA,4BAAUA,YAAUA;;UAEpBA,sBAAUA;;YAGCA;QACbA,sBAAUA;IAEdA,C;iBAEI8xC;MACFA;oBAAoBA,oBAAWA,kBAESA,sCAFxCA;eACaA;QAAXA;UAA0BA,YAI9BA;QAH8BA;UAAYA;iCAAYA;0BAAZA;;UAAZA;QAA1BA;UAAuDA,YAG3DA;;MADEA,aACFA;K;yBAEcC;MAIRA;MAGOA;MAHCA;gBACLA;;iCAAKA;aAALA;gBACIA;;iCAAUA;aAAVA;gBAA4BA;;iCAAYA;MADnDA,OAAYA,yCAC2BA,eAEzCA;K;mBARcC;;K;qBAAAC;;K;gBAUPC;MrF5FiBA;;qBqF8FFA,uBAKRA,yBAEAA,qBAPmBA,SAA/BA;0BAGYA;QAEAA;+BAAYA;oBAAZA;QAEAA;+BAAKA;QrFkZFA,YqFlZHA;;MrFkZGA;MqF9YfA,sCACFA;K;;;qCAQAjyC;MACEA;4GAQAA,YARAA;QAC4CA,YAA/BA,YAAUA,UADvBA;QAQAA,kBAAkBA;;IALpBA,C;gBAWOkyC;MACDA;MACsBA,cAAVA,8BAAhBA;QACaA,oBADbA;MAGAA,sCACFA;K;yBAIcC;MAEZA;;;QACEA,sBAAUA;MAeaA;mBACDA,kBAGhBA,sCAHRA;QACEA;UACkBA;UACZA;YACFA,OAAOA,wBACFA,mDAgBbA;;QAbiBA,8DAA4BA;;MAUxBA,qEAC4BA;MmFpOjDA;MAAAC;MnFqOED,SACFA;K;mBAxCcE;;K;;;qCAmIdpyC;MASuBA;;;yDACfA,eACIA,iBAAqBA,8BAAHA;;kBAI1BA;kBAAkDA;;;MAHpDA;eAAyBA;0CAA6BA;;;UACvCA;6CAAcA;iCAAdA;UACbA;;UACqCA;UAAaA;iCAAIA;iBAAJA;U7F7RtDpG;UuDrCyBkB;UA4BzBkF,sBAaUjF,kCAAsBA,2CxC+3BnBD,oBwC93BiCC;UAd9CA;UsCsSIiF;;QAH4DA;;MAYrBA,4BAAHA;aA8QfA;MAFzBA;;MA3Q6BA;gBA2CJA;MAyOKA;MAAeA;gBA/QrCA;MAA8BA;MAqBlCA;MAIEA;MAMAA;MAEAA;MAIEA;MAxCNA;uBAkRoBA;;;UAjRJA,4BAASA;uB1E6NPA;c0E3NZA,4BA0ORA;cAzO+BA;;YAEzBA;;;;;UAiBYA,4BAASA;YAAcA,sBAAMA;UAqQxBA;UAnQJA;mBAsSEA,iBAAcA,oBAAiBA;YArS9CA,iCAgONA;;YAkCuBA;8BA/PIA;cACnBA,sBAAUA,0CACmBA;YAEhBA;qBA8RAA,iBAAcA,oBAAiBA;cA9RbA,sBAAMA;YA2PtBA;YAzPFA;qBA4RAA,iBAAcA,oBAAiBA;cA5RbA,sBAAMA;YAyPtBA;YAvPFA;qBA0RAA,iBAAcA,oBAAiBA;cAzR5CA,iCAoNRA;;cAkCuBA;iCAnPQA;gBACrBA,sBAAUA,oCACaA;cAEzBA,iCA6MRA;;;UAzMkBA,4BAASA;;;;iB1E6KPA;Q0E1KhBA,4BAyLJA;MAtLEA,iBAAYA;IAGdA,C;qBAqEAqyC;MACIA,O3F8CJA,gH2F7C8CA,wCAAwBA;K;iBAKtDC;MACFA;iBAAaA;mCAAOA;;;;QACGA;QAANA;gCAAKA;eAALA;;;MAA7BA,SACFA;K;mBAOYC;MACVA;wCAAmCA,QAAQA;QAAaA,WAK1DA;MAJuDA,aAAvCA;QAAcA,2CAAiBA,SAI/CA;yBAH0BA;MACZA,gCAAsBA;;;;QACGA;QAARA;qCAAOA;oBAAPA;;MAA7BA,SACFA;K;yBAEcC;MAERA;MAMAA;MANQA,0CAA0BA;gCACXA;QAAqBA,WA6BlDA;MA5BYA,gDAAWA;gBACjBA;MAAJA;QACwBA;gBAePA;MAAwBA;gBACvBA;MAFAA,kCAGEA;gBAGRA;MAAVA;kBAC6CA;;gCAAKA;eAALA;emFpgBAA;QAAnCA,4BAAqBA,mBAGPA,mBADFA,YADKA;QAJ/BA;QAAAC;QnFugBMD,SAKNA;;QmFphBAA;QAAAL;QnFihBMK,SAGNA;;K;mBAhCcE;;K;qBAAAC;;K;gBAkCPC;MrFneiBA;;MAgf4BA;MAOnCA,uCqFjBDA,iCrFiBCA,SqFfDA,4BrFeCA,SqFbDA,uBrFaCA,SqFXDA,wBrFWCA,SqFTDA;MAVdA,sCAaFA;K;;;YAjJcC;MACNA;QAAuBA,mCAAWA;IACvCA,C;;;EA8EwCC;YAATA;MAAOA,0BAASA,KAAIA;K;;;EAaTC;YAATA;MAAOA,4BAAWA,OAAMA;K;;;ErF7bpCC;gBqFwhBjBA;MAAcA,yDAAgBA,cAAMA,iBAAQA;K;;;;;;gBAiB5CC;MAAcA;arFziBGA,qDqF0iBjBA,iBAASA,gCAAcA,+BAAaA,iCAAeA,6BAAcA;K;;;;;;gBAanEC;MAAcA,0BAAUA,gBAAOA;K;iBACzBC;;iBACNA;8BAAsBA;iBAAWA;;gCAASA;eAATA;;;MAAlCA,SAAyDA;K;mBAEpDC;mBAAqBA;MAARA,oCAAkCA;K;kBAEzCC;MACbA;MAAKA;QAAWA,QAAkBA,4BAKpCA;eAJaA;eAAUA;MAAVA;8BAASA;eAATA;MACXA;QAAiBA,QAAkBA,4BAGrCA;MAFEA;QAAiBA,QAAkBA,4BAErCA;MADEA,QAAkBA,6BACpBA;K;gBAaOC;MACDA;qBAESA,qCADOA,QAApBA;QACaA;+BAASA;gBAATA;;MrF5FEA;oBqF+FJA,mCAAuBA;oBAErBA,mBAAyBA,SAAtCA;QACaA;+BAASA;gBAATA;;6BAEEA;MACfA,sCACFA;K;;;;;;;;;;YDtoB+BC;MACRA;;MACvBA;QACEA,mFAAIA;MAENA,UACDA;K;;;;gBrCISC;MAAUA,yBAAcA,OAAMA;K;eAG9BC;MAASA,uBAAYA,OAAMA;K;8BA+BnC34C;MAGEA;oBAAoBA,uBAAcA,kBAOlBA,qBAPhBA;cACUA;QACRA;UAEUA;UACsBA;YAAGA;mCAAaA;mBAAbA;;YAAHA;UAA9BA;YAAqDA;;QAEvDA;UAAcA;;IAElBA,C;YAKS44C;MAEPA,OAAWA,8BACbA;K;eAMIC;MACFA;;QACEA,sBAAUA;6BA9DIA,cAAcA;QAgE5BA,sBAAUA,wGACuBA;gBAGtBA;MAAYA;QAAOA,SAOlCA;MAN4BA;QAAMA,SAAmBA,WAMrDA;MAJMA;QAA2BA,YAAOA,YAIxCA;MADEA,YADAA,eAAcA,iCAEhBA;K;yBAMKC;;kBACCA;MAAJA;QAAyBA,YAmB3BA;gBAhBeA;;8BAAWA;qBAAXA;QAA0BA,YAgBzCA;gBAbMA;aAA2BA;MAA3BA;uBAAYA;MAA0BA;QACjBA;QAAZA;gCAAWA;wBAAXA;;QAD6BA;MAA1CA;QAEEA,WAWJA;MAP4CA;QACjBA;QAAZA;gCAAWA;wBAAXA;QAD6BA;;;MAA1CA;aAEEA;QACAA,WAIJA;;MADEA,YACFA;K;qBAKIC;;iBAEQA;eAAYA;;MACtBA;QACyBA;QACnBA;kCAAWA;cAAXA;;;UAGIA;;MAIVA,UACFA;K;iBAMIC;MACFA;;QACEA,sBAAUA;6BA/HIA,cAAcA;QAiI5BA,sBAAUA,2GAC8BA;MAIjCA;MAQOA;MAChBA;QACEA,sBAAUA,wBAAkBA;MAG9BA,yBACFA;K;iBAKIC;MACFA;MAEIA;yBAAKA;MAATA;QACEA,sBAAUA;;iBA1JGA;eAAYA;QA2JpBA;UACLA,sBAAUA,wFACeA;;iBAKdA;wBArKGA,cAAcA;QAuKzBA;oCAA8BA;;QAb/BA;MAYJA;QAEEA,sBAAUA;MAGZA,aACFA;K;iBAnBIC;;K;;EAwCYC;mBADRC;MAAaA,gBAAKA,IAAGA;K;cACrBD;MAAQA,+BAAaA,QAAOA;K;gBAC5BE;MAAUA,iCAAeA,QAAOA;K;;;;;EA0DVC;mBAFtBC;MAAaA,gBAAKA,IAAGA;K;gBACrBC;MAAUA,6BAAOA,aAAMA;K;eACdF;MAASA,4BAAmBA,WAAMA,cAAOA;K;aACzCG;MAAOA,OAAIA,qBAAeA,WAAMA,YAAKA;K;cAC3CC;MAAQA,OA5EXA,8BAAqBA,yCA4EVA,KA5EUA,oBA4EGA,mBAAQA,sBAAKA;K;iBAElCC;MACKA;;yBAAaA;;MACXA;6BAPOA;4BAxPRA,YAAYA;;;YA6QfA;YAAwCA;mCAAQA;YA9FtDA,mCAAqBA,2DA8FUA;;UAHjCA,SAkBNA;;+BA5RiBA,YAAYA;sBAHXA,cAAcA;;QA2RDA;+BAAQA;QAAvBA;;MAGdA,OA5GMA,8BAAqBA,uDA4GPA,eAAeA,kBAAaA,qCAClDA;K;SAuCcC;MACZA;MADcA;oBAShBA;MARYA;QAAcA,OAAaA,yCAQvCA;MANiBA;QAAbA,oDAAyBA,YA/ERA,KAAKA,MA+EsBA,sBAMhDA;MAHEA,YAAOA,uBAAgBA,sBACnBA,qBAAcA,eACdA,YApFeA,KAAKA,WAALA,KAAKA,KAqF1BA;K;kBAGQC;MAAYA,OAAMA,yDAAQA;K;cAMzBC;;kBA9FYA;MA+FfA,cA/FoBA,WA+FDA,KA/FCA;QAgGtBA,sBAAUA,mCAA+BA,0CACzBA;4BAIUA,oBAAcA;MAExCA,OAAWA,sCADaA,kBAAYA,aAOxCA;K;;;;;iBoDjNOC;MAC4BA;MAAjCA,0BsEzD+BA,CChHZC;gBvE0KnBD;;gBAKkBA;MAAdA,4BAAoBA,kBAAeA,eAAYA,eAAMA;MACzDA;MAEoBA;MAChBA;8BAAUA;MAAdA;QAKcA,kEAAoCA;QACzBA,oBAAMA;kBAAaA;QAAbA;0BAAKA;QAALA;uBA1K7BA,qBA2KAA;;UACEA;UACcA;UACdA;;UAEAA;;QAEQA;;MAGAA;MAEcA,kBAAIA;MAAaA,oBAAMA;MAAnBA;wBAAKA;MAALA;wBAAKA;MAALA;MACpBA;QAAKA;MvFqNGA,uCuFrNcA;QAG9BA;mCAAMA;QAANA;;MAGFA,wBAAsBA;eAClBA;QACFA,gCxFyDSA,iDwFzD6BA;QACvBA;8CAAKA;QAApBA,4BAAeA;;MAEjBA,4BxFsDWA;MwFpDXA,0BsE1G6BA,CC1GVE;a1KgkByBF;MmG1W5CA,sCACFA;K;uBAGKG;;kBACiBA;MAApBA,2BAA0BA,eAAMA;MAECA,oBAAMA;eAAaA;sBAAhDA;MAEoBA;MAAIA;MAAeA;oBADvCA,yCAC6CA;MAChCA;gBAIbA;MAAcA;kBAChBA;;QACAA,kBAAUA;;QAMVA,MAiCJA;;gBA9BEA;MAAcA;MACdA;MACiBA;MACjBA,kBAAUA;MACVA,mBAAWA;;MAKMA;MACAA;MACHA;QAAdA;QACAA;MAIAA;MACAA;;QAEEA,kBAAUA;;QAMIA;QACdA,kBACIA;;;IAGRA,C;+BAGKC;MACHA;MAIiBA;MAJjBA,oBAAOA;MAGgBA,UAANA,mBAAYA;;wBAAKA;MAALA;M1GgC/Bn9C,oCAEyBA,yBAFzBA,8D0G5BIm9C,uBAHFA;e1GoCeA;Q0GnCbA;;QAGAA,kBAAUA;;QAOVA;;IAEJA,C;sBAGKC;;kBACIA;MAAPA;gBAEoBA;MAApBA,2BAA0BA,aAAIA;MAECA,kBAAIA;eAAaA;oBAA5CA;MAIJA;kBACEA;;QACAA,kBAAUA;;QAMVA,MA4BJA;;gBAzBEA;;MACiBA;MACjBA,kBAAUA;MAKVA,mBAAWA;;MAKMA,EACjBA;MAIAA;;MAEAA,kBAAUA;;IAMZA,C;2BAGKC;MAECA;MACaA;MADMA,UAANA,iBAAUA;;wBAAKA;MAALA;M1GnC7Br9C,oCAEyBA,yBAFzBA,8D0GwCIq9C,iCA7UAA,aAyUFA;e1G/BeA;Q0GgCbA;QACcA;QACdA;;QAEAA;;IAEJA,C;kBAIKC;MACHA;UAAsBA;M3GnTxBx7C;MCmQAmJ,4BAEyBA,mBAFzBA;e0GoDMqyC;aAJJA;e1G3CeA;Q0G4CbA;UACgBA;;UnGuGA9/C;;ImGlGpB8/C,C;8BAIKC;MACHA,uBAAUA;IAUZA,C;yBAXKC;;K;0BAAAC;;K;qBAAAC;;K;kBAcDC;MACEA;M3G7UN77C,sCCmQAmJ,uBAEyBA,mBAFzBA,kE0G2EE0yC;c1GtEeA;U0GuEKA;MAEpBA,YACFA;K;yBAGKC;MACHA;M3GtVF97C,sCCmQAmJ,uBAEyBA,mBAFzBA,uD0GmFE2yC;e1G9EeA;Q0G+EbA;UAAoCA,YAGxCA;;MADEA,WACFA;K;uBAMKC;MACHA;MACAA;eADIA;MAAOA;MAAXA;QnGsJeA;YmGtJKA;;MACpBA;MACAA;YAAoBA;IACtBA,C;iBAJKC;;K;;;YA3KSC;MuEtNZA,avEuNIA;;8BuEvOeC;Q1KmkBnBx9C;MmG1VIu9C,oBAAWA;IACZA,C;;;EAQaA;YAANA;MAAMA,mCAAWA,YAAWA;K;;;;YAgB1BA;;iBACRA;MsE/MiCA,iBCpDlBE;MvEoQKF,6CsE5NcA,CCxCnBG,0CvEoQuBH;QnG+T1Cv9C;ImG7TGu9C,C;;;;YAIGA;;MAAoBA,IAAdA,iFAA6BA,eAAYA;MAAzCA,WAAyDA;K;;;;YAezDI;MsE3OwBA,atE4OhCA;;8BuE1ReC;Q1KmkBnB59C;MmGvSI29C,oBAAWA;IACZA,C;;;;YAmBSE;MuEhSZA,avEiSIA;;8BuEjTeL;Q1KmkBnBx9C;MmGhRI69C,oBAAWA;IACZA,C;;;;YAOOA;MsE7Q0BA,atE8QlCA;;8BuE5TiBD;Q1KmkBnB59C;MmGrQE69C,oBAAWA;IACZA,C;;;;YAaSA;;iBACRA;MsE7QsCA,iBChErBC;MvE8UGD,6CsEtSgBA,CCxCnBH,0CvE8UoBG;QnGqPvC79C;ImGnPC69C,C;;;;YAgCSE;mBACJA;iBAGFA;;aAA6CA;MAH/CA;QAG2BA,8CAALA;;QAENA;eAEFA;MsE1UoBA,8BC9CjBH;IvEyXlBG,C;;;;gBxBhVCC;mBACEA;sBAAmBA;QACrBA,sBAAUA,mCAA+BA,sBAC1BA;MAEjBA,OAAeA,aAAPA,UAAeA,wBACzBA;K;SAgBcC;MAAEA;oBAGUA;MAFtBA,OAAMA,mCACNA,uBAAmBA,8BACnBA,YAAgBA,uBAAMA;K;kBAElBC;MAAYA,OAAUA,oBAAVA,kBAAqBA,OAAMA;K;gBAExCC;M3ErBiBA;uE2EqBcA;sBAxDvBA;MAwDMA,aAvDVA,8DAASA,yBAAYA,mBAuD0BA;K;;;;;;;;;;;;;;;gBgGrEtDC;MACEA,gB5HgNeA,KAAKA,M4HhNDA;QACrBA,sBAAUA,mCAA+BA,wCAC1BA;MAEjBA,OAAeA,aAAPA,UAAeA,wBACzBA;K;SAYcC;MAAEA;oBAGUA;MAFtBA,OAAMA,mCACNA,W5H6LiBA,KAAKA,M4H7LHA,8BACnBA,YAAgBA,uBAAMA;K;kBAElBC;MAAYA,OAAUA,oB5H0LTA,KAAKA,Y4H1LeA,OAAMA;K;gBAExCC;M3KuBiBA,a2KvBcA;;iB5HwLjBC;mBAAKA;a4HpNfD;a5HqNKC;M4HrNID;wBAAKA;MA4BJA,oC5H0LHC,8B4H1LwCD;K;;;;;sBC6C1DE;;iBACMA;iBAAiBA;MAAbA,gCAAmBA;QACzBA,sBAAUA,mCAAqCA,uCACjCA;WACDA,wBAAeA;QAC5BA,sBAAUA,0BAAoBA,+CAA2BA;;iBAChDA;QAAeA,MAAVA;UACdA,sBAAUA,gDAAsCA;;IAGpDA,C;;;;;;;;;;;;iBnF3FWC;MAAWA,oCAAQA;K;sBAmBvBC;mBAZgBA;MAarBA;QAAkBA,WApBEA,yBAsBtBA;MADEA,qBAAqBA,0BArBDA,iCAsBtBA;K;gBAHOC;;K;;;;EoFXcC;mBAAbA;MAAaA,wBAAMA,eAASA;K;gBAC5BC;MAAUA;;MAAIA;MAASA;MAAbA,YAAmBA,iBAAMA;K;qBA2BpCC;MAEgBA;+BAAMA;;wBAAKA;MAAeA,2DAAMA;MACjDA;QAAmDA;gCvD8ZlCA,iBAAQA;;;MuD7ZZA;MAEDA;mBjK4XEA;;MiKtXlBA,sCACFA;K;eAbOC;;K;uBAeAC;MACIA;;MAAkCA;QAAaA,SAE1DA;M1EYYC,0BAAmBA,qBAAcA,kBAAWA,kBAAMA;;;QAG1BA;QAApBA,uBAA0BA,yBACVA;QACIA;QAAIA;QACRA;QACVA,sBAAoBA;QAL5BA,kCAGEA,sBAGQA,8BAAqBA,4BAC5BA,kBACAA;;;MAvBLD,4CADAA,wCADAA;M0EEVA,O1EmHFC,kCACyBA,oBAAMA,cAAcA,kBAAIA,YAITA,cAAJA,kBAAIA,WAAgBA,anG8XxDC,wB6Ktf6CF,aAC7CA;K;SAEcG;MAAEA;oBACmDA;MAA/DA,OAAMA,+BAAiBA,iBAAMA,OAASA,sBAASA,eAAIA,OAASA,gBAAGA;K;kBAE3DC;MAAYA;;MAAMA;MAAiBA;MAAvBA,iBAA2BA,mBAASA;K;gBAEjDC;MAAcA;mB7KFGA,oD6KEmBA,2CAAUA,uCAAMA,uBAAOA;K;;;;iB7E3DvDC;MAAWA,oBAAQA;K;;;wBtCyMxBC;mBAEAA;;ajEsMNl/C;2EkBrJ4Ck/C,O+CjD3BA;yBjExCgCA,wEAAMA,OiEyCbA;MpD2NrBA,iDAASA,iBAONA;QoDnNpBA,OA9CJA,YAA6CA,yBA8CxBA,sBAAcA,yEAInCA;MADEA,OAjDFA,YAA6CA,sDAkD7CA;K;eAMMC;mBAAuBA;;MAAVA,OCTnBA,YACmBA,yBlEgOnBC,0DkB9NwCD,O+CMGA,gCjEwN3CC,sDmE9YAr8C,8BFsLoEo8C;K;gBAE7DE;mBAESA;;;MAQdA,OjEgKFr/C,qDkBrJ4Cq/C,O+CXxBA,6BjEgKpBr/C,kDkBrJ4Cq/C,O+CnBjBA,kCjEwK3Br/C,yCiEpKKq/C,8BAAaA,mCjEoKlBr/C,4CiE5JKq/C,iEACLA;K;;;;;;;YAhKkBC;MACdA;;QACSA;QAAPA,SAMHA;;QAPCA;QAEEA;QAEKA,C1C8LgBA;Q0C7LrBA,WAEHA;;K;gBAReC;;K;;;YA4CKC;MAIFA;iBAAbA;yCAAMA,iBAAaA;M/C0IdA,gC+C1I0BA,kB/C0I1BA;M+CzIkBA,iCAAPA,iBAAaA;MAChBA,2BCoFrBA,YACmBA,2CC9KnBz8C,0BACqBy8C;MFwFsBA;MAAtBA,+B/CwIRA;M+CxITA,OAqCJA,YAA6CA,0CApC1CA;K;;;EAe8BC;YAAVA;MAAMA,2BAAgBA,0BAAiBA;K;;;;YAY1BC;MAA6BA;MAAlBA,OCpC/CA,YA6FmBl7C,yBA7FgBk7C,uCCjFnC38C,+BFqHuE28C;K;;;EAKxBA;YAAfA;MAAWA,6BAAwBA,8BAAMA;K;;;EAkC7CC;YAAXA;MAAWA,iCAAMA,uBAAWA,gBAAkBA,OAAMA;K;;;;YAC3BA;MAElCA;MAAMA,sBAAOA;QAAYA,WAQ9BA;MAPWA,sB/CiXMA;Q+CjXUA,YAO3BA;MADqBA,SADfA;QAAOA,YAEbA;MADCA,oCAAaA,oBAAcA,kBAC5BA;K;;;EAemDC;YAAXA;MAAWA,iCAAMA,YAAMA;K;;;;YAIvCC;MAChBA,mCAAMA;;;MAAbA,OjEuKJ7/C,kDkBrJ4C6/C,O+CjB/BA,mCjEsKb7/C,yCiErKS6/C,8BAAaA,+BACnBA;K;;;;YAFUC;MAAWA;aAAMA,yBAASA,OAAMA;K;;;;YAMzBD;MACTA,mCAAMA;;MAAbA,OjE+JJ7/C,qDkBrJ4C6/C,O+CVhBA,8CjE+J5B7/C,4CiE7JO6/C,SACJA;K;;;;YAHyBC;MACZA;MAAVA,OAAgBA,8CAAkBA,mBAAmBA,8BACtDA;K;;;E8DvKkBC;gBAAdA;MAAUA,uCAAoBA;K;iBAO5BC;mBACLA;MAAIA;QAAkBA,iBAE5BA;MADEA,OF6WqBA,iBAAQA,eE5W/BA;K;kBAIWC;mBACLA;MAAIA;QAAqBA,WAE/BA;MADEA,OAA2BA,4BAAhBA,gBAAKA,WAClBA;K;kBAGWC;;kBACLA;MAAJA;QAAkBA,OAAOA,mBAG3BA;gBAFMA;MAAJA;QAAoBA,OAASA,iCAASA,OAExCA;MADEA,OAASA,iCAASA,gBAAMA,OAC1BA;K;gBAkMOC;MAAcA,OAAEA,wCAAaA,gBAAOA;K;;;;;;;;;;;;;;;YAjLyBC;;iBAG1DA;MAAJA;QACEA,OA2KRA,YA3K6BA,6DAmBxBA;MAhBaA,0BAASA;MACrBA;QAAmBA,OCtHzBA,oBAVoBv0C,iDD+Ifu0C;gBpH8C6CvkC;;6BAAMA;;MoHxDlCukC;QADEA;M5G/EfA;;MRwIyCvkC;6BAAMA;MoHtDpCukC;MpHsD8BvkC;6BAAMA;MoHpDzBukC;wBAEPA;MAAiBA,yCAAMA;MAGzCA,OAyJNA,gCA1JyCA,yBAAMA,mCAE1CA;K;;;;YAG+DC;MAClDA;iBAAoBA;kCAAXA;MACrBA;QAAmBA,OC1IzBA,oBAVoBx0C,8CD0Lfw0C;MAlCcA;gBpHqC+BxkC;;;6BAAMA;aAANA;MoHlB5CwkC;;UAMWA;Q5G5HRA;;Q4G0HDA,OAAOA,c5G1HNA,8D4GqIJA;;QpHG6CxkC;+BAAMA;QoHLhDwkC,OAAOA,sBAEVA;;K;;;;YAlCCC;MACkBA;;;aAChBA;sBpHmC0CzkC;;+BAAMA;sBoHjCPykC;QAA3BA;;MAGdA;QACEA,OAuIVA,YAvI+BA,4CAQzBA;MALiBA,mCAAeA;MAC9BA;QAAsBA,OC1J9BA,oBAVoBz0C,kDDoKmCy0C,OAIjDA;mBpHqB4CzkC;;6BAAMA;MoHvB/BykC;MpHuByBzkC;6BAAMA;MoHvBGykC;MpHuBTzkC;6BAAMA;MoHvBhDykC,OAiIRA,oBAhIgBA,yCACVA;K;;;;YA8BmEC;MACvDA;iBAA+BA;6CAAXA;MAChCA;QAAmBA,OC9LzBA,oBAVoB10C,iDD+Nf00C;gBpHlC6C1kC;;6BAAMA;MoHcxC0kC;;MpHdkC1kC;6BAAMA;aAANA;MoHiB5C0kC;QpHjB4C1kC;+BAAMA;QoHoB5B0kC;QADpBA,yBACQA,4CAAqCA;QAC7CA;UAISA;2DAAoBA;;QAQKA;MpHjCQ1kC;6BAAMA;aAANA;MoH8BL0kC;MpH9BK1kC;6BAAMA;MoH0GxD0kC,OpH1GkD1kC;MoHiC5C0kC,gEADoDA,sCAErDA;K;;;;YAcqEC;MACxDA;iBAA0BA;wCAAXA;MAC3BA;QACEA,sBAAUA,6EACiDA;gBpHpDjB3kC;;6BAAMA;aAANA;;QJ8WlD4kC;QyC8sFsBC;QAapBA;QACAA,uCzCztFgBD,UAAUA;;QyCguFxBC,2BAAgBA,WAAYA,CATjBA;mBzC3rF+BD;QyC8pF9CA,qEA57FcD;;Q+ErDEA;MAGFA;QF+JOA;QAsBGA,iBA7StBA,iBD40BqBG,ECrjBFH,qBDqjBoBG;;MjHjxBS9kC;6BAAMA;aAANA;MoHiEH2kC;MpHjEG3kC;6BAAMA;aAANA;MoHkED2kC;MpHlEC3kC;6BAAMA;MoHmElD2kC,OAuCNA,iCAA6CA,IAtCxCA;K;;;;gBnBtPKI;MACJA;;QAAgBA,6BAASA;MAC7BA,YAAOA,mBACTA;K;gBAEgBC;MAAUA,yBAAOA,YAAMA;K;wBAEjCC;MACFA,OAVJA,gBAUkBA,4FAAiDA;K;eAC7DC;MAAaA,O5BbnBA,gB4BaiCA,sCAAuBA;K;gBACjDC;MAAcA,uCAAiBA;K;4BAdhCC;;K;;;;EAYkBC;YAANA;MAAMA,+BAAOA,uBAAWA,gBAAkBA,OAAMA;K;;;EAC3BC;YAANA;MAAMA,+BAAOA,WAASA;K;;;;4B5BX7CC;MACJA;;QAAgBA,6BAASA;MAC7BA,YAAOA,mBACTA;K;gBAEgBC;MAAUA,qCAAOA,YAAMA;K;kBACxBC;MAAYA,qCAAOA,cAAQA;K;wBAGpCC;MACFA,OAZJA,gBAYkBA,4FAAiDA;K;gBAC5DC;MAAcA,mDAAiBA;K;4BAfhCC;;K;;;;EAckBC;YAANA;MAAMA,2CAAOA,uBAAWA,gBAAkBA,OAAMA;K;;;;gB2B8D5DC;MACJA;;MAAUA;QAAUA,YAkBtBA;;QAjBuBA;UAArBA;;;;MAEeA;;uBAAkBA;MACjCA;;QAIYA;UAAUA,O1CqFxBA,YAA6CA,yB0CrFJA,qDAUzCA;QATIA,OClFJA,gBDkFyBA,kDASzBA;;QAFIA,OAgJJA,YAAuDA,oBArJzCA,wBAERA,S3BxFNA,gB2BwF4BA,2EAGUA,WAEtCA;K;qDAIgBC;MAEdA;wBAAIA;MA1E4BA,wBAAPA,CpF2PAC,yBoF3PQD;QA0ELA,OAAOA,yCAGrCA;MA6EcA;MA9ELA,SA8E+BA;MA9EtCA,0CAAqCA,gEAsIvCt5C,YAAuDA,qCArIvDs5C;K;mDALgBE;;K;0DASQC;MAEtBA;qDAAIA;MAnF4BA,wBAAPA,CpF2PAF,yBoF3PQE;QAmFLA,OAAOA,kDAKrCA;MAkEcA;MArELA,SAqE+BA;MArEtCA,+CAA0CA,qEA6H5Cz5C,YAAuDA,6CA1HvDy5C;K;wDAPwBC;;K;2DAWMC;MAE5BA;MAAIA;MA9F4BA,wBAAPA,CpF2PAJ,yBoF3PQI;QA8FLA,OAAOA,yCAAoCA,mFAMzEA;MAsDcA;MAzDLA,SAyD+BA;MAzDtCA,gDAA2CA,sEAiH7C35C,YAAuDA,qDA9GvD25C;K;yDAR8BC;;K;gDAwCnBC;MAETA;MAAwDA;MAtIxBA,WAAPA,CpF2PAN,yBoF3PQM;QAsIlBA,OAAOA,gDAWxBA;MAREA;QAiBYA;kBAA0BA;QAwDxC75C,yBAAuDA,4BAxEvB65C;;kBAExBA;;UAcMA;oBAA0BA;UAdHA,4BAsErC75C,YAAuDA;;;MAnEpC65C;MACjBA,4BpF7IFA,gDoF8IAA;K;wCAiBEC;MACIA;;0BAAeA;WACnBA;;QAESA;QAAPA,SAUJA;;QAXEA;QAEEA;kBAIAA;QAAQA;QAARA;;QACAA;;QAEAA;;IAEJA,C;qBAIMC;MACOA;M3B9MbA;M2BgNEA,uBAAqBA,6DADOA,wBAS9BA;K;oBAIOC;MACMA;gBACCA,yBAAKA;MACjBA,6BAA4BA,8CAC9BA;K;sBApLMC;;K;;EAwC6BC;YAAVA;MAAMA,2BAAgBA,iCAAiBA;K;;;EAI1BA;YAAVA;MAAMA,2BAAgBA,8BAAaA,WAAUA;K;;;;YAalCC;;MAAMA,2DAAKA,SAAGA,eAAKA;K;gBAAnBC;;K;;;YASKC;MACjCA;;MAAPA,YAAOA,0CAAKA,qGAAcA,UAC3BA;K;gBAFyCC;;K;;EACtBC;YAANA;MAAMA,yBAAEA,KAAIA;K;gBAAZC;;K;;;YAW6BC;MAClCA;;MAAPA,YAAOA,0CAAKA,+HAAqBA,UAClCA;K;gBAF0CC;;K;;;YAC7BC;;MAAMA,0CAAEA,YAAMA,OAAKA;K;gBAAnBC;;K;;;YAqFOC;MACRA,yCAAaA;aACRA,yBAGOA;wBAAYA;;wBAAMA;MAAzCA,OzCEJA,YACmBA,yBhDmDNA,4FiDjObpgD,8BwC6KGogD;K;;;;eAuBGC;MACeA;;MAEnBA;QACEA,mCAAeA;Q1C1EnBA,W0C2EgBA;;MAEdA,mB1C7E2CA,6C0C8E7CA;K;;;wBzCSMC;MACJA;;MAEcA,MAAZA;MAkBqBA;MhDoOOA,cgDnOZA,uCoEzCpBC,kFtI2EApkD,uBAEyBA,mBAFzBA,6CkElCEmkD;elEuCeA;oEkEtCkBA;UAC7BA;0BhDoScA,wCgDnSiBA,wBAAoBA;UACnDA,mC6DONA,Y7DN+BA,cAAWA,eAAYA,iBAAcA;;MlEkHpErjD,gDkBrJ4CqjD,kCgDwCdA,gFAIvBA;mBAEWA,qCAAcA,wBAAoBA;QAC9CA;MAIJA,OAnFFA,YACmBA,yBoEoBnBC,sCpH4QgCD,gCoH5QhCC,mDnElMAvgD,4BDgQsDsgD,SC/PjCA,cDgQrBA;K;gBAGOE;mBAGDA;;;MAGJA,OlEwFFvjD,qDkBrJ4CujD,OgD6DxBA,6BlEwFpBvjD,kDkBrJ4CujD,OgD0D3BA,kClE2FjBvjD,yCkE3FmDujD,8BAAaA,mClE2FhEvjD,4CkErFKujD,SACLA;K;;;;;;;;;;YAlPuBC;MAGIA,aAANA;;MhDkMRA,gCgDlM0BA,kBhDkM1BA;MgDjMWA;MADpBA,OA8IJA,YACmBA,2CC9KnBzgD,0BACqBygD,cDgClBA;K;;;EAiB8BC;YAAVA;MAAMA,2BAAgBA,yBAAiBA;K;;;EAuCrCC;YAAdA;MAAUA,6BAAkBA,6BAAKA;K;;;EAoBRC;YAAXA;MAAUA,yBAACA,8BAAgBA,sBAAaA;K;;;EAChCA;YAAdA;MAAUA,6BAAkBA,6BAAKA;K;;;EAQrBC;YAAVA;MAAUA,+CAAeA;K;;;EACbA;YAAdA;MAAUA,6BAAkBA,6BAAKA;K;;;;YAe/BC;MAAUA;iBAAKA,yCAAqCA;K;;;EACxCA;YAAdA;MAAUA,kCAAuBA,6BAAKA;K;;;EAiCrBC;YAAXA;MAAUA,yBAACA,sCAAwBA;K;;;EACvBA;YAAdA;MAAUA,mCAAwBA,6BAAKA;K;;;;YA+C9CC;gCACNA;QAAqBA,WAc1BA;MAZWA;QAAQA,WAYnBA;MAXWA;QAA0BA,WAWrCA;MAFYA;QAA4BA,YAExCA;MADCA,OAAaA,wBACdA;K;;;;YAcyBA;MACxBA;MAAIA;qEAA2BA;QAAkBA,YAGlDA;MAFqBA;MAAmBA;M6DD7CA,E7DC0BA;MACpBA,mBAAqBA,Y/CpPlBA,sD+CoPoDA,mBACxDA;K;;;;YAcYC;MAAWA;aAAMA,yBAASA,OAAMA;K;;;;YAG7BA;MACZA;MAAiCA;QAATA,iCAE7BA;MADCA,OAAgBA,8CAAkBA,mBAAmBA,8BACtDA;K;;;;gB8DlTIC;MAAcA,kBAAMA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBrEPbj+C;mBAAUA;M/BuyBxBzO,E+BvyB0CyO;MAAlBA,mC/BgdIA,oBAuV5BzO,gC+BvyBgDyO;K;cAG9Bk+C;MAAQA,iBAAKA;K;wCAgB/Bj4C;MAE0EA;MAAxEA,gBA4EFA,uCrC1EIrK,sBAsLJD,eCyE2B3M,yFoCrL3BiX;MAnEEA,4BAAoBA,0CACNA;IAYhBA,C;2BAMKk4C;UACHA;mBACIA;MAAJA;QAA2BA;MAC3BA;IACFA,C;eAjDkBC;;K;2BAOEC;;K;uBAGEC;;K;;;YAiBNC;;iBAGJA;;QAAeA,MAOpBA;sBALiBA;aAAmBA;MAAnCA,qBAAgBA,2BAAqCA,gBACJA,qCAAlBA;IAIhCA,C;;;;YAJkDC;mBAC/CA;;MACAA;IACDA,C;;;;cA4BQC;MAAQA,0BAAeA,OAAMA;K;WAiCzCC;MACHA;MAMWA;eANPA;QAASA,sBAAMA;eAbIA;QAerBA,sBAAMA;eAEJA;QAAeA,MAGrBA;gBADEA;M/BuuBAA,2BAAYA;I+BtuBdA,C;gBAGKC;MACHA;MAMiBA;eANbA;QAASA,sBAAMA;eAxBIA;QA0BrBA,sBAAMA;eAEJA;QAAeA,MAGrBA;MADEA;IACFA,C;gBARKC;;K;iBAcAC;MACHA;MACyBA;eADrBA;Q/BwtBJA,K+BvtBEA,O/ButBFA;Q+BttBEA,MAYJA;;MATEA;MAGAA;MACAA;M/BktBgBA,K+B9sBhBA,O/B8sBgBA,2B+B9sBDA,aAAWA;IAC5BA,C;iBAfKC;;K;iBAkBQC;MACXA;qCAOyBA;eAPrBA;QAASA,sBAAMA;eAxDIA;QA0DrBA,sBAAMA;eAEJA;QrC0DN/uD,oBCuE2BC;QDtEzBA;QqC3DmB8uD,SASrBA;;MrC5HI5a,0BA2KJxoC,eCyE2B3M;WoC/HzB+vD;gBACuCA;MAAvCA,iCAAyBA,+BAAqBA,gBACMA,mBAAvCA;MACbA,OAA2BA,KAApBA,oBAAoBA,iBAAYA,0DAIzCA;K;aAGaC;MACXA;eAzEuBA;QA0ErBA,sBAAMA;eAGJA;QAASA,YAlGUA,eAAeA,OA2GxCA;WAREA;gBAEKA;QACHA;QACAA,gC/B+qBcA,K+B/qBUA,O/B+qBVA;;M+B5qBhBA,YA1GuBA,eAAeA,OA2GxCA;K;6BAMKC;MACiBA;WAApBA;gBACKA;YrCnKkBA,OA4MA3+C;QqCzCU2+C;gBA9FVA;MAgGvBA;QAAmBA,MAIrBA;MAHEA,qCAA6BA;WAC7BA;MACAA;IACFA,C;gCA3GsBC;;K;;;;;;;YA0DMC;IAAMA,C;;;;YAcOC;mBACrCA;;MACAA;IACDA,C;;;;qBHtCHj6C;;kBAGoBA;MAAlBA;aCvG4BA,OEnBNA;QAAkBA;M/BuyB1C5T,4BAvV4ByO,oBAuV5BzO,iC4B5qB+B4T,gBACzBA,wCACQA;gBAEeA,sBAAOA;QG/HMA;M/BuyB1C5T,K4BxqBE4T,wD5BiV0BnF,oBAuV5BzO,iC4BxqB2C4T,wBAAOA,yCAyBpCA,gCAC4BA,ECtIZA,OEhBJA;IHuJ1BA,C;sBAGkBk6C;MACZA;;MAEJA;UAIEA;UACAA;;;kBAKUA;eAAVA;UACAA;aACAA;;;eAKEA;;QlC8BNrvD,oBCuE2BC;QDtEzBA;QkC9BEovD,OA2EJA,gC3BuxBMA,mDsHv/BNA,2D3FgOAA,gCAtDAA;;MAjBMA;QAGWA;;kBACJA;oCACPA;UACFA,sBAAMA,gDAA0CA;;UAEnCA;UACbA;;;qBAGSA,OGlMWA;QAAkBA;M/BuyB1C9tD,4BAvV4ByO,oBAuV5BzO,iC4BrmB0B8tD,gBACpBA,uDACQA;aAEFA;qBC5KoBA;aE1BRA;MH6PxBA,EG7P0CA;MHqMxCA,uC5BkmBF9tD,4BAvV4ByO,oBAuV5BzO,oC+BpyB0B8tD,QH0P1BA,uCAtDAA;K;sBA1CkBC;;K;qBA8CbC;MACoBA;MAAvBA;gBACiBA;6BACNA,OG3MaA,OH2MFA;gBAElBA;MAAJA;QAAoBA,MAMtBA;MAFSA,EGjNiBA,gBHiNRA;MACCA;QAASA;IAC5BA,C;0BAGKC;MACgBA;MAAZA,KAAPA,sBAAOA;MACPA;WACAA;MAI4BA,eAAKA,qCAAaA,8CAA9CA;QACaA,EADbA,gBG7NwBA,OH8NAA;MAExBA;IACFA,C;;;;YAxGMC;MAAiCA;MAApBA,OAAOA,IAAPA,4BAAOA,6BAAsBA;K;gBAA1CC;;K;;EACcD;YAANA;MAAMA,uCAAmBA;K;;;;YAEWA;MACrCA;;;iBAILA;;QAAyBA,MAmB9BA;MAjB2CA;;MAAzBA,+CAA6BA;MAQlCA;;uBAAOA;MAAnBA;QACmBA,UAANA,OG5ISA,gBH4IaA,UAAPA;;QAMTA,UAANA,OGlJSA;IHoJvBA,C;;;;YAjB+CE;MAI5CA,gCAAgBA;MAChBA,OAAOA,8CACRA;K;gBAN6CC;;K;;;YA6D5CC;;MAAwCA;MAA3BA,OAAOA,EAAPA,sBAAOA,4BAAUA,oBAAmBA;K;gBAAjDC;;K;;;YACQD;MAAMA;0CAAcA,YAASA,UAASA;K;;;;;;;;;4C6H3LnCE;;K;;;e5HUIC;MAASA,kBAAMA;K;gBACnBC;;K;kBAOAC;;K;;;;;;;;;;;gBJ4CRC;MAEAA,sB6GjEWA;M7GiElBA,WAAOA,8BAA4BA,uBACrCA;K;eAEKC;MACHA;MAAWA;aACTA;QACAA,YAKJA;;MAFcA,KAAZA,kBAAYA,yB6G1EMA,4B7G0EqBA,sBAAUA;MACjDA,WACFA;K;6BAEKC;mBACeA;MAAlBA;MAOAA,sBAAMA,mCADKA;IAEbA,C;;;;mB6GxEUC;MAGJA;mDAAaA;aAAoBA;MACrCA,YAAOA,WACTA;K;gBAsCIC;sBA1DgBA;MA8DXA,8BADmBA,OAAOA;QAAQA,WAE3CA;MADEA,4BAAOA,eACTA;K;YAsCKC;MACWA;;MACdA;QACyBA,KACvBA,2BADAA,kCAAYA;MAGdA,cACFA;K;mBASKC;MACHA;MAAIA;QAAeA,MAarBA;MAXEA;QACcA;+BACWA;;UAIjBA;U/ItFDA;;;M+IqJPA,kEA7LkBC;IAmIpBD,C;cAdKE;;K;eA2BAC;MACUA;+CAAsBA,cAjJjBA;WAiJlBA;WACAA,2BAAqBA;MACrBA,iBACFA;K;;;oBoB7JOC;MAAkDA,kBAAWA;K;wBA8CzDC;MAAkBA,UAAGA;K;sBAKrBC;MAAgBA,UAAGA;K;uBAKnBC;MAAiBA,UAAGA;K;0BAUpBC;MAAoBA,UAAGA;K;eAmCvBC;MAASA,UAAGA;K;iBAKZC;MAAWA,UAAGA;K;;;oBC1GlBC;MAAkDA,YAAKA;K;wBA8CnDC;MAAkBA,eAAGA;K;sBAKrBC;MAAgBA,eAAGA;K;uBAKnBC;MAAiBA,eAAGA;K;0BAUpBC;MAAoBA,eAAGA;K;eAmCvBC;MAASA,eAAGA;K;iBAKZC;MAAWA,eAAGA;K;;;Y1F5GkCC;MACrDA;;;oDADqDA;QACrDA;;;;;;cnCcwBC,wCAArBA,0BAAQA;;gBoCsBfD,kBAAMA;cAGDA;cDtCyCA;;cAA1CA;mCAAiDA,gCAAjDA;;;cAAuDA;;;gBACnCA;;;cACeA;cjCkBXE,0CAArBA,0BAAQA;;gBkC6BfF,kBAAMA;cAIRA;;;cDlDCA;;;MAJKA;IAILA,C;;;;YoCS2BG;MAK1BA;MAAOA;kBAAQA;MAA0BA,W7Ey07BlBA;M6Ez07BvBA,2DAA2DA,Oe6CzDC,4CAtBGC,4D5Fq9nB4DF,qB6E3+nBlEA;K;;;;YAAOA;MACmBA;;8BAAdA,kBAAQA;UACSA;;M7EsvlCOA,6C6EtvlCUA;;M7EqvlClCA;aKrvlCiBA,OEnBNA;QAAkBA;M/BuyB1CvwD,4BAvV4ByO,oBAuV5BzO,iCqGhxB0BuwD,gBAAOA,0CAEpBA;IAIZA,C;;;;YAV8CG;MACjBA;MAATA,IAAjBA,WxED0BA,OEhBJA,gBqF0DtBF,4CAtBGC,4DfnB+BC;IACnCA,C;;;;YAE8BA;MAC7BA,+CAAiBA;IAClBA,C;;;;YAAUA;;MACTA,+CAAiBA;MACjBA;IACDA,C;;;;gBEjCIC;MAAcA,mCAA4BA;K;;;;2D3B2H5CC;MAQmBA;;MAMNA;MANhBA;MAE2BA,sEAMhBA;MACXA,6CAAsCA;MACvBA;gBAuEcA;MnB/KhBA;sCmBiIHA,mBAAuBA;MAvBjCA,wCnB1GFA,yCmB0GkDA;IA4BlDA,C;4DAGKC;;;;MAcaA;MANhBA;sCAQWA;MANgBA;gBAOWA;MAAtCA;MACeA;sCACHA;MAAuBA;gBAmBNA;MAnGDA;;MAvEM3gD;MAGGA;MAGAA;MAGdA;MAUSA;;MASLA;MAMIA;MAqCjC2gD,8EjC9EM1gD;;MiCqFF0gD,WAASA,UA6EMA,mDA7EYA,yCAACA;iBAoF9BA;mCAAaA;ctFsXK1nD;MsFpXlB0nD;QACEA,4CAA0BA;IAE9BA,C;aAwCMC;MACmBA;MAAvBA;WAEAA;gBACcA;;MAWdA,OAAOA,cAAMA,kBxG2IfroD,yDkBrJ4CqoD,OsFDfA,sCxGsJ7BroD,gDwG7IKqoD,kBAGWA,YAEAA,uBACGA,+BAFNA,kBAGbA;K;sBAKKC;eACEA;QAAQA,MAEfA;MADEA,sBAAMA;IACRA,C;kBAMOC;MACLA;;;0DADKA;QACLA;;;;;;;;;;;cAAqBA;mCAAMA,uCAANA;;;;;cACrBA;mCAAaA,wHAAbA;;;;cACFA;;;MAFEA;IAEFA,C;mBAGSC;MACiBA,WAS1BA;K;sBAGSC;;kBAGmBA,ctFiRRA;MsFjRlBA;QAAiDA,WAenDA;gBA5G+BA;MnB/KhBA;MmB8QbA,OnB9QFA,oBmB+QgCA,sCAA0BA,wBAAWA,kDAYrEA;K;;;YAjLkDC;MAC1CA;;;oDAD0CA;QAC1CA;;;;;;;gBAAoBA;;kBAEtBA;yIxG8KmBxpD,mBAFzBA,mHwGtKIwpD;;;sBACEA;;;;;;oBnBtB+BA,YAAvBA,2BAAQA;;oBAoDcA;8CA5GatiD,kBAAtBA;sBAyGbsiD,kBAAMA;;sBmB+DhBC,wBAjKwDA,OAAxBA,2BAAQA;;sBnBuGxCD;;;gBmB3BAA;qCAAMA,iFAOUA,yCAnFwBC,mEA4ExCD;;;;;gBAQDA;;;MAtBKA;IAsBLA,C;;;EnBnCkCE;YmB4B7BA;MAAMA,yBnB5BAA,C9DwJavjD,0B8DxJLujD,cmB4BQA,8BAA4BA,qDAG5CA;K;;;;YAH4CC;MAC1BA;;;oDAD0BA;QAC1BA;;;;;;cAAlBA;mCAAMA,gDAANA;;;cACAA;mCAAMA,yCAANA;;;;cACDA;;;MAFmBA;IAEnBA,C;;;;YAmCMC;MAIJA,8BADQA,IAALA;QACSA,MAExBA;MADCA,sBAAMA;IACPA,C;;;;YAkD0BC;MACzBA;MAAoCA;MAAtBA,SAAVA,MA/KUA;MAsLdA,StF6TgBroD,4DmE7hBpBqoD,gBmB2NgBA,uBACAA,qBACDA,wFAIZA;K;;;EAuBwCC;YAAXA;MAAWA,qBAAOA;K;;;;YAuBmBC;MAC1DA;;MAAPA,kBAAgBA,sDASAA,yCAACA,6CAClBA;K;;;EnB5LkCC;YmBkLjBA;MACdA,yBnBnLQA,C9DwJa7jD,0B8DxJL6jD,cmBmLOA,eAAWA,qEAKnCA;K;;;;YALmCC;MAChCA;;;oDADgCA;QAChCA;;;;;;;;;;;;;;;gBAC2BA;;;;;cAAzBA;mCAAMA,qBAAmBA,yBAAzBA;;;;cADFA;;;;;;cAGDA;;;MAHCA;IAGDA,C;;;;mBpC3QDC;;kBACCA;iCAASA;QAA2BA,WAS3CA;MARoBA;MACHA,+BAAKA;MAEbA,YlD8gBWA,sBkD/gBMA,QlD+gBN1oD;QkD/gB0B0oD,WAM9CA;MALEA,qBAAaA,mCAGCA,gBACGA,mBAFNA,OAGbA;K;mBAgBiBC;mBACRA;;apEyUTrpD;oEkBrJ4CqpD,OkDnLjCA,sFpE0FsCA,2DAAMA,OoEzF1CA;MAFXA,OvD2TAA,wDuDvTFA;K;;;;;;;;;EA5BiCC;YAAXA;MAAWA,+BAAkBA,UAASA;K;;;EAyBtCC;YAAXA;MAAWA,4BAASA,+BAAMA;K;;;EACbA;YAAXA;MAAWA,6CAAaA;K;;;;;mBiB9B5BC;MACHA;MAAyCA;M/DnB3C5nD,2BAsLJD,eCyE2B3M;M8DpH3Bw0D,4BAxHgEA,WuD1B1DC,oBvD6FkCC,8CuD7FlCC,gBvD6IyBD,6DAGEA;MAKjBA,wCACGA,+BAA0BA;aAD3CA;MA1HAF,SFUuBI,UETzBJ;K;mBAGKK;;kBACEA;iCAASA;QAA2BA,WAG3CA;MAFEA,OAbFA,qBAaqBA,OAAMA,iCAAuCA,aAClDA,qBAD2CA,aACrDA,UACNA;K;;;;;;;;;+BA+CkBC;MACwBA,sCAArBA,C9DmLMA,6B8DnLEA;MAC3BA;QAAqBA,cAGvBA;MAFEA,sBAAMA;IAERA,C;8BA2FKC;gCA5H4C3jD,kBAAtBA,C9DgNAC,6B8DhNQD,wBAcH2jD,kB/DhEP3jD,OA4MAE;Q+D7BXyjD,sBAAMA;MAClBA;IACFA,C;mCAyBaC;MACAA;;MAAXA;;M/DlBFroD,oBCyE2B3M;M8DkKvBg1D,8B/DjaApoD;;M+D4MFooD,WAASA,uFAKMA,6CAACA;MAEhBA,OAAeA,kBAAoBA,8DAGrCA;K;oBAOEC;MACWA;wBAEKA;MAFhBA;MAEOA;MAAPA,kCAAgCA,4CAACA,mCACnCA;K;iBAMKC;MACHA;eAhMuBA,qBAAYA,UAgMtBA,kCFhPgBC,6BqG8BFD,aAAiBA;QnGkNnBA,MAoB3BA;gBAnBMA;MAAJA;QAA2BA;MAGUA,eApMdA,qBAAYA,UAoMZA,kCFvPIA,MEuPCA,SAASA,kBAAcA;MACnDA;QAAqBA,MAevBA;MANkBA,KAAhBA,sBAAgBA,qCAAkCA,uCARpCA;IAchBA,C;oBAoCKE;MAEHA;;MAAiBA,SAAbA,+BAAkBA;QAAYA,MAgDpCA;MA7CEA,aAASA;gBA7PcA;aAAYA,UAsQPA,kCFtTCA;YsGLNA,aAAiBA;eAAYA;+BA0FxBC,2BAAmBA;;QA1FED;;QpG8T/CA,eAA2BA;iBACHA,aAAiBA;QACzCA,eAA2BA;MAG7BA,+CAA4BA;MAC5BA,aAASA;gBA/QcA,qBAAYA,UAiRrBA;YFpUaA,MEoURA,ShBnTQA;QgBoTzBA;gBAKEA;YnEuOc1pD;QmEtOhB0pD,QAAMA;QnE7GRA;;MmEmHAA;QAAmBA,MAYrBA;WA1SyBA,qBAAYA,UAkStBA,kCF3VgBA,6BE2VVA;MAEnBA,qKAKIA;IACNA,C;oBAlDKE;;K;uBAqDAC;MAC8DA;MAAjEA,uCAA2BA;Y9DvFFv1D;;gB8DvNFu1D,qBAAYA,UAgWjBA;MA7CZA,gBAAQA,oCAsEZA,oB/DjaA3oD,sBAsLJD,+E6DjM6B4oD,MEmZJA,ShBlYIA;IgBmY7BA,C;qBAeaC;MACXA;;;6DADWA;QACXA;;;;;;;;;;;;;;;gBAC2BA;;;;;cAAzBA;mCAAMA,qBAAmBA,kCAAzBA;;;;cADFA;;;;;;cAGFA;;;MAHEA;IAGFA,C;;;YA3S6BC;MACnBA;MAIqCA;MAJ3BA,0BAAKA;MACnBA;QACOA,wBAAOA,QAAIA;;QAEXA,wBAAOA;IAEfA,C;;;;YAJmBC;;MAAMA,yCAAqBA,YAAMA,aAAOA,YAAWA;K;;;;YAwFhEC;MACYA;;;oDADZA;QACYA;;;;;;;;cACnBA;cACAA;mCAAMA,uCAANA;;;cACAA;;cACDA;;;MAJoBA;IAIpBA,C;;;;YAEkCA;MACjCA,4EAAiCA;IAClCA,C;;;;YAyBDC;MhEnFmBC;iBgEoFkCD,QhEpFlCC;;kB8EQED,qB9EDFC;sB8EEsBD,4BAAfA,qB9EKFC;;;M8EA1BD;;;;;;;Md0EIA,0FACFA;K;;;;YAEkDE;mBAChDA;MAA0BA,6BAA1BA,4BAA+BA,QAAIA;IAIpCA,C;;;;YAJoCC;mBAC7BA;YAhNeA,qBAAYA,UAgNlBA,kCFhQYZ,6BqG8BFY,aAAiBA;QnGkOfA,MAE1BA;MADCA,mB9DMqBA,gBCsa3BA,uB6D5akDA,2BAAWA;IACxDA,C;;;;YA2CMC;;eACHA;MAAJA;QACqBA,EAAnBA;;QAEmBA,EAAnBA;IAEHA,C;;;;YAYQA;MAAMA,+CAgIVA;Y/D1bkBC,OA4MA3kD;Q+D8OM0kD;MAhIdA,WAAgCA;K;;;;YAoCjCE;MAmDEA,aAlDdA;wCAAgBA;YAiDdA;QACMA;;QAERA;IARDA,C;;;;YA5CiBC;;;;MAiCEA,8CACVA,mBAGAA,kBAAaA,gCACbA,sBACAA,oBAAWA;MAtCjBA,WAASA,2CAyCDA,yDAAyBA;IAClCA,C;;;;YA1CUC;MACoBA;;;oDADpBA;QACoBA;;;;;;;;;cAC3BA;cAUUA;cAMVA;mCAAMA,yEAANA;;;;;gBAC2BA;;;;0BAESA;;;;;;;gBAElCA,+BqG1YoCA,gCrG0YsBA;gBAC1DA;;gBACAA;;;cAGFA,2BAAkCA;cAEtBA;;;cACbA;;;MA9B4BA;IA8B5BA,C;;;;YAnBkBC;MACIA;;;oDADJA;QACIA;;;;;;;cAAnBA;mCAAMA,wGAANA;;;cACAA;mCAAMA,kBAAWA,0DAAjBA;;;cAxLRA;cACAA,+BAAsBA;;cAyLfA;;;MAHoBA;IAGpBA,C;;;;YAyB8BD;MAA6BA;MAAPA,OAejCA,IAfiCA,MAejCA,mCqG3a5BE,eAA8CA,0BrG4Z2BF;K;;;;iBAsCpEG;;QAEcA,MAGnBA;mBAFMA;Y/DlbmBA,OA4MAjlD;Q+DsOKilD,MAE9BA;MADEA;IACFA,C;;;;WFtaaC;mBAASA;YA2IhBA;QACFA,kBAAMA;kBArEYC,mBRKAC;QQkElBF,kBAAMA;QAGRA;MAEAA;MAnJoBA,SAmBGC,UAiIPD,kCAMaG,UAAUA,OA1JDH;K;;;gBAwGnCI;;iBAjCiBA;aRKAF;QQ6BLE,MAKjBA;M5DlHAA,qC4D+G2CA;MACzCA;MACAA;IACFA,C;gBAOKC;MACHA;gBA/CoBA,mBRKAH;QQ0CLG,MAKjBA;MAJMA;QAAoBA,MAI1BA;WAFEA;MACAA;IACFA,C;eAGKC;mBACCA;YRdeC;QQejBD;;QpD1IJ75B,qBoD8I4B65B;IAE5BA,C;kCAIaL;MACPA;;QACFA,sBAAMA;qBArEYA,mBRKAC;QQkElBD,sBAAMA;WAGRA;MAEAA;MACAA,YAjIuBA,UAiIPA,kCAMaE,UAAUA,OALzCF;K;oCAQaO;;kBAtFSA;aRKAN;QQkFLM,YAJcA,UAAUA,OAgBzCA;MAVEA;MACAA;eAEIA;QACFA;;QAEAA;MAGFA,YAf6BA,UAAUA,OAgBzCA;K;;;;gBuG/KOC;MAAcA,gBAAIA;K;;;qBrHuOpBC;MACeA,8BACPA;;arEuFbrnD;sBamCEqnD,iBbnCFrnD,iDAkEuEqnD,OqExJ5DA,qDxDyHTA;sBK6LkBA;MmDnTlBA;QAAyBA,MAK3BA;MAHEA,sBAAMA,8BAAyBA,+BACxBA;IAETA,C;iCAKKC;MACaA;MAAhBA;MACAA,6BAAmBA;IAIrBA,C;aAOSC;MACGA;8CAA0BA;aACzBA,2BAAoBA;kBACjBA;;kBAASA;gBACHA;;kBAAcA;gBACZA;;kBAAiBA;gBACbA;;kBAAqBA;gBAChCA;;kBAAUA;MACjBA,6BAAiBA;;MACXA,uBAAUA,kBAAkBA,aAC7BA;MAVmBA,+BAWtBA,iBAAUA,cAAcA,SACrBA,6FAAsDA;K;iDAG5DC;MAWeA;MAOtBA;MACAA;MACAA;;uBARiBA;;oBACRA;;0BAIWA;;QAIbA,kBAHaA;MAGpBA,gCANqBA,yBAKLA,0BAJNA,gCAGIA,YAREA,uBAGCA,eAkBnBA;K;yBAhCSC;;K;sBAAAC;;K;8BAAAC;;K;mBAoCAC;;iBACHA;MAAWA;QAASA,WAQ1BA;QANMA;MACJA,gBAAmBA;MAInBA,OAAOA,gCAA4BA,6EACrCA;K;iBAIqBC;MAEfA;MACJA,8BAAmBA;gBAKPA,OkBpQmBA;;uBAAgBA;MAJ5BA;MlBuQZA;MAAPA,wEAEaA,+BAAkBA,wBACrBA,2BACMA,kCACEA,yCACIA,kCACXA,iBACDA,sEAEEA,wBAAWA,uFAGzBA;K;yBAGQC;MACNA;MAAIA,oBAAmBA;QAAMA,aAM/BA;kBAHgBA;MAFPA,2BhDrLiBA;MgDqLxBA,qFAGyBA,uCAE3BA;K;;;YAvPEC;MAAmCA;;eAQzBA;MARgBA,yBAKJA,qBAKVA,cADIA,kBAHLA,aAHDA,YAIMA,sBANJA,cACCA,eAEKA,cAMCA;K;;;;YAY2BC;MAC5CA;MAA8CA;MAAzCA;;aAAkBA;iCAAlBA,oBAAuBA;QAAWA,aAExCA;MADCA,OAAOA,eAAaA,gCACrBA;K;;;ExBkOGC;YwB7I2CA;MAAiBA,sBuF5OlEA,0BILAC,aCgBAC,cAAsCA,e5FkOFF,4BuF5ODA,YvF6OhBA,wEAAoBA;K;;;EAchBG;YAAVA;MAASA,yBAACA,6BAAaA,sCAA6BA;K;;;EAC1CA;YAAZA;MAASA,iBAAGA,kCAAKA;K;;;;YAePC;MACgBA;MAAjCA;MACAA;eADkBA;MAAlBA;MACAA;IACDA,C;;;;YAkBYC;MAA0BA;kCAAUA,QAAMA,qBAAUA;K;;;;YAEpDA;MAA0BA;kCAAUA,QAAMA,qBAAUA;K;;;;YA2C9CC;MACjBA;MAAKA;MACqBA;iCADrBA,gCAA0BA;QAAWA,MAE3CA;;MADYA,EAAXA,cAAWA;IACZA,C;;;;YASkBC;MACSA;MAAgBA;MAA1CA,oDAA0BA,oBAAgBA;IAC3CA,C;;;;YAYsBA;MACRA;MAAqBA;MAA9BA,OxBgBFA,ewBhBWA,yBAAqBA,wEAAqBA;K;;;;gB6DlTpDC;MAAcA,gBAAIA;K;;EApCQC;YAAdA;MAAcA,6CAASA,oBAAcA,WAAUA;K;;;;YAClDA;MAAMA,WAAIA;K;;;;gB3CsBrBC;;oBACiBA;QAAMA,MAO5BA;MALEA,wCACIA;IAINA,C;gBAKKC;MACHA,OAAOA,0CAAgBA,kDAqBzBA;K;oBAIiBC;MAUgBA;yBAAgBA;MAT/CA;QAAmCA,WAErCA;MADEA,OA5DIA,uBA4DsBA,kDAC5BA;K;gBAGOC;MAAcA,oDAAiBA;K;SAGxBC;MAAEA;oBACuCA;MAAnDA,8CAA6BA,4CAAgBA,2BAAMA;K;kBAG/CC;MAAYA,OAAOA,oBAAPA,2BAAeA;K;;EqE9FnCC;YrEoB+BA;MAAMA,iCyEzBrCf,aCgBAC,cAAsCA,mB1ESqBc,aqEnBxBA,UrEmBiCA;K;;;EA0BxDC;YAANA;MAAMA,uDAAgBA,8DAEYA;K;;;EAD9BC;YADkBA;MAClBA,yCAAyBA,wBACzBA,wCAA6BA;K;;;;YAQdC;MACrBA;MAAIA;eAAYA;aAASA;wBAAQA;QAAYA,WAmB9CA;aAlBkCA;6CAAQA;QAAYA,WAkBtDA;aAjB0BA;yBAAGA;QAAYA,WAiBzCA;MAhBCA;;UAEIA,SAAwBA,SAc7BA;;UAZKA,SAAwBA,UAY7BA;;UAVKA,SAAwBA,KAU7BA;;UARKA,SAAwBA,QAQ7BA;;UANKA,e2CpBoBA,4CAAmBA,0B3C0B5CA;;UAJKA,SAAgBA,SAIrBA;;UAFKA,YAELA;;K;;;;gB2BuDIC;MAAcA,gBAAIA;K;;EAxDSC;YAAdA;MAAcA,qCAASA,oBAAcA,WAAUA;K;;;;oCtDnD9DC;;MAGCA;MACAA;MAFJA;YAAoBA;MACpBA;QAAoBA;MACpBA;QAAkBA;IACpBA,C;6BALKC;;K;wBAAAC;;K;gCAaCC;;iBAKeA;;Q+E4BUC;;elD1D7BD;;iBAA2BA;iBAAsBA;UGHjDE,OHGAF,gCkD0DAC;;;QlDzDOD,8CACcA,qBAA2BA;;M7B4BtCA;MACVA;QAAaA,YAMfA;MAJEA,OAAOA,yBAAiBA,+DAI1BA;K;iBAjDIG;;K;eAIAC;;K;;;YAyCsBC;mBAClBA;;MAA0BA,M5B+tCdC;Q4B/tCMD,yBAA6BA,qBAEpDA;MADCA,OAAOA,yBAAuBA,qBAC/BA;K;;;;S6H3CWE;MAAEA;oBACsDA;MAAlEA,uCAAkBA,iBAAgBA,eAAUA,iBAAgBA,OAAMA;K;kBAG9DC;MAAYA,QlLuBWA,gCkLvBXA,elLuBWA,gCkLvBYA,eAAgBA;K;gBAGpDC;mBACDA;kBAAiBA;QAASA,gBAIhCA;kBAHuBA;QAAUA,WAAOA,OAsGnBA,KAnGrBA;eAFMA;MACkBA,YADDA;QAASA,gBAEhCA;MADEA,yCACFA;K;;;gBAuCOC;MAAcA,gBAAIA;K;;;gBA4DlBC;MAAcA,gBAAIA;K;;;;;;gBxFxHlBC;MAAcA,mBAAOA;K;;;;;;YA2DdC;M1Fqed1oD;M0FneE0oD,iCCpEFA;MDsESA,O1FggBqCzoD;M0FhgB5CyoD,8EAEDA;K;;;;YAwDsBA;IAAKA,C;;;;a1BXpBC;MACNA;MAAIA,iBAAQA,uBAAQA,cAARA;QAAuBA,QAAvBA,kBAIdA;gBAHYA;MAAVA;QAA4BA,OAxFxBA,uBA2FNA;eAFMA;MAAJA;kBAAsDA;elDEvBA;;0BAAUA;QkDFnBA,OAzFlBA,clDiEAC,eA0BqCD,2CkDA3CA;;eADwBA;gBAAoBA;MAApBA;wBAAYA;MAAZA;wBAAYA;MAAlCA,OAvFIA,4BAwFNA;K;aAKSE;MACPA;MAAIA,iBAAQA;QAAMA,WAEpBA;eADSA;;iBAAmBA;QlDPKA;0BAAUA;QA1BrCD,oBA0BqCC,+BAAVA;;MkDO/BA,SACFA;K;kBAGQC;MAAYA,QAASA,oBAATA,iBAAoCA,oBAAZA,oBAAoBA;K;SAGlDC;MAAEA;oBAGoBA;MAFhCA,qCACMA,2BAAYA,mBACZA,oBAAeA,YAAWA;K;gBAG7BC;mBACDA;MAAJA;QAAsBA,OAAOA,gBAG/BA;eAFMA;MAAJA;QAAyBA,OAAUA,aAErCA;MADEA,aACFA;K;;;uBhB2BIC;MAEoCA;;;uDrC0ZhC5lD;MqC1ZY4lD;QAAlBA;MAIoBA;gBACHA;MyBpKEA;gBzBuKAA;;MAPZA;MAAPA,6EAEgBA,gDAGFA,oCAA8BA,oCAC3BA,oCAA8BA,mCvDyNjD3vD,uDkBrJ4C2vD,OqCnEXA,kEvDwNjC3vD,8CuDpNO2vD,qBAEPA;K;sBAMIC;MACFA;;;QAAkBA,WAgBpBA;MAdoBA;MACNA,4BAAcA;eAQXA;MACIA;eACHA;MyBjMGA;MzB6LZA;MAAPA,8HAKyBA,aAE3BA;K;oBAGKC;MAIDA;MAHMA,wBAAcA;mBAKbA;a4BzMKA;MRzBhBC,2BAgH4BC,oBAhH5BD,gCpBkOyBD,SAAOA;a4BnMcA;MR/B9CC,2BAgH4BE,oBAhH5BF,gCpB0OmBD,SAAOA;a4BxMmBA;MRlC7CC,2BAgH4BG,oBAhH5BH,gCpBoPqBD,SAAOA;;MAS1BA,WAASA,2EAEMA,yCAACA;IAClBA,C;;;YA/MsCK;MAClCA;MAAuCA;eAAnCA;MAAJA;QAAuBA;;MACfA,IAARA,QCmCsBA,gBCtDM1tD,SEvBNA,gBJ0CL0tD;IAClBA,C;;;;YAI8BA;IAAMA,C;;;;YAELA;MK1CpBC;;;;MAgBVD,WAASA,2BL2BuBA,+JK3BLA,wCAACA,uBAtB5BA,8BAUgBC;ILiHjBD,C;;;;YA1EiCE;;;;MAC9BA,WAASA,kHAqEGA,oDAEUA;IACvBA,C;;;;YAxEUC;MACCA;;;oDADDA;QACCA;;;;;;;;gBAECA;;gBADTA;gBAEEA;kBACAA;;kBAEAA;;;;kBACAA;kBACAA;;kBACAA;;;;cAGOA;gBACPA;;gBAEAA;;qBACcA;gBACdA;;gBAEAA;;;;;;oE3BsYkBrqD,oBAuV5BzO,kC2HzsByC+4D,oCAKEA;chGrBrBD;mCAAYA,gCAAZA;;;;cACPA;cAAPA,eAAcA,OAAPA;;gBgG8GXA,kBAAMA;;;cAIRA;chGhHYA;cAWsBA,uBAAvBA;;6B0H7EKA;c1H8EcA,kCAAYA;;cAKxBA,wCAAkCA,2BAA7BA;cAHFA,uBAI6BA,kBAAzBA,gDACaA,kBAAnBA;;cKjFSA,8BAArBA,0BAAQA,wBLmFmBA,wBAChBA,iCAA2CA,OAA3BA,yCAClBA,iCAAyCA,OAAzBA;cAEFA;mCAAMA,+CAANA;;;;cAGxBA;mCiDMJA,WAASA,8CAAkBA,yCAACA,4DjDNxBA;;;cAGIA;ciC3FWA,oCjC2FiCA;ciC1FzBA,mCAAYA;cACjBA,4BAAeA,oBAAVA;cADtBA,0BAEuBA,kBAAhBA;cjC2FRA,kEAF0BA,oBAAhBA,6BsD7FJA,uEtDsGUA,yCiDPQA;;;cjDQzBA;;;MApESA;IAoETA,C;;;;YA1CmBE;MACZA;;MAAOA,WAAPA;QACeA,IAAjBA,WEhEkBA,OEhBJA;QJiFdA,MAMHA;;MAHCA,eAAcA,OAAPA;MG3EaA,mCAArBA,CnC0QkBC,yBmC1QVD;MH4E+CA,yBAAhBA;MAClCA,mCAAqCA,iBAAdA;aADPA;MGnDxBA;QACFA;UAAqBA;uD2HIUE;cAH7BA;UAAMA,kBAAMA;UAChBA;QAEAA,wCAAyCA;eACzCA;;yC5BK0BC,S4BLgBD;Q5B7BbE;cA+BnBD;UACRA,kBAAMA;QAERA;;e/FTWH;;UACTA,kBAAMA,+DAAyDA;;UAE/DA;;IHgDKA,C;;;;YAyBQA;MACCA,gBACJA;IACLA,C;;;;YADKK;mBAAuBA;iBAA0BA;MA8CrDA,ECnFgBC,gBCtDMruD,SEvBNA,gBJgKPouD,mEALnBA,6BAzC4CA,YAgDhCA,wBAAgCA,QAAOA;MAhD/BA,WAAmDA;K;;;;YAMrDP;MACVA,gCAAWA,iBAAgBA,gDAAYA;IACxCA,C;;;;YAyD0BS;MAC3BA;MAAOA;eACDA;eAAgBA;MAAhBA,gBAAgCA;MADtCA,wEAEMA,wBAA8BA,0BACrCA;K;;;;YAYuBC;MACjBA;;MAAPA,eAAcA,OAAPA;gBACPA;wBAAaA,2BAAUA,cAAgBA,UACnCA,+BAA0CA,iBAAnBA;IAC5BA,C;;;;YAaqBC;MACpBA,eAAcA,OAAPA;M4BnLaA,I5BoLpBA;IACDA,C;;;;YAE6BA;MAK1BA;MAFUA;;MAFJA,IAARA,QAAQA,eAASA,+EAECA,OAAOA,sBACPA,OAAOA;IAE1BA,C;;;;YAEuBA;MAOpBA;MAHIA;qBAAWA;MKrNSA,mCAArBA,CrCmQkBtuD,yBqCnQVsuD;qBLsNiDA;eAC3CA,SAASA;MALpBA,IAARA,QAAQA,eAASA,kEAEUA,gCAEDA,oC4B7NDA,M5B8NQA,ScjNZA;IdmNtBA,C;;;;YAEyBA;MACxBA;MAAyCA;eAArCA;MAAJA;QAAwBA,qBAAyBA;;MACzCA,IAARA,QAAQA,eAASA,kFAESA,KAAKA,sBACbA;IAEnBA,C;;;;YAEQA;M4BrNWA,I5BsNlBA,2EAAeA,SAAKA;IACrBA,C;;;;YADqBC;MAAeA;MAARA,mBAAQA,eAASA,qEAAqBA;K;;;;kBGlOvDC;;iBACRA;;QACFA,OAAOA,mBASXA;;iBARaA;;UACTA,sBAAMA;;UAENA;U4F8DAC;UG3BAC;U4BnCJF,yC/BnBIG,0DGNAC;U4B0BFC,iDtFoGFC;UrCnGIN;UACAA,gB2HvB4BA,mC3HyBhCA;;;K;;;gBiI1BQO;MnDAkBA,amDARA,oBnDAAA;MmDAAA,wBAAYA;K;kBAGdC;M3L+ShBvnD,a2L/S4BunD;oC3LiTHvnD,mBAFzBA,4C2L/S0CunD;K;aAanCC;MAAWA;2BAAaA;K;;;;;YvGnBaC;MACnCA,yBAAKA,sBAAMA,eAAuBA,IAAVA;IAChCA,C;;;;YAAOA;MCwH6BA,2BAAvBA,C9DwJavsD,0B8DxJLusD;MA4EpBA;MACAA,+BAAsBA;MDrMTA,WAA2CA;K;;;;YesCpBC;M0BkBrBA,yBAAQA;M1BjBFA;QAAKA,QAAuBA,0BAIpDA;MAHwBA;QAASA,QAAuBA,gCAGxDA;MAFKA,iCAAgCA,mBAARA;QAAqBA,QAAuBA,oBAEzEA;MADCA,QAAuBA,4BACxBA;K;;;;qB3ByBYC;MlDqIX97D,wBCuE2BC;MDtEzBA;MkDrIE67D,SAAiEA;K;iBAOpDC;MAEMA;;;yDAFNA;QAEMA;;;;;;cADrBA;mCAAaA,cAAaA,6NAA1BA;;;;gBAEuBA;;;;;cAChBA,iDAAUA;;cAAjBA;;;;cAGFA;;;MALuBA;IAKvBA,C;mBAgEkBC;MACCA;MAAfA,OO9HJA,e7DijBsBC,mCsDnbJD,2BAUUA,aM1JLE,kCN8JMF,cM9JNG,kCNkKKH,aMlKLI,6B6GGvBJ,kBnDTAK,gChE4KkDL,8JArB3BA;K;6CAkDvBvuD;MAISA,IAAPA,OChM4BA,yBAAWA,iBDgMpBA,wCAIhBA,aAAWA;IAGhBA,C;WAwBa6uD;MACXA;eAAIA;QACFA,sBAAMA;WAERA;;gBAGeA;M5CgjBjB/6D,2CAvV4B+6D,oBAuV5B/6D,iC4ChjByC+6D,gBAAOA,iCA6BnCA;QA7BXA;MAmCAA;MAEAA,OAAOA,mBACTA;K;iBAQOC;;MAEaA;IA8CpBA,C;2BAhDOA;MAEaA;;;yDAFbA;QAEaA;;;;;;;;cAAlBA;;;;;;;csCtRqBA;;ctC2RnBA;;;cACuBA;cAErBA;mCAAMA,sGAANA;;;;0CiH3MwBA,2BAAmBA;;;;cjH+M7CA;;;;ctDhPiCC,uCAqgB7BzoD;;;;;;;;gBsD7QFwoD;;;;;gBACeA;;;;;;cAEbA;;;cACEA;mCAAMA,6EAANA;;;;cADFA;;;;;cAE4CA;;;cAArCA;;;cACLA;mCAAMA,+CAAuCA,6CAA7CA;;;;cADKA;;;;cAGYA;;;;cazRoBA;;yEAmEP7I,+CAgDTA,+BAGEA;cFtFLvkD;;c5EyWRA;;;cwBjZpBlJ;0FsDoImBytD,+BAA0BA,0BFzF1BvkD;;;;cXuPTotD;mCAAMA,6EAANA;;;;;;;;;cATJA;;;;;;;;;cAiBFA;;;cACuBA;cAErBA;mCAAMA,uGAANA;;;;cACAA;;;cAAaA;mCW3SKA,iGX2SLA;;;;;;;;;;;;;;;;;cAGfA;;;;;;;;cA9CGA;;;;;;MAEaA;IAFbA,C;yCAsDAE;MAEYA;IAoCnBA,C;4BAtCOC;;K;8BAAAD;MAEYA;;;iFAFZA;QAEYA;;;;;;;cAAjBA;mCAAMA,0EAANA;;;;cgDvSAA,sBAAKA;chD6SOA;;;;wDGzPc1C,oBAhH5BD,gCH4WwC2C;;cAWtCA;cAEAA;cAIAA;mCAAaA,0BAAmBA,+EAAhCA;;;cAIAA;mCAAMA,8GAANA;;;;cAEKA;;gBAA+BA;;;cACpCA;mCAAMA,iEgHxRWA,+HhHwRjBA;;;cAEAA;;;cArCKA;;;MAEYA;IAFZA,C;uBA4CAE;MAEYA;IAmBnBA,C;iCArBOA;MAEYA;;;+DAFZA;QAEYA;;;;;;;cAAjBA;mCAAMA,wDAANA;;;;;cAKIA;;cAaGA;mCAAMA,oGAANA;;;cAAPA;;;;;;cApBKA;;;MAEYA;IAFZA,C;qBAiGFC;MACuBA;MAA1BA;MACAA;oBAEkCA;a2CtdpBA;M3CsddA,mCGlfF9C,2BAgH4B+C,oBAhH5B/C;gBHmfE8C;;MM/cAA,iEAAUA,ORiDZE,4B6CtD4DF;gB3Cqd1DA;MMhdAA,iEAAUA,ORiDZG,4B6CnD6DH;gB3Cmd3DA;MMjdAA,iEAAUA,ORiDZI,4B6ChD4DJ;I3Cid5DA,C;;;YA1ZyBK;MACnBA,wCAASA,kCWxEgBA;eXwEVA;MAAfA,gBiHawBA,2BAAmBA,sBjHZ5BA,aAAiBA,gBAAQA;K;;;;YAyHzBC;MACUA;;eAA3BA;;MACAA;YACAA;;IACDA,C;;;;YAAaA;IAEbA,C;;;;YAgC6CC;MACrBA;MAANA;eAAjBA;;MACAA;MAEAA,mBAAWA,qCAwBVA;IACFA,C;;;EAxBOC;YADKA;MACLA;IAuBLA,C;oCAxBUC;MACLA;;;oDADKA;QACLA;;;;;;;;cAAeD;mCAAMA,yCAANA;;;;;cAWJA;;cAGfA;cAEAA;mCAAMA,0GAANA;;;;cAjBSC;;;MACLA;IADKA,C;;;;YAiBmBC;MAC1BA;;;oDAD0BA;QAC1BA;;;;;;;;;gBAAaA;;;;;cACbA;mCAAMA,yGAAwDA,8DAA9DA;;;;c2CnINA;cACAA;;;crD0NgCA;;gBAH9BA,kBAAMA;;cAGRA;;;cUpFKA;;;MALCA;IAKDA,C;;;EADiCC;YAANA;MAAMA,wCAAkBA;K;;;;YAG7CJ;mBACTA;uDAAsBA;MACtBA;MACAA;MACAA;IACDA,C;;;;YA6E4CK;MAC3CA;MAAIA,6BAAMA,aAAiBA;QAAUA,MAOtCA;eANCA;;0BAAeA;M4D3SCA,iC5D8SOA,iBxC46BP3E;ewC36BF2E;QgDtThBA,sBAAKA,4BhDsT4BA;;IAEhCA,C;;;;YAAUA;MACTA,yDAAsBA;IACvBA,C;;;;YAWYA;IAAKA,C;;;;YAegCC;IAAKA,C;;;;YAIUA;;;MAC/DA,0BAA0BA;MAC1BA,0BAA0BA;eAEtBA,QAAQA,SAASA;MAArBA;QACEA,2BkHjZNA,eAA6CA;MlHqZzCA,0BAA0BA;MACfA,EAAXA,WAAWA;IACZA,C;;;;YAAEA;IAAKA,C;;;;;;2B2C/TV/pD;MAC+BA;MAvD/BA,KAuDEA;MAEiBA,KAAjBA,iB1C5E4BA,yBAAWA,yB0C4EVA,0CAEjBA;IACdA,C;mCASKgqD;;kBACCA;axCIgBA;QwCHlBA,sBAAMA;mBhCrGSA;MgCwGjBA,iBhCxG6BA,sCgCwGJA;MACzBA,oBAAOA;WAEPA;ahC9FcA;MRzBhB5D,2BAgH4BC,oBAhH5BD,gCwCyHyB4D,SAAOA;MAgB9BA;MAEAA,kChCuD6B/H,UAAUA;IgCtDzC+H,C;aAUOC;MAAWA,wDAAmBA,8CAM/BA;K;;;YAzDyBC;;IAE5BA,C;;;;YAAWA;IAAMA,C;;;;YAoBYC;MAC5BA;MAAIA;eAAMA,aAAiBA;QAAUA,MAatCA;gBAZCA;;gBAEUA;kBAAiBA;QACzBA,0BAAaA;uBACmBA;kBACjBA;QAAfA;QACAA;sBACSA;kBACGA;QAAZA;QAEAA;;IAEHA,C;;;;YAekCC;MAC/BA;;;oDAD+BA;QAC/BA;;;;;;;;;cACEA;mCyEpFUA,kHzEoFVA;;;;;;;;;;;;;cAEAA;;;;;;;cAEHA;;;;;;MALCA;IAKDA,C;;;;sB0EbAC;MACHA;MAAIA;cAASA;gBACNA;a9CtCaA;M8CsClBA;Q9CrGFA;iBAGEA;UxIkViBC,yBAAWA;iBwIlVTD;UAATA;4BAAOA;UAAPA;4BAAOA;YAAjBA;YACAA;;gB8CqGIA,QrHiC0CA;MgEzKxBA;QqDwIUA,sBAAcA;mB1G5H9CA,kCAAYA;M0GiIZA,8BlH1JJjE,2BAgH4BC,oBAhH5BD,gCkH2JSiE,SAAOA;gBASdA;mB1GrIgCA;aAAYA;M0GqI5CA,YlHpKFjE,2BAgH4BE,oBAhH5BF,gCkHqKOiE,SAAOA;a1GnI+BA;M0GqI3CA,YlHvKFjE,2BAgH4BG,oBAhH5BH,gCkHuKwCiE,SAAOA;IAM/CA,C;sBAGKE;MACHA;eAAUA,aAAiBA;QAAUA,MAOvCA;eAHMA,QrHC4CA;;MgE5KlD5B;MJyDoBxoB;QIzDpBwoB;QqD4KI4B,qBAAcA,oBAA4BA;;IAE9CA,C;0BAGKC;MACHA;kB1GvKiBA,kCAAYA,6B0GuKVA,aAAiBA;QAAUA,MAgBhDA;MAdEA,6BAAcA,2CAAmCA,cAAMA,qBAAQA;gBAG7DA;mBAAeA,SAASA;MAAxBA,aAA0CA,SAASA;MACnDA,MAUJA;K;yBAMKC;MAIHA;MAAIA;MAAJA;QAAqBA,MAevBA;gBAbMA;MAAQA;MpDtLMA;QoDuLhBA;WACKA;QrDhNT9B,iFhE4KkD8B,oBxEyIlDhqD,uBAEyBA,mBAFzBA,oD6LlGwCgqD,kBAAMA,iBAAQA,WAFlDA;UACEA,6BAAcA,uB7LwGHA;Q6LrGbA;;erHrDwBA,aM1JLjC;Q2DkBHiC;UoD+LhBA;;UAEAA;;IAEJA,C;kCAOKC;;kBAECA;erHpEsBA;eM1JLlC;M+G8NFkC,8BAAUA;erHhEFA,cM9JNjC;Q+G+NDiC,8BAAUA;iBrH7DJA,aMlKLhC;U+GgOFgC,8BAAUA;gCACdA;qDAEkBA;;cAFrBA;;YADcA;;UADCA;;QAESA;MAHpCA;QAMEA,MAyCJA;a/G7QuBlC;M+GuOgBkC,KAArCA;arHzE2BA;aM9JNjC;M+GwOkBiC,KAAvCA;arHtE0BA;aMlKLhC;M+GyOgBgC,KAArCA;WACAA;WACAA;MAEAA;QAAoBA;;QtL+S8BA;MwIjd3CA,iBAAuBA,K8CoKfA,yCxKvEIC;MwKyGUD,kCAAVA,2BxKzGAC,4DwK0GcD,6BAANA,2BAAVA,qBxKnGEC,qEwKqEND;a/GpPQlC;gB+GuPRkC;MtL4SEA,csL7SaA;a/GtPPjC;M2DoBAiC;uBoDsONA;e/G1PMjC;QvEmiBNiC,csLvSgBA;;;a/G5PVhC;M2DoBAgC;uBoD6ONA;e/GjQMhC;QvEmiBNgC,csLhSeA;;;MtLgSfA;MsLvRfA;IACFA,C;4BAjDKE;;K;2BAAAC;;K;qBAAAC;;K;oBA6DEC;uBACeA;MAcpBA,S1GtS2BA,M0GwRFA,KAe3BA;K;;EA9J2BC;YAAXA;MAAWA,uCAAeA,WAAUA,0BAAMA;K;;;;YAU5CA;MAA8BA;MAAnBA,2CAASA,gBAAgBA,aAAaA,YAAWA;K;;;;YAE3BA;MACNA;MAC1BA;eADXA;yBAAcA,sBAAaA;oBACRA;iBACPA,WAAoBA;wBAAiBA,oBAAaA;MAC9DA;IACDA,C;;;;EDbgBC;4BAAZA;MAAYA,iCAAmBA,iDAGhCA;K;8BAhFcC;;K;;;YA6EkBC;MACIA;;;oDADJA;QACIA;;;;;;cAApCA;mCAAMA,mEAANA;;;;cAEDA;;;MAFqCA;IAErCA,C;;;;;;eEjJAC;UACHA;MACAA;IACFA,C;cAGKC;mBACGA;MAAQA,kCAARA;QACJA;UvL8iBFA;;IuL3iBFA,C;;;;EjJ6WMC;Y4C9TkBA;MAAgBA,sBAASA,6BAASA,YAAMA,0DAAOA;K;;;;YuB/BrDC;MACZA;;;oDADYA;QACZA;;;;;;cAAkEA;cAClEA;cAAyBA,uBAAsBA,qBAAQA;cACjCA;cauZLA,sBAAQA;gK+D/VDC;4D/E7EhBC;;cvF4LZl/D;csKlKWg/D;c5EHEA;;cpFwyBbG,YA9X4BC,kCA8XhBD,OmKx0BFH;cnK+0BMK;;gBrBpeLC;;;csLjT8BC;;;;cA8BzCA,uClHO0BC,oBAhH5B3F,gCkHyG2C0F,SAAOA;cAIrBA;;cAA3BA,YvK2M0BA,qDuK3MoBA,SAAOA;;;c7EtDvCP;mCAAMA,yDACJA,yCAACA,4EADHA;;;;gBAEDA;;;;;cACbA;cACiBA;;;cAClBA;;;MAfKA;IAeLA,C;;;EAL4CS;YAAdA;MAAMA,uBAAqBA,IAAPA,qCAAWA;K;;;;YZ1C7CC;MACfA,sBAAoBA;IAWrBA,C;;;;YAXqBC;MAClBA;;;oDADkBA;QAClBA;;;;;;cAGYA;;gBAERA;cAEFA,gBAAaA;;cAEhBA;;;MATCA;IASDA,C;;;Ea5B6CD;YAAXA;MAAMA,kCAASA;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wGpFwjBjDE;;K;;;wFNmiBHC;;K;kGAWAC;;K;;kHAwBcC;;K;4HAKQC;;K;8HAKMC;;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6E4B1nC5BC;;K;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8EzC2CWC;aACTA,6CADSA;K;8EAyIPC;aAA6BA,oCAA7BA;K;kGN0tC0BC;aAC1BA,kCAAeA;;;;SADWA;K;8FAKAC;aAC1BA,kCAAeA;;;;SADWA;K;0FAKAC;aAC1BA,kCAAeA,4CADWA;K;wGAKAC;aAC1BA,kCA+N2BA;;;;;;;UAhODA;K;oGAKAC;aAC1BA,kCAAeA,8CADWA;K;kHAKAC;aAC1BA,kCAoO2BA;;;;;;;UArODA;K;kGAKAC;aAC1BA,kCAAeA,gDADWA;K;gHAKAC;aAC1BA,kCAsP2BA;;;;;;UAvPDA;K;4GAKAC;aAC1BA,kCAAeA,kDADWA;K;0HAKAC;aAC1BA,kCA0P2BA;;;;;;UA3PDA;K;gGgB96CRC;aAClBA,0CADkBA;K;8DIsHKC;aACnBA,2BAAmCA,yBADhBA;K;8DD2mCdC;MAAeA;MAAfA;K;kEiBhyBAC;aAAWA,4BAAXA;K;wFC2CUC;a3BgXnBA,0BAASA,oB2BhX+CA,iiBAArCA;K;oElCuLLC;;K;oEASEC;aAAuBA,gDAAvBA;K;sEAkCjBC;;K;sDyCsoGiBC;aAAiBA,iBAAjBA;K;0FiHz2HhBC;aAAmCA,wDAAnCA;K;oEAMAC;aAAwBA,gDAAxBA;K;qEAMAC;aAAwBA,kDAAxBA;K;4DQwEAC;aAAoBA,+CAApBA;K;oDhDzEAC;aAAgBA,4CACmBA,CAAXA,sBAAgBA,WAAIA,gDAAgBA,uBAD5DA;K;wCIqCQC;aAAUA,kBAAqBA,uBAA/BA;K;gCAMAC;aAAMA,kBAAqBA,mBAA3BA;K;wCAOAC;aDzBZC,cACoBA,8BCwBRD;K;gDhE3DOE;a8GHnBA,iBAQyBC,6BACKA,iCACVA,6B9GPDD;K;oDAOAE;agHLnBA,mBAQyBC,mCACKA,qCACVA,6EACQA,8ChHNTD;K;4CAQAE;a+GlBnBA,eAQyBC,6BACKA,+DACVA,2DACQA,6B/GOTD;K;sDAMAE;aAAWA,2BAAXA;K;wC8BNEC;aAAUA,gBAMhCA,QANsBA;K;4CAQbC;aAAuBA,oBAAXA,iBAAZA;K;4CACAC;aAAYA,qBAACA,aAAbA;K;0C1BnBJC;a2EaEA,c3EbFA;K;0C8DNAC;aAAeA,wEAAfA;K;0CAOAC;aACEA,qFADFA;K;sDAIAC;aAAqBA,qDAArBA;K;wDAMAC;aACEA,6EADFA;K;gEAQAC;aAA0BA,0GAA1BA;K;sDAmBAC;aAAqBA,wEAArBA;K;8CAIAC;aAAiBA,kEAAjBA;K;gDAEAC;aAAkBA,8BAAlBA;K;0DAgNSC;aAAiBA,qDAAjBA;K;kEAGAC;aAAqBA,sDAArBA;K;4FpB1OAC;aiCRPA,cjCQOA;K;kDzC1BTC;aAAmBA,gDAAnBA;K;0CAQAC;aAAeA,qCAAfA;K;kDAMAC;aAAmBA,kCAAnBA;K;gEAeAC;aAA0BA,uEAA1BA;K;sDAYAC;aACEA,kEoDvBJxvD,AEmKAG,ArGkKA4G,AUoFA+Y,A8FzUE4oB,KzD1DA8mB;K;sDG9BSC;;aAAiBA,kFAAjBA;K;0EkBZTC;MAA2BA;;;;;;;;MAO/BA;QAP+BA,aAOHA,SAA5BA,IAA6CA;MAC7CA;QAR+BA,aAQAA,SAA/BA,IAAuCA;MARnCA;K;iD3BAAC;agFmBEA,chFnBFA;K;iDFHAA;akFsBEA,clFtBFA;K;sDyCkDgBC;aAAkBA,iBAKtCA,QALoBA;K;qEAWhBrC;aAAwBA,kDAAxBA;K;kFAIAsC;aACFA,sBAAWA,8BAAsBA,sBAD/BA;K;0EWlDSC;MAA2BA;MA4KpBA;;MACHA,uBAAyCA;MACxCA;;MAGLA;MACMA;MAEoBA;MApL1BA,OA6JbA,0BA7JaA;K;;;;;;;;;;;;;;;;;;;;;;;UpG2DDC,AAAAxvE,AAAAC,AAAAI,4BNokGgBvB","x_org_dartlang_dart2js":{"minified_names":{"global":"main_closure,2397,internalBootstrapBrowserTest,535,Closure_fromTearOff,2398,StaticClosure,2399,BoundClosure,2400,Closure_functionCounter,2401,Closure_forwardCallTo,2402,Closure__computeSignatureFunctionNewRti,2403,_checkStringNullable,181,wrapException,42,CyclicInitializationError,2404,toStringWrapper,43,NullThrownError,2405,S,12,argumentErrorValue,40,ArgumentError,395,Error_safeToString,2406,_isBool,168,Error__objectToString,2407,Closure,2408,Primitives_objectTypeName,2409,Primitives__objectTypeNameNewRti,2410,Object,2411,instanceType,145,_rtiToString,184,Primitives__saneNativeClassName,2412,assertHelper,79,_unminifyOrTag,186,Rti__getInterfaceTypeArguments,2413,_rtiArrayToString,182,_functionRtiToString,90,Rti__getGenericFunctionBounds,2414,ioore,37,diagnoseIndexError,38,_isInt,173,_checkIntNullable,175,iae,36,IndexError$,2415,RangeError$value,2416,_checkNumNullable,178,RangeError,398,IndexError,404,setRuntimeTypeInfo,83,isTopType,243,Rti__getFunctionParameters,2417,ArgumentError$value,2416,_arrayInstanceType,147,UnsupportedError$,2415,throwExpression,44,UnsupportedError,405,unmangleGlobalNameIfPreservedAnyways,246,assertTest,77,AssertionError$,2415,AssertionError,394,TypeErrorImplementation$,2415,TypeErrorImplementation,75,_typeDescription,76,extractFunctionTypeObjectFromInternal,74,runtimeTypeToString,86,_runtimeTypeToString,87,unminifyOrTag,10,_joinArguments,92,_functionRtiToString0,90,extractKeys,245,JSArray_JSArray$markFixed,2418,JSArray,2419,JSArray_markFixedList,2420,StringBuffer,2421,_checkBoolNullable,170,getIsolateAffinityTag,82,IterableBase_iterableToFullString,2422,_isToStringVisiting,357,_toStringVisiting,2423,StringBuffer__writeAll,2424,IterableElementError_noElement,2425,StateError,407,ArrayIterator,2426,throwConcurrentModificationError,45,ConcurrentModificationError$,2415,ConcurrentModificationError,408,ListIterator,2427,ListMixin,2428,_checkValidIndex,124,Iterable,2429,initNativeDispatchFlag,2430,initNativeDispatch,104,UnimplementedError$,2415,lookupAndCacheInterceptor,99,getTagFunction,2431,dispatchRecordsForInstanceTags,2432,interceptorsForUncacheableTags,2433,alternateTagFunction,2434,makeLeafDispatchRecord,102,patchInteriorProto,101,makeDispatchRecord,248,JavaScriptIndexingBehavior,2435,UnimplementedError,406,initNativeDispatchContinue,105,initHooks,107,prototypeForTagFunction,2436,makeDefaultDispatchRecord,103,applyHooksTransformer,108,initHooks_closure,2437,initHooks_closure0,2437,initHooks_closure1,2437,_TypeError__TypeError$forType,2438,_TypeError,2439,_Error_compose,2440,_CastError__CastError$forType,2438,_CastError,2441,instanceOrFunctionType,144,_TypeError$fromMessage,2442,Rti__isUnionOfFunctionType,2443,closureFunctionType,143,getTypeFromTypesTable,151,_Universe_eval,2444,_Universe__parseRecipe,2445,_Parser_create,2446,_Parser_parse,2447,_Parser_handleDigit,2448,_Parser_handleIdentifier,2449,_Parser_toType,2450,_Universe__lookupGenericFunctionParameterRti,2451,_Universe__lookupTerminalRti,2452,_Parser_toTypes,2453,_Universe__lookupInterfaceRti,2454,_Universe__lookupGenericFunctionRti,2455,_Universe__lookupBindingRti,2456,_Parser_handleExtendedOperations,2457,assertThrow,78,_Universe__lookupUnaryRti,2458,_FunctionParameters,2459,_Universe__lookupFunctionRti,2460,_Parser_toTypesNamed,2461,_Universe__canonicalRecipeJoin,2462,_Universe__canonicalRecipeJoinNamed,2463,Rti,2464,_Universe__finishRti,2465,_generalTypeCheckImplementation,159,_generalAsCheckImplementation,158,_installSpecializedIsTest,154,_generalIsTestImplementation,156,_isTop,166,_asTop,167,int,2466,double,2467,_isNum,176,num,2468,String,2469,_isString,179,bool,2470,isLegacyTopType,242,_isTestViaProperty,157,_AssertionError,2471,Rti__getBindingArguments,2472,_Parser_indexToType,2473,_Universe_findRule,2474,Rti__getCanonicalRecipe,2475,_Universe_evalInEnvironment,2476,_CastError$fromMessage,2442,_isSubtype,233,Rti__getFutureFromFutureOr,2477,typesEqual,240,_isFunctionSubtype,236,_isInterfaceSubtype,237,typeEqual,238,namedTypesEqual,241,Future,272,_Universe_bind,2478,_instanceTypeFromConstructor,149,_instanceTypeFromConstructorMiss,150,_Universe_findErasedType,2479,BoundClosure_evalRecipeIntercepted,2480,BoundClosure_evalRecipe,2481,Closure_forwardInterceptedCallTo,2482,Closure_cspForwardCall,2483,BoundClosure_selfFieldNameCache,2484,BoundClosure_computeFieldNamed,2485,BoundClosure_selfOf,2486,BoundClosure_receiverFieldNameCache,2487,Closure_cspForwardInterceptedCall,2488,BoundClosure_receiverOf,2489,RuntimeError$,2415,RuntimeError,81,getRuntimeTypeInfo,84,substitute,95,invokeOn,97,internalBootstrapBrowserTest_closure,2490,RemoteListener_start,2491,postMessageChannel,631,StreamChannel,2257,_ControllerStream,2492,_instanceType,148,_Future,265,Zone__current,2493,Stream_length_closure,1045,Stream_length_closure0,1045,Null,2494,Stream,2495,AsyncError,2496,_Future__propagateToListeners,2497,_Future__propagateToListeners_handleWhenCompleteCallback,2498,_Future__propagateToListeners_handleValueCallback,2499,_Future__propagateToListeners_handleError,2500,_Future__chainCoreFuture,2501,_Future__prependListeners_closure,2502,boolConversionCheck,73,unwrapException,51,getTraceFromException,52,ExceptionAndStackTrace,2503,_StackTrace,2504,unwrapException_saveStackTrace,2505,JsNoSuchMethodError$,2415,NullError$,2415,UnknownJsTypeError,2506,StackOverflowError,2507,TypeErrorDecoder_extractPattern,2508,quoteStringForRegExp,114,TypeErrorDecoder,2509,TypeErrorDecoder_provokePropertyErrorOn,2510,TypeErrorDecoder_provokeCallErrorOn,2511,NullError,49,JsNoSuchMethodError,50,_Future__propagateToListeners_handleWhenCompleteCallback_closure,2512,_registerErrorHandler,297,_FutureListener,2513,_rootScheduleMicrotask,331,_scheduleAsyncCallback,300,_RootZone_bindCallback_closure,1244,_RootZone_bindCallbackGuarded_closure,2514,_rootRun,324,_rootHandleUncaughtError,323,_rootHandleUncaughtError_closure,2515,_schedulePriorityAsyncCallback,301,_nextCallback,2516,_lastPriorityCallback,2517,_lastCallback,2518,_AsyncCallbackEntry,2519,Zone__enter,2520,_isInCallbackLoop,2521,_microtaskLoop,298,_AsyncRun__initializeScheduleImmediate,2522,_AsyncRun__initializeScheduleImmediate_internalCallback,2523,convertDartClosureToJS,59,_AsyncRun__initializeScheduleImmediate_closure,2524,Timer__createTimer,2525,Duration_toString_twoDigits,2526,Duration,392,Duration_toString_sixDigits,2527,_TimerImpl$,2415,_TimerImpl,261,_TimerImpl_internalCallback,2528,_AsyncRun__scheduleImmediateWithSetImmediate_internalCallback,2529,_AsyncRun__scheduleImmediateJsOverride_internalCallback,2530,invokeClosure,57,_Exception,2531,_rootRunBinary,326,_rootRunUnary,325,_Future__addListener_closure,2532,_BufferingStreamSubscription$,2415,_PendingEvents,2533,_BufferingStreamSubscription,310,ArgumentError$,2415,_Future__chainForeignFuture,2534,_Future__chainForeignFuture_closure,2535,_Future__chainForeignFuture_closure0,2535,_Future__chainForeignFuture_closure1,2535,scheduleMicrotask,302,get$scheduleMicrotask,302,_StreamControllerLifecycle,2536,StreamController,307,StreamConsumer,2537,Stream_pipe_closure,2538,_GuaranteeSink,2539,StreamChannelController$,2415,_EventStream,2540,postMessageChannel_closure,2541,postMessageChannel_closure0,2541,LinkedHashMap_LinkedHashMap$_literal,2542,_convertDataTree,466,_EventStreamSubscription$,2415,_EventStreamSubscription_closure,2543,_wrapZone,473,_EventStreamSubscription,472,_RootZone_bindUnaryCallbackGuarded_closure,1247,_convertDataTree__convert,2544,_IdentityHashMap,2545,MapBase_mapToString,2546,MapBase_mapToString_closure,2547,MapMixin,2548,_HashMap__getTableEntry,2549,Primitives_objectHashCode,53,objectHashCode,53,_HashMapKeyIterable,2550,IterableBase_iterableToShortString,2551,_iterablePartsToStrings,358,RangeError_checkNotNegative,2552,RangeError$range,2553,_HashMapKeyIterator,2554,MappedIterable_MappedIterable,2415,MappedIterator,2555,Iterator,2556,EfficientLengthMappedIterable,2557,MappedIterable,3,MappedListIterable,2558,ListIterable,2559,_HashMap__newHashTable,2560,_HashMap__setTableEntry,2561,LinkedHashMap,346,JsLinkedHashMap,2562,fillLiteralMap,54,LinkedHashMapKeyIterable,2563,LinkedHashMapKeyIterator,870,LinkedHashMapCell,2564,postMessageChannel__closure,2565,postMessageChannel__closure0,2565,postMessageChannel__closure1,2565,_StructuredCloneDart2Js,2566,DateTime,2567,_StructuredClone_walk_closure,2568,_StructuredClone_walk_closure0,2568,_AcceptStructuredCloneDart2Js,2569,StateError$,2415,StreamSink,2570,StreamSubscription,2571,promiseToFuture,467,LinkedHashMap_LinkedHashMap$_empty,2572,_AcceptStructuredClone_walk_closure,2573,Primitives_getYear,2574,DateTime__fourDigits,2575,Primitives_getMonth,2576,DateTime__twoDigits,2577,Primitives_getDay,2578,Primitives_getHours,2579,Primitives_getMinutes,2580,Primitives_getSeconds,2581,Primitives_getMilliseconds,2582,DateTime__threeDigits,2583,Primitives_lazyAsJsDate,2584,_checkDoubleNullable,172,_AsyncCompleter,2585,promiseToFuture_closure,2586,promiseToFuture_closure0,2586,_Future__asyncCompleteError_closure,2587,_Future__asyncComplete_closure,2588,_Future__chainFuture_closure,2589,Stream_firstWhere_closure,1051,Stream_firstWhere_closure0,1051,_completeWithErrorCallback,287,Stream_firstWhere__closure,2590,Stream_firstWhere__closure0,2590,_cancelAndErrorClosure,317,_runUserCode,315,_cancelAndErrorClosure_closure,2591,_cancelAndError,316,_cancelAndError_closure,2592,_Future$zoneValue,2593,_cancelAndValue,318,_cancelAndValue_closure,2594,StreamChannelController,588,StreamController_StreamController,2415,_StreamSinkWrapper,2595,GuaranteeChannel$,2415,GuaranteeChannel,634,GuaranteeChannel_closure,2596,_StreamImplEvents,2597,_StreamControllerAddStreamState,1059,_SyncCompleter,2598,_GuaranteeSink_addStream_closure,2599,_GuaranteeSink__addError_closure,2600,GuaranteeChannel__closure,2601,_SyncStreamController,2602,_AsyncStreamController,2603,_EventDispatch,2604,_PendingEvents_schedule_closure,2605,_BufferingStreamSubscription__sendDone_sendDone,2606,_ControllerSubscription,1071,_StreamController__subscribe_closure,2607,_StreamController__recordCancel_complete,2608,_AddStreamState_cancel_closure,2609,_runGuarded,308,_DelayedError,2610,_BufferingStreamSubscription__sendError_sendError,2611,_DelayedData,2612,_MultiChannel$,2415,RemoteListener_start_closure,2613,_ZoneSpecification$,2415,Stream_Stream$fromIterable,2614,RemoteListener_start_closure0,2613,RemoteListener_start_closure1,2613,SuiteChannelManager,478,LinkedHashSet_LinkedHashSet$_empty,2572,runZoned,339,Map,2615,_runZoned,340,runZoned_closure,2616,_parentDelegate,322,_RootZone__rootDelegate,2617,_ZoneDelegate,2618,_rootFork,337,printToZone,2619,HashMap_HashMap$from,2620,_CustomZone,338,_ZoneFunction,2621,printString,247,_CustomZone_bindUnaryCallbackGuarded_closure,1205,_CustomZone_bindCallbackGuarded_closure,2622,_CustomZone_bindCallback_closure,1200,_TimerImpl$periodic,2623,_TimerImpl$periodic_closure,2624,_CustomZone_bindUnaryCallback_closure,1202,HashMap_HashMap,2415,_HashMap,2625,HashMap_HashMap$from_closure,2626,_LinkedHashSet,2627,_LinkedHashSetIterator,353,LinkedHashSet_LinkedHashSet$_literal,2542,RemoteListener_start__closure,2628,StackTraceFormatter,2236,RemoteListener_start___closure,2629,RemoteListener_start___closure0,2629,RemoteListener__sendError,2630,RemoteException_serialize,2631,TestFailure,2632,Chain_Chain$forTrace,2633,Chain_toString_closure,2634,Chain_toString_closure0,2634,instantiate1,8,checkTypeBound,160,checkNum,41,Chain_toString__closure,2635,Instantiation1,9,createRuntimeType,152,_Type,2636,instantiatedGenericFunctionType,134,_instantiate,135,_instantiateArray,139,_instantiateFunctionParameters,141,_instantiateNamed,140,Chain_toString__closure0,2635,getRuntimeType,93,Chain,2637,List_List$unmodifiable,2638,LazyChain,2639,Chain_Chain$forTrace_closure,2640,Chain_Chain$parse,2447,Chain_Chain$parse_closure,2641,Trace_Trace$parse,2447,Chain_Chain$parse_closure0,2641,Trace_toString_closure,2642,Trace_toString_closure0,2642,UnparsedFrame,630,Trace$parseFriendly,2643,WhereIterable,2644,Trace$parseFriendly_closure,2645,Trace$parseFriendly_closure0,2645,Trace,488,_StringStackTrace,2646,WhereIterator,2647,Frame_Frame$parseFriendly,2643,_parseUri,616,ParsedPath_ParsedPath$parse,2447,Context_split_closure,2648,List_List$from,2620,List,2649,ParsedPath,2650,List_List$filled,2651,ParsedPath_normalize_closure,2652,List_List$generate,2653,stringReplaceAllUnchecked,115,stringReplaceAllUncheckedString,116,JSSyntaxRegExp,2654,escapeReplacement,112,JSSyntaxRegExp_makeNative,2655,FormatException$,2415,FormatException,409,WindowsStyle,2366,RegExp_RegExp,2415,isDriveLetter,602,_Uri__uriDecode,2656,StringMatch,2657,CodeUnits,2658,_Uri__hexCharPairToByte,2659,Utf8Decoder,2660,UnmodifiableListMixin,2661,Utf8Decoder__convertIntercepted,2662,RangeError_checkValidRange,2663,_scanOneByteCharacters,372,String_String$fromCharCodes,2664,_Utf8Decoder,2665,Primitives_stringFromCharCode,2666,Primitives_stringFromCharCodes,2667,Primitives_stringFromNativeUint8List,2668,String__stringFromIterable,2669,Primitives_stringFromCodePoints,2670,Primitives__fromCharCodeApply,2671,Utf8Decoder__convertInterceptedUint8List,2672,Utf8Decoder__useTextDecoderChecked,2673,Utf8Decoder__unsafe,2674,Utf8Decoder__useTextDecoderUnchecked,2675,Utf8Decoder__makeDecoder,2676,RangeError_checkValueInInterval,2677,stringReplaceFirstUnchecked,120,stringReplaceRangeUnchecked,121,stringReplaceFirstRE,113,_StringAllMatchesIterable,2678,_StringAllMatchesIterator,2679,_MatchImplementation$,2415,_MatchImplementation,110,isAlphabetic,601,_AllMatchesIterable,2680,_AllMatchesIterator,2681,IterableElementError_tooFew,2682,JSArray_JSArray$fixed,2683,UrlStyle,2368,Context,615,current,621,get$current,621,PathException$,2415,_validateArgList,617,Context_join_closure,2684,Context_joinAll_closure,2685,SubListIterable$,2415,_validateArgList_closure,2686,SubListIterable,2,PathException,559,Uri_base,2687,_current,2493,set$_current,2493,_currentUriBase,2688,Primitives_currentUri,2689,Uri_parse,2447,UriData__parse,2690,_scan,465,_SimpleUri,2691,_Uri__Uri$notSimple,2692,int_parse,2447,Primitives_parseInt,2693,_Uri__defaultPort,2694,_Uri__toWindowsFilePath,2695,_Uri__checkNonWindowsPathReservedCharacters,2696,_Uri__checkNonWindowsPathReservedCharacters_closure,2697,_Uri__checkWindowsDriveLetter,2698,_Uri__checkWindowsPathReservedCharacters,2699,String_String$fromCharCode,2700,_Uri__removeDotSegments,2701,_Uri__makePort,2702,_Uri__normalizeRelativePath,2703,_Uri,420,_Uri__mayContainDotSegments,2704,_Uri__escapeScheme,2705,_Uri__isAlphabeticCharacter,2706,_Uri__makeScheme,2707,_Uri__fail,2708,_Uri__makeUserInfo,2709,_Uri__makeHost,2710,_Uri__Uri$notSimple_closure,2711,_Uri__makePath,2712,_Uri__makeQuery,2713,_Uri__makeFragment,2714,_Uri__normalizeOrSubstring,2715,_Uri__normalize,2716,_Uri__normalizeEscape,2717,_Uri__escapeChar,2718,hexDigitValue,1,_Uri__makePath_closure,2719,_Uri__normalizePath,2720,_Uri__uriEncode,2721,Codec,2722,_Utf8Encoder,2723,_checkValidRange,125,diagnoseRangeError,39,_Uri__checkZoneID,2724,_Uri__normalizeZoneID,2725,Uri_parseIPv6Address,2726,_Uri__normalizeRegName,2727,Uri_parseIPv6Address_error,2728,Uri_parseIPv6Address_parseHex,2729,Uri__parseIPv4Address,2730,Uri__parseIPv4Address_error,2731,_Uri__canonicalizeScheme,2732,_createTables,464,_createTables_closure,2733,_createTables_build,2734,_createTables_setChars,2735,_createTables_setRange,2736,_DataUri,2737,UriData,2738,Base64Codec__checkPadding,2739,_ensureNativeList,122,NativeInt8List__create1,2740,Style__getPlatformStyle,2741,_Uri__Uri,2415,PosixStyle,2364,Frame_Frame$parseFriendly_closure,2742,Frame__catchFormatException,2743,UriData__writeUri,2744,UriData__uriEncodeBytes,2745,Frame,2746,WindowsStyle_absolutePathToUri_closure,2747,Context_Context,2415,UriData__validateMimeType,2748,JSString__skipLeadingWhitespace,2749,JSString__skipTrailingWhitespace,2750,JSString__isWhitespace,2751,Trace$parseV8,2752,Trace$parseJSCore,2753,Trace$parseFirefox,2754,Trace__parseVM,2755,Trace__parseVM_closure,2756,Frame_Frame$parseVM,2757,Frame_Frame$parseVM_closure,2758,ExpandIterable,2759,Chain_toTrace_closure,2760,ExpandIterator,782,Trace$parseFirefox_closure,2761,Trace$parseFirefox_closure0,2761,Frame_Frame$parseFirefox,2754,Frame_Frame$parseFirefox_closure,2762,Frame__uriOrPathToUri,2763,_Uri__Uri$file,2764,_Uri__makeWindowsFileUrl,2765,_Uri__makeFileUri,2766,Trace$parseJSCore_closure,2767,Trace$parseJSCore_closure0,2767,Frame_Frame$parseV8,2752,Frame_Frame$parseV8_closure,2768,Frame_Frame$parseV8_closure_parseLocation,2769,Trace$parseV8_closure,2770,Trace$parseV8_closure0,2770,SkipWhileIterable,2771,SkipWhileIterator,2772,stringContainsUnchecked,111,StackTrace_current,621,StackZoneSpecification_chainFor_closure,2773,_Node,2774,LazyTrace,2775,StackZoneSpecification_chainFor_closure0,2773,Trace_Trace$from,2620,Trace_Trace$from_closure,2776,LazyChain_toTrace_closure,2777,Primitives_getProperty,2778,parseJsonExtended,553,mapStackTrace,487,StackTraceFormatter_formatStackTrace_closure,2779,LazyChain_foldFrames_closure,2780,Chain_foldFrames_closure,2781,Chain_foldFrames_closure0,2781,IterableElementError_tooMany,2782,LazyTrace_foldFrames_closure,2783,Trace_foldFrames_closure,2784,ReversedListIterable,2785,Trace_foldFrames_closure0,2784,mapStackTrace_closure,2786,mapStackTrace_closure0,2786,mapStackTrace_closure1,2786,_prettifyMember,489,_prettifyMember_closure,2787,_prettifyMember_closure0,2787,stringReplaceAllFuncUnchecked,118,_stringIdentity,117,MappingBundle$fromJson,2788,parseJson,554,ArgumentError$notNull,2789,SourceLocation$,2415,SourceMapSpan,1872,findLineStart,605,countCodeUnits,603,Highlighter__lastLineLength,2790,SourceSpanWithContext$,2415,Highlighter__normalizeNewlines,2791,Highlighter__normalizeTrailingNewline,2792,Highlighter__normalizeEndOfLine,2793,Highlighter,1957,_glyphs,2794,Highlighter__writeSidebar_closure,2795,Highlighter__writeLastLine_closure,2796,Highlighter__writeLastLine_closure0,2796,Highlighter__writeLastLine_closure1,2796,Highlighter__writeIntermediateLines_closure,2797,Highlighter__writeFirstLine_closure,2798,Highlighter__writeFirstLine_closure0,2798,Highlighter__writeFirstLine_closure1,2798,Highlighter__writeFirstLine_closure2,2798,SourceSpanWithContext,560,RangeError$,2415,SourceLocation,523,SingleMapping__findColumn_closure,2799,binarySearch,504,SingleMapping__findLine_closure,2800,JsLinkedHashMap_values_closure,863,MultiSectionMapping$fromJson,2788,SingleMapping$fromJson,2788,SingleMapping,2801,SourceFile,2802,_MappingTokenizer,2803,TargetLineEntry,2804,decodeVlq,534,TargetEntry,2805,SingleMapping$fromJson_closure,2806,pow,471,closure,2807,MultiSectionMapping,2808,MappingBundle,2809,_parseJson,364,_convertJsonToDartLazy,365,_JsonMap,2810,_JsonMapKeyIterable,2811,RemoteListener__sendLoadException,2812,StreamQueue,2813,QueueList$,2415,ListQueue$,2415,_CompleterStream,2814,_RestRequest,2815,StreamCompleter,2816,RemoteListener_start____closure,2817,_asBoolNullable,169,Metadata$deserialize,2818,LinkedHashSet_LinkedHashSet$from,2620,Declarer$,2415,RemoteListener__deserializeSet,2819,Runtime_Runtime$deserialize,2818,_asStringNullable,180,OperatingSystem_find,2820,SuitePlatform$,2415,RemoteListener_start____closure0,2817,Suite,2821,Suite__filterGroup,2822,_asyncStartSync,266,_asyncAwait,267,_asyncReturn,268,_asyncRethrow,269,_wrapJsFunctionForAsync,271,_makeAsyncAwaitCompleter,263,Symbol,2823,_AddStreamState_makeErrorHandler,2824,_AddStreamState_makeErrorHandler_closure,2825,_ListQueueIterator,363,ListQueue,362,QueueList,607,Result,2826,_wrapJsFunctionForAsync_closure,2827,_StreamIterator,2828,_awaitOnObject,270,_awaitOnObject_closure,2829,_awaitOnObject_closure0,2829,_AsyncAwaitCompleter,2830,RemoteListener_start_____closure,2831,Invoker_guard,2832,Invoker_guard_closure,2833,Invoker_guard__closure,2834,RemoteListener,2835,RemoteListener__serializeGroup_closure,2836,Group,490,RemoteListener__serializeTest_closure,2837,VirtualChannel,2838,_EmptyStream,2839,NullStreamSink,2840,_MultiChannel_virtualChannel_closure,2071,_MultiChannel_virtualChannel_closure0,2071,MultiChannel,2841,_DoneStreamSubscription,949,NullStreamSink_addStream_closure,2842,_LinkedHashSet__newHashTable,2560,_LinkedHashSetCell,2843,_asIntNullable,174,RemoteListener__runLiveTest_closure,2844,_BroadcastStream,2845,RemoteListener__runLiveTest_closure0,2844,RemoteListener__runLiveTest_closure1,2844,RemoteListener__runLiveTest_closure2,2844,RemoteListener__runLiveTest_closure3,2844,RemoteListener__runLiveTest__closure,2846,Invoker,2847,LiveTestController$,2415,_BroadcastSubscription,950,State,2848,Invoker__onRun_closure,2849,_AsyncCounter,2850,Chain_capture,2851,Expando__keyCount,2852,StackZoneSpecification,2853,Expando,570,Chain_capture_closure,1968,Primitives_setProperty,2854,StackZoneSpecification__currentTrace_closure,2855,StackZoneSpecification__registerBinaryCallback_closure,2025,StackZoneSpecification__registerBinaryCallback__closure,2027,StackZoneSpecification__registerUnaryCallback_closure,2021,StackZoneSpecification__registerUnaryCallback__closure,2023,StackZoneSpecification__registerCallback_closure,2019,Invoker__onRun__closure,2856,Invoker__onRun___closure,2857,Invoker__onRun___closure0,2857,Message,2858,Invoker__onRun____closure,2859,Future_Future,2415,Future_Future_closure,2860,Timer_Timer,2415,errorsDontStopTest,525,errorsDontStopTest_closure,2861,errorsDontStopTest_closure0,2861,Invoker_waitForOutstandingCallbacks_closure,2862,Invoker_waitForOutstandingCallbacks_closure0,2862,Future_Future$sync,2863,ClosedException$,2415,ClosedException,635,Invoker_heartbeat_closure,2864,Invoker_heartbeat_message,2865,Invoker_heartbeat__closure,2866,TimeoutException,2867,Timeout,2868,Invoker__handleError_closure,2869,Invoker__handleError_closure0,2869,print,412,get$print,412,Chain_Chain$current,621,Chain_Chain$current_closure,2870,LiveTestController,524,_SyncBroadcastStreamController,2871,_LiveTest,2872,_SyncBroadcastStreamController__sendError_closure,974,_AddStreamState,1058,_SyncBroadcastStreamController__sendDone_closure,976,_SyncBroadcastStreamController__sendData_closure,972,_BroadcastStreamController,2873,Metadata_serialize_closure,2874,Metadata_serialize_closure0,2874,MapEntry,2875,_LinkedHashSetIterator$,2415,PlatformSelector,2876,Group_forPlatform_closure,2877,Group$,2415,GroupEntry,2878,Group__map_closure,2879,Group__map_closure0,2879,Metadata_forPlatform_closure,2880,Metadata_Metadata,2415,Metadata_Metadata__unresolved,2881,LinkedHashMap_LinkedHashMap$from,2620,Metadata$_,2882,Metadata_Metadata_closure,2883,Metadata_merge_closure,2884,mergeMaps,506,Metadata_merge_closure0,2884,Set,2885,mergeMaps_closure,1723,UnmodifiableMapView,2886,Metadata,493,UnmodifiableSetView,533,ConstantMap_map_closure,806,ConstantMap__throwUnmodifiable,2887,_ConstantMapKeyIterable,2888,ConstantStringMap,2889,DelegatingSet,2890,Metadata__validateTags_closure,2891,Metadata__validateTags_closure0,2891,pluralize,593,toSentence,592,LinkedHashMap_LinkedHashMap,2415,LinkedHashMap_LinkedHashMap$from_closure,2892,PlatformSelector_evaluate_closure,2893,SuitePlatform,530,OperatingSystem_find_closure,2894,OperatingSystem_find_closure0,2894,Runtime_Runtime$deserialize_closure,2895,Runtime,2896,Declarer_build_closure,2897,LocalTest,2898,Declarer__tearDownAll_closure,2899,Declarer__tearDownAll__closure,2900,Declarer__tearDownAll___closure,2901,Declarer,561,Duration$,2415,LinkedHashSet_LinkedHashSet,2415,PlatformSelector$parse,2447,Metadata__deserializeTimeout,2902,Metadata$deserialize_closure,2903,Stream_last_closure,1049,Stream_last_closure0,1049,Stream_first_closure,1047,Stream_first_closure0,1047,BooleanSelectorImpl,2904,Parser,2185,Scanner,2905,SpanScanner$,2415,AndNode,2906,IntersectionSelector,2907,OrNode,2908,ConditionalNode,2909,Evaluator,2910,SourceSpanFormatException$,2415,SourceSpanFormatException,538,Token,2911,_SpanScannerState,2912,IdentifierToken,2913,validateErrorArgs,606,StringScannerException$,2415,StringScannerException,527,_FileSpan$,2415,SourceSpanMixin,2914,_FileSpan,509,FileLocation$_,2882,FileLocation,2915,NotNode,2916,VariableNode,2917,_expandSafe,564,SpanScanner,474,_asNumNullable,177,PlatformSelector$parse_closure,2918,PlatformSelector__wrapFormatException,2919,_CompleterSink,2920,_CompleterSink__setDestinationSink_closure,2921,StreamSinkCompleter,2922,_EventRequest,2923,SubscriptionStream,1612,_CancelOnErrorSubscriptionWrapper,2924,_CancelOnErrorSubscriptionWrapper_onError_closure,2925,_CancelOnErrorSubscriptionWrapper_onError__closure,2926,StreamQueue__ensureListening_closure,1619,StreamQueue__ensureListening_closure0,1619,StreamQueue__ensureListening_closure1,1619,ErrorResult,2927,ValueResult,2928,EventSink,2929,_NextRequest,2930,Completer,469,LinkedHashSet,349,fillLiteralSet,56,_GeneratedStreamImpl,2931,Stream_Stream$fromIterable_closure,1042,_IterablePendingEvents,1041,_ZoneSpecification,320,_MultiChannel,620,_MultiChannel_closure,2067,_MultiChannel_closure0,2067,_MultiChannel_closure1,2067,_MultiChannel__closure,2069,JSStackTraceMapper_deserialize,2818,PackageRootResolver,2932,asUri,598,ensureTrailingSlash,599,JSStackTraceMapper__deserializePackageConfigMap,2933,PackageConfigResolver__normalizeMap,2934,PackageConfigResolver,2935,JSStackTraceMapper,2936,Map_castFrom,2937,CastMap,2938,CastIterable_CastIterable,2415,CastIterator,2939,EfficientLengthIterable,2940,_EfficientLengthCastIterable,2941,CastIterable,0,CastMap_forEach_closure,747,PackageConfigResolver__normalizeMap_closure,2942,mapMap,505,mapMap_closure,1721,mapMap_closure0,1721,JSStackTraceMapper__deserializePackageConfigMap_closure,2943,StreamChannelCompleter,2256,_StreamChannel,2944,main_closure0,2397,group,587,get$group,587,_declarer,584,Metadata$parse,2447,Trace_Trace$current,621,Declarer_group_closure,2945,Trace_Trace$current_closure,2946,Metadata_validatePlatformSelectors_closure,2947,PlatformSelector_validate_closure,2948,PlatformSelector_validate__closure,2949,Validator,2950,Metadata__parseOnPlatform,2951,Metadata__parseTags,2952,_globalDeclarer,2953,_declarer_closure,2954,RunnerSuiteController,2955,_AsyncBroadcastStreamController,2956,AsyncMemoizer,2957,RunnerSuite,2958,Engine$,2415,Stopwatch__frequency,2959,Primitives_initTicker,2960,Primitives_timerFrequency,2961,ExpandedReporter,2962,Stopwatch,2320,PrintSink,2963,Stream_Stream$fromFuture,2964,_declarer__closure,2965,Future_Future$error,2966,UnmodifiableListView,2967,Primitives_timerTicks,2968,UnionSet,2969,UnionSet_length_closure,1739,IterableSet,2970,UnionSet__iterable_closure,1741,ExpandedReporter__onTestStarted_closure,2971,ExpandedReporter__onTestStarted_closure0,2971,ExpandedReporter__onTestStarted_closure1,2971,indent,591,prefixLines,594,Engine_run_closure,2972,Engine_run_closure0,2972,Pool_close_closure,2973,FutureGroup,499,_ListQueueIterator$,2415,FutureGroup_add_closure,1573,FutureGroup_add_closure0,1573,Engine_run__closure,2286,LiveSuiteController$,2415,Engine_run___closure,2974,Engine_run____closure,2975,Pool__onResourceReleaseAllowed_closure,2976,Pool__runOnRelease_closure,2977,Pool__runOnRelease_closure0,2977,PoolResource,2978,LiveSuiteController_close_closure,2979,RunnerSuiteController__close_closure,2980,Engine__runSkippedTest_closure,2981,Engine__runSkippedTest_closure0,2981,Engine__runSkippedTest_closure1,2981,Engine__runLiveTest_closure,2982,Engine__runLiveTest_closure0,2982,Future_Future$microtask,2983,Engine__runLiveTest_closure1,2982,Future_Future$microtask_closure,2984,LiveSuiteController_reportLiveTest_closure,2985,QueueList__nextPowerOf2,2986,StreamGroup_add_closure,1602,StreamGroup_add_closure0,1602,StreamGroup__listenToStream_closure,2987,LiveSuiteController,595,_LiveSuite,2988,LiveSuiteController_closure,2989,LiveSuiteController_closure0,2989,Stream_Stream$fromFuture_closure,1039,Stream_Stream$fromFuture_closure0,1039,Future_wait,2990,Engine_success_closure,2991,Future_wait_handleError,2992,Future_wait_closure,984,Primitives_initTicker_closure,2993,StreamGroup,2994,UnionSetController$,2415,Pool$,2415,Engine,498,StreamGroup__onCancelBroadcast_closure,1606,StreamGroup__onListen_closure,1604,Engine_closure,2995,Engine_closure0,2995,Pool,485,UnionSetController,507,closure0,2807,_macOSDirectories,2996,SuiteConfiguration__list,2997,UnmodifiableSetView$,2415,SuiteConfiguration__map,2998,SuiteConfiguration,2999,main__closure,3000,test,586,get$test,586,Declarer_test_closure,3001,Declarer_test__closure,3002,Declarer_test___closure,3003,Declarer__runSetUps_closure,3004,Future_forEach,3005,Future_forEach_closure,3006,Future_doWhile,3007,Future_doWhile_closure,3008,method1,550,method2,551,expect,539,get$expect,539,_expect,540,wrapMatcher,609,_expect_closure,3009,_expect_closure0,3009,fail,544,StringDescription,3010,formatFailure,545,Matcher,3011,prettyPrint,546,prettyPrint__prettyPrint,3012,prettyPrint__prettyPrint_pp,3013,_typeName,622,prettyPrint__prettyPrint_closure,3014,prettyPrint__prettyPrint_closure0,3014,prettyPrint__prettyPrint_closure1,3014,escape,612,escape_closure,3015,_getHexLiteral,613,Runes,3016,_combineSurrogatePair,413,RuneIterator,3017,_Predicate,3018,wrapMatcher_closure,3019,_StringEqualsMatcher,3020,_DeepMatcher,3021,JsLinkedHashMap_addAll_closure,865,_DeepMatcher__compareSets_closure,3022,TypeMatcher,3023,FeatureMatcher,3024,_StringEqualsMatcher__writeTrailing,3025,_StringEqualsMatcher__writeLeading,3026,x,3027,_Utils_objectAssign,3028,JS_CONST,3029,Interceptor,3030,JSBool,3031,JSNull,3032,JSObject,3033,JavaScriptObject,3034,PlainJavaScriptObject,3035,UnknownJavaScriptObject,3036,Function,3037,JavaScriptFunction,3038,JSUnmodifiableArray,3039,JSNumber,3040,JSInt,3041,JSDouble,3042,Pattern,3043,JSString,3044,_CastIterableBase,3045,EmptyIterator,3046,FixedLengthListMixin,3047,UnmodifiableListBase,3048,ConstantMap,3049,Instantiation,815,TypeErrorDecoder_noSuchMethodPattern,3050,TypeErrorDecoder_notClosurePattern,3051,TypeErrorDecoder_nullCallPattern,3052,TypeErrorDecoder_nullLiteralCallPattern,3053,TypeErrorDecoder_undefinedCallPattern,3054,TypeErrorDecoder_undefinedLiteralCallPattern,3055,TypeErrorDecoder_nullPropertyPattern,3056,TypeErrorDecoder_nullLiteralPropertyPattern,3057,TypeErrorDecoder_undefinedPropertyPattern,3058,TypeErrorDecoder_undefinedLiteralPropertyPattern,3059,NoSuchMethodError,3060,StackTrace,3061,TearOffClosure,3062,RegExp,382,RegExpMatch,3063,Match,3064,NativeByteBuffer,3065,ByteBuffer,3066,NativeTypedData,3067,NativeByteData,3068,NativeTypedArray,3069,NativeTypedArrayOfDouble,3070,NativeTypedArrayOfInt,3071,NativeFloat32List,3072,NativeFloat64List,3073,NativeInt16List,3074,NativeInt32List,3075,NativeInt8List,3076,NativeUint16List,3077,Uint32List,3078,NativeUint32List,3079,NativeUint8ClampedList,3080,NativeUint8List,418,Uint8List,3081,Type,3082,_Error,3083,Timer,319,Sink,3084,Exception,58,_Completer,3085,StreamTransformer,3086,StreamTransformerBase,3087,_StreamController,3088,_SyncStreamControllerDispatch,3089,_AsyncStreamControllerDispatch,3090,_StreamImpl,3091,_DelayedEvent,3092,_DelayedDone,3093,Error,3094,ZoneSpecification,3095,ZoneDelegate,3096,Zone,3097,_Zone,3098,_RootZone__rootMap,3099,_RootZone,3100,IterableBase,3101,ListBase,3102,MapBase,3103,_UnmodifiableMapMixin,3104,MapView,3105,Queue,3106,SetMixin,3107,SetBase,3108,_SetBase,3109,AsciiCodec,3110,_UnicodeSubsetEncoder,3111,AsciiEncoder,3112,Base64Codec,3113,Base64Encoder,3114,_FusedCodec,3115,Converter,3116,Encoding,3117,JsonCodec,3118,JsonDecoder,3119,Utf8Codec,3120,Utf8Encoder,3121,Utf8Decoder__decoder,3122,OutOfMemoryError,3123,StringSink,3124,Uri,3125,_Uri__isWindowsCached,3126,_Uri__needsNoEncoding,3127,AbortPaymentEvent,3128,AnimationEvent,3129,AnimationPlaybackEvent,3130,ApplicationCacheErrorEvent,3131,BackgroundFetchClickEvent,3132,BackgroundFetchEvent,3133,BackgroundFetchFailEvent,3134,BackgroundFetchedEvent,3135,BeforeInstallPromptEvent,3136,BeforeUnloadEvent,3137,Blob,3138,BlobEvent,3139,CanMakePaymentEvent,3140,ClipboardEvent,3141,CloseEvent,3142,CompositionEvent,3143,CustomEvent,3144,DeviceMotionEvent,3145,DeviceOrientationEvent,3146,DomError,3147,DomException,3148,ErrorEvent,3149,Event,3150,EventTarget,3151,ExtendableEvent,3152,ExtendableMessageEvent,3153,FetchEvent,3154,File,3155,FocusEvent,3156,FontFaceSetLoadEvent,3157,ForeignFetchEvent,3158,GamepadEvent,3159,HashChangeEvent,3160,InstallEvent,3161,KeyboardEvent,3162,Location,3163,MediaEncryptedEvent,3164,MediaError,3165,MediaKeyMessageEvent,3166,MediaQueryListEvent,3167,MediaStreamEvent,3168,MediaStreamTrackEvent,3169,MessageEvent,3170,MessagePort,3171,MidiConnectionEvent,3172,MidiMessageEvent,3173,MouseEvent,3174,MutationEvent,3175,NavigatorUserMediaError,3176,NotificationEvent,3177,OverconstrainedError,3178,PageTransitionEvent,3179,PaymentRequestEvent,3180,PaymentRequestUpdateEvent,3181,PointerEvent,3182,PopStateEvent,3183,PositionError,3184,PresentationConnectionAvailableEvent,3185,PresentationConnectionCloseEvent,3186,ProgressEvent,3187,PromiseRejectionEvent,3188,PushEvent,3189,RtcDataChannelEvent,3190,RtcDtmfToneChangeEvent,3191,RtcPeerConnectionIceEvent,3192,RtcTrackEvent,3193,SecurityPolicyViolationEvent,3194,SensorErrorEvent,3195,SpeechRecognitionError,3196,SpeechRecognitionEvent,3197,SpeechSynthesisEvent,3198,StorageEvent,3199,SyncEvent,3200,TextEvent,3201,TouchEvent,3202,TrackEvent,3203,TransitionEvent,3204,UIEvent,3205,VRDeviceEvent,3206,VRDisplayEvent,3207,VRSessionEvent,3208,WheelEvent,3209,Window,3210,_MojoInterfaceRequestEvent,3211,_ResourceProgressEvent,3212,_USBConnectionEvent,3213,EventStreamProvider,3214,_StructuredClone,3215,_AcceptStructuredClone,3216,VersionChangeEvent,3217,ByteData,3218,Int8List,3219,Uint8ClampedList,3220,Int16List,3221,Uint16List,3222,Int32List,3223,Float32List,3224,Float64List,3225,AudioProcessingEvent,3226,OfflineAudioCompletionEvent,3227,ContextEvent,3228,SqlError,3229,DelegatingSink,3230,DelegatingStreamSubscription,3231,_StreamGroupState,3232,BooleanSelector,3233,All,3234,Node,3235,Visitor,3236,None,3237,TokenType,3238,RecursiveVisitor,3239,EmptyUnmodifiableSet,3240,UnmodifiableSetMixin,3241,_DelegatingIterableBase,3242,DelegatingIterable,3243,_IsTrue,3244,Description,3245,SyncPackageResolver,3246,_PathDirection,3247,_PathRelation,3248,InternalStyle,3249,Style,3250,Mapping,3251,_TokenKind,3252,FileSpan,3253,SourceLocationMixin,3254,SourceSpan,3255,SourceSpanBase,1948,SourceSpanException,3256,Frame__uriRegExp,3257,Frame__windowsRegExp,3258,StackZoneSpecification_disableKey,3259,StreamChannelMixin,3260,LineScannerState,3261,StringScanner,3262,AsciiGlyphSet,3263,UnicodeGlyphSet,3264,LiveTest,3265,MessageType,3266,Metadata_empty,3267,OperatingSystem,3268,Status,3269,Result0,2826,Test,3270,StackTraceMapper,3271,LiveSuite,3272,RuntimeSelection,3273,SuiteConfiguration_empty,3267,_NativeTypedArrayOfDouble_NativeTypedArray_ListMixin,3274,_NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin,3275,_NativeTypedArrayOfInt_NativeTypedArray_ListMixin,3276,_NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin,3277,_ListBase_Object_ListMixin,3278,_SetBase_Object_SetMixin,3279,_UnmodifiableMapView_MapView__UnmodifiableMapMixin,3280,_QueueList_Object_ListMixin,3281,_UnionSet_SetBase_UnmodifiableSetMixin,3282,_UnmodifiableSetView_DelegatingSet_UnmodifiableSetMixin,3283,_IterableSet_SetMixin_UnmodifiableSetMixin,3284,main,552,getNativeInterceptor,249,isJsIndexable,11,Primitives_dateNow,3285,closureFromTearOff,66,throwCyclicInit,80,getRuntimeTypeArguments,85,computeSignature,96,defineProperty,98,findType,133,typeLiteral,153,_asDoubleNullable,171,_Universe_addRules,3286,_Universe_addErasedTypes,3287,_AsyncRun__scheduleImmediateJsOverride,3288,_AsyncRun__scheduleImmediateWithSetImmediate,3289,_AsyncRun__scheduleImmediateWithTimer,3290,Future__kTrue,3291,_startMicrotaskLoop,299,StreamIterator_StreamIterator,2415,_nullDataHandler,312,_nullErrorHandler,313,_nullDoneHandler,314,_rootRegisterCallback,327,_rootRegisterUnaryCallback,328,_rootRegisterBinaryCallback,329,_rootErrorCallback,330,_rootCreateTimer,332,_rootCreatePeriodicTimer,333,_rootPrint,335,_printToZone,336,Uri_decodeComponent,3292,_escapeString,623,main0,552,max,470,DART_CLOSURE_PROPERTY_NAME,2333,JS_INTEROP_INTERCEPTOR_TAG,2334,_AsyncRun__scheduleImmediateClosure,3293,Future__nullFuture,3294,_Base64Decoder__inverseAlphabet,3295,_hasErrorStackProperty,2352,_scannerTables,2353,_whitespaceAndSingleLineComments,2354,_multiLineCommentBody,2355,_hyphenatedIdentifier,2356,_dart2DynamicArgs,2357,_escapeRegExp,2358,windows,2359,url,2360,context,2361,get$context,2361,Style_posix,3296,Style_windows,2359,Style_url,2360,Style_platform,3297,_digits,2370,MAX_INT32,2371,MIN_INT32,2372,_specKey,2373,_vmFrame,2374,_v8Frame,2375,_v8UrlLocation,2376,_v8EvalLocation,2377,_firefoxSafariFrame,2378,_friendlyFrame,2379,_asyncBody,2380,_initialDot,2381,_terseRegExp,2385,_v8Trace,2386,_v8TraceLine,2387,_firefoxSafariTrace,2388,_friendlyTrace,2389,_universalValidVariables,2391,_currentKey,2392,_currentKey0,2392,currentOSGuess,2393,_hyphenatedIdentifier0,2356,anchoredHyphenatedIdentifier,2394,$get$DART_CLOSURE_PROPERTY_NAME,2333,$get$JS_INTEROP_INTERCEPTOR_TAG,2334,$get$TypeErrorDecoder_noSuchMethodPattern,3050,$get$TypeErrorDecoder_notClosurePattern,3051,$get$TypeErrorDecoder_nullCallPattern,3052,$get$TypeErrorDecoder_nullLiteralCallPattern,3053,$get$TypeErrorDecoder_undefinedCallPattern,3054,$get$TypeErrorDecoder_undefinedLiteralCallPattern,3055,$get$TypeErrorDecoder_nullPropertyPattern,3056,$get$TypeErrorDecoder_nullLiteralPropertyPattern,3057,$get$TypeErrorDecoder_undefinedPropertyPattern,3058,$get$TypeErrorDecoder_undefinedLiteralPropertyPattern,3059,$get$_AsyncRun__scheduleImmediateClosure,3293,$get$Future__nullFuture,3294,$get$_currentKey,2392,$get$_RootZone__rootMap,3099,$get$_currentKey0,2392,$get$_specKey,2373,$get$context,2361,$get$Style_url,2360,$get$Style_windows,2359,$get$Utf8Decoder__decoder,3122,$get$Style_platform,3297,$get$_Uri__isWindowsCached,3126,$get$_Uri__needsNoEncoding,3127,$get$_scannerTables,2353,$get$_Base64Decoder__inverseAlphabet,3295,$get$Style_posix,3296,$get$_friendlyFrame,2379,$get$_v8Trace,2386,$get$_firefoxSafariTrace,2388,$get$_friendlyTrace,2389,$get$_vmFrame,2374,$get$_asyncBody,2380,$get$_firefoxSafariFrame,2378,$get$_initialDot,2381,$get$Frame__uriRegExp,3257,$get$Frame__windowsRegExp,3258,$get$windows,2359,$get$_v8Frame,2375,$get$_v8EvalLocation,2377,$get$_v8UrlLocation,2376,$get$_v8TraceLine,2387,$get$_hasErrorStackProperty,2352,$get$_terseRegExp,2385,$get$url,2360,$get$_digits,2370,$get$MIN_INT32,2372,$get$MAX_INT32,2371,$get$StackZoneSpecification_disableKey,3259,$get$anchoredHyphenatedIdentifier,2394,$get$_hyphenatedIdentifier,2356,$get$_hyphenatedIdentifier0,2356,$get$_whitespaceAndSingleLineComments,2354,$get$_multiLineCommentBody,2355,$get$_universalValidVariables,2391,$get$SuiteConfiguration_empty,3267,$get$currentOSGuess,2393,$get$Metadata_empty,3267,$get$_escapeRegExp,2358,$get$_dart2DynamicArgs,2357,getInterceptor$,3298,getInterceptor$asx,3299,async___startMicrotaskLoop$closure,3300,async__AsyncRun__scheduleImmediateJsOverride$closure,3301,async__AsyncRun__scheduleImmediateWithSetImmediate$closure,3302,async__AsyncRun__scheduleImmediateWithTimer$closure,3303,async___nullDoneHandler$closure,3304,async___nullErrorHandler$closure,3305,async___nullDataHandler$closure,3306,getInterceptor$ax,3307,async___printToZone$closure,3308,math__max$closure,3309,getInterceptor$s,3310,core_Uri_decodeComponent$closure,3311,main_test__main$closure,3312,_js_helper_Primitives_dateNow$closure,3313,async_Future__kTrue$closure,3314,pretty_print___escapeString$closure,3315,util___getHexLiteral$closure,3316,getInterceptor$x,3317,getInterceptor$ansx,3318,getInterceptor$n,3319,async___rootHandleUncaughtError$closure,3320,async___rootRun$closure,3321,async___rootRunUnary$closure,3322,async___rootRunBinary$closure,3323,async___rootRegisterCallback$closure,3324,async___rootRegisterUnaryCallback$closure,3325,async___rootRegisterBinaryCallback$closure,3326,async___rootErrorCallback$closure,3327,async___rootScheduleMicrotask$closure,3328,async___rootCreateTimer$closure,3329,async___rootCreatePeriodicTimer$closure,3330,async___rootPrint$closure,3331,async___rootFork$closure,3332","instance":"K1,3333,$this,3334,_box_0,3335,matcher,3336,future,3337,get$future,3337,V1,3338,listener,3339,frame,3340,expectedElement,3341,getMain,3342,value,2416,location,3343,get$location,3343,channel,3344,get$channel,3344,depth,3345,controller,3346,super$StringScanner$matches,3347,beforeLoad,3348,f,3349,line,3350,get$line,3350,printZone,3351,R,3352,end,3353,get$end,3353,transform,3354,result,3355,selector,3356,handleError,3357,get$handleError,3357,body,3358,elements,3359,x,3360,suite,3361,get$suite,3361,T,3362,index,3363,predicate,610,error,2966,get$error,2966,validVariables,3364,terse,3365,super$EventTarget$addEventListener,3366,_TimerImpl$2,2415,stackTrace,3367,_BufferingStreamSubscription$4,2415,_EventStreamSubscription$4,2415,LinkedHashMapKeyIterator$2,2415,timeout,3368,DateTime$_withValue$2$isUtc,3369,_Future$zoneValue$2,2593,StreamChannelController$2$allowForeignErrors$sync,2415,GuaranteeChannel$3$allowSinkErrors,2415,message,3370,get$message,3370,_Future$immediate$1,3371,_CustomZone$3,2415,performance,3372,trace,3373,div,3374,_TimerImpl$periodic$2,2623,level,3375,span,3376,get$span,3376,_LinkedHashSetIterator$2,2415,registered,3377,Instantiation$1,2415,_MatchImplementation$2,2415,SubListIterable$3,2415,super$Iterable$where,3378,SourceSpanBase$3,2415,SourceSpanWithContext$4,2415,SourceLocation$4$column$line$sourceUrl,2415,super$JavaScriptObject$toString,3379,SingleMapping$fromJson$2$mapUrl,2788,callback,3380,SourceFile$decoded$2$url,3381,test,586,get$test,586,MultiSectionMapping$fromJson$3$mapUrl,2788,groups,3382,get$groups,3382,liveTest,3383,get$liveTest,3383,engine,3384,MappingBundle$fromJson$2$mapUrl,2788,_StreamControllerAddStreamState$4,2415,_DoneStreamSubscription$1,2415,Invoker$_$4$groups$guarded,2882,chain,3385,LiveTestController$5$groups,2415,_BroadcastSubscription$5,2415,Metadata$_$10$chainStackTraces$forTag$onPlatform$retry$skip$skipReason$tags$testOn$timeout$verboseTrace,2882,completer,3386,longest,3387,SuitePlatform$3$inGoogle$os,2415,FileLocation$_$2,2882,_FileSpan$3,2415,StringScanner$3$position$sourceUrl,2415,_box_1,3388,SubscriptionStream$1,2415,super$Iterable$skipWhile,3389,fn,3390,$call$body$Engine_run__closure,3391,oldPredicate,3392,ListQueue$1,2415,counter,3393,QueueList$1,2415,hasError,3394,_MultiChannel$1,2415,loadResource,3395,StreamChannelCompleter$0,2415,super$TypeMatcher$describe,3396,id,3397,Metadata$parse$8$chainStackTraces$onPlatform$retry$skip$tags$testOn$timeout$verboseTrace,2447,milliseconds,3398,super$TypeMatcher$matches,3347,originalSource,3399,Stopwatch$0,2415,start,2491,get$start,2491,stream,3400,get$stream,3400,ExpandedReporter$_$5$color$printPath$printPlatform,2882,_Future$immediateError$2,3401,outstandingCallbacksForBody,3402,sourceResult,3403,K,3404,serializedOnPlatform,3405,V,3406,LiveSuiteController$1,2415,StreamGroup$broadcast$0,3407,onData,3408,get$onData,3408,Engine$3$concurrency$coverage$maxSuites,2415,Pool$2$timeout,2415,UnionSetController$1$disjoint,2415,target,3409,StringDescription$1,2415,sourceMap,3410,invoker,3411,minified,3412,zone,3413,sdkRoot,3414,streamConsumer,3415,e,3416,platform,3297,s,3417,sdkLib,3418,super$_BroadcastStreamController$_addEventError,3419,column,3420,get$column,3420,cleanUp,3421,eagerError,3422,iterator,3423,get$iterator,3423,identifier,3424,port,3425,get$port,3425,action,3426,node,3427,T1,3428,T2,3429,withResource$body$Pool,3430,portSubscription,3431,serialized,3432,doneSignal,3433,arg1,3434,pos,3435,arg2,3436,dispatch,3437,getTag,3438,testOn,3439,getUnknownTag,3440,skip,3441,get$skip,3441,verboseTrace,3442,get$verboseTrace,3442,prototypeForTag,3443,chainStackTraces,3444,get$chainStackTraces,3444,argumentError,3445,super$SourceSpanMixin$$eq,3446,retry,3447,get$retry,3447,arg,3448,skipReason,3449,_convertedObjects,3450,onPlatform,3451,uri,3452,get$uri,3452,portStart,3453,skipped,3454,get$skipped,3454,textInside,3455,maxItems,3456,maxLineLength,3457,original,3458,get$original,3458,_runGroup$body$Engine,3459,host,3460,get$host,3460,_prettyPrint,3461,_runLiveTest$body$Engine,3462,indent,3463,_runSkippedTest$body$Engine,3464,computation,3465,orElse,3466,countSuccess,3467,K2,3468,$protected,3469,spec,3470,pp,3471,super$DelegatingStreamSubscription$onError,3472,object,3473,ex,3474,subscription,3475,super$DelegatingStreamSubscription$cancel,3476,bodyFunction,3477,tables,3478,data,3479,get$data,3479,_foreign,3480,set$_foreign,3480,_disabled,3481,get$_disabled,3481,test$9$onPlatform$retry$skip$solo$tags$testOn$timeout,586,_onTestStarted,3482,get$_onTestStarted,3482,newDartList$1,3483,configure$1$mapper,3484,elapsedMicroseconds,3485,get$elapsedMicroseconds,3485,_captured_argumentError_0,3486,_platform_selector$_captured_this_0,3487,_completeWithValue,3488,get$_completeWithValue,3488,_parser$_captured_this_0,3489,_isScheduled,3490,get$_isScheduled,3490,hashMapCellKey,3491,_captured_future_1,3492,_closeChannel,3493,get$_closeChannel,3493,encode$1,3494,_error,3495,get$_error,3495,_core$_start,3496,onClose,3497,get$onClose,3497,_captured_callback_1,3498,_completeError,3499,get$_completeError,3499,onData$1,3408,_captured_doneSignal_2,3500,_captured_result_2,3501,configure$3$except$mapper$only,3484,separators,3502,set$separators,3502,_async_memoizer$_completer,3503,_counterKey,3504,_captured_V1_2,3505,prettyUri,3506,get$prettyUri,3506,_captured_serializedOnPlatform_0,3507,_compareSets,3508,get$_compareSets,3508,fold$1$2,3509,getRoot,3510,get$getRoot,3510,_newSet$0,3511,_captured_stackTrace_3,3512,_isPort$1,3513,catchError$1,3514,*,3515,get$*,3515,_and$0,3516,_captured_verboseTrace_4,3517,_scanOperator$1,3518,_writeFirstLine$1,3519,_handleUncaughtError,3520,get$_handleUncaughtError,3520,set$_handleUncaughtError,3520,_failedGroup,3521,_kind,3522,isOdd,3523,get$isOdd,3523,_findLine,3524,get$_findLine,3524,_captured_V_3,3525,_currentNode,3526,set$_currentNode,3526,_onSuiteStartedController,3527,_captured_f_0,3528,_requestedResources,3529,indexOf$2,3530,_precomputed4,3531,_consumeValue$0,3532,replaceAll$2,3533,_completer,3534,tags,3535,_captured_sdkRoot_3,3536,_previous,3537,needsSeparatorPattern,3538,_run,3539,get$_run,3539,set$_run,3539,replace$1$path,3540,_collection$_add,3541,get$_collection$_add,3541,_shlPositive$1,3542,_ensureController,3543,get$_ensureController,3543,_location,3544,get$_location,3544,_mayAddListener,3545,get$_mayAddListener,3545,_captured_terse_2,3546,_preGrow,3547,get$_preGrow,3547,evaluate$1,3548,_base,3549,_isWithinOrEqualsFast,3550,get$_isWithinOrEqualsFast,3550,_modified$0,3551,shouldBeDone,3552,get$shouldBeDone,3552,isBlink,3553,_currentCodePoint,3554,_addResult,3555,get$_addResult,3555,_source_map_stack_trace$_box_0,3556,typedMatches$2,3557,moveNext$0,3558,_execAnchored$2,3559,duration,3560,_onSinkDisconnected$0,3561,isCompleted,3562,get$isCompleted,3562,query,3563,get$query,3563,visitVariable$1,3564,bindCallback,3565,get$bindCallback,3565,_currentTrace,3566,get$_currentTrace,3566,sourceRoot,3567,take,3568,get$take,3568,_progressLine$2$suffix,3569,listenerHasError,3570,liveTests,3571,get$liveTests,3571,createPeriodicTimer,3572,_live_suite_controller$_onCloseCompleter,3573,_remote_listener$_captured_controller_0,3574,_onCancel$0,3575,pathsEqual,3576,get$pathsEqual,3576,distance,3577,get$distance,3577,_core$_position,3578,asStream$0,3579,abs$0,3580,verticalLine,1935,get$verticalLine,1935,listenerValueOrError,3581,_decrementPauseCount$0,3582,_html_common$_captured_this_1,3583,hasTrailingSeparator,3584,get$hasTrailingSeparator,3584,_stack_trace_formatter$_captured_this_0,3585,_declarer$_name,3586,_stack_zone_specification$_registerBinaryCallback$4,3587,_tail,3588,asUint8List$2,3589,isScaffoldAll,3590,_captured_test_1,3591,isWithin$2,3592,_platform_selector$_captured_validVariables_0,3593,_functions$_box_0,3594,_passed,3595,addTearDown$1,3596,_iterator,3597,hashMapCellValue,3598,_captured_K1_1,3599,lastSpan,3600,get$lastSpan,3600,_environment,3601,registerCallback$1$1,3602,handleUncaughtError$3,3603,_stack_zone_specification$_captured_this_1,3604,allMatches$2,3605,_position,3606,_expr,3607,_data,3608,_suiteChannel,3609,_captured_suite_1,3610,onListen,3611,_recursiveMatch$4,3612,_writeSidebar$2$end$line,3613,_onCancelBroadcast$0,3614,__internal$_iterable,3615,_buffer,3616,_flush$0,3617,_captured_identifier_0,3618,_invoker$_print$1,3619,handleUncaughtError,3603,get$handleUncaughtError,3603,scan,3620,get$scan,3620,onCancel,3621,_schedule$0,3622,_metadata,3623,_colorize$1,3624,_captured_sdkRoot_2,3625,_target,3626,_multiline,3627,_paddingBeforeSidebar,3628,_startIndex,3629,get$_startIndex,3629,_specializedTestResource,3630,_isInt32$1,3631,_contains,3632,get$_contains,3632,_handleError$3,3633,_modified,3551,get$_modified,3551,_runPool,3634,_setPendingComplete$0,3635,_simpleExpression$0,3636,_rootRunUnary$5,3637,_cloneResult$1,3638,_trimVMChain,3639,get$_trimVMChain,3639,_live_test_controller$_run,3640,get$_live_test_controller$_run,3640,_collection$_first,3641,_serializeTimeout,3642,get$_serializeTimeout,3642,relative$1,3643,_collectTraces,3644,_span_exception$_message,3645,_onRun,3646,join,3647,get$join,3647,_stack_zone_specification$_errorCallback$5,3648,_stack_zone_specification$_registerUnaryCallback$4,3649,_closeMemo,3650,change$4$onPlatform$skip$skipReason$timeout,3651,addAll$1,3652,_isPaused,3653,get$_isPaused,3653,previous,3654,_async$_addError$2,3655,_captured_minified_4,3656,_queryStart,3657,_captured_eagerError_4,3658,_captured_T_2,3659,join$8,3647,whenComplete$1,3660,position,3661,get$position,3661,set$position,3661,_newLinkedCell$2,3662,asCurrent$1$1,3663,addDescriptionOf$1,3664,_captured_orElse_1,3665,_captured_subscription_0,3666,_count,3667,_isPort,3513,get$_isPort,3513,_eval,3668,get$_eval,3668,_addEventError,3669,get$_addEventError,3669,_optionalPositional,3670,encode,3494,get$encode,3494,_writeToList$1,3671,getRoot$1,3510,_hasPending,3672,get$_hasPending,3672,_test,3673,_runner_suite$_captured_this_0,3674,_captured_zone_0,3675,_invoker$_controller,3676,setRange$4,3677,write$1,3678,_captured_maxItems_0,3679,_isClosed,3680,_closeInnerChannel$0,3681,_closable,3682,get$_closable,3682,update,3683,get$update,3683,_newSet,3511,get$_newSet,3511,_post_message_channel$_captured_controller_0,3684,_collection$_current,3685,set$_collection$_current,3685,_thenAwait$1$2,3686,_upgrade$0,3687,_fetch,3688,get$_fetch,3688,isNewSegment,3689,where$1,3378,_semantics,3690,internalFindBucketIndex,3691,get$internalFindBucketIndex,3691,_stack_zone_specification$_registerCallback$4,3692,_cachedLine,3693,_live_suite_controller$_controller,3694,_cancel,3695,get$_cancel,3695,isPassing,3696,get$isPassing,3696,_lineStart,3697,_noColor,3698,_forEachListener$1,3699,_isDebugging,3700,fillRange$3,3701,_second,3702,removeTrailingSeparators,3703,get$removeTrailingSeparators,3703,_errorName,3704,get$_errorName,3704,_union_set_controller$_set,3705,set$_union_set_controller$_set,3705,visitAnd$1,3706,_pool$_closeMemo,3707,_chainFuture,3708,get$_chainFuture,3708,declare$1,3709,needsSeparator$1,3710,second,3711,get$second,3711,_isCanceled,3712,get$_isCanceled,3712,handleNext$1,3713,_disjoint,3714,_liveTest,3715,_ensurePendingEvents$0,3716,failed,3717,get$failed,3717,_parse$1,3718,_lastMatch,3719,replaceRange$3,3720,_carry,3721,expand$1$1,3722,_stack_zone_specification$_captured_this_0,3723,isAbsolute,3724,get$isAbsolute,3724,peek,3725,get$peek,3725,_captured_object_1,3726,_rootRegisterCallback$4,3727,_doneCompleter,3728,isValue,3729,get$isValue,3729,distance$1,3577,_defaultSplit$1,3730,_execGlobal$2,3731,_simpleExpression,3636,get$_simpleExpression,3636,_onResourceReleaseAllowed$1,3732,topLeftCorner,1932,get$topLeftCorner,1932,_shrBothPositive$1,3733,_captured_longest_0,3734,_stack_zone_specification$_registerCallback,3692,get$_stack_zone_specification$_registerCallback,3692,_captured_error_0,3735,_remove$1,3736,_string,3737,padRight$1,3738,_async$_iterator,3739,set$_async$_iterator,3739,success,3740,get$success,3740,_stack_zone_specification$_captured_stackTrace_2,3741,_pendingIds,3742,_toNonSimple,3743,get$_toNonSimple,3743,_captured_spec_6,3744,readChar$0,3745,scaleFactor,3746,__js_helper$_string,3747,_stream_group$_controller,3748,set$_stream_group$_controller,3748,_serializeGroup,3749,get$_serializeGroup,3749,microsecond,3750,get$microsecond,3750,_checkNotBuilt,3751,get$_checkNotBuilt,3751,_computeKeys$0,3752,binaryOnError,3753,_or$0,3754,_captured_computation_1,3755,_execAnchored,3559,get$_execAnchored,3559,_findBucketIndex,3756,get$_findBucketIndex,3756,release,3757,get$release,3757,_runner_suite$_close$0,3758,union,3759,get$union,3759,_iterable,3760,_setRangeFast$4,3761,_captured_countSuccess_2,3762,_map,3763,internalSet$2,3764,_checkModification$1,3765,single,3766,get$single,3766,_captured_K_2,3767,joinAll$1,3768,configure,3484,get$configure,3484,_isEmpty,3769,get$_isEmpty,3769,load,3770,get$load,3770,pipe,3771,get$pipe,3771,identicalInJs$2,3772,_asyncCompleteError,3773,get$_asyncCompleteError,3773,_lazy_trace$_trace,3774,get$_lazy_trace$_trace,3774,hashCode,3775,get$hashCode,3775,_pool,3776,onError$1,3472,decrement$0,3777,registerUnaryCallback,3778,get$registerUnaryCallback,3778,_maxAllocatedResources,3779,isComplete,3780,get$isComplete,3780,indexable,3781,hasTokens,3782,get$hasTokens,3782,_html$_onData,3783,set$_html$_onData,3783,__js_helper$_strings,3784,pathSegments,3785,get$pathSegments,3785,_green,3786,_captured_registered_1,3787,describeTypedMismatch$4,3788,_expected,3789,parse,2447,get$parse,2447,whenFalse,3790,decode$2$reviver,3791,_captured_f_1,3792,any$1,3793,convert,3794,get$convert,3794,[]=,3795,get$[]=,3795,_future_group$_completer,3796,_add$1,3797,_fetch$1,3688,matchTypeError$1,3798,_last,3799,unclosable,3800,get$unclosable,3800,replace,3540,get$replace,3540,containsKey$1,3801,_runGroup$3,3802,_queue_list$_grow$0,3803,_captured_predicate_0,3804,minute,3805,get$minute,3805,_parser$_length,3806,_setUpAllTrace,3807,codeUnitAt,3808,get$codeUnitAt,3808,modifiedObject,3809,_captured_completer_0,3810,newJsObject$0,3811,active,3812,get$active,3812,_lastProgressSuffix,3813,_captured_index_1,3814,padRight,3738,get$padRight,3738,_dedupIterable,3815,get$_dedupIterable,3815,_eval$1,3668,_live_suite_controller$_captured_this_0,3816,endsWith,3817,get$endsWith,3817,_captured_streamConsumer_0,3818,removeLast$0,3819,urls,3820,_captured_hasError_3,3821,_remote_listener$_captured_this_1,3822,_varData,3823,_name,3824,_coverage,3825,_endIndex,3826,get$_endIndex,3826,codeUnitsEqual,3827,get$codeUnitsEqual,3827,_captured_s_2,3828,toTrace,3829,get$toTrace,3829,_segmentError$2,3830,_closeGroup,3831,bindUnaryCallback,3832,get$bindUnaryCallback,3832,_collection$_length,3833,_runner_suite$_controller,3834,_js_util$_captured_T_1,3835,_delegationTarget,3836,storedCallback,3837,_solo,3838,get$_solo,3838,round$0,3839,_bind$1,3840,errorCallback$2,3841,_captured_V1_3,3842,_allowMalformed,3843,lastIndexOf,3844,get$lastIndexOf,3844,_expanded$_onError,3845,get$_expanded$_onError,3845,_setUpAll,3846,get$_setUpAll,3846,_core_matchers$_description,3847,_callback,3848,_skip,3849,dart2jsArgs,3850,cancel,3476,get$cancel,3476,skipWhile$1,3389,group$1,587,_subscription_stream$_captured_error_1,3851,_resultOrListeners,3852,relativeRootPattern,3853,_onError,3854,get$_onError,3854,_createController$0,3855,_collection$_previous,3856,_setError$2,3857,_isNearCachedLine,3858,get$_isNearCachedLine,3858,convert$3,3794,_setBase,3859,get$_setBase,3859,_compareIterables$5,3860,add$1,3861,bindUnaryCallback$2$1,3832,_listenToStream,3862,get$_listenToStream,3862,_html_common$_box_0,3863,visitNot$1,3864,upEnd,1916,get$upEnd,1916,complete,3865,get$complete,3865,cast,3866,get$cast,3866,_skippedGroup,3867,_type_matcher$_name,3868,lastIndexOf$1,3844,_errorExplanation,3869,get$_errorExplanation,3869,close$0,3870,highlight$1$color,3871,_onCancelBroadcast,3614,get$_onCancelBroadcast,3614,_mappings,3872,putIfAbsent,3873,get$putIfAbsent,3873,_captured_performance_0,3874,_completeError$2,3499,isFinite,3875,get$isFinite,3875,runSkipped,3876,get$runSkipped,3876,isUnicode,3877,get$isUnicode,3877,_upgrade,3687,get$_upgrade,3687,span$2,3376,addError$1,3878,toChain$0,3879,__js_helper$_map,3880,_captured_this_1,3881,setUpAll,3882,_noRetry,3883,spanFor$4$files$uri,3884,_errorCallback,3885,get$_errorCallback,3885,set$_errorCallback,3885,_captured_onData_0,3886,count,3887,whenComplete,3660,get$whenComplete,3660,_isComplete,3888,get$_isComplete,3888,_captured_span_2,3889,_captured_groups_2,3890,setAll$2,3891,_onValue,3892,get$_onValue,3892,setDestinationSink$1,3893,_getNext$0,3894,packageConfigMap,3895,get$packageConfigMap,3895,_captured_tables_0,3896,writeln$1,3897,registerUnaryCallback$2$2,3778,_printPlatform,3898,skip$1,3441,_trace,3899,_mayResumeInput,3900,get$_mayResumeInput,3900,invalidValue,3901,_recordPause,3902,get$_recordPause,3902,_captured_T1_3,3903,_span_scanner$_scanner,3904,_bold,3905,_file$_start,3906,noMoreLiveTests$0,3907,change,3651,get$change,3651,_unlisten$0,3908,_engine$_runCalled,3909,_string_scanner$_position,3910,removeFragment$0,3911,_released,3912,_setValue$1,3913,firstMatch$1,3914,_captured_originalSource_0,3915,union$1,3759,liveSuite,3916,get$liveSuite,3916,_next,3917,_internal,3918,_isFile,3919,get$_isFile,3919,isLoadSuite,3920,get$isLoadSuite,3920,where,3378,get$where,3378,_streamController,3921,set$_streamController,3921,unclosable$1$1,3800,_addEventListener,3922,get$_addEventListener,3922,_endOrLength,3923,resolveUri$1,3924,__js_helper$_addHashTableEntry,3925,get$__js_helper$_addHashTableEntry,3925,whenTrue,3926,serialize$0,2631,highlight$0,3871,isEmpty,3927,get$isEmpty,3927,_multiLineComment,3928,get$_multiLineComment,3928,_iterable_set$_base,3929,_checkState,3930,get$_checkState,3930,_captured_future_3,3931,addAll$4,3652,_thenAwait,3686,get$_thenAwait,3686,_inCallback,3932,get$_inCallback,3932,_expanded$_captured_this_0,3933,files,3934,splitMapJoin,3935,get$splitMapJoin,3935,visitNot,3864,get$visitNot,3864,toFilePath$0,3936,internalRemove$1,3937,toolString,3938,get$toolString,3938,toString,3379,get$toString,3379,_failClosed$0,3939,_toListFixed$0,3940,glyphOrAscii,1931,get$glyphOrAscii,1931,_captured_platform_0,3941,_lazy_trace$_captured_this_0,3942,remaining,3943,_captured_portStart_1,3944,_conditional,3945,get$_conditional,3945,_equals_matcher$_match,3946,get$_equals_matcher$_match,3946,_pathSegments,3947,set$_pathSegments,3947,firstWhere,3948,get$firstWhere,3948,floor,3949,get$floor,3949,padLeft$2,3950,_captured_R_5,3951,_trace$_captured_longest_0,3952,onMessage,3953,get$onMessage,3953,_addedSuites,3954,_captured_host_0,3955,_captured_skipped_1,3956,_expanded$_color,3957,_stack_zone_specification$_run,3958,get$_stack_zone_specification$_run,3958,change$1$onPlatform,3651,_mergePaths$2,3959,getText$2,3960,_declarer$_trace,3961,_captured_handleError_1,3962,_isHttp,3963,get$_isHttp,3963,_lastProgressPassed,3964,month,3965,get$month,3965,apply$1,3966,_captured_outstandingCallbacksForBody_1,3967,_createController,3855,get$_createController,3855,_badEventState$0,3968,_captured_validVariables_0,3969,canonicalizePart$1,3970,forEach,3005,get$forEach,3005,toRadixString$1,3971,message$2$color,3370,_asyncCompleteError$2,3773,join$2,3647,update$2,3683,_collection$_cell,3972,_simpleMerge,3973,get$_simpleMerge,3973,_runLiveTest$2,3974,_addRequest$1,3975,_removeHashTableEntry,3976,get$_removeHashTableEntry,3976,_onResourceReleaseAllowed,3732,get$_onResourceReleaseAllowed,3732,validate$1,3977,_queue_list$_table,3978,set$_queue_list$_table,3978,_future_group$_pending,3979,matchesErrorTest,3980,get$matchesErrorTest,3980,_removeListener,3981,get$_removeListener,3981,hasErrorTest,3982,get$hasErrorTest,3982,_expanded$_onDone$1,3983,_onPause$0,3984,packageConfigUri,3985,_lastProgressSkipped,3986,_engine$_box_0,3987,_check,3988,isRelative$1,3989,_captured_selector_0,3990,_retry,3991,_input,3992,addEventListener$3,3366,nextIteration,3993,_timeString$1,3994,pointSpan$0,3995,variableName,3996,_schemeCache,3997,insert,3998,get$insert,3998,day,3999,get$day,3999,_lazy_trace$_captured_predicate_1,4000,putIntoMap$3,4001,_live_test_controller$_state,4002,lines,4003,get$lines,4003,_recordCancel$1,4004,_sendError$2,4005,_newHashTable,4006,get$_newHashTable,4006,removeFirst$0,4007,_runOnRelease$1,4008,_findColumn,4009,get$_findColumn,4009,_removeListeners$0,4010,trim,4011,get$trim,4011,_stream_queue$_close$0,4012,_queue_list$_head,4013,indexOf$1,3530,__js_helper$_index,4014,isDartVM,4015,_stream_sink_completer$_sink,4016,get$_stream_sink_completer$_sink,4016,_flush,3617,get$_flush,3617,virtualChannel$0,4017,listeners,4018,_host,4019,_stream_queue$_subscription,4020,set$_stream_queue$_subscription,4020,_addRequest,3975,get$_addRequest,3975,bindCallbackGuarded,4021,get$bindCallbackGuarded,4021,handleError$1,3357,containsSeparator$1,4022,inMinutes,4023,get$inMinutes,4023,endColumn,4024,_streamCompleter,4025,right,4026,setRange$3,3677,hasAbsolutePath,4027,get$hasAbsolutePath,4027,_mergePaths,3959,get$_mergePaths,3959,_re,4028,varData,4029,expand$1,3722,onComplete,4030,get$onComplete,4030,_get,4031,get$_get,4031,toUri,4032,get$toUri,4032,_fragmentStart,4033,_outgoingConnections,4034,hasPort,4035,get$hasPort,4035,_collection$_modified,4036,get$_collection$_modified,4036,runtime,4037,getLine,4038,get$getLine,4038,_countTabs$1,4039,_nativeAnchoredRegExp,4040,_waitsForCancel,4041,get$_waitsForCancel,4041,file,2764,run$1$1,4042,_captured_ex_0,4043,errorZone,4044,get$errorZone,4044,foundResult,4045,relative$2$from,3643,_onSuiteAddedController,4046,_captured_future_2,4047,run$0,4042,virtualChannel,4017,get$virtualChannel,4017,_setSourceStream$1,4048,_incomingConnections,4049,_setUpAlls,4050,getColumn$1,4051,_element,4052,_errorTest,4053,get$_errorTest,4053,_argumentsExpr,4054,schedule$1,4055,_collection$_captured_result_0,4056,_sinkCompleter,4057,_eventScheduled,4058,get$_eventScheduled,4058,_writeTrailingLines,4059,get$_writeTrailingLines,4059,removeTrailingSeparators$0,3703,rootLength$2$withDrive,4060,_live_suite_controller$_captured_liveTest_1,4061,normalize$1,4062,_closableKey,4063,_live_test_controller$_controller,4064,isSync,4065,_parent,4066,source,4067,scheduleMicrotask,302,get$scheduleMicrotask,302,_engine$_runLiveTest$3$countSuccess,4068,_isPendingComplete,4069,get$_isPendingComplete,4069,message$1,3370,_captured_line_0,4070,copyList$2,4071,_writeSurrogate$2,4072,_serializeTest,4073,get$_serializeTest,4073,_fillBuffer$3,4074,toJson$0,4075,_writeLastLine,4076,get$_writeLastLine,4076,_schedule,3622,get$_schedule,3622,addOutstandingCallback,4077,get$addOutstandingCallback,4077,_codeUnitAt$1,4078,chainFor$1,4079,_serializeTimeout$1,3642,~/,4080,get$~/,4080,print$1,412,_addHashTableEntry$2,4081,$package,4082,get$$package,4082,_stack_zone_specification$_registerBinaryCallback,3587,get$_stack_zone_specification$_registerBinaryCallback,3587,isHeadless,4083,completeError,4084,get$completeError,4084,verboseChain,4085,containsSeparator,4022,get$containsSeparator,4022,_addHashTableEntry,4081,get$_addHashTableEntry,4081,_declarer$_parent,4086,_stream_group$_subscriptions,4087,listen$4$cancelOnError$onDone$onError,4088,describeMismatch$4,4089,closed,4090,get$closed,4090,_streamQueue,4091,_runSetUps$0,4092,_captured_indent_0,4093,_checkPosition$3,4094,_prefix$1,4095,_linkStreamToController,4096,get$_linkStreamToController,4096,setSourceStream,4097,get$setSourceStream,4097,targetUrl,4098,_and,3516,get$_and,3516,peek$0,3725,__js_helper$_message,4099,inMilliseconds,4100,get$inMilliseconds,4100,_async$_previous,4101,set$_async$_previous,4101,_captured__convertedObjects_0,4102,_entries,4103,_setPendingEvents,4104,get$_setPendingEvents,4104,listen$2$onDone,4088,_captured_node_2,4105,addDescriptionOf,3664,get$addDescriptionOf,3664,__internal$_length,4106,_guardIfGuarded$1,4107,scan$1,3620,_runOnRelease,4008,get$_runOnRelease,4008,done,4108,get$done,4108,_platformVariables,4109,_isOnlyWhitespace$1,4110,isJS,4111,isEof,4112,sourceLine,4113,_runSetUps,4092,get$_runSetUps,4092,matchesErrorTest$1,3980,_f,4114,isBroadcast,4115,get$isBroadcast,4115,_captured_invoker_0,4116,_remote_listener$_box_0,4117,_conditional$0,3945,_tearDowns,4118,_close,4119,get$_close,4119,endsWith$1,3817,_nextId,4120,addAll,3652,get$addAll,3652,_captured_liveTest_0,4121,_engine$_closed,4122,_writeText,4123,get$_writeText,4123,matchAsPrefix,4124,get$matchAsPrefix,4124,_guarded,4125,_lazy_trace$_inner,4126,set$_lazy_trace$_inner,4126,_runGroup,3802,get$_runGroup,3802,__js_helper$_unlinkCell$1,4127,describe,3396,get$describe,3396,setSourceStream$1,4097,_failed,4128,_stack_zone_specification$_box_0,4129,_lazy_chain$_captured_this_0,4130,_colorize,3624,get$_colorize,3624,relativePathToUri,4131,get$relativePathToUri,4131,_isChained,4132,get$_isChained,4132,newJsMap$0,4133,_allocatedResources,4134,_color,4135,_mayAddEvent,4136,get$_mayAddEvent,4136,_group$_map$1,4137,_multi_channel$_captured_this_1,4138,_computeHashCode$1,4139,_complete$1,4140,_async$_captured_result_2,4141,_ensurePendingEvents,3716,get$_ensurePendingEvents,3716,_captured_e_1,4142,_null_stream_sink$_captured_this_0,4143,_captured_printZone_0,4144,_isAddingStream,4145,get$_isAddingStream,4145,_collection$_newLinkedCell,4146,get$_collection$_newLinkedCell,4146,_shrReceiverPositive,4147,get$_shrReceiverPositive,4147,fragment,4148,get$fragment,4148,_sendData,4149,get$_sendData,4149,_pauseCount,4150,runUnary$2$2,4151,_upgradedMap,4152,get$_upgradedMap,4152,_scanner,4153,precompiledPath,4154,_html$_target,4155,_hashCodeCache,4156,runGuarded,4157,get$runGuarded,4157,_lastSpan,4158,toList,4159,get$toList,4159,_verboseTrace,4160,_whenCompleteAction,4161,get$_whenCompleteAction,4161,relativePathToUri$1,4131,replaceAllMapped$2,4162,_as,4163,_captured_counter_3,4164,_nativeGlobalRegExp,4165,allMatches,3605,get$allMatches,3605,_soloEntries,4166,_writeTrailingLines$1,4059,addSubscription,4167,_writeSurrogate,4072,get$_writeSurrogate,4072,increment$0,4168,_captured_R_4,4169,_onResourceReleased$0,4170,_strings,4171,_handle,4172,hasListener,4173,get$hasListener,4173,_ensureDoneFuture$0,4174,_stack_zone_specification$_handleUncaughtError$5,4175,_captured_printZone_1,4176,_invokerZone,4177,_captured_transform_1,4178,evaluate,3548,get$evaluate,3548,_findBucketIndex$2,3756,pause$0,4179,_compareSets$5,3508,runUnaryGuarded$1$2,4180,spanFrom,4181,get$spanFrom,4181,fold,3509,get$fold,3509,_config,4182,_runner_suite$_onClose,4183,_zone,4184,get$_zone,4184,_stream_sink_completer$_controller,4185,set$_stream_sink_completer$_controller,4185,_captured_textInside_1,4186,pipe$1,3771,[],4187,get$[],4187,_lastProgressMessage,4188,matches$2,3347,_captured_fn_2,4189,_ensureController$0,3543,lastPendingEvent,4190,inMicroseconds,4191,get$inMicroseconds,4191,joinAll,3768,get$joinAll,3768,visitConditional$1,4192,__internal$_index,4193,_stream_sink_completer$_doneCompleter,4194,inSeconds,4195,get$inSeconds,4195,_onStateChangeController,4196,_cachedRuntimeType,4197,_captured_controller_0,4198,packageResolver,4199,_captured_eagerError_2,4200,_captured_T2_4,4201,_onClose,4202,_groups,4203,_addEventError$0,3669,convertNativeToDart_AcceptStructuredClone$2$mustCopy,2104,_duration,4204,_addHashTableEntry$3,4081,_decodedChars,4205,parents,4206,parent,4207,get$parent,4207,skipWhile,3389,get$skipWhile,3389,runGuarded$1,4157,join$1,3647,_jsObject,4208,_captured_test_0,4209,_stream_group$_state,4210,startsWith$2,4211,_set,4212,get$_set,4212,absolute$1,4213,foreign,4214,get$foreign,4214,_collection$_add$1,3541,_hasError,4215,get$_hasError,4215,merge,4216,get$merge,4216,registerUnaryCallback$2$1,3778,firstWhere$2$orElse,3948,handleValue$1,4217,resolve,4218,get$resolve,4218,_message,4219,bindCallbackGuarded$1,4021,_updateRequests,4220,get$_updateRequests,4220,_delegateCache,4221,_recordCancel,4004,get$_recordCancel,4004,hasFragment,4222,get$hasFragment,4222,traces,4223,get$traces,4223,isScheduled,4224,get$isScheduled,4224,_union_set$_iterable,4225,get$_union_set$_iterable,4225,parse$0,2447,_onCloseCompleter,4226,isNotEmpty,4227,get$isNotEmpty,4227,_test$_captured_body_0,4228,hasScheme,4229,get$hasScheme,4229,_closedBeforeDone,4230,_span_exception$_span,4231,_captured_cleanUp_1,4232,_source,4233,fuse$1$1,4234,_isNearCachedLine$1,3858,_live_suite_controller$_suite,4235,_runTearDowns,4236,get$_runTearDowns,4236,rootLength,4060,get$rootLength,4060,trim$0,4011,_captured_elements_0,4237,addStream$2$cancelOnError,4238,_precomputed3,4239,_completeError$1,3499,_checkEventAllowed,4240,get$_checkEventAllowed,4240,_captured_terse_0,4241,patterns,4242,_setEmpty$0,4243,_fragment,4244,createTimer,4245,get$createTimer,4245,variables,4246,_chainFuture$1,3708,_onDebuggingController,4247,_captured_protected_0,4248,every,4249,get$every,4249,_trace$_captured_trace_0,4250,location$1,3343,perform,4251,get$perform,4251,completeError$1,4084,_captured_bodyFunction_0,4252,_allowInvalid,4253,change$1$timeout,3651,_countTabs,4039,get$_countTabs,4039,_pool$_captured_this_0,4254,outputId,4255,_onResume$0,4256,_extraUnits,4257,toUpperCase$0,4258,__js_helper$_addHashTableEntry$3,3925,_equals_matcher$_value,4259,_controller,4260,_multi_channel$_captured_this_0,4261,_group,4262,_addStreamSubscription,4263,set$_addStreamSubscription,4263,_queue_list$_add$1,4264,forEachJsField,4265,get$forEachJsField,4265,glyphOrAscii$2,1931,_writeLastLine$1,4076,_regExp,4266,__js_helper$_nums,4267,_getTableBucket,4268,get$_getTableBucket,4268,_convert$_computeKeys,4269,get$_convert$_computeKeys,4269,_mapping,4270,millisecondsSinceEpoch,4271,get$millisecondsSinceEpoch,4271,_cell,4272,_checkNotBuilt$1,3751,connectOut$1,4273,_sets,4274,_onUnpaused,4275,get$_onUnpaused,4275,_genericClosure,4276,_mapContents,4277,_captured_indent_2,4278,_innerStreamSubscription,4279,startsWith,4211,get$startsWith,4211,context,2361,get$context,2361,substring$1,4280,matchAsPrefix$2,4124,entries,4281,_multi_channel$_inner,4282,_fillBuffer,4074,get$_fillBuffer,4074,hasRun,4283,get$hasRun,4283,forEachJsField$2,4265,_stack_zone_specification$_onError,4284,elapsedTicks,4285,get$elapsedTicks,4285,_onTestStartedGroup,4286,tearDownAll,4287,_matcher,4288,_engine,4289,_onSinkDisconnected,3561,get$_onSinkDisconnected,3561,containsKey,3801,get$containsKey,3801,_captured_future_0,4290,_captured_getTag_0,4291,error$3$length$position,2966,names,4292,internalContainsKey$1,4293,_runTearDowns$0,4236,_captured_start_2,4294,_addStreamState,4295,set$_addStreamState,4295,_extractStream,4296,get$_extractStream,4296,cancel$0,3476,setState$1,4297,substring,4280,get$substring,4280,clear,4298,get$clear,4298,errorCallback$3,3841,_stop,4299,_stream_group$_closed,4300,os,4301,hasPartialInput,4302,get$hasPartialInput,4302,_getBucket,4303,get$_getBucket,4303,_timeout,4304,parts,4305,set$parts,4305,_pathDirection,4306,get$_pathDirection,4306,describeTypedMismatch,3788,get$describeTypedMismatch,3788,findSlot$1,4307,_scheduleMicrotask,4308,get$_scheduleMicrotask,4308,set$_scheduleMicrotask,4308,_loadPool,4309,_canSendDirectly,4310,get$_canSendDirectly,4310,local,4311,get$local,4311,hour,4312,get$hour,4312,packageRoot,4313,get$packageRoot,4313,_endOfFileEmitted,4314,_captured_callback_0,4315,_captured_terse_1,4316,_future_group$_closed,4317,_convert$_value,4318,readSlot$1,4319,fork,4320,get$fork,4320,elementAt$1,4321,_runUnary,4322,get$_runUnary,4322,set$_runUnary,4322,writeAll$2,4323,_captured_callback_3,4324,_captured_arg_1,4325,_progressLine$2$color,3569,writeSlot$2,4326,_async$_next,4327,set$_async$_next,4327,toChain,3879,get$toChain,3879,_hashCode,4328,_onListen,4329,get$_onListen,4329,_captured_sourceResult_2,4330,runOnce$1,4331,_reviver,4332,_invoker$_captured_this_1,4333,toList$1$growable,4159,innerStream,4334,expect$2$name,539,_thunk,4335,_writeToList,3671,get$_writeToList,3671,_ensureListening$0,4336,_chains,4337,visitConditional,4192,get$visitConditional,4192,_captured_listener_1,4338,_failClosed,3939,get$_failClosed,3939,startColumn,4339,matchTypeError,3798,get$matchTypeError,3798,status,4340,toString$0,3379,_runLiveTest,3974,get$_runLiveTest,3974,_removeAfterFiring,4341,get$_removeAfterFiring,4341,_multi_channel$_box_0,4342,_eventType,4343,_head,4344,url,2360,resume,4345,get$resume,4345,__js_helper$_removeHashTableEntry$2,4346,_removeListeners,4010,get$_removeListeners,4010,codeUnitsEqual$2,3827,_match,4347,_isFiring,4348,get$_isFiring,4348,includeTags,4349,_pathDirection$2,4306,_stack_zone_specification$_registerBinaryCallback$3$4,3587,add,3861,get$add,3861,_current,4350,set$_current,4350,_selector2,4351,toString$1$color,3379,_rti,4352,_asyncComplete,4353,get$_asyncComplete,4353,request,4354,get$request,4354,_sendData$1,4149,_gray,4355,listen$3$onDone$onError,4088,matches,3347,get$matches,3347,_stack_zone_specification$_errorCallback,3648,get$_stack_zone_specification$_errorCallback,3648,toFilePath,3936,get$toFilePath,3936,setRange,3677,get$setRange,3677,_except,4356,set$_except,4356,_engine$_subscriptions,4357,_subscription_stream$_source,4358,set$_subscription_stream$_source,4358,_sdkRoot,4359,_recordResume$1,4360,scheme,4361,get$scheme,4361,_expectedUnits,4362,_captured_column_0,4363,convertDartToNative_PrepareForStructuredClone$1,1533,_closeGap$2,4364,_highlighter$_buffer,4365,_sink$_sink,4366,$call,3391,get$$call,3391,map$2$1,4367,_parser0$_scanner,4368,_bindCache,4369,__internal$_name,4370,_only,4371,set$_only,4371,removeEventListener$3,4372,_setTableEntry,4373,get$_setTableEntry,4373,_live_test_controller$_close$0,4374,toTrace$0,3829,_queryParameters,4375,resolveUri,3924,get$resolveUri,3924,__js_helper$_length,4376,_engine$_captured_this_1,4377,_pretty_print$_box_0,4378,addMapping$1,4379,absolute,4213,get$absolute,4213,_out,4380,_captured_R_3,4381,_async$_isClosed,4382,get$_async$_isClosed,4382,flush,4383,get$flush,4383,_captured_getMain_1,4384,_onStateChange,4385,get$_onStateChange,4385,_captured_K1_2,4386,toLowerCase$0,4387,heartbeat$0,4388,_writeFirstLine,3519,get$_writeFirstLine,3519,registerBinaryCallback$3$1,4389,_method,4390,_collection$_writeToList$1,4391,contains$1,4392,_writeSidebar$1$line,3613,removeOutstandingCallback$0,4393,_functions$_captured_value_1,4394,_prependListeners,4395,get$_prependListeners,4395,_core$_data,4396,_chain$_captured_callback_0,4397,_inner,4398,_fork,4399,get$_fork,4399,set$_fork,4399,_extractStream$0,4296,catchError,3514,get$catchError,3514,_nextIndex,4400,_captured_uri_0,4401,_maps,4402,_async$_addError,3655,get$_async$_addError,3655,_bufferIndex,4403,_red,4404,_unlinkCell,4405,get$_unlinkCell,4405,forEachObjectKey,4406,get$forEachObjectKey,4406,isRootRelative$1,4407,addStream,4238,get$addStream,4238,_restarted,4408,_captured_validVariables_1,4409,_doneFuture,4410,_original,4411,_registerCallback,4412,get$_registerCallback,4412,set$_registerCallback,4412,foldFrames$2$terse,4413,normalize$0,4062,_captured_channel_3,4414,_onMessageController,4415,separatorPattern,4416,_isFirstCharacter,4417,_errorZone,4418,contains,4392,get$contains,4392,addStreamFuture,4419,_built,4420,_requiredPositional,4421,_captured_test_2,4422,_table,4423,set$_table,4423,_deleteTableEntry$2,4424,split$1,4425,padLeft,3950,get$padLeft,3950,_group$_captured_callback_0,4426,_listen$1,4427,_parser$_mapUrl,4428,validatePlatformSelectors$1,4429,_shrBothPositive,3733,get$_shrBothPositive,3733,_async$_map,4430,get$_async$_map,4430,hasEmptyPath,4431,get$hasEmptyPath,4431,sublist,4432,get$sublist,4432,_stream,4433,_invoker$_onRun$0,4434,complete$1,3865,_subscribe,4435,get$_subscribe,4435,_captured_x_0,4436,_sourceStream,4437,set$_sourceStream,4437,_completeWithValue$1,3488,_chainStackTraces,4438,_setDestinationSink$1,4439,internalFindBucketIndex$2,3691,addTearDownAll$1,4440,_live_suite_controller$_isComplete,4441,_captured_result_0,4442,_captured_expectedElement_1,4443,getColumn,4051,get$getColumn,4051,_package_config_resolver$_uri,4444,_reverseListeners$1,4445,_collection$_last,4446,findSlot,4307,get$findSlot,4307,_captured_timeout_0,4447,walk$1,4448,_userInfo,4449,formatStackTrace$2$verbose,4450,replaceRange,3720,get$replaceRange,3720,_addResult$1,3555,remove,4451,get$remove,4451,_queue_list$_add,4264,get$_queue_list$_add,4264,_captured_listener_2,4452,__js_helper$_keys,4453,_encoder,4454,runBinary,4455,get$runBinary,4455,_cancelFuture,4456,_future_group$_captured_this_0,4457,handlesComplete,4458,get$handlesComplete,4458,_trace$_box_0,4459,_captured_pos_1,4460,sublist$2,4432,_invoker$_test,4461,get$_invoker$_test,4461,_metadata$_captured_timeout_2,4462,_guarantee_channel$_box_0,4463,cancelSchedule$0,4464,sourceNameId,4465,runtimeType,4466,get$runtimeType,4466,_collection$_modifications,4467,then,4468,get$then,4468,absolute$7,4213,_captured_maxLineLength_1,4469,_subsetMask,4470,_recordResume,4360,get$_recordResume,4360,_forEachListener,3699,get$_forEachListener,3699,testRandomizeOrderingSeed,4471,visitOr,4472,get$visitOr,4472,expect,539,get$expect,539,_lastProgressFailed,4473,internalContainsKey,4293,get$internalContainsKey,4293,splitMapJoin$2$onMatch,3935,_getTableBucket$2,4268,writeln,3897,get$writeln,3897,_convert$_first,4474,_expanded$_onError$3,3845,_removeListener$1,3981,millisecond,4475,get$millisecond,4475,_highlighter$_captured_this_1,4476,validatePlatformSelectors,4429,get$validatePlatformSelectors,4429,_preGrow$1,3547,configure$2$except$only,3484,request$0,4354,_rootRegisterUnaryCallback$4,4477,_async$_captured_f_1,4478,_remote_listener$_captured_this_0,4479,reversed,4480,get$reversed,4480,_queryParameterLists,4481,hasErrorCallback,4482,get$hasErrorCallback,4482,_scanOperator,3518,get$_scanOperator,3518,_captured_testOn_1,4483,split,4425,get$split,4425,left,4484,_listenToStream$1,3862,_live_test_controller$_isClosed,4485,get$_live_test_controller$_isClosed,4485,_codeUnitAt,4078,get$_codeUnitAt,4078,_highlighter$_captured_this_0,4486,_html$_start$0,4487,_chain,4488,get$_chain,4488,_addingStream,4489,_getTableCell$2,4490,forTarget$1,4491,_captured_minified_2,4492,connectOut,4273,get$connectOut,4273,peekChar,4493,get$peekChar,4493,_collection$_next,4494,_equals_matcher$_match$3,3946,cast$2$0,3866,build,4495,get$build,4495,_engine$_runLiveTest$2,4068,_segmentError,3830,get$_segmentError,3830,_process$1,4496,_precomputed2,4497,lastMatch,4498,get$lastMatch,4498,_description,4499,get$_description,4499,_captured_chainStackTraces_5,4500,startsWith$1,4211,_captured_printZone_5,4501,decoder,4502,get$decoder,4502,hasAuthority,4503,get$hasAuthority,4503,unaryOnError,4504,_needsNormalization$1,4505,_collection$_modified$0,4036,onResume,4506,build$0,4495,_or,3754,get$_or,3754,_printPath,4507,_tdivSlow$1,4508,withResource$1$1,3430,_writeText$1,4123,handleNext,3713,get$handleNext,3713,__js_helper$_rest,4509,_paused,4510,_tearDownAll,4511,get$_tearDownAll,4511,_captured_result_3,4512,_lazy_trace$_thunk,4513,waitForOutstandingCallbacks,4514,get$waitForOutstandingCallbacks,4514,_mayComplete,4515,get$_mayComplete,4515,_captured_T_5,4516,$function,4517,_offset,4518,_asyncComplete$1,4353,load$2$groups,3770,_captured_value_1,4519,runUnaryGuarded,4180,get$runUnaryGuarded,4180,bindUnaryCallbackGuarded$1$1,4520,_sendDone$0,4521,_outstandingCallbacks,4522,get$_outstandingCallbacks,4522,extensions,4523,_closeUnchecked,4524,get$_closeUnchecked,4524,_toListGrowable$0,4525,_captured_end_2,4526,_invoker$_captured_this_0,4527,_convert$_computeKeys$0,4269,codeUnits,4528,get$codeUnits,4528,mapStackTrace$1,487,_precomputed1,4529,_stack_zone_specification$_captured_f_1,4530,insert$2,3998,floor$0,3949,internalGet$1,4531,_names,4532,internalGet,4531,get$internalGet,4531,pattern,4533,_captured_stackTrace_1,4534,_liveSuite,4535,_collection$_newLinkedCell$1,4146,then$1$2$onError,4468,_consumeNewLine$0,4536,_live_test_controller$_close,4374,get$_live_test_controller$_close,4374,_newHashTable$0,4006,_metadata$_box_0,4537,suiteSink,4538,get$suiteSink,4538,_port,4539,_passedGroup,4540,_hostStart,4541,_isWithinOrEquals$2,4542,_unlisten,3908,get$_unlisten,3908,_expanded$_captured_liveTest_1,4543,_live_suite_controller$_closeMemo,4544,_captured_target_0,4545,_captured_host_1,4546,_uriCache,4547,_nativeAnchoredVersion,4548,get$_nativeAnchoredVersion,4548,relative,3643,get$relative,3643,_consumeWhitespace,4549,get$_consumeWhitespace,4549,_scanOr$0,4550,_tryResume,4551,get$_tryResume,4551,_runner_suite$_suite,4552,set$_runner_suite$_suite,4552,bind$1,2478,toSet,4553,get$toSet,4553,_captured_level_1,4554,sourceColumn,4555,_nextListener,4556,connectIn$2,4557,_isCaseSensitive,4558,get$_isCaseSensitive,4558,_progressLine,3569,get$_progressLine,3569,_body,4559,waitForOutstandingCallbacks$1,4514,_description$1,4499,encoder,4560,get$encoder,4560,metadata,4561,get$metadata,4561,_isInputPaused,4562,get$_isInputPaused,4562,inHours,4563,get$inHours,4563,allowRelease$1,4564,serialize,2631,get$serialize,2631,_captured_getUnknownTag_0,4565,_invoker$_completer,4566,intersection$1,4567,_ensureDoneFuture,4174,get$_ensureDoneFuture,4174,state,4568,get$state,4568,_state,4569,reportLiveTest$2$countSuccess,4570,_clearPendingComplete$0,4571,_captured_timeout_2,4572,_mapUrl,4573,_controllers,4574,forEachObjectKey$2,4406,fromUri$1,1988,_tearDownAllTrace,4575,_chain$_captured_T_1,4576,_highlighter$_box_0,4577,_multi_channel$_captured_T_2,4578,_subscriptions,4579,every$1,4249,_captured_V_2,4580,_captured_original_1,4581,formatStackTrace,4450,get$formatStackTrace,4450,_subscription_stream$_captured_this_0,4582,_newLinkedCell,3662,get$_newLinkedCell,3662,_stream_queue$_captured_this_0,4583,_runCalled,4584,_testCount,4585,onDone$1,4586,_isInitialState,4587,get$_isInitialState,4587,_stack_zone_specification$_registerUnaryCallback$2$4,3649,isEven,4588,get$isEven,4588,completeError$2,4084,_checkState$1,3930,_types,4589,get$_types,4589,_stack_zone_specification$_registerUnaryCallback,3649,get$_stack_zone_specification$_registerUnaryCallback,3649,_closeInnerChannel,3681,get$_closeInnerChannel,3681,root,4590,_writeIntermediateLines$1,4591,library,4592,get$library,4592,_multiLineComment$0,3928,_hasValue,4593,member,4594,get$member,4594,addStream$1,4238,_lastSubscription,4595,set$_lastSubscription,4595,_onListen$0,4329,dartException,4596,==,3446,get$==,3446,_schemeEnd,4597,__js_helper$_captured_this_0,4598,isPosix,4599,get$isPosix,4599,_hasSkipped,4600,heartbeat,4388,get$heartbeat,4388,_cancel$0,3695,_isUpgraded,4601,get$_isUpgraded,4601,_writeSidebar$0,3613,_print,4602,get$_print,4602,set$_print,4602,_tryResume$0,4551,_rootRegisterBinaryCallback$4,4603,_recordPause$1,3902,_useCapture,4604,firstMatch,3914,get$firstMatch,3914,_captured_port_0,4605,pause$1,4179,type,4606,get$type,4606,_scanIdentifier$0,4607,substring$2,4280,_onDone,4608,set$_onDone,4608,_computeKeys,3752,get$_computeKeys,3752,origin,4609,get$origin,4609,bindUnaryCallbackGuarded,4520,get$bindUnaryCallbackGuarded,4520,convert$1,3794,_multi_channel$_parent,4610,%,4611,get$%,4611,_keysArray,4612,get$_keysArray,4612,runUnary,4151,get$runUnary,4151,_sourceFile,4613,_captured_skip_3,4614,registerBinaryCallback,4389,get$registerBinaryCallback,4389,insertAll$2,4615,_platform_selector$_inner,4616,_captured_pp_0,4617,_engine$_captured_this_0,4618,_eventState,4619,child,4620,forTag,4621,_channel,4622,_captured_iterator_0,4623,checkMutable$1,4624,_captured_controller_3,4625,flush$2,4383,replaceFirst$2,4626,_binarySearch$1,4627,transform$1$1,4628,_mapper,4629,start$0,2491,replace$2$path$pathSegments,3540,_tdivFast$1,4630,_captured_oldPredicate_0,4631,_exception,4632,replace$1$pathSegments,3540,_captured_arg2_2,4633,toUri$1,4032,_suite,4634,isIdentifier,4635,get$isIdentifier,4635,convertNativeToDart_AcceptStructuredClone,2104,get$convertNativeToDart_AcceptStructuredClone,2104,_primary,4636,then$1$1,4468,removeAt,4637,get$removeAt,4637,_captured_div_1,4638,__internal$_current,4639,set$__internal$_current,4639,__js_helper$_current,4640,set$__js_helper$_current,4640,_removeEventListener,4641,get$_removeEventListener,4641,_optionalNamed,4642,onDone,4586,get$onDone,4586,reportLiveTest,4570,get$reportLiveTest,4570,_isSent,4643,get$_isSent,4643,_receiver,4644,forPlatform$1,4645,_runner_suite$_close,3758,get$_runner_suite$_close,3758,_delegate,4646,get$_delegate,4646,firstPendingEvent,4647,inSameErrorZone$1,4648,expect$1,539,intersection,4567,get$intersection,4567,horizontalLine,1933,get$horizontalLine,1933,frames,4649,get$frames,4649,onError,3472,get$onError,3472,_span,4650,_captured_channel_2,4651,group,587,get$group,587,_currentExpansion,4652,set$_currentExpansion,4652,_union_set_controller$_sets,4653,_async$_captured_this_0,4654,_serializeTest$3,4073,_isUnicode,4655,get$_isUnicode,4655,_shlPositive,3542,get$_shlPositive,3542,_lazy_trace$_captured_terse_2,4656,spanFor,3884,get$spanFor,3884,peekChar$0,4493,_writeSidebar,3613,get$_writeSidebar,3613,_expanded$_onDone,3983,get$_expanded$_onDone,3983,_span_exception$_source,4657,__internal$_start,4658,_modifications,4659,_nextPosition,4660,_toEncodable,4661,hasMatch$1,4662,_bind,3840,get$_bind,3840,_canFire,4663,get$_canFire,4663,postMessage$1,4664,_setPendingEvents$1,4104,internalComputeHashCode,4665,get$internalComputeHashCode,4665,_isOnlyWhitespace,4110,get$_isOnlyWhitespace,4110,_outstandingCallbackZones,4666,_captured_zone_1,4667,_isWithinOrEqualsFast$2,3550,rootPattern,4668,_captured_id_1,4669,pause,4179,get$pause,4179,_platform_selector$_span,4670,decode$1,3791,replaceFirst,4626,get$replaceFirst,4626,isUtc,4671,_postMessage_2$1,4672,set,4673,get$set,4673,pathFromUri,4674,get$pathFromUri,4674,_hasOneListener,4675,get$_hasOneListener,4675,_activeLoadTests,4676,_containsTableEntry$2,4677,_restartable_timer$_timer,4678,_recursiveMatch,3612,get$_recursiveMatch,3612,_pendingEvents,4679,get$_pendingEvents,4679,_addError$2,4680,_captured_prototypeForTag_0,4681,_nullErrorHandler$1,4682,_captured_cleanUp_3,4683,+,4684,get$+,4684,_chainSource,4685,get$_chainSource,4685,_complete,4140,get$_complete,4140,_portStart,4686,_isWithinOrEquals,4542,get$_isWithinOrEquals,4542,_printZone,4687,_multi_channel$_captured_T_1,4688,_captured_frame_0,4689,_columnStart,4690,_functions$_captured_result_0,4691,_addLiveSuite$1,4692,_pattern,4693,_onStreamDisconnected$0,4694,describeMismatch,4089,get$describeMismatch,4089,_stackTrace,4695,elapsed,4696,get$elapsed,4696,_process,4496,get$_process,4496,_closeChannel$2,3493,accept$1,4697,_containsTableEntry,4677,get$_containsTableEntry,4677,_async$_subscription,4698,get$_async$_subscription,4698,_packageResolver,4699,_eventsReceived,4700,_isMultiLine,4701,get$_isMultiLine,4701,_errors,4702,_index,4703,onZero,4704,get$onZero,4704,internalRemove,3937,get$internalRemove,3937,_captured_chain_0,4705,_runSkippedTest,4706,get$_runSkippedTest,4706,take$1,3568,visitAnd,3706,get$visitAnd,3706,_captured__prettyPrint_1,4707,_shrReceiverPositive$1,4147,removeAll$1,4708,apply,3966,get$apply,3966,_captured_arg1_1,4709,_callOnCancel$0,4710,firstWhere$1,3948,spanFrom$1,4181,_binarySearch,4627,get$_binarySearch,4627,_computeHashCode,4139,get$_computeHashCode,4139,_onCompleteGroup,4711,last,4712,get$last,4712,_getNext,3894,get$_getNext,3894,_channelNames,4713,sourceUrl,4714,get$sourceUrl,4714,_async$_onListen$1,4715,_resetTimer,4716,get$_resetTimer,4716,runBinary$3$3,4455,pathsEqual$2,3576,_currentTrace$1,3566,perform$1,4251,_liveSuites,4717,_stream_channel_completer$_set,4718,_file$_end,4719,forPlatform,4645,get$forPlatform,4645,_captured_value_2,4720,remove$1,4451,_gatherCoverage,4721,_isHttps,4722,get$_isHttps,4722,_closeUnchecked$0,4524,_captured_result_1,4723,removeFragment,3911,get$removeFragment,3911,_closedIds,4724,_captured_channel_0,4725,isNewLine,4726,handleUncaughtError$2,3603,elementAt,4321,get$elementAt,4321,highlight,3871,get$highlight,3871,_runCount,4727,close,3870,get$close,3870,_add,3797,get$_add,3797,_union_set$_captured_this_0,4728,_runSkipped,4729,_skipped,4730,_stack_zone_specification$_captured_R_2,4731,_writeIntermediateLines,4591,get$_writeIntermediateLines,4591,_isPackage,4732,get$_isPackage,4732,_findLine$1,3524,_expectsEvent$1,4733,_validateTags,4734,get$_validateTags,4734,copy,4735,_captured_error_2,4736,bottomLeftCorner,1937,get$bottomLeftCorner,1937,_addPending$1,4737,_stringSink,4738,expand,3722,get$expand,3722,_get$1,4031,_progressLine$1,3569,toRadixString,3971,get$toRadixString,3971,resolve$1,4218,insertAll,4615,get$insertAll,4615,remainder$1,4739,_inAddStream,4740,get$_inAddStream,4740,_pool$_captured_registered_1,4741,_captured_serialized_0,4742,_addError$1,4680,_onReleaseCompleters,4743,_functions$_captured_result_1,4744,inGoogle,4745,runBinaryGuarded$2$3,4746,_allowErrors,4747,_captured_body_0,4748,registerBinaryCallback$3$2,4389,_createSubscription$4,4749,condition,4750,map,4367,get$map,4367,checkGrowable$1,4751,moveNext,3558,get$moveNext,3558,absolutePathToUri$1,4752,_runtimes,4753,_captured_loadResource_2,4754,_collection$_rest,4755,_addError,4680,get$_addError,4680,registerCallback$1$2,3602,_setRemoveAfterFiring$0,4756,_sink,4757,set$_sink,4757,_captured_retry_6,4758,internalComputeHashCode$1,4665,_linkStreamToController$0,4096,_context$_current,4759,_onResume,4256,get$_onResume,4256,_registerBinaryCallback,4760,get$_registerBinaryCallback,4760,set$_registerBinaryCallback,4760,_ensureListening,4336,get$_ensureListening,4336,_stream_completer$_controller,4761,set$_stream_completer$_controller,4761,isCore,4762,get$isCore,4762,_setDestinationSink,4439,get$_setDestinationSink,4439,_captured_line_1,4763,_invoker$_onRun,4434,get$_invoker$_onRun,4434,getOffset,4764,get$getOffset,4764,listen$1,4088,indexOf,3530,get$indexOf,3530,_createPeriodicTimer,4765,get$_createPeriodicTimer,4765,set$_createPeriodicTimer,4765,_pool$_timeout,4766,mustCopy,4767,_firstSubscription,4768,set$_firstSubscription,4768,_scanner$_next,4769,foldFrames,4413,get$foldFrames,4413,_callOnCancel,4710,get$_callOnCancel,4710,onTestStarted,4770,get$onTestStarted,4770,_scanAnd$0,4771,__js_helper$_removeHashTableEntry,4346,get$__js_helper$_removeHashTableEntry,4346,_sendDone,4521,get$_sendDone,4521,_once,4772,absolutePathToUri,4752,get$absolutePathToUri,4752,_query,4773,config,4774,get$config,4774,_future,4775,removeFirst,4007,get$removeFirst,4007,_subscribe$4,4435,next,4776,get$next,4776,set$next,4776,_removeEventListener$3,4641,style,4777,_invoker$_tearDowns,4778,map$1$1,4367,_contains$1,3632,__js_helper$_getBucket$2,4779,_execGlobal,3731,get$_execGlobal,3731,_removeHashTableEntry$2,3976,complete$0,3865,_stopwatch,4780,decode,3791,get$decode,3791,addOutstandingCallback$0,4077,internalSet,3764,get$internalSet,3764,_getBucket$2,4303,join$0,3647,toSet$0,4553,_active,4781,_rootRun$4,4782,_remove,3736,get$_remove,3736,decrement,3777,get$decrement,3777,_guardCallback,4783,get$_guardCallback,4783,_onTestStartedController,4784,isAbsolute$1,3724,path,4785,get$path,4785,_async$_target,4786,_handleError,3633,get$_handleError,3633,_captured_K2_0,4787,_knownTags,4788,_tick,4789,_onReleaseCallbacks,4790,schedule,4055,get$schedule,4055,_captured_suite_0,4791,_pathStart,4792,_platform_selector$_captured_platform_0,4793,_restartable_timer$_duration,4794,_captured_portSubscription_1,4795,_badEventState,3968,get$_badEventState,3968,_guarantee_channel$_captured_this_0,4796,setEmpty$0,4797,_invalidPosition$3,4798,visitVariable,3564,get$visitVariable,3564,_containsKey$1,4799,_lastMatchPosition,4800,_captured_onPlatform_8,4801,_captured_predicate_1,4802,_addListener$1,4803,_mainController,4804,_colorize$2$color,3624,_guarantee_channel$_captured_this_1,4805,_invoker$_box_0,4806,_length,4807,typedMatches,3557,get$typedMatches,3557,_sendError,4005,get$_sendError,4005,nextKind,4808,get$nextKind,4808,_collection$_box_0,4809,isRootRelative,4407,get$isRootRelative,4407,_subscription,4810,set$_subscription,4810,addTo$1,4811,_tdivFast,4630,get$_tdivFast,4630,_uri,4812,isDone,4813,get$isDone,4813,_stateData,4814,setChannel$1,4815,_writeSidebar$1$end,3613,_captured_R_2,4816,_stream_channel_completer$_channel,4817,set$_stream_channel_completer$_channel,4817,runes,4818,get$runes,4818,_jsWeakMapOrKey,4819,_containsKey,4799,get$_containsKey,4799,_trimVMChain$1,3639,_queue,4820,_null_stream_sink$_closed,4821,_lineStarts,4822,listen,4088,get$listen,4088,_eventQueue,4823,bindCallback$1$1,3565,_engine$_runLiveTest,4068,get$_engine$_runLiveTest,4068,isSeparator$1,4824,_arguments,4825,_disconnected,4826,_validateTags$0,4734,_context,4827,_createSubscription,4749,get$_createSubscription,4749,_captured_stream_1,4828,_indexFor$2,4829,scheduleMicrotask$1,302,_cancelOnError,4830,get$_cancelOnError,4830,runOnce,4331,get$runOnce,4331,_tdivSlow,4508,get$_tdivSlow,4508,needsSeparator,3710,get$needsSeparator,3710,rest,4831,get$rest,4831,_rest,4832,errorCallback,3841,get$errorCallback,3841,rootLength$1,4060,_captured_stackTrace_2,4833,downEnd,1915,get$downEnd,1915,group$9$onPlatform$retry$skip$solo$tags$testOn$timeout,587,_onPause,3984,get$_onPause,3984,release$0,3757,_guardCallback$1,4783,forEach$1,3005,_stream_subscription$_source,4834,_checkEventAllowed$0,4240,_stack_zone_specification$_run$1$2,3958,_toFilePath$0,4835,sourceUrlId,4836,_shrOtherPositive,4837,get$_shrOtherPositive,4837,_closed,4838,_onIdleController,4839,_value,4840,_captured_error_1,4841,writeCharCode$1,4842,_close$0,4119,_tearDownAlls,4843,addError,3878,get$addError,3878,_captured_sourceMap_1,4844,walk,4448,get$walk,4448,_self,4845,onStateChange,4846,get$onStateChange,4846,addError$2,3878,_timeoutTimer,4847,currentChain$1,4848,_print_sink$_buffer,4849,_live_test_controller$_suite,4850,string,4851,_engine$_captured_liveTest_1,4852,isBrowser,4853,getOffset$1,4764,_suiteController,4854,_canonicalRecipe,4855,_canceled,4856,get$_canceled,4856,_nativeGlobalVersion,4857,get$_nativeGlobalVersion,4857,_pending,4858,set$_pending,4858,_queue_list$_tail,4859,_createTimer,4860,get$_createTimer,4860,set$_createTimer,4860,passed,4861,get$passed,4861,_onData,4862,set$_onData,4862,change$2$skip$skipReason,3651,_getTableCell,4490,get$_getTableCell,4490,_captured_action_1,4863,_captured_body_1,4864,_stream_group$_captured_this_0,4865,_captured_liveTest_1,4866,addEventListener,3366,get$addEventListener,3366,_captured_beforeLoad_4,4867,spanFor$3$files,3884,_printsOnFailure,4868,merge$1,4216,_writeAuthority$1,4869,_runSkippedTest$3,4706,spanFor$3$uri,3884,current,621,get$current,621,_onTimeout$0,4870,_onStateChange$2,4385,startChunkedConversion$1,4871,next$0,4776,accept,4697,get$accept,4697,handleWhenComplete$0,4872,_addStreamCompleter,4873,_group$_map,4137,get$_group$_map,4137,_captured_K_1,4874,runBinaryGuarded,4746,get$runBinaryGuarded,4746,_toNonSimple$0,3743,normalize$3,4062,getOffset$2,4764,clear$0,4298,inputId,4875,cloneNotRequired$1,4876,first,4877,get$first,4877,matches$1,3347,_handleError$2,3633,shuffle$1,4878,_pauseCompleter,4879,newJsList$1,4880,createTimer$2,4245,_registerUnaryCallback,4881,get$_registerUnaryCallback,4881,set$_registerUnaryCallback,4881,key,4882,_first,4883,_captured_T_1,4884,name,4885,get$name,4885,_simpleMerge$2,3973,_postMessage_1$2,4886,_addEventListener$3,3922,_resetTimer$0,4716,_consumeWhitespace$0,4549,_keys,4887,_live_test_controller$_run$0,3640,allMatches$1,3605,onPause,4888,fork$2$specification$zoneValues,4320,_captured_data_1,4889,isSeparator,4824,get$isSeparator,4824,withResource,3430,get$withResource,3430,hasQuery,4890,get$hasQuery,4890,_nums,4891,_setErrorObject$1,4892,_collection$_source,4893,handlesValue,4894,get$handlesValue,4894,_progressLine$3$color$suffix,3569,_stack_zone_specification$_captured_R_3,4895,_captured_channel_1,4896,run,4042,get$run,4042,getLine$1,4038,_stack_zone_specification$_registerCallback$1$4,3692,seen,4897,_lazy_chain$_inner,4898,set$_lazy_chain$_inner,4898,_selector1,4899,_consumeNewSegment$0,4900,lastIndexOf$2,3844,_urlSafe,4901,input,4902,_subscription_stream$_captured_stackTrace_2,4903,_reverseListeners,4445,get$_reverseListeners,4445,normalize,4062,get$normalize,4062,isRunning,4904,get$isRunning,4904,postMessage,4664,get$postMessage,4664,round,3839,get$round,3839,_deleteTableEntry,4424,get$_deleteTableEntry,4424,prettyUri$1,3506,_trace$_captured_level_1,4905,_selector,4906,virtualChannel$1,4017,_pause$0,4907,_isScheme$1,4908,_onStreamDisconnected,4694,get$_onStreamDisconnected,4694,_parsed_path$_captured_this_0,4909,_declarer$_captured_this_0,4910,_isSourceStreamSet,4911,get$_isSourceStreamSet,4911,_local,4912,set$_local,4912,length,4913,get$length,4913,set$length,4913,separator,4914,get$separator,4914,_captured_T_3,4915,_captured_handleError_0,4916,toList$0,4159,_serializeGroup$3,3749,fillRange,3701,get$fillRange,3701,_setChained$1,4917,_yellow,4918,visitOr$1,4472,_captured_location_2,4919,describe$1,3396,removeLast,3819,get$removeLast,3819,registerCallback,3602,get$registerCallback,3602,validate,3977,get$validate,3977,cleanupSlots$0,4920,max$2,470,_captured_depth_3,4921,_jsTrace,4922,codeUnitAt$1,3808,_captured_dispatch_1,4923,_end,4924,__js_helper$_unlinkCell,4127,get$__js_helper$_unlinkCell,4127,_captured_matcher_0,4925,addTo,4811,get$addTo,4811,_modificationCount,4926,_processed,4927,_timer,4928,_writeString$1,4929,_cloneResult,3638,get$_cloneResult,3638,_captured_platform_1,4930,_fail$1,4931,isClosed,4932,get$isClosed,4932,keys,4933,get$keys,4933,isPaused,4934,get$isPaused,4934,pathFromUri$1,4674,_onCancel,3575,get$_onCancel,3575,_captured_engine_0,4935,_set$2,4212,_setUps,4936,_expanded$_sink,4937,_grow$0,4938,text,4939,get$text,4939,any,3793,get$any,3793,_findColumn$3,4009,_onErrorController,4940,_text,4941,_captured_this_0,4942,copyList,4071,get$copyList,4071,_prependListeners$1,4395,handlesError,4943,get$handlesError,4943,_contents,4944,_captured_milliseconds_1,4945,_updateRequests$0,4220,_captured_sdkLib_3,4946,_initializeText$0,4947,_captured_trace_0,4948,_evalCache,4949,_closeGap,4364,get$_closeGap,4364,_limit,4950,_toggleEventId$0,4951,_live_suite_controller$_active,4952,_addLiveSuite,4692,get$_addLiveSuite,4692,_createNode$1,4953,copy$0,4735,toSpec$0,4954,userInfo,4955,get$userInfo,4955,_addListener,4803,get$_addListener,4803,excludeTags,4956,_indexFor,4829,get$_indexFor,4829,_separatorIndices,4957,setState,4297,get$setState,4297,_captured_completer_1,4958,_is,4959,_shrOtherPositive$1,4837,_isUsed,4960,putIfAbsent$2,3873,_paddingAfterSidebar,4961,get$_paddingAfterSidebar,4961,code,4962,sink,4963,get$sink,4963,_captured_skipReason_7,4964,_destinationSink,4965,set$_destinationSink,4965,_values,4966,_suite$_metadata,4967,_addLoadSuite$1,4968,_captured_message_1,4969,_compareIterables,3860,get$_compareIterables,3860,values,4970,get$values,4970,_nativeRegExp,4971,chainFor,4079,get$chainFor,4079,_setTableEntry$3,4373,removeAt$1,4637,_isDefined,4972,_isDone,4973,resume$0,4345,_isDotAll,4974,get$_isDotAll,4974,_unlinkCell$1,4405,offset,4975,get$offset,4975,putIntoObject$3,4976,copies,4977,print,412,get$print,412,_runBinary,4978,get$_runBinary,4978,set$_runBinary,4978,_addPending,4737,get$_addPending,4737,_start,4979,_onTestStarted$1,3482,_stream_queue$_source,4980,year,4981,get$year,4981,_requestQueue,4982,_needsNormalization,4505,get$_needsNormalization,4505,$le,4983,$indexSet,4984,$index,4985,$xor,4986,$or,4987,$eq,4988,$mod,4989,$shr,4990,$and,4991,$ge,4992,$gt,4993,$lt,4994,$mul,4995,$not,4996,$shl,4997,$div,4998,$sub,4999,$add,5000,$negate,5001,$tdiv,5002"},"frames":"qsTAyEiB+2EuH;eAEFmduF;mXEqKbndAAAAAwR,A;iQAuHeAsI;eAEFmdwG;uEAohBwBnd8B;qEAEFAqC;oEAEDAoC;w7GGrpBvBAyEAhOXA6B,A;u1CC+YE4hF8F;qxCA0MSCuB;uCAAAA6B;wIAqBeC6B;0YAYjBD4C;uyHA4NQ7tBgB;+5DA8Ya/zD4C;igBAmBjByIyD;oFAOEAyD;eAIJzI2C;iEASAA6C;uPAmCcDoC;urCA4QZA+S;wnJAgSHAoE;iJAKKA0B;qLAWaAwH;oLASbA0B;sOAiCmBA4B;6HAGtBA4B;iRAmCCxzEAIn4BNu1JkF,gE;wEJq4BKC+C;6CACEA4B;0IAUDx1JAIh5BNu1J8D,yD;oDJk5BMC4B;2kBAmBHhiFAKj9D0BA8E,A;q1BLqlEtBA6D;AAEAA0Q;w+IAwPmCiiF0C;8EAAAA+E;wZAYXAwC;8EAAAAuD;49DAkGJA+J;AACICyL;w6CAsI7B70JACnsEF80JiD,sB;0GDusEE90JACvsEF80JiD,sB;qQDyuEcniF+G;0iCAgbMoiFgG;+dA6BjBpiFqC;qNAqBAAkD;m4BIt6FN+hFgC;OAEKtzJmBArBwB4zJY,wC;wEAyBVAM;wDAKnBCqC;sYAOACwF;AAhBK9zJAAtBFszJiB,A;AAsCHQ2B;sFAIACgE;AApBK/zJAAtBFszJiB,A;AA0CHS2B;iCACiB9zJAAwYd8zJsE,A;AA7ZE/zJAAtBFszJmB,A;AA2CcrzJAAwYd8zJ6B,2C;8xCA9VC5zJAAq2BN6zJqB,A;4zDAhxBKViC;0BAGmB/hFuC;4DACWxzE0C;4EAGpBw1J4C;8PAqDsBlzJAHmW7B4zJ6BAjBR3zJAA3I8B4zJuD,A,A,A;OGvMO7zJ+D;6NAWXizJkC;AACbaiE;qDAEXbyC;iFASKa0C;gJA0HLt0Ja;0BAAAA2D;oKAygBwByzJkC;gnEF/1BnB1yJAA2BTwzJoI,A;kTAZSxzJAAYTwzJoI,A;6yCApEuBlzJAAzChBmzJwE,A;0zDA+QSjzJsL;0gCKjNhBmwEAAAAAqG,A;+WCpESusEwB;+IAGyBnbkB;0bA0BhBxsDO;qfAuBPm+E+F;sCACFCiC;gBAGTCqF;6vBA2CODiC;0YAyBPhkDADKQh/B4B,mE;2CCLRlwDsC;wCACEi/Fc;+EACAAI;2EAGFAc;kmBA8DkCm0CgB;AAA1BFoC;0EAGRCqF;grPP/KkDEyC;AAA3BCY;AACfCyE;AADeD2B;m8CAySPEmB;qDAGVCmD;AAEW3/E0H;4FAIT4/EuD;yiBAcOCiC;+WAaMCAAqnCiBCAA/C9B//EiH,A,A;OAtkCa8/EuE;2PAMAGAAqnCjBCAAnDIlgFiH,A,A;OAlkCaigFuE;2PAMAGAAqnCjBCAAvDIrgFiH,A,A;OA9jCaogFuE;uUAQkCG2C;+HAGpCC+C;geAUMCqD;wvBAiBNbsD;mUAOCcgD;qiCAgCGC6B;ymCA+B0BCAA5ORxkFkD,A;AA6OrBykFmE;AAEACmE;AAEACmD;ycAgCd51JAAzB0B4zJsB,A;+NAgD5BxwJAAnD+BwwJmB,A;AAoD1BtwJ0B;mhCA8EkBtDAA/HK4zJoM,A;8MAoJpBrxJqF;2LAoBRszJsB;AADG5kFgB;8EAOkB1uE4C;iHAsCVmyJ6D;AAKXtrJ0E;AAIE0sJiB;AADACQ;yDAGalhFgI;+UAaGugF2DAxlBGYqB,A;6FAkmBfC4H;AAMNCmB;+HAWGCgC;6IAQOCiC;uBAKVhzJAAvR+BwwJiB,A;83BA8T/BuC8E;u2BA6BgBvjFiC;sOAQAAiC;+1IAmKXxpE8C;oPAUYksJkEAp1BDUiB,A;mnDAk5BLtBiC;gQASU2BkC;wGAKICkC;wGAKAlCkC;sHAKTgBkC;8VAcSXmC;4IAOXc2CA36BISsC,A;+4BA0mCLO4F;u4BAwCCCmB;8CAGVC+B;+UAUUlCmB;8CAGVC+C;AAEuB3/E0H;6jBAgDZAkI;AACjB6hF0B;AASIXQ;yCACADW;2CACAIQ;yPAyDGSAAIOlBAArvCHxkF4C,A,AAsvCP2lFqB,GACAC2C,A;gQAwBGCAAKOrBAApxCHxkF4C,A,AAqxCP2lFwB,AACAG4B,GACAF2C,A;qSASGGAAKOvBAAryCHxkF4C,A,AAsyCP2lFsB,AACAGyB,GACAF2C,A;2QASqBhiFiI;wTAYF2gF4B;OAEE3gFiI;mKAqBZoiF2K;iFAINCAAKOzBAA71CHxkF4C,A,AA81CP2lFqB,AACAG4B,AACAIyC,wBAGE7CsC,GAEFuC6B,A;8LAuBInCc;yBACQWoE;uKAIH+BAAlBEviF0H,kF;iFAsBRwiFAAKO5BAA14CHxkF4C,A,AA24CP2lFsB,AACAG8B,AACAI6B,GACAN6B,A;6TA8CSSAAxCPziFyJ,AACJ0iF2xB,gC;mFA2CKCAAKO/BAAr8CHxkF4C,A,AAs8CP2lFsB,AACAGiC,AACAI2B,GACAN+B,A;oMAaSYAAPP5iF0H,sE;mFAWC6iFAAKOjCAA/9CHxkF4C,A,AAg+CP2lFsB,AACAGuC,AACAIuB,GACAN+B,A;4ZAoKOcoD;itBAuBCCyL;qDAIkBrBiE;qDAIAsBiE;sDAIACiE;2DAItBCAAqERCmC,AACACuB,A;2DAlEQCkBA4GWC2BAmFACmB,4DAEnBHsC,A,imB;sPAtLsBtDAAjccCAA/C9B//EwI,A,+D;2IAwfgBigFAAncpBCAAnDIlgFwI,A,+D;2IA8fgBogFAArcpBCAAvDIrgFwI,A,+D;2DAigBEkjFAAiCRCmC,AACACuB,A;2DA9BQIkBAiG6C5CAApyDdxkFqJ,A,meA6zDvBknF2BAiCGCmB,4DAEnBHgD,A,AApCoBvCsD,AAEACmE,AACAC0D,wH;2DAxHZmCAAyBRCmC,AACACuB,A;0CAtBQKAA0HYH2BAyBDCmB,4DAEnBHqG,A,A;4DAjJQFAAiBRCmC,AACACuB,A;2CAdQMAAwHYC2BA0BDJmB,iEAEnBHqG,A,A;o9BAhHoDQsD;wJAUpCC4DAroBDhEgB,2BAEKW2F,AAGODiD,2X;0JAktBHuD4D;2DAIAC4D;uhCAsDTlEiC;wDAEcWqC;+OAQTA4D;w7BAuGJEwC;8GAKFbc;6CA6BI2BuC;yGAUJAkC;MAAAAAAxoEILmB,A;iGAipEA5BuC;sOAYIkCuC;0HAWKlCkC;oOAYIkCkC;4rBA4BS7B8CAvrEtBuBmB,A;AAwrEVvBwC;s9BAsBYa4CAxtEFUiB,A;AAytEEVsC;gkCA4BHuDa;iMAQAAa;+NASAAuC;oZAoBDC4B;+NAEJDiB;mSASKzD8C;iBACAA8C;gSAkBJyDyB;AACAAe;80BA0ECnEc;4NAYJU0CAp7EaYqB,A;AAo7EeZyC;2LAMxBC2CA96EIWqB,A;AA86EoBX0C;yJAMxBC2CA35EIUqB,A;AA25EmBV0C;yJAC/ByD6O;4DAIiBtE2CAt5ELuBqB,A;AAu5EJvB0C;qrCAqDDCc;+JAMON0C;w2FK1kFJ4EqG;oiBA+BhBC8C;grZUpF4B3+BuD;sMAmB9BrpD+C;4HAeAgNwD;4EAiFWhN2BA7BSioFAAAAjoFeE0BKlwDgB,2B,A,sC;2JFkBR4pFQ;y1BA2DM15BwBE7EElwDwD,A;AF6EFo4IqE;mdAiCXp4I0C;sJI9JckwD4BFgDDlwDgB,iC;AE/CjB61G4B;8IAyBkB3lD4BFsBDlwDgB,iC;saEORmwDoBFUmCnwDgB,uCAVpDo7DAAUAAAATEg9E6D,A,A,A;sKEEmBloFAFVIlwDwB,8D;gKEcfxVAAsrBuC0lEwC,A;0QA9oB3BlwDkC;8LAGRxVAA2oBmC0lEmE,A;qCAvoBpC09BoBFjDM5tFgB,iCADnB4tFAAAAAmD,A,A;6EE4HsC19B0KFvIblwD6D,A;kkBEuMRmwDAAlKJ27BoBFnCwC9rF+B,AAArD8rFAAAAAqB,A,A,A;uhBE0Q0BoDANsHMh/BiC,+BAAAAsC,A;iHMnFLA0CF/SFlwDoH,A;4TEgrBKAyD;mGAEpBxVAAkBuC0lEiE,A;uMF7rBjDkLAAAAAAACEg9EkF,A,A;oIAiOeCoB;sDAIfCqBArIOC4B,iC;6dAqKOCiE;uCAEICyF;uRAQhBCqBAvOKF6B,iE;ycAmUSHkC;8BACSMuB;+DAGYC2D;yjBA8BV3NkB;iEAaNt0EmB;kCAZIkiF8C;uDACGldiG;AAWPhlEsB;sDATgBiiFiBAvS9BD4B,2D;oIA8SiB34I0B;+BAEH22DqH;yFAoEJk5DkB;+lBAuBOwoB8B;AACFSiBA5SdT4B,iK;AA6SEUiBA/WFV4B,iBACMA+B,sG;gMA2XASqBA1TNTsB,sK;gFA+TJWAA9YIXsB,A;qBA2YJDsK;yBAGAYoH;mqCIrrBQCoD;+GAYqB/oF+D;4HAIrB+oFoD;yXAsBkB/oFyD;qZAwCPlwD2B;gNASrB27HM;iCAAAAgD;qLAKC37HsB;8HCuBKkwD+J;+JAQUy9BAC4SQz9BuE,A;+ED7OfA2B;wDAAAAsC;qGAs6DLA4D;OAAAAuD;qIClkEIAwG;AACAAuG;6TAwtBLlwDwD;0PChtBiB64IAAAA74I0D,A;sGAgBxBkwDqF;wKA+cKlwD6D;qXChjB2BA8C;wHAIhBxVAN84BiC0lE6F,A;u9BCj3BtClwDsB;2pDFwjCJk5IsE;weAYAAsE;wiBAYAAsE;2vBA0BmBvdc;iCAAAAwB;uoBA0BbwdAH/jCiB5/BmD,yB;OG+jCjB4/BoE;sEAIbCc;gFAIKp5IqC;4hBA0BMkwD8CArXXAAAAAAgQAcYA4D,gIAGAA4D,uIAGAA4D,sHAIAAmH,kUAeAAkG,sKAMAA6G,wC,A,A;u/BA4kBc6Mie;ygBAkBnB/8D0E;6/gBSr8CYkwD8C;+CAAAAwD;0cA4dAmpFAC/cPnpF4C,A;4GD+cOmpFAC/cPnpF+D,A;sMD4e+BmpFAC5e/BnpFuF,A;iFDofCmpFACpfDnpFqF,A;sEDupCOAqD;6EA8BmBAqD;sJAKPAuD;qGAqU7BkJ8H;2MA2GFlJAAAAAoD,A;u8BGz6CUo3DiH;wQAqBcp3DkD;iGAGpBo3DiG;oRAMKh7BkB;4gHGrPMp8BqD;gdAoBNo8BkB;uJCwdTp8BAAAAA4H,A;+kIC7ZaA2C;26IjCkDCopFwD;gVAwDMC8C;mmBAiOXC2D;iKAYACqC;6BAAAAc;qMAoBEC8E;OAAAAyH;yEAGACoH;yrCAoEHzpFuG;yMA+DQw+CsC;AAEDkrCc;uFAGFAc;0EAGEAkC;qhBA+GoBndAI3lBcqVuI,A;kGJkmBnCr+CyF;0TAKRo0CAA/Ja9lEiI,A;+7IsCnZf7RyG;+HClKFkpFwC;kZEixBkBSgQ;usGAAAA8D;8CAAAAqD;ovEA8NT3pFoG;82FAuUSAAlCrS4B4pFkD,A;sIkCqS5B5pFAlCrS4B4pFuC,A;24FkC6blCC4E;8RAcoBCgB;4GAENAuB;gOAOI14BA7B/jCR5S4D,A;8J6BokCTsrC+D;AACFtrCqB;8MASCqrCmC;y1BAgMQ3pD+G;AAApBlBAhD7pD8Bh/B2F,A;mCgD6pD9BlwD8B;00DAsDSg2FoE;szFAkNSzyBiI;6sBAsCPrTgK;uZAeIA2C;8TASX+uCAzC18CJg7CyC,A;sGyC88CaCoH;qBAAAA4F;wHAGIhqF+C;2rBAiBFA6C;2cAaRo8BkB;+nBA8BQp8B2C;icAWX+uCAzCxhDJg7CyC,A;iHyC4hDaEoH;qBAAAA4F;wHAGIjqF+C;uRAQJkqF0H;uBAAAAkG;+hBAWElqF+C;ymBAeRo8BkB;ggBAiBA+tDsH;mBAAAA0F;w6CAyCInwBA9B/6DAh6DwE,O;iC8B+6DAg6DA9B/6DAh6D4C,A;wC8Bm7DAw+CyB;gkDA0FP4rC4I;iBAAAAiF;uBAIYv4EqG;q+FAmGoBq4EgI;yBAAAAyH;w0BAiBrBlqF2C;8FAEX+uCgD;0VAWG3SkB;qbAoEKg1BA7B5iEU5SsB,A;4O6BkjEP4SA9Bt5DO5SmB,A;mI8Bw5DLA6B;osBAgCL4SA7BplEU5SsB,A;oO6B0lENA4E;obAYLAe;knEAiMX4YiH;s7CAwKuC6MA7BvgFVjkEwB,A;yoB6B6hFtBg2CoC;OAAAAAC31FAh2CyB,gB;2SDoyGL+uCAzCpyFFg7CoD,A;+KyC0yFEh7C6B;uHAEAAAzC5yFFg7C+B,A;AyC6yFEh7CwB;49EAgXa5xBuC;gpBAkBXw6DAzC1qGJoSoB,A;kByC0qGIpSAzC1qGa9lEM,AAAjBk4EkF,A;AyC4qGIpSAzC5qGa9lE+D,AAAjBk4E2B,A;AyC6qGIpSAzC7qGa9lEsC,A;wGyC6qGb8lEAzC7qGJoS2B,A;AyC8qGIpSAzC9qGa9lEM,AAAjBk4EkD,A;gxX2C3hB8B/pFgE;0EA6GdAA1BooBSAAFjvBvBAAAtB0B05BAAAA15BwBA4MLlwDgB,+C,A,A,kF,A;uoD8B0plCzBkwDAAAAAyB,A;0EA44GSlwDsB;wwECvssCsBu6IiBCEPpmBAnC6TOjkEoC,A,AmC7TpBs8BAA7BcguDyD,A,gDA6BdhuDAAaeiuDoB,0B,AAF1BjuD6C,A;urBCnBgBt8B2B;AAAwBw2DsB;yCAIG1mHsB;gTAUzCk+FsC;mHAAAA8D;AAAAhuC0BGpDkDwqFuE,AAISCgF,AAGtCCwE,A;iBH0HHn6BS;6VAcV6uBgBC/DgC7uBS,AAAQ6uBgB,A;wMDqExCAgBCrEgC7uBS,AAAQ6uBgB,A;qGDyEtBtvI+BKtInBAyB,wB;m8HEXmB66I+F;AAMACyC;AAOCCmC;AA4NVCAAAA9qFAC/NA+qFAAAA/qFAvCsvBQAAFjvBvBAAAtB0B05BAAAA15BAA4MLlwDsB,A,A,A,A,A,A,A,A;AwC5IzBkwDAAAAAwK,A;sDAgLmB8qFAAAA9qFoBC/NA+qFAAAA/qFAvCsvBQAsBFjvBvBAAAtB0B05BAAAA15BuG,A,A,A,A,A,A,A;yqC0CuBjBAqC;AAAiBg6DA9CiOjBh6DoD,O;6D8CjOiBg6DA9CiOjBh6DyD,A;+M8CjNUg6DA9CiNVh6DsD,A;O8CjNFAqC;AAAYg6DA9CiNVh6DoD,O;0E8CjNiBm8BkE;gDAAnBn8BAEmLUA8B,A;6IF9Hd8lCwD;0GAIFqnB+C;AAFArnByC;mDAEAqnBU;wFAEArnBoD;+CAMAAoD;uDAEAAoD;2EAKAqnB0C;AAHArnByC;2CAGAqnBU;m4IK8CiBH8E;giBA+BoBhtD2H;cACCA6F;8EAH9BAuF;AAjBbmdAAAAA4G,A;ibA6BAnbAAAAAuH,A;gxDAuD0CipFoB;6CACjCjrFc;89DGnKMkrFAAAAlrFACnDCmrF0D,AAvBGJAAAA/qFAjDsvBQAAFjvBvBAAAtB0B05BAAAA15BAA4MLlwD2H,A,A,A,A,A,A,A,A;AkDpGAu7I2E;AAwDCCAAAAttDmBEzIKutD4B,AAURCAAAArCAzCEXnpFoI,A,A,AyCiCZg+BAAAAAiCACcAA9C2DFh+BqC,A,mI,A,A,A;A4CoCS0rF4C;AAICC4C;AAIDC4C;AAILC8B;2DArFDXAAAAlrFkBC1EI+qFAAAA/qFAjDsvBQAsBFjvBvBAAAtB0B05BAAAA15BoH,A,A,A,A,A,A,A;AkD8FawrF4E;AAiBTM0C;AAUJCAAAA/tDA5CQlBh+BwG,A,A;A4CGmBisFuD;AAQCCAAAAluDA5CXpBh+B2H,A,A;A4CqDiBosF0C;AAMMCiD;AAgBnCrsFuE;6xIM/LcssF2E;yEAOdtsFAAAAAkCACSA4D,A,A;wbxBqMTmdAAAAAyIAG2B++D+B,+J,A;qGA0F3Bl8EAAAAAoJAGyBk8E+B,iR,A;qbYnPZl8E+G;4aAsBAAgB;gLAUqBA8B;8EAAAAgBAmHbA8B,A;gyBArGNsVAAOetV8B,+C;OAPfsVgBAOetVAA8FTA+B,A,A;ucAzFD8lCmE;0CACLmCuC;qDACR+xBAlE8BmCh6D2E,O;iCkE9BnCg6DAlE8BmCh6DwD,A;8PkEd3BkgC4C;6FACApDkF;qGAHT98ByB;AAOSg6D2E;iCAAAAoC;AAPTh6DAAyEeA+B,A;2EA5DfAyB;AAGSg6DAlE6P2B78CqB,A;AkE9P3BgfAhDuDFn8BoB,A;+DgDvDEm8BkC;iEACA69BmC;uFAHTh6DAA4DeA+B,A;4EA7CfAyB;AAISg6DAlE6O2B78CqB,A;AkE9O3BgfAhDuCFn8BoB,A;0FgDvCEm8BkC;kEACA69BmC;wFAJTh6DAA6CeA+B,A;wIAPFg6DAlE2MuB78CqB,A;AkE7MvBgfAhDMNn8BoB,A;0FgDNMm8BkC;mEAEA69BmC;oGAPbh6D2CAceA+B,A;2hFe9LbAqD;s/BCARAAAAAAqX,A;2cC6C4BusFiG;AAyBV5vDAAAA38BA3DqqBSAAFjvBvBAAAtB0B05BAAAA15BAA4MLlwD6B,A,A,A,A,A,A;0H6DhINy7IsC;AAMYkBAAAAzuDAvD8CnBh+BgG,A,A;AuDvCa2sFAAAA3uDAvDuCbh+BqG,A,A;AuDjCe6sFAAAA7uDAvDiCfh+BkG,A,A;AuD9BM28BAAAA38BA3DqqBSAsBFjvBvBAAAtB0B05BAAAA15B2E,A,A,A,A,A;A6D0H9BAAAAAAAAOcAE,wC,A;gsBCjIEAA5DuwBWAAFjvBvBAAAtB0B05BAAAA15BUA4MLlwDyG,A,A,A,A,A;A8D1MjBAmC;kCACAAQC0HMA0B,A;AD3HNAc;qEAFQkwDA5DuwBWA2D,A;8+DgE7vB3BAAAAAAuB,A;oCAAAAAAAAAkH,A;isBCoCmCoxDAtEoXX5SuB,A;AsEnXQx+C6D;yHAEAA2C;yJAAAAoD;OALvBAqC;iqFEWFunC4B;AACYz3FkD;8KAAAAiE;qBAAAA+B;80BE5Dfi9I0D;oIAMJn4CuDEsIoBwqC2B,AACZ3hD6CpC1IkCAA/Bgddz9B4B,oBAAAAiC,A,A,2B;4oEqEvYhBlwDYZqDEA0B,+B;0FYjDFAaZiDEA0B,A;AYrDFA+C;AAIQ64GAZODqkCmBAdQl9I2B,A,A;sBYOP64GkBZO8BhhBO/DhElB0gDuB,A,A;wsB2EsHCroF2B;8EAMX70DAE6JpB60D6CDjTwBitFAAAAjtFwB,A,A,4BCiTJo8BKDrSDAkB,A,A;2EDyICjxFAE4JpB60D6BDjTwBitFAAAAjtFwB,A,A,wBCiTJo8BKDrSDAkB,A,A;4FD0IXg1BA9EiRc5SwE,A;4B8EhRJ9BA1FyalBqtC2B,A;6R6FhkBFmDM;uDAMAAM;u+ER8EkCC8B;AAGEC8B;AAICCwD;AAGrCh2E6E;0GA0EuCi2EgF;AAIvCj2EwD;08BA4JAAuD;olGS1QoB8FgD;qlB8EkBpBnd6C;A5EpEAAAAAAA0Z,A;mmCC2FWmdAA9DyBowE8B,AAGGC8B,AAGAC8B,AAGtBCAAAA1tFc,4B,AAUiB2tF8B,AASLC8B,AAMIC6B,A;05FEqB3B/nD4D;2EACKA8C;gjBAmBuBgoDoM;UAAAA4E;+6CAgCvBtvCe;inEzC9DMx+CA0C7CG+tFAAAA/tFApGyDRguF0G,A,A,oCoGzDQDAAAA/tF6E,A,A;8F1CuDK2+E8T;sLAgCnBsPUA1FiDn+IiG,mD;AA0FpBm+IgBA1FoBn+IuC,A;AA0FpBmoIA0CvDIiWoCAgH/BluFO,uB,A;mB1CzD2Bi4EA0CvDIiWAAgH/BluF4B,A,W;uB1CtDKAgB;oOAoBPiuFAAjHiDn+IsB,wH;OAiHpBm+IWAjHoBn+I8B,A;mFAkHtBkwDqC;uEACpBAgB;2NASmBAS;0CAAAAyB;oIAEjBAqC;AACDg6DA/CwFDh6DyB,A;gE+CxFCg6DmC;kKAE8Bh6DqC;qGAE/BAqC;AACDg6DA/CmFCh6DyB,A;gE+CnFDg6DmC;kmJ4C1IG+NAzCdT/nE8B,A;oFyCcS+nEwB;urFGCSj4H+CRgDYA0B,qB;40C/CtCpCkwDAAAAA0KAI+By9BwD,AAAiC2hDiD,cADvD+OoB,AACsB1wDA7BqaHz9BuF,A,A6BraoCo/EA7B0alCp/E2G,A,gB6BzanBmuFoB,AACoB1wDA7BmaHz9BuF,A,A6BnaoCo/EA7BwalCp/EyH,A,A,A;6uBsFtXXouFwF;uBAIVpuFc;6lCfOIioCuF;mnBAuLI/H2D;kCAAjBlBAnG7QgCh/B2F,A;+CmG6QhClwDoC;0MgBvOyBu+IAAAAruFA1CjBTmrFU,AAvBGJAAAA/qFAjDsvBQAAFjvBvBAAAtB0B05BAAAA15BAA4MLlwD4F,A,A,A,A,A,A,A,A;A6F3ICw+IAAAAtuFA3FssBCAAFjvBvBAAAtB0B05BAAAA15BAA4MLlwDmI,A,A,A,A,A,A;uC6FnJAu+IAAAAruFkB1CxCN+qFAAAA/qFAjDsvBQAsBFjvBvBAAAtB0B05BAAAA15BoH,A,A,A,A,A,A,A;A6FiEJsuFAAAAtuFA3FssBCAsBFjvBvBAAAtB0B05BAAAA15B4B,A,A,A,A,A;A6FoECwuFAAAAxwDAvF4DnBh+BiG,A,A;AuFxDc0uF0C;AAGCC0C;AAGDC0C;AAwEP9DAAAA9qFoBpDrIA+qFAAAA/qFAvCsvBQAsBFjvBvBAAAtB0B05BAAAA15BiE,A,A,A,A,A,A,A;A6FyF9BAwC;21CC1BqBw+CuB;2HACKAwC;4FACWwOAlGkgBtB6hCuD,A;0wBoGlkBoB5qBAnGyWJjkEwC,A;AmGzW/Bg/BAcyC4Bh/B4G,A;gCdzC5BlwD6C;oJAaS0uGuB;g2CEMTx+CAAAAAwI,A;s7CCOS7wDAC0QP6wDmD,A;iEDrQO7wDACqQP6wDiB,A;iHDnQO5wDAE/BL4wDgC,AACAA0B,A;2CFwCGmtDG;kEADDrnBgD;wBACCqnBmC;kKASUgpBAtGuTMn2E+B,A;AsGvTAu0CoP;qaG1BNp3B6B;6kBA4gCDnd0C;AACd+uCkCrH5fAg7CyB,A;AqH6fc9hDkH;AACT+xBA5Hz4BmCh6D4E,O;mC4Hy4BnCg6DA5Hz4BmCh6DyD,A;gC4Hw4BxC+uCArH7fAg7CgC,A;AqHigBAh7CArHjgBAg7C6F,A;ktBoHteEh7CApHseFg7CkB,A;0BoHzeEh7C0BpHyeFg7CyB,A;IoHxeEh7CApHweFg7C6F,A;IoHteEh7CApHseFg7CmE,A;mHoHheEh7CApHgeFg7C4B,A;qBoHheEh7CApHgeFg7CiF,A;oEoH9dEh7CApH8dFg7C6B,A;AoH7dEh7CApH6dFg7CsC,A;usBiD1dsB+E4C;AAI8BCoF;AAIlCCmC;AAIDCmC;uCAwBnBjvFsC;i9FsEIqC8lC2C;yoECmKtB9lCoBCnSK6gCgD,A;k1CCgBbqfA7Eor+B+B0hBAA49G9B5hE8E,A,A;0L6EznlCiCg6BS;0DAAtBm1D8C;AACRn1D+E;wCAEOu2BS;y8CtElBlBvwDiF;ulDjDsSgCqpFgD;8qDQrM9BrX+E;wGAKAAuE;8TASAAqE;kWASAAwE;saAqBAAwE;0NAMAAwD;4YA2DAAwD;wsBAwBWhyEkE;WAAAAkE;srGA8JXiqE0D;09BAwCAA4D;4YASA+H2E;ygCAyH4BoduD;+MAcEpvF+C;+BAAAA4B;8SAO9BgyE8F;suBAoBA/H2F;2kEmH7ZOolBgQ;sBAAAAwD;yBAAAAqH;2gGlHzMACiF;6TASP1NyG;yHAKO5sIAPyBEgrDwD,A;2mBOXEAkC;k2JA0XXijFiF;smCrB5Z8BjjFmB;qBAAAA6B;WAAAA6B;8hCAuPEAyB;mCAAAA6B;mCAAAA4B;i/CEjOFAmD;uBAAAAwC;w/BAiHfw+CyB;6QASXzP0B;2RASAAU;uYAWoC/uC2E;WAAAA+E;q/HA6LVAqB;uDAAAA6B;WAAAA+B;4uCA6DAAgD;sGAAAAqC;iDAGUmdyB;4EAAAA8D;yaA6BVndyB;oFAAAAAASMuvFkB,6B;WATNvvF+B;y+BAmMnBAoD;0GAAAAyC;2nIE/fAAoC;sBAAAAsC;6FA8B+Bg/BAgBibZh/Ba,A;iBhBjbYg/B0B;iCAAAAAgBibZh/BS,yBAAAA4B,A;yVf5jBdwvFiE;6xECitDYhxCwC;wuEAo2BV6qCiD;2hB6B5hFPrpFgD;kPAAAAuC;48BAwBEyvF8E;qhCAiCAAoF;opJA8HgBzvFwB;85FA0JlBAa;sFAAAAwD;EAAAAAA0BbAAAAAA0B,A,A;knDtBzWe0vFsB;yTAU4CAsB;mNA4CrD9N8F;kUAqBO5hF8C;qtCAyDT4Ee;uIAQ6Bh3DwE;+EA0CzBoyDsD;6oBA4BQ4EiD;AAII02CAA5GEq0CkD,A;gUA+GVC0E;4iBCrPiBhiJ2E;WAAAAQ;4FAoCrBoyD4D;0RAKOA4B;wnBA0BEAK;urJPZRmiFiC;yJAMiB0NqB;AA+vBnB3KiC;oMA/E+BthFgI;0hIehf5B5DoC;+6BuDjIiBAerD+DFlwDsC,A;igCqDfnButI4D;sDAESr9EoC9C6gBsClwDwB,mDAArDkwDAAAAA0B,A,A;+B8C3gB2CAAApLrCAA/CizBAAAC/uBkB2oFAAAA74IwD,A,A,A,0HAgBxBkwDsF,A;uB8CkG2CAAAtL3CAAAAAA0G,A,A;AAwLE8vF8d;gZAYiBC+B;kBACfCyE;gDAKKD2B;AAAaEuC;gYAahB5Se;mCACSr9E6D;qDAGFAkE;8YASH1lEAnDiqBuC0lEuC,A;2GmD/pBjBlwDyD;mGAEpBxVAnD6pBqC0lEiE,A;2OmDtpB3Cq9E8B;ihBA8BG6S2C;iGAIPx1CQ;0PAMIq1Ce;4JAIAE2B;yJAaEEsB;meAgBFFqC;oHAMGA8C;AACH5S2B;8+BAe0C0SkB;kDAIjC/vFS;AADT+vF4B;8RAQAEqC;wBACAGmG;sEAKEHuC;2NAWFAqC;qMAOCAqC;m8CAsB0BjwFwB;4JAAAAmC;iOAQAA6C;qFAK1BiwF2B;u/EnD4D0BngJkB;gvBA8CzB8WeA8XsB9W+D,+GAEpBxVAAOuC0lEqE,A,6H;43BF34BvC1lEAE24BuC0lE+C,A;OF14BnCqoFuB;uFACkBv4IyD;mGAEpBxVAEu4BqC0lEiE,A;qWFx3BnCqoFuB;+cAWAAuB;oYA4FPtmC4B;8BACE4mC2B;AAA6B0H4D;0JAI7BrSyB;kBAAgB7csCAbhBmvB6C,A;wLAkBE3HqB;wkBAyHe74I2C;wNAUAkwDwBAhEDlwDgB,qE;oBAiENuwHsH;6PAYOrgEwBA7EDlwDgB,iC;oBA8ENygJkJ;uKAKOvwFAAnFDlwDsB,kD;gGAwFN60F6E;gBAAAAyC;qKAKO3kCAA7FDlwDsB,kD;yGAiGN+9F4E;gBAAAAyC;sFA+CTs6CoB;qBACMAyB;8OAOVGe;sNAQiBCqF;0KAOZJuB;0UAULGe;oaAeiBCqF;gLAOZJuB;yQAWDAoB;2mBA2EAAgD;4QASNDoBAzKMC2B,+D;yOA+KAAoB;yGAIRDoBAnLQCyB,2D;sNAwLAAoB;8CAGRqIAA/KA1HoBANQXyB,mB,AAMYnoFK,AAApB8oFiE,A;kTAoLQXgD;iFAgBRCoBArOOC2B,mB;2QA6OKI2B;AAERLoBA/OGC+B,uB;8XA6PCFoB;AAERCoBA/POC2B,mB;umBAwIWoIsB;AAIdCiBAvIGDwB,mB;8PA+IWAsB;0iCA+KK1Vc;sCACAiD2B;qEAGEvE4BAxeRkXyC,mBAAVhIsB,AAAUgIgG,A;8JA0ewBjIiBA/TlCD0B,mD;iOAgUiCCiBAhUjCD0B,E;kDAgUiCC+C;AAEH1oFE;mOAMmBmoF4C;AAC3BM6B;iCACqBCiBA1U3CD2D,E;kDA0U2CCoC;iyBAiBnBh4BoB;wBAAAAAA9hBOkgCkBAxB/B7V4B,A,Y;0BAsjBwBrqBAA9hBxBi4B2B,AAA+BiIwG,A;qHAgiBH5wFE;8UAOI0oFiBApWhCDwB,+E;6FAsWctnBkBA9iBd6cqC,AACAsSiD,A;+VAkjBsB5HiBA3WtBDuD,qC;0IA4WiCCiBA5WjCD0B,E;oCA4WiCC+C;AAEH1oFE;ohBK+RXA6CL/vBHlwD4C,A;iPKogCCkwD6CLpgCDlwDgB,A;sBKogCCkwDmE;kPA6BAA6CLjiCDlwDgB,A;sBKiiCCkwD+D;4aA+FAAwBLhoCDlwDgB,sE;u1BKuBTkwDa;qDAAAAAEsR4Cg/BAXqF5Bh/B2B,yBAAAA8B,A,I;yxHUxFvB6wF2B;UACFX4B;8WASEWqC;AACFXwC;6CACclwFU;2DAAAA0C;oQAI4BAU;mCAAAA2C;+JAQxC8tDqC;AACHoiC8B;qVAaA7Se;mCACSr9EkD;qDAGFA0D;qNAKN8wFe;0GACuBl1DoBNxVuB9rFgD,AAArD8rFAAAAAmC,A,A;oDM0VU57BmCAyXJAAArDsBAoBNhqBHlwD8C,A,2M,AMmtBzBkwDAAAAAAAGiBu9EAA3bbzvBe,mG,oB,A,K;8DAiEM9tDkF;oJAiBQ+wFmD;AAAuC/wFeN7WhClwD8C,A;mJMqXlBghJsB;iNAQAAsB;iFACGx2JAJsUuC0lEuC,A;eIrUjBlwDyD;mGAEpBxVAJmUqC0lEiE,A;uOI9S3Cq9Ee;slBAqBAvvBe;qIAG6B9tD+D;iIAK7B8tDe;gJAG6B9tD6C;2FAM1BkwF2B;yLAIPx1CqD;uRAOKm2C4B;0FAGyC7wFAAwK1CAAC/uBkB2oFAAAA74IwD,A,A,6GAgBxBkwDsF,A;0QD+jBI04D+D;6bAsBEw3B4B;wdAkBelwFyBN1fIlwDoD,A;wgBMkhBnBogJ4B;wFAEF9hCiB;gOAME8hC4B;wFAEFx3BkB;wgBAzBuC2vBuB;qpBAoDXroF8D;uGAIAA6C;6gBAyCAg1CgC;unHC7pB1B+7Ce;oNAMgC9wB2B;2OAKhC8wBe;86BA2DDCsC;mKAGgBAc;0NAKjB/wB2B;ySAqBMgxBqC;AACJFe;+HAIc/wF2F;4EAKd+wFe;2IAIc/wF6C;qFAKVixFqC;AACJFe;gQAcGGyB;2DAICAyB;2DAIDH2B;sQAeoB/wF+C;qFAGtBmxFe;gWAWGJ2B;oBACACsB;qBACAIsC;AACcFoB;2VAQdH2B;oBACACsB;qBACAIsC;AACcFe;qhBAmCdH2B;oBACACsB;qBACAI4B;4bA6BAAsC;AACcFoB;kRAkBdEsC;AACJDyC;8WASEJiB;8FAIiBGwC;sRAWnBCe;mtBAzGEJe;2sBAqCCMe;q0HA6QHpgCuB;yEAEAqgCe;mhCA2CIrgCoC;qXAsCJsgC4B;6iBAiBAhUe;6+BAiTOv9EoCA3UwClwDwB,iDAArDkwDAAAAAwB,A,A;mgHNgIuBAyB;8rYA4PPAoB;kIAEdwxF0F;mhDA6K2BxxFyB;qdAqBzBoqC2F;2cAYAA2F;giBAYAA2F;m3EAgFF8+CyB;6iDSvyCWlpFyC;6OAAAAkC;iNAU0ByxFa;gJAGHAa;wiKAuL7BAiE;kiBAuGqBCyD;+nBAiEf1xFa;uEAAAA2C;+1BAg1BWA8C;qEAAAA6B;+CASXAwE;oDAAAA+CA2XbAAAAAAqD,A,A;u5BAjWeyvF8C;2jDAiEXvmF4E;y1DA4F4BlJqG;w9EwGj8CJk3DI;wiBJkCAl3D4C;+DAAAA2B;yBAAAAqC;6rBA2IUA4E;WAAAA4E;0kE9F9JhC+uCqC;AACAAA/BohBJg7C8B,A;A+BnhBIh7C4B;+lFAiVF/uCkD;4FAAAAmE;8GCyMwBA+H;k2BA+Bf2xFkN;m8CA0KSC0gB;qXAmGpBCoG;yrBkGjvBE7xFyE;WAAAA6E;gsCAmOgBk8E0B;wpBA2D2BA6B;AAE7Cl9CuG;gGAAAlvFsC;4MAKEkwDyE;WAAAA6E;iMAYoCAgD;WAAAA+B;oNAuBtCg/BoH;0DAAAlvF8B;sIAKAkvF8F;gEAAAlvFmC;6JAyBAkvF8F;kEAAAlvFmC;2EAuBiBkvFsH;wGAIPlvFqB;2CAIOkvFsI;qHAMHlvFoC;wXjG5XVgiJmB;gUAWYA+B;gRAMZA6B;wDACO9xF+B;0DAwCP8xF6B;yOAaCAyD;qNAoBDA6B;0jBA+BGA4B;4HAQCA4B;sSASJA6B;+XAiBFn8BkD;yiBAyCam8B6B;qTASAA+B;wHAEc9yDAtBiQCh/BwC,yBAAAA4C,A;0LwHpjBGimEmC;4+CjGyEpB8rB6Q;+sBAqBmB7V6F;0TAQfl8E6C;4FAEX23EAlC+aW9lEM,AAAjBk4EkG,A;kQkCja6B7NiB;uWASvBntC6BlCmZNg7C6B,A;sDkC/YyC3tDoB;w5BkGrBb+Z0B;kBAAAAkB;6kB1FlED67CwC;0pBA0DdlvJgF;0mHAiLFk9DgD;0BAKGAiD;6GADHAuC;AACGA0D;+IAIPo8BkB;2LAkFH25B+B;4jEAsEE4hBA1C+FW9lE2E,A;wiEAnNCmiDe;mPoC2MKssB0C;sBACDx/B2C;sBACAkCyC;sBACAyT6C;sBACE3f+C;sBACA9F8C;wBACC4vBmI;6NtBrWiB5RU;oQAyCtCAkB;iCACSijCAAiCmBCoC,A;oCA/BG1tCuD;4BACA4KsD;yFAG1BgXoD;0qPdxJP+rByR;qCAGKC4I;uTAQLC0FAYaryFmC,4H;ycM2E0BAyD;cAAAAwC;oZAwJnBA8B;gpCA8IfA6D;cAAAA4C;qvDN9buBqpF4C;wiBAkVlBv0BsCwIjTKw9B2E,yE;QxIiTLx9B6B;0LwCqPe90DwC;62HC4sCXwiEc;0PAQYsnB+E;+DAIYtrCsC;4HAkB5BqrCoD;wfAaIz4BA7Bx8CM5SkF,A;0I6B88CFwbA9BxnDTh6DyB,A;oE8BwnDSg6DqC;4jGAiuBHgE2BA+CWxf+B,A;mEA7CN8SgD;yTAcHA+B;AAAuC1M6F;2UAiB9CilC0F;suBAsCRjiDe;uKAIAykBkB;gKAIQkmC4F;4DACgCCSAIxChwB0D,yPAUJpL8B,AADIxS6I,A;wJA2Da6tCyEAObjwByC,0EAIFkwBsLA1BA3jD8E,A,8L;0UAsCEyzByD;SACAockD;oNAIAjEkE;2LAEA5pB6E;yiFAqsBQ/wD4C;y4FA8xBD2yFkF;kzEA4FN5hCgD;AACE/wDY;AADF+wDiB;k5BA2CeKA7B/8HE5S4D,A;mJ6Bq9HWsrCmE;gJAIOtrCsC;iaAmB5BqrC+D;0vBAoBJv4BmB;8CACAkRmB;+BACIlRqB;2FAGQ0M8C;uNAUTh+DiB;sVAcHg+D+C;uCACE2cyB;4FAIC36EiB;2OAUD+wD+C;AAIC/wDS;gVAYH4kDwF;2DAIC5kDiB;kPAUAg+DsF;AAAqBwEkC;yIAUrBxiEiB;k6BA4D4C4kDkC;AAAnB0MyF;8DAmB3BtxDmC;s4BAuBUuyF4F;qEACgCCsKAUrCte6E,A;siBAmBH1RkB;mHAEA0RgI;AACAyGuB;uDANGkP0C;AAOH94BU;y5EI89eO6hCA6F3koBX9pHADgBDk3BsC,AAAAl3BwB,A,A;kgD5F80lCA+pHgC;6LA4BAAgC;uMAYAA+B;AAActV2B;4LAMMA2B;qQAOtBljBsG;89B6Ft1lCOxwFADjDuBmqFQ,A;yNCqE5B6lBuG;8GAIS7iB0E;6BAAAAgB;4FAGXOqD;6LAckDP0E;uNAQvCA0E;6BAAAAgB;4FAGXOqD;+WAeFA4D;+oCAsESptFwCD9LA2oHArG2VXp3DApC/IAAuF,A,mBoC+IAAApC/IAAuH,A,A,A;O0IdWvxDAD9LA2oHsC,A;wPC0MLCoG;8CAIS/7B0E;iCAAAAgB;sKAIXOqD;8NAQwDP0E;sNAOxDOqD;qjHlFhOG3C0CANuBjtBqBzCDE0gDuB,A,A;2qDmDyDf1gDOnDzDe0gDuB,A;wRmDmCb1gDOnDnCa0gDuB,A;wgBmD+Cb1gDOnD/Ca0gDuB,A;0hB6HiCsBpoFA3H6LzC27BwBFnCwC9rFgD,AAArD8rFAAAAA6C,A,A,A;glEgIlJco3DgC;yEAGZCwK;kuBAqDmBx1DA1H2VOz9BE,A;oD0H3VPy9BoB1H2VOz9BiC,A;i5F8CtQM6pDS;sRAKbAK;4qDAjB8BuVa;uBAAAA4G;0DAAAA0I;0S6EhC7Bp/DAAugBH+qFAAAA/qFA/HmGQAAFjvBvBAAAtB0B05BAAAA15BoBA4MLlwDgB,mC,A,A,A,A,A,A;oBiI/CHkwDmBAugBH+qFAAAA/qFA/HmGQA6D,A,A,yC;uN+H/WJoxDuC;AACD0oB2L;gBAAAAuB;kHAQlBqZiD;wIAaAnzFS;4CAAAAqC;6OAYWAAC3afAAAAAAsG,A,A;mDD2aeAwE;wpBAsDbs6CkE;+EAmBOt6CqC;qLAQWw+C+B;4HAIlBlEiE;iVA5DsBt6CkB;+BAAAAoC;2NAEAuiBAyCtZpBviByB,A;yOzCyZEozFmD;yMAmNOhiCAnB7mBW5S+C,A;6ImBknBKx+CiC;qTAyLhBw+CyD;yFAEPs2B2BDpyBQkekC,8FAGZKyNAoF4B51DA1HiTFz9B4B,oBAAAA6C,A,sE,A;mK2HoaxBg/BAnBz0BwBh/BkH,A;8BmBy0BxBlwDkD;gLAMsC2tFA3H1adz9BoC,4BAAAAiD,A;+c6HxXGgcAjIouBChcAF1xB5BAAAjC0B05BAAAA15BoBA4MLlwDgD,A,A,A,I,A;60CmIvDM2tFA7H0THz9B4B,oBAAAAkC,A;gxC4H7apBAuJ;irOIlBqCA0N;+BAAAAoB;8PAMjBmd0B;AAAEndkB;gCACtBAuC;6EAYWAgB;mtBC5BfAuC;qyDG4BKA2C;oLAUAAmB;yLAUAAoB;oRAcIAc;oZAWAAwB;2/BCtBE81EACtBIhoCkC,A;ADuBR9tCa;AADI81EwB;kDACkDrPA5GnDnCzmEiC,A;0b4GkEjBszFAAsBU7sBA5GxF+B34BsC,A,6B;O4GkEzCwlDAAwBJtzFa,6BAFcymEA5GxFOzmEiC,A,A;oC4GoEjBuzFAA6BU9sBA5GjG+B34BsC,A,6B;O4GoEzCylDAA+BJvzFa,8BAFcymEA5GjGOzmEiC,A,A;6B4GsEjBwzF2HAmC4CvpD4C,AAAhDjqCE,AAAgDiqC6B,A;+BAnC5CupDAAmC4CvpDe,A;oGA1BlCw8BA5G/E+B34B2C,A;A4GgFpDoFAClCI4iC6C,AAAQzjEoE,4D;ODmCLrSkB;cAFcymEA5G/EOzmEiC,A;4H4G+GrBqrC0B;oDAAAA+G;kPAYAA0B;yCAAAA+G;+8CIlIuCrMgB;miJ7C6L1B4yDwkB;sjEzCxJNjgD+G;sDAAAAA0D4XZ3xC2F,A;gI1DhWFg/Bc;6CAAAAiE;+CAAAlvF8B;oqFuFsO4B2jJsB;wDAEKAsC;OAAjBzzFoB;AAAiByzFwC;YAAjBzzF+B;yO5CtP+Bs6CiC;qPAgQ7CAuB;2JxBjTmB4hCiB;+DAIF9/CkB;sLAyBjBkeuD;gjByBPSt6CyC;AACX+uCApHkhBAg7CoC,A;+doHpgBIh7CApHogBJg7CoB,A;4CoHpgBIh7CApHogBJg7C+H,A;qGoHhgBIh7CApHggBJg7CiI,A;klBoHnfIh7CyBpHmfJg7C6G,A;AoH9e+B3tDqC;AAAxBke0D;67FAwFat6CsCzB3JIitFAAAAjtFiC,A,A;6wEyB6MNAAzB7MMitFAAAAjtFmC,A,A;2ByBkNtBs6CAzBjMFvLA3FgiBAg7C6B,A,A;AoHpWkB/pFiC;sCAOXs6C2C;gDAGGleAzB3MSAoB,A;2eyBsNTg1BAxGqMY5S0C,A;oDwGpMV4SAxGoMU5SsC,A;qOwG3LtBm1C8L;6fAoBWn1CoC;AAA+B09BKzBxPrBAqD,A;AyByPnB5hCoBzBhPFvLA3FgiBAg7CkB,A,A;oBoHhTEzvCAzBhPFvLA3FgiBAg7CiC,A,A;qEoH9SEzvCAzBlPFvLA3FgiBAg7CgC,A,A;s0BgKjiBsBzvCoC;urBzCNFt6CsC5BVIitFAAAAjtFiC,A,A;ygC4ByClBg6DA5GoNKh6D0D,O;iD4GpNLg6DA5GoNKh6D4C,A;0B4GhNL4zFuE;8qBAwBA55BA5GwLKh6D0D,O;kD4GxLLg6DA5GwLKh6D4C,A;0B4GpLL4zFuE;0GAMA55BA5G8KKh6DyB,A;gE4G9KLg6DoC;uGAAuC45BkF;iEAGIA2F;qBAA5B9tD6D;i1BAxCN8tDgD;wcA4BAAgD;yJ2CMKp7GAAiBpB4jDuC,A;mEAjBoB5jDAAiBpB4jD2B,qDAAK0JkE,A;AAhBEwU0D;k5C7CFczIkD;AAAsB2qBkC;6CAI/B1sH0B;wCAAAA6D;gaA6IGqsFA1GAJn8B2B,kC;2b0GsBMm8BO;uCAAjB6CgC5H8K8Bh/B+E,A;2G4H9K9BlwD+B;AACM0sHyE;AAGWrrD4G;+RASJ0gCyC;AACuB2qBmE;AAGhCztBgD;2PAKeotCgE;8IAiCNhrEiF;4DAESgrBA1G/EXn8BsC,A;iB0G+EiBgtDiB;AAAN7wBA1G/EXn8B8C,O;2C0G+EiBgtD6C;oPAqCf77CgE;gYAwBHy9CoE;mIAhBWqVAzGuBQjkE+B,A;AyGFKk8E8D;yEACjBttB2D;w8BA2EGtMAAzQWzQuD,A;kEA2QT/hGuF;kDAGlBwyGAA9Q2BzQgD,A;AA8QFAmC;sCAMzByQAApR2BzQkC,A;AAoRF2qBmC;wCAMzBlaAA1R2BzQkC,A;AA0RFAmC;kGAIZ1gC4D;gCACAA4D;oEAEIigDA1GkHC5Se,A;ue0GnGE4SA1GmGF5SiB,A;kE0GlGD4SA1GkGC5SmB,A;8nB0GvFD4SA1GuFC5Se,A;onB0G9EDAe;slBA4CE3M+N;AACDA0D;2qCA8BjByQAAhZ0BzQoB,+C;qmMAgzB3ByQAAhzB2BzQsD,A;mEAmzBO/hG4B;+DAAAAmB;8aAuCjBu1CyD;k3C8C19BNqXuC;2erE8BP00DAnFqfc5SuB,A;gTmFlfT4SAnFkfS5SwB,A;wNmF9eP4SAnF8eO5Se,A;0kBmFleL4SAnFkeK5SqB,A;uQmFtdjB3MuB;sHAKQ2MsB;AAAY3MuB;oLAUrBAa;mEAAuBufAnFucL5SiB,A;wQmF7bb1YK;yXASPiJgB;qGACAAgB;oBAEFAU;umDsEpHalYyD;0QAOI2nBuB;u4IEyCU1YyD;OAAhBjPyD;oNAUmBsFA3JoInBn8BgC,A;4D2JpImBm8BkC;qYAkBXqiB8D;6HAOK1YuD;kCAAKAoD;6vC/G1BzBu3CiBAjC0BzoB2BC7BFjtBOzCDE0gDuB,A,A,A;gOwCqEdpoFAtCyJL27BoBFnCwC9rFqD,AAArD8rFAAAAAoB,A,A,A;AwCtHqCzeoC;0EACJi0CmC;2EAGbpxDAtC2qBOAAFjvBvBAAAtB0B05BAAAA15BoBA4MLlwDiE,A,A,A,A,A;gCwC/GrBwqGkD;AADgBt6CAtC2qBOA2E,A;+vFsCngBDoxDiC;2HAGbisBiBAtNmBzoB2BC7BFjtBOzCDE0gD2B,A,A,A;+LwCyPZv4IoC;gCAEhBwqGkD;oYAgBYt+BAtC6hBgBhcAF1xB5BAAAjC0B05BAAAA15BoBA4MLlwD4D,A,A,A,A,A;6BwCmFvBwqGkD;AADct+BAtC6hBgBhcqE,A;iLsCphBNw+C6B;AACtBnc8D;AAEAwxD0J;8LAzE8Cn6DgC;kCAI9B15BE;iCAAAAAWpND+qFAAAA/qFAjDsvBQAsBFjvBvBAAAtB0B05BAAAA15BeA4MLlwDkF,A,A,A,A,A,A,AmDpKTq7ImF,A;AX8LVnsDY;2DAAAAqC;yCAAAlvF+B;oSAQmB4pFO;6WA2CoCvc6B;ihBAwD3D22E6DA3FwB1iCiC,8BAEQj0C2F,AAG1BkgEiBA1MwBzoB2BC7BFjtBOzCDE0gDqC,A,A,A,uC;mhC0CsCL5+CyB;yBAAAA+B;iQAIjBAoB;qEAJiBAmC;0RASgC6zCiB;sKAClB1uB8B;iCAC1BnlBuD;AAXYAuC;mhBAoBdzpCmC;wxH4BqEmBmgEmH;2RAE5BpxBY;uCASFAiB;2RAYE6rBY;yGAAAA+C;2nCA8DS56DiEuF5JbAqD,A;gnCvFuQmBqqFAtCrSKpmBAnC6TOjkEwC,A,AmC7TpBs8BAA7BcguD8C,A,sBA6BdhuD6EAaeiuDoB,8B,AAF1BjuD+C,A;kJsCmSsBt8BwG;sEAGHu1CgD;uKAAAA8D;iEAEAiJ+B;4BACGx+CqD;sSAqBR+zF4C;kDACc7hD0D;iCACNlyCqF;AAEJ+zFkE;+MAKY7hD4D;mEACb6hD+C;oDACa7hD4D;mEACX6hDiD;oDACW7hD4D;iCACNlyCkG;AAEH+zFsE;2LAML/zFyG;6GAKDw+CuB;4BACGx+C6C;+HA4EVAgH;2zDAmDSi/B2KuFtcjBj/B4C,A;kCvFwciBA2DuFxcjBA+C,A;oTvF8c6BmgE4E;AAAfngEmB;AAAA+uCuC;iCAAAAS;4BAAAAS;uBAAAAS;wBAAAAS;imBAoDSoxBgD;oRAiBAAqD;y7CA4CrBpxBwB;AACAAc;wxDtCtjBoBmtC+B;siEAiEAA+B;otBA8BD94B8C;2NAQN84BiC;kiCAwFIz7BuE;KAAAAoB;iTAYXy7BmD;AAGqB94B2E;4HAEjB3C8F;kHAKiB2C+C;AAGR84B4C;wIAOZz7BqF;uYA2CoBkvBW;uIAKvBAgB;AAAmBAU;4MAWnBAa;cAAAAW;KAAmBAe;6iBoDlME/uFCsEzDDozGyC,A;0mBtE4EACqB;8sBAWTz1CuC;yQAQWteiD;+OAGNAyE;0BAEKr/CCsE1GHmzGoC,A;AtE4Gf53DkB;ytEA+DP4CA1GtQ8Bh/B2H,A;0D0GsQ9BlwD8B;snDAmEAkvFA1GzU8Bh/B2H,A;iC0G2URi0Fa;mCAFtBnkJ8B;iSAYsBm0HAvFEOjkEkC,A;AuFF7Bg/BA0B9T0Bh/BqH,A;uE1B8T1BlwD8B;gGAII6nIAnGqMa9lEiE,A;khBmG9KKoyDAvFzBOjkEsC,A;AuFyB7Bg/BA0BzV0Bh/B4G,A;gC1ByV1BlwDsC;sGAQsBm0HAvFjCOjkEsC,A;AuFiC7Bg/BA0BjW0Bh/BiG,A;mC1BiW1BlwD8B;6QAWoBi/F6C;kVA3KFntDa;4EAAAAAuEvNlBoyGgD,A;AvEwNIjlDAnGgUJg7C6B,A;iXmGrSwBloGiBsE/MMmyGoC,A;6CtEgNNlyGCsE5NOkyG0C,A;2BtE6N3BjlDAnGmSJg7C2B,A;iZmG9QwB/nGa;4EAAAAAsE5OKgyGqC,A;AtE6OzBjlDAnG6QJg7C6B,A;8ImGvPkBnoGa;4EAAAAAuEjSlBoyGiD,A;AvEkSIjlDAnGsPJg7C6B,A;+ImG5OsB/nGa;4EAAAAAsE9QOgyGqC,A;AtE+Q3BjlDAnG2OFg7C6B,A;iNmG3NsB7nGiBsE7QW8xGuC,A;6CtE8QXlyGCsEtSSkyG0C,A;qBtEuS7BjlDAnGyNFg7C2B,A;0bmGhL6B/nG8BsE1UAgyGsC,A;6tB9FwBP7zByF;qCAAsBhhBkB;aAAAA0G;6WgGpExCwwBW;gYAmBFAW;2IAGgBAiB;oDAEIxPa;qGAAsBhhBAA7B/BwwB6C,oEACKp1CwB,oD;4CA4B0B4kBAA5BdtgB8B,A;qqClFY1B5C8B;mCAAqBNyB;uDACSAiC;m3BoFkBSwImE;gGAI5BqayD;qXAUJx+CA1EHGk0FglB,kI;O0EGHl0FA1EEAmd0JA3BOg3EAAAAn0FwB,A,A,A;gf0EiCImgEoD;sZnHgJlBnGA/CiDOh6DsH,O;kH+ChDUm8B+E;+CAcFqiBkE;AAAwB4SgD;OAC9BpxDqC;8GAGFAkE;qHAOUAqC;AAAM2xCA/CNhB3xC0D,O;gC+CMgB2xCA/CNhB3xCsD,A;A+CMUAACPFA8B,A;+IDmBZg6DA/CWIh6DqD,O;6B+CnBGg6DA/CmBHh6DkD,O;kC+CnBGg6DA/CmBHh6DyC,A;iE+CXJg6DA/CWIh6D4C,A;+d+CjKFlwDiE;oSA2CgBowFgC;kBAAAA+C;mGADPlgCuDCyFCA0B,A;ADvFgBo8B6C;2DACM8DgF;OAA5BlgCsD;iUA4BoCsVYCpCrBtVyB,uCAAAAAA8FTA+B,A,A;klBDfAw+CuB;ihBA2BJwbA/CkBJh6DkD,O;mC+ClBIg6DA/CkBJh6DyC,A;wc+CVIg6DA/CUJh6DqD,O;8C+CVIg6DA/CUJh6D4C,A;ghB6GtKJmkCgC;+jCAoCUnkCY;yJAIiBAoBChIhB6gCiD,A;kBDoID+tBApH2DchhHgE,A;6EoH3DTk4F2D;AACbA+E;AAEe8oBApHwDOhhHiD,A;wCoHtDPghHApHsDOhhHiD,A;mKoHjDhBoyDgC;8TAMmBAoBCpJhB6gC8C,A;kFD2KV+tBApHoBuBhhH+E,A;eoHpBvBghHApHoBuBhhHW,A;mEoHdhBk4FmE;AACAA0E;qBACAA8D;yBAKY8oBApHOIhhH4C,A;gXoHpCZghHApHoCYhhHoE,A;sIoH/BZoyDY;2JAIoBAoBCpKrB6gCkD,A;4BDsKqB+tBApHyBRhhHgE,A;mDoHzBgCghHApHyBhChhHiD,A;qDoHxBXghHApHwBWhhHiD,A;eoHzBdoyDoB;yUAkCiBAoBCxMhB6gCiD,A;kBD2MY+tBApHZChhHgE,A;0EoHevBghHApHfuBhhH0C,A;eoHevBghHApHfuBhhHW,A;0BoHkBUghHApHlBVhhH4C,A;8WoH4BhBghHApH5BgBhhHiD,A;eoH4BhBghHApH5BgBhhHW,A;gEoH8BvBghHApH9BuBhhHiD,A;QoH+BhBoyDO;AADP4uDApH9BuBhhHW,A;2hBoHsDjBghHApHtDiBhhHgE,A;eoHsDjBghHApHtDiBhhH4C,A;AoHuDjBymJA/EiDShKAAi9FDrqFyC,2KAeHk8E6D,+FASF9/CoB,AAAFjfqE,A,gC;oE+ErhGsB93B+B;AAAzB4/DiB;AAAWqLiB;AAAcjrEAF8JlBAE,qBAAAA6E,A;AE3JJupEApH/DgBhhHiD,A;eoH+DhBghHApH/DgBhhHW,A;iEoHgEdghHApHhEchhHiD,A;eoHgEdghHApHhEchhHW,A;mEoHiESghHApHjEThhHiD,A;eoHiEhBoyDqC;4ZnB7OTAgB;8IACeAgB;inC5BDfAgB;2kC2BuE2BAqC;sEACpBAgB;gFAOAAgC;iCAHGAgB;uPAWCs0FyBA1EQxkJyB,4D;wDA2Edo+IoC;SAAAAqB;0GAAAAAA+ELluFiD,A;gZAvEWs0FyBAnFQxkJyB,4D;iEAoFdo+IoC;SAAAAqB;oHAAAAAAsELluFyD,A;8YA5DWs0FyBA9FQxkJyB,4D;2IAgGdo+IoC;SAAAAqB;sHAAAAAA0DLluFiE,A;icApBFs0FYAtIqBxkJyB,4D;iGA0IVo+IwEAgBTluFqD,A;kHAdmDkuF4E;4BAAAAAAcnDluFkE,A;iGAV0BAgD;stBAuCrBAwB;wzFAKEAqC;AAAYkgC4F;AAAZlgCAzCIMA8B,A;wQyC4BRAW;4CAAAA6C;qVzCgCcihEc;uCAAAAAhDmOKjhEkF,A;AgDnO9Bg/BAlEnQ8Bh/BuF,A;mCkEmQ9BlwD0F;0GAGuB0uGwC;8GAENx+CY;+EAKHg6DAhDxCHh6DgD,kC;wRgDmDAAqC;AAAgBihEAhD8MGjhEsC,gCAAAAmD,A;AgD9MnBAAAjFQA4B,A;SAiFiCo8Bc;+IAU7C49BAhD7DIh6DqD,O;6BgD0DPg6DAhD1DOh6DkD,O;kCgD0DPg6DAhD1DOh6DyC,A;iEgD6DJg6DAhD7DIh6D4C,A;kTgD9KckgCgC;kBAAAA+C;qCAAZlgCuDAgJMA0B,A;AA/IGo8Bc;i+EAwNPp8BE;gDADS8lCsD;yuCPnSgBrIA/Bgddz9BE,A;oD+Bhdcy9BoB/Bgddz9BgC,A;6M+B3blBAuCAgDau0FAAAAv0FAnCmsBIAsBFjvBvBAAAtB0B05BAAAA15BeA4MLlwDyF,A,A,A,A,A,A,yC;opDqCtGnB2kJyC;6JAKJn6CmE;6OAMIm6CyC;+ZAcFl5CK;OAAAAuD;0KAYFRK;OAAAA2B;wYAMI05CyC;yHAG6Bx0FAnC6FtB27BoBFnCwC9rF6C,AAArD8rFAAAAAmC,A,A,A;yBqCxDkC5fAnCqqBFhc0BF1xB5BAAAjC0B05BAAAA15BeA4MLlwDkF,A,A,A,A,A;kXqC3CnB2kJyC;6HAIgB5qCsB;wJAKM9OK;OAAAA2C;YAGnB8OsB;8JASaliBOrCnKU0gDuB,A;iCqCqKzBoM+B;i9BH9DWj+BO;AAAM/4B6CG3HkBAA/Bgddz9B4B,oBAAAAiC,A,A;gK4BjVQy9BiBG/HMAA/Bgddz9BK,A,A;wD4BjVQy9BAG/HMAoB/Bgddz9BiC,A,A;mG4BvTGw2DO;AAAM4oB4B;qdAyBsBp/EA2FrJLCA3HqNzC27BoBFnCwC9rFgD,AAArD8rFAAAAAmC,A,A,A,A;OkC7B0BzegC;AAAwBndmD;AAASA2D;AAAjCmdgC;ohBAgBPsgB6CGlMuBAA/Bgddz9B4B,oBAAAAiC,A,A;6K4B1QKuwDwB;AAAQ9yB0B;AADjBtgBE;AACiBsgBiB;uCAAAAAGtMCAA/Bgddz9B4B,oBAAAAoC,A,A;A4B1QwCo/EQ;AAD5CjiEuC;6RASLiiEO;kGAMVAgB;ykBAaYAO;2/BAlFEAgB;uEAMAAuB;82DH7EgBtxCkC;uTAURA4B;orB6GdjBAkC;gpBAkEIhI8D;AAAWAiF;AAI3BzzBkEA2DmCy7BiC,A;uNA5CQAwC;moDrE1JjCxhDACiCsBx8C6I,2K;ygBD/BhCy8CAC6CkCz8CkJ,8M;uWmC9BFkqFiB;kEAA2BwIA7E4+nBzC91CA6Fp+nBbDADcDuT4C,4D,A,qB;oSfnBwByoD6C;sFAAAA6F;AAIjB+NO;AAAM/4B6CtEvBuBAA/Bgddz9B4B,oBAAAAiC,A,A;mSqG5bbw2DO;AAAM4oBgB;AAAiB58CA7Ew+nBlB91CA6Fp+nBbDADcDuT4C,4D,A,A;m0CxCoGmB20FwB;AAAV30FkF;kGAAAAyC;i3BAoDmB20FwB;AAARx3EgGAzJUowEyC,AAGGCyC,AAGACyC,AAGtBCgC,AAUiBC+E,AASLC2C,AAMIC2C,8EAzBhBHAAAA1tF2E,A,A;AAkJf8wCqB;mDAAAA0G;iFASqB8jDAA/HQxjCAtFqfP5Se,A,A;oVsFvURwbAtFCHh6DyD,O;sCsFDGg6DAtFCHh6DgD,A;qsDsFmD6Bw+Ce;mDAGpCm2CwB;AADG30FiE;OAAAAoB;wnCA3JLg/BAxG/H4Bh/BsI,A;8YwGiIhBlwD2G;AAAA+5FmEnB0BV8eAA3FaqkCkI,A,gLA8FNvuBwB,AAAA3uHyH,mI;gLmB7BG+5FAnB6BH/5FmE,A;uTmBxBSAmD;4CAAAACnB5BRA0B,c;ghDmB2HN8kJqB;SAAAAAA/KuBxjCAtFqfP5S4D,A,A;AsFrUVx+CgB;mnBAuDOlwD2D;4CAAAACnBnLPA0B,c;w9DjBhFC0uGsB;QAAmB4SAlDihBV5SuB,A;uPkD1ffwbAlDoLIh6DoH,O;sFkDnLNm8BkE;4CACA6wBwD;8yBiB7BiB7vCAAkDEmxEAAAAtuFA7D4qBCA2BFjvBvBAAAtB0B05BAAAA15BeA4MLlwDwE,A,A,A,A,A,A,4B;W+DnKDqtEAAmCH43EAAAA/0FoB,A,AAgCmBg1F8C,AAOpBCAAAAj1FgB,A,AAyCWwtF6D,AAGE0HuD,AAEjC/3EAAAAAkJ,A,A;SAvHiBqfAAoBoBAU,A;0MAdlBrfqB;qWAkDErtE6B;sQAgGf64GAA/GaqkCmBAdQl9I6B,wB,kBAcuB63FO/DhElB0gDuB,A,A;+S+D8MhBroFAA2NG+qFAAAA/qFA7D2UQAAFjvBvBAAAtB0B05BAAAA15BoBA4MLlwD2C,A,A,A,A,A,A,8B+DgPNi7IAAAA/qFA7D2UQAwF,A,A,A;yoB6DzgBrBw8B+B;kCAAS6YAmGlNQoxB6B,uC;0GnGsNPjqC+B;kCAAS7uFM;kkBAkEJ6uF8C;kCAASiqC2C;AAAMx/BwFoG3TyBgJiE,2E;gUpGsUtDzT+B;gDAAS7uFM;SAAc0yFsC;yOAMP+wBAnEyOC5SyB,A;uDmEvOpBmXmD;8CASEn5B+B;kCAAStB6B;udAcqBl7BAA8EjB+qFAAAA/qFA7D2UQAAFjvBvBAAAtB0B05BAAAA15BAA4MLlwDyD,A,A,A,A,A,A,A;A+DkNd0sF+B;8FAhDyBx8BoBA8EjB+qFAAAA/qFA7D2UQAsBFjvBvBAAAtB0B05BAAAA15B+E,A,A,A,A,A,A;A+D8ZVryDM;SAAc0yF+C;++GAzJQ9wCAc7EnBi1D8B,A;Qd6EmBj1DAc7EnBi1D2F,qBACA4KqE,iDACK/FwI,2R;4fdoFlB7sB+B;kCAAS6YAmGlOIoxB6B,uC;iCnGmOC32HgB;AAASkwDuB;ueA8DhB06CkCAgIC/SO/D1bc0gDuB,A,uB;mH+D+V5B+Ma;kIAAAAwF;uoEAwBkCvyJgC;0+CAR5B64H6H;0SA0BmD25BI;MAAAAmCAeLxyJyC,A;mMA0BvC8kGO/Dlbe0gDuB,A;8L6DcViN6HA6ITrEmBAtE4B5T4B,A,qJ;SAvEnBiYAAoJb94DU,kCAASuoBAAvJyBAiB,A,A;uIA4GrCksCkCAlCmC5T4B,A;cAoCtBr9EqC;iNAWbixFmBA/CmC5T4B,A;wSAwDdvvBARxCFmiCqC,A;yCQ6ChBptJA5D+sCPqmJqB,A;yO4DtsCW+HmBAtE4B5T4B,A;2KA6EhC7gDU;kCAASuoBAAvJyBAiB,A;oGAiKrCksCkCAvFmC5T4B,A;YAuFjBt4BiB;wMAWfAiB;oTd2DFiVArEyJmC78C8D,A;AqExJnC6vCiB;AADAgNArEyJmC78CiD,O;qDqExJnC6vCiD;AAGWxOe;snGA+FJjeoG;AAAwCnE0C;8qBAmBK4yBkB;k5BAtIO7xCyD;oDACxCnb0BuF5ORhCaINmBA6B,A,A;4B3FkPXgCY;+mEA4HlBmbe;oiCkBvRFojBkF;0CACoBpjBuB;wdA/D2Bnb2D;oDAAAAAqEnBnChCaINmBAiC,A,A;azEyBgBgCU;krCAkD1BwmEsE;8pC3B5BNhhIA6B9BN0rDAGHKqiGuC,A,0GHGLriGO,gCAAAAAGHKqiG0F,A,6F;kjBhCqCNnkCA5BguCU5SoC,A;6YyJrwCGxJgC;eAAuBAgC;6MAKV5YK;qsBxF0CZp8BACtEFitFAAAAjtFuC,A,A;iCDsEEAuD;OAGYo8BAC7DnBAkB,A;wc3B8GgBp8BuB;mGACE4kC0E;iBAAR5kCc;AAAQ4kCAlDErBstDe,2C;0MkDDDjH4B;+MAQIrmDsD;UAAAAAlDPHstDoB,gE;20BkCqDNllCArCsZG6hCsC,A;4IqCjZIzyDqF;2VAGE49BArCmERh6DuD,O;kEqCnEQg6DArCmERh6D8C,A;6cqCzCKo8B2E;0YAYP27CiC4BzM8Bt6CARuFbz9B2B,oBAAAAgC,A,A;4EpB0HjBiiC2B4B3MsDxEARiFrCz9B2B,oBAAAAgC,A,A;sFpBoIjBkgD6B4BlNuDziBAR8EtCz9B2B,oBAAAAgC,A,A;+hBpB7DhBo/EgBCmC8B7uBS,AAAQ6uBgB,A;wSD3B9Cp/EAK3CUw1FgL,A;AL2CVxnDsC;+JAAAA+D;AAAAhuC8BKvCgBy1FsE,A;+jFL+DoBh4DACCQAAG9ENAoB/Bgddz9BkC,A,A,A;A2BnYRAAgGyBiCmdAARZw4EoC,AAKECqF,A,A;0WhGlB7B5e6T;qNAW+C6egC;ifAUjC/lJgF;2cAObghG8J;kHAG6B33BoC;+CAAAA4P;mHADxBnZuE;yCAFL8wCwG;sZA1BQ0lBO;AAAM4oB2B;gGAKCtvIoCG5ErBAyB,8B;sLH4EqBg2HyIGlDLkQsV2HKvB15BS,gBAAAAA5BEIw5CoE,2K,A,kO;iYlGwE6BCEA8CzB3WgBCnFgC7uBS,AAAQ6uBgB,A,mE;ADqCfjiE6B;YAAA44EqH;4vCAoG/Bh7CI;gpBAgB0BjrGoCKtNrBAyB,8C;gPLuNuBnCM;SAAcwyF8D;gjBAc1CwlBI;k3BG3NgB3lDA2H3BKg2FAAAAh2FA/BSTi2FAAAAj2FuE,A,A,A,A+BNOk2FAAAAl2FA5BMIo/EAAAAp/EmE,A,A,A,yC4BTFg2FAAAAh2F0D,A,AAGFk2FAAAAl2FmH,A,AAuBvBAAAAAAiDACaAAtF6BTAuE,A,A,A,A;oFrC3BiBi6BmC;iGiIxBGiiDa;oBAAAA4B;uEAGUl9CAvDiCNh/Ba,A;0DuDjCMg/BAvDiCNh/B+D,A;+ehDrCLlwD4BCwHTA0B,qB;ADxHS4rH4E;sGeuCjBgYuC;ga3B8B+BzzEAhDuKxB27BwBFnCwC9rF8C,AAArD8rFAAAAAiC,A,A,A;qhDkDrDa/uBeO7HF64DmC,A;2BP6HQoTaAUsB5LkC,A;AAVdnsCcAcgBmsCkC,A;AAdP57BaAkBK47B6B,A;AAlBGltEkB;AAAYq3CAAsB3Br3CgC,8J;oHAiCpB05B0C;mZAsCyB+DA5CyNNz9B2C,oBAAAAiC,A;qnD4CtKKq7CyI;ueAMepLmN;iGAKtB+cAtD+QX6hCAAIPsHuC,4tB,A;i9CsDnQMxhDiLa3RUx3BAAmEgB63E+C,AAgDTxH+B,AAGE0H8C,AAEjC/3EAAAAAAAGgBndAF3FYusFwF,AAuD0Bx+EqJ5EmT7Cw7EmH,A,A,yD8E/QOvpFAFxFGurFyY,A,A,A,A,A;q0CXmQMxwCiG;spEAcvBT4E;wOAQwBy9BAWnVet6CoBRuFbz9BgC,A,A;umCHoRUgxE+H;2hFA8GFmCiC;mCAAAAA2CtdK11CAxCoFbz9B2B,oBAAAAkD,A,A;oEHmY1Bs6CwE;AAA2Bw+BA2CpdD94E4B,iC;sB3Cqd1Bs6CwE;AAA4BvZA2CldD/gC4B,kC;qB3Cmd3Bs6CwE;AAA2BhJA2ChdDtxC4B,qB;iK3CwDbymE8C;+BAAax2BiD;k6GAwLpBmN4K;AAEAipByV;m3BA0FQ7nBiC;iBAA4B4SAxC66BpB5S6C,A;2BwC56BlBlEkD;qyBAwCqBpayD;oa2CzTZlgCK;mEAEI05BkD;oQAaY2jD4B;6GAIbniD0C;iBAAAAsC;yKAKP68CiChChG8Bt6CARuFbz9B2B,oBAAAAgC,A,A;gKwC2BI+kDAhCtGWAwB,A;wwDgCmH7BhKkH;0nC0EPM0gCsB;gBAAW72EoD9ClGjB0tF6E,0E;Y8CkGiB1tFwD;cAAAAqF;QAIfyyCgB;AAAO6kCqC;0EAKSnEmE;8BAAAAA1GjISt6CARuFbz9B2B,oBAAAAgC,A,A;+HkHoDEiiC4E;YAAAAA1GrImCxEARiFrCz9B2B,oBAAAAgC,A,A;yFkHuDEkgD6B;YAAAAA1GrIoCziBAR8EtCz9B2B,oBAAAAgC,A,A;gPkHqEdq3CgErHCer3C+C,A;AqHDRoxDAzDhHG5SuC,A;AyDiHenHArHAVr3CiD,A;4LqHMdymE+D;4iBA4BSjoBqC;qFAGSnHArHrCJr3CiF,oB;AqHqCzBg/BAzD1KwBh/B8F,A;8HyD0KxBlwD+E;qFAKiBgpIarHtDoB5LqC,A;AqHsDb1uBuC;+QAcds6B8BrHpE2B5LmC,A;qEqHqE3BnsCcrHjE6BmsCqC,A;wEqHkE7B57BarH9D2B47BuC,A;yXqHqET4LArH7ES5LmC,A;4DqH8ERnsC6BrH1EUmsCmC,A;6DqH2EX57B4BrHvES47BmC,A;gPqH8E1BltEkB;AADayuEsB;yCAIV2nBAA8BG5xCkB,6DAAAA4D,6EACF4KqE,A;4BA5BI0pBArH5FkB5L6C,A;iBqH4FvCn+Bc;sCAGYhOArH3F6BmsCmC,A;AqH2FrB9bsD;gCAGGrwBArH9FkBmsCqC,A;AqH8FvCn+Bc;+DAIUuCArH9F2B47BmC,A;AqH8FpB9bsD;6BAGI9fArHjGgB47BqC,A;AqHiGrCn+Bc;6DAMFAkD;0jBAiBoBphGM;09EChRlBgoH6B;sErGiDoCx4CoF;k8BuB5B5BgnBuM;AAFEnkCA4EKcq2FAAqDECgR,A,AApDJn5EAAOpBnd2H,A,AANuBCApKoMhB27BAFnCbAAAAAA0C,A,A,A,uD;gF0FnKS0eA+EjCPAY,A;A/EiCOqqBAxC4D0DyakC,A;AwC5D1D9kCA+EjCPAO,iD;A/EkCOSA+E9BPAmF,A;A/E+BiBw7CA6EsCOp5EAAvCPs5EAAAAz2FA9C1BnBAAAAAAAAC0B22F+H,A,A,A,A,A8CiDiBnL8Y,AAmB3CruEAAAAAuCAW6Bg2DArH6D6B11CAEjJtBAoBC2FRz9BgC,A,A,A,kIkHHC4oCqD,uH,A,A,A;i5qFzL2zCViuDoL;oZAUACwL;kZAUACsH;waAUAC0H;+tBqCn8BgCzM8C;6xEoFpc7B5tFAD3DYktF4C,A;oF/DAP7pFiB8GKFi9D6B,AACK92BiC,AACV0mC6B,A;wF9GAS7sEmBgHGJi9DmC,AACK92BqC,AACV0mC6E,AACQ/yB8C,A;gFhHEH95Ce+GVAi9D6B,AACK92B+D,AACV0mC2D,AACQ/yB6B,A;8gB3GHT95Cc;spD0CqBWAc;09C/C3BZAc;qFFHAAc;ilBoDesBmdyb;OAAAA0B;kwBxGmIbteAAqE3BgkF4B,A;"}}
\ No newline at end of file
diff --git a/pkgs/coverage/test/test_files/test_app.dart b/pkgs/coverage/test/test_files/test_app.dart
new file mode 100644
index 0000000..1e50703
--- /dev/null
+++ b/pkgs/coverage/test/test_files/test_app.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// coverage:ignore-file
+
+import 'dart:async';
+import 'dart:developer';
+import 'dart:isolate';
+
+import 'package:coverage/src/util.dart';
+
+import 'test_app_isolate.dart';
+
+part 'test_app.g.dart';
+
+Future<void> main() async {
+ for (var i = 0; i < 10; i++) {
+ for (var j = 0; j < 10; j++) {
+ final sum = usedMethod(i, j);
+ if (sum != (i + j)) {
+ throw 'bad method!';
+ }
+
+ final multiplication = usedGeneratedMethod(i, j);
+ if (multiplication != i * j) {
+ throw 'bad generated method!';
+ }
+ }
+ }
+
+ final port = ReceivePort();
+
+ final isolate =
+ await Isolate.spawn(isolateTask, [port.sendPort, 1, 2], paused: true);
+ await Service.controlWebServer(enable: true);
+ final isolateID = Service.getIsolateID(isolate);
+ print('isolateId = $isolateID');
+
+ isolate.addOnExitListener(port.sendPort);
+ isolate.resume(isolate.pauseCapability!);
+
+ final value = await port.first as int;
+ if (value != 3) {
+ throw 'expected 3!';
+ }
+
+ final result = await retry(() async => 42, const Duration(seconds: 1)) as int;
+ print(result);
+}
+
+int usedMethod(int a, int b) {
+ return a + b;
+}
+
+int unusedMethod(int a, int b) {
+ return a - b;
+}
+
+// ignore_for_file: unreachable_from_main, only_throw_errors
+// ignore_for_file: deprecated_member_use
diff --git a/pkgs/coverage/test/test_files/test_app.g.dart b/pkgs/coverage/test/test_files/test_app.g.dart
new file mode 100644
index 0000000..c80718a
--- /dev/null
+++ b/pkgs/coverage/test/test_files/test_app.g.dart
@@ -0,0 +1,5 @@
+part of 'test_app.dart';
+
+int usedGeneratedMethod(int a, int b) {
+ return a * b;
+}
diff --git a/pkgs/coverage/test/test_files/test_app_isolate.dart b/pkgs/coverage/test/test_files/test_app_isolate.dart
new file mode 100644
index 0000000..8bbc6be
--- /dev/null
+++ b/pkgs/coverage/test/test_files/test_app_isolate.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:isolate';
+
+const int answer = 42;
+
+String fooSync(int x) {
+ if (x == answer) {
+ return '*' * x;
+ }
+ return List.generate(x, (_) => 'xyzzy').join(' ');
+}
+
+class BarClass {
+ BarClass(this.x);
+
+ int x;
+
+ void baz() {
+ print(x);
+ }
+}
+
+Future<String> fooAsync(int x) async {
+ if (x == answer) {
+ return '*' * x;
+ }
+ return List.generate(x, (_) => 'xyzzy').join(' ');
+}
+
+/// The number of covered lines is tested and expected to be 4.
+///
+/// If you modify this method, you may have to update the tests!
+void isolateTask(List threeThings) async {
+ sleep(const Duration(milliseconds: 500));
+
+ fooSync(answer);
+ unawaited(fooAsync(answer).then((_) {
+ final port = threeThings.first as SendPort;
+ final sum = (threeThings[1] as int) + (threeThings[2] as int);
+ port.send(sum);
+ }));
+
+ final bar = BarClass(123);
+ bar.baz();
+
+ print('678'); // coverage:ignore-line
+
+ // coverage:ignore-start
+ print('1');
+ print('2');
+ print('3');
+ // coverage:ignore-end
+
+ print('4 // coverage:ignore-line');
+ print('5 // coverage:ignore-file');
+
+ print('6'); // coverage:ignore-start
+ print('7');
+ print('8');
+ // coverage:ignore-end
+ print('9'); // coverage:ignore-start
+ print('10');
+ print('11'); // coverage:ignore-line
+
+ // Regression test for https://github.com/dart-lang/tools/issues/520.
+ await Isolate.run(() => print('Isolate.run'), debugName: 'Grandchild');
+ // coverage:ignore-end
+}
diff --git a/pkgs/coverage/test/test_files/test_library.dart b/pkgs/coverage/test/test_files/test_library.dart
new file mode 100644
index 0000000..d2fe49f
--- /dev/null
+++ b/pkgs/coverage/test/test_files/test_library.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part 'test_library_part.dart';
+
+int libraryFunction() {
+ return 123;
+}
diff --git a/pkgs/coverage/test/test_files/test_library_part.dart b/pkgs/coverage/test/test_files/test_library_part.dart
new file mode 100644
index 0000000..c99876d
--- /dev/null
+++ b/pkgs/coverage/test/test_files/test_library_part.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of 'test_library.dart';
+
+int otherLibraryFunction() {
+ return 123;
+}
diff --git a/pkgs/coverage/test/test_util.dart b/pkgs/coverage/test/test_util.dart
new file mode 100644
index 0000000..e0a3edb
--- /dev/null
+++ b/pkgs/coverage/test/test_util.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test_process/test_process.dart';
+
+final String testAppPath = p.join('test', 'test_files', 'test_app.dart');
+
+const Duration timeout = Duration(seconds: 20);
+
+Future<TestProcess> runTestApp(int openPort) => TestProcess.start(
+ Platform.resolvedExecutable,
+ [
+ '--enable-vm-service=$openPort',
+ '--pause_isolates_on_exit',
+ '--branch-coverage',
+ testAppPath
+ ],
+ );
+
+List<Map<String, dynamic>> coverageDataFromJson(Map<String, dynamic> json) {
+ expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
+ expect(json, containsPair('type', 'CodeCoverage'));
+
+ return (json['coverage'] as List).cast<Map<String, dynamic>>();
+}
+
+final _versionPattern = RegExp('([0-9]+)\\.([0-9]+)\\.([0-9]+)');
+
+bool platformVersionCheck(int minMajor, int minMinor) {
+ final match = _versionPattern.matchAsPrefix(Platform.version);
+ if (match == null) return false;
+ if (match.groupCount < 3) return false;
+ final major = int.parse(match.group(1)!);
+ final minor = int.parse(match.group(2)!);
+ return major > minMajor || (major == minMajor && minor >= minMinor);
+}
+
+/// Returns a mapping of (URL: (function_name: hit_count)) from [sources].
+Map<String, Map<String, int>> functionInfoFromSources(
+ Map<String, List<Map<dynamic, dynamic>>> sources,
+) {
+ Map<int, String> getFuncNames(List list) {
+ return {
+ for (var i = 0; i < list.length; i += 2)
+ list[i] as int: list[i + 1] as String,
+ };
+ }
+
+ Map<int, int> getFuncHits(List list) {
+ return {
+ for (var i = 0; i < list.length; i += 2)
+ list[i] as int: list[i + 1] as int,
+ };
+ }
+
+ return {
+ for (var entry in sources.entries)
+ entry.key: entry.value.fold(
+ {},
+ (previousValue, element) {
+ expect(element['source'], entry.key);
+ final names = getFuncNames(element['funcNames'] as List);
+ final hits = getFuncHits(element['funcHits'] as List);
+
+ for (var pair in hits.entries) {
+ previousValue[names[pair.key]!] =
+ (previousValue[names[pair.key]!] ?? 0) + pair.value;
+ }
+
+ return previousValue;
+ },
+ ),
+ };
+}
+
+extension ListTestExtension on List {
+ Map<String, List<Map<dynamic, dynamic>>> sources() => cast<Map>().fold(
+ <String, List<Map>>{},
+ (Map<String, List<Map>> map, value) {
+ final sourceUri = value['source'] as String;
+ map.putIfAbsent(sourceUri, () => <Map>[]).add(value);
+ return map;
+ },
+ );
+}
diff --git a/pkgs/coverage/test/test_with_coverage_package/lib/validate_lib.dart b/pkgs/coverage/test/test_with_coverage_package/lib/validate_lib.dart
new file mode 100644
index 0000000..771c040
--- /dev/null
+++ b/pkgs/coverage/test/test_with_coverage_package/lib/validate_lib.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+int sum(Iterable<int> values) {
+ var val = 0;
+ for (var value in values) {
+ val += value;
+ }
+ return val;
+}
+
+int product(Iterable<int> values) {
+ var val = 1;
+ for (var value in values) {
+ val *= value;
+ }
+ return val;
+}
diff --git a/pkgs/coverage/test/test_with_coverage_package/pubspec.yaml b/pkgs/coverage/test/test_with_coverage_package/pubspec.yaml
new file mode 100644
index 0000000..3fa7ee0
--- /dev/null
+++ b/pkgs/coverage/test/test_with_coverage_package/pubspec.yaml
@@ -0,0 +1,12 @@
+name: coverage_integration_test_for_test_with_coverage
+publish_to: none
+
+environment:
+ sdk: '>=2.15.0 <3.0.0'
+
+dev_dependencies:
+ test: ^1.16.0
+
+dependency_overrides:
+ coverage:
+ path: ../../
diff --git a/pkgs/coverage/test/test_with_coverage_package/test/product_test.dart b/pkgs/coverage/test/test_with_coverage_package/test/product_test.dart
new file mode 100644
index 0000000..91eac53
--- /dev/null
+++ b/pkgs/coverage/test/test_with_coverage_package/test/product_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+
+// ignore: avoid_relative_lib_imports
+import '../lib/validate_lib.dart';
+
+void main() {
+ test('product', () {
+ expect(product([2, 3]), 6);
+ });
+}
diff --git a/pkgs/coverage/test/test_with_coverage_package/test/sum_test.dart b/pkgs/coverage/test/test_with_coverage_package/test/sum_test.dart
new file mode 100644
index 0000000..f5b1ea4
--- /dev/null
+++ b/pkgs/coverage/test/test_with_coverage_package/test/sum_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+
+// ignore: avoid_relative_lib_imports
+import '../lib/validate_lib.dart';
+
+void main() {
+ test('sum', () {
+ expect(sum([1, 2]), 3);
+ });
+}
diff --git a/pkgs/coverage/test/test_with_coverage_test.dart b/pkgs/coverage/test/test_with_coverage_test.dart
new file mode 100644
index 0000000..689452d
--- /dev/null
+++ b/pkgs/coverage/test/test_with_coverage_test.dart
@@ -0,0 +1,157 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Timeout(Duration(seconds: 60))
+library;
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
+import 'package:test_process/test_process.dart';
+
+import 'test_util.dart';
+
+// this package
+final _pkgDir = p.absolute('');
+final _testWithCoveragePath = p.join(_pkgDir, 'bin', 'test_with_coverage.dart');
+
+// test package
+final _testPkgDirPath = p.join(_pkgDir, 'test', 'test_with_coverage_package');
+
+/// Override PUB_CACHE
+///
+/// Use a subdirectory different from `test/` just in case there is a problem
+/// with the clean up. If other packages are present under the `test/`
+/// subdirectory their tests may accidentally get run when running `dart test`
+final _pubCachePathInTestPkgSubDir = p.join(_pkgDir, 'var', 'pub-cache');
+final _env = {'PUB_CACHE': _pubCachePathInTestPkgSubDir};
+
+const _testPackageName = 'coverage_integration_test_for_test_with_coverage';
+
+int _port = 9300;
+
+Iterable<File> _dartFiles(String dir) =>
+ Directory(p.join(_testPkgDirPath, dir)).listSync().whereType<File>();
+
+String _fixTestFile(String content) => content.replaceAll(
+ "import '../lib/",
+ "import 'package:$_testPackageName/",
+ );
+
+void main() {
+ setUpAll(() async {
+ for (var dir in const ['lib', 'test']) {
+ await d.dir(dir, [
+ for (var dartFile in _dartFiles(dir))
+ d.file(
+ p.basename(dartFile.path),
+ _fixTestFile(dartFile.readAsStringSync()),
+ ),
+ ]).create();
+ }
+
+ var pubspecContent =
+ File(p.join(_testPkgDirPath, 'pubspec.yaml')).readAsStringSync();
+
+ expect(
+ pubspecContent.replaceAll('\r\n', '\n'),
+ contains(r'''
+dependency_overrides:
+ coverage:
+ path: ../../
+'''),
+ );
+
+ pubspecContent =
+ pubspecContent.replaceFirst('path: ../../', 'path: $_pkgDir');
+
+ await d.file('pubspec.yaml', pubspecContent).create();
+
+ final localPub = await _run(['pub', 'get']);
+ await localPub.shouldExit(0);
+ });
+
+ test('dart run bin/test_with_coverage.dart -f', () async {
+ final list = await _runTest(['run', _testWithCoveragePath, '-f']);
+
+ final sources = list.sources();
+ final functionHits = functionInfoFromSources(sources);
+
+ expect(
+ functionHits['package:$_testPackageName/validate_lib.dart'],
+ {
+ 'product': 1,
+ 'sum': 1,
+ },
+ );
+ });
+
+ test('dart run bin/test_with_coverage.dart -f -- -N sum', () async {
+ final list = await _runTest(
+ ['run', _testWithCoveragePath, '-f'],
+ extraArgs: ['--', '-N', 'sum'],
+ );
+
+ final sources = list.sources();
+ final functionHits = functionInfoFromSources(sources);
+
+ expect(
+ functionHits['package:$_testPackageName/validate_lib.dart'],
+ {
+ 'product': 0,
+ 'sum': 1,
+ },
+ reason: 'only `sum` tests should be run',
+ );
+ });
+
+ test('dart run coverage:test_with_coverage', () async {
+ await _runTest(['run', 'coverage:test_with_coverage']);
+ });
+
+ test('dart pub global run coverage:test_with_coverage', () async {
+ final globalPub =
+ await _run(['pub', 'global', 'activate', '-s', 'path', _pkgDir]);
+ await globalPub.shouldExit(0);
+
+ await _runTest(
+ ['pub', 'global', 'run', 'coverage:test_with_coverage'],
+ );
+ });
+}
+
+Future<TestProcess> _run(List<String> args) => TestProcess.start(
+ Platform.executable,
+ args,
+ workingDirectory: d.sandbox,
+ environment: _env,
+ );
+
+Future<List<Map<String, dynamic>>> _runTest(
+ List<String> invokeArgs, {
+ List<String>? extraArgs,
+}) async {
+ final process = await _run([
+ ...invokeArgs,
+ '--port',
+ '${_port++}',
+ ...?extraArgs,
+ ]);
+
+ await process.shouldExit(0);
+
+ await d.dir(
+ 'coverage',
+ [d.file('coverage.json', isNotEmpty), d.file('lcov.info', isNotEmpty)],
+ ).validate();
+
+ final coverageDataFile = File(p.join(d.sandbox, 'coverage', 'coverage.json'));
+
+ final json = jsonDecode(coverageDataFile.readAsStringSync());
+
+ return coverageDataFromJson(json as Map<String, dynamic>);
+}
diff --git a/pkgs/coverage/test/util_test.dart b/pkgs/coverage/test/util_test.dart
new file mode 100644
index 0000000..6a4e556
--- /dev/null
+++ b/pkgs/coverage/test/util_test.dart
@@ -0,0 +1,358 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: only_throw_errors
+
+import 'dart:async';
+
+import 'package:coverage/src/util.dart';
+import 'package:test/test.dart';
+
+const _failCount = 5;
+const _delay = Duration(milliseconds: 10);
+
+void main() {
+ test('retry', () async {
+ var count = 0;
+ final stopwatch = Stopwatch()..start();
+
+ Future failCountTimes() async {
+ expect(stopwatch.elapsed, greaterThanOrEqualTo(_delay * count));
+
+ while (count < _failCount) {
+ count++;
+ throw 'not yet!';
+ }
+ return 42;
+ }
+
+ final value = await retry(failCountTimes, _delay) as int;
+
+ expect(value, 42);
+ expect(count, _failCount);
+ expect(stopwatch.elapsed, greaterThanOrEqualTo(_delay * count));
+ });
+
+ group('retry with timeout', () {
+ test('if it finishes', () async {
+ var count = 0;
+ final stopwatch = Stopwatch()..start();
+
+ Future failCountTimes() async {
+ expect(stopwatch.elapsed, greaterThanOrEqualTo(_delay * count));
+
+ while (count < _failCount) {
+ count++;
+ throw 'not yet!';
+ }
+ return 42;
+ }
+
+ final safeTimoutDuration = _delay * _failCount * 10;
+ final value = await retry(
+ failCountTimes,
+ _delay,
+ timeout: safeTimoutDuration,
+ ) as int;
+
+ expect(value, 42);
+ expect(count, _failCount);
+ expect(stopwatch.elapsed, greaterThanOrEqualTo(_delay * count));
+ });
+
+ test('if it does not finish', () async {
+ var count = 0;
+ final stopwatch = Stopwatch()..start();
+
+ var caught = false;
+ var countAfterError = 0;
+
+ Future failCountTimes() async {
+ if (caught) {
+ countAfterError++;
+ }
+ expect(stopwatch.elapsed, greaterThanOrEqualTo(_delay * count));
+
+ count++;
+ throw 'never';
+ }
+
+ final unsafeTimeoutDuration = _delay * (_failCount / 2);
+
+ try {
+ await retry(failCountTimes, _delay, timeout: unsafeTimeoutDuration);
+ // ignore: avoid_catching_errors
+ } on StateError catch (e) {
+ expect(e.message, 'Failed to complete within 25ms');
+ caught = true;
+
+ expect(countAfterError, 0,
+ reason: 'Execution should stop after a timeout');
+
+ await Future<dynamic>.delayed(_delay * 3);
+
+ expect(countAfterError, 0, reason: 'Even after a delay');
+ }
+
+ expect(caught, isTrue);
+ });
+ });
+
+ group('extractVMServiceUri', () {
+ test('returns null when not found', () {
+ expect(extractVMServiceUri('foo bar baz'), isNull);
+ });
+
+ test('returns null for an incorrectly formatted URI', () {
+ const msg = 'Observatory listening on :://';
+ expect(extractVMServiceUri(msg), null);
+ });
+
+ test('returns URI at end of string', () {
+ const msg = 'Observatory listening on http://foo.bar:9999/';
+ expect(extractVMServiceUri(msg), Uri.parse('http://foo.bar:9999/'));
+ });
+
+ test('returns URI with auth token at end of string', () {
+ const msg = 'Observatory listening on http://foo.bar:9999/cG90YXRv/';
+ expect(
+ extractVMServiceUri(msg), Uri.parse('http://foo.bar:9999/cG90YXRv/'));
+ });
+
+ test('return URI embedded within string', () {
+ const msg = '1985-10-26 Observatory listening on http://foo.bar:9999/ **';
+ expect(extractVMServiceUri(msg), Uri.parse('http://foo.bar:9999/'));
+ });
+
+ test('return URI with auth token embedded within string', () {
+ const msg =
+ '1985-10-26 Observatory listening on http://foo.bar:9999/cG90YXRv/ **';
+ expect(
+ extractVMServiceUri(msg), Uri.parse('http://foo.bar:9999/cG90YXRv/'));
+ });
+
+ test('handles new Dart VM service message format', () {
+ const msg =
+ 'The Dart VM service is listening on http://foo.bar:9999/cG90YXRv/';
+ expect(
+ extractVMServiceUri(msg), Uri.parse('http://foo.bar:9999/cG90YXRv/'));
+ });
+ });
+
+ group('getIgnoredLines', () {
+ const invalidSources = [
+ '''final str = ''; // coverage:ignore-start
+ final str = '';
+ final str = ''; // coverage:ignore-start
+ ''',
+ '''final str = ''; // coverage:ignore-start
+ final str = '';
+ final str = ''; // coverage:ignore-start
+ final str = ''; // coverage:ignore-end
+ final str = '';
+ final str = ''; // coverage:ignore-end
+ ''',
+ '''final str = ''; // coverage:ignore-start
+ final str = '';
+ final str = ''; // coverage:ignore-end
+ final str = '';
+ final str = ''; // coverage:ignore-end
+ ''',
+ '''final str = ''; // coverage:ignore-end
+ final str = '';
+ final str = ''; // coverage:ignore-start
+ final str = '';
+ final str = ''; // coverage:ignore-end
+ ''',
+ '''final str = ''; // coverage:ignore-end
+ final str = '';
+ final str = ''; // coverage:ignore-end
+ ''',
+ '''final str = ''; // coverage:ignore-end
+ final str = '';
+ final str = ''; // coverage:ignore-start
+ ''',
+ '''final str = ''; // coverage:ignore-end
+ ''',
+ '''final str = ''; // coverage:ignore-start
+ ''',
+ ];
+
+ test('throws FormatException when the annotations are not balanced', () {
+ void runTest(int index, String errMsg) {
+ final content = invalidSources[index].split('\n');
+ expect(
+ () => getIgnoredLines('content-$index.dart', content),
+ throwsA(
+ allOf(
+ isFormatException,
+ predicate((FormatException e) => e.message == errMsg),
+ ),
+ ),
+ reason: 'expected FormatException with message "$errMsg"',
+ );
+ }
+
+ runTest(
+ 0,
+ 'coverage:ignore-start found at content-0.dart:'
+ '3 before previous coverage:ignore-start ended',
+ );
+ runTest(
+ 1,
+ 'coverage:ignore-start found at content-1.dart:'
+ '3 before previous coverage:ignore-start ended',
+ );
+ runTest(
+ 2,
+ 'unmatched coverage:ignore-end found at content-2.dart:5',
+ );
+ runTest(
+ 3,
+ 'unmatched coverage:ignore-end found at content-3.dart:1',
+ );
+ runTest(
+ 4,
+ 'unmatched coverage:ignore-end found at content-4.dart:1',
+ );
+ runTest(
+ 5,
+ 'unmatched coverage:ignore-end found at content-5.dart:1',
+ );
+ runTest(
+ 6,
+ 'unmatched coverage:ignore-end found at content-6.dart:1',
+ );
+ runTest(
+ 7,
+ 'coverage:ignore-start found at content-7.dart:'
+ '1 has no matching coverage:ignore-end',
+ );
+ });
+
+ test(
+ 'returns [[0,lines.length]] when the annotations are not '
+ 'balanced but the whole file is ignored', () {
+ for (final content in invalidSources) {
+ final lines = content.split('\n');
+ lines.add(' // coverage:ignore-file');
+ expect(getIgnoredLines('', lines), [
+ [0, lines.length]
+ ]);
+ }
+ });
+
+ test('returns [[0,lines.length]] when the whole file is ignored', () {
+ final lines = '''final str = ''; // coverage:ignore-start
+ final str = ''; // coverage:ignore-end
+ final str = ''; // coverage:ignore-file
+ '''
+ .split('\n');
+
+ expect(getIgnoredLines('', lines), [
+ [0, lines.length]
+ ]);
+ });
+
+ test('return the correct range of lines ignored', () {
+ final lines = '''
+ final str = ''; // coverage:ignore-start
+ final str = ''; // coverage:ignore-line
+ final str = ''; // coverage:ignore-end
+ final str = ''; // coverage:ignore-start
+ final str = ''; // coverage:ignore-line
+ final str = ''; // coverage:ignore-end
+ '''
+ .split('\n');
+
+ expect(getIgnoredLines('', lines), [
+ [1, 3],
+ [4, 6],
+ ]);
+ });
+
+ test('return the correct list of lines ignored', () {
+ final lines = '''
+ final str = ''; // coverage:ignore-line
+ final str = ''; // coverage:ignore-line
+ final str = ''; // coverage:ignore-line
+ '''
+ .split('\n');
+
+ expect(getIgnoredLines('', lines), [
+ [1, 1],
+ [2, 2],
+ [3, 3],
+ ]);
+ });
+
+ test('ignore comments have no effect inside string literals', () {
+ final lines = '''
+ final str = '// coverage:ignore-file';
+ final str = '// coverage:ignore-line';
+ final str = ''; // coverage:ignore-line
+ final str = '// coverage:ignore-start';
+ final str = '// coverage:ignore-end';
+ '''
+ .split('\n');
+
+ expect(getIgnoredLines('', lines), [
+ [3, 3],
+ ]);
+ });
+
+ test('allow white-space after ignore comments', () {
+ // Using multiple strings, rather than splitting a multi-line string,
+ // because many code editors remove trailing white-space.
+ final lines = [
+ "final str = ''; // coverage:ignore-start ",
+ "final str = ''; // coverage:ignore-line\t",
+ "final str = ''; // coverage:ignore-end \t \t ",
+ "final str = ''; // coverage:ignore-line \t ",
+ "final str = ''; // coverage:ignore-start \t ",
+ "final str = ''; // coverage:ignore-end \t \t ",
+ ];
+
+ expect(getIgnoredLines('', lines), [
+ [1, 3],
+ [4, 4],
+ [5, 6],
+ ]);
+ });
+
+ test('allow omitting space after //', () {
+ final lines = [
+ "final str = ''; //coverage:ignore-start",
+ "final str = ''; //coverage:ignore-line",
+ "final str = ''; //coverage:ignore-end",
+ "final str = ''; //coverage:ignore-line",
+ "final str = ''; //coverage:ignore-start",
+ "final str = ''; //coverage:ignore-end",
+ ];
+
+ expect(getIgnoredLines('', lines), [
+ [1, 3],
+ [4, 4],
+ [5, 6],
+ ]);
+ });
+
+ test('allow text after ignore comments', () {
+ final lines = [
+ "final str = ''; // coverage:ignore-start due to XYZ",
+ "final str = ''; // coverage:ignore-line",
+ "final str = ''; // coverage:ignore-end due to XYZ",
+ "final str = ''; // coverage:ignore-line due to 123",
+ "final str = ''; // coverage:ignore-start",
+ "final str = ''; // coverage:ignore-end it is done",
+ ];
+
+ expect(getIgnoredLines('', lines), [
+ [1, 3],
+ [4, 4],
+ [5, 6],
+ ]);
+ });
+ });
+}
diff --git a/pkgs/csslib/.gitignore b/pkgs/csslib/.gitignore
new file mode 100644
index 0000000..c107fc6
--- /dev/null
+++ b/pkgs/csslib/.gitignore
@@ -0,0 +1,4 @@
+.dart_tool
+.packages
+pubspec.lock
+doc/api/
diff --git a/pkgs/csslib/CHANGELOG.md b/pkgs/csslib/CHANGELOG.md
new file mode 100644
index 0000000..366c3a6
--- /dev/null
+++ b/pkgs/csslib/CHANGELOG.md
@@ -0,0 +1,233 @@
+## 1.0.2
+
+- Require Dart 3.1
+- Move to `dart-lang/tools` monorepo.
+
+## 1.0.1
+
+- Update `ExpressionsProcessor.processFont` to handle null expressions.
+- Require Dart 3.0.
+
+## 1.0.0
+
+- Rev to `1.0.0` (note however that there are no API changes from `0.17.x`).
+
+## 0.17.3
+
+- Add markdown badges to the readme.
+- Adopted `package:dart_flutter_team_lints` linting rules.
+- Addressed an issue parsing font names not surrounded by quotes.
+- Fixed the reported span for `Expression` nodes.
+- Fixed a regression parsing declaration values containing spaces.
+- Add support for `lh` and `rlh` units.
+- Refactor the package example.
+- Addressed an issue with the indent level of the `CssPrinter` output.
+- Require Dart 2.19.
+
+## 0.17.2
+
+- Fixed a crash caused by `min()`, `max()` and `clamp()` functions that contain
+ mathematical expressions.
+- Add commas between PercentageTerms in keyframe rules.
+
+## 0.17.1
+
+- Fix `Color.css` constructor when there are double values in the `rgba` string.
+
+## 0.17.0
+
+- Migrate to null safety.
+- `Font.merge` and `BoxEdge.merge` are now static methods instead of factory
+ constructors.
+- Add a type on the `identList` argument to `TokenKind.matchList`.
+- Remove workaround for https://github.com/dart-lang/sdk/issues/43136, which is
+ now fixed.
+
+## 0.16.2
+
+- Added support for escape codes in identifiers.
+
+## 0.16.1
+
+- Fixed a crash caused by parsing certain calc() expressions and variables names that contain numbers.
+
+## 0.16.0
+
+- Removed support for the shadow-piercing comibnators `/deep/` and `>>>`. These
+ were dropped from the Shadow DOM specification.
+
+## 0.15.0
+
+- **BREAKING**
+ - Removed `css` executable from `bin` directory.
+ - Removed the deprecated `css.dart` library.
+ - `Message.level` is now of type `MessageLevel` defined in this package.
+- Removed dependencies on `package:args` and `package:logging`.
+- Require Dart SDK `>=2.1.0`.
+
+## 0.14.6
+
+* Removed whitespace between comma-delimited expressions in compact output.
+
+ Before:
+ ```css
+ div{color:rgba(0, 0, 0, 0.5);}
+ ```
+
+ After:
+ ```css
+ div{color:rgba(0,0,0,0.5);}
+ ```
+
+* Removed last semicolon from declaration groups in compact output.
+
+ Before:
+ ```css
+ div{color:red;background:blue;}
+ ```
+
+ After:
+ ```css
+ div{color:red;background:blue}
+ ```
+
+## 0.14.5
+
+* Fixed a crashed caused by parsing `:host()` without an argument and added an
+ error message explaining that a selector argument is expected.
+
+## 0.14.4+1
+
+* Set max SDK version to `<3.0.0`, and adjust other dependencies.
+
+## 0.14.4
+
+* Reduced whitespace in compact output for the `@page` at-rule and margin boxes.
+* Updated SDK version to 2.0.0-dev.17.0.
+* Stop using deprecated constants.
+
+## 0.14.3
+
+* Reduced the amount of whitespace in compact output around braces.
+
+## 0.14.2
+
+* Fixed Dart 2 runtime failure.
+
+## 0.14.1
+
+* Deprecated `package:csslib/css.dart`.
+ Use `parser.dart` and `visitor.dart` instead.
+
+## 0.14.0
+
+### New features
+
+* Supports nested at-rules.
+* Supports nested HTML comments in CSS comments and vice-versa.
+
+### Breaking changes
+
+* The `List<RuleSet> rulesets` field on `MediaDirective`, `HostDirective`, and
+ `StyletDirective` has been replaced by `List<TreeNode> rules` to allow nested
+ at-rules in addition to rulesets.
+
+## 0.13.6
+
+* Adds support for `@viewport`.
+* Adds support for `-webkit-calc()` and `-moz-calc()`.
+* Adds support for querying media features without specifying an expression. For
+ example: `@media (transform-3d) { ... }`.
+* Prevents exception being thrown for invalid dimension terms, and instead
+ issues an error.
+
+## 0.13.5
+
+* Adds support for `@-moz-document`.
+* Adds support for `@supports`.
+
+## 0.13.4
+
+* Parses CSS 2.1 pseudo-elements as pseudo-elements instead of pseudo-classes.
+* Supports signed decimal numbers with no integer part.
+* Fixes parsing hexadecimal numbers when followed by an identifier.
+* Fixes parsing strings which contain unicode-range character sequences.
+
+## 0.13.3+1
+
+* Fixes analyzer error.
+
+## 0.13.3
+
+* Adds support for shadow host selectors `:host()` and `:host-context()`.
+* Adds support for shadow-piercing descendant combinator `>>>` and its alias
+ `/deep/` for backwards compatibility.
+* Adds support for non-functional IE filter properties (i.e. `filter: FlipH`).
+* Fixes emitted CSS for `@page` directive when body includes declarations and
+ page-margin boxes.
+* Exports `Message` from `parser.dart` so it's no longer necessary to import
+ `src/messages.dart` to use the parser API.
+
+## 0.13.2+2
+
+* Fix static warnings.
+
+## 0.13.2+1
+
+* Fix new strong mode error.
+
+## 0.13.2
+
+* Relax type of TreeNode.visit, to allow returning values from visitors.
+
+## 0.13.1
+
+* Fix two checked mode bugs introduced in 0.13.0.
+
+## 0.13.0
+
+ * **BREAKING** Fix all [strong mode][] errors and warnings.
+ This involved adding more precise on some public APIs, which
+ is why it may break users.
+
+[strong mode]: https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
+
+## 0.12.2
+
+ * Fix to handle calc functions however, the expressions are treated as a
+ LiteralTerm and not fully parsed into the AST.
+
+## 0.12.1
+
+ * Fix to handling of escapes in strings.
+
+## 0.12.0+1
+
+* Allow the latest version of `logging` package.
+
+## 0.12.0
+
+* Top-level methods in `parser.dart` now take `PreprocessorOptions` instead of
+ `List<String>`.
+
+* `PreprocessorOptions.inputFile` is now final.
+
+## 0.11.0+4
+
+* Cleanup some ambiguous and some incorrect type signatures.
+
+## 0.11.0+3
+
+* Improve the speed and memory efficiency of parsing.
+
+## 0.11.0+2
+
+* Fix another test that was failing on IE10.
+
+## 0.11.0+1
+
+* Fix a test that was failing on IE10.
+
+## 0.11.0
+
+* Switch from `source_maps`' `Span` class to `source_span`'s `SourceSpan` class.
diff --git a/pkgs/csslib/LICENSE b/pkgs/csslib/LICENSE
new file mode 100644
index 0000000..ab3bfa0
--- /dev/null
+++ b/pkgs/csslib/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2013, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/csslib/README.md b/pkgs/csslib/README.md
new file mode 100644
index 0000000..edbd80d
--- /dev/null
+++ b/pkgs/csslib/README.md
@@ -0,0 +1,21 @@
+[](https://github.com/dart-lang/tools/actions/workflows/csslib.yaml)
+[](https://pub.dev/packages/csslib)
+[](https://pub.dev/packages/csslib/publisher)
+
+A Dart [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) parser.
+
+## Usage
+
+Parsing CSS is easy!
+
+```dart
+import 'package:csslib/parser.dart';
+
+void main() {
+ var stylesheet = parse(
+ '.foo { color: red; left: 20px; top: 20px; width: 100px; height:200px }');
+ print(stylesheet.toDebugString());
+}
+```
+
+You can pass a `String` or `List<int>` to `parse`.
diff --git a/pkgs/csslib/analysis_options.yaml b/pkgs/csslib/analysis_options.yaml
new file mode 100644
index 0000000..6c38fe4
--- /dev/null
+++ b/pkgs/csslib/analysis_options.yaml
@@ -0,0 +1,13 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+ errors:
+ comment_references: ignore # too many false positives
+
+linter:
+ rules:
+ - prefer_expression_function_bodies
diff --git a/pkgs/csslib/example/main.dart b/pkgs/csslib/example/main.dart
new file mode 100644
index 0000000..88dc748
--- /dev/null
+++ b/pkgs/csslib/example/main.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+
+import 'package:csslib/parser.dart' as css;
+import 'package:csslib/visitor.dart';
+
+void main() {
+ var errors = <css.Message>[];
+
+ // Parse a simple stylesheet.
+ print('1. Good CSS, parsed CSS emitted:');
+ print(' =============================');
+ var stylesheet = parseCss('''
+@import "support/at-charset-019.css";
+div { color: red; }
+button[type] { background-color: red; }
+.foo {
+ color: red; left: 20px; top: 20px; width: 100px; height:200px
+}
+#div {
+ color : #00F578; border-color: #878787;
+}
+''', errors: errors);
+
+ if (errors.isNotEmpty) {
+ print('Got ${errors.length} errors.\n');
+ for (var error in errors) {
+ print(error);
+ }
+ } else {
+ print(prettyPrint(stylesheet));
+ }
+
+ // Parse a stylesheet with errors
+ print('\n2. Catch severe syntax errors:');
+ print(' ===========================');
+ var stylesheetError = parseCss('''
+.foo #%^&*asdf {
+ color: red; left: 20px; top: 20px; width: 100px; height:200px
+}
+''', errors: errors);
+
+ if (errors.isNotEmpty) {
+ print('Got ${errors.length} errors.\n');
+ for (var error in errors) {
+ print(error);
+ }
+ } else {
+ print(stylesheetError.toString());
+ }
+
+ // Parse a stylesheet that warns (checks) problematic CSS.
+ print('\n3. Detect CSS problem with checking on:');
+ print(' ===================================');
+ stylesheetError = parseCss('# div1 { color: red; }', errors: errors);
+
+ if (errors.isNotEmpty) {
+ print('Detected ${errors.length} problem in checked mode.\n');
+ for (var error in errors) {
+ print(error);
+ }
+ } else {
+ print(stylesheetError.toString());
+ }
+
+ // Parse a CSS selector.
+ print('\n4. Parse a selector only:');
+ print(' ======================');
+ var selectorAst = css.selector('#div .foo', errors: errors);
+ if (errors.isNotEmpty) {
+ print('Got ${errors.length} errors.\n');
+ for (var error in errors) {
+ print(error);
+ }
+ } else {
+ print(prettyPrint(selectorAst));
+ }
+}
+
+/// Spin-up CSS parser in checked mode to detect any problematic CSS. Normally,
+/// CSS will allow any property/value pairs regardless of validity; all of our
+/// tests (by default) will ensure that the CSS is really valid.
+StyleSheet parseCss(
+ String cssInput, {
+ List<css.Message>? errors,
+ css.PreprocessorOptions? opts,
+}) =>
+ css.parse(cssInput, errors: errors, options: opts ?? _default);
+
+/// Pretty printer for CSS.
+String prettyPrint(StyleSheet ss) =>
+ (CssPrinter()..visitTree(ss, pretty: true)).toString();
+
+const _default = css.PreprocessorOptions(
+ useColors: false,
+ checked: true,
+ warningsAsErrors: true,
+ inputFile: 'memory',
+);
diff --git a/pkgs/csslib/lib/parser.dart b/pkgs/csslib/lib/parser.dart
new file mode 100644
index 0000000..4469298
--- /dev/null
+++ b/pkgs/csslib/lib/parser.dart
@@ -0,0 +1,2870 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' as math;
+
+import 'package:source_span/source_span.dart';
+
+import 'src/messages.dart';
+import 'src/preprocessor_options.dart';
+import 'visitor.dart';
+
+export 'src/messages.dart' show Message, MessageLevel;
+export 'src/preprocessor_options.dart';
+
+part 'src/analyzer.dart';
+part 'src/polyfill.dart';
+part 'src/property.dart';
+part 'src/token.dart';
+part 'src/token_kind.dart';
+part 'src/tokenizer.dart';
+part 'src/tokenizer_base.dart';
+
+enum ClauseType {
+ none,
+ conjunction,
+ disjunction,
+}
+
+/// Used for parser lookup ahead (used for nested selectors Less support).
+class ParserState extends TokenizerState {
+ final Token peekToken;
+ final Token? previousToken;
+
+ ParserState(this.peekToken, this.previousToken, Tokenizer tokenizer)
+ : super(tokenizer);
+}
+
+void _createMessages({List<Message>? errors, PreprocessorOptions? options}) {
+ errors ??= [];
+ options ??= const PreprocessorOptions(useColors: false, inputFile: 'memory');
+
+ messages = Messages(options: options, printHandler: errors.add);
+}
+
+/// CSS checked mode enabled.
+bool get isChecked => messages.options.checked;
+
+// TODO(terry): Remove nested name parameter.
+/// Parse and analyze the CSS file.
+StyleSheet compile(Object input,
+ {List<Message>? errors,
+ PreprocessorOptions? options,
+ bool nested = true,
+ bool polyfill = false,
+ List<StyleSheet>? includes}) {
+ includes ??= [];
+
+ var source = _inputAsString(input);
+
+ _createMessages(errors: errors, options: options);
+
+ var file = SourceFile.fromString(source);
+
+ var tree = _Parser(file, source).parse();
+
+ analyze([tree], errors: errors, options: options);
+
+ if (polyfill) {
+ var processCss = PolyFill(messages);
+ processCss.process(tree, includes: includes);
+ }
+
+ return tree;
+}
+
+/// Analyze the CSS file.
+void analyze(List<StyleSheet> styleSheets,
+ {List<Message>? errors, PreprocessorOptions? options}) {
+ _createMessages(errors: errors, options: options);
+ Analyzer(styleSheets, messages).run();
+}
+
+/// Parse the [input] CSS stylesheet into a tree.
+///
+/// The [input] can be a [String], or [List]`<int>` of bytes and returns a
+/// [StyleSheet] AST. The optional [errors] list will collect any error
+/// encountered.
+StyleSheet parse(
+ Object input, {
+ List<Message>? errors,
+ PreprocessorOptions? options,
+}) {
+ var source = _inputAsString(input);
+
+ _createMessages(errors: errors, options: options);
+
+ var file = SourceFile.fromString(source);
+ return _Parser(file, source).parse();
+}
+
+/// Parse the [input] CSS selector into a tree. The [input] can be a [String],
+/// or [List]`<int>` of bytes and returns a [StyleSheet] AST. The optional
+/// [errors] list will contain each error/warning as a [Message].
+// TODO(jmesserly): should rename "parseSelector" and return Selector
+StyleSheet selector(Object input, {List<Message>? errors}) {
+ var source = _inputAsString(input);
+
+ _createMessages(errors: errors);
+
+ var file = SourceFile.fromString(source);
+ return (_Parser(file, source)..tokenizer.inSelector = true).parseSelector();
+}
+
+SelectorGroup? parseSelectorGroup(Object input, {List<Message>? errors}) {
+ var source = _inputAsString(input);
+
+ _createMessages(errors: errors);
+
+ var file = SourceFile.fromString(source);
+ return (_Parser(file, source)
+ // TODO(jmesserly): this fix should be applied to the parser. It's
+ // tricky because by the time the flag is set one token has already
+ // been fetched.
+ ..tokenizer.inSelector = true)
+ .processSelectorGroup();
+}
+
+String _inputAsString(Object input) {
+ String source;
+
+ if (input is String) {
+ source = input;
+ } else if (input is List) {
+ // TODO(terry): The parse function needs an "encoding" argument and will
+ // default to whatever encoding CSS defaults to.
+ //
+ // Here's some info about CSS encodings:
+ // http://www.w3.org/International/questions/qa-css-charset.en.php
+ //
+ // As JMesserly suggests it will probably need a "pre-parser" html5lib
+ // (encoding_parser.dart) that interprets the bytes as ASCII and scans for
+ // @charset. But for now an "encoding" argument would work. Often the
+ // HTTP header will indicate the correct encoding.
+ //
+ // See encoding helpers at: package:html5lib/lib/src/char_encodings.dart
+ // These helpers can decode in different formats given an encoding name
+ // (mostly unicode, ascii, windows-1252 which is html5 default encoding).
+ source = String.fromCharCodes(input as List<int>);
+ } else {
+ // TODO(terry): Support RandomAccessFile using console.
+ throw ArgumentError("'source' must be a String or "
+ 'List<int> (of bytes). RandomAccessFile not supported from this '
+ 'simple interface');
+ }
+
+ return source;
+}
+
+// TODO(terry): Consider removing this class when all usages can be eliminated
+// or replaced with compile API.
+/// Public parsing interface for csslib.
+class Parser {
+ final _Parser _parser;
+
+ // TODO(jmesserly): having file and text is redundant.
+ // TODO(rnystrom): baseUrl isn't used. Remove from API.
+ Parser(SourceFile file, String text, {int start = 0, String? baseUrl})
+ : _parser = _Parser(file, text, start: start);
+
+ StyleSheet parse() => _parser.parse();
+}
+
+// CSS2.1 pseudo-elements which were defined with a single ':'.
+const _legacyPseudoElements = <String>{
+ 'after',
+ 'before',
+ 'first-letter',
+ 'first-line',
+};
+
+/// A simple recursive descent parser for CSS.
+class _Parser {
+ final Tokenizer tokenizer;
+
+ /// File containing the source being parsed, used to report errors with
+ /// source-span locations.
+ final SourceFile file;
+
+ Token? _previousToken;
+ late Token _peekToken;
+
+ _Parser(this.file, String text, {int start = 0})
+ : tokenizer = Tokenizer(file, text, true, start) {
+ _peekToken = tokenizer.next();
+ }
+
+ /// Main entry point for parsing an entire CSS file.
+ StyleSheet parse() {
+ var productions = <TreeNode>[];
+
+ var start = _peekToken.span;
+ while (!_maybeEat(TokenKind.END_OF_FILE) && !_peekKind(TokenKind.RBRACE)) {
+ // TODO(terry): Need to handle charset.
+ final rule = processRule();
+ if (rule != null) {
+ productions.add(rule);
+ } else {
+ break;
+ }
+ }
+
+ checkEndOfFile();
+
+ return StyleSheet(productions, _makeSpan(start));
+ }
+
+ /// Main entry point for parsing a simple selector sequence.
+ StyleSheet parseSelector() {
+ var productions = <TreeNode>[];
+
+ var start = _peekToken.span;
+ while (!_maybeEat(TokenKind.END_OF_FILE) && !_peekKind(TokenKind.RBRACE)) {
+ var selector = processSelector();
+ if (selector != null) {
+ productions.add(selector);
+ } else {
+ break; // Prevent infinite loop if we can't parse something.
+ }
+ }
+
+ checkEndOfFile();
+
+ return StyleSheet.selector(productions, _makeSpan(start));
+ }
+
+ /// Generate an error if [file] has not been completely consumed.
+ void checkEndOfFile() {
+ if (!(_peekKind(TokenKind.END_OF_FILE) ||
+ _peekKind(TokenKind.INCOMPLETE_COMMENT))) {
+ _error('premature end of file unknown CSS', _peekToken.span);
+ }
+ }
+
+ /// Guard to break out of parser when an unexpected end of file is found.
+ // TODO(jimhug): Failure to call this method can lead to infinite parser
+ // loops. Consider embracing exceptions for more errors to reduce
+ // the danger here.
+ bool isPrematureEndOfFile() {
+ if (_maybeEat(TokenKind.END_OF_FILE)) {
+ _error('unexpected end of file', _peekToken.span);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // Basic support methods
+ ///////////////////////////////////////////////////////////////////
+ int _peek() => _peekToken.kind;
+
+ Token _next({bool unicodeRange = false}) {
+ final next = _previousToken = _peekToken;
+ _peekToken = tokenizer.next(unicodeRange: unicodeRange);
+ return next;
+ }
+
+ bool _peekKind(int kind) => _peekToken.kind == kind;
+
+ // Is the next token a legal identifier? This includes pseudo-keywords.
+ bool _peekIdentifier() => TokenKind.isIdentifier(_peekToken.kind);
+
+ /// Marks the parser/tokenizer look ahead to support Less nested selectors.
+ ParserState get _mark => ParserState(_peekToken, _previousToken, tokenizer);
+
+ /// Restores the parser/tokenizer state to state remembered by _mark.
+ void _restore(ParserState markedData) {
+ tokenizer.restore(markedData);
+ _peekToken = markedData.peekToken;
+ _previousToken = markedData.previousToken;
+ }
+
+ bool _maybeEat(int kind, {bool unicodeRange = false}) {
+ if (_peekToken.kind == kind) {
+ _previousToken = _peekToken;
+ _peekToken = tokenizer.next(unicodeRange: unicodeRange);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void _eat(int kind, {bool unicodeRange = false}) {
+ if (!_maybeEat(kind, unicodeRange: unicodeRange)) {
+ _errorExpected(TokenKind.kindToString(kind));
+ }
+ }
+
+ void _errorExpected(String expected) {
+ var tok = _next();
+ String message;
+ try {
+ message = 'expected $expected, but found $tok';
+ } catch (e) {
+ message = 'parsing error expected $expected';
+ }
+ _error(message, tok.span);
+ }
+
+ void _error(String message, SourceSpan? location) {
+ location ??= _peekToken.span;
+ messages.error(message, location);
+ }
+
+ void _warning(String message, SourceSpan? location) {
+ location ??= _peekToken.span;
+ messages.warning(message, location);
+ }
+
+ FileSpan _makeSpan(FileSpan start) {
+ // TODO(terry): there are places where we are creating spans before we eat
+ // the tokens, so using _previousToken is not always valid.
+ // TODO(nweiz): use < rather than compareTo when SourceSpan supports it.
+ if (_previousToken == null || _previousToken!.span.compareTo(start) < 0) {
+ return start;
+ }
+ return start.expand(_previousToken!.span);
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // Top level productions
+ ///////////////////////////////////////////////////////////////////
+
+ /// The media_query_list production below replaces the media_list production
+ /// from CSS2 the new grammar is:
+ ///
+ /// media_query_list
+ /// : S* [media_query [ ',' S* media_query ]* ]?
+ /// media_query
+ /// : [ONLY | NOT]? S* media_type S* [ AND S* expression ]*
+ /// | expression [ AND S* expression ]*
+ /// media_type
+ /// : IDENT
+ /// expression
+ /// : '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+ /// media_feature
+ /// : IDENT
+ List<MediaQuery> processMediaQueryList() {
+ var mediaQueries = <MediaQuery>[];
+
+ do {
+ var mediaQuery = processMediaQuery();
+ if (mediaQuery != null) {
+ mediaQueries.add(mediaQuery);
+ } else {
+ break;
+ }
+ } while (_maybeEat(TokenKind.COMMA));
+
+ return mediaQueries;
+ }
+
+ MediaQuery? processMediaQuery() {
+ // Grammar: [ONLY | NOT]? S* media_type S*
+ // [ AND S* MediaExpr ]* | MediaExpr [ AND S* MediaExpr ]*
+
+ var start = _peekToken.span;
+
+ // Is it a unary media operator?
+ var op = _peekToken.text;
+ var opLen = op.length;
+ var unaryOp = TokenKind.matchMediaOperator(op, 0, opLen);
+ if (unaryOp != -1) {
+ if (isChecked) {
+ if (unaryOp != TokenKind.MEDIA_OP_NOT ||
+ unaryOp != TokenKind.MEDIA_OP_ONLY) {
+ _warning('Only the unary operators NOT and ONLY allowed',
+ _makeSpan(start));
+ }
+ }
+ _next();
+ start = _peekToken.span;
+ }
+
+ Identifier? type;
+ // Get the media type.
+ if (_peekIdentifier()) type = identifier();
+
+ var exprs = <MediaExpression>[];
+
+ while (true) {
+ // Parse AND if query has a media_type or previous expression.
+ var andOp = exprs.isNotEmpty || type != null;
+ if (andOp) {
+ op = _peekToken.text;
+ opLen = op.length;
+ if (TokenKind.matchMediaOperator(op, 0, opLen) !=
+ TokenKind.MEDIA_OP_AND) {
+ break;
+ }
+ _next();
+ }
+
+ var expr = processMediaExpression(andOp);
+ if (expr == null) break;
+
+ exprs.add(expr);
+ }
+
+ if (unaryOp != -1 || type != null || exprs.isNotEmpty) {
+ return MediaQuery(unaryOp, type, exprs, _makeSpan(start));
+ }
+ return null;
+ }
+
+ MediaExpression? processMediaExpression([bool andOperator = false]) {
+ var start = _peekToken.span;
+
+ // Grammar: '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+ if (_maybeEat(TokenKind.LPAREN)) {
+ if (_peekIdentifier()) {
+ var feature = identifier(); // Media feature.
+ var exprs = _maybeEat(TokenKind.COLON)
+ ? processExpr()
+ : Expressions(_makeSpan(_peekToken.span));
+ if (_maybeEat(TokenKind.RPAREN)) {
+ return MediaExpression(andOperator, feature, exprs, _makeSpan(start));
+ } else if (isChecked) {
+ _warning(
+ 'Missing parenthesis around media expression', _makeSpan(start));
+ return null;
+ }
+ } else if (isChecked) {
+ _warning('Missing media feature in media expression', _makeSpan(start));
+ }
+ }
+ return null;
+ }
+
+ /// Directive grammar:
+ ///
+ /// import: '@import' [string | URI] media_list?
+ /// media: '@media' media_query_list '{' ruleset '}'
+ /// page: '@page' [':' IDENT]? '{' declarations '}'
+ /// stylet: '@stylet' IDENT '{' ruleset '}'
+ /// media_query_list: IDENT [',' IDENT]
+ /// keyframes: '@-webkit-keyframes ...' (see grammar below).
+ /// font_face: '@font-face' '{' declarations '}'
+ /// namespace: '@namespace name url("xmlns")
+ /// host: '@host '{' ruleset '}'
+ /// mixin: '@mixin name [(args,...)] '{' declarations/ruleset '}'
+ /// include: '@include name [(@arg,@arg1)]
+ /// '@include name [(@arg...)]
+ /// content: '@content'
+ /// -moz-document: '@-moz-document' [ <url> | url-prefix(<string>) |
+ /// domain(<string>) | regexp(<string) ]# '{'
+ /// declarations
+ /// '}'
+ /// supports: '@supports' supports_condition group_rule_body
+ Directive? processDirective() {
+ var start = _peekToken.span;
+
+ var tokId = processVariableOrDirective();
+ if (tokId is VarDefinitionDirective) return tokId;
+ final tokenId = tokId as int;
+ switch (tokenId) {
+ case TokenKind.DIRECTIVE_IMPORT:
+ _next();
+
+ // @import "uri_string" or @import url("uri_string") are identical; only
+ // a url can follow an @import.
+ String? importStr;
+ if (_peekIdentifier()) {
+ var func = processFunction(identifier());
+ if (func is UriTerm) {
+ importStr = func.text;
+ }
+ } else {
+ importStr = processQuotedString(false);
+ }
+
+ // Any medias?
+ var medias = processMediaQueryList();
+
+ if (importStr == null) {
+ _error('missing import string', _peekToken.span);
+ }
+
+ return ImportDirective(importStr!.trim(), medias, _makeSpan(start));
+
+ case TokenKind.DIRECTIVE_MEDIA:
+ _next();
+
+ // Any medias?
+ var media = processMediaQueryList();
+
+ var rules = <TreeNode>[];
+ if (_maybeEat(TokenKind.LBRACE)) {
+ while (!_maybeEat(TokenKind.END_OF_FILE)) {
+ final rule = processRule();
+ if (rule == null) break;
+ rules.add(rule);
+ }
+
+ if (!_maybeEat(TokenKind.RBRACE)) {
+ _error('expected } after ruleset for @media', _peekToken.span);
+ }
+ } else {
+ _error('expected { after media before ruleset', _peekToken.span);
+ }
+ return MediaDirective(media, rules, _makeSpan(start));
+
+ case TokenKind.DIRECTIVE_HOST:
+ _next();
+
+ var rules = <TreeNode>[];
+ if (_maybeEat(TokenKind.LBRACE)) {
+ while (!_maybeEat(TokenKind.END_OF_FILE)) {
+ final rule = processRule();
+ if (rule == null) break;
+ rules.add(rule);
+ }
+
+ if (!_maybeEat(TokenKind.RBRACE)) {
+ _error('expected } after ruleset for @host', _peekToken.span);
+ }
+ } else {
+ _error('expected { after host before ruleset', _peekToken.span);
+ }
+ return HostDirective(rules, _makeSpan(start));
+
+ case TokenKind.DIRECTIVE_PAGE:
+ // @page S* IDENT? pseudo_page?
+ // S* '{' S*
+ // [ declaration | margin ]?
+ // [ ';' S* [ declaration | margin ]? ]* '}' S*
+ //
+ // pseudo_page :
+ // ':' [ "left" | "right" | "first" ]
+ //
+ // margin :
+ // margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S*
+ //
+ // margin_sym : @top-left-corner, @top-left, @bottom-left, etc.
+ //
+ // See http://www.w3.org/TR/css3-page/#CSS21
+ _next();
+
+ // Page name
+ Identifier? name;
+ if (_peekIdentifier()) {
+ name = identifier();
+ }
+
+ // Any pseudo page?
+ Identifier? pseudoPage;
+ if (_maybeEat(TokenKind.COLON)) {
+ if (_peekIdentifier()) {
+ pseudoPage = identifier();
+ // TODO(terry): Normalize pseudoPage to lowercase.
+ if (isChecked &&
+ !(pseudoPage.name == 'left' ||
+ pseudoPage.name == 'right' ||
+ pseudoPage.name == 'first')) {
+ _warning(
+ 'Pseudo page must be left, top or first', pseudoPage.span);
+ return null;
+ }
+ }
+ }
+
+ var pseudoName = pseudoPage is Identifier ? pseudoPage.name : '';
+ var ident = name is Identifier ? name.name : '';
+ return PageDirective(
+ ident, pseudoName, processMarginsDeclarations(), _makeSpan(start));
+
+ case TokenKind.DIRECTIVE_CHARSET:
+ // @charset S* STRING S* ';'
+ _next();
+
+ var charEncoding = processQuotedString(false);
+ return CharsetDirective(charEncoding, _makeSpan(start));
+
+ // TODO(terry): Workaround Dart2js bug continue not implemented in switch
+ // see https://code.google.com/p/dart/issues/detail?id=8270
+ /*
+ case TokenKind.DIRECTIVE_MS_KEYFRAMES:
+ // TODO(terry): For now only IE 10 (are base level) supports @keyframes,
+ // -moz- has only been optional since Oct 2012 release of Firefox, not
+ // all versions of webkit support @keyframes and opera doesn't yet
+ // support w/o -o- prefix. Add more warnings for other prefixes when
+ // they become optional.
+ if (isChecked) {
+ _warning('@-ms-keyframes should be @keyframes', _makeSpan(start));
+ }
+ continue keyframeDirective;
+
+ keyframeDirective:
+ */
+ case TokenKind.DIRECTIVE_KEYFRAMES:
+ case TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES:
+ case TokenKind.DIRECTIVE_MOZ_KEYFRAMES:
+ case TokenKind.DIRECTIVE_O_KEYFRAMES:
+ // TODO(terry): Remove workaround when bug 8270 is fixed.
+ case TokenKind.DIRECTIVE_MS_KEYFRAMES:
+ if (tokenId == TokenKind.DIRECTIVE_MS_KEYFRAMES && isChecked) {
+ _warning('@-ms-keyframes should be @keyframes', _makeSpan(start));
+ }
+ // TODO(terry): End of workaround.
+
+ // Key frames grammar:
+ //
+ // @[browser]? keyframes [IDENT|STRING] '{' keyframes-blocks '}';
+ //
+ // browser: [-webkit-, -moz-, -ms-, -o-]
+ //
+ // keyframes-blocks:
+ // [keyframe-selectors '{' declarations '}']* ;
+ //
+ // keyframe-selectors:
+ // ['from'|'to'|PERCENTAGE] [',' ['from'|'to'|PERCENTAGE] ]* ;
+ _next();
+
+ Identifier? name;
+ if (_peekIdentifier()) {
+ name = identifier();
+ }
+
+ _eat(TokenKind.LBRACE);
+
+ var keyframe = KeyFrameDirective(tokenId, name, _makeSpan(start));
+
+ do {
+ var selectors = Expressions(_makeSpan(start));
+
+ do {
+ var term = processTerm() as Expression;
+
+ // TODO(terry): Only allow from, to and PERCENTAGE ...
+
+ selectors.add(term);
+ } while (_maybeEat(TokenKind.COMMA));
+
+ keyframe.add(KeyFrameBlock(
+ selectors, processDeclarations(), _makeSpan(start)));
+ } while (!_maybeEat(TokenKind.RBRACE) && !isPrematureEndOfFile());
+
+ return keyframe;
+
+ case TokenKind.DIRECTIVE_FONTFACE:
+ _next();
+ return FontFaceDirective(processDeclarations(), _makeSpan(start));
+
+ case TokenKind.DIRECTIVE_STYLET:
+ // Stylet grammar:
+ //
+ // @stylet IDENT '{'
+ // ruleset
+ // '}'
+ _next();
+
+ dynamic name;
+ if (_peekIdentifier()) {
+ name = identifier();
+ }
+
+ _eat(TokenKind.LBRACE);
+
+ var productions = <TreeNode>[];
+
+ start = _peekToken.span;
+ while (!_maybeEat(TokenKind.END_OF_FILE)) {
+ final rule = processRule();
+ if (rule == null) {
+ break;
+ }
+ productions.add(rule);
+ }
+
+ _eat(TokenKind.RBRACE);
+
+ return StyletDirective(name as String, productions, _makeSpan(start));
+
+ case TokenKind.DIRECTIVE_NAMESPACE:
+ // Namespace grammar:
+ //
+ // @namespace S* [namespace_prefix S*]? [STRING|URI] S* ';' S*
+ // namespace_prefix : IDENT
+ _next();
+
+ Identifier? prefix;
+ if (_peekIdentifier()) {
+ prefix = identifier();
+ }
+
+ // The namespace URI can be either a quoted string url("uri_string")
+ // are identical.
+ String? namespaceUri;
+ if (_peekIdentifier()) {
+ var func = processFunction(identifier());
+ if (func is UriTerm) {
+ namespaceUri = func.text;
+ }
+ } else {
+ if (prefix != null && prefix.name == 'url') {
+ var func = processFunction(prefix);
+ if (func is UriTerm) {
+ // @namespace url("");
+ namespaceUri = func.text;
+ prefix = null;
+ }
+ } else {
+ namespaceUri = processQuotedString(false);
+ }
+ }
+
+ return NamespaceDirective(
+ prefix?.name ?? '', namespaceUri, _makeSpan(start));
+
+ case TokenKind.DIRECTIVE_MIXIN:
+ return processMixin();
+
+ case TokenKind.DIRECTIVE_INCLUDE:
+ return processInclude(_makeSpan(start));
+ case TokenKind.DIRECTIVE_CONTENT:
+ // TODO(terry): TBD
+ _warning('@content not implemented.', _makeSpan(start));
+ return null;
+ case TokenKind.DIRECTIVE_MOZ_DOCUMENT:
+ return processDocumentDirective();
+ case TokenKind.DIRECTIVE_SUPPORTS:
+ return processSupportsDirective();
+ case TokenKind.DIRECTIVE_VIEWPORT:
+ case TokenKind.DIRECTIVE_MS_VIEWPORT:
+ return processViewportDirective();
+ }
+ return null;
+ }
+
+ /// Parse the mixin beginning token offset [start]. Returns a
+ /// [MixinDefinition] node.
+ ///
+ /// Mixin grammar:
+ ///
+ /// @mixin IDENT [(args,...)] '{'
+ /// [ruleset | property | directive]*
+ /// '}'
+ MixinDefinition? processMixin() {
+ _next();
+
+ var name = identifier();
+
+ var params = <TreeNode>[];
+ // Any parameters?
+ if (_maybeEat(TokenKind.LPAREN)) {
+ var mustHaveParam = false;
+ var keepGoing = true;
+ while (keepGoing) {
+ var varDef = processVariableOrDirective(mixinParameter: true);
+ if (varDef is VarDefinitionDirective || varDef is VarDefinition) {
+ params.add(varDef as TreeNode);
+ } else if (mustHaveParam) {
+ _warning('Expecting parameter', _makeSpan(_peekToken.span));
+ keepGoing = false;
+ }
+ if (_maybeEat(TokenKind.COMMA)) {
+ mustHaveParam = true;
+ continue;
+ }
+ keepGoing = !_maybeEat(TokenKind.RPAREN);
+ }
+ }
+
+ _eat(TokenKind.LBRACE);
+
+ var productions = <TreeNode>[];
+ MixinDefinition? mixinDirective;
+
+ var start = _peekToken.span;
+ while (!_maybeEat(TokenKind.END_OF_FILE)) {
+ var directive = processDirective();
+ if (directive != null) {
+ productions.add(directive);
+ continue;
+ }
+
+ var declGroup = processDeclarations(checkBrace: false);
+ if (declGroup.declarations.any((decl) =>
+ decl is Declaration && decl is! IncludeMixinAtDeclaration)) {
+ var newDecls = <Declaration>[];
+ for (var include in productions) {
+ // If declGroup has items that are declarations then we assume
+ // this mixin is a declaration mixin not a top-level mixin.
+ if (include is IncludeDirective) {
+ newDecls.add(IncludeMixinAtDeclaration(include, include.span));
+ } else {
+ _warning('Error mixing of top-level vs declarations mixins',
+ _makeSpan(include.span as FileSpan));
+ }
+ }
+ declGroup.declarations.insertAll(0, newDecls);
+ productions = [];
+ } else {
+ // Declarations are just @includes make it a list of productions
+ // not a declaration group (anything else is a ruleset). Make it a
+ // list of productions, not a declaration group.
+ for (var decl in declGroup.declarations) {
+ productions
+ .add(decl is IncludeMixinAtDeclaration ? decl.include : decl);
+ }
+ declGroup.declarations.clear();
+ }
+
+ if (declGroup.declarations.isNotEmpty) {
+ if (productions.isEmpty) {
+ mixinDirective = MixinDeclarationDirective(
+ name.name, params, false, declGroup, _makeSpan(start));
+ break;
+ } else {
+ for (var decl in declGroup.declarations) {
+ productions
+ .add(decl is IncludeMixinAtDeclaration ? decl.include : decl);
+ }
+ }
+ } else {
+ mixinDirective = MixinRulesetDirective(
+ name.name, params, false, productions, _makeSpan(start));
+ break;
+ }
+ }
+
+ if (productions.isNotEmpty) {
+ mixinDirective = MixinRulesetDirective(
+ name.name, params, false, productions, _makeSpan(start));
+ }
+
+ _eat(TokenKind.RBRACE);
+
+ return mixinDirective;
+ }
+
+ /// Returns a VarDefinitionDirective or VarDefinition if a varaible otherwise
+ /// return the token id of a directive or -1 if neither.
+ dynamic // VarDefinitionDirective | VarDefinition | int
+ processVariableOrDirective({bool mixinParameter = false}) {
+ var start = _peekToken.span;
+
+ var tokId = _peek();
+ // Handle case for @ directive (where there's a whitespace between the @
+ // sign and the directive name. Technically, it's not valid grammar but
+ // a number of CSS tests test for whitespace between @ and name.
+ if (tokId == TokenKind.AT) {
+ _next();
+ tokId = _peek();
+ if (_peekIdentifier()) {
+ // Is it a directive?
+ var directive = _peekToken.text;
+ var directiveLen = directive.length;
+ tokId = TokenKind.matchDirectives(directive, 0, directiveLen);
+ if (tokId == -1) {
+ tokId = TokenKind.matchMarginDirectives(directive, 0, directiveLen);
+ }
+ }
+
+ if (tokId == -1) {
+ if (messages.options.lessSupport) {
+ // Less compatibility:
+ // @name: value; => var-name: value; (VarDefinition)
+ // property: @name; => property: var(name); (VarUsage)
+ Identifier? name;
+ if (_peekIdentifier()) {
+ name = identifier();
+ }
+
+ Expressions? exprs;
+ if (mixinParameter && _maybeEat(TokenKind.COLON)) {
+ exprs = processExpr();
+ } else if (!mixinParameter) {
+ _eat(TokenKind.COLON);
+ exprs = processExpr();
+ }
+
+ var span = _makeSpan(start);
+ return VarDefinitionDirective(VarDefinition(name, exprs, span), span);
+ } else if (isChecked) {
+ _error('unexpected directive @$_peekToken', _peekToken.span);
+ }
+ }
+ } else if (mixinParameter && _peekToken.kind == TokenKind.VAR_DEFINITION) {
+ _next();
+ Identifier? definedName;
+ if (_peekIdentifier()) definedName = identifier();
+
+ Expressions? exprs;
+ if (_maybeEat(TokenKind.COLON)) {
+ exprs = processExpr();
+ }
+
+ return VarDefinition(definedName, exprs, _makeSpan(start));
+ }
+
+ return tokId;
+ }
+
+ IncludeDirective processInclude(SourceSpan span, {bool eatSemiColon = true}) {
+ // Stylet grammar:
+ //
+ // @include IDENT [(args,...)];
+ _next();
+
+ Identifier? name;
+ if (_peekIdentifier()) {
+ name = identifier();
+ }
+
+ var params = <List<Expression>>[];
+
+ // Any parameters? Parameters can be multiple terms per argument e.g.,
+ // 3px solid yellow, green is two parameters:
+ // 1. 3px solid yellow
+ // 2. green
+ // the first has 3 terms and the second has 1 term.
+ if (_maybeEat(TokenKind.LPAREN)) {
+ var terms = <Expression>[];
+ dynamic expr;
+ var keepGoing = true;
+ while (keepGoing && (expr = processTerm()) != null) {
+ // VarUsage is returned as a list
+ terms.add((expr is List ? expr[0] : expr) as Expression);
+ keepGoing = !_peekKind(TokenKind.RPAREN);
+ if (keepGoing) {
+ if (_maybeEat(TokenKind.COMMA)) {
+ params.add(terms);
+ terms = [];
+ }
+ }
+ }
+ params.add(terms);
+ _maybeEat(TokenKind.RPAREN);
+ }
+
+ if (eatSemiColon) {
+ _eat(TokenKind.SEMICOLON);
+ }
+
+ return IncludeDirective(name!.name, params, span);
+ }
+
+ DocumentDirective processDocumentDirective() {
+ var start = _peekToken.span;
+ _next(); // '@-moz-document'
+ var functions = <LiteralTerm>[];
+ do {
+ LiteralTerm function;
+
+ // Consume function token: IDENT '('
+ var ident = identifier();
+ _eat(TokenKind.LPAREN);
+
+ // Consume function arguments.
+ if (ident.name == 'url-prefix' || ident.name == 'domain') {
+ // @-moz-document allows the 'url-prefix' and 'domain' functions to
+ // omit quotations around their argument, contrary to the standard
+ // in which they must be strings. To support this we consume a
+ // string with optional quotation marks, then reapply quotation
+ // marks so they're present in the emitted CSS.
+ var argumentStart = _peekToken.span;
+ var value = processQuotedString(true);
+ // Don't quote the argument if it's empty. '@-moz-document url-prefix()'
+ // is a common pattern used for browser detection.
+ var argument = value.isNotEmpty ? '"$value"' : '';
+ var argumentSpan = _makeSpan(argumentStart);
+
+ _eat(TokenKind.RPAREN);
+
+ var arguments = Expressions(_makeSpan(argumentSpan))
+ ..add(LiteralTerm(argument, argument, argumentSpan));
+ function = FunctionTerm(ident.name, ident.name, arguments,
+ _makeSpan(ident.span as FileSpan));
+ } else {
+ function = processFunction(ident) as LiteralTerm;
+ }
+
+ functions.add(function);
+ } while (_maybeEat(TokenKind.COMMA));
+
+ _eat(TokenKind.LBRACE);
+ var groupRuleBody = processGroupRuleBody();
+ _eat(TokenKind.RBRACE);
+ return DocumentDirective(functions, groupRuleBody, _makeSpan(start));
+ }
+
+ SupportsDirective processSupportsDirective() {
+ var start = _peekToken.span;
+ _next(); // '@supports'
+ var condition = processSupportsCondition();
+ _eat(TokenKind.LBRACE);
+ var groupRuleBody = processGroupRuleBody();
+ _eat(TokenKind.RBRACE);
+ return SupportsDirective(condition, groupRuleBody, _makeSpan(start));
+ }
+
+ SupportsCondition? processSupportsCondition() {
+ if (_peekKind(TokenKind.IDENTIFIER)) {
+ return processSupportsNegation();
+ }
+
+ var start = _peekToken.span;
+ var conditions = <SupportsConditionInParens>[];
+ var clauseType = ClauseType.none;
+
+ while (true) {
+ conditions.add(processSupportsConditionInParens());
+
+ ClauseType type;
+ var text = _peekToken.text.toLowerCase();
+
+ if (text == 'and') {
+ type = ClauseType.conjunction;
+ } else if (text == 'or') {
+ type = ClauseType.disjunction;
+ } else {
+ break; // Done parsing clause.
+ }
+
+ if (clauseType == ClauseType.none) {
+ clauseType = type; // First operand and operator of clause.
+ } else if (clauseType != type) {
+ _error("Operators can't be mixed without a layer of parentheses",
+ _peekToken.span);
+ break;
+ }
+
+ _next(); // Consume operator.
+ }
+
+ if (clauseType == ClauseType.conjunction) {
+ return SupportsConjunction(conditions, _makeSpan(start));
+ } else if (clauseType == ClauseType.disjunction) {
+ return SupportsDisjunction(conditions, _makeSpan(start));
+ } else {
+ return conditions.first;
+ }
+ }
+
+ SupportsNegation? processSupportsNegation() {
+ var start = _peekToken.span;
+ var text = _peekToken.text.toLowerCase();
+ if (text != 'not') return null;
+ _next(); // 'not'
+ var condition = processSupportsConditionInParens();
+ return SupportsNegation(condition, _makeSpan(start));
+ }
+
+ SupportsConditionInParens processSupportsConditionInParens() {
+ var start = _peekToken.span;
+ _eat(TokenKind.LPAREN);
+ // Try to parse a condition.
+ var condition = processSupportsCondition();
+ if (condition != null) {
+ _eat(TokenKind.RPAREN);
+ return SupportsConditionInParens.nested(condition, _makeSpan(start));
+ }
+ // Otherwise, parse a declaration.
+ var declaration = processDeclaration([]);
+ _eat(TokenKind.RPAREN);
+ return SupportsConditionInParens(declaration, _makeSpan(start));
+ }
+
+ ViewportDirective processViewportDirective() {
+ var start = _peekToken.span;
+ var name = _next().text;
+ var declarations = processDeclarations();
+ return ViewportDirective(name, declarations, _makeSpan(start));
+ }
+
+ TreeNode? processRule([SelectorGroup? selectorGroup]) {
+ if (selectorGroup == null) {
+ final directive = processDirective();
+ if (directive != null) {
+ _maybeEat(TokenKind.SEMICOLON);
+ return directive;
+ }
+ selectorGroup = processSelectorGroup();
+ }
+ if (selectorGroup != null) {
+ return RuleSet(selectorGroup, processDeclarations(), selectorGroup.span);
+ }
+ return null;
+ }
+
+ List<TreeNode> processGroupRuleBody() {
+ var nodes = <TreeNode>[];
+ while (!(_peekKind(TokenKind.RBRACE) || _peekKind(TokenKind.END_OF_FILE))) {
+ var rule = processRule();
+ if (rule != null) {
+ nodes.add(rule);
+ continue;
+ }
+ break;
+ }
+ return nodes;
+ }
+
+ /// Look ahead to see if what should be a declaration is really a selector.
+ /// If it's a selector than it's a nested selector. This support's Less'
+ /// nested selector syntax (requires a look ahead). E.g.,
+ ///
+ /// div {
+ /// width : 20px;
+ /// span {
+ /// color: red;
+ /// }
+ /// }
+ ///
+ /// Two tag name selectors div and span equivalent to:
+ ///
+ /// div {
+ /// width: 20px;
+ /// }
+ /// div span {
+ /// color: red;
+ /// }
+ ///
+ /// Return `null` if no selector or [SelectorGroup] if a selector was parsed.
+ SelectorGroup? _nestedSelector() {
+ var oldMessages = messages;
+ _createMessages();
+
+ var markedData = _mark;
+
+ // Look a head do we have a nested selector instead of a declaration?
+ var selGroup = processSelectorGroup();
+
+ var nestedSelector = selGroup != null &&
+ _peekKind(TokenKind.LBRACE) &&
+ messages.messages.isEmpty;
+
+ if (!nestedSelector) {
+ // Not a selector so restore the world.
+ _restore(markedData);
+ messages = oldMessages;
+ return null;
+ } else {
+ // Remember any messages from look ahead.
+ oldMessages.mergeMessages(messages);
+ messages = oldMessages;
+ return selGroup;
+ }
+ }
+
+ DeclarationGroup processDeclarations({bool checkBrace = true}) {
+ var start = _peekToken.span;
+
+ if (checkBrace) _eat(TokenKind.LBRACE);
+
+ var decls = <TreeNode>[];
+ var dartStyles =
+ <DartStyleExpression>[]; // List of latest styles exposed to Dart.
+
+ do {
+ var selectorGroup = _nestedSelector();
+ while (selectorGroup != null) {
+ // Nested selector so process as a ruleset.
+ var ruleset = processRule(selectorGroup)!;
+ decls.add(ruleset);
+ selectorGroup = _nestedSelector();
+ }
+
+ var decl = processDeclaration(dartStyles);
+ if (decl != null) {
+ if (decl.hasDartStyle) {
+ var newDartStyle = decl.dartStyle!;
+
+ // Replace or add latest Dart style.
+ var replaced = false;
+ for (var i = 0; i < dartStyles.length; i++) {
+ var dartStyle = dartStyles[i];
+ if (dartStyle.isSame(newDartStyle)) {
+ dartStyles[i] = newDartStyle;
+ replaced = true;
+ break;
+ }
+ }
+ if (!replaced) {
+ dartStyles.add(newDartStyle);
+ }
+ }
+ decls.add(decl);
+ }
+ } while (_maybeEat(TokenKind.SEMICOLON));
+
+ if (checkBrace) _eat(TokenKind.RBRACE);
+
+ // Fixup declaration to only have dartStyle that are live for this set of
+ // declarations.
+ for (var decl in decls) {
+ if (decl is Declaration) {
+ if (decl.hasDartStyle && !dartStyles.contains(decl.dartStyle)) {
+ // Dart style not live, ignore these styles in this Declarations.
+ decl.dartStyle = null;
+ }
+ }
+ }
+
+ return DeclarationGroup(decls, _makeSpan(start));
+ }
+
+ List<DeclarationGroup> processMarginsDeclarations() {
+ var groups = <DeclarationGroup>[];
+
+ var start = _peekToken.span;
+
+ _eat(TokenKind.LBRACE);
+
+ var decls = <Declaration>[];
+ var dartStyles =
+ <DartStyleExpression>[]; // List of latest styles exposed to Dart.
+
+ do {
+ switch (_peek()) {
+ case TokenKind.MARGIN_DIRECTIVE_TOPLEFTCORNER:
+ case TokenKind.MARGIN_DIRECTIVE_TOPLEFT:
+ case TokenKind.MARGIN_DIRECTIVE_TOPCENTER:
+ case TokenKind.MARGIN_DIRECTIVE_TOPRIGHT:
+ case TokenKind.MARGIN_DIRECTIVE_TOPRIGHTCORNER:
+ case TokenKind.MARGIN_DIRECTIVE_BOTTOMLEFTCORNER:
+ case TokenKind.MARGIN_DIRECTIVE_BOTTOMLEFT:
+ case TokenKind.MARGIN_DIRECTIVE_BOTTOMCENTER:
+ case TokenKind.MARGIN_DIRECTIVE_BOTTOMRIGHT:
+ case TokenKind.MARGIN_DIRECTIVE_BOTTOMRIGHTCORNER:
+ case TokenKind.MARGIN_DIRECTIVE_LEFTTOP:
+ case TokenKind.MARGIN_DIRECTIVE_LEFTMIDDLE:
+ case TokenKind.MARGIN_DIRECTIVE_LEFTBOTTOM:
+ case TokenKind.MARGIN_DIRECTIVE_RIGHTTOP:
+ case TokenKind.MARGIN_DIRECTIVE_RIGHTMIDDLE:
+ case TokenKind.MARGIN_DIRECTIVE_RIGHTBOTTOM:
+ // Margin syms processed.
+ // margin :
+ // margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S*
+ //
+ // margin_sym : @top-left-corner, @top-left, @bottom-left, etc.
+ var marginSym = _peek();
+
+ _next();
+
+ var declGroup = processDeclarations();
+ groups.add(
+ MarginGroup(marginSym, declGroup.declarations, _makeSpan(start)));
+ break;
+ default:
+ var decl = processDeclaration(dartStyles);
+ if (decl != null) {
+ if (decl.hasDartStyle) {
+ var newDartStyle = decl.dartStyle!;
+
+ // Replace or add latest Dart style.
+ var replaced = false;
+ for (var i = 0; i < dartStyles.length; i++) {
+ var dartStyle = dartStyles[i];
+ if (dartStyle.isSame(newDartStyle)) {
+ dartStyles[i] = newDartStyle;
+ replaced = true;
+ break;
+ }
+ }
+ if (!replaced) {
+ dartStyles.add(newDartStyle);
+ }
+ }
+ decls.add(decl);
+ }
+ _maybeEat(TokenKind.SEMICOLON);
+ break;
+ }
+ } while (!_maybeEat(TokenKind.RBRACE) && !isPrematureEndOfFile());
+
+ // Fixup declaration to only have dartStyle that are live for this set of
+ // declarations.
+ for (var decl in decls) {
+ if (decl.hasDartStyle && !dartStyles.contains(decl.dartStyle)) {
+ // Dart style not live, ignore these styles in this Declarations.
+ decl.dartStyle = null;
+ }
+ }
+
+ if (decls.isNotEmpty) {
+ groups.add(DeclarationGroup(decls, _makeSpan(start)));
+ }
+
+ return groups;
+ }
+
+ SelectorGroup? processSelectorGroup() {
+ var selectors = <Selector>[];
+ var start = _peekToken.span;
+
+ tokenizer.inSelector = true;
+ do {
+ var selector = processSelector();
+ if (selector != null) {
+ selectors.add(selector);
+ }
+ } while (_maybeEat(TokenKind.COMMA));
+ tokenizer.inSelector = false;
+
+ if (selectors.isNotEmpty) {
+ return SelectorGroup(selectors, _makeSpan(start));
+ }
+ return null;
+ }
+
+ /// Return list of selectors
+ Selector? processSelector() {
+ var simpleSequences = <SimpleSelectorSequence>[];
+ var start = _peekToken.span;
+ while (true) {
+ // First item is never descendant make sure it's COMBINATOR_NONE.
+ var selectorItem = simpleSelectorSequence(simpleSequences.isEmpty);
+ if (selectorItem != null) {
+ simpleSequences.add(selectorItem);
+ } else {
+ break;
+ }
+ }
+
+ if (simpleSequences.isEmpty) return null;
+
+ return Selector(simpleSequences, _makeSpan(start));
+ }
+
+ /// Same as [processSelector] but reports an error for each combinator.
+ ///
+ /// This is a quick fix for parsing `<compound-selectors>` until the parser
+ /// supports Selector Level 4 grammar:
+ /// https://drafts.csswg.org/selectors-4/#typedef-compound-selector
+ Selector? processCompoundSelector() {
+ var selector = processSelector();
+ if (selector != null) {
+ for (var sequence in selector.simpleSelectorSequences) {
+ if (!sequence.isCombinatorNone) {
+ _error('compound selector can not contain combinator', sequence.span);
+ }
+ }
+ }
+ return selector;
+ }
+
+ SimpleSelectorSequence? simpleSelectorSequence(bool forceCombinatorNone) {
+ var start = _peekToken.span;
+ var combinatorType = TokenKind.COMBINATOR_NONE;
+ var thisOperator = false;
+
+ switch (_peek()) {
+ case TokenKind.PLUS:
+ _eat(TokenKind.PLUS);
+ combinatorType = TokenKind.COMBINATOR_PLUS;
+ break;
+ case TokenKind.GREATER:
+ _eat(TokenKind.GREATER);
+ combinatorType = TokenKind.COMBINATOR_GREATER;
+ break;
+ case TokenKind.TILDE:
+ _eat(TokenKind.TILDE);
+ combinatorType = TokenKind.COMBINATOR_TILDE;
+ break;
+ case TokenKind.AMPERSAND:
+ _eat(TokenKind.AMPERSAND);
+ thisOperator = true;
+ break;
+ }
+
+ // Check if WHITESPACE existed between tokens if so we're descendent.
+ if (combinatorType == TokenKind.COMBINATOR_NONE && !forceCombinatorNone) {
+ if (_previousToken != null && _previousToken!.end != _peekToken.start) {
+ combinatorType = TokenKind.COMBINATOR_DESCENDANT;
+ }
+ }
+
+ var span = _makeSpan(start);
+ var simpleSel = thisOperator
+ ? ElementSelector(ThisOperator(span), span)
+ : simpleSelector();
+ if (simpleSel == null &&
+ (combinatorType == TokenKind.COMBINATOR_PLUS ||
+ combinatorType == TokenKind.COMBINATOR_GREATER ||
+ combinatorType == TokenKind.COMBINATOR_TILDE)) {
+ // For "+ &", "~ &" or "> &" a selector sequence with no name is needed
+ // so that the & will have a combinator too. This is needed to
+ // disambiguate selector expressions:
+ // .foo&:hover combinator before & is NONE
+ // .foo & combinator before & is DESCDENDANT
+ // .foo > & combinator before & is GREATER
+ simpleSel = ElementSelector(Identifier('', span), span);
+ }
+ if (simpleSel != null) {
+ return SimpleSelectorSequence(simpleSel, span, combinatorType);
+ }
+ return null;
+ }
+
+ /// Simple selector grammar:
+ ///
+ /// simple_selector_sequence
+ /// : [ type_selector | universal ]
+ /// [ HASH | class | attrib | pseudo | negation ]*
+ /// | [ HASH | class | attrib | pseudo | negation ]+
+ /// type_selector
+ /// : [ namespace_prefix ]? element_name
+ /// namespace_prefix
+ /// : [ IDENT | '*' ]? '|'
+ /// element_name
+ /// : IDENT
+ /// universal
+ /// : [ namespace_prefix ]? '*'
+ /// class
+ /// : '.' IDENT
+ SimpleSelector? simpleSelector() {
+ // TODO(terry): Natalie makes a good point parsing of namespace and element
+ // are essentially the same (asterisk or identifier) other
+ // than the error message for element. Should consolidate the
+ // code.
+ // TODO(terry): Need to handle attribute namespace too.
+ dynamic first;
+ var start = _peekToken.span;
+ switch (_peek()) {
+ case TokenKind.ASTERISK:
+ // Mark as universal namespace.
+ var tok = _next();
+ first = Wildcard(_makeSpan(tok.span));
+ break;
+ case TokenKind.IDENTIFIER:
+ first = identifier();
+ break;
+ default:
+ // Expecting simple selector.
+ // TODO(terry): Could be a synthesized token like value, etc.
+ if (TokenKind.isKindIdentifier(_peek())) {
+ first = identifier();
+ } else if (_peekKind(TokenKind.SEMICOLON)) {
+ // Can't be a selector if we found a semi-colon.
+ return null;
+ }
+ break;
+ }
+
+ if (_maybeEat(TokenKind.NAMESPACE)) {
+ TreeNode? element;
+ switch (_peek()) {
+ case TokenKind.ASTERISK:
+ // Mark as universal element
+ var tok = _next();
+ element = Wildcard(_makeSpan(tok.span));
+ break;
+ case TokenKind.IDENTIFIER:
+ element = identifier();
+ break;
+ default:
+ _error('expected element name or universal(*), but found $_peekToken',
+ _peekToken.span);
+ break;
+ }
+
+ return NamespaceSelector(
+ first, ElementSelector(element, element!.span!), _makeSpan(start));
+ } else if (first != null) {
+ return ElementSelector(first, _makeSpan(start));
+ } else {
+ // Check for HASH | class | attrib | pseudo | negation
+ return simpleSelectorTail();
+ }
+ }
+
+ bool _anyWhiteSpaceBeforePeekToken(int kind) {
+ if (_previousToken != null && _previousToken!.kind == kind) {
+ // If end of previous token isn't same as the start of peek token then
+ // there's something between these tokens probably whitespace.
+ return _previousToken!.end != _peekToken.start;
+ }
+
+ return false;
+ }
+
+ /// type_selector | universal | HASH | class | attrib | pseudo
+ SimpleSelector? simpleSelectorTail() {
+ // Check for HASH | class | attrib | pseudo | negation
+ var start = _peekToken.span;
+ switch (_peek()) {
+ case TokenKind.HASH:
+ _eat(TokenKind.HASH);
+
+ if (_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) {
+ _error('Not a valid ID selector expected #id', _makeSpan(start));
+ return null;
+ }
+ return IdSelector(identifier(), _makeSpan(start));
+ case TokenKind.DOT:
+ _eat(TokenKind.DOT);
+
+ if (_anyWhiteSpaceBeforePeekToken(TokenKind.DOT)) {
+ _error('Not a valid class selector expected .className',
+ _makeSpan(start));
+ return null;
+ }
+ return ClassSelector(identifier(), _makeSpan(start));
+ case TokenKind.COLON:
+ // :pseudo-class ::pseudo-element
+ return processPseudoSelector(start);
+ case TokenKind.LBRACK:
+ return processAttribute();
+ case TokenKind.DOUBLE:
+ _error('name must start with a alpha character, but found a number',
+ _peekToken.span);
+ _next();
+ break;
+ }
+ return null;
+ }
+
+ SimpleSelector? processPseudoSelector(FileSpan start) {
+ // :pseudo-class ::pseudo-element
+ // TODO(terry): '::' should be token.
+ _eat(TokenKind.COLON);
+ var pseudoElement = _maybeEat(TokenKind.COLON);
+
+ // TODO(terry): If no identifier specified consider optimizing out the
+ // : or :: and making this a normal selector. For now,
+ // create an empty pseudoName.
+ Identifier pseudoName;
+ if (_peekIdentifier()) {
+ pseudoName = identifier();
+ } else {
+ return null;
+ }
+ var name = pseudoName.name.toLowerCase();
+
+ // Functional pseudo?
+ if (_peekToken.kind == TokenKind.LPAREN) {
+ if (!pseudoElement && name == 'not') {
+ _eat(TokenKind.LPAREN);
+
+ // Negation : ':NOT(' S* negation_arg S* ')'
+ var negArg = simpleSelector();
+
+ _eat(TokenKind.RPAREN);
+ return NegationSelector(negArg, _makeSpan(start));
+ } else if (!pseudoElement &&
+ (name == 'host' ||
+ name == 'host-context' ||
+ name == 'global-context' ||
+ name == '-acx-global-context')) {
+ _eat(TokenKind.LPAREN);
+ var selector = processCompoundSelector();
+ if (selector == null) {
+ _errorExpected('a selector argument');
+ return null;
+ }
+ _eat(TokenKind.RPAREN);
+ var span = _makeSpan(start);
+ return PseudoClassFunctionSelector(pseudoName, selector, span);
+ } else {
+ // Special parsing for expressions in pseudo functions. Minus is used
+ // as operator not identifier.
+ // TODO(jmesserly): we need to flip this before we eat the "(" as the
+ // next token will be fetched when we do that. I think we should try to
+ // refactor so we don't need this boolean; it seems fragile.
+ tokenizer.inSelectorExpression = true;
+ _eat(TokenKind.LPAREN);
+
+ // Handle function expression.
+ var span = _makeSpan(start);
+ var expr = processSelectorExpression();
+
+ tokenizer.inSelectorExpression = false;
+
+ // Used during selector look-a-head if not a SelectorExpression is
+ // bad.
+ if (expr is SelectorExpression) {
+ _eat(TokenKind.RPAREN);
+ return pseudoElement
+ ? PseudoElementFunctionSelector(pseudoName, expr, span)
+ : PseudoClassFunctionSelector(pseudoName, expr, span);
+ } else {
+ _errorExpected('CSS expression');
+ return null;
+ }
+ }
+ }
+
+ // Treat CSS2.1 pseudo-elements defined with pseudo class syntax as pseudo-
+ // elements for backwards compatibility.
+ return pseudoElement || _legacyPseudoElements.contains(name)
+ ? PseudoElementSelector(pseudoName, _makeSpan(start),
+ isLegacy: !pseudoElement)
+ : PseudoClassSelector(pseudoName, _makeSpan(start));
+ }
+
+ /// In CSS3, the expressions are identifiers, strings, or of the form "an+b".
+ ///
+ /// : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+
+ ///
+ /// num [0-9]+|[0-9]*\.[0-9]+
+ /// PLUS '+'
+ /// DIMENSION {num}{ident}
+ /// NUMBER {num}
+ TreeNode /* SelectorExpression | LiteralTerm */ processSelectorExpression() {
+ var start = _peekToken.span;
+
+ var expressions = <Expression>[];
+
+ Token? termToken;
+ dynamic value;
+
+ var keepParsing = true;
+ while (keepParsing) {
+ switch (_peek()) {
+ case TokenKind.PLUS:
+ start = _peekToken.span;
+ termToken = _next();
+ expressions.add(OperatorPlus(_makeSpan(start)));
+ break;
+ case TokenKind.MINUS:
+ start = _peekToken.span;
+ termToken = _next();
+ expressions.add(OperatorMinus(_makeSpan(start)));
+ break;
+ case TokenKind.INTEGER:
+ termToken = _next();
+ value = int.parse(termToken.text);
+ break;
+ case TokenKind.DOUBLE:
+ termToken = _next();
+ value = double.parse(termToken.text);
+ break;
+ case TokenKind.SINGLE_QUOTE:
+ value = processQuotedString(false);
+ value = "'${_escapeString(value as String, single: true)}'";
+ return LiteralTerm(value, value, _makeSpan(start));
+ case TokenKind.DOUBLE_QUOTE:
+ value = processQuotedString(false);
+ value = '"${_escapeString(value as String)}"';
+ return LiteralTerm(value, value, _makeSpan(start));
+ case TokenKind.IDENTIFIER:
+ value = identifier(); // Snarf up the ident we'll remap, maybe.
+ break;
+ default:
+ keepParsing = false;
+ }
+
+ if (keepParsing && value != null) {
+ var unitTerm =
+ processDimension(termToken, value as Object, _makeSpan(start));
+ expressions.add(unitTerm);
+
+ value = null;
+ }
+ }
+
+ return SelectorExpression(expressions, _makeSpan(start));
+ }
+
+ // Attribute grammar:
+ //
+ // attributes :
+ // '[' S* IDENT S* [ ATTRIB_MATCHES S* [ IDENT | STRING ] S* ]? ']'
+ //
+ // ATTRIB_MATCHES :
+ // [ '=' | INCLUDES | DASHMATCH | PREFIXMATCH | SUFFIXMATCH | SUBSTRMATCH ]
+ //
+ // INCLUDES: '~='
+ //
+ // DASHMATCH: '|='
+ //
+ // PREFIXMATCH: '^='
+ //
+ // SUFFIXMATCH: '$='
+ //
+ // SUBSTRMATCH: '*='
+ AttributeSelector? processAttribute() {
+ var start = _peekToken.span;
+
+ if (_maybeEat(TokenKind.LBRACK)) {
+ var attrName = identifier();
+
+ int op;
+ switch (_peek()) {
+ case TokenKind.EQUALS:
+ case TokenKind.INCLUDES: // ~=
+ case TokenKind.DASH_MATCH: // |=
+ case TokenKind.PREFIX_MATCH: // ^=
+ case TokenKind.SUFFIX_MATCH: // $=
+ case TokenKind.SUBSTRING_MATCH: // *=
+ op = _peek();
+ _next();
+ break;
+ default:
+ op = TokenKind.NO_MATCH;
+ }
+
+ dynamic value;
+ if (op != TokenKind.NO_MATCH) {
+ // Operator hit so we require a value too.
+ if (_peekIdentifier()) {
+ value = identifier();
+ } else {
+ value = processQuotedString(false);
+ }
+
+ if (value == null) {
+ _error('expected attribute value string or ident', _peekToken.span);
+ }
+ }
+
+ _eat(TokenKind.RBRACK);
+
+ return AttributeSelector(attrName, op, value, _makeSpan(start));
+ }
+ return null;
+ }
+
+ // Declaration grammar:
+ //
+ // declaration: property ':' expr prio?
+ //
+ // property: IDENT [or IE hacks]
+ // prio: !important
+ // expr: (see processExpr)
+ //
+ // Here are the ugly IE hacks we need to support:
+ // property: expr prio? \9; - IE8 and below property, /9 before semi-colon
+ // *IDENT - IE7 or below
+ // _IDENT - IE6 property (automatically a valid ident)
+ Declaration? processDeclaration(List<DartStyleExpression> dartStyles) {
+ Declaration? decl;
+
+ var start = _peekToken.span;
+
+ // IE7 hack of * before property name if so the property is IE7 or below.
+ var ie7 = _peekKind(TokenKind.ASTERISK);
+ if (ie7) {
+ _next();
+ }
+
+ // IDENT ':' expr '!important'?
+ if (TokenKind.isIdentifier(_peekToken.kind)) {
+ var propertyIdent = identifier();
+
+ var ieFilterProperty = propertyIdent.name.toLowerCase() == 'filter';
+
+ _eat(TokenKind.COLON);
+
+ var exprs = processExpr(ieFilterProperty);
+
+ var dartComposite = _styleForDart(propertyIdent, exprs, dartStyles);
+
+ // Handle !important (prio)
+ var importantPriority = _maybeEat(TokenKind.IMPORTANT);
+
+ decl = Declaration(propertyIdent, exprs, dartComposite, _makeSpan(start),
+ important: importantPriority, ie7: ie7);
+ } else if (_peekToken.kind == TokenKind.VAR_DEFINITION) {
+ _next();
+ Identifier? definedName;
+ if (_peekIdentifier()) definedName = identifier();
+
+ _eat(TokenKind.COLON);
+
+ var exprs = processExpr();
+
+ decl = VarDefinition(definedName, exprs, _makeSpan(start));
+ } else if (_peekToken.kind == TokenKind.DIRECTIVE_INCLUDE) {
+ // @include mixinName in the declaration area.
+ var span = _makeSpan(start);
+ var include = processInclude(span, eatSemiColon: false);
+ decl = IncludeMixinAtDeclaration(include, span);
+ } else if (_peekToken.kind == TokenKind.DIRECTIVE_EXTEND) {
+ var simpleSequences = <TreeNode>[];
+
+ _next();
+ var span = _makeSpan(start);
+ var selector = simpleSelector();
+ if (selector == null) {
+ _warning('@extends expecting simple selector name', span);
+ } else {
+ simpleSequences.add(selector);
+ }
+ if (_peekKind(TokenKind.COLON)) {
+ var pseudoSelector = processPseudoSelector(_peekToken.span);
+ if (pseudoSelector is PseudoElementSelector ||
+ pseudoSelector is PseudoClassSelector) {
+ simpleSequences.add(pseudoSelector!);
+ } else {
+ _warning('not a valid selector', span);
+ }
+ }
+ decl = ExtendDeclaration(simpleSequences, span);
+ }
+
+ return decl;
+ }
+
+ /// List of styles exposed to the Dart UI framework.
+ static const int _fontPartFont = 0;
+ static const int _fontPartVariant = 1;
+ static const int _fontPartWeight = 2;
+ static const int _fontPartSize = 3;
+ static const int _fontPartFamily = 4;
+ static const int _fontPartStyle = 5;
+ static const int _marginPartMargin = 6;
+ static const int _marginPartLeft = 7;
+ static const int _marginPartTop = 8;
+ static const int _marginPartRight = 9;
+ static const int _marginPartBottom = 10;
+ static const int _lineHeightPart = 11;
+ static const int _borderPartBorder = 12;
+ static const int _borderPartLeft = 13;
+ static const int _borderPartTop = 14;
+ static const int _borderPartRight = 15;
+ static const int _borderPartBottom = 16;
+ static const int _borderPartWidth = 17;
+ static const int _borderPartLeftWidth = 18;
+ static const int _borderPartTopWidth = 19;
+ static const int _borderPartRightWidth = 20;
+ static const int _borderPartBottomWidth = 21;
+ static const int _heightPart = 22;
+ static const int _widthPart = 23;
+ static const int _paddingPartPadding = 24;
+ static const int _paddingPartLeft = 25;
+ static const int _paddingPartTop = 26;
+ static const int _paddingPartRight = 27;
+ static const int _paddingPartBottom = 28;
+
+ static const Map<String, int> _stylesToDart = {
+ 'font': _fontPartFont,
+ 'font-family': _fontPartFamily,
+ 'font-size': _fontPartSize,
+ 'font-style': _fontPartStyle,
+ 'font-variant': _fontPartVariant,
+ 'font-weight': _fontPartWeight,
+ 'line-height': _lineHeightPart,
+ 'margin': _marginPartMargin,
+ 'margin-left': _marginPartLeft,
+ 'margin-right': _marginPartRight,
+ 'margin-top': _marginPartTop,
+ 'margin-bottom': _marginPartBottom,
+ 'border': _borderPartBorder,
+ 'border-left': _borderPartLeft,
+ 'border-right': _borderPartRight,
+ 'border-top': _borderPartTop,
+ 'border-bottom': _borderPartBottom,
+ 'border-width': _borderPartWidth,
+ 'border-left-width': _borderPartLeftWidth,
+ 'border-top-width': _borderPartTopWidth,
+ 'border-right-width': _borderPartRightWidth,
+ 'border-bottom-width': _borderPartBottomWidth,
+ 'height': _heightPart,
+ 'width': _widthPart,
+ 'padding': _paddingPartPadding,
+ 'padding-left': _paddingPartLeft,
+ 'padding-top': _paddingPartTop,
+ 'padding-right': _paddingPartRight,
+ 'padding-bottom': _paddingPartBottom
+ };
+
+ static const Map<String, int> _nameToFontWeight = {
+ 'bold': FontWeight.bold,
+ 'normal': FontWeight.normal
+ };
+
+ static int? _findStyle(String styleName) => _stylesToDart[styleName];
+
+ DartStyleExpression? _styleForDart(Identifier property, Expressions exprs,
+ List<DartStyleExpression> dartStyles) {
+ var styleType = _findStyle(property.name.toLowerCase());
+ if (styleType != null) {
+ return buildDartStyleNode(styleType, exprs, dartStyles);
+ }
+ return null;
+ }
+
+ FontExpression _mergeFontStyles(
+ FontExpression fontExpr, List<DartStyleExpression> dartStyles) {
+ // Merge all font styles for this class selector.
+ for (var dartStyle in dartStyles) {
+ if (dartStyle.isFont) {
+ fontExpr = FontExpression.merge(dartStyle as FontExpression, fontExpr);
+ }
+ }
+
+ return fontExpr;
+ }
+
+ DartStyleExpression? buildDartStyleNode(
+ int styleType, Expressions exprs, List<DartStyleExpression> dartStyles) {
+ switch (styleType) {
+ // Properties in order:
+ //
+ // font-style font-variant font-weight font-size/line-height font-family
+ //
+ // The font-size and font-family values are required. If other values are
+ // missing; a default, if it exist, will be used.
+ case _fontPartFont:
+ var processor = ExpressionsProcessor(exprs);
+ return _mergeFontStyles(processor.processFont(), dartStyles);
+ case _fontPartFamily:
+ var processor = ExpressionsProcessor(exprs);
+
+ try {
+ return _mergeFontStyles(processor.processFontFamily(), dartStyles);
+ } catch (fontException) {
+ _error('$fontException', _peekToken.span);
+ }
+ break;
+ case _fontPartSize:
+ var processor = ExpressionsProcessor(exprs);
+ return _mergeFontStyles(processor.processFontSize(), dartStyles);
+ case _fontPartStyle:
+ // Possible style values:
+ // normal [default]
+ // italic
+ // oblique
+ // inherit
+
+ // TODO(terry): TBD
+ break;
+ case _fontPartVariant:
+ // Possible variant values:
+ // normal [default]
+ // small-caps
+ // inherit
+
+ // TODO(terry): TBD
+ break;
+ case _fontPartWeight:
+ // Possible weight values:
+ // normal [default]
+ // bold
+ // bolder
+ // lighter
+ // 100 - 900
+ // inherit
+
+ // TODO(terry): Only 'normal', 'bold', or values of 100-900 supported
+ // need to handle bolder, lighter, and inherit. See
+ // https://github.com/dart-lang/csslib/issues/1
+ var expr = exprs.expressions[0];
+ if (expr is NumberTerm) {
+ var fontExpr = FontExpression(expr.span, weight: expr.value as int?);
+ return _mergeFontStyles(fontExpr, dartStyles);
+ } else if (expr is LiteralTerm) {
+ var weight = _nameToFontWeight[expr.value.toString()];
+ if (weight != null) {
+ var fontExpr = FontExpression(expr.span, weight: weight);
+ return _mergeFontStyles(fontExpr, dartStyles);
+ }
+ }
+ break;
+ case _lineHeightPart:
+ if (exprs.expressions.length == 1) {
+ var expr = exprs.expressions[0];
+ if (expr is UnitTerm) {
+ var unitTerm = expr;
+ // TODO(terry): Need to handle other units and LiteralTerm normal
+ // See https://github.com/dart-lang/csslib/issues/2.
+ if (unitTerm.unit == TokenKind.UNIT_LENGTH_PX ||
+ unitTerm.unit == TokenKind.UNIT_LENGTH_PT) {
+ var fontExpr = FontExpression(expr.span,
+ lineHeight: LineHeight(expr.value as num, inPixels: true));
+ return _mergeFontStyles(fontExpr, dartStyles);
+ } else if (isChecked) {
+ _warning('Unexpected unit for line-height', expr.span);
+ }
+ } else if (expr is NumberTerm) {
+ var fontExpr = FontExpression(expr.span,
+ lineHeight: LineHeight(expr.value as num, inPixels: false));
+ return _mergeFontStyles(fontExpr, dartStyles);
+ } else if (isChecked) {
+ _warning('Unexpected value for line-height', expr.span);
+ }
+ }
+ break;
+ case _marginPartMargin:
+ return MarginExpression.boxEdge(exprs.span, processFourNums(exprs));
+ case _borderPartBorder:
+ for (var expr in exprs.expressions) {
+ var v = marginValue(expr);
+ if (v != null) {
+ final box = BoxEdge.uniform(v);
+ return BorderExpression.boxEdge(exprs.span, box);
+ }
+ }
+ break;
+ case _borderPartWidth:
+ var v = marginValue(exprs.expressions[0]);
+ if (v != null) {
+ final box = BoxEdge.uniform(v);
+ return BorderExpression.boxEdge(exprs.span, box);
+ }
+ break;
+ case _paddingPartPadding:
+ return PaddingExpression.boxEdge(exprs.span, processFourNums(exprs));
+ case _marginPartLeft:
+ case _marginPartTop:
+ case _marginPartRight:
+ case _marginPartBottom:
+ case _borderPartLeft:
+ case _borderPartTop:
+ case _borderPartRight:
+ case _borderPartBottom:
+ case _borderPartLeftWidth:
+ case _borderPartTopWidth:
+ case _borderPartRightWidth:
+ case _borderPartBottomWidth:
+ case _heightPart:
+ case _widthPart:
+ case _paddingPartLeft:
+ case _paddingPartTop:
+ case _paddingPartRight:
+ case _paddingPartBottom:
+ if (exprs.expressions.isNotEmpty) {
+ return processOneNumber(exprs, styleType);
+ }
+ break;
+ }
+ return null;
+ }
+
+ // TODO(terry): Look at handling width of thin, thick, etc. any none numbers
+ // to convert to a number.
+ DartStyleExpression? processOneNumber(Expressions exprs, int part) {
+ var value = marginValue(exprs.expressions[0]);
+ if (value != null) {
+ return switch (part) {
+ _marginPartLeft => MarginExpression(exprs.span, left: value),
+ _marginPartTop => MarginExpression(exprs.span, top: value),
+ _marginPartRight => MarginExpression(exprs.span, right: value),
+ _marginPartBottom => MarginExpression(exprs.span, bottom: value),
+ _borderPartLeft ||
+ _borderPartLeftWidth =>
+ BorderExpression(exprs.span, left: value),
+ _borderPartTop ||
+ _borderPartTopWidth =>
+ BorderExpression(exprs.span, top: value),
+ _borderPartRight ||
+ _borderPartRightWidth =>
+ BorderExpression(exprs.span, right: value),
+ _borderPartBottom ||
+ _borderPartBottomWidth =>
+ BorderExpression(exprs.span, bottom: value),
+ _heightPart => HeightExpression(exprs.span, value),
+ _widthPart => WidthExpression(exprs.span, value),
+ _paddingPartLeft => PaddingExpression(exprs.span, left: value),
+ _paddingPartTop => PaddingExpression(exprs.span, top: value),
+ _paddingPartRight => PaddingExpression(exprs.span, right: value),
+ _paddingPartBottom => PaddingExpression(exprs.span, bottom: value),
+ _ => null
+ };
+ }
+ return null;
+ }
+
+ /// Margins are of the format:
+ ///
+ /// * top,right,bottom,left (4 parameters)
+ /// * top,right/left, bottom (3 parameters)
+ /// * top/bottom,right/left (2 parameters)
+ /// * top/right/bottom/left (1 parameter)
+ ///
+ /// The values of the margins can be a unit or unitless or auto.
+ BoxEdge? processFourNums(Expressions exprs) {
+ num? top;
+ num? right;
+ num? bottom;
+ num? left;
+
+ var totalExprs = exprs.expressions.length;
+ switch (totalExprs) {
+ case 1:
+ top = marginValue(exprs.expressions[0]);
+ right = top;
+ bottom = top;
+ left = top;
+ break;
+ case 2:
+ top = marginValue(exprs.expressions[0]);
+ bottom = top;
+ right = marginValue(exprs.expressions[1]);
+ left = right;
+ break;
+ case 3:
+ top = marginValue(exprs.expressions[0]);
+ right = marginValue(exprs.expressions[1]);
+ left = right;
+ bottom = marginValue(exprs.expressions[2]);
+ break;
+ case 4:
+ top = marginValue(exprs.expressions[0]);
+ right = marginValue(exprs.expressions[1]);
+ bottom = marginValue(exprs.expressions[2]);
+ left = marginValue(exprs.expressions[3]);
+ break;
+ default:
+ return null;
+ }
+
+ return BoxEdge.clockwiseFromTop(top, right, bottom, left);
+ }
+
+ // TODO(terry): Need to handle auto.
+ num? marginValue(Expression exprTerm) {
+ if (exprTerm is UnitTerm) {
+ return exprTerm.value as num;
+ } else if (exprTerm is NumberTerm) {
+ return exprTerm.value as num;
+ }
+ return null;
+ }
+
+ // Expression grammar:
+ //
+ // expression: term [ operator? term]*
+ //
+ // operator: '/' | ','
+ // term: (see processTerm)
+ Expressions processExpr([bool ieFilter = false]) {
+ var start = _peekToken.span;
+ var expressions = Expressions(_makeSpan(start));
+
+ var keepGoing = true;
+ dynamic expr;
+ while (keepGoing && (expr = processTerm(ieFilter)) != null) {
+ Expression? op;
+
+ var opStart = _peekToken.span;
+
+ switch (_peek()) {
+ case TokenKind.SLASH:
+ op = OperatorSlash(_makeSpan(opStart));
+ break;
+ case TokenKind.COMMA:
+ op = OperatorComma(_makeSpan(opStart));
+ break;
+ case TokenKind.BACKSLASH:
+ // Backslash outside of string; detected IE8 or older signaled by \9
+ // at end of an expression.
+ var ie8Start = _peekToken.span;
+
+ _next();
+ if (_peekKind(TokenKind.INTEGER)) {
+ var numToken = _next();
+ var value = int.parse(numToken.text);
+ if (value == 9) {
+ op = IE8Term(_makeSpan(ie8Start));
+ } else if (isChecked) {
+ _warning(
+ '\$value is not valid in an expression', _makeSpan(start));
+ }
+ }
+ break;
+ }
+
+ if (expr != null) {
+ if (expr is List<Expression>) {
+ for (var exprItem in expr) {
+ expressions.add(exprItem);
+ }
+ } else {
+ expressions.add(expr as Expression);
+ }
+ } else {
+ keepGoing = false;
+ }
+
+ if (op != null) {
+ expressions.add(op);
+ if (op is IE8Term) {
+ keepGoing = false;
+ } else {
+ _next();
+ }
+ }
+ }
+
+ return expressions;
+ }
+
+ // ignore: constant_identifier_names
+ static const int MAX_UNICODE = 0x10FFFF;
+
+ // Term grammar:
+ //
+ // term:
+ // unary_operator?
+ // [ term_value ]
+ // | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor
+ //
+ // term_value:
+ // NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
+ // TIME S* | FREQ S* | function
+ //
+ // NUMBER: {num}
+ // PERCENTAGE: {num}%
+ // LENGTH: {num}['px' | 'cm' | 'mm' | 'in' | 'pt' | 'pc']
+ // EMS: {num}'em'
+ // EXS: {num}'ex'
+ // ANGLE: {num}['deg' | 'rad' | 'grad']
+ // TIME: {num}['ms' | 's']
+ // FREQ: {num}['hz' | 'khz']
+ // function: IDENT '(' expr ')'
+ //
+ dynamic /* Expression | List<Expression> | ... */ processTerm(
+ [bool ieFilter = false]) {
+ var start = _peekToken.span;
+ var unary = '';
+
+ dynamic processIdentifier() {
+ var nameValue = identifier(); // Snarf up the ident we'll remap, maybe.
+
+ if (!ieFilter && _maybeEat(TokenKind.LPAREN)) {
+ var calc = processCalc(nameValue);
+ if (calc != null) return calc;
+ // FUNCTION
+ return processFunction(nameValue);
+ }
+ if (ieFilter) {
+ if (_maybeEat(TokenKind.COLON) &&
+ nameValue.name.toLowerCase() == 'progid') {
+ // IE filter:progid:
+ return processIEFilter(start);
+ } else {
+ // Handle filter:<name> where name is any filter e.g., alpha,
+ // chroma, Wave, blur, etc.
+ return processIEFilter(start);
+ }
+ }
+
+ // TODO(terry): Need to have a list of known identifiers today only
+ // 'from' is special.
+ if (nameValue.name == 'from') {
+ return LiteralTerm(nameValue, nameValue.name, _makeSpan(start));
+ }
+
+ // What kind of identifier is it, named color?
+ var colorEntry = TokenKind.matchColorName(nameValue.name);
+ if (colorEntry == null) {
+ if (isChecked) {
+ var propName = nameValue.name;
+ var errMsg = TokenKind.isPredefinedName(propName)
+ ? 'Improper use of property value $propName'
+ : 'Unknown property value $propName';
+ _warning(errMsg, _makeSpan(start));
+ }
+ return LiteralTerm(nameValue, nameValue.name, _makeSpan(start));
+ }
+
+ // Yes, process the color as an RGB value.
+ var rgbColor =
+ TokenKind.decimalToHex(TokenKind.colorValue(colorEntry), 6);
+ return _parseHex(rgbColor, _makeSpan(start));
+ }
+
+ switch (_peek()) {
+ case TokenKind.HASH:
+ _eat(TokenKind.HASH);
+ if (!_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) {
+ String? hexText;
+ if (_peekKind(TokenKind.INTEGER)) {
+ var hexText1 = _peekToken.text;
+ _next();
+ // Append identifier only if there's no delimiting whitespace.
+ if (_peekIdentifier() && _previousToken!.end == _peekToken.start) {
+ hexText = '$hexText1${identifier().name}';
+ } else {
+ hexText = hexText1;
+ }
+ } else if (_peekIdentifier()) {
+ hexText = identifier().name;
+ }
+ if (hexText != null) {
+ return _parseHex(hexText, _makeSpan(start));
+ }
+ }
+
+ if (isChecked) {
+ _warning('Expected hex number', _makeSpan(start));
+ }
+ // Construct the bad hex value with a #<space>number.
+ return _parseHex(
+ ' ${(processTerm() as LiteralTerm).text}', _makeSpan(start));
+ case TokenKind.INTEGER:
+ var t = _next();
+ var value = int.parse('$unary${t.text}');
+ return processDimension(t, value, _makeSpan(start));
+ case TokenKind.DOUBLE:
+ var t = _next();
+ var value = double.parse('$unary${t.text}');
+ return processDimension(t, value, _makeSpan(start));
+ case TokenKind.SINGLE_QUOTE:
+ var value = processQuotedString(false);
+ value = "'${_escapeString(value, single: true)}'";
+ return LiteralTerm(value, value, _makeSpan(start));
+ case TokenKind.DOUBLE_QUOTE:
+ var value = processQuotedString(false);
+ value = '"${_escapeString(value)}"';
+ return LiteralTerm(value, value, _makeSpan(start));
+ case TokenKind.LPAREN:
+ _next();
+
+ var group = GroupTerm(_makeSpan(start));
+
+ dynamic /* Expression | List<Expression> | ... */ term;
+ do {
+ term = processTerm();
+ if (term != null && term is LiteralTerm) {
+ group.add(term);
+ }
+ } while (term != null &&
+ !_maybeEat(TokenKind.RPAREN) &&
+ !isPrematureEndOfFile());
+
+ return group;
+ case TokenKind.LBRACK:
+ _next();
+
+ var term = processTerm() as LiteralTerm;
+ if (term is! NumberTerm) {
+ _error('Expecting a positive number', _makeSpan(start));
+ }
+
+ _eat(TokenKind.RBRACK);
+
+ return ItemTerm(term.value, term.text, _makeSpan(start));
+ case TokenKind.IDENTIFIER:
+ return processIdentifier();
+ case TokenKind.UNICODE_RANGE:
+ String? first;
+ String? second;
+ int firstNumber;
+ int secondNumber;
+ _eat(TokenKind.UNICODE_RANGE, unicodeRange: true);
+ if (_maybeEat(TokenKind.HEX_INTEGER, unicodeRange: true)) {
+ first = _previousToken!.text;
+ firstNumber = int.parse('0x$first');
+ if (firstNumber > MAX_UNICODE) {
+ _error('unicode range must be less than 10FFFF', _makeSpan(start));
+ }
+ if (_maybeEat(TokenKind.MINUS, unicodeRange: true)) {
+ if (_maybeEat(TokenKind.HEX_INTEGER, unicodeRange: true)) {
+ second = _previousToken!.text;
+ secondNumber = int.parse('0x$second');
+ if (secondNumber > MAX_UNICODE) {
+ _error(
+ 'unicode range must be less than 10FFFF', _makeSpan(start));
+ }
+ if (firstNumber > secondNumber) {
+ _error('unicode first range can not be greater than last',
+ _makeSpan(start));
+ }
+ }
+ }
+ } else if (_maybeEat(TokenKind.HEX_RANGE, unicodeRange: true)) {
+ first = _previousToken!.text;
+ }
+
+ return UnicodeRangeTerm(first, second, _makeSpan(start));
+ case TokenKind.AT:
+ if (messages.options.lessSupport) {
+ _next();
+
+ var expr = processExpr();
+ if (isChecked && expr.expressions.length > 1) {
+ _error('only @name for Less syntax', _peekToken.span);
+ }
+
+ var param = expr.expressions[0];
+ var varUsage =
+ VarUsage((param as LiteralTerm).text, [], _makeSpan(start));
+ expr.expressions[0] = varUsage;
+ return expr.expressions;
+ }
+ break;
+ default:
+ // For tokens that we don't match above, but that are identifier like
+ // ('PT', 'PX', ...) handle them like identifiers.
+ if (TokenKind.isKindIdentifier(_peek())) {
+ return processIdentifier();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ /// Process all dimension units.
+ LiteralTerm processDimension(Token? t, Object value, FileSpan span) {
+ LiteralTerm term;
+ var unitType = _peek();
+
+ switch (unitType) {
+ case TokenKind.UNIT_EM:
+ span = span.expand(_next().span);
+ term = EmTerm(value, t!.text, span);
+ break;
+ case TokenKind.UNIT_EX:
+ span = span.expand(_next().span);
+ term = ExTerm(value, t!.text, span);
+ break;
+ case TokenKind.UNIT_LENGTH_PX:
+ case TokenKind.UNIT_LENGTH_CM:
+ case TokenKind.UNIT_LENGTH_MM:
+ case TokenKind.UNIT_LENGTH_IN:
+ case TokenKind.UNIT_LENGTH_PT:
+ case TokenKind.UNIT_LENGTH_PC:
+ span = span.expand(_next().span);
+ term = LengthTerm(value, t!.text, span, unitType);
+ break;
+ case TokenKind.UNIT_ANGLE_DEG:
+ case TokenKind.UNIT_ANGLE_RAD:
+ case TokenKind.UNIT_ANGLE_GRAD:
+ case TokenKind.UNIT_ANGLE_TURN:
+ span = span.expand(_next().span);
+ term = AngleTerm(value, t!.text, span, unitType);
+ break;
+ case TokenKind.UNIT_TIME_MS:
+ case TokenKind.UNIT_TIME_S:
+ span = span.expand(_next().span);
+ term = TimeTerm(value, t!.text, span, unitType);
+ break;
+ case TokenKind.UNIT_FREQ_HZ:
+ case TokenKind.UNIT_FREQ_KHZ:
+ span = span.expand(_next().span);
+ term = FreqTerm(value, t!.text, span, unitType);
+ break;
+ case TokenKind.PERCENT:
+ span = span.expand(_next().span);
+ term = PercentageTerm(value, t!.text, span);
+ break;
+ case TokenKind.UNIT_FRACTION:
+ span = span.expand(_next().span);
+ term = FractionTerm(value, t!.text, span);
+ break;
+ case TokenKind.UNIT_RESOLUTION_DPI:
+ case TokenKind.UNIT_RESOLUTION_DPCM:
+ case TokenKind.UNIT_RESOLUTION_DPPX:
+ span = span.expand(_next().span);
+ term = ResolutionTerm(value, t!.text, span, unitType);
+ break;
+ case TokenKind.UNIT_CH:
+ span = span.expand(_next().span);
+ term = ChTerm(value, t!.text, span, unitType);
+ break;
+ case TokenKind.UNIT_REM:
+ span = span.expand(_next().span);
+ term = RemTerm(value, t!.text, span, unitType);
+ break;
+ case TokenKind.UNIT_VIEWPORT_VW:
+ case TokenKind.UNIT_VIEWPORT_VH:
+ case TokenKind.UNIT_VIEWPORT_VMIN:
+ case TokenKind.UNIT_VIEWPORT_VMAX:
+ span = span.expand(_next().span);
+ term = ViewportTerm(value, t!.text, span, unitType);
+ break;
+ case TokenKind.UNIT_LH:
+ case TokenKind.UNIT_RLH:
+ span = span.expand(_next().span);
+ term = LineHeightTerm(value, t!.text, span, unitType);
+ break;
+ default:
+ if (value is Identifier) {
+ term = LiteralTerm(value, value.name, span);
+ } else {
+ term = NumberTerm(value, t!.text, span);
+ }
+ }
+
+ return term;
+ }
+
+ String processQuotedString([bool urlString = false]) {
+ var start = _peekToken.span;
+
+ // URI term sucks up everything inside of quotes(' or ") or between parens
+ var stopToken = urlString ? TokenKind.RPAREN : -1;
+
+ // Note: disable skipping whitespace tokens inside a string.
+ // TODO(jmesserly): the layering here feels wrong.
+ var inString = tokenizer._inString;
+ tokenizer._inString = false;
+
+ switch (_peek()) {
+ case TokenKind.SINGLE_QUOTE:
+ stopToken = TokenKind.SINGLE_QUOTE;
+ _next(); // Skip the SINGLE_QUOTE.
+ start = _peekToken.span;
+ break;
+ case TokenKind.DOUBLE_QUOTE:
+ stopToken = TokenKind.DOUBLE_QUOTE;
+ _next(); // Skip the DOUBLE_QUOTE.
+ start = _peekToken.span;
+ break;
+ default:
+ if (urlString) {
+ if (_peek() == TokenKind.LPAREN) {
+ _next(); // Skip the LPAREN.
+ start = _peekToken.span;
+ }
+ stopToken = TokenKind.RPAREN;
+ } else {
+ _error('unexpected string', _makeSpan(start));
+ }
+ break;
+ }
+
+ // Gobble up everything until we hit our stop token.
+ var stringValue = StringBuffer();
+ while (_peek() != stopToken && _peek() != TokenKind.END_OF_FILE) {
+ stringValue.write(_next().text);
+ }
+
+ tokenizer._inString = inString;
+
+ // All characters between quotes is the string.
+ if (stopToken != TokenKind.RPAREN) {
+ _next(); // Skip the SINGLE_QUOTE or DOUBLE_QUOTE;
+ }
+
+ return stringValue.toString();
+ }
+
+ // TODO(terry): Should probably understand IE's non-standard filter syntax to
+ // fully support calc, var(), etc.
+ /// IE's filter property breaks CSS value parsing. IE's format can be:
+ ///
+ /// filter: progid:DXImageTransform.MS.gradient(Type=0, Color='#9d8b83');
+ ///
+ /// We'll just parse everything after the 'progid:' look for the left paren
+ /// then parse to the right paren ignoring everything in between.
+ dynamic processIEFilter(FileSpan startAfterProgidColon) {
+ // Support non-functional filters (i.e. filter: FlipH)
+ var kind = _peek();
+ if (kind == TokenKind.SEMICOLON || kind == TokenKind.RBRACE) {
+ var tok = tokenizer.makeIEFilter(
+ startAfterProgidColon.start.offset, _peekToken.start);
+ return LiteralTerm(tok.text, tok.text, tok.span);
+ }
+
+ var parens = 0;
+ while (_peek() != TokenKind.END_OF_FILE) {
+ switch (_peek()) {
+ case TokenKind.LPAREN:
+ _eat(TokenKind.LPAREN);
+ parens++;
+ break;
+ case TokenKind.RPAREN:
+ _eat(TokenKind.RPAREN);
+ if (--parens == 0) {
+ var tok = tokenizer.makeIEFilter(
+ startAfterProgidColon.start.offset, _peekToken.start);
+ return LiteralTerm(tok.text, tok.text, tok.span);
+ }
+ break;
+ default:
+ _eat(_peek());
+ }
+ }
+ }
+
+ // TODO(terry): Hack to gobble up the calc expression as a string looking
+ // for the matching RPAREN the expression is not parsed into the
+ // AST.
+ //
+ // grammar should be:
+ //
+ // <calc()> = calc( <calc-sum> )
+ // <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]*
+ // <calc-product> = <calc-value> [ '*' <calc-value> | '/' <number> ]*
+ // <calc-value> = <number> | <dimension> | <percentage> | ( <calc-sum> )
+ //
+ String processCalcExpression() {
+ var inString = tokenizer._inString;
+ tokenizer._inString = false;
+
+ // Gobble up everything until we hit our stop token.
+ var stringValue = StringBuffer();
+ var left = 1;
+ var matchingParens = false;
+ while (_peek() != TokenKind.END_OF_FILE && !matchingParens) {
+ var token = _peek();
+ if (token == TokenKind.LPAREN) {
+ left++;
+ } else if (token == TokenKind.RPAREN) {
+ left--;
+ }
+
+ matchingParens = left == 0;
+ if (!matchingParens) stringValue.write(_next().text);
+ }
+
+ if (!matchingParens) {
+ _error('problem parsing function expected ), ', _peekToken.span);
+ }
+
+ tokenizer._inString = inString;
+
+ return stringValue.toString();
+ }
+
+ CalcTerm? processCalc(Identifier func) {
+ var start = _peekToken.span;
+
+ var name = func.name;
+ if (const {'calc', '-webkit-calc', '-moz-calc', 'min', 'max', 'clamp'}
+ .contains(name)) {
+ // TODO(terry): Implement expression parsing properly.
+ var expression = processCalcExpression();
+ var calcExpr = LiteralTerm(expression, expression, _makeSpan(start));
+
+ if (!_maybeEat(TokenKind.RPAREN)) {
+ _error('problem parsing function expected ), ', _peekToken.span);
+ }
+
+ return CalcTerm(name, name, calcExpr, _makeSpan(start));
+ }
+
+ return null;
+ }
+
+ // Function grammar:
+ //
+ // function: IDENT '(' expr ')'
+ //
+ TreeNode /* LiteralTerm | Expression */ processFunction(Identifier func) {
+ var start = _peekToken.span;
+ var name = func.name;
+
+ switch (name) {
+ case 'url':
+ // URI term sucks up everything inside of quotes(' or ") or between
+ // parens.
+ var urlParam = processQuotedString(true);
+
+ // TODO(terry): Better error message and checking for mismatched quotes.
+ if (_peek() == TokenKind.END_OF_FILE) {
+ _error('problem parsing URI', _peekToken.span);
+ }
+
+ if (_peek() == TokenKind.RPAREN) {
+ _next();
+ }
+
+ return UriTerm(urlParam, _makeSpan(start));
+ case 'var':
+ // TODO(terry): Consider handling var in IE specific filter/progid.
+ // This will require parsing entire IE specific syntax
+ // e.g. `param = value` or `progid:com_id`, etc.
+ // for example:
+ //
+ // var-blur: Blur(Add = 0, Direction = 225, Strength = 10);
+ // var-gradient: progid:DXImageTransform.Microsoft.gradient"
+ // (GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
+ var expr = processExpr();
+ if (!_maybeEat(TokenKind.RPAREN)) {
+ _error('problem parsing var expected ), ', _peekToken.span);
+ }
+ if (isChecked &&
+ expr.expressions.whereType<OperatorComma>().length > 1) {
+ _error('too many parameters to var()', _peekToken.span);
+ }
+
+ var paramName = (expr.expressions[0] as LiteralTerm).text;
+
+ // [0] - var name, [1] - OperatorComma, [2] - default value.
+ var defaultValues = expr.expressions.length >= 3
+ ? expr.expressions.sublist(2)
+ : <Expression>[];
+ return VarUsage(paramName, defaultValues, _makeSpan(start));
+ default:
+ var expr = processExpr();
+ if (!_maybeEat(TokenKind.RPAREN)) {
+ _error('problem parsing function expected ), ', _peekToken.span);
+ }
+
+ return FunctionTerm(name, name, expr, _makeSpan(start));
+ }
+ }
+
+ Identifier identifier() {
+ var tok = _next();
+
+ if (!TokenKind.isIdentifier(tok.kind) &&
+ !TokenKind.isKindIdentifier(tok.kind)) {
+ if (isChecked) {
+ _warning('expected identifier, but found $tok', tok.span);
+ }
+ return Identifier('', _makeSpan(tok.span));
+ }
+
+ return Identifier(tok.text, _makeSpan(tok.span));
+ }
+
+ // TODO(terry): Move this to base <= 36 and into shared code.
+ static int _hexDigit(int c) {
+ if (c >= 48 /*0*/ && c <= 57 /*9*/) {
+ return c - 48;
+ } else if (c >= 97 /*a*/ && c <= 102 /*f*/) {
+ return c - 87;
+ } else if (c >= 65 /*A*/ && c <= 70 /*F*/) {
+ return c - 55;
+ } else {
+ return -1;
+ }
+ }
+
+ HexColorTerm _parseHex(String hexText, SourceSpan span) {
+ var hexValue = 0;
+
+ for (var i = 0; i < hexText.length; i++) {
+ var digit = _hexDigit(hexText.codeUnitAt(i));
+ if (digit < 0) {
+ _warning('Bad hex number', span);
+ return HexColorTerm(BAD_HEX_VALUE(), hexText, span);
+ }
+ hexValue = (hexValue << 4) + digit;
+ }
+
+ // Make 3 character hex value #RRGGBB => #RGB iff:
+ // high/low nibble of RR is the same, high/low nibble of GG is the same and
+ // high/low nibble of BB is the same.
+ if (hexText.length == 6 &&
+ hexText[0] == hexText[1] &&
+ hexText[2] == hexText[3] &&
+ hexText[4] == hexText[5]) {
+ hexText = '${hexText[0]}${hexText[2]}${hexText[4]}';
+ } else if (hexText.length == 4 &&
+ hexText[0] == hexText[1] &&
+ hexText[2] == hexText[3]) {
+ hexText = '${hexText[0]}${hexText[2]}';
+ } else if (hexText.length == 2 && hexText[0] == hexText[1]) {
+ hexText = hexText[0];
+ }
+ return HexColorTerm(hexValue, hexText, span);
+ }
+}
+
+class ExpressionsProcessor {
+ final Expressions _exprs;
+ int _index = 0;
+
+ ExpressionsProcessor(this._exprs);
+
+ // TODO(terry): Only handles ##px unit.
+ FontExpression processFontSize() {
+ // font-size[/line-height]
+ //
+ // Possible size values:
+ // * xx-small
+ // * small
+ // * medium [default]
+ // * large
+ // * x-large
+ // * xx-large
+ // * smaller
+ // * larger
+ // * ##length in px, pt, etc.
+ // * ##%, percent of parent elem's font-size
+ // * inherit
+ LengthTerm? size;
+ LineHeight? lineHt;
+ var nextIsLineHeight = false;
+ for (; _index < _exprs.expressions.length; _index++) {
+ var expr = _exprs.expressions[_index];
+ if (size == null && expr is LengthTerm) {
+ // font-size part.
+ size = expr;
+ } else if (size != null) {
+ if (expr is OperatorSlash) {
+ // LineHeight could follow?
+ nextIsLineHeight = true;
+ } else if (nextIsLineHeight && expr is LengthTerm) {
+ assert(expr.unit == TokenKind.UNIT_LENGTH_PX);
+ lineHt = LineHeight(expr.value as num, inPixels: true);
+ nextIsLineHeight = false;
+ _index++;
+ break;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return FontExpression(_exprs.span, size: size, lineHeight: lineHt);
+ }
+
+ FontExpression processFontFamily() {
+ var family = <String>[];
+
+ // Possible family values:
+ // * font-family: arial, Times new roman ,Lucida Sans Unicode,Courier;
+ // * font-family: "Times New Roman", arial, Lucida Sans Unicode, Courier;
+ var moreFamilies = false;
+
+ for (; _index < _exprs.expressions.length; _index++) {
+ var expr = _exprs.expressions[_index];
+ if (expr is LiteralTerm) {
+ if (family.isEmpty || moreFamilies) {
+ // It's font-family now.
+ family.add(expr.toString());
+ moreFamilies = false;
+ } else if (isChecked) {
+ messages.warning('Only font-family can be a list', _exprs.span);
+ }
+ } else if (expr is OperatorComma && family.isNotEmpty) {
+ moreFamilies = true;
+ } else {
+ break;
+ }
+ }
+
+ return FontExpression(_exprs.span, family: family);
+ }
+
+ FontExpression processFont() {
+ // Process all parts of the font expression.
+ FontExpression? fontSize;
+ FontExpression? fontFamily;
+ for (; _index < _exprs.expressions.length; _index++) {
+ // Order is font-size font-family
+ fontSize ??= processFontSize();
+ fontFamily ??= processFontFamily();
+ // TODO(terry): Handle font-weight, font-style, and font-variant. See
+ // https://github.com/dart-lang/csslib/issues/3
+ // https://github.com/dart-lang/csslib/issues/4
+ // https://github.com/dart-lang/csslib/issues/5
+ }
+
+ return FontExpression(_exprs.span,
+ size: fontSize?.font.size,
+ lineHeight: fontSize?.font.lineHeight,
+ family: fontFamily?.font.family);
+ }
+}
+
+/// Escapes [text] for use in a CSS string.
+/// [single] specifies single quote `'` vs double quote `"`.
+String _escapeString(String text, {bool single = false}) {
+ StringBuffer? result;
+
+ for (var i = 0; i < text.length; i++) {
+ var code = text.codeUnitAt(i);
+ String? replace;
+ switch (code) {
+ case 34 /*'"'*/ :
+ if (!single) replace = r'\"';
+ break;
+ case 39 /*"'"*/ :
+ if (single) replace = r"\'";
+ break;
+ }
+
+ if (replace != null && result == null) {
+ result = StringBuffer(text.substring(0, i));
+ }
+
+ if (result != null) result.write(replace ?? text[i]);
+ }
+
+ return result == null ? text : result.toString();
+}
diff --git a/pkgs/csslib/lib/src/analyzer.dart b/pkgs/csslib/lib/src/analyzer.dart
new file mode 100644
index 0000000..9d6f4ff
--- /dev/null
+++ b/pkgs/csslib/lib/src/analyzer.dart
@@ -0,0 +1,1014 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../parser.dart';
+
+// TODO(terry): Add optimizing phase to remove duplicated selectors in the same
+// selector group (e.g., .btn, .btn { color: red; }). Also, look
+// at simplifying selectors expressions too (much harder).
+// TODO(terry): Detect invalid directive usage. All @imports must occur before
+// all rules other than @charset directive. Any @import directive
+// after any non @charset or @import directive are ignored. e.g.,
+// @import "a.css";
+// div { color: red; }
+// @import "b.css";
+// becomes:
+// @import "a.css";
+// div { color: red; }
+// <http://www.w3.org/TR/css3-syntax/#at-rules>
+
+/// Analysis phase will validate/fixup any new CSS feature or any Sass style
+/// feature.
+class Analyzer {
+ final List<StyleSheet> _styleSheets;
+ final Messages _messages;
+
+ Analyzer(this._styleSheets, this._messages);
+
+ // TODO(terry): Currently each feature walks the AST each time. Once we have
+ // our complete feature set consider benchmarking the cost and
+ // possibly combine in one walk.
+ void run() {
+ // Expand top-level @include.
+ TopLevelIncludes.expand(_messages, _styleSheets);
+
+ // Expand @include in declarations.
+ DeclarationIncludes.expand(_messages, _styleSheets);
+
+ // Remove all @mixin and @include
+ for (var styleSheet in _styleSheets) {
+ MixinsAndIncludes.remove(styleSheet);
+ }
+
+ // Expand any nested selectors using selector descendant combinator to
+ // signal CSS inheritance notation.
+ for (var styleSheet in _styleSheets) {
+ ExpandNestedSelectors()
+ ..visitStyleSheet(styleSheet)
+ ..flatten(styleSheet);
+ }
+
+ // Expand any @extend.
+ for (var styleSheet in _styleSheets) {
+ var allExtends = AllExtends()..visitStyleSheet(styleSheet);
+ InheritExtends(_messages, allExtends).visitStyleSheet(styleSheet);
+ }
+ }
+}
+
+/// Traverse all rulesets looking for nested ones. If a ruleset is in a
+/// declaration group (implies nested selector) then generate new ruleset(s) at
+/// level 0 of CSS using selector inheritance syntax (flattens the nesting).
+///
+/// How the AST works for a rule [RuleSet] and nested rules. First of all a
+/// CSS rule [RuleSet] consist of a selector and a declaration e.g.,
+///
+/// selector {
+/// declaration
+/// }
+///
+/// AST structure of a [RuleSet] is:
+///
+/// RuleSet
+/// SelectorGroup
+/// List<Selector>
+/// List<SimpleSelectorSequence>
+/// Combinator // +, >, ~, DESCENDENT, or NONE
+/// SimpleSelector // class, id, element, namespace, attribute
+/// DeclarationGroup
+/// List // Declaration or RuleSet
+///
+/// For the simple rule:
+///
+/// div + span { color: red; }
+///
+/// the AST [RuleSet] is:
+///
+/// RuleSet
+/// SelectorGroup
+/// List<Selector>
+/// [0]
+/// List<SimpleSelectorSequence>
+/// [0] Combinator = COMBINATOR_NONE
+/// ElementSelector (name = div)
+/// [1] Combinator = COMBINATOR_PLUS
+/// ElementSelector (name = span)
+/// DeclarationGroup
+/// List // Declarations or RuleSets
+/// [0]
+/// Declaration (property = color, expression = red)
+///
+/// Usually a SelectorGroup contains 1 Selector. Consider the selectors:
+///
+/// div { color: red; }
+/// a { color: red; }
+///
+/// are equivalent to
+///
+/// div, a { color : red; }
+///
+/// In the above the RuleSet would have a SelectorGroup with 2 selectors e.g.,
+///
+/// RuleSet
+/// SelectorGroup
+/// List<Selector>
+/// [0]
+/// List<SimpleSelectorSequence>
+/// [0] Combinator = COMBINATOR_NONE
+/// ElementSelector (name = div)
+/// [1]
+/// List<SimpleSelectorSequence>
+/// [0] Combinator = COMBINATOR_NONE
+/// ElementSelector (name = a)
+/// DeclarationGroup
+/// List // Declarations or RuleSets
+/// [0]
+/// Declaration (property = color, expression = red)
+///
+/// For a nested rule e.g.,
+///
+/// div {
+/// color : blue;
+/// a { color : red; }
+/// }
+///
+/// Would map to the follow CSS rules:
+///
+/// div { color: blue; }
+/// div a { color: red; }
+///
+/// The AST for the former nested rule is:
+///
+/// RuleSet
+/// SelectorGroup
+/// List<Selector>
+/// [0]
+/// List<SimpleSelectorSequence>
+/// [0] Combinator = COMBINATOR_NONE
+/// ElementSelector (name = div)
+/// DeclarationGroup
+/// List // Declarations or RuleSets
+/// [0]
+/// Declaration (property = color, expression = blue)
+/// [1]
+/// RuleSet
+/// SelectorGroup
+/// List<Selector>
+/// [0]
+/// List<SimpleSelectorSequence>
+/// [0] Combinator = COMBINATOR_NONE
+/// ElementSelector (name = a)
+/// DeclarationGroup
+/// List // Declarations or RuleSets
+/// [0]
+/// Declaration (property = color, expression = red)
+///
+/// Nested rules is a terse mechanism to describe CSS inheritance. The analyzer
+/// will flatten and expand the nested rules to it's flatten structure. Using
+/// the all parent [RuleSets] (selector expressions) and applying each nested
+/// [RuleSet] to the list of [Selectors] in a [SelectorGroup].
+///
+/// Then result is a style sheet where all nested rules have been flatten and
+/// expanded.
+class ExpandNestedSelectors extends Visitor {
+ /// Parent [RuleSet] if a nested rule otherwise `null`.
+ RuleSet? _parentRuleSet;
+
+ /// Top-most rule if nested rules.
+ SelectorGroup? _topLevelSelectorGroup;
+
+ /// SelectorGroup at each nesting level.
+ SelectorGroup? _nestedSelectorGroup;
+
+ /// Declaration (sans the nested selectors).
+ DeclarationGroup? _flatDeclarationGroup;
+
+ /// Each nested selector get's a flatten RuleSet.
+ List<RuleSet> _expandedRuleSets = [];
+
+ /// Maping of a nested rule set to the fully expanded list of RuleSet(s).
+ final _expansions = <RuleSet, List<RuleSet>>{};
+
+ @override
+ void visitRuleSet(RuleSet node) {
+ final oldParent = _parentRuleSet;
+
+ var oldNestedSelectorGroups = _nestedSelectorGroup;
+
+ if (_nestedSelectorGroup == null) {
+ // Create top-level selector (may have nested rules).
+ final newSelectors = node.selectorGroup!.selectors.toList();
+ _topLevelSelectorGroup = SelectorGroup(newSelectors, node.span);
+ _nestedSelectorGroup = _topLevelSelectorGroup;
+ } else {
+ // Generate new selector groups from the nested rules.
+ _nestedSelectorGroup = _mergeToFlatten(node);
+ }
+
+ _parentRuleSet = node;
+
+ super.visitRuleSet(node);
+
+ _parentRuleSet = oldParent;
+
+ // Remove nested rules; they're all flatten and in the _expandedRuleSets.
+ node.declarationGroup.declarations
+ .removeWhere((declaration) => declaration is RuleSet);
+
+ _nestedSelectorGroup = oldNestedSelectorGroups;
+
+ // If any expandedRuleSets and we're back at the top-level rule set then
+ // there were nested rule set(s).
+ if (_parentRuleSet == null) {
+ if (_expandedRuleSets.isNotEmpty) {
+ // Remember ruleset to replace with these flattened rulesets.
+ _expansions[node] = _expandedRuleSets;
+ _expandedRuleSets = [];
+ }
+ assert(_flatDeclarationGroup == null);
+ assert(_nestedSelectorGroup == null);
+ }
+ }
+
+ /// Build up the list of all inherited sequences from the parent selector
+ /// [node] is the current nested selector and it's parent is the last entry in
+ /// the [_nestedSelectorGroup].
+ SelectorGroup _mergeToFlatten(RuleSet node) {
+ // Create a new SelectorGroup for this nesting level.
+ var nestedSelectors = _nestedSelectorGroup!.selectors;
+ var selectors = node.selectorGroup!.selectors;
+
+ // Create a merged set of previous parent selectors and current selectors.
+ var newSelectors = <Selector>[];
+ for (var selector in selectors) {
+ for (var nestedSelector in nestedSelectors) {
+ var seq = _mergeNestedSelector(nestedSelector.simpleSelectorSequences,
+ selector.simpleSelectorSequences);
+ newSelectors.add(Selector(seq, node.span));
+ }
+ }
+
+ return SelectorGroup(newSelectors, node.span);
+ }
+
+ /// Merge the nested selector sequences [current] to the [parent] sequences or
+ /// substitute any & with the parent selector.
+ List<SimpleSelectorSequence> _mergeNestedSelector(
+ List<SimpleSelectorSequence> parent,
+ List<SimpleSelectorSequence> current) {
+ // If any & operator then the parent selector will be substituted otherwise
+ // the parent selector is pre-pended to the current selector.
+ var hasThis = current.any((s) => s.simpleSelector.isThis);
+
+ var newSequence = <SimpleSelectorSequence>[];
+
+ if (!hasThis) {
+ // If no & in the sector group then prefix with the parent selector.
+ newSequence.addAll(parent);
+ newSequence.addAll(_convertToDescendentSequence(current));
+ } else {
+ for (var sequence in current) {
+ if (sequence.simpleSelector.isThis) {
+ // Substitute the & with the parent selector and only use a combinator
+ // descendant if & is prefix by a sequence with an empty name e.g.,
+ // "... + &", "&", "... ~ &", etc.
+ var hasPrefix = newSequence.isNotEmpty &&
+ newSequence.last.simpleSelector.name.isNotEmpty;
+ newSequence.addAll(
+ hasPrefix ? _convertToDescendentSequence(parent) : parent);
+ } else {
+ newSequence.add(sequence);
+ }
+ }
+ }
+
+ return newSequence;
+ }
+
+ /// Return selector sequences with first sequence combinator being a
+ /// descendant. Used for nested selectors when the parent selector needs to
+ /// be prefixed to a nested selector or to substitute the this (&) with the
+ /// parent selector.
+ List<SimpleSelectorSequence> _convertToDescendentSequence(
+ List<SimpleSelectorSequence> sequences) {
+ if (sequences.isEmpty) return sequences;
+
+ var newSequences = <SimpleSelectorSequence>[];
+ var first = sequences.first;
+ newSequences.add(SimpleSelectorSequence(
+ first.simpleSelector, first.span, TokenKind.COMBINATOR_DESCENDANT));
+ newSequences.addAll(sequences.skip(1));
+
+ return newSequences;
+ }
+
+ @override
+ void visitDeclarationGroup(DeclarationGroup node) {
+ var span = node.span;
+
+ var currentGroup = DeclarationGroup([], span);
+
+ var oldGroup = _flatDeclarationGroup;
+ _flatDeclarationGroup = currentGroup;
+
+ var expandedLength = _expandedRuleSets.length;
+
+ super.visitDeclarationGroup(node);
+
+ // We're done with the group.
+ _flatDeclarationGroup = oldGroup;
+
+ // No nested rule to process it's a top-level rule.
+ if (_nestedSelectorGroup == _topLevelSelectorGroup) return;
+
+ // If flatten selector's declaration is empty skip this selector, no need
+ // to emit an empty nested selector.
+ if (currentGroup.declarations.isEmpty) return;
+
+ var selectorGroup = _nestedSelectorGroup;
+
+ // Build new rule set from the nested selectors and declarations.
+ var newRuleSet = RuleSet(selectorGroup, currentGroup, span);
+
+ // Place in order so outer-most rule is first.
+ if (expandedLength == _expandedRuleSets.length) {
+ _expandedRuleSets.add(newRuleSet);
+ } else {
+ _expandedRuleSets.insert(expandedLength, newRuleSet);
+ }
+ }
+
+ // Record all declarations in a nested selector (Declaration, VarDefinition
+ // and MarginGroup) but not the nested rule in the Declaration.
+
+ @override
+ void visitDeclaration(Declaration node) {
+ if (_parentRuleSet != null) {
+ _flatDeclarationGroup!.declarations.add(node);
+ }
+ super.visitDeclaration(node);
+ }
+
+ @override
+ void visitVarDefinition(VarDefinition node) {
+ if (_parentRuleSet != null) {
+ _flatDeclarationGroup!.declarations.add(node);
+ }
+ super.visitVarDefinition(node);
+ }
+
+ @override
+ void visitExtendDeclaration(ExtendDeclaration node) {
+ if (_parentRuleSet != null) {
+ _flatDeclarationGroup!.declarations.add(node);
+ }
+ super.visitExtendDeclaration(node);
+ }
+
+ @override
+ void visitMarginGroup(MarginGroup node) {
+ if (_parentRuleSet != null) {
+ _flatDeclarationGroup!.declarations.add(node);
+ }
+ super.visitMarginGroup(node);
+ }
+
+ /// Replace the rule set that contains nested rules with the flatten rule
+ /// sets.
+ void flatten(StyleSheet styleSheet) {
+ // TODO(terry): Iterate over topLevels instead of _expansions it's already
+ // a map (this maybe quadratic).
+ _expansions.forEach((RuleSet ruleSet, List<RuleSet> newRules) {
+ var index = styleSheet.topLevels.indexOf(ruleSet);
+ if (index == -1) {
+ // Check any @media directives for nested rules and replace them.
+ var found = _MediaRulesReplacer.replace(styleSheet, ruleSet, newRules);
+ assert(found);
+ } else {
+ styleSheet.topLevels.insertAll(index + 1, newRules);
+ }
+ });
+ _expansions.clear();
+ }
+}
+
+class _MediaRulesReplacer extends Visitor {
+ final RuleSet _ruleSet;
+ final List<RuleSet> _newRules;
+ bool _foundAndReplaced = false;
+
+ /// Look for the [ruleSet] inside of an @media directive; if found then
+ /// replace with the [newRules]. If [ruleSet] is found and replaced return
+ /// true.
+ static bool replace(
+ StyleSheet styleSheet, RuleSet ruleSet, List<RuleSet> newRules) {
+ var visitor = _MediaRulesReplacer(ruleSet, newRules);
+ visitor.visitStyleSheet(styleSheet);
+ return visitor._foundAndReplaced;
+ }
+
+ _MediaRulesReplacer(this._ruleSet, this._newRules);
+
+ @override
+ void visitMediaDirective(MediaDirective node) {
+ var index = node.rules.indexOf(_ruleSet);
+ if (index != -1) {
+ node.rules.insertAll(index + 1, _newRules);
+ _foundAndReplaced = true;
+ }
+ }
+}
+
+/// Expand all @include at the top-level the ruleset(s) associated with the
+/// mixin.
+class TopLevelIncludes extends Visitor {
+ StyleSheet? _styleSheet;
+ final Messages _messages;
+
+ /// Map of variable name key to it's definition.
+ final map = <String, MixinDefinition>{};
+ MixinDefinition? currDef;
+
+ static void expand(Messages messages, List<StyleSheet> styleSheets) {
+ TopLevelIncludes(messages, styleSheets);
+ }
+
+ bool _anyRulesets(MixinRulesetDirective def) =>
+ def.rulesets.any((rule) => rule is RuleSet);
+
+ TopLevelIncludes(this._messages, List<StyleSheet> styleSheets) {
+ for (var styleSheet in styleSheets) {
+ visitTree(styleSheet);
+ }
+ }
+
+ @override
+ void visitStyleSheet(StyleSheet ss) {
+ _styleSheet = ss;
+ super.visitStyleSheet(ss);
+ _styleSheet = null;
+ }
+
+ @override
+ void visitIncludeDirective(IncludeDirective node) {
+ final currDef = this.currDef;
+ if (map.containsKey(node.name)) {
+ var mixinDef = map[node.name];
+ if (mixinDef is MixinRulesetDirective) {
+ _TopLevelIncludeReplacer.replace(_styleSheet!, node, mixinDef.rulesets);
+ } else if (currDef is MixinRulesetDirective && _anyRulesets(currDef)) {
+ final mixinRuleset = currDef;
+ var index = mixinRuleset.rulesets.indexOf(node);
+ mixinRuleset.rulesets.removeAt(index);
+ _messages.warning(
+ 'Using declaration mixin ${node.name} as top-level mixin',
+ node.span);
+ }
+ } else {
+ if (currDef is MixinRulesetDirective) {
+ var rulesetDirect = currDef;
+ rulesetDirect.rulesets.removeWhere((entry) {
+ if (entry == node) {
+ _messages.warning('Undefined mixin ${node.name}', node.span);
+ return true;
+ }
+ return false;
+ });
+ }
+ }
+ super.visitIncludeDirective(node);
+ }
+
+ @override
+ void visitMixinRulesetDirective(MixinRulesetDirective node) {
+ currDef = node;
+
+ super.visitMixinRulesetDirective(node);
+
+ // Replace with latest top-level mixin definition.
+ map[node.name] = node;
+ currDef = null;
+ }
+
+ @override
+ void visitMixinDeclarationDirective(MixinDeclarationDirective node) {
+ currDef = node;
+
+ super.visitMixinDeclarationDirective(node);
+
+ // Replace with latest mixin definition.
+ map[node.name] = node;
+ currDef = null;
+ }
+}
+
+/// @include as a top-level with ruleset(s).
+class _TopLevelIncludeReplacer extends Visitor {
+ final IncludeDirective _include;
+ final List<TreeNode> _newRules;
+
+ /// Look for the [ruleSet] inside of an @media directive; if found then
+ /// replace with the [newRules]. If [ruleSet] is found and replaced return
+ /// true.
+ static void replace(StyleSheet styleSheet, IncludeDirective include,
+ List<TreeNode> newRules) {
+ _TopLevelIncludeReplacer(include, newRules).visitStyleSheet(styleSheet);
+ }
+
+ _TopLevelIncludeReplacer(this._include, this._newRules);
+
+ @override
+ void visitStyleSheet(StyleSheet node) {
+ var index = node.topLevels.indexOf(_include);
+ if (index != -1) {
+ node.topLevels.insertAll(index + 1, _newRules);
+ node.topLevels.replaceRange(index, index + 1, [NoOp()]);
+ }
+ super.visitStyleSheet(node);
+ }
+
+ @override
+ void visitMixinRulesetDirective(MixinRulesetDirective node) {
+ var index = node.rulesets.indexOf(_include);
+ if (index != -1) {
+ node.rulesets.insertAll(index + 1, _newRules);
+ // Only the resolve the @include once.
+ node.rulesets.replaceRange(index, index + 1, [NoOp()]);
+ }
+ super.visitMixinRulesetDirective(node);
+ }
+}
+
+/// Utility function to match an include to a list of either Declarations or
+/// RuleSets, depending on type of mixin (ruleset or declaration). The include
+/// can be an include in a declaration or an include directive (top-level).
+int _findInclude(List<Object> list, TreeNode node) {
+ final matchNode = (node is IncludeMixinAtDeclaration)
+ ? node.include
+ : node as IncludeDirective;
+
+ var index = 0;
+ for (var item in list) {
+ var includeNode = (item is IncludeMixinAtDeclaration) ? item.include : item;
+ if (includeNode == matchNode) return index;
+ index++;
+ }
+ return -1;
+}
+
+/// Stamp out a mixin with the defined args substituted with the user's
+/// parameters.
+class CallMixin extends Visitor {
+ final MixinDefinition mixinDef;
+ List<TreeNode>? _definedArgs;
+ Expressions? _currExpressions;
+ int _currIndex = -1;
+
+ final varUsages = <String, Map<Expressions, Set<int>>>{};
+
+ /// Only var defs with more than one expression (comma separated).
+ final Map<String, VarDefinition>? varDefs;
+
+ CallMixin(this.mixinDef, [this.varDefs]) {
+ if (mixinDef is MixinRulesetDirective) {
+ visitMixinRulesetDirective(mixinDef as MixinRulesetDirective);
+ } else {
+ visitMixinDeclarationDirective(mixinDef as MixinDeclarationDirective);
+ }
+ }
+
+ /// Given a mixin's defined arguments return a cloned mixin definition that
+ /// has replaced all defined arguments with user's supplied VarUsages.
+ MixinDefinition transform(List<List<Expression>> callArgs) {
+ // TODO(terry): Handle default arguments and varArgs.
+ // Transform mixin with callArgs.
+ for (var index = 0; index < _definedArgs!.length; index++) {
+ var definedArg = _definedArgs![index];
+ VarDefinition? varDef;
+ if (definedArg is VarDefinition) {
+ varDef = definedArg;
+ } else if (definedArg is VarDefinitionDirective) {
+ var varDirective = definedArg;
+ varDef = varDirective.def;
+ }
+ var callArg = callArgs[index];
+
+ // Is callArg a var definition with multi-args (expressions > 1).
+ var defArgs = _varDefsAsCallArgs(callArg);
+ if (defArgs.isNotEmpty) {
+ // Replace call args with the var def parameters.
+ callArgs.insertAll(index, defArgs);
+ callArgs.removeAt(index + defArgs.length);
+ callArg = callArgs[index];
+ }
+
+ var expressions = varUsages[varDef!.definedName];
+ expressions!.forEach((k, v) {
+ for (var usagesIndex in v) {
+ k.expressions.replaceRange(usagesIndex, usagesIndex + 1, callArg);
+ }
+ });
+ }
+
+ // Clone the mixin
+ return mixinDef.clone();
+ }
+
+ /// Rip apart var def with multiple parameters.
+ List<List<Expression>> _varDefsAsCallArgs(List<Expression> callArg) {
+ var defArgs = <List<Expression>>[];
+ var firstCallArg = callArg[0];
+ if (firstCallArg is VarUsage) {
+ var varDef = varDefs![firstCallArg.name];
+ var expressions = (varDef!.expression as Expressions).expressions;
+ assert(expressions.length > 1);
+ for (var expr in expressions) {
+ if (expr is! OperatorComma) {
+ defArgs.add([expr]);
+ }
+ }
+ }
+ return defArgs;
+ }
+
+ @override
+ void visitExpressions(Expressions node) {
+ var oldExpressions = _currExpressions;
+ var oldIndex = _currIndex;
+
+ _currExpressions = node;
+ for (_currIndex = 0; _currIndex < node.expressions.length; _currIndex++) {
+ node.expressions[_currIndex].visit(this);
+ }
+
+ _currIndex = oldIndex;
+ _currExpressions = oldExpressions;
+ }
+
+ void _addExpression(Map<Expressions, Set<int>> expressions) {
+ var indexSet = <int>{};
+ indexSet.add(_currIndex);
+ expressions[_currExpressions!] = indexSet;
+ }
+
+ @override
+ void visitVarUsage(VarUsage node) {
+ assert(_currIndex != -1);
+ assert(_currExpressions != null);
+ if (varUsages.containsKey(node.name)) {
+ var expressions = varUsages[node.name];
+ var allIndexes = expressions![_currExpressions];
+ if (allIndexes == null) {
+ _addExpression(expressions);
+ } else {
+ allIndexes.add(_currIndex);
+ }
+ } else {
+ var newExpressions = <Expressions, Set<int>>{};
+ _addExpression(newExpressions);
+ varUsages[node.name] = newExpressions;
+ }
+ super.visitVarUsage(node);
+ }
+
+ @override
+ void visitMixinDeclarationDirective(MixinDeclarationDirective node) {
+ _definedArgs = node.definedArgs;
+ super.visitMixinDeclarationDirective(node);
+ }
+
+ @override
+ void visitMixinRulesetDirective(MixinRulesetDirective node) {
+ _definedArgs = node.definedArgs;
+ super.visitMixinRulesetDirective(node);
+ }
+}
+
+/// Expand all @include inside of a declaration associated with a mixin.
+class DeclarationIncludes extends Visitor {
+ StyleSheet? _styleSheet;
+ final Messages _messages;
+
+ /// Map of variable name key to it's definition.
+ final Map<String, MixinDefinition> map = <String, MixinDefinition>{};
+
+ /// Cache of mixin called with parameters.
+ final Map<String, CallMixin> callMap = <String, CallMixin>{};
+ MixinDefinition? currDef;
+ DeclarationGroup? currDeclGroup;
+
+ /// Var definitions with more than 1 expression.
+ final varDefs = <String, VarDefinition>{};
+
+ static void expand(Messages messages, List<StyleSheet> styleSheets) {
+ DeclarationIncludes(messages, styleSheets);
+ }
+
+ DeclarationIncludes(this._messages, List<StyleSheet> styleSheets) {
+ for (var styleSheet in styleSheets) {
+ visitTree(styleSheet);
+ }
+ }
+
+ bool _allIncludes(List<TreeNode> rulesets) =>
+ rulesets.every((rule) => rule is IncludeDirective || rule is NoOp);
+
+ CallMixin _createCallDeclMixin(MixinDefinition mixinDef) =>
+ callMap[mixinDef.name] ??= CallMixin(mixinDef, varDefs);
+
+ @override
+ void visitStyleSheet(StyleSheet ss) {
+ _styleSheet = ss;
+ super.visitStyleSheet(ss);
+ _styleSheet = null;
+ }
+
+ @override
+ void visitDeclarationGroup(DeclarationGroup node) {
+ currDeclGroup = node;
+ super.visitDeclarationGroup(node);
+ currDeclGroup = null;
+ }
+
+ @override
+ void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) {
+ if (map.containsKey(node.include.name)) {
+ var mixinDef = map[node.include.name];
+
+ // Fix up any mixin that is really a Declaration but has includes.
+ if (mixinDef is MixinRulesetDirective) {
+ if (!_allIncludes(mixinDef.rulesets) && currDeclGroup != null) {
+ var index = _findInclude(currDeclGroup!.declarations, node);
+ if (index != -1) {
+ currDeclGroup!.declarations
+ .replaceRange(index, index + 1, [NoOp()]);
+ }
+ _messages.warning(
+ 'Using top-level mixin ${node.include.name} as a declaration',
+ node.span);
+ } else {
+ // We're a list of @include(s) inside of a mixin ruleset - convert
+ // to a list of IncludeMixinAtDeclaration(s).
+ var origRulesets = mixinDef.rulesets;
+ var rulesets = <Declaration>[];
+ if (origRulesets.every((ruleset) => ruleset is IncludeDirective)) {
+ for (var ruleset in origRulesets) {
+ rulesets.add(IncludeMixinAtDeclaration(
+ ruleset as IncludeDirective, ruleset.span));
+ }
+ _IncludeReplacer.replace(_styleSheet!, node, rulesets);
+ }
+ }
+ }
+
+ if (mixinDef!.definedArgs.isNotEmpty && node.include.args.isNotEmpty) {
+ var callMixin = _createCallDeclMixin(mixinDef);
+ mixinDef = callMixin.transform(node.include.args);
+ }
+
+ if (mixinDef is MixinDeclarationDirective) {
+ _IncludeReplacer.replace(
+ _styleSheet!, node, mixinDef.declarations.declarations);
+ }
+ } else {
+ _messages.warning('Undefined mixin ${node.include.name}', node.span);
+ }
+
+ super.visitIncludeMixinAtDeclaration(node);
+ }
+
+ @override
+ void visitIncludeDirective(IncludeDirective node) {
+ if (map.containsKey(node.name)) {
+ var mixinDef = map[node.name];
+ if (currDef is MixinDeclarationDirective &&
+ mixinDef is MixinDeclarationDirective) {
+ _IncludeReplacer.replace(
+ _styleSheet!, node, mixinDef.declarations.declarations);
+ } else if (currDef is MixinDeclarationDirective) {
+ var decls =
+ (currDef as MixinDeclarationDirective).declarations.declarations;
+ var index = _findInclude(decls, node);
+ if (index != -1) {
+ decls.replaceRange(index, index + 1, [NoOp()]);
+ }
+ }
+ }
+
+ super.visitIncludeDirective(node);
+ }
+
+ @override
+ void visitMixinRulesetDirective(MixinRulesetDirective node) {
+ currDef = node;
+
+ super.visitMixinRulesetDirective(node);
+
+ // Replace with latest top-level mixin definition.
+ map[node.name] = node;
+ currDef = null;
+ }
+
+ @override
+ void visitMixinDeclarationDirective(MixinDeclarationDirective node) {
+ currDef = node;
+
+ super.visitMixinDeclarationDirective(node);
+
+ // Replace with latest mixin definition.
+ map[node.name] = node;
+ currDef = null;
+ }
+
+ @override
+ void visitVarDefinition(VarDefinition node) {
+ // Only record var definitions that have multiple expressions (comma
+ // separated for mixin parameter substitution.
+ var exprs = (node.expression as Expressions).expressions;
+ if (exprs.length > 1) {
+ varDefs[node.definedName] = node;
+ }
+ super.visitVarDefinition(node);
+ }
+
+ @override
+ void visitVarDefinitionDirective(VarDefinitionDirective node) {
+ visitVarDefinition(node.def);
+ }
+}
+
+/// @include as a top-level with ruleset(s).
+class _IncludeReplacer extends Visitor {
+ final TreeNode _include;
+ final List<TreeNode> _newDeclarations;
+
+ /// Look for the [ruleSet] inside of a @media directive; if found then replace
+ /// with the [newRules].
+ static void replace(
+ StyleSheet ss, TreeNode include, List<TreeNode> newDeclarations) {
+ var visitor = _IncludeReplacer(include, newDeclarations);
+ visitor.visitStyleSheet(ss);
+ }
+
+ _IncludeReplacer(this._include, this._newDeclarations);
+
+ @override
+ void visitDeclarationGroup(DeclarationGroup node) {
+ var index = _findInclude(node.declarations, _include);
+ if (index != -1) {
+ node.declarations.insertAll(index + 1, _newDeclarations);
+ // Change @include to NoOp so it's processed only once.
+ node.declarations.replaceRange(index, index + 1, [NoOp()]);
+ }
+ super.visitDeclarationGroup(node);
+ }
+}
+
+/// Remove all @mixin and @include and any NoOp used as placeholder for
+/// @include.
+class MixinsAndIncludes extends Visitor {
+ static void remove(StyleSheet styleSheet) {
+ MixinsAndIncludes().visitStyleSheet(styleSheet);
+ }
+
+ bool _nodesToRemove(Object node) =>
+ node is IncludeDirective || node is MixinDefinition || node is NoOp;
+
+ @override
+ void visitStyleSheet(StyleSheet ss) {
+ var index = ss.topLevels.length;
+ while (--index >= 0) {
+ if (_nodesToRemove(ss.topLevels[index])) {
+ ss.topLevels.removeAt(index);
+ }
+ }
+ super.visitStyleSheet(ss);
+ }
+
+ @override
+ void visitDeclarationGroup(DeclarationGroup node) {
+ var index = node.declarations.length;
+ while (--index >= 0) {
+ if (_nodesToRemove(node.declarations[index])) {
+ node.declarations.removeAt(index);
+ }
+ }
+ super.visitDeclarationGroup(node);
+ }
+}
+
+/// Find all @extend to create inheritance.
+class AllExtends extends Visitor {
+ final inherits = <String, List<SelectorGroup>>{};
+
+ SelectorGroup? _currSelectorGroup;
+ int? _currDeclIndex;
+ final _extendsToRemove = <int>[];
+
+ @override
+ void visitRuleSet(RuleSet node) {
+ var oldSelectorGroup = _currSelectorGroup;
+ _currSelectorGroup = node.selectorGroup;
+
+ super.visitRuleSet(node);
+
+ _currSelectorGroup = oldSelectorGroup;
+ }
+
+ @override
+ void visitExtendDeclaration(ExtendDeclaration node) {
+ var inheritName = '';
+ for (var selector in node.selectors) {
+ inheritName += selector.toString();
+ }
+ if (inherits.containsKey(inheritName)) {
+ inherits[inheritName]!.add(_currSelectorGroup!);
+ } else {
+ inherits[inheritName] = [_currSelectorGroup!];
+ }
+
+ // Remove this @extend
+ _extendsToRemove.add(_currDeclIndex!);
+
+ super.visitExtendDeclaration(node);
+ }
+
+ @override
+ void visitDeclarationGroup(DeclarationGroup node) {
+ var oldDeclIndex = _currDeclIndex;
+
+ var decls = node.declarations;
+ for (_currDeclIndex = 0;
+ _currDeclIndex! < decls.length;
+ _currDeclIndex = _currDeclIndex! + 1) {
+ decls[_currDeclIndex!].visit(this);
+ }
+
+ if (_extendsToRemove.isNotEmpty) {
+ var removeTotal = _extendsToRemove.length - 1;
+ for (var index = removeTotal; index >= 0; index--) {
+ decls.removeAt(_extendsToRemove[index]);
+ }
+ _extendsToRemove.clear();
+ }
+
+ _currDeclIndex = oldDeclIndex;
+ }
+}
+
+// TODO(terry): Need to handle merging selector sequences
+// TODO(terry): Need to handle @extend-Only selectors.
+// TODO(terry): Need to handle !optional glag.
+/// Changes any selector that matches @extend.
+class InheritExtends extends Visitor {
+ final AllExtends _allExtends;
+
+ InheritExtends(Messages messages, this._allExtends);
+
+ @override
+ void visitSelectorGroup(SelectorGroup node) {
+ for (var selectorsIndex = 0;
+ selectorsIndex < node.selectors.length;
+ selectorsIndex++) {
+ var selectors = node.selectors[selectorsIndex];
+ var isLastNone = false;
+ var selectorName = '';
+ for (var index = 0;
+ index < selectors.simpleSelectorSequences.length;
+ index++) {
+ var simpleSeq = selectors.simpleSelectorSequences[index];
+ var namePart = simpleSeq.simpleSelector.toString();
+ selectorName = isLastNone ? (selectorName + namePart) : namePart;
+ var matches = _allExtends.inherits[selectorName];
+ if (matches != null) {
+ for (var match in matches) {
+ // Create a new group.
+ var newSelectors = selectors.clone();
+ var newSeq = match.selectors[0].clone();
+ if (isLastNone) {
+ // Add the inherited selector.
+ node.selectors.add(newSeq);
+ } else {
+ // Replace the selector sequence to the left of the pseudo class
+ // or pseudo element.
+
+ // Make new selector seq combinator the same as the original.
+ var orgCombinator =
+ newSelectors.simpleSelectorSequences[index].combinator;
+ newSeq.simpleSelectorSequences[0].combinator = orgCombinator;
+
+ newSelectors.simpleSelectorSequences.replaceRange(
+ index, index + 1, newSeq.simpleSelectorSequences);
+ node.selectors.add(newSelectors);
+ }
+ isLastNone = false;
+ }
+ } else {
+ isLastNone = simpleSeq.isCombinatorNone;
+ }
+ }
+ }
+ super.visitSelectorGroup(node);
+ }
+}
diff --git a/pkgs/csslib/lib/src/css_printer.dart b/pkgs/csslib/lib/src/css_printer.dart
new file mode 100644
index 0000000..463c855
--- /dev/null
+++ b/pkgs/csslib/lib/src/css_printer.dart
@@ -0,0 +1,737 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../visitor.dart';
+
+/// Visitor that produces a formatted string representation of the CSS tree.
+class CssPrinter extends Visitor {
+ StringBuffer _buff = StringBuffer();
+ bool _prettyPrint = true;
+ bool _isInKeyframes = false;
+ int _indent = 0;
+ bool _startOfLine = true;
+
+ /// Walk the [tree] Stylesheet. [pretty] if true emits line breaks, extra
+ /// spaces, friendly property values, etc., if false emits compacted output.
+ @override
+ void visitTree(StyleSheet tree, {bool pretty = false}) {
+ _prettyPrint = pretty;
+ _buff = StringBuffer();
+ _indent = 0;
+ _startOfLine = true;
+
+ visitStyleSheet(tree);
+ }
+
+ /// Appends [str] to the output buffer.
+ void emit(String str) {
+ if (_prettyPrint) {
+ if (_startOfLine) {
+ _startOfLine = false;
+ _buff.write(' ' * _indent);
+ }
+ _buff.write(str);
+ } else {
+ _buff.write(str);
+ }
+ }
+
+ void _emitLBrace() {
+ _indent += 2;
+ _buff.write('{');
+
+ if (_prettyPrint) {
+ _buff.writeln();
+ _startOfLine = true;
+ }
+ }
+
+ void _emitRBrace() {
+ _indent -= 2;
+
+ if (_prettyPrint) {
+ if (!_startOfLine) _buff.write('\n');
+ _buff.write('${' ' * _indent}}\n');
+ _startOfLine = true;
+ } else {
+ _buff.write('}');
+ }
+ }
+
+ void _emitSemicolon({bool forceLf = false}) {
+ if (_prettyPrint) {
+ _buff.write(';\n');
+ _startOfLine = true;
+ } else {
+ _buff.write(';');
+ if (forceLf) _buff.write('\n');
+ }
+ }
+
+ void _emitLf({bool force = false}) {
+ if (_prettyPrint) {
+ _buff.write('\n');
+ _startOfLine = true;
+ } else if (force) {
+ _buff.write('\n');
+ }
+ }
+
+ /// Returns the output buffer.
+ @override
+ String toString() => _buff.toString().trim();
+
+ String get _sp => _prettyPrint ? ' ' : '';
+
+ // TODO(terry): When adding obfuscation we'll need isOptimized (compact w/
+ // obfuscation) and have isTesting (compact no obfuscation) and
+ // isCompact would be !prettyPrint. We'll need another boolean
+ // flag for obfuscation.
+ bool get _isTesting => !_prettyPrint;
+
+ @override
+ void visitCalcTerm(CalcTerm node) {
+ emit('${node.text}(');
+ node.expr.visit(this);
+ emit(')');
+ }
+
+ @override
+ void visitCssComment(CssComment node) {
+ emit('/* ${node.comment} */');
+ }
+
+ @override
+ void visitCommentDefinition(CommentDefinition node) {
+ emit('<!-- ${node.comment} -->');
+ }
+
+ @override
+ void visitMediaExpression(MediaExpression node) {
+ emit(node.andOperator ? ' AND ' : ' ');
+ emit('(${node.mediaFeature}');
+ if (node.exprs.expressions.isNotEmpty) {
+ emit(':');
+ visitExpressions(node.exprs);
+ }
+ emit(')');
+ }
+
+ @override
+ void visitMediaQuery(MediaQuery node) {
+ var unary = node.hasUnary ? ' ${node.unary}' : '';
+ var mediaType = node.hasMediaType ? ' ${node.mediaType}' : '';
+ emit('$unary$mediaType');
+ for (var expression in node.expressions) {
+ visitMediaExpression(expression);
+ }
+ }
+
+ void emitMediaQueries(List<MediaQuery> queries) {
+ var queriesLen = queries.length;
+ for (var i = 0; i < queriesLen; i++) {
+ var query = queries[i];
+ if (i > 0) emit(',');
+ visitMediaQuery(query);
+ }
+ }
+
+ @override
+ void visitDocumentDirective(DocumentDirective node) {
+ emit('@-moz-document ');
+ node.functions.first.visit(this);
+ for (var function in node.functions.skip(1)) {
+ emit(',$_sp');
+ function.visit(this);
+ }
+ emit(_sp);
+ _emitLBrace();
+ for (var ruleSet in node.groupRuleBody) {
+ ruleSet.visit(this);
+ }
+ _emitRBrace();
+ }
+
+ @override
+ void visitSupportsDirective(SupportsDirective node) {
+ emit('@supports ');
+ node.condition!.visit(this);
+ emit(_sp);
+ _emitLBrace();
+ for (var rule in node.groupRuleBody) {
+ rule.visit(this);
+ }
+ _emitRBrace();
+ }
+
+ @override
+ void visitSupportsConditionInParens(SupportsConditionInParens node) {
+ emit('(');
+ node.condition!.visit(this);
+ emit(')');
+ }
+
+ @override
+ void visitSupportsNegation(SupportsNegation node) {
+ emit('not$_sp');
+ node.condition.visit(this);
+ }
+
+ @override
+ void visitSupportsConjunction(SupportsConjunction node) {
+ node.conditions.first.visit(this);
+ for (var condition in node.conditions.skip(1)) {
+ emit('${_sp}and$_sp');
+ condition.visit(this);
+ }
+ }
+
+ @override
+ void visitSupportsDisjunction(SupportsDisjunction node) {
+ node.conditions.first.visit(this);
+ for (var condition in node.conditions.skip(1)) {
+ emit('${_sp}or$_sp');
+ condition.visit(this);
+ }
+ }
+
+ @override
+ void visitViewportDirective(ViewportDirective node) {
+ emit('@${node.name}$_sp');
+ _emitLBrace();
+ node.declarations.visit(this);
+ _emitRBrace();
+ }
+
+ @override
+ void visitMediaDirective(MediaDirective node) {
+ emit('@media');
+ emitMediaQueries(node.mediaQueries.cast<MediaQuery>());
+ emit(_sp);
+ _emitLBrace();
+ for (var ruleset in node.rules) {
+ ruleset.visit(this);
+ }
+ _emitRBrace();
+ }
+
+ @override
+ void visitHostDirective(HostDirective node) {
+ emit('@host$_sp');
+ _emitLBrace();
+ for (var ruleset in node.rules) {
+ ruleset.visit(this);
+ }
+ _emitRBrace();
+ }
+
+ /// @page : pseudoPage {
+ /// decls
+ /// }
+ @override
+ void visitPageDirective(PageDirective node) {
+ emit('@page');
+ if (node.hasIdent || node.hasPseudoPage) {
+ if (node.hasIdent) emit(' ');
+ emit(node._ident!);
+ emit(node.hasPseudoPage ? ':${node._pseudoPage}' : '');
+ }
+
+ var declsMargin = node._declsMargin;
+ var declsMarginLength = declsMargin.length;
+ emit(_sp);
+ _emitLBrace();
+ for (var i = 0; i < declsMarginLength; i++) {
+ declsMargin[i].visit(this);
+ }
+ _emitRBrace();
+ }
+
+ /// @charset "charset encoding"
+ @override
+ void visitCharsetDirective(CharsetDirective node) {
+ emit('@charset "${node.charEncoding}"');
+ _emitSemicolon(forceLf: true);
+ }
+
+ @override
+ void visitImportDirective(ImportDirective node) {
+ bool isStartingQuote(String ch) => '\'"'.contains(ch[0]);
+
+ if (_isTesting) {
+ // Emit assuming url() was parsed; most suite tests use url function.
+ emit('@import url(${node.import})');
+ } else if (isStartingQuote(node.import)) {
+ emit('@import ${node.import}');
+ } else {
+ // url(...) isn't needed only a URI can follow an @import directive; emit
+ // url as a string.
+ emit('@import "${node.import}"');
+ }
+ emitMediaQueries(node.mediaQueries);
+ _emitSemicolon(forceLf: true);
+ }
+
+ @override
+ void visitKeyFrameDirective(KeyFrameDirective node) {
+ emit('${node.keyFrameName} ');
+ node.name!.visit(this);
+ emit(_sp);
+ _emitLBrace();
+ _isInKeyframes = true;
+ for (final block in node._blocks) {
+ block.visit(this);
+ }
+ _isInKeyframes = false;
+ _emitRBrace();
+ }
+
+ @override
+ void visitFontFaceDirective(FontFaceDirective node) {
+ emit('@font-face');
+ emit(_sp);
+ _emitLBrace();
+ node._declarations.visit(this);
+ _emitRBrace();
+ }
+
+ @override
+ void visitKeyFrameBlock(KeyFrameBlock node) {
+ node._blockSelectors.visit(this);
+ emit(_sp);
+ _emitLBrace();
+ node._declarations.visit(this);
+ _emitRBrace();
+ }
+
+ @override
+ void visitStyletDirective(StyletDirective node) {
+ emit('/* @stylet export as ${node.dartClassName} */');
+ _emitLf(force: true);
+ }
+
+ @override
+ void visitNamespaceDirective(NamespaceDirective node) {
+ bool isStartingQuote(String ch) => '\'"'.contains(ch);
+
+ if (isStartingQuote(node._uri!)) {
+ emit('@namespace ${node.prefix}"${node._uri}"');
+ } else {
+ if (_isTesting) {
+ // Emit exactly was we parsed.
+ emit('@namespace ${node.prefix}url(${node._uri})');
+ } else {
+ // url(...) isn't needed only a URI can follow a:
+ // @namespace prefix directive.
+ emit('@namespace ${node.prefix}${node._uri}');
+ }
+ }
+ _emitSemicolon(forceLf: true);
+ }
+
+ @override
+ void visitVarDefinitionDirective(VarDefinitionDirective node) {
+ visitVarDefinition(node.def);
+ _emitSemicolon();
+ }
+
+ @override
+ void visitMixinRulesetDirective(MixinRulesetDirective node) {
+ emit('@mixin ${node.name} ');
+ _emitLBrace();
+ for (var ruleset in node.rulesets) {
+ ruleset.visit(this);
+ }
+ _emitRBrace();
+ }
+
+ @override
+ void visitMixinDeclarationDirective(MixinDeclarationDirective node) {
+ emit('@mixin ${node.name}$_sp');
+ _emitLBrace();
+ visitDeclarationGroup(node.declarations);
+ _emitRBrace();
+ }
+
+ /// Added optional newLine for handling @include at top-level vs/ inside of
+ /// a declaration group.
+ @override
+ void visitIncludeDirective(IncludeDirective node, [bool topLevel = true]) {
+ if (topLevel) _emitLf();
+ emit('@include ${node.name}');
+ _emitSemicolon(forceLf: true);
+ }
+
+ @override
+ void visitContentDirective(ContentDirective node) {
+ // TODO(terry): TBD
+ }
+
+ @override
+ void visitRuleSet(RuleSet node) {
+ node.selectorGroup!.visit(this);
+ emit(_sp);
+ _emitLBrace();
+ node.declarationGroup.visit(this);
+ _emitRBrace();
+ }
+
+ @override
+ void visitDeclarationGroup(DeclarationGroup node) {
+ var declarations = node.declarations;
+ var declarationsLength = declarations.length;
+ for (var i = 0; i < declarationsLength; i++) {
+ declarations[i].visit(this);
+ // Don't emit the last semicolon in compact mode.
+ if (_prettyPrint || i < declarationsLength - 1) {
+ _emitSemicolon();
+ }
+ }
+ }
+
+ @override
+ void visitMarginGroup(MarginGroup node) {
+ var marginSymName =
+ TokenKind.idToValue(TokenKind.MARGIN_DIRECTIVES, node.margin_sym);
+
+ emit('@$marginSymName$_sp');
+ _emitLBrace();
+ visitDeclarationGroup(node);
+ _emitRBrace();
+ }
+
+ @override
+ void visitDeclaration(Declaration node) {
+ emit('${node.property}:$_sp');
+ node.expression!.visit(this);
+ if (node.important) {
+ emit('$_sp!important');
+ }
+ }
+
+ @override
+ void visitVarDefinition(VarDefinition node) {
+ emit('var-${node.definedName}: ');
+ node.expression!.visit(this);
+ }
+
+ @override
+ void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) {
+ // Don't emit a new line we're inside of a declaration group.
+ visitIncludeDirective(node.include, false);
+ }
+
+ @override
+ void visitExtendDeclaration(ExtendDeclaration node) {
+ emit('@extend ');
+ for (var selector in node.selectors) {
+ selector.visit(this);
+ }
+ }
+
+ @override
+ void visitSelectorGroup(SelectorGroup node) {
+ var selectors = node.selectors;
+ var selectorsLength = selectors.length;
+ for (var i = 0; i < selectorsLength; i++) {
+ if (i > 0) emit(',$_sp');
+ selectors[i].visit(this);
+ }
+ }
+
+ @override
+ void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
+ emit(node._combinatorToString);
+ node.simpleSelector.visit(this);
+ }
+
+ @override
+ void visitSimpleSelector(SimpleSelector node) {
+ emit(node.name);
+ }
+
+ @override
+ void visitNamespaceSelector(NamespaceSelector node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitElementSelector(ElementSelector node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitAttributeSelector(AttributeSelector node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitIdSelector(IdSelector node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitClassSelector(ClassSelector node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitPseudoClassSelector(PseudoClassSelector node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitPseudoElementSelector(PseudoElementSelector node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) {
+ emit(':${node.name}(');
+ node.argument.visit(this);
+ emit(')');
+ }
+
+ @override
+ void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) {
+ emit('::${node.name}(');
+ node.expression.visit(this);
+ emit(')');
+ }
+
+ @override
+ void visitNegationSelector(NegationSelector node) {
+ emit(':not(');
+ node.negationArg!.visit(this);
+ emit(')');
+ }
+
+ @override
+ void visitSelectorExpression(SelectorExpression node) {
+ var expressions = node.expressions;
+ var expressionsLength = expressions.length;
+ for (var i = 0; i < expressionsLength; i++) {
+ // Add space seperator between terms without an operator.
+ var expression = expressions[i];
+ expression.visit(this);
+ }
+ }
+
+ @override
+ void visitUnicodeRangeTerm(UnicodeRangeTerm node) {
+ if (node.hasSecond) {
+ emit('U+${node.first}-${node.second}');
+ } else {
+ emit('U+${node.first}');
+ }
+ }
+
+ @override
+ void visitLiteralTerm(LiteralTerm node) {
+ emit(node.text);
+ }
+
+ @override
+ void visitHexColorTerm(HexColorTerm node) {
+ String? mappedName;
+ if (_isTesting && (node.value is! BAD_HEX_VALUE)) {
+ mappedName = TokenKind.hexToColorName(node.value);
+ }
+ mappedName ??= '#${node.text}';
+
+ emit(mappedName);
+ }
+
+ @override
+ void visitNumberTerm(NumberTerm node) {
+ visitLiteralTerm(node);
+ }
+
+ @override
+ void visitUnitTerm(UnitTerm node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitLengthTerm(LengthTerm node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitPercentageTerm(PercentageTerm node) {
+ emit('${node.text}%');
+ }
+
+ @override
+ void visitEmTerm(EmTerm node) {
+ emit('${node.text}em');
+ }
+
+ @override
+ void visitExTerm(ExTerm node) {
+ emit('${node.text}ex');
+ }
+
+ @override
+ void visitAngleTerm(AngleTerm node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitTimeTerm(TimeTerm node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitFreqTerm(FreqTerm node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitFractionTerm(FractionTerm node) {
+ emit('${node.text}fr');
+ }
+
+ @override
+ void visitUriTerm(UriTerm node) {
+ emit('url("${node.text}")');
+ }
+
+ @override
+ void visitResolutionTerm(ResolutionTerm node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitViewportTerm(ViewportTerm node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitLineHeightTerm(LineHeightTerm node) {
+ emit(node.toString());
+ }
+
+ @override
+ void visitFunctionTerm(FunctionTerm node) {
+ // TODO(terry): Optimize rgb to a hexcolor.
+ emit('${node.text}(');
+ node._params.visit(this);
+ emit(')');
+ }
+
+ @override
+ void visitGroupTerm(GroupTerm node) {
+ emit('(');
+ var terms = node._terms;
+ var termsLength = terms.length;
+ for (var i = 0; i < termsLength; i++) {
+ if (i > 0) emit(_sp);
+ terms[i].visit(this);
+ }
+ emit(')');
+ }
+
+ @override
+ void visitItemTerm(ItemTerm node) {
+ emit('[${node.text}]');
+ }
+
+ @override
+ void visitIE8Term(IE8Term node) {
+ visitLiteralTerm(node);
+ }
+
+ @override
+ void visitOperatorSlash(OperatorSlash node) {
+ emit('/');
+ }
+
+ @override
+ void visitOperatorComma(OperatorComma node) {
+ emit(',');
+ }
+
+ @override
+ void visitOperatorPlus(OperatorPlus node) {
+ emit('+');
+ }
+
+ @override
+ void visitOperatorMinus(OperatorMinus node) {
+ emit('-');
+ }
+
+ @override
+ void visitVarUsage(VarUsage node) {
+ emit('var(${node.name}');
+ if (node.defaultValues.isNotEmpty) {
+ emit(',');
+ for (var defaultValue in node.defaultValues) {
+ emit(' ');
+ defaultValue.visit(this);
+ }
+ }
+ emit(')');
+ }
+
+ @override
+ void visitExpressions(Expressions node) {
+ var expressions = node.expressions;
+ var expressionsLength = expressions.length;
+
+ for (var i = 0; i < expressionsLength; i++) {
+ // Add space seperator between terms without an operator.
+ // TODO(terry): Should have a BinaryExpression to solve this problem.
+ var expression = expressions[i];
+ if (i > 0 &&
+ !(expression is OperatorComma || expression is OperatorSlash)) {
+ // If the previous expression is an operator, use `_sp` so the space is
+ // collapsed when emitted in compact mode. If the previous expression
+ // isn't an operator, the space is significant to delimit the two
+ // expressions and can't be collapsed.
+ var previous = expressions[i - 1];
+ if (previous is OperatorComma || previous is OperatorSlash) {
+ emit(_sp);
+ } else if (previous is PercentageTerm &&
+ expression is PercentageTerm &&
+ _isInKeyframes) {
+ emit(',');
+ emit(_sp);
+ } else {
+ emit(' ');
+ }
+ }
+ expression.visit(this);
+ }
+ }
+
+ @override
+ void visitBinaryExpression(BinaryExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError('visitBinaryExpression');
+ }
+
+ @override
+ void visitUnaryExpression(UnaryExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError('visitUnaryExpression');
+ }
+
+ @override
+ void visitIdentifier(Identifier node) {
+ emit(node.name);
+ }
+
+ @override
+ void visitWildcard(Wildcard node) {
+ emit('*');
+ }
+
+ @override
+ void visitDartStyleExpression(DartStyleExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError('visitDartStyleExpression');
+ }
+}
diff --git a/pkgs/csslib/lib/src/messages.dart b/pkgs/csslib/lib/src/messages.dart
new file mode 100644
index 0000000..fb1516c
--- /dev/null
+++ b/pkgs/csslib/lib/src/messages.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+import 'preprocessor_options.dart';
+
+enum MessageLevel { info, warning, severe }
+
+// TODO(#159): Remove the global messages, use some object that tracks
+// compilation state.
+
+/// The global [Messages] for tracking info/warnings/messages.
+late Messages messages;
+
+// Color constants used for generating messages.
+const _greenColor = '\u001b[32m';
+const _redColor = '\u001b[31m';
+const _magentaColor = '\u001b[35m';
+const _noColor = '\u001b[0m';
+
+/// Map between error levels and their display color.
+const Map<MessageLevel, String> _errorColors = {
+ MessageLevel.severe: _redColor,
+ MessageLevel.warning: _magentaColor,
+ MessageLevel.info: _greenColor,
+};
+
+/// Map between error levels and their friendly name.
+const Map<MessageLevel, String> _errorLabel = {
+ MessageLevel.severe: 'error',
+ MessageLevel.warning: 'warning',
+ MessageLevel.info: 'info',
+};
+
+/// A single message from the compiler.
+class Message {
+ final MessageLevel level;
+ final String message;
+ final SourceSpan? span;
+ final bool useColors;
+
+ Message(this.level, this.message, {this.span, this.useColors = false});
+
+ String get describe {
+ var span = this.span;
+ if (span == null) {
+ return message;
+ }
+
+ var start = span.start;
+ return '${start.line + 1}:${start.column + 1}:$message';
+ }
+
+ @override
+ String toString() {
+ var output = StringBuffer();
+ var colors = useColors && _errorColors.containsKey(level);
+ var levelColor = colors ? _errorColors[level] : null;
+ if (colors) output.write(levelColor);
+ output
+ ..write(_errorLabel[level])
+ ..write(' ');
+ if (colors) output.write(_noColor);
+
+ if (span == null) {
+ output.write(message);
+ } else {
+ output.write('on ');
+ output.write(span!.message(message, color: levelColor));
+ }
+
+ return output.toString();
+ }
+}
+
+/// This class tracks and prints information, warnings, and errors emitted by
+/// the compiler.
+class Messages {
+ /// Called on every error. Set to blank function to suppress printing.
+ final void Function(Message obj) printHandler;
+
+ final PreprocessorOptions options;
+
+ final List<Message> messages = <Message>[];
+
+ Messages({PreprocessorOptions? options, this.printHandler = print})
+ : options = options ?? const PreprocessorOptions();
+
+ /// Report a compile-time CSS error.
+ void error(String message, SourceSpan? span) {
+ var msg = Message(MessageLevel.severe, message,
+ span: span, useColors: options.useColors);
+
+ messages.add(msg);
+
+ printHandler(msg);
+ }
+
+ /// Report a compile-time CSS warning.
+ void warning(String message, SourceSpan? span) {
+ if (options.warningsAsErrors) {
+ error(message, span);
+ } else {
+ var msg = Message(MessageLevel.warning, message,
+ span: span, useColors: options.useColors);
+
+ messages.add(msg);
+ }
+ }
+
+ /// Report and informational message about what the compiler is doing.
+ void info(String message, SourceSpan span) {
+ var msg = Message(MessageLevel.info, message,
+ span: span, useColors: options.useColors);
+
+ messages.add(msg);
+
+ if (options.verbose) printHandler(msg);
+ }
+
+ /// Merge [newMessages] to this message list.
+ void mergeMessages(Messages newMessages) {
+ messages.addAll(newMessages.messages);
+ newMessages.messages
+ .where((message) =>
+ message.level == MessageLevel.severe || options.verbose)
+ .forEach(printHandler);
+ }
+}
diff --git a/pkgs/csslib/lib/src/polyfill.dart b/pkgs/csslib/lib/src/polyfill.dart
new file mode 100644
index 0000000..b65ec61
--- /dev/null
+++ b/pkgs/csslib/lib/src/polyfill.dart
@@ -0,0 +1,258 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../parser.dart';
+
+/// CSS polyfill emits CSS to be understood by older parsers that which do not
+/// understand (var, calc, etc.).
+class PolyFill {
+ final Messages _messages;
+ Map<String, VarDefinition> _allVarDefinitions = <String, VarDefinition>{};
+
+ Set<StyleSheet> allStyleSheets = <StyleSheet>{};
+
+ /// [_pseudoElements] list of known pseudo attributes found in HTML, any
+ /// CSS pseudo-elements 'name::custom-element' is mapped to the manged name
+ /// associated with the pseudo-element key.
+ PolyFill(this._messages);
+
+ /// Run the analyzer on every file that is a style sheet or any component that
+ /// has a style tag.
+ void process(StyleSheet styleSheet, {List<StyleSheet>? includes}) {
+ if (includes != null) {
+ processVarDefinitions(includes);
+ }
+ processVars(styleSheet);
+
+ // Remove all var definitions for this style sheet.
+ _RemoveVarDefinitions().visitTree(styleSheet);
+ }
+
+ /// Process all includes looking for var definitions.
+ void processVarDefinitions(List<StyleSheet> includes) {
+ for (var include in includes) {
+ _allVarDefinitions = (_VarDefinitionsIncludes(_allVarDefinitions)
+ ..visitTree(include))
+ .varDefs;
+ }
+ }
+
+ void processVars(StyleSheet styleSheet) {
+ // Build list of all var definitions.
+ var mainStyleSheetVarDefs = (_VarDefAndUsage(_messages, _allVarDefinitions)
+ ..visitTree(styleSheet))
+ .varDefs;
+
+ // Resolve all definitions to a non-VarUsage (terminal expression).
+ mainStyleSheetVarDefs.forEach((key, value) {
+ for (var _ in (value.expression as Expressions).expressions) {
+ mainStyleSheetVarDefs[key] =
+ _findTerminalVarDefinition(_allVarDefinitions, value);
+ }
+ });
+ }
+}
+
+/// Build list of all var definitions in all includes.
+class _VarDefinitionsIncludes extends Visitor {
+ final Map<String, VarDefinition> varDefs;
+
+ _VarDefinitionsIncludes(this.varDefs);
+
+ @override
+ void visitTree(StyleSheet tree) {
+ visitStyleSheet(tree);
+ }
+
+ @override
+ void visitVarDefinition(VarDefinition node) {
+ // Replace with latest variable definition.
+ varDefs[node.definedName] = node;
+ super.visitVarDefinition(node);
+ }
+
+ @override
+ void visitVarDefinitionDirective(VarDefinitionDirective node) {
+ visitVarDefinition(node.def);
+ }
+}
+
+/// Find var- definitions in a style sheet.
+/// [found] list of known definitions.
+class _VarDefAndUsage extends Visitor {
+ final Messages _messages;
+ final Map<String, VarDefinition> _knownVarDefs;
+ final varDefs = <String, VarDefinition>{};
+
+ VarDefinition? currVarDefinition;
+ List<Expression>? currentExpressions;
+
+ _VarDefAndUsage(this._messages, this._knownVarDefs);
+
+ @override
+ void visitTree(StyleSheet tree) {
+ visitStyleSheet(tree);
+ }
+
+ @override
+ void visitVarDefinition(VarDefinition node) {
+ // Replace with latest variable definition.
+ currVarDefinition = node;
+
+ _knownVarDefs[node.definedName] = node;
+ varDefs[node.definedName] = node;
+
+ super.visitVarDefinition(node);
+
+ currVarDefinition = null;
+ }
+
+ @override
+ void visitVarDefinitionDirective(VarDefinitionDirective node) {
+ visitVarDefinition(node.def);
+ }
+
+ @override
+ void visitExpressions(Expressions node) {
+ currentExpressions = node.expressions;
+ super.visitExpressions(node);
+ currentExpressions = null;
+ }
+
+ @override
+ void visitVarUsage(VarUsage node) {
+ if (currVarDefinition != null && currVarDefinition!.badUsage) return;
+
+ // Don't process other var() inside of a varUsage. That implies that the
+ // default is a var() too. Also, don't process any var() inside of a
+ // varDefinition (they're just place holders until we've resolved all real
+ // usages.
+ var expressions = currentExpressions;
+ var index = expressions!.indexOf(node);
+ assert(index >= 0);
+ var def = _knownVarDefs[node.name];
+ if (def != null) {
+ if (def.badUsage) {
+ // Remove any expressions pointing to a bad var definition.
+ expressions.removeAt(index);
+ return;
+ }
+ _resolveVarUsage(currentExpressions!, index,
+ _findTerminalVarDefinition(_knownVarDefs, def));
+ } else if (node.defaultValues.any((e) => e is VarUsage)) {
+ // Don't have a VarDefinition need to use default values resolve all
+ // default values.
+ var terminalDefaults = <Expression>[];
+ for (var defaultValue in node.defaultValues) {
+ terminalDefaults.addAll(resolveUsageTerminal(defaultValue as VarUsage));
+ }
+ expressions.replaceRange(index, index + 1, terminalDefaults);
+ } else if (node.defaultValues.isNotEmpty) {
+ // No VarDefinition but default value is a terminal expression; use it.
+ expressions.replaceRange(index, index + 1, node.defaultValues);
+ } else {
+ if (currVarDefinition != null) {
+ currVarDefinition!.badUsage = true;
+ var mainStyleSheetDef = varDefs[node.name];
+ if (mainStyleSheetDef != null) {
+ varDefs.remove(currVarDefinition!.property);
+ }
+ }
+ // Remove var usage that points at an undefined definition.
+ expressions.removeAt(index);
+ _messages.warning('Variable is not defined.', node.span);
+ }
+
+ var oldExpressions = currentExpressions;
+ currentExpressions = node.defaultValues;
+ super.visitVarUsage(node);
+ currentExpressions = oldExpressions;
+ }
+
+ List<Expression> resolveUsageTerminal(VarUsage usage) {
+ var result = <Expression>[];
+
+ var varDef = _knownVarDefs[usage.name];
+ List<Expression> expressions;
+ if (varDef == null) {
+ // VarDefinition not found try the defaultValues.
+ expressions = usage.defaultValues;
+ } else {
+ // Use the VarDefinition found.
+ expressions = (varDef.expression as Expressions).expressions;
+ }
+
+ for (var expr in expressions) {
+ if (expr is VarUsage) {
+ // Get terminal value.
+ result.addAll(resolveUsageTerminal(expr));
+ }
+ }
+
+ // We're at a terminal just return the VarDefinition expression.
+ if (result.isEmpty && varDef != null) {
+ result = (varDef.expression as Expressions).expressions;
+ }
+
+ return result;
+ }
+
+ void _resolveVarUsage(
+ List<Expression> expressions, int index, VarDefinition def) {
+ var defExpressions = (def.expression as Expressions).expressions;
+ expressions.replaceRange(index, index + 1, defExpressions);
+ }
+}
+
+/// Remove all var definitions.
+class _RemoveVarDefinitions extends Visitor {
+ @override
+ void visitTree(StyleSheet tree) {
+ visitStyleSheet(tree);
+ }
+
+ @override
+ void visitStyleSheet(StyleSheet ss) {
+ ss.topLevels.removeWhere((e) => e is VarDefinitionDirective);
+ super.visitStyleSheet(ss);
+ }
+
+ @override
+ void visitDeclarationGroup(DeclarationGroup node) {
+ node.declarations.removeWhere((e) => e is VarDefinition);
+ super.visitDeclarationGroup(node);
+ }
+}
+
+/// Find terminal definition (non VarUsage implies real CSS value).
+VarDefinition _findTerminalVarDefinition(
+ Map<String, VarDefinition> varDefs, VarDefinition varDef) {
+ var expressions = varDef.expression as Expressions;
+ for (var expr in expressions.expressions) {
+ if (expr is VarUsage) {
+ var usageName = expr.name;
+ var foundDef = varDefs[usageName];
+
+ // If foundDef is unknown check if defaultValues; if it exist then resolve
+ // to terminal value.
+ if (foundDef == null) {
+ // We're either a VarUsage or terminal definition if in varDefs;
+ // either way replace VarUsage with it's default value because the
+ // VarDefinition isn't found.
+ var defaultValues = expr.defaultValues;
+ var replaceExprs = expressions.expressions;
+ assert(replaceExprs.length == 1);
+ replaceExprs.replaceRange(0, 1, defaultValues);
+ return varDef;
+ }
+ return _findTerminalVarDefinition(varDefs, foundDef);
+ } else {
+ // Return real CSS property.
+ return varDef;
+ }
+ }
+
+ // Didn't point to a var definition that existed.
+ return varDef;
+}
diff --git a/pkgs/csslib/lib/src/preprocessor_options.dart b/pkgs/csslib/lib/src/preprocessor_options.dart
new file mode 100644
index 0000000..3879ead
--- /dev/null
+++ b/pkgs/csslib/lib/src/preprocessor_options.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class PreprocessorOptions {
+ /// Generate polyfill code (e.g., var, etc.)
+ final bool polyfill;
+
+ /// Report warnings as errors.
+ final bool warningsAsErrors;
+
+ /// Throw an exception on warnings (not used by command line tool).
+ final bool throwOnWarnings;
+
+ /// Throw an exception on errors (not used by command line tool).
+ final bool throwOnErrors;
+
+ /// True to show informational messages. The `--verbose` flag.
+ final bool verbose;
+
+ /// True to show warning messages for bad CSS. The '--checked' flag.
+ final bool checked;
+
+ // TODO(terry): Add mixin support and nested rules.
+ /// Subset of Less commands enabled; disable with '--no-less'.
+ /// Less syntax supported:
+ /// - @name at root level statically defines variables resolved at compilation
+ /// time. Essentially a directive e.g., @var-name.
+ final bool lessSupport;
+
+ /// Whether to use colors to print messages on the terminal.
+ final bool useColors;
+
+ /// File to process by the compiler.
+ final String? inputFile;
+
+ // TODO: Should less support really default to being enabled?
+
+ const PreprocessorOptions({
+ this.verbose = false,
+ this.checked = false,
+ this.lessSupport = true,
+ this.warningsAsErrors = false,
+ this.throwOnErrors = false,
+ this.throwOnWarnings = false,
+ this.useColors = true,
+ this.polyfill = false,
+ this.inputFile,
+ });
+}
diff --git a/pkgs/csslib/lib/src/property.dart b/pkgs/csslib/lib/src/property.dart
new file mode 100644
index 0000000..ec6b854
--- /dev/null
+++ b/pkgs/csslib/lib/src/property.dart
@@ -0,0 +1,1183 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Representations of CSS styles.
+
+part of '../parser.dart';
+
+// TODO(terry): Prune down this file we do need some of the code in this file
+// for darker, lighter, how to represent a Font, etc but alot of
+// the complexity can be removed.
+// See https://github.com/dart-lang/csslib/issues/7
+
+/// Base for all style properties (e.g., Color, Font, Border, Margin, etc.)
+abstract class _StyleProperty {
+ /// Returns the expression part of a CSS declaration. Declaration is:
+ ///
+ /// property:expression;
+ ///
+ /// E.g., if property is color then expression could be rgba(255,255,0) the
+ /// CSS declaration would be 'color:rgba(255,255,0);'.
+ ///
+ /// then _cssExpression would return 'rgba(255,255,0)'. See
+ /// <http://www.w3.org/TR/CSS21/grammar.html>
+ String? get cssExpression;
+}
+
+/// Base interface for Color, HSL and RGB.
+abstract class ColorBase {
+ /// Canonical form for color #rrggbb with alpha blending (0.0 == full
+ /// transparency and 1.0 == fully opaque). If _argb length is 6 it's an
+ /// rrggbb otherwise it's aarrggbb.
+ String toHexArgbString();
+
+ /// Return argb as a value (int).
+ int get argbValue;
+}
+
+/// General purpose Color class. Represent a color as an ARGB value that can be
+/// converted to and from num, hex string, hsl, hsla, rgb, rgba and SVG pre-
+/// defined color constant.
+class Color implements _StyleProperty, ColorBase {
+ // If _argb length is 6 it's an rrggbb otherwise it's aarrggbb.
+ final String _argb;
+
+ // TODO(terry): Look at reducing Rgba and Hsla classes as factories for
+ // converting from Color to an Rgba or Hsla for reading only.
+ // Usefulness of creating an Rgba or Hsla is limited.
+
+ /// Create a color with an integer representing the rgb value of red, green,
+ /// and blue. The value 0xffffff is the color white #ffffff (CSS style).
+ /// The [rgb] value of 0xffd700 would map to #ffd700 or the constant
+ /// Color.gold, where ff is red intensity, d7 is green intensity, and 00 is
+ /// blue intensity.
+ Color(int rgb, [num? alpha]) : _argb = Color._rgbToArgbString(rgb, alpha);
+
+ /// RGB takes three values. The [red], [green], and [blue] parameters are
+ /// the intensity of those components where '0' is the least and '256' is the
+ /// greatest.
+ ///
+ /// If [alpha] is provided, it is the level of translucency which ranges from
+ /// '0' (completely transparent) to '1.0' (completely opaque). It will
+ /// internally be mapped to an int between '0' and '255' like the other color
+ /// components.
+ Color.createRgba(int red, int green, int blue, [num? alpha])
+ : _argb = Color.convertToHexString(
+ Color._clamp(red, 0, 255),
+ Color._clamp(green, 0, 255),
+ Color._clamp(blue, 0, 255),
+ alpha != null ? Color._clamp(alpha, 0, 1) : alpha);
+
+ /// Creates a new color from a CSS color string. For more information, see
+ /// <https://developer.mozilla.org/en/CSS/color>.
+ Color.css(String color) : _argb = Color._convertCssToArgb(color)!;
+
+ // TODO(jmesserly): I found the use of percents a bit suprising.
+ /// HSL takes three values. The [hueDegree] degree on the color wheel; '0' is
+ /// the least and '100' is the greatest. The value '0' or '360' is red, '120'
+ /// is green, '240' is blue. Numbers in between reflect different shades.
+ /// The [saturationPercent] percentage; where'0' is the least and '100' is the
+ /// greatest (100 represents full color). The [lightnessPercent] percentage;
+ /// where'0' is the least and '100' is the greatest. The value 0 is dark or
+ /// black, 100 is light or white and 50 is a medium lightness.
+ ///
+ /// If [alpha] is provided, it is the level of translucency which ranges from
+ /// '0' (completely transparent foreground) to '1.0' (completely opaque
+ /// foreground).
+ Color.createHsla(num hueDegree, num saturationPercent, num lightnessPercent,
+ [num? alpha])
+ : _argb = Hsla(
+ Color._clamp(hueDegree, 0, 360) / 360,
+ Color._clamp(saturationPercent, 0, 100) / 100,
+ Color._clamp(lightnessPercent, 0, 100) / 100,
+ alpha != null ? Color._clamp(alpha, 0, 1) : alpha)
+ .toHexArgbString();
+
+ /// The hslaRaw takes three values. The [hue] degree on the color wheel; '0'
+ /// is the least and '1' is the greatest. The value '0' or '1' is red, the
+ /// ratio of 120/360 is green, and the ratio of 240/360 is blue. Numbers in
+ /// between reflect different shades. The [saturation] is a percentage; '0'
+ /// is the least and '1' is the greatest. The value of '1' is equivalent to
+ /// 100% (full colour). The [lightness] is a percentage; '0' is the least and
+ /// '1' is the greatest. The value of '0' is dark (black), the value of '1'
+ /// is light (white), and the value of '.50' is a medium lightness.
+ ///
+ /// The fourth optional parameter is:
+ /// [alpha] level of translucency range of values is 0..1, zero is a
+ /// completely transparent foreground and 1 is a completely
+ /// opaque foreground.
+ Color.hslaRaw(num hue, num saturation, num lightness, [num? alpha])
+ : _argb = Hsla(
+ Color._clamp(hue, 0, 1),
+ Color._clamp(saturation, 0, 1),
+ Color._clamp(lightness, 0, 1),
+ alpha != null ? Color._clamp(alpha, 0, 1) : alpha)
+ .toHexArgbString();
+
+ /// Generate a real constant for pre-defined colors (no leading #).
+ const Color.hex(this._argb);
+
+ // TODO(jmesserly): this is needed by the example so leave it exposed for now.
+ @override
+ String toString() => cssExpression;
+
+ // TODO(terry): Regardless of how color is set (rgb, num, css or hsl) we'll
+ // always return a rgb or rgba loses fidelity when debugging in
+ // CSS if user uses hsl and would like to edit as hsl, etc. If
+ // this is an issue we should keep the original value and not re-
+ // create the CSS from the normalized value.
+ @override
+ String get cssExpression {
+ if (_argb.length == 6) {
+ return '#$_argb'; // RGB only, no alpha blending.
+ } else {
+ num alpha = Color.hexToInt(_argb.substring(0, 2));
+ var a = (alpha / 255).toStringAsPrecision(2);
+ var r = Color.hexToInt(_argb.substring(2, 4));
+ var g = Color.hexToInt(_argb.substring(4, 6));
+ var b = Color.hexToInt(_argb.substring(6, 8));
+ return 'rgba($r,$g,$b,$a)';
+ }
+ }
+
+ Rgba get rgba {
+ var nextIndex = 0;
+ num? a;
+ if (_argb.length == 8) {
+ // Get alpha blending value 0..255
+ var alpha = Color.hexToInt(_argb.substring(nextIndex, nextIndex + 2));
+ // Convert to value from 0..1
+ a = double.parse((alpha / 255).toStringAsPrecision(2));
+ nextIndex += 2;
+ }
+ var r = Color.hexToInt(_argb.substring(nextIndex, nextIndex + 2));
+ nextIndex += 2;
+ var g = Color.hexToInt(_argb.substring(nextIndex, nextIndex + 2));
+ nextIndex += 2;
+ var b = Color.hexToInt(_argb.substring(nextIndex, nextIndex + 2));
+ return Rgba(r, g, b, a);
+ }
+
+ Hsla get hsla => Hsla.fromRgba(rgba);
+
+ @override
+ int get argbValue => Color.hexToInt(_argb);
+
+ @override
+ bool operator ==(Object other) => Color.equal(this, other);
+
+ @override
+ String toHexArgbString() => _argb;
+
+ Color darker(num amount) {
+ var newRgba = Color._createNewTintShadeFromRgba(rgba, -amount);
+ return Color.hex(newRgba.toHexArgbString());
+ }
+
+ Color lighter(num amount) {
+ var newRgba = Color._createNewTintShadeFromRgba(rgba, amount);
+ return Color.hex(newRgba.toHexArgbString());
+ }
+
+ static bool equal(ColorBase curr, Object other) {
+ if (other is Color) {
+ var o = other;
+ return o.toHexArgbString() == curr.toHexArgbString();
+ } else if (other is Rgba) {
+ var rgb = other;
+ return rgb.toHexArgbString() == curr.toHexArgbString();
+ } else if (other is Hsla) {
+ var hsla = other;
+ return hsla.toHexArgbString() == curr.toHexArgbString();
+ } else {
+ return false;
+ }
+ }
+
+ @override
+ int get hashCode => _argb.hashCode;
+
+ // Conversion routines:
+
+ static String _rgbToArgbString(int rgba, num? alpha) {
+ num? a;
+ // If alpha is defined then adjust from 0..1 to 0..255 value, if not set
+ // then a is left as undefined and passed to convertToHexString.
+ if (alpha != null) {
+ a = (Color._clamp(alpha, 0, 1) * 255).round();
+ }
+
+ var r = (rgba & 0xff0000) >> 0x10;
+ var g = (rgba & 0xff00) >> 8;
+ var b = rgba & 0xff;
+
+ return Color.convertToHexString(r, g, b, a);
+ }
+
+ static const int _rgbCss = 1;
+ static const int _rgbaCss = 2;
+ static const int _hslCss = 3;
+ static const int _hslaCss = 4;
+
+ /// Parse CSS expressions of the from #rgb, rgb(r,g,b), rgba(r,g,b,a),
+ /// hsl(h,s,l), hsla(h,s,l,a) and SVG colors (e.g., darkSlateblue, etc.) and
+ /// convert to argb.
+ static String? _convertCssToArgb(String value) {
+ // TODO(terry): Better parser/regex for converting CSS properties.
+ var color = value.trim().replaceAll('\\s', '');
+ if (color[0] == '#') {
+ var v = color.substring(1);
+ Color.hexToInt(v); // Valid hexadecimal, throws if not.
+ return v;
+ } else if (color.isNotEmpty && color[color.length - 1] == ')') {
+ int type;
+ if (color.indexOf('rgb(') == 0 || color.indexOf('RGB(') == 0) {
+ color = color.substring(4);
+ type = _rgbCss;
+ } else if (color.indexOf('rgba(') == 0 || color.indexOf('RGBA(') == 0) {
+ type = _rgbaCss;
+ color = color.substring(5);
+ } else if (color.indexOf('hsl(') == 0 || color.indexOf('HSL(') == 0) {
+ type = _hslCss;
+ color = color.substring(4);
+ } else if (color.indexOf('hsla(') == 0 || color.indexOf('HSLA(') == 0) {
+ type = _hslaCss;
+ color = color.substring(5);
+ } else {
+ throw UnsupportedError('CSS property not implemented');
+ }
+
+ color = color.substring(0, color.length - 1); // Strip close paren.
+
+ var args = <num>[];
+ var params = color.split(',');
+ for (var param in params) {
+ args.add(double.parse(param));
+ }
+ switch (type) {
+ case _rgbCss:
+ return Color.convertToHexString(
+ args[0].toInt(), args[1].toInt(), args[2].toInt());
+ case _rgbaCss:
+ return Color.convertToHexString(
+ args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3]);
+ case _hslCss:
+ return Hsla(args[0], args[1], args[2]).toHexArgbString();
+ case _hslaCss:
+ return Hsla(args[0], args[1], args[2], args[3]).toHexArgbString();
+ default:
+ // Type not defined UnsupportedOperationException should have thrown.
+ assert(false);
+ break;
+ }
+ }
+ return null;
+ }
+
+ static int hexToInt(String hex) => int.parse(hex, radix: 16);
+
+ static String convertToHexString(int r, int g, int b, [num? a]) {
+ var rHex = Color._numAs2DigitHex(Color._clamp(r, 0, 255));
+ var gHex = Color._numAs2DigitHex(Color._clamp(g, 0, 255));
+ var bHex = Color._numAs2DigitHex(Color._clamp(b, 0, 255));
+ var aHex = (a != null)
+ ? Color._numAs2DigitHex((Color._clamp(a, 0, 1) * 255).round())
+ : '';
+
+ // TODO(terry) 15.toRadixString(16) return 'F' on Dartium not f as in JS.
+ // bug: <http://code.google.com/p/dart/issues/detail?id=2670>
+ return '$aHex$rHex$gHex$bHex'.toLowerCase();
+ }
+
+ static String _numAs2DigitHex(int v) => v.toRadixString(16).padLeft(2, '0');
+
+ static T _clamp<T extends num>(T value, T min, T max) =>
+ math.max(math.min(max, value), min);
+
+ /// Change the tint (make color lighter) or shade (make color darker) of all
+ /// parts of [rgba] (r, g and b). The [amount] is percentage darker between
+ /// -1 to 0 for darker and 0 to 1 for lighter; '0' is no change. The [amount]
+ /// will darken or lighten the rgb values; it will not change the alpha value.
+ /// If [amount] is outside of the value -1 to +1 then [amount] is changed to
+ /// either the min or max direction -1 or 1.
+ ///
+ /// Darker will approach the color #000000 (black) and lighter will approach
+ /// the color #ffffff (white).
+ static Rgba _createNewTintShadeFromRgba(Rgba rgba, num amount) {
+ int r, g, b;
+ var tintShade = Color._clamp(amount, -1, 1);
+ if (amount < 0 && rgba.r == 255 && rgba.g == 255 && rgba.b == 255) {
+ // TODO(terry): See TODO in _changeTintShadeColor; eliminate this test
+ // by converting to HSL and adjust lightness although this
+ // is fastest lighter/darker algorithm.
+ // Darkening white special handling.
+ r = Color._clamp((255 + (255 * tintShade)).round().toInt(), 0, 255);
+ g = Color._clamp((255 + (255 * tintShade)).round().toInt(), 0, 255);
+ b = Color._clamp((255 + (255 * tintShade)).round().toInt(), 0, 255);
+ } else {
+ // All other colors then darkening white go here.
+ r = Color._changeTintShadeColor(rgba.r, tintShade).round().toInt();
+ g = Color._changeTintShadeColor(rgba.g, tintShade).round().toInt();
+ b = Color._changeTintShadeColor(rgba.b, tintShade).round().toInt();
+ }
+ return Rgba(r, g, b, rgba.a);
+ }
+
+ // TODO(terry): This does an okay lighter/darker; better would be convert to
+ // HSL then change the lightness.
+ /// The parameter [v] is the color to change (r, g, or b) in the range '0' to
+ /// '255'. The parameter [delta] is a number between '-1' and '1'. A value
+ /// between '-1' and '0' is darker and a value between '0' and '1' is lighter
+ /// ('0' imples no change).
+ static num _changeTintShadeColor(num v, num delta) =>
+ Color._clamp(((1 - delta) * v + (delta * 255)).round(), 0, 255);
+
+ // Predefined CSS colors see <http://www.w3.org/TR/css3-color/>
+ static final Color transparent = const Color.hex('00ffffff'); // Alpha 0.0
+ static final Color aliceBlue = const Color.hex('0f08ff');
+ static final Color antiqueWhite = const Color.hex('0faebd7');
+ static final Color aqua = const Color.hex('00ffff');
+ static final Color aquaMarine = const Color.hex('7fffd4');
+ static final Color azure = const Color.hex('f0ffff');
+ static final Color beige = const Color.hex('f5f5dc');
+ static final Color bisque = const Color.hex('ffe4c4');
+ static final Color black = const Color.hex('000000');
+ static final Color blanchedAlmond = const Color.hex('ffebcd');
+ static final Color blue = const Color.hex('0000ff');
+ static final Color blueViolet = const Color.hex('8a2be2');
+ static final Color brown = const Color.hex('a52a2a');
+ static final Color burlyWood = const Color.hex('deb887');
+ static final Color cadetBlue = const Color.hex('5f9ea0');
+ static final Color chartreuse = const Color.hex('7fff00');
+ static final Color chocolate = const Color.hex('d2691e');
+ static final Color coral = const Color.hex('ff7f50');
+ static final Color cornFlowerBlue = const Color.hex('6495ed');
+ static final Color cornSilk = const Color.hex('fff8dc');
+ static final Color crimson = const Color.hex('dc143c');
+ static final Color cyan = const Color.hex('00ffff');
+ static final Color darkBlue = const Color.hex('00008b');
+ static final Color darkCyan = const Color.hex('008b8b');
+ static final Color darkGoldenRod = const Color.hex('b8860b');
+ static final Color darkGray = const Color.hex('a9a9a9');
+ static final Color darkGreen = const Color.hex('006400');
+ static final Color darkGrey = const Color.hex('a9a9a9');
+ static final Color darkKhaki = const Color.hex('bdb76b');
+ static final Color darkMagenta = const Color.hex('8b008b');
+ static final Color darkOliveGreen = const Color.hex('556b2f');
+ static final Color darkOrange = const Color.hex('ff8c00');
+ static final Color darkOrchid = const Color.hex('9932cc');
+ static final Color darkRed = const Color.hex('8b0000');
+ static final Color darkSalmon = const Color.hex('e9967a');
+ static final Color darkSeaGreen = const Color.hex('8fbc8f');
+ static final Color darkSlateBlue = const Color.hex('483d8b');
+ static final Color darkSlateGray = const Color.hex('2f4f4f');
+ static final Color darkSlateGrey = const Color.hex('2f4f4f');
+ static final Color darkTurquoise = const Color.hex('00ced1');
+ static final Color darkViolet = const Color.hex('9400d3');
+ static final Color deepPink = const Color.hex('ff1493');
+ static final Color deepSkyBlue = const Color.hex('00bfff');
+ static final Color dimGray = const Color.hex('696969');
+ static final Color dimGrey = const Color.hex('696969');
+ static final Color dodgerBlue = const Color.hex('1e90ff');
+ static final Color fireBrick = const Color.hex('b22222');
+ static final Color floralWhite = const Color.hex('fffaf0');
+ static final Color forestGreen = const Color.hex('228b22');
+ static final Color fuchsia = const Color.hex('ff00ff');
+ static final Color gainsboro = const Color.hex('dcdcdc');
+ static final Color ghostWhite = const Color.hex('f8f8ff');
+ static final Color gold = const Color.hex('ffd700');
+ static final Color goldenRod = const Color.hex('daa520');
+ static final Color gray = const Color.hex('808080');
+ static final Color green = const Color.hex('008000');
+ static final Color greenYellow = const Color.hex('adff2f');
+ static final Color grey = const Color.hex('808080');
+ static final Color honeydew = const Color.hex('f0fff0');
+ static final Color hotPink = const Color.hex('ff69b4');
+ static final Color indianRed = const Color.hex('cd5c5c');
+ static final Color indigo = const Color.hex('4b0082');
+ static final Color ivory = const Color.hex('fffff0');
+ static final Color khaki = const Color.hex('f0e68c');
+ static final Color lavender = const Color.hex('e6e6fa');
+ static final Color lavenderBlush = const Color.hex('fff0f5');
+ static final Color lawnGreen = const Color.hex('7cfc00');
+ static final Color lemonChiffon = const Color.hex('fffacd');
+ static final Color lightBlue = const Color.hex('add8e6');
+ static final Color lightCoral = const Color.hex('f08080');
+ static final Color lightCyan = const Color.hex('e0ffff');
+ static final Color lightGoldenRodYellow = const Color.hex('fafad2');
+ static final Color lightGray = const Color.hex('d3d3d3');
+ static final Color lightGreen = const Color.hex('90ee90');
+ static final Color lightGrey = const Color.hex('d3d3d3');
+ static final Color lightPink = const Color.hex('ffb6c1');
+ static final Color lightSalmon = const Color.hex('ffa07a');
+ static final Color lightSeaGreen = const Color.hex('20b2aa');
+ static final Color lightSkyBlue = const Color.hex('87cefa');
+ static final Color lightSlateGray = const Color.hex('778899');
+ static final Color lightSlateGrey = const Color.hex('778899');
+ static final Color lightSteelBlue = const Color.hex('b0c4de');
+ static final Color lightYellow = const Color.hex('ffffe0');
+ static final Color lime = const Color.hex('00ff00');
+ static final Color limeGreen = const Color.hex('32cd32');
+ static final Color linen = const Color.hex('faf0e6');
+ static final Color magenta = const Color.hex('ff00ff');
+ static final Color maroon = const Color.hex('800000');
+ static final Color mediumAquaMarine = const Color.hex('66cdaa');
+ static final Color mediumBlue = const Color.hex('0000cd');
+ static final Color mediumOrchid = const Color.hex('ba55d3');
+ static final Color mediumPurple = const Color.hex('9370db');
+ static final Color mediumSeaGreen = const Color.hex('3cb371');
+ static final Color mediumSlateBlue = const Color.hex('7b68ee');
+ static final Color mediumSpringGreen = const Color.hex('00fa9a');
+ static final Color mediumTurquoise = const Color.hex('48d1cc');
+ static final Color mediumVioletRed = const Color.hex('c71585');
+ static final Color midnightBlue = const Color.hex('191970');
+ static final Color mintCream = const Color.hex('f5fffa');
+ static final Color mistyRose = const Color.hex('ffe4e1');
+ static final Color moccasin = const Color.hex('ffe4b5');
+ static final Color navajoWhite = const Color.hex('ffdead');
+ static final Color navy = const Color.hex('000080');
+ static final Color oldLace = const Color.hex('fdf5e6');
+ static final Color olive = const Color.hex('808000');
+ static final Color oliveDrab = const Color.hex('6b8e23');
+ static final Color orange = const Color.hex('ffa500');
+ static final Color orangeRed = const Color.hex('ff4500');
+ static final Color orchid = const Color.hex('da70d6');
+ static final Color paleGoldenRod = const Color.hex('eee8aa');
+ static final Color paleGreen = const Color.hex('98fb98');
+ static final Color paleTurquoise = const Color.hex('afeeee');
+ static final Color paleVioletRed = const Color.hex('db7093');
+ static final Color papayaWhip = const Color.hex('ffefd5');
+ static final Color peachPuff = const Color.hex('ffdab9');
+ static final Color peru = const Color.hex('cd85ef');
+ static final Color pink = const Color.hex('ffc0cb');
+ static final Color plum = const Color.hex('dda0dd');
+ static final Color powderBlue = const Color.hex('b0e0e6');
+ static final Color purple = const Color.hex('800080');
+ static final Color red = const Color.hex('ff0000');
+ static final Color rosyBrown = const Color.hex('bc8f8f');
+ static final Color royalBlue = const Color.hex('4169e1');
+ static final Color saddleBrown = const Color.hex('8b4513');
+ static final Color salmon = const Color.hex('fa8072');
+ static final Color sandyBrown = const Color.hex('f4a460');
+ static final Color seaGreen = const Color.hex('2e8b57');
+ static final Color seashell = const Color.hex('fff5ee');
+ static final Color sienna = const Color.hex('a0522d');
+ static final Color silver = const Color.hex('c0c0c0');
+ static final Color skyBlue = const Color.hex('87ceeb');
+ static final Color slateBlue = const Color.hex('6a5acd');
+ static final Color slateGray = const Color.hex('708090');
+ static final Color slateGrey = const Color.hex('708090');
+ static final Color snow = const Color.hex('fffafa');
+ static final Color springGreen = const Color.hex('00ff7f');
+ static final Color steelBlue = const Color.hex('4682b4');
+ static final Color tan = const Color.hex('d2b48c');
+ static final Color teal = const Color.hex('008080');
+ static final Color thistle = const Color.hex('d8bfd8');
+ static final Color tomato = const Color.hex('ff6347');
+ static final Color turquoise = const Color.hex('40e0d0');
+ static final Color violet = const Color.hex('ee82ee');
+ static final Color wheat = const Color.hex('f5deb3');
+ static final Color white = const Color.hex('ffffff');
+ static final Color whiteSmoke = const Color.hex('f5f5f5');
+ static final Color yellow = const Color.hex('ffff00');
+ static final Color yellowGreen = const Color.hex('9acd32');
+}
+
+/// Rgba class for users that want to interact with a color as a RGBA value.
+class Rgba implements _StyleProperty, ColorBase {
+ // TODO(terry): Consider consolidating rgba to a single 32-bit int, make sure
+ // it works under JS and Dart VM.
+ final int r;
+ final int g;
+ final int b;
+ final num? a;
+
+ Rgba(int red, int green, int blue, [num? alpha])
+ : r = Color._clamp(red, 0, 255),
+ g = Color._clamp(green, 0, 255),
+ b = Color._clamp(blue, 0, 255),
+ a = (alpha != null) ? Color._clamp(alpha, 0, 1) : alpha;
+
+ factory Rgba.fromString(String hexValue) =>
+ Color.css('#${Color._convertCssToArgb(hexValue)}').rgba;
+
+ factory Rgba.fromColor(Color color) => color.rgba;
+
+ factory Rgba.fromArgbValue(num value) => Rgba(
+ (value.toInt() & 0xff000000) >> 0x18, // a
+ (value.toInt() & 0xff0000) >> 0x10, // r
+ (value.toInt() & 0xff00) >> 8, // g
+ value.toInt() & 0xff,
+ ); // b
+
+ factory Rgba.fromHsla(Hsla hsla) {
+ // Convert to Rgba.
+ // See site <http://easyrgb.com/index.php?X=MATH> for good documentation
+ // and color conversion routines.
+
+ var h = hsla.hue;
+ var s = hsla.saturation;
+ var l = hsla.lightness;
+ var a = hsla.alpha;
+
+ int r;
+ int g;
+ int b;
+
+ if (s == 0) {
+ r = (l * 255).round().toInt();
+ g = r;
+ b = r;
+ } else {
+ num var2;
+
+ if (l < 0.5) {
+ var2 = l * (1 + s);
+ } else {
+ var2 = (l + s) - (s * l);
+ }
+ var var1 = 2 * l - var2;
+
+ r = (255 * Rgba._hueToRGB(var1, var2, h + (1 / 3))).round().toInt();
+ g = (255 * Rgba._hueToRGB(var1, var2, h)).round().toInt();
+ b = (255 * Rgba._hueToRGB(var1, var2, h - (1 / 3))).round().toInt();
+ }
+
+ return Rgba(r, g, b, a);
+ }
+
+ static num _hueToRGB(num v1, num v2, num vH) {
+ if (vH < 0) {
+ vH += 1;
+ }
+
+ if (vH > 1) {
+ vH -= 1;
+ }
+
+ if ((6 * vH) < 1) {
+ return v1 + (v2 - v1) * 6 * vH;
+ }
+
+ if ((2 * vH) < 1) {
+ return v2;
+ }
+
+ if ((3 * vH) < 2) {
+ return v1 + (v2 - v1) * ((2 / 3 - vH) * 6);
+ }
+
+ return v1;
+ }
+
+ @override
+ bool operator ==(Object other) => Color.equal(this, other);
+
+ @override
+ String get cssExpression {
+ if (a == null) {
+ return '#${Color.convertToHexString(r, g, b)}';
+ } else {
+ return 'rgba($r,$g,$b,$a)';
+ }
+ }
+
+ @override
+ String toHexArgbString() => Color.convertToHexString(r, g, b, a);
+
+ @override
+ int get argbValue {
+ var value = 0;
+ if (a != null) {
+ value = a!.toInt() << 0x18;
+ }
+ value += r << 0x10;
+ value += g << 0x08;
+ value += b;
+ return value;
+ }
+
+ Color get color => Color.createRgba(r, g, b, a);
+ Hsla get hsla => Hsla.fromRgba(this);
+
+ Rgba darker(num amount) => Color._createNewTintShadeFromRgba(this, -amount);
+ Rgba lighter(num amount) => Color._createNewTintShadeFromRgba(this, amount);
+
+ @override
+ int get hashCode => toHexArgbString().hashCode;
+}
+
+/// Hsl class support to interact with a color as a hsl with hue, saturation,
+/// and lightness with optional alpha blending. The hue is a ratio of 360
+/// degrees 360° = 1 or 0, (1° == (1/360)), saturation and lightness is a 0..1
+/// fraction (1 == 100%) and alpha is a 0..1 fraction.
+class Hsla implements _StyleProperty, ColorBase {
+ final num _h; // Value from 0..1
+ final num _s; // Value from 0..1
+ final num _l; // Value from 0..1
+ final num? _a; // Value from 0..1
+
+ /// [hue] is a 0..1 fraction of 360 degrees (360 == 0).
+ /// [saturation] is a 0..1 fraction (100% == 1).
+ /// [lightness] is a 0..1 fraction (100% == 1).
+ /// [alpha] is a 0..1 fraction, alpha blending between 0..1, 1 == 100% opaque.
+ Hsla(num hue, num saturation, num lightness, [num? alpha])
+ : _h = (hue == 1) ? 0 : Color._clamp(hue, 0, 1),
+ _s = Color._clamp(saturation, 0, 1),
+ _l = Color._clamp(lightness, 0, 1),
+ _a = (alpha != null) ? Color._clamp(alpha, 0, 1) : alpha;
+
+ factory Hsla.fromString(String hexValue) {
+ var rgba = Color.css('#${Color._convertCssToArgb(hexValue)}').rgba;
+ return _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a);
+ }
+
+ factory Hsla.fromColor(Color color) {
+ var rgba = color.rgba;
+ return _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a);
+ }
+
+ factory Hsla.fromArgbValue(num value) {
+ num a = (value.toInt() & 0xff000000) >> 0x18;
+ var r = (value.toInt() & 0xff0000) >> 0x10;
+ var g = (value.toInt() & 0xff00) >> 8;
+ var b = value.toInt() & 0xff;
+
+ // Convert alpha to 0..1 from (0..255).
+ a = double.parse((a / 255).toStringAsPrecision(2));
+
+ return _createFromRgba(r, g, b, a);
+ }
+
+ factory Hsla.fromRgba(Rgba rgba) =>
+ _createFromRgba(rgba.r, rgba.g, rgba.b, rgba.a);
+
+ static Hsla _createFromRgba(num r, num g, num b, num? a) {
+ // Convert RGB to hsl.
+ // See site <http://easyrgb.com/index.php?X=MATH> for good documentation
+ // and color conversion routines.
+ r /= 255;
+ g /= 255;
+ b /= 255;
+
+ // Hue, saturation and lightness.
+ num h;
+ num s;
+ num l;
+
+ var minRgb = math.min(r, math.min(g, b));
+ var maxRgb = math.max(r, math.max(g, b));
+ l = (maxRgb + minRgb) / 2;
+ if (l <= 0) {
+ return Hsla(0, 0, l); // Black;
+ }
+
+ var vm = maxRgb - minRgb;
+ s = vm;
+ if (s > 0) {
+ s /= (l < 0.5) ? (maxRgb + minRgb) : (2 - maxRgb - minRgb);
+ } else {
+ return Hsla(0, 0, l); // White
+ }
+
+ num r2, g2, b2;
+ r2 = (maxRgb - r) / vm;
+ g2 = (maxRgb - g) / vm;
+ b2 = (maxRgb - b) / vm;
+ if (r == maxRgb) {
+ h = (g == minRgb) ? 5.0 + b2 : 1 - g2;
+ } else if (g == maxRgb) {
+ h = (b == minRgb) ? 1 + r2 : 3 - b2;
+ } else {
+ h = (r == minRgb) ? 3 + g2 : 5 - r2;
+ }
+ h /= 6;
+
+ return Hsla(h, s, l, a);
+ }
+
+ /// Returns 0..1 fraction (ratio of 360°, e.g. 1° == 1/360).
+ num get hue => _h;
+
+ /// Returns 0..1 fraction (1 == 100%)
+ num get saturation => _s;
+
+ /// Returns 0..1 fraction (1 == 100%).
+ num get lightness => _l;
+
+ /// Returns number as degrees 0..360.
+ num get hueDegrees => (_h * 360).round();
+
+ /// Returns number as percentage 0..100
+ num get saturationPercentage => (_s * 100).round();
+
+ /// Returns number as percentage 0..100.
+ num get lightnessPercentage => (_l * 100).round();
+
+ /// Returns number as 0..1
+ num? get alpha => _a;
+
+ @override
+ bool operator ==(Object other) => Color.equal(this, other);
+
+ @override
+ String get cssExpression => (_a == null)
+ ? 'hsl($hueDegrees,$saturationPercentage,$lightnessPercentage)'
+ : 'hsla($hueDegrees,$saturationPercentage,$lightnessPercentage,$_a)';
+
+ @override
+ String toHexArgbString() => Rgba.fromHsla(this).toHexArgbString();
+
+ @override
+ int get argbValue => Color.hexToInt(toHexArgbString());
+
+ Color get color => Color.createHsla(_h, _s, _l, _a);
+ Rgba get rgba => Rgba.fromHsla(this);
+
+ Hsla darker(num amount) => Hsla.fromRgba(Rgba.fromHsla(this).darker(amount));
+
+ Hsla lighter(num amount) =>
+ Hsla.fromRgba(Rgba.fromHsla(this).lighter(amount));
+
+ @override
+ int get hashCode => toHexArgbString().hashCode;
+}
+
+/// X,Y position.
+class PointXY implements _StyleProperty {
+ final num x, y;
+ const PointXY(this.x, this.y);
+
+ @override
+ String? get cssExpression =>
+ // TODO(terry): TBD
+ null;
+}
+
+// TODO(terry): Implement style and color.
+/// Supports border for measuring with layout.
+class Border implements _StyleProperty {
+ final int? top, left, bottom, right;
+
+ // TODO(terry): Just like CSS, 1-arg -> set all properties, 2-args -> top and
+ // bottom are first arg, left and right are second, 3-args, and
+ // 4-args -> tlbr or trbl.
+ const Border([this.top, this.left, this.bottom, this.right]);
+
+ // TODO(terry): Consider using Size or width and height.
+ Border.uniform(int amount)
+ : top = amount,
+ left = amount,
+ bottom = amount,
+ right = amount;
+
+ int get width => left! + right!;
+ int get height => top! + bottom!;
+
+ @override
+ String get cssExpression => (top == left && bottom == right && top == right)
+ ? '${left}px'
+ : "${top != null ? '$top' : '0'}px "
+ "${right != null ? '$right' : '0'}px "
+ "${bottom != null ? '$bottom' : '0'}px "
+ "${left != null ? '$left' : '0'}px";
+}
+
+/// Font style constants.
+class FontStyle {
+ /// Font style [normal] default.
+ static const String normal = 'normal';
+
+ /// Font style [italic] use explicity crafted italic font otherwise inclined
+ /// on the fly like oblique.
+ static const String italic = 'italic';
+
+ /// Font style [oblique] is rarely used. The normal style of a font is
+ /// inclined on the fly to the right by 8-12 degrees.
+ static const String oblique = 'oblique';
+}
+
+/// Font variant constants.
+class FontVariant {
+ /// Font style [normal] default.
+ static const String normal = 'normal';
+
+ /// Font variant [smallCaps].
+ static const String smallCaps = 'small-caps';
+}
+
+/// Font weight constants values 100, 200, 300, 400, 500, 600, 700, 800, 900.
+class FontWeight {
+ /// Font weight normal [default]
+ static const int normal = 400;
+
+ /// Font weight bold
+ static const int bold = 700;
+
+ static const int wt100 = 100;
+ static const int wt200 = 200;
+ static const int wt300 = 300;
+ static const int wt400 = 400;
+ static const int wt500 = 500;
+ static const int wt600 = 600;
+ static const int wt700 = 700;
+ static const int wt800 = 800;
+ static const int wt900 = 900;
+}
+
+/// Generic font family names.
+class FontGeneric {
+ /// Generic family sans-serif font (w/o serifs).
+ static const String sansSerif = 'sans-serif';
+
+ /// Generic family serif font.
+ static const String serif = 'serif';
+
+ /// Generic family fixed-width font.
+ static const monospace = 'monospace';
+
+ /// Generic family emulate handwriting font.
+ static const String cursive = 'cursive';
+
+ /// Generic family decorative font.
+ static const String fantasy = 'fantasy';
+}
+
+/// List of most common font families across different platforms. Use the
+/// collection names in the Font class (e.g., Font.SANS_SERIF, Font.FONT_SERIF,
+/// Font.MONOSPACE, Font.CURSIVE or Font.FANTASY). These work best on all
+/// platforms using the fonts that best match availability on each platform.
+/// See <http://www.angelfire.com/al4/rcollins/style/fonts.html> for a good
+/// description of fonts available between platforms and browsers.
+class FontFamily {
+ /// Sans-Serif font for Windows similar to Helvetica on Mac bold/italic.
+ static const String arial = 'arial';
+
+ /// Sans-Serif font for Windows less common already bolded.
+ static const String arialBlack = 'arial black';
+
+ /// Sans-Serif font for Mac since 1984, similar to Arial/Helvetica.
+ static const String geneva = 'geneva';
+
+ /// Sans-Serif font for Windows most readable sans-serif font for displays.
+ static const String verdana = 'verdana';
+
+ /// Sans-Serif font for Mac since 1984 is identical to Arial.
+ static const String helvetica = 'helvetica';
+
+ /// Serif font for Windows traditional font with “old-style” numerals.
+ static const String georgia = 'georgia';
+
+ /// Serif font for Mac. PCs may have the non-scalable Times use Times New
+ /// Roman instead. Times is more compact than Times New Roman.
+ static const String times = 'times';
+
+ /// Serif font for Windows most common serif font and default serif font for
+ /// most browsers.
+ static const String timesNewRoman = 'times new roman';
+
+ /// Monospace font for Mac/Windows most common. Scalable on Mac not scalable
+ /// on Windows.
+ static const String courier = 'courier';
+
+ /// Monospace font for Mac/Windows scalable on both platforms.
+ static const String courierNew = 'courier new';
+
+ /// Cursive font for Windows and default cursive font for IE.
+ static const String comicSansMs = 'comic sans ms';
+
+ /// Cursive font for Mac on Macs 2000 and newer.
+ static const String textile = 'textile';
+
+ /// Cursive font for older Macs.
+ static const String appleChancery = 'apple chancery';
+
+ /// Cursive font for some PCs.
+ static const String zaphChancery = 'zaph chancery';
+
+ /// Fantasy font on most Mac/Windows/Linux platforms.
+ static const String impact = 'impact';
+
+ /// Fantasy font for Windows.
+ static const String webdings = 'webdings';
+}
+
+class LineHeight {
+ final num height;
+ final bool inPixels;
+ const LineHeight(this.height, {this.inPixels = true});
+}
+
+// TODO(terry): Support @font-face fule.
+/// Font style support for size, family, weight, style, variant, and lineheight.
+class Font implements _StyleProperty {
+ /// Collection of most common sans-serif fonts in order.
+ static const List<String> sansSerif = [
+ FontFamily.arial,
+ FontFamily.verdana,
+ FontFamily.geneva,
+ FontFamily.helvetica,
+ FontGeneric.sansSerif
+ ];
+
+ /// Collection of most common serif fonts in order.
+ static const List<String> serif = [
+ FontFamily.georgia,
+ FontFamily.timesNewRoman,
+ FontFamily.times,
+ FontGeneric.serif
+ ];
+
+ /// Collection of most common monospace fonts in order.
+ static const List<String> monospace = [
+ FontFamily.courierNew,
+ FontFamily.courier,
+ FontGeneric.monospace
+ ];
+
+ /// Collection of most common cursive fonts in order.
+ static const List<String> cursive = [
+ FontFamily.textile,
+ FontFamily.appleChancery,
+ FontFamily.zaphChancery,
+ FontGeneric.fantasy
+ ];
+
+ /// Collection of most common fantasy fonts in order.
+ static const List<String> fantasy = [
+ FontFamily.comicSansMs,
+ FontFamily.impact,
+ FontFamily.webdings,
+ FontGeneric.fantasy
+ ];
+
+ // TODO(terry): Should support the values xx-small, small, large, xx-large,
+ // etc. (mapped to a pixel sized font)?
+ /// Font size in pixels.
+ final num? size;
+
+ // TODO(terry): _family should be an immutable list, wrapper class to do this
+ // should exist in Dart.
+ /// Family specifies a list of fonts, the browser will sequentially select the
+ /// the first known/supported font. There are two types of font families the
+ /// family-name (e.g., arial, times, courier, etc) or the generic-family
+ /// (e.g., serif, sans-seric, etc.)
+ final List<String>? family;
+
+ /// Font weight from 100, 200, 300, 400, 500, 600, 700, 800, 900
+ final int? weight;
+
+ /// Style of a font normal, italic, oblique.
+ final String? style;
+
+ /// Font variant NORMAL (default) or SMALL_CAPS. Different set of font glyph
+ /// lower case letters designed to have to fit within the font-height and
+ /// weight of the corresponding lowercase letters.
+ final String? variant;
+
+ final LineHeight? lineHeight;
+
+ // TODO(terry): Size and computedLineHeight are in pixels. Need to figure out
+ // how to handle in other units (specified in other units) like
+ // points, inches, etc. Do we have helpers like Units.Points(12)
+ // where 12 is in points and that's converted to pixels?
+ // TODO(terry): lineHeight is computed as 1.2 although CSS_RESET is 1.0 we
+ // need to be consistent some browsers use 1 others 1.2.
+ // TODO(terry): There is a school of thought "Golden Ratio Typography".
+ // Where width to display the text is also important in computing the line
+ // height. Classic typography suggest the ratio be 1.5. See
+ // <http://www.pearsonified.com/2011/12/golden-ratio-typography.php> and
+ // <http://meyerweb.com/eric/thoughts/2008/05/06/line-height-abnormal/>.
+ /// Create a font using [size] of font in pixels, [family] name of font(s)
+ /// using [FontFamily], [style] of the font using [FontStyle], [variant] using
+ /// [FontVariant], and [lineHeight] extra space (leading) around the font in
+ /// pixels, if not specified it's 1.2 the font size.
+ const Font(
+ {this.size,
+ this.family,
+ this.weight,
+ this.style,
+ this.variant,
+ this.lineHeight});
+
+ /// Merge the two fonts and return the result. See [Style.merge] for
+ /// more information.
+ static Font? merge(Font? a, Font? b) {
+ if (a == null) return b;
+ if (b == null) return a;
+ return Font._merge(a, b);
+ }
+
+ Font._merge(Font a, Font b)
+ : size = _mergeVal(a.size, b.size),
+ family = _mergeVal(a.family, b.family),
+ weight = _mergeVal(a.weight, b.weight),
+ style = _mergeVal(a.style, b.style),
+ variant = _mergeVal(a.variant, b.variant),
+ lineHeight = _mergeVal(a.lineHeight, b.lineHeight);
+
+ /// Shorthand CSS format for font is:
+ ///
+ /// font-style font-variant font-weight font-size/line-height font-family
+ ///
+ /// The font-size and font-family values are required. If any of the other
+ /// values are missing the default value is used.
+ @override
+ String get cssExpression {
+ // TODO(jimhug): include variant, style, other options
+ if (weight != null) {
+ // TODO(jacobr): is this really correct for lineHeight?
+ if (lineHeight != null) {
+ return '$weight ${size}px/$lineHeightInPixels $_fontsAsString';
+ }
+ return '$weight ${size}px $_fontsAsString';
+ }
+
+ return '${size}px $_fontsAsString';
+ }
+
+ Font scale(num ratio) => Font(
+ size: size! * ratio,
+ family: family,
+ weight: weight,
+ style: style,
+ variant: variant);
+
+ /// The lineHeight, provides an indirect means to specify the leading. The
+ /// leading is the difference between the font-size height and the (used)
+ /// value of line height in pixels. If lineHeight is not specified it's
+ /// automatically computed as 1.2 of the font size. Firefox is 1.2, Safari is
+ /// ~1.2, and CSS suggest a ration from 1 to 1.2 of the font-size when
+ /// computing line-height. The Font class constructor has the computation for
+ /// _lineHeight.
+ num? get lineHeightInPixels {
+ if (lineHeight != null) {
+ if (lineHeight!.inPixels) {
+ return lineHeight!.height;
+ } else {
+ return (size != null) ? lineHeight!.height * size! : null;
+ }
+ } else {
+ return (size != null) ? size! * 1.2 : null;
+ }
+ }
+
+ @override
+ int get hashCode =>
+ // TODO(jimhug): Lot's of potential collisions here. List of fonts, etc.
+ size!.toInt() % family![0].hashCode;
+
+ @override
+ bool operator ==(Object other) {
+ if (other is! Font) return false;
+ return other.size == size &&
+ other.family == family &&
+ other.weight == weight &&
+ other.lineHeight == lineHeight &&
+ other.style == style &&
+ other.variant == variant;
+ }
+
+ // TODO(terry): This is fragile should probably just iterate through the list
+ // of fonts construction the font-family string.
+ /// Return fonts as a comma seperated list sans the square brackets.
+ String get _fontsAsString {
+ var fonts = family.toString();
+ return fonts.length > 2 ? fonts.substring(1, fonts.length - 1) : '';
+ }
+}
+
+/// This class stores the sizes of the box edges in the CSS [box model][]. Each
+/// edge area is placed around the sides of the content box. The innermost area
+/// is the [Style.padding] area which has a background and surrounds the
+/// content. The content and padding area is surrounded by the [Style.border],
+/// which itself is surrounded by the transparent [Style.margin]. This box
+/// represents the eges of padding, border, or margin depending on which
+/// accessor was used to retrieve it.
+///
+/// [box model]: https://developer.mozilla.org/en/CSS/box_model
+class BoxEdge {
+ /// The size of the left edge, or null if the style has no edge.
+ final num? left;
+
+ /// The size of the top edge, or null if the style has no edge.
+ final num? top;
+
+ /// The size of the right edge, or null if the style has no edge.
+ final num? right;
+
+ /// The size of the bottom edge, or null if the style has no edge.
+ final num? bottom;
+
+ /// Creates a box edge with the specified [left], [top], [right], and
+ /// [bottom] width.
+ const BoxEdge([this.left, this.top, this.right, this.bottom]);
+
+ /// Creates a box edge with the specified [top], [right], [bottom], and
+ /// [left] width. This matches the typical CSS order:
+ /// <https://developer.mozilla.org/en/CSS/margin>
+ /// <https://developer.mozilla.org/en/CSS/border-width>
+ /// <https://developer.mozilla.org/en/CSS/padding>.
+ const BoxEdge.clockwiseFromTop(this.top, this.right, this.bottom, this.left);
+
+ /// This is a helper to creates a box edge with the same [left], [top]
+ /// [right], and [bottom] widths.
+ const BoxEdge.uniform(num size)
+ : top = size,
+ left = size,
+ bottom = size,
+ right = size;
+
+ /// Takes a possibly null box edge, with possibly null metrics, and fills
+ /// them in with 0 instead.
+ factory BoxEdge.nonNull(BoxEdge? other) {
+ if (other == null) return const BoxEdge(0, 0, 0, 0);
+ var left = other.left;
+ var top = other.top;
+ var right = other.right;
+ var bottom = other.bottom;
+ var make = false;
+ if (left == null) {
+ make = true;
+ left = 0;
+ }
+ if (top == null) {
+ make = true;
+ top = 0;
+ }
+ if (right == null) {
+ make = true;
+ right = 0;
+ }
+ if (bottom == null) {
+ make = true;
+ bottom = 0;
+ }
+ return make ? BoxEdge(left, top, right, bottom) : other;
+ }
+
+ /// Merge the two box edge sizes and return the result. See [Style.merge] for
+ /// more information.
+ static BoxEdge? merge(BoxEdge? x, BoxEdge? y) {
+ if (x == null) return y;
+ if (y == null) return x;
+ return BoxEdge._merge(x, y);
+ }
+
+ BoxEdge._merge(BoxEdge x, BoxEdge y)
+ : left = _mergeVal(x.left, y.left),
+ top = _mergeVal(x.top, y.top),
+ right = _mergeVal(x.right, y.right),
+ bottom = _mergeVal(x.bottom, y.bottom);
+
+ /// The total size of the horizontal edges. Equal to [left] + [right], where
+ /// null is interpreted as 0px.
+ num get width => (left ?? 0) + (right ?? 0);
+
+ /// The total size of the vertical edges. Equal to [top] + [bottom], where
+ /// null is interpreted as 0px.
+ num get height => (top ?? 0) + (bottom ?? 0);
+}
+
+T _mergeVal<T>(T x, T y) => y ?? x;
diff --git a/pkgs/csslib/lib/src/token.dart b/pkgs/csslib/lib/src/token.dart
new file mode 100644
index 0000000..5a07535
--- /dev/null
+++ b/pkgs/csslib/lib/src/token.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../parser.dart';
+
+/// A single token in the Dart language.
+class Token {
+ /// A member of [TokenKind] specifying what kind of token this is.
+ final int kind;
+
+ /// The location where this token was parsed from.
+ final FileSpan span;
+
+ /// The start offset of this token.
+ int get start => span.start.offset;
+
+ /// The end offset of this token.
+ int get end => span.end.offset;
+
+ /// Returns the source text corresponding to this [Token].
+ String get text => span.text;
+
+ Token(this.kind, this.span);
+
+ /// Returns a pretty representation of this token for error messages.
+ @override
+ String toString() {
+ var kindText = TokenKind.kindToString(kind);
+ var actualText = text.trim();
+ if (actualText.isNotEmpty && kindText != actualText) {
+ if (actualText.length > 10) {
+ actualText = '${actualText.substring(0, 8)}...';
+ }
+ return '$kindText($actualText)';
+ } else {
+ return kindText;
+ }
+ }
+}
+
+/// A token containing a parsed literal value.
+class LiteralToken extends Token {
+ dynamic value;
+ LiteralToken(super.kind, super.span, this.value);
+}
+
+/// A token containing error information.
+class ErrorToken extends Token {
+ String? message;
+ ErrorToken(super.kind, super.span, this.message);
+}
+
+/// CSS ident-token.
+///
+/// See <http://dev.w3.org/csswg/css-syntax/#typedef-ident-token> and
+/// <http://dev.w3.org/csswg/css-syntax/#ident-token-diagram>.
+class IdentifierToken extends Token {
+ @override
+ final String text;
+
+ IdentifierToken(this.text, int kind, FileSpan span) : super(kind, span);
+}
diff --git a/pkgs/csslib/lib/src/token_kind.dart b/pkgs/csslib/lib/src/token_kind.dart
new file mode 100644
index 0000000..3f50402
--- /dev/null
+++ b/pkgs/csslib/lib/src/token_kind.dart
@@ -0,0 +1,728 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: constant_identifier_names
+
+part of '../parser.dart';
+
+// TODO(terry): Need to be consistent with tokens either they're ASCII tokens
+// e.g., ASTERISK or they're CSS e.g., PSEUDO, COMBINATOR_*.
+class TokenKind {
+ // Common shared tokens used in TokenizerBase.
+ static const int UNUSED = 0; // Unused place holder...
+ static const int END_OF_FILE = 1; // EOF
+ static const int LPAREN = 2; // (
+ static const int RPAREN = 3; // )
+ static const int LBRACK = 4; // [
+ static const int RBRACK = 5; // ]
+ static const int LBRACE = 6; // {
+ static const int RBRACE = 7; // }
+ static const int DOT = 8; // .
+ static const int SEMICOLON = 9; // ;
+
+ // Unique tokens for CSS.
+ static const int AT = 10; // @
+ static const int HASH = 11; // #
+ static const int PLUS = 12; // +
+ static const int GREATER = 13; // >
+ static const int TILDE = 14; // ~
+ static const int ASTERISK = 15; // *
+ static const int NAMESPACE = 16; // |
+ static const int COLON = 17; // :
+ static const int PRIVATE_NAME = 18; // _ prefix private class or id
+ static const int COMMA = 19; // ,
+ static const int SPACE = 20;
+ static const int TAB = 21; // /t
+ static const int NEWLINE = 22; // /n
+ static const int RETURN = 23; // /r
+ static const int PERCENT = 24; // %
+ static const int SINGLE_QUOTE = 25; // '
+ static const int DOUBLE_QUOTE = 26; // "
+ static const int SLASH = 27; // /
+ static const int EQUALS = 28; // =
+ static const int CARET = 30; // ^
+ static const int DOLLAR = 31; // $
+ static const int LESS = 32; // <
+ static const int BANG = 33; // !
+ static const int MINUS = 34; // -
+ static const int BACKSLASH = 35; // \
+ static const int AMPERSAND = 36; // &
+
+ // WARNING: Tokens from this point and above must have the corresponding ASCII
+ // character in the TokenChar list at the bottom of this file. The
+ // order of the above tokens should be the same order as TokenChar.
+
+ /// [TokenKind] representing integer tokens.
+ static const int INTEGER = 60;
+
+ /// [TokenKind] representing hex integer tokens.
+ static const int HEX_INTEGER = 61;
+
+ /// [TokenKind] representing double tokens.
+ static const int DOUBLE = 62;
+
+ /// [TokenKind] representing whitespace tokens.
+ static const int WHITESPACE = 63;
+
+ /// [TokenKind] representing comment tokens.
+ static const int COMMENT = 64;
+
+ /// [TokenKind] representing error tokens.
+ static const int ERROR = 65;
+
+ /// [TokenKind] representing incomplete string tokens.
+ static const int INCOMPLETE_STRING = 66;
+
+ /// [TokenKind] representing incomplete comment tokens.
+ static const int INCOMPLETE_COMMENT = 67;
+
+ static const int VAR_DEFINITION = 400; // var-NNN-NNN
+ static const int VAR_USAGE = 401; // var(NNN-NNN [,default])
+
+ // Synthesized Tokens (no character associated with TOKEN).
+ static const int STRING = 500;
+ static const int STRING_PART = 501;
+ static const int NUMBER = 502;
+ static const int HEX_NUMBER = 503;
+ static const int HTML_COMMENT = 504; // <!--
+ static const int IMPORTANT = 505; // !important
+ static const int CDATA_START = 506; // <![CDATA[
+ static const int CDATA_END = 507; // ]]>
+ // U+uNumber[-U+uNumber]
+ // uNumber = 0..10FFFF | ?[?]*
+ static const int UNICODE_RANGE = 508;
+ static const int HEX_RANGE = 509; // ? in the hex range
+ static const int IDENTIFIER = 511;
+
+ // Uniquely synthesized tokens for CSS.
+ static const int SELECTOR_EXPRESSION = 512;
+ static const int COMBINATOR_NONE = 513;
+ static const int COMBINATOR_DESCENDANT = 514; // Space combinator
+ static const int COMBINATOR_PLUS = 515; // + combinator
+ static const int COMBINATOR_GREATER = 516; // > combinator
+ static const int COMBINATOR_TILDE = 517; // ~ combinator
+
+ static const int UNARY_OP_NONE = 518; // No unary operator present.
+
+ // Attribute match types:
+ static const int INCLUDES = 530; // '~='
+ static const int DASH_MATCH = 531; // '|='
+ static const int PREFIX_MATCH = 532; // '^='
+ static const int SUFFIX_MATCH = 533; // '$='
+ static const int SUBSTRING_MATCH = 534; // '*='
+ static const int NO_MATCH = 535; // No operator.
+
+ // Unit types:
+ static const int UNIT_EM = 600;
+ static const int UNIT_EX = 601;
+ static const int UNIT_LENGTH_PX = 602;
+ static const int UNIT_LENGTH_CM = 603;
+ static const int UNIT_LENGTH_MM = 604;
+ static const int UNIT_LENGTH_IN = 605;
+ static const int UNIT_LENGTH_PT = 606;
+ static const int UNIT_LENGTH_PC = 607;
+ static const int UNIT_ANGLE_DEG = 608;
+ static const int UNIT_ANGLE_RAD = 609;
+ static const int UNIT_ANGLE_GRAD = 610;
+ static const int UNIT_ANGLE_TURN = 611;
+ static const int UNIT_TIME_MS = 612;
+ static const int UNIT_TIME_S = 613;
+ static const int UNIT_FREQ_HZ = 614;
+ static const int UNIT_FREQ_KHZ = 615;
+ static const int UNIT_PERCENT = 616;
+ static const int UNIT_FRACTION = 617;
+ static const int UNIT_RESOLUTION_DPI = 618;
+ static const int UNIT_RESOLUTION_DPCM = 619;
+ static const int UNIT_RESOLUTION_DPPX = 620;
+ static const int UNIT_CH = 621; // Measure of "0" U+0030 glyph.
+ static const int UNIT_REM = 622; // computed value ‘font-size’ on root elem.
+ static const int UNIT_VIEWPORT_VW = 623;
+ static const int UNIT_VIEWPORT_VH = 624;
+ static const int UNIT_VIEWPORT_VMIN = 625;
+ static const int UNIT_VIEWPORT_VMAX = 626;
+ static const int UNIT_LH = 627; // Computed height of the element.
+ static const int UNIT_RLH = 628; // Line height of the root element.
+
+ // Directives (@nnnn)
+ static const int DIRECTIVE_NONE = 640;
+ static const int DIRECTIVE_IMPORT = 641;
+ static const int DIRECTIVE_MEDIA = 642;
+ static const int DIRECTIVE_PAGE = 643;
+ static const int DIRECTIVE_CHARSET = 644;
+ static const int DIRECTIVE_STYLET = 645;
+ static const int DIRECTIVE_KEYFRAMES = 646;
+ static const int DIRECTIVE_WEB_KIT_KEYFRAMES = 647;
+ static const int DIRECTIVE_MOZ_KEYFRAMES = 648;
+ static const int DIRECTIVE_MS_KEYFRAMES = 649;
+ static const int DIRECTIVE_O_KEYFRAMES = 650;
+ static const int DIRECTIVE_FONTFACE = 651;
+ static const int DIRECTIVE_NAMESPACE = 652;
+ static const int DIRECTIVE_HOST = 653;
+ static const int DIRECTIVE_MIXIN = 654;
+ static const int DIRECTIVE_INCLUDE = 655;
+ static const int DIRECTIVE_CONTENT = 656;
+ static const int DIRECTIVE_EXTEND = 657;
+ static const int DIRECTIVE_MOZ_DOCUMENT = 658;
+ static const int DIRECTIVE_SUPPORTS = 659;
+ static const int DIRECTIVE_VIEWPORT = 660;
+ static const int DIRECTIVE_MS_VIEWPORT = 661;
+
+ // Media query operators
+ static const int MEDIA_OP_ONLY = 665; // Unary.
+ static const int MEDIA_OP_NOT = 666; // Unary.
+ static const int MEDIA_OP_AND = 667; // Binary.
+
+ // Directives inside of a @page (margin sym).
+ static const int MARGIN_DIRECTIVE_TOPLEFTCORNER = 670;
+ static const int MARGIN_DIRECTIVE_TOPLEFT = 671;
+ static const int MARGIN_DIRECTIVE_TOPCENTER = 672;
+ static const int MARGIN_DIRECTIVE_TOPRIGHT = 673;
+ static const int MARGIN_DIRECTIVE_TOPRIGHTCORNER = 674;
+ static const int MARGIN_DIRECTIVE_BOTTOMLEFTCORNER = 675;
+ static const int MARGIN_DIRECTIVE_BOTTOMLEFT = 676;
+ static const int MARGIN_DIRECTIVE_BOTTOMCENTER = 677;
+ static const int MARGIN_DIRECTIVE_BOTTOMRIGHT = 678;
+ static const int MARGIN_DIRECTIVE_BOTTOMRIGHTCORNER = 679;
+ static const int MARGIN_DIRECTIVE_LEFTTOP = 680;
+ static const int MARGIN_DIRECTIVE_LEFTMIDDLE = 681;
+ static const int MARGIN_DIRECTIVE_LEFTBOTTOM = 682;
+ static const int MARGIN_DIRECTIVE_RIGHTTOP = 683;
+ static const int MARGIN_DIRECTIVE_RIGHTMIDDLE = 684;
+ static const int MARGIN_DIRECTIVE_RIGHTBOTTOM = 685;
+
+ // Simple selector type.
+ // TODO: These are unused and should be removed in a future version.
+ static const int CLASS_NAME = 700; // .class
+ static const int ELEMENT_NAME = 701; // tagName
+ static const int HASH_NAME = 702; // #elementId
+ static const int ATTRIBUTE_NAME = 703; // [attrib]
+ static const int PSEUDO_ELEMENT_NAME = 704; // ::pseudoElement
+ static const int PSEUDO_CLASS_NAME = 705; // :pseudoClass
+ static const int NEGATION = 706; // NOT
+
+ static const List<Map<String, Object>> _DIRECTIVES = [
+ {'type': TokenKind.DIRECTIVE_IMPORT, 'value': 'import'},
+ {'type': TokenKind.DIRECTIVE_MEDIA, 'value': 'media'},
+ {'type': TokenKind.DIRECTIVE_PAGE, 'value': 'page'},
+ {'type': TokenKind.DIRECTIVE_CHARSET, 'value': 'charset'},
+ {'type': TokenKind.DIRECTIVE_STYLET, 'value': 'stylet'},
+ {'type': TokenKind.DIRECTIVE_KEYFRAMES, 'value': 'keyframes'},
+ {
+ 'type': TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES,
+ 'value': '-webkit-keyframes'
+ },
+ {'type': TokenKind.DIRECTIVE_MOZ_KEYFRAMES, 'value': '-moz-keyframes'},
+ {'type': TokenKind.DIRECTIVE_MS_KEYFRAMES, 'value': '-ms-keyframes'},
+ {'type': TokenKind.DIRECTIVE_O_KEYFRAMES, 'value': '-o-keyframes'},
+ {'type': TokenKind.DIRECTIVE_FONTFACE, 'value': 'font-face'},
+ {'type': TokenKind.DIRECTIVE_NAMESPACE, 'value': 'namespace'},
+ {'type': TokenKind.DIRECTIVE_HOST, 'value': 'host'},
+ {'type': TokenKind.DIRECTIVE_MIXIN, 'value': 'mixin'},
+ {'type': TokenKind.DIRECTIVE_INCLUDE, 'value': 'include'},
+ {'type': TokenKind.DIRECTIVE_CONTENT, 'value': 'content'},
+ {'type': TokenKind.DIRECTIVE_EXTEND, 'value': 'extend'},
+ {'type': TokenKind.DIRECTIVE_MOZ_DOCUMENT, 'value': '-moz-document'},
+ {'type': TokenKind.DIRECTIVE_SUPPORTS, 'value': 'supports'},
+ {'type': TokenKind.DIRECTIVE_VIEWPORT, 'value': 'viewport'},
+ {'type': TokenKind.DIRECTIVE_MS_VIEWPORT, 'value': '-ms-viewport'},
+ ];
+
+ static const List<Map<String, Object>> MEDIA_OPERATORS = [
+ {'type': TokenKind.MEDIA_OP_ONLY, 'value': 'only'},
+ {'type': TokenKind.MEDIA_OP_NOT, 'value': 'not'},
+ {'type': TokenKind.MEDIA_OP_AND, 'value': 'and'},
+ ];
+
+ static const List<Map<String, Object>> MARGIN_DIRECTIVES = [
+ {
+ 'type': TokenKind.MARGIN_DIRECTIVE_TOPLEFTCORNER,
+ 'value': 'top-left-corner'
+ },
+ {'type': TokenKind.MARGIN_DIRECTIVE_TOPLEFT, 'value': 'top-left'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_TOPCENTER, 'value': 'top-center'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_TOPRIGHT, 'value': 'top-right'},
+ {
+ 'type': TokenKind.MARGIN_DIRECTIVE_TOPRIGHTCORNER,
+ 'value': 'top-right-corner'
+ },
+ {
+ 'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMLEFTCORNER,
+ 'value': 'bottom-left-corner'
+ },
+ {'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMLEFT, 'value': 'bottom-left'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMCENTER, 'value': 'bottom-center'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMRIGHT, 'value': 'bottom-right'},
+ {
+ 'type': TokenKind.MARGIN_DIRECTIVE_BOTTOMRIGHTCORNER,
+ 'value': 'bottom-right-corner'
+ },
+ {'type': TokenKind.MARGIN_DIRECTIVE_LEFTTOP, 'value': 'left-top'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_LEFTMIDDLE, 'value': 'left-middle'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_LEFTBOTTOM, 'value': 'right-bottom'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_RIGHTTOP, 'value': 'right-top'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_RIGHTMIDDLE, 'value': 'right-middle'},
+ {'type': TokenKind.MARGIN_DIRECTIVE_RIGHTBOTTOM, 'value': 'right-bottom'},
+ ];
+
+ static const List<Map<String, Object>> _UNITS = [
+ {'unit': TokenKind.UNIT_EM, 'value': 'em'},
+ {'unit': TokenKind.UNIT_EX, 'value': 'ex'},
+ {'unit': TokenKind.UNIT_LENGTH_PX, 'value': 'px'},
+ {'unit': TokenKind.UNIT_LENGTH_CM, 'value': 'cm'},
+ {'unit': TokenKind.UNIT_LENGTH_MM, 'value': 'mm'},
+ {'unit': TokenKind.UNIT_LENGTH_IN, 'value': 'in'},
+ {'unit': TokenKind.UNIT_LENGTH_PT, 'value': 'pt'},
+ {'unit': TokenKind.UNIT_LENGTH_PC, 'value': 'pc'},
+ {'unit': TokenKind.UNIT_ANGLE_DEG, 'value': 'deg'},
+ {'unit': TokenKind.UNIT_ANGLE_RAD, 'value': 'rad'},
+ {'unit': TokenKind.UNIT_ANGLE_GRAD, 'value': 'grad'},
+ {'unit': TokenKind.UNIT_ANGLE_TURN, 'value': 'turn'},
+ {'unit': TokenKind.UNIT_TIME_MS, 'value': 'ms'},
+ {'unit': TokenKind.UNIT_TIME_S, 'value': 's'},
+ {'unit': TokenKind.UNIT_FREQ_HZ, 'value': 'hz'},
+ {'unit': TokenKind.UNIT_FREQ_KHZ, 'value': 'khz'},
+ {'unit': TokenKind.UNIT_FRACTION, 'value': 'fr'},
+ {'unit': TokenKind.UNIT_RESOLUTION_DPI, 'value': 'dpi'},
+ {'unit': TokenKind.UNIT_RESOLUTION_DPCM, 'value': 'dpcm'},
+ {'unit': TokenKind.UNIT_RESOLUTION_DPPX, 'value': 'dppx'},
+ {'unit': TokenKind.UNIT_CH, 'value': 'ch'},
+ {'unit': TokenKind.UNIT_REM, 'value': 'rem'},
+ {'unit': TokenKind.UNIT_VIEWPORT_VW, 'value': 'vw'},
+ {'unit': TokenKind.UNIT_VIEWPORT_VH, 'value': 'vh'},
+ {'unit': TokenKind.UNIT_VIEWPORT_VMIN, 'value': 'vmin'},
+ {'unit': TokenKind.UNIT_VIEWPORT_VMAX, 'value': 'vmax'},
+ {'unit': TokenKind.UNIT_LH, 'value': 'lh'},
+ {'unit': TokenKind.UNIT_RLH, 'value': 'rlh'},
+ ];
+
+ // Some more constants:
+ static const int ASCII_UPPER_A = 65; // ASCII value for uppercase A
+ static const int ASCII_UPPER_Z = 90; // ASCII value for uppercase Z
+
+ // Extended color keywords:
+ static const List<Map<String, Object>> _EXTENDED_COLOR_NAMES = [
+ {'name': 'aliceblue', 'value': 0xF08FF},
+ {'name': 'antiquewhite', 'value': 0xFAEBD7},
+ {'name': 'aqua', 'value': 0x00FFFF},
+ {'name': 'aquamarine', 'value': 0x7FFFD4},
+ {'name': 'azure', 'value': 0xF0FFFF},
+ {'name': 'beige', 'value': 0xF5F5DC},
+ {'name': 'bisque', 'value': 0xFFE4C4},
+ {'name': 'black', 'value': 0x000000},
+ {'name': 'blanchedalmond', 'value': 0xFFEBCD},
+ {'name': 'blue', 'value': 0x0000FF},
+ {'name': 'blueviolet', 'value': 0x8A2BE2},
+ {'name': 'brown', 'value': 0xA52A2A},
+ {'name': 'burlywood', 'value': 0xDEB887},
+ {'name': 'cadetblue', 'value': 0x5F9EA0},
+ {'name': 'chartreuse', 'value': 0x7FFF00},
+ {'name': 'chocolate', 'value': 0xD2691E},
+ {'name': 'coral', 'value': 0xFF7F50},
+ {'name': 'cornflowerblue', 'value': 0x6495ED},
+ {'name': 'cornsilk', 'value': 0xFFF8DC},
+ {'name': 'crimson', 'value': 0xDC143C},
+ {'name': 'cyan', 'value': 0x00FFFF},
+ {'name': 'darkblue', 'value': 0x00008B},
+ {'name': 'darkcyan', 'value': 0x008B8B},
+ {'name': 'darkgoldenrod', 'value': 0xB8860B},
+ {'name': 'darkgray', 'value': 0xA9A9A9},
+ {'name': 'darkgreen', 'value': 0x006400},
+ {'name': 'darkgrey', 'value': 0xA9A9A9},
+ {'name': 'darkkhaki', 'value': 0xBDB76B},
+ {'name': 'darkmagenta', 'value': 0x8B008B},
+ {'name': 'darkolivegreen', 'value': 0x556B2F},
+ {'name': 'darkorange', 'value': 0xFF8C00},
+ {'name': 'darkorchid', 'value': 0x9932CC},
+ {'name': 'darkred', 'value': 0x8B0000},
+ {'name': 'darksalmon', 'value': 0xE9967A},
+ {'name': 'darkseagreen', 'value': 0x8FBC8F},
+ {'name': 'darkslateblue', 'value': 0x483D8B},
+ {'name': 'darkslategray', 'value': 0x2F4F4F},
+ {'name': 'darkslategrey', 'value': 0x2F4F4F},
+ {'name': 'darkturquoise', 'value': 0x00CED1},
+ {'name': 'darkviolet', 'value': 0x9400D3},
+ {'name': 'deeppink', 'value': 0xFF1493},
+ {'name': 'deepskyblue', 'value': 0x00BFFF},
+ {'name': 'dimgray', 'value': 0x696969},
+ {'name': 'dimgrey', 'value': 0x696969},
+ {'name': 'dodgerblue', 'value': 0x1E90FF},
+ {'name': 'firebrick', 'value': 0xB22222},
+ {'name': 'floralwhite', 'value': 0xFFFAF0},
+ {'name': 'forestgreen', 'value': 0x228B22},
+ {'name': 'fuchsia', 'value': 0xFF00FF},
+ {'name': 'gainsboro', 'value': 0xDCDCDC},
+ {'name': 'ghostwhite', 'value': 0xF8F8FF},
+ {'name': 'gold', 'value': 0xFFD700},
+ {'name': 'goldenrod', 'value': 0xDAA520},
+ {'name': 'gray', 'value': 0x808080},
+ {'name': 'green', 'value': 0x008000},
+ {'name': 'greenyellow', 'value': 0xADFF2F},
+ {'name': 'grey', 'value': 0x808080},
+ {'name': 'honeydew', 'value': 0xF0FFF0},
+ {'name': 'hotpink', 'value': 0xFF69B4},
+ {'name': 'indianred', 'value': 0xCD5C5C},
+ {'name': 'indigo', 'value': 0x4B0082},
+ {'name': 'ivory', 'value': 0xFFFFF0},
+ {'name': 'khaki', 'value': 0xF0E68C},
+ {'name': 'lavender', 'value': 0xE6E6FA},
+ {'name': 'lavenderblush', 'value': 0xFFF0F5},
+ {'name': 'lawngreen', 'value': 0x7CFC00},
+ {'name': 'lemonchiffon', 'value': 0xFFFACD},
+ {'name': 'lightblue', 'value': 0xADD8E6},
+ {'name': 'lightcoral', 'value': 0xF08080},
+ {'name': 'lightcyan', 'value': 0xE0FFFF},
+ {'name': 'lightgoldenrodyellow', 'value': 0xFAFAD2},
+ {'name': 'lightgray', 'value': 0xD3D3D3},
+ {'name': 'lightgreen', 'value': 0x90EE90},
+ {'name': 'lightgrey', 'value': 0xD3D3D3},
+ {'name': 'lightpink', 'value': 0xFFB6C1},
+ {'name': 'lightsalmon', 'value': 0xFFA07A},
+ {'name': 'lightseagreen', 'value': 0x20B2AA},
+ {'name': 'lightskyblue', 'value': 0x87CEFA},
+ {'name': 'lightslategray', 'value': 0x778899},
+ {'name': 'lightslategrey', 'value': 0x778899},
+ {'name': 'lightsteelblue', 'value': 0xB0C4DE},
+ {'name': 'lightyellow', 'value': 0xFFFFE0},
+ {'name': 'lime', 'value': 0x00FF00},
+ {'name': 'limegreen', 'value': 0x32CD32},
+ {'name': 'linen', 'value': 0xFAF0E6},
+ {'name': 'magenta', 'value': 0xFF00FF},
+ {'name': 'maroon', 'value': 0x800000},
+ {'name': 'mediumaquamarine', 'value': 0x66CDAA},
+ {'name': 'mediumblue', 'value': 0x0000CD},
+ {'name': 'mediumorchid', 'value': 0xBA55D3},
+ {'name': 'mediumpurple', 'value': 0x9370DB},
+ {'name': 'mediumseagreen', 'value': 0x3CB371},
+ {'name': 'mediumslateblue', 'value': 0x7B68EE},
+ {'name': 'mediumspringgreen', 'value': 0x00FA9A},
+ {'name': 'mediumturquoise', 'value': 0x48D1CC},
+ {'name': 'mediumvioletred', 'value': 0xC71585},
+ {'name': 'midnightblue', 'value': 0x191970},
+ {'name': 'mintcream', 'value': 0xF5FFFA},
+ {'name': 'mistyrose', 'value': 0xFFE4E1},
+ {'name': 'moccasin', 'value': 0xFFE4B5},
+ {'name': 'navajowhite', 'value': 0xFFDEAD},
+ {'name': 'navy', 'value': 0x000080},
+ {'name': 'oldlace', 'value': 0xFDF5E6},
+ {'name': 'olive', 'value': 0x808000},
+ {'name': 'olivedrab', 'value': 0x6B8E23},
+ {'name': 'orange', 'value': 0xFFA500},
+ {'name': 'orangered', 'value': 0xFF4500},
+ {'name': 'orchid', 'value': 0xDA70D6},
+ {'name': 'palegoldenrod', 'value': 0xEEE8AA},
+ {'name': 'palegreen', 'value': 0x98FB98},
+ {'name': 'paleturquoise', 'value': 0xAFEEEE},
+ {'name': 'palevioletred', 'value': 0xDB7093},
+ {'name': 'papayawhip', 'value': 0xFFEFD5},
+ {'name': 'peachpuff', 'value': 0xFFDAB9},
+ {'name': 'peru', 'value': 0xCD853F},
+ {'name': 'pink', 'value': 0xFFC0CB},
+ {'name': 'plum', 'value': 0xDDA0DD},
+ {'name': 'powderblue', 'value': 0xB0E0E6},
+ {'name': 'purple', 'value': 0x800080},
+ {'name': 'red', 'value': 0xFF0000},
+ {'name': 'rosybrown', 'value': 0xBC8F8F},
+ {'name': 'royalblue', 'value': 0x4169E1},
+ {'name': 'saddlebrown', 'value': 0x8B4513},
+ {'name': 'salmon', 'value': 0xFA8072},
+ {'name': 'sandybrown', 'value': 0xF4A460},
+ {'name': 'seagreen', 'value': 0x2E8B57},
+ {'name': 'seashell', 'value': 0xFFF5EE},
+ {'name': 'sienna', 'value': 0xA0522D},
+ {'name': 'silver', 'value': 0xC0C0C0},
+ {'name': 'skyblue', 'value': 0x87CEEB},
+ {'name': 'slateblue', 'value': 0x6A5ACD},
+ {'name': 'slategray', 'value': 0x708090},
+ {'name': 'slategrey', 'value': 0x708090},
+ {'name': 'snow', 'value': 0xFFFAFA},
+ {'name': 'springgreen', 'value': 0x00FF7F},
+ {'name': 'steelblue', 'value': 0x4682B4},
+ {'name': 'tan', 'value': 0xD2B48C},
+ {'name': 'teal', 'value': 0x008080},
+ {'name': 'thistle', 'value': 0xD8BFD8},
+ {'name': 'tomato', 'value': 0xFF6347},
+ {'name': 'turquoise', 'value': 0x40E0D0},
+ {'name': 'violet', 'value': 0xEE82EE},
+ {'name': 'wheat', 'value': 0xF5DEB3},
+ {'name': 'white', 'value': 0xFFFFFF},
+ {'name': 'whitesmoke', 'value': 0xF5F5F5},
+ {'name': 'yellow', 'value': 0xFFFF00},
+ {'name': 'yellowgreen', 'value': 0x9ACD32},
+ ];
+
+ // TODO(terry): Should used Dart mirroring for parameter values and types
+ // especially for enumeration (e.g., counter's second parameter
+ // is list-style-type which is an enumerated list for ordering
+ // of a list 'circle', 'decimal', 'lower-roman', 'square', etc.
+ // see http://www.w3schools.com/cssref/pr_list-style-type.asp
+ // for list of possible values.
+
+ /// Check if a name is a pre-defined CSS name.
+ ///
+ /// This is used by the error handler to report if a name is unknown or used
+ /// improperly.
+ static bool isPredefinedName(String name) {
+ final len = name.length;
+
+ // TODO(terry): Add more pre-defined names (hidden, bolder, inherit, etc.).
+ if (matchColorName(name) != null) return true;
+ if (matchDirectives(name, 0, len) != -1) return true;
+ if (matchMarginDirectives(name, 0, len) != -1) return true;
+ if (matchUnits(name, 0, len) != -1) return true;
+
+ return false;
+ }
+
+ /// Return the token that matches the unit ident found.
+ static int matchList(List<Map<String, dynamic>> identList, String tokenField,
+ String text, int offset, int length) {
+ for (final entry in identList) {
+ final ident = entry['value'] as String;
+
+ if (length == ident.length) {
+ var idx = offset;
+ var match = true;
+ for (var i = 0; i < ident.length; i++) {
+ var identChar = ident.codeUnitAt(i);
+ var char = text.codeUnitAt(idx++);
+ // Compare lowercase to lowercase then check if char is uppercase.
+ match = match &&
+ (char == identChar ||
+ ((char >= ASCII_UPPER_A && char <= ASCII_UPPER_Z) &&
+ (char + 32) == identChar));
+ if (!match) {
+ break;
+ }
+ }
+
+ if (match) {
+ // Completely matched; return the token for this unit.
+ return entry[tokenField] as int;
+ }
+ }
+ }
+
+ return -1; // Not a unit token.
+ }
+
+ /// Return the token that matches the unit ident found.
+ static int matchUnits(String text, int offset, int length) =>
+ matchList(_UNITS, 'unit', text, offset, length);
+
+ /// Return the token that matches the directive name found.
+ static int matchDirectives(String text, int offset, int length) =>
+ matchList(_DIRECTIVES, 'type', text, offset, length);
+
+ /// Return the token that matches the margin directive name found.
+ static int matchMarginDirectives(String text, int offset, int length) =>
+ matchList(MARGIN_DIRECTIVES, 'type', text, offset, length);
+
+ /// Return the token that matches the media operator found.
+ static int matchMediaOperator(String text, int offset, int length) =>
+ matchList(MEDIA_OPERATORS, 'type', text, offset, length);
+
+ static String? idToValue(Iterable<Object?> identList, int tokenId) {
+ for (var entry in identList) {
+ entry as Map<String, Object?>;
+ if (tokenId == entry['type']) {
+ return entry['value'] as String?;
+ }
+ }
+
+ return null;
+ }
+
+ /// Return the unit token as its pretty name.
+ static String? unitToString(int unitTokenToFind) {
+ if (unitTokenToFind == TokenKind.PERCENT) {
+ return '%';
+ } else {
+ for (final entry in _UNITS) {
+ final unit = entry['unit'] as int;
+ if (unit == unitTokenToFind) {
+ return entry['value'] as String?;
+ }
+ }
+ }
+
+ return '<BAD UNIT>'; // Not a unit token.
+ }
+
+ /// Match color name, case insensitive match and return the associated color
+ /// entry from _EXTENDED_COLOR_NAMES list, return `null` if not found.
+ static Map<String, Object>? matchColorName(String text) {
+ var name = text.toLowerCase();
+ for (var color in _EXTENDED_COLOR_NAMES) {
+ if (color['name'] == name) return color;
+ }
+ return null;
+ }
+
+ /// Return RGB value as [int] from a color entry in _EXTENDED_COLOR_NAMES.
+ static int colorValue(Map<String, Object> entry) => entry['value'] as int;
+
+ static String? hexToColorName(Object hexValue) {
+ for (final entry in _EXTENDED_COLOR_NAMES) {
+ if (entry['value'] == hexValue) {
+ return entry['name'] as String?;
+ }
+ }
+
+ return null;
+ }
+
+ static String decimalToHex(int number, [int minDigits = 1]) {
+ final hexDigits = '0123456789abcdef';
+
+ var result = <String>[];
+
+ var dividend = number >> 4;
+ var remain = number % 16;
+ result.add(hexDigits[remain]);
+ while (dividend != 0) {
+ remain = dividend % 16;
+ dividend >>= 4;
+ result.add(hexDigits[remain]);
+ }
+
+ var invertResult = StringBuffer();
+ var paddings = minDigits - result.length;
+ while (paddings-- > 0) {
+ invertResult.write('0');
+ }
+ for (var i = result.length - 1; i >= 0; i--) {
+ invertResult.write(result[i]);
+ }
+
+ return invertResult.toString();
+ }
+
+ static String kindToString(int kind) => switch (kind) {
+ TokenKind.UNUSED => 'ERROR',
+ TokenKind.END_OF_FILE => 'end of file',
+ TokenKind.LPAREN => '(',
+ TokenKind.RPAREN => ')',
+ TokenKind.LBRACK => '[',
+ TokenKind.RBRACK => ']',
+ TokenKind.LBRACE => '{',
+ TokenKind.RBRACE => '}',
+ TokenKind.DOT => '.',
+ TokenKind.SEMICOLON => ';',
+ TokenKind.AT => '@',
+ TokenKind.HASH => '#',
+ TokenKind.PLUS => '+',
+ TokenKind.GREATER => '>',
+ TokenKind.TILDE => '~',
+ TokenKind.ASTERISK => '*',
+ TokenKind.NAMESPACE => '|',
+ TokenKind.COLON => ':',
+ TokenKind.PRIVATE_NAME => '_',
+ TokenKind.COMMA => ',',
+ TokenKind.SPACE => ' ',
+ TokenKind.TAB => '\t',
+ TokenKind.NEWLINE => '\n',
+ TokenKind.RETURN => '\r',
+ TokenKind.PERCENT => '%',
+ TokenKind.SINGLE_QUOTE => "'",
+ TokenKind.DOUBLE_QUOTE => '"',
+ TokenKind.SLASH => '/',
+ TokenKind.EQUALS => '=',
+ TokenKind.CARET => '^',
+ TokenKind.DOLLAR => '\$',
+ TokenKind.LESS => '<',
+ TokenKind.BANG => '!',
+ TokenKind.MINUS => '-',
+ TokenKind.BACKSLASH => '\\',
+ _ => throw StateError('Unknown TOKEN')
+ };
+
+ static bool isKindIdentifier(int kind) {
+ switch (kind) {
+ // Synthesized tokens.
+ case TokenKind.DIRECTIVE_IMPORT:
+ case TokenKind.DIRECTIVE_MEDIA:
+ case TokenKind.DIRECTIVE_PAGE:
+ case TokenKind.DIRECTIVE_CHARSET:
+ case TokenKind.DIRECTIVE_STYLET:
+ case TokenKind.DIRECTIVE_KEYFRAMES:
+ case TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES:
+ case TokenKind.DIRECTIVE_MOZ_KEYFRAMES:
+ case TokenKind.DIRECTIVE_MS_KEYFRAMES:
+ case TokenKind.DIRECTIVE_O_KEYFRAMES:
+ case TokenKind.DIRECTIVE_FONTFACE:
+ case TokenKind.DIRECTIVE_NAMESPACE:
+ case TokenKind.DIRECTIVE_HOST:
+ case TokenKind.DIRECTIVE_MIXIN:
+ case TokenKind.DIRECTIVE_INCLUDE:
+ case TokenKind.DIRECTIVE_CONTENT:
+ case TokenKind.UNIT_EM:
+ case TokenKind.UNIT_EX:
+ case TokenKind.UNIT_LENGTH_PX:
+ case TokenKind.UNIT_LENGTH_CM:
+ case TokenKind.UNIT_LENGTH_MM:
+ case TokenKind.UNIT_LENGTH_IN:
+ case TokenKind.UNIT_LENGTH_PT:
+ case TokenKind.UNIT_LENGTH_PC:
+ case TokenKind.UNIT_ANGLE_DEG:
+ case TokenKind.UNIT_ANGLE_RAD:
+ case TokenKind.UNIT_ANGLE_GRAD:
+ case TokenKind.UNIT_TIME_MS:
+ case TokenKind.UNIT_TIME_S:
+ case TokenKind.UNIT_FREQ_HZ:
+ case TokenKind.UNIT_FREQ_KHZ:
+ case TokenKind.UNIT_FRACTION:
+ case TokenKind.UNIT_LH:
+ case TokenKind.UNIT_RLH:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static bool isIdentifier(int kind) => kind == IDENTIFIER;
+}
+
+// Note: these names should match TokenKind names
+class TokenChar {
+ static const int UNUSED = -1;
+ static const int END_OF_FILE = 0;
+ static const int LPAREN = 0x28; // "(".codeUnitAt(0)
+ static const int RPAREN = 0x29; // ")".codeUnitAt(0)
+ static const int LBRACK = 0x5b; // "[".codeUnitAt(0)
+ static const int RBRACK = 0x5d; // "]".codeUnitAt(0)
+ static const int LBRACE = 0x7b; // "{".codeUnitAt(0)
+ static const int RBRACE = 0x7d; // "}".codeUnitAt(0)
+ static const int DOT = 0x2e; // ".".codeUnitAt(0)
+ static const int SEMICOLON = 0x3b; // ";".codeUnitAt(0)
+ static const int AT = 0x40; // "@".codeUnitAt(0)
+ static const int HASH = 0x23; // "#".codeUnitAt(0)
+ static const int PLUS = 0x2b; // "+".codeUnitAt(0)
+ static const int GREATER = 0x3e; // ">".codeUnitAt(0)
+ static const int TILDE = 0x7e; // "~".codeUnitAt(0)
+ static const int ASTERISK = 0x2a; // "*".codeUnitAt(0)
+ static const int NAMESPACE = 0x7c; // "|".codeUnitAt(0)
+ static const int COLON = 0x3a; // ":".codeUnitAt(0)
+ static const int PRIVATE_NAME = 0x5f; // "_".codeUnitAt(0)
+ static const int COMMA = 0x2c; // ",".codeUnitAt(0)
+ static const int SPACE = 0x20; // " ".codeUnitAt(0)
+ static const int TAB = 0x9; // "\t".codeUnitAt(0)
+ static const int NEWLINE = 0xa; // "\n".codeUnitAt(0)
+ static const int RETURN = 0xd; // "\r".codeUnitAt(0)
+ static const int BACKSPACE = 0x8; // "/b".codeUnitAt(0)
+ static const int FF = 0xc; // "/f".codeUnitAt(0)
+ static const int VT = 0xb; // "/v".codeUnitAt(0)
+ static const int PERCENT = 0x25; // "%".codeUnitAt(0)
+ static const int SINGLE_QUOTE = 0x27; // "'".codeUnitAt(0)
+ static const int DOUBLE_QUOTE = 0x22; // '"'.codeUnitAt(0)
+ static const int SLASH = 0x2f; // "/".codeUnitAt(0)
+ static const int EQUALS = 0x3d; // "=".codeUnitAt(0)
+ static const int OR = 0x7c; // "|".codeUnitAt(0)
+ static const int CARET = 0x5e; // "^".codeUnitAt(0)
+ static const int DOLLAR = 0x24; // "\$".codeUnitAt(0)
+ static const int LESS = 0x3c; // "<".codeUnitAt(0)
+ static const int BANG = 0x21; // "!".codeUnitAt(0)
+ static const int MINUS = 0x2d; // "-".codeUnitAt(0)
+ static const int BACKSLASH = 0x5c; // "\".codeUnitAt(0)
+ static const int AMPERSAND = 0x26; // "&".codeUnitAt(0)
+}
diff --git a/pkgs/csslib/lib/src/tokenizer.dart b/pkgs/csslib/lib/src/tokenizer.dart
new file mode 100644
index 0000000..d090106
--- /dev/null
+++ b/pkgs/csslib/lib/src/tokenizer.dart
@@ -0,0 +1,471 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../parser.dart';
+
+// TODO: We should update the tokenization to follow what's described in the
+// spec: https://www.w3.org/TR/css-syntax-3/#tokenization.
+
+class Tokenizer extends TokenizerBase {
+ /// U+ prefix for unicode characters.
+ // ignore: non_constant_identifier_names
+ final UNICODE_U = 'U'.codeUnitAt(0);
+ // ignore: non_constant_identifier_names
+ final UNICODE_LOWER_U = 'u'.codeUnitAt(0);
+ // ignore: non_constant_identifier_names
+ final UNICODE_PLUS = '+'.codeUnitAt(0);
+
+ // ignore: non_constant_identifier_names
+ final QUESTION_MARK = '?'.codeUnitAt(0);
+
+ /// CDATA keyword.
+ // ignore: non_constant_identifier_names
+ final List<int> CDATA_NAME = 'CDATA'.codeUnits;
+
+ Tokenizer(super.file, super.text, super.skipWhitespace, [super.index]);
+
+ @override
+ Token next({bool unicodeRange = false}) {
+ // keep track of our starting position
+ _startIndex = _index;
+
+ int ch;
+ ch = _nextChar();
+ switch (ch) {
+ case TokenChar.NEWLINE:
+ case TokenChar.RETURN:
+ case TokenChar.SPACE:
+ case TokenChar.TAB:
+ return finishWhitespace();
+ case TokenChar.END_OF_FILE:
+ return _finishToken(TokenKind.END_OF_FILE);
+ case TokenChar.AT:
+ var peekCh = _peekChar();
+ if (TokenizerHelpers.isIdentifierStart(peekCh)) {
+ var oldIndex = _index;
+ var oldStartIndex = _startIndex;
+
+ _startIndex = _index;
+ ch = _nextChar();
+ finishIdentifier();
+
+ // Is it a directive?
+ var tokId = TokenKind.matchDirectives(
+ _text, _startIndex, _index - _startIndex);
+ if (tokId == -1) {
+ // No, is it a margin directive?
+ tokId = TokenKind.matchMarginDirectives(
+ _text, _startIndex, _index - _startIndex);
+ }
+
+ if (tokId != -1) {
+ return _finishToken(tokId);
+ } else {
+ // Didn't find a CSS directive or margin directive so the @name is
+ // probably the Less definition '@name: value_variable_definition'.
+ _startIndex = oldStartIndex;
+ _index = oldIndex;
+ }
+ }
+ return _finishToken(TokenKind.AT);
+ case TokenChar.DOT:
+ var start = _startIndex; // Start where the dot started.
+ if (maybeEatDigit()) {
+ // looks like a number dot followed by digit(s).
+ var number = finishNumber();
+ if (number.kind == TokenKind.INTEGER) {
+ // It's a number but it's preceded by a dot, so make it a double.
+ _startIndex = start;
+ return _finishToken(TokenKind.DOUBLE);
+ } else {
+ // Don't allow dot followed by a double (e.g, '..1').
+ return _errorToken();
+ }
+ }
+ // It's really a dot.
+ return _finishToken(TokenKind.DOT);
+ case TokenChar.LPAREN:
+ return _finishToken(TokenKind.LPAREN);
+ case TokenChar.RPAREN:
+ return _finishToken(TokenKind.RPAREN);
+ case TokenChar.LBRACE:
+ return _finishToken(TokenKind.LBRACE);
+ case TokenChar.RBRACE:
+ return _finishToken(TokenKind.RBRACE);
+ case TokenChar.LBRACK:
+ return _finishToken(TokenKind.LBRACK);
+ case TokenChar.RBRACK:
+ if (_maybeEatChar(TokenChar.RBRACK) &&
+ _maybeEatChar(TokenChar.GREATER)) {
+ // ]]>
+ return next();
+ }
+ return _finishToken(TokenKind.RBRACK);
+ case TokenChar.HASH:
+ return _finishToken(TokenKind.HASH);
+ case TokenChar.PLUS:
+ if (_nextCharsAreNumber(ch)) return finishNumber();
+ return _finishToken(TokenKind.PLUS);
+ case TokenChar.MINUS:
+ if (inSelectorExpression || unicodeRange) {
+ // If parsing in pseudo function expression then minus is an operator
+ // not part of identifier e.g., interval value range (e.g. U+400-4ff)
+ // or minus operator in selector expression.
+ return _finishToken(TokenKind.MINUS);
+ } else if (_nextCharsAreNumber(ch)) {
+ return finishNumber();
+ } else if (TokenizerHelpers.isIdentifierStart(ch)) {
+ return finishIdentifier();
+ }
+ return _finishToken(TokenKind.MINUS);
+ case TokenChar.GREATER:
+ return _finishToken(TokenKind.GREATER);
+ case TokenChar.TILDE:
+ if (_maybeEatChar(TokenChar.EQUALS)) {
+ return _finishToken(TokenKind.INCLUDES); // ~=
+ }
+ return _finishToken(TokenKind.TILDE);
+ case TokenChar.ASTERISK:
+ if (_maybeEatChar(TokenChar.EQUALS)) {
+ return _finishToken(TokenKind.SUBSTRING_MATCH); // *=
+ }
+ return _finishToken(TokenKind.ASTERISK);
+ case TokenChar.AMPERSAND:
+ return _finishToken(TokenKind.AMPERSAND);
+ case TokenChar.NAMESPACE:
+ if (_maybeEatChar(TokenChar.EQUALS)) {
+ return _finishToken(TokenKind.DASH_MATCH); // |=
+ }
+ return _finishToken(TokenKind.NAMESPACE);
+ case TokenChar.COLON:
+ return _finishToken(TokenKind.COLON);
+ case TokenChar.COMMA:
+ return _finishToken(TokenKind.COMMA);
+ case TokenChar.SEMICOLON:
+ return _finishToken(TokenKind.SEMICOLON);
+ case TokenChar.PERCENT:
+ return _finishToken(TokenKind.PERCENT);
+ case TokenChar.SINGLE_QUOTE:
+ return _finishToken(TokenKind.SINGLE_QUOTE);
+ case TokenChar.DOUBLE_QUOTE:
+ return _finishToken(TokenKind.DOUBLE_QUOTE);
+ case TokenChar.SLASH:
+ if (_maybeEatChar(TokenChar.ASTERISK)) return finishMultiLineComment();
+ return _finishToken(TokenKind.SLASH);
+ case TokenChar.LESS: // <!--
+ if (_maybeEatChar(TokenChar.BANG)) {
+ if (_maybeEatChar(TokenChar.MINUS) &&
+ _maybeEatChar(TokenChar.MINUS)) {
+ return finishHtmlComment();
+ } else if (_maybeEatChar(TokenChar.LBRACK) &&
+ _maybeEatChar(CDATA_NAME[0]) &&
+ _maybeEatChar(CDATA_NAME[1]) &&
+ _maybeEatChar(CDATA_NAME[2]) &&
+ _maybeEatChar(CDATA_NAME[3]) &&
+ _maybeEatChar(CDATA_NAME[4]) &&
+ _maybeEatChar(TokenChar.LBRACK)) {
+ // <![CDATA[
+ return next();
+ }
+ }
+ return _finishToken(TokenKind.LESS);
+ case TokenChar.EQUALS:
+ return _finishToken(TokenKind.EQUALS);
+ case TokenChar.CARET:
+ if (_maybeEatChar(TokenChar.EQUALS)) {
+ return _finishToken(TokenKind.PREFIX_MATCH); // ^=
+ }
+ return _finishToken(TokenKind.CARET);
+ case TokenChar.DOLLAR:
+ if (_maybeEatChar(TokenChar.EQUALS)) {
+ return _finishToken(TokenKind.SUFFIX_MATCH); // $=
+ }
+ return _finishToken(TokenKind.DOLLAR);
+ case TokenChar.BANG:
+ return finishIdentifier();
+ default:
+ // TODO(jmesserly): this is used for IE8 detection; I'm not sure it's
+ // appropriate outside of a few specific places; certainly shouldn't
+ // be parsed in selectors.
+ if (!inSelector && ch == TokenChar.BACKSLASH) {
+ return _finishToken(TokenKind.BACKSLASH);
+ }
+
+ if (unicodeRange) {
+ // Three types of unicode ranges:
+ // - single code point (e.g. U+416)
+ // - interval value range (e.g. U+400-4ff)
+ // - range where trailing ‘?’ characters imply ‘any digit value’
+ // (e.g. U+4??)
+ if (maybeEatHexDigit()) {
+ var t = finishHexNumber();
+ // Any question marks then it's a HEX_RANGE not HEX_NUMBER.
+ if (maybeEatQuestionMark()) finishUnicodeRange();
+ return t;
+ } else if (maybeEatQuestionMark()) {
+ // HEX_RANGE U+N???
+ return finishUnicodeRange();
+ } else {
+ return _errorToken();
+ }
+ } else if (_inString &&
+ (ch == UNICODE_U || ch == UNICODE_LOWER_U) &&
+ (_peekChar() == UNICODE_PLUS)) {
+ // `_inString` is misleading. We actually DON'T want to enter this
+ // block while tokenizing a string, but the parser sets this value to
+ // false while it IS consuming tokens within a string.
+ //
+ // Unicode range: U+uNumber[-U+uNumber]
+ // uNumber = 0..10FFFF
+ _nextChar(); // Skip +
+ _startIndex = _index; // Starts at the number
+ return _finishToken(TokenKind.UNICODE_RANGE);
+ } else if (varDef(ch)) {
+ return _finishToken(TokenKind.VAR_DEFINITION);
+ } else if (varUsage(ch)) {
+ return _finishToken(TokenKind.VAR_USAGE);
+ } else if (TokenizerHelpers.isIdentifierStart(ch)) {
+ return finishIdentifier();
+ } else if (TokenizerHelpers.isDigit(ch)) {
+ return finishNumber();
+ }
+ return _errorToken();
+ }
+ }
+
+ bool varDef(int ch) =>
+ ch == 'v'.codeUnitAt(0) &&
+ _maybeEatChar('a'.codeUnitAt(0)) &&
+ _maybeEatChar('r'.codeUnitAt(0)) &&
+ _maybeEatChar('-'.codeUnitAt(0));
+
+ bool varUsage(int ch) =>
+ ch == 'v'.codeUnitAt(0) &&
+ _maybeEatChar('a'.codeUnitAt(0)) &&
+ _maybeEatChar('r'.codeUnitAt(0)) &&
+ (_peekChar() == '-'.codeUnitAt(0));
+
+ @override
+ Token _errorToken([String? message]) => _finishToken(TokenKind.ERROR);
+
+ @override
+ int getIdentifierKind() {
+ // Is the identifier a unit type?
+ var tokId = -1;
+
+ // Don't match units in selectors or selector expressions.
+ if (!inSelectorExpression && !inSelector) {
+ tokId = TokenKind.matchUnits(_text, _startIndex, _index - _startIndex);
+ }
+ if (tokId == -1) {
+ tokId = (_text.substring(_startIndex, _index) == '!important')
+ ? TokenKind.IMPORTANT
+ : -1;
+ }
+
+ return tokId >= 0 ? tokId : TokenKind.IDENTIFIER;
+ }
+
+ Token finishIdentifier() {
+ // If we encounter an escape sequence, remember it so we can post-process
+ // to unescape.
+ var chars = <int>[];
+
+ // backup so we can start with the first character
+ var validateFrom = _index;
+ _index = _startIndex;
+ while (_index < _text.length) {
+ var ch = _text.codeUnitAt(_index);
+
+ // If the previous character was "\" we need to escape. T
+ // http://www.w3.org/TR/CSS21/syndata.html#characters
+ // if followed by hexadecimal digits, create the appropriate character.
+ // otherwise, include the character in the identifier and don't treat it
+ // specially.
+ if (ch == 92 /*\*/ && _inString) {
+ var startHex = ++_index;
+ eatHexDigits(startHex + 6);
+ if (_index != startHex) {
+ // Parse the hex digits and add that character.
+ chars.add(int.parse('0x${_text.substring(startHex, _index)}'));
+
+ if (_index == _text.length) break;
+
+ // if we stopped the hex because of a whitespace char, skip it
+ ch = _text.codeUnitAt(_index);
+ if (_index - startHex != 6 &&
+ (ch == TokenChar.SPACE ||
+ ch == TokenChar.TAB ||
+ ch == TokenChar.RETURN ||
+ ch == TokenChar.NEWLINE)) {
+ _index++;
+ }
+ } else {
+ // not a digit, just add the next character literally
+ if (_index == _text.length) break;
+ chars.add(_text.codeUnitAt(_index++));
+ }
+ } else if (_index < validateFrom ||
+ (inSelectorExpression
+ ? TokenizerHelpers.isIdentifierPartExpr(ch)
+ : TokenizerHelpers.isIdentifierPart(ch))) {
+ chars.add(ch);
+ _index++;
+ } else {
+ // Not an identifier or escaped character.
+ break;
+ }
+ }
+
+ var span = _file.span(_startIndex, _index);
+ var text = String.fromCharCodes(chars);
+
+ return IdentifierToken(text, getIdentifierKind(), span);
+ }
+
+ @override
+ Token finishNumber() {
+ eatDigits();
+
+ if (_peekChar() == 46 /*.*/) {
+ // Handle the case of 1.toString().
+ _nextChar();
+ if (TokenizerHelpers.isDigit(_peekChar())) {
+ eatDigits();
+ return _finishToken(TokenKind.DOUBLE);
+ } else {
+ _index -= 1;
+ }
+ }
+
+ return _finishToken(TokenKind.INTEGER);
+ }
+
+ bool maybeEatDigit() {
+ if (_index < _text.length &&
+ TokenizerHelpers.isDigit(_text.codeUnitAt(_index))) {
+ _index += 1;
+ return true;
+ }
+ return false;
+ }
+
+ Token finishHexNumber() {
+ eatHexDigits(_text.length);
+ return _finishToken(TokenKind.HEX_INTEGER);
+ }
+
+ void eatHexDigits(int end) {
+ end = math.min(end, _text.length);
+ while (_index < end) {
+ if (TokenizerHelpers.isHexDigit(_text.codeUnitAt(_index))) {
+ _index += 1;
+ } else {
+ return;
+ }
+ }
+ }
+
+ bool maybeEatHexDigit() {
+ if (_index < _text.length &&
+ TokenizerHelpers.isHexDigit(_text.codeUnitAt(_index))) {
+ _index += 1;
+ return true;
+ }
+ return false;
+ }
+
+ bool maybeEatQuestionMark() {
+ if (_index < _text.length && _text.codeUnitAt(_index) == QUESTION_MARK) {
+ _index += 1;
+ return true;
+ }
+ return false;
+ }
+
+ void eatQuestionMarks() {
+ while (_index < _text.length) {
+ if (_text.codeUnitAt(_index) == QUESTION_MARK) {
+ _index += 1;
+ } else {
+ return;
+ }
+ }
+ }
+
+ Token finishUnicodeRange() {
+ eatQuestionMarks();
+ return _finishToken(TokenKind.HEX_RANGE);
+ }
+
+ Token finishHtmlComment() {
+ while (true) {
+ var ch = _nextChar();
+ if (ch == 0) {
+ return _finishToken(TokenKind.INCOMPLETE_COMMENT);
+ } else if (ch == TokenChar.MINUS) {
+ /* Check if close part of Comment Definition --> (CDC). */
+ if (_maybeEatChar(TokenChar.MINUS)) {
+ if (_maybeEatChar(TokenChar.GREATER)) {
+ if (_inString) {
+ return next();
+ } else {
+ return _finishToken(TokenKind.HTML_COMMENT);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @override
+ Token finishMultiLineComment() {
+ while (true) {
+ var ch = _nextChar();
+ if (ch == 0) {
+ return _finishToken(TokenKind.INCOMPLETE_COMMENT);
+ } else if (ch == 42 /*'*'*/) {
+ if (_maybeEatChar(47 /*'/'*/)) {
+ if (_inString) {
+ return next();
+ } else {
+ return _finishToken(TokenKind.COMMENT);
+ }
+ }
+ }
+ }
+ }
+}
+
+/// Static helper methods.
+class TokenizerHelpers {
+ static bool isIdentifierStart(int c) =>
+ isIdentifierStartExpr(c) || c == 45 /*-*/;
+
+ static bool isDigit(int c) => c >= 48 /*0*/ && c <= 57 /*9*/;
+
+ static bool isHexDigit(int c) =>
+ isDigit(c) ||
+ (c >= 97 /*a*/ && c <= 102 /*f*/) ||
+ (c >= 65 /*A*/ && c <= 70 /*F*/);
+
+ static bool isIdentifierPart(int c) =>
+ isIdentifierPartExpr(c) || c == 45 /*-*/;
+
+ /// Pseudo function expressions identifiers can't have a minus sign.
+ static bool isIdentifierStartExpr(int c) =>
+ (c >= 97 /*a*/ && c <= 122 /*z*/) ||
+ (c >= 65 /*A*/ && c <= 90 /*Z*/) ||
+ // Note: Unicode 10646 chars U+00A0 or higher are allowed, see:
+ // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ // http://www.w3.org/TR/CSS21/syndata.html#characters
+ // Also, escaped character should be allowed.
+ c == 95 /*_*/ ||
+ c >= 0xA0 ||
+ c == 92 /*\*/;
+
+ /// Pseudo function expressions identifiers can't have a minus sign.
+ static bool isIdentifierPartExpr(int c) =>
+ isIdentifierStartExpr(c) || isDigit(c);
+}
diff --git a/pkgs/csslib/lib/src/tokenizer_base.dart b/pkgs/csslib/lib/src/tokenizer_base.dart
new file mode 100644
index 0000000..bcac7be
--- /dev/null
+++ b/pkgs/csslib/lib/src/tokenizer_base.dart
@@ -0,0 +1,419 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Generated by scripts/tokenizer_gen.py.
+
+part of '../parser.dart';
+
+/// Tokenizer state to support look ahead for Less' nested selectors.
+class TokenizerState {
+ final int index;
+ final int startIndex;
+ final bool inSelectorExpression;
+ final bool inSelector;
+
+ TokenizerState(TokenizerBase base)
+ : index = base._index,
+ startIndex = base._startIndex,
+ inSelectorExpression = base.inSelectorExpression,
+ inSelector = base.inSelector;
+}
+
+/// The base class for our tokenizer. The hand coded parts are in this file,
+/// with the generated parts in the subclass Tokenizer.
+abstract class TokenizerBase {
+ final SourceFile _file;
+ final String _text;
+
+ // TODO: this seems like a bug – this field *is* used
+ // ignore: prefer_final_fields
+ bool _inString;
+
+ /// Changes tokenization when in a pseudo function expression. If true then
+ /// minus signs are handled as operators instead of identifiers.
+ bool inSelectorExpression = false;
+
+ /// Changes tokenization when in selectors. If true, it prevents identifiers
+ /// from being treated as units. This would break things like ":lang(fr)" or
+ /// the HTML (unknown) tag name "px", which is legal to use in a selector.
+ // TODO(jmesserly): is this a problem elsewhere? "fr" for example will be
+ // processed as a "fraction" unit token, preventing it from working in
+ // places where an identifier is expected. This was breaking selectors like:
+ // :lang(fr)
+ // The assumption that "fr" always means fraction (and similar issue with
+ // other units) doesn't seem valid. We probably should defer this
+ // analysis until we reach places in the parser where units are expected.
+ // I'm not sure this is tokenizing as described in the specs:
+ // http://dev.w3.org/csswg/css-syntax/
+ // http://dev.w3.org/csswg/selectors4/
+ bool inSelector = false;
+
+ int _index = 0;
+ int _startIndex = 0;
+
+ TokenizerBase(this._file, this._text, this._inString, [this._index = 0]);
+
+ Token next();
+ int getIdentifierKind();
+
+ /// Snapshot of Tokenizer scanning state.
+ TokenizerState get mark => TokenizerState(this);
+
+ /// Restore Tokenizer scanning state.
+ void restore(TokenizerState markedData) {
+ _index = markedData.index;
+ _startIndex = markedData.startIndex;
+ inSelectorExpression = markedData.inSelectorExpression;
+ inSelector = markedData.inSelector;
+ }
+
+ int _nextChar() {
+ if (_index < _text.length) {
+ return _text.codeUnitAt(_index++);
+ } else {
+ return 0;
+ }
+ }
+
+ int _peekChar([int offset = 0]) {
+ if (_index + offset < _text.length) {
+ return _text.codeUnitAt(_index + offset);
+ } else {
+ return 0;
+ }
+ }
+
+ bool _maybeEatChar(int ch) {
+ if (_index < _text.length) {
+ if (_text.codeUnitAt(_index) == ch) {
+ _index++;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ bool _nextCharsAreNumber(int first) {
+ if (TokenizerHelpers.isDigit(first)) return true;
+ var second = _peekChar();
+ if (first == TokenChar.DOT) return TokenizerHelpers.isDigit(second);
+ if (first == TokenChar.PLUS || first == TokenChar.MINUS) {
+ return TokenizerHelpers.isDigit(second) ||
+ (second == TokenChar.DOT && TokenizerHelpers.isDigit(_peekChar(1)));
+ }
+ return false;
+ }
+
+ Token _finishToken(int kind) => Token(kind, _file.span(_startIndex, _index));
+
+ Token _errorToken([String? message]) =>
+ ErrorToken(TokenKind.ERROR, _file.span(_startIndex, _index), message);
+
+ Token finishWhitespace() {
+ _index--;
+ while (_index < _text.length) {
+ final ch = _text.codeUnitAt(_index++);
+ if (ch == TokenChar.SPACE ||
+ ch == TokenChar.TAB ||
+ ch == TokenChar.RETURN) {
+ // do nothing
+ } else if (ch == TokenChar.NEWLINE) {
+ if (!_inString) {
+ return _finishToken(TokenKind.WHITESPACE); // note the newline?
+ }
+ } else {
+ _index--;
+ if (_inString) {
+ return next();
+ } else {
+ return _finishToken(TokenKind.WHITESPACE);
+ }
+ }
+ }
+ return _finishToken(TokenKind.END_OF_FILE);
+ }
+
+ Token finishMultiLineComment() {
+ var nesting = 1;
+ do {
+ var ch = _nextChar();
+ if (ch == 0) {
+ return _errorToken();
+ } else if (ch == TokenChar.ASTERISK) {
+ if (_maybeEatChar(TokenChar.SLASH)) {
+ nesting--;
+ }
+ } else if (ch == TokenChar.SLASH) {
+ if (_maybeEatChar(TokenChar.ASTERISK)) {
+ nesting++;
+ }
+ }
+ } while (nesting > 0);
+
+ if (_inString) {
+ return next();
+ } else {
+ return _finishToken(TokenKind.COMMENT);
+ }
+ }
+
+ void eatDigits() {
+ while (_index < _text.length) {
+ if (TokenizerHelpers.isDigit(_text.codeUnitAt(_index))) {
+ _index++;
+ } else {
+ return;
+ }
+ }
+ }
+
+ static int _hexDigit(int c) {
+ if (c >= 48 /*0*/ && c <= 57 /*9*/) {
+ return c - 48;
+ } else if (c >= 97 /*a*/ && c <= 102 /*f*/) {
+ return c - 87;
+ } else if (c >= 65 /*A*/ && c <= 70 /*F*/) {
+ return c - 55;
+ } else {
+ return -1;
+ }
+ }
+
+ int readHex([int? hexLength]) {
+ int maxIndex;
+ if (hexLength == null) {
+ maxIndex = _text.length - 1;
+ } else {
+ // TODO(jimhug): What if this is too long?
+ maxIndex = _index + hexLength;
+ if (maxIndex >= _text.length) return -1;
+ }
+ var result = 0;
+ while (_index < maxIndex) {
+ final digit = _hexDigit(_text.codeUnitAt(_index));
+ if (digit == -1) {
+ if (hexLength == null) {
+ return result;
+ } else {
+ return -1;
+ }
+ }
+ _hexDigit(_text.codeUnitAt(_index));
+ // Multiply by 16 rather than shift by 4 since that will result in a
+ // correct value for numbers that exceed the 32 bit precision of JS
+ // 'integers'.
+ // TODO: Figure out a better solution to integer truncation. Issue 638.
+ result = (result * 16) + digit;
+ _index++;
+ }
+
+ return result;
+ }
+
+ Token finishNumber() {
+ eatDigits();
+
+ if (_peekChar() == TokenChar.DOT) {
+ // Handle the case of 1.toString().
+ _nextChar();
+ if (TokenizerHelpers.isDigit(_peekChar())) {
+ eatDigits();
+ return finishNumberExtra(TokenKind.DOUBLE);
+ } else {
+ _index--;
+ }
+ }
+
+ return finishNumberExtra(TokenKind.INTEGER);
+ }
+
+ Token finishNumberExtra(int kind) {
+ if (_maybeEatChar(101 /*e*/) || _maybeEatChar(69 /*E*/)) {
+ kind = TokenKind.DOUBLE;
+ _maybeEatChar(TokenKind.MINUS);
+ _maybeEatChar(TokenKind.PLUS);
+ eatDigits();
+ }
+ if (_peekChar() != 0 && TokenizerHelpers.isIdentifierStart(_peekChar())) {
+ _nextChar();
+ return _errorToken('illegal character in number');
+ }
+
+ return _finishToken(kind);
+ }
+
+ Token _makeStringToken(List<int> buf, bool isPart) {
+ final s = String.fromCharCodes(buf);
+ final kind = isPart ? TokenKind.STRING_PART : TokenKind.STRING;
+ return LiteralToken(kind, _file.span(_startIndex, _index), s);
+ }
+
+ Token makeIEFilter(int start, int end) {
+ var filter = _text.substring(start, end);
+ return LiteralToken(TokenKind.STRING, _file.span(start, end), filter);
+ }
+
+ Token _makeRawStringToken(bool isMultiline) {
+ String s;
+ if (isMultiline) {
+ // Skip initial newline in multiline strings
+ var start = _startIndex + 4;
+ if (_text[start] == '\n') start++;
+ s = _text.substring(start, _index - 3);
+ } else {
+ s = _text.substring(_startIndex + 2, _index - 1);
+ }
+ return LiteralToken(TokenKind.STRING, _file.span(_startIndex, _index), s);
+ }
+
+ Token finishMultilineString(int quote) {
+ var buf = <int>[];
+ while (true) {
+ var ch = _nextChar();
+ if (ch == 0) {
+ return _errorToken();
+ } else if (ch == quote) {
+ if (_maybeEatChar(quote)) {
+ if (_maybeEatChar(quote)) {
+ return _makeStringToken(buf, false);
+ }
+ buf.add(quote);
+ }
+ buf.add(quote);
+ } else if (ch == TokenChar.BACKSLASH) {
+ var escapeVal = readEscapeSequence();
+ if (escapeVal == -1) {
+ return _errorToken('invalid hex escape sequence');
+ } else {
+ buf.add(escapeVal);
+ }
+ } else {
+ buf.add(ch);
+ }
+ }
+ }
+
+ Token finishString(int quote) {
+ if (_maybeEatChar(quote)) {
+ if (_maybeEatChar(quote)) {
+ // skip an initial newline
+ _maybeEatChar(TokenChar.NEWLINE);
+ return finishMultilineString(quote);
+ } else {
+ return _makeStringToken(<int>[], false);
+ }
+ }
+ return finishStringBody(quote);
+ }
+
+ Token finishRawString(int quote) {
+ if (_maybeEatChar(quote)) {
+ if (_maybeEatChar(quote)) {
+ return finishMultilineRawString(quote);
+ } else {
+ return _makeStringToken(<int>[], false);
+ }
+ }
+ while (true) {
+ var ch = _nextChar();
+ if (ch == quote) {
+ return _makeRawStringToken(false);
+ } else if (ch == 0) {
+ return _errorToken();
+ }
+ }
+ }
+
+ Token finishMultilineRawString(int quote) {
+ while (true) {
+ var ch = _nextChar();
+ if (ch == 0) {
+ return _errorToken();
+ } else if (ch == quote && _maybeEatChar(quote) && _maybeEatChar(quote)) {
+ return _makeRawStringToken(true);
+ }
+ }
+ }
+
+ Token finishStringBody(int quote) {
+ var buf = <int>[];
+ while (true) {
+ var ch = _nextChar();
+ if (ch == quote) {
+ return _makeStringToken(buf, false);
+ } else if (ch == 0) {
+ return _errorToken();
+ } else if (ch == TokenChar.BACKSLASH) {
+ var escapeVal = readEscapeSequence();
+ if (escapeVal == -1) {
+ return _errorToken('invalid hex escape sequence');
+ } else {
+ buf.add(escapeVal);
+ }
+ } else {
+ buf.add(ch);
+ }
+ }
+ }
+
+ int readEscapeSequence() {
+ final ch = _nextChar();
+ int hexValue;
+ switch (ch) {
+ case 110 /*n*/ :
+ return TokenChar.NEWLINE;
+ case 114 /*r*/ :
+ return TokenChar.RETURN;
+ case 102 /*f*/ :
+ return TokenChar.FF;
+ case 98 /*b*/ :
+ return TokenChar.BACKSPACE;
+ case 116 /*t*/ :
+ return TokenChar.TAB;
+ case 118 /*v*/ :
+ return TokenChar.FF;
+ case 120 /*x*/ :
+ hexValue = readHex(2);
+ break;
+ case 117 /*u*/ :
+ if (_maybeEatChar(TokenChar.LBRACE)) {
+ hexValue = readHex();
+ if (!_maybeEatChar(TokenChar.RBRACE)) {
+ return -1;
+ }
+ } else {
+ hexValue = readHex(4);
+ }
+ break;
+ default:
+ return ch;
+ }
+
+ if (hexValue == -1) return -1;
+
+ // According to the Unicode standard the high and low surrogate halves
+ // used by UTF-16 (U+D800 through U+DFFF) and values above U+10FFFF
+ // are not legal Unicode values.
+ if (hexValue < 0xD800 || hexValue > 0xDFFF && hexValue <= 0xFFFF) {
+ return hexValue;
+ } else if (hexValue <= 0x10FFFF) {
+ messages.error('unicode values greater than 2 bytes not implemented yet',
+ _file.span(_startIndex, _startIndex + 1));
+ return -1;
+ } else {
+ return -1;
+ }
+ }
+
+ Token finishDot() {
+ if (TokenizerHelpers.isDigit(_peekChar())) {
+ eatDigits();
+ return finishNumberExtra(TokenKind.DOUBLE);
+ } else {
+ return _finishToken(TokenKind.DOT);
+ }
+ }
+}
diff --git a/pkgs/csslib/lib/src/tree.dart b/pkgs/csslib/lib/src/tree.dart
new file mode 100644
index 0000000..94655cf
--- /dev/null
+++ b/pkgs/csslib/lib/src/tree.dart
@@ -0,0 +1,1775 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: prefer_asserts_in_initializer_lists
+
+part of '../visitor.dart';
+
+/////////////////////////////////////////////////////////////////////////
+// CSS specific types:
+/////////////////////////////////////////////////////////////////////////
+
+class Identifier extends TreeNode {
+ String name;
+
+ Identifier(this.name, SourceSpan? span) : super(span);
+
+ @override
+ Identifier clone() => Identifier(name, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitIdentifier(this);
+
+ @override
+ String toString() =>
+ // Try to use the identifier's original lexeme to preserve any escape
+ // codes as authored. The name, which may include escaped values, may no
+ // longer be a valid identifier.
+ span?.text ?? name;
+}
+
+class Wildcard extends TreeNode {
+ Wildcard(super.span);
+ @override
+ Wildcard clone() => Wildcard(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitWildcard(this);
+
+ String get name => '*';
+}
+
+class ThisOperator extends TreeNode {
+ ThisOperator(super.span);
+ @override
+ ThisOperator clone() => ThisOperator(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitThisOperator(this);
+
+ String get name => '&';
+}
+
+class Negation extends TreeNode {
+ Negation(super.span);
+ @override
+ Negation clone() => Negation(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitNegation(this);
+
+ String get name => 'not';
+}
+
+// calc(...)
+// TODO(terry): Hack to handle calc however the expressions should be fully
+// parsed and in the AST.
+class CalcTerm extends LiteralTerm {
+ final LiteralTerm expr;
+
+ CalcTerm(Object value, String text, this.expr, SourceSpan? span)
+ : super(value, text, span);
+
+ @override
+ CalcTerm clone() => CalcTerm(value, text, expr.clone(), span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitCalcTerm(this);
+
+ @override
+ String toString() => '$text($expr)';
+}
+
+// /* .... */
+class CssComment extends TreeNode {
+ final String comment;
+
+ CssComment(this.comment, SourceSpan? span) : super(span);
+ @override
+ CssComment clone() => CssComment(comment, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitCssComment(this);
+}
+
+// CDO/CDC (Comment Definition Open <!-- and Comment Definition Close -->).
+class CommentDefinition extends CssComment {
+ CommentDefinition(super.comment, super.span);
+ @override
+ CommentDefinition clone() => CommentDefinition(comment, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitCommentDefinition(this);
+}
+
+class SelectorGroup extends TreeNode {
+ final List<Selector> selectors;
+
+ SelectorGroup(this.selectors, SourceSpan? span) : super(span);
+
+ @override
+ SelectorGroup clone() => SelectorGroup(selectors, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitSelectorGroup(this);
+}
+
+class Selector extends TreeNode {
+ final List<SimpleSelectorSequence> simpleSelectorSequences;
+
+ Selector(this.simpleSelectorSequences, SourceSpan? span) : super(span);
+
+ void add(SimpleSelectorSequence seq) => simpleSelectorSequences.add(seq);
+
+ int get length => simpleSelectorSequences.length;
+
+ @override
+ Selector clone() {
+ var simpleSequences =
+ simpleSelectorSequences.map((ss) => ss.clone()).toList();
+
+ return Selector(simpleSequences, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitSelector(this);
+}
+
+class SimpleSelectorSequence extends TreeNode {
+ /// +, >, ~, NONE
+ int combinator;
+ final SimpleSelector simpleSelector;
+
+ SimpleSelectorSequence(this.simpleSelector, SourceSpan? span,
+ [this.combinator = TokenKind.COMBINATOR_NONE])
+ : super(span);
+
+ bool get isCombinatorNone => combinator == TokenKind.COMBINATOR_NONE;
+ bool get isCombinatorPlus => combinator == TokenKind.COMBINATOR_PLUS;
+ bool get isCombinatorGreater => combinator == TokenKind.COMBINATOR_GREATER;
+ bool get isCombinatorTilde => combinator == TokenKind.COMBINATOR_TILDE;
+ bool get isCombinatorDescendant =>
+ combinator == TokenKind.COMBINATOR_DESCENDANT;
+
+ String get _combinatorToString => switch (combinator) {
+ TokenKind.COMBINATOR_DESCENDANT => ' ',
+ TokenKind.COMBINATOR_GREATER => ' > ',
+ TokenKind.COMBINATOR_PLUS => ' + ',
+ TokenKind.COMBINATOR_TILDE => ' ~ ',
+ _ => ''
+ };
+
+ @override
+ SimpleSelectorSequence clone() =>
+ SimpleSelectorSequence(simpleSelector, span, combinator);
+
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitSimpleSelectorSequence(this);
+
+ @override
+ String toString() => simpleSelector.name;
+}
+
+// All other selectors (element, #id, .class, attribute, pseudo, negation,
+// namespace, *) are derived from this selector.
+abstract class SimpleSelector extends TreeNode {
+ final dynamic _name; // Wildcard, ThisOperator, Identifier, Negation, others?
+
+ SimpleSelector(this._name, SourceSpan? span) : super(span);
+
+ // TOOD(srawlins): Figure this one out.
+ // ignore: avoid_dynamic_calls
+ String get name => _name.name as String;
+
+ bool get isWildcard => _name is Wildcard;
+
+ bool get isThis => _name is ThisOperator;
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitSimpleSelector(this);
+}
+
+// element name
+class ElementSelector extends SimpleSelector {
+ ElementSelector(super.name, super.span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitElementSelector(this);
+
+ @override
+ ElementSelector clone() => ElementSelector(_name, span);
+
+ @override
+ String toString() => name;
+}
+
+// namespace|element
+class NamespaceSelector extends SimpleSelector {
+ final dynamic _namespace; // null, Wildcard or Identifier
+
+ NamespaceSelector(this._namespace, Object name, SourceSpan? span)
+ : super(name, span);
+
+ String get namespace => _namespace is Wildcard
+ ? '*'
+ : _namespace == null
+ ? ''
+ : (_namespace as Identifier).name;
+
+ bool get isNamespaceWildcard => _namespace is Wildcard;
+
+ SimpleSelector? get nameAsSimpleSelector => _name as SimpleSelector?;
+
+ @override
+ NamespaceSelector clone() => NamespaceSelector(_namespace, '', span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitNamespaceSelector(this);
+
+ @override
+ String toString() => '$namespace|${nameAsSimpleSelector!.name}';
+}
+
+// [attr op value]
+class AttributeSelector extends SimpleSelector {
+ final int _op;
+ final dynamic value;
+
+ AttributeSelector(Identifier name, this._op, this.value, SourceSpan? span)
+ : super(name, span);
+
+ int get operatorKind => _op;
+
+ String? matchOperator() => switch (_op) {
+ TokenKind.EQUALS => '=',
+ TokenKind.INCLUDES => '~=',
+ TokenKind.DASH_MATCH => '|=',
+ TokenKind.PREFIX_MATCH => '^=',
+ TokenKind.SUFFIX_MATCH => '\$=',
+ TokenKind.SUBSTRING_MATCH => '*=',
+ TokenKind.NO_MATCH => '',
+ _ => null
+ };
+
+ // Return the TokenKind for operator used by visitAttributeSelector.
+ String? matchOperatorAsTokenString() => switch (_op) {
+ TokenKind.EQUALS => 'EQUALS',
+ TokenKind.INCLUDES => 'INCLUDES',
+ TokenKind.DASH_MATCH => 'DASH_MATCH',
+ TokenKind.PREFIX_MATCH => 'PREFIX_MATCH',
+ TokenKind.SUFFIX_MATCH => 'SUFFIX_MATCH',
+ TokenKind.SUBSTRING_MATCH => 'SUBSTRING_MATCH',
+ _ => null
+ };
+
+ String valueToString() {
+ if (value != null) {
+ if (value is Identifier) {
+ return value.toString();
+ } else {
+ return '"$value"';
+ }
+ } else {
+ return '';
+ }
+ }
+
+ @override
+ AttributeSelector clone() =>
+ AttributeSelector(_name as Identifier, _op, value, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitAttributeSelector(this);
+
+ @override
+ String toString() => '[$name${matchOperator()}${valueToString()}]';
+}
+
+// #id
+class IdSelector extends SimpleSelector {
+ IdSelector(Identifier super.name, super.span);
+ @override
+ IdSelector clone() => IdSelector(_name as Identifier, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitIdSelector(this);
+
+ @override
+ String toString() => '#$_name';
+}
+
+// .class
+class ClassSelector extends SimpleSelector {
+ ClassSelector(Identifier super.name, super.span);
+ @override
+ ClassSelector clone() => ClassSelector(_name as Identifier, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitClassSelector(this);
+
+ @override
+ String toString() => '.$_name';
+}
+
+// :pseudoClass
+class PseudoClassSelector extends SimpleSelector {
+ PseudoClassSelector(Identifier super.name, super.span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitPseudoClassSelector(this);
+
+ @override
+ PseudoClassSelector clone() => PseudoClassSelector(_name as Identifier, span);
+
+ @override
+ String toString() => ':$name';
+}
+
+// ::pseudoElement
+class PseudoElementSelector extends SimpleSelector {
+ // If true, this is a CSS2.1 pseudo-element with only a single ':'.
+ final bool isLegacy;
+
+ PseudoElementSelector(Identifier super.name, super.span,
+ {this.isLegacy = false});
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitPseudoElementSelector(this);
+
+ @override
+ PseudoElementSelector clone() =>
+ PseudoElementSelector(_name as Identifier, span);
+
+ @override
+ String toString() => "${isLegacy ? ':' : '::'}$name";
+}
+
+// :pseudoClassFunction(argument)
+class PseudoClassFunctionSelector extends PseudoClassSelector {
+ final TreeNode argument; // Selector, SelectorExpression
+
+ PseudoClassFunctionSelector(Identifier name, this.argument, SourceSpan? span)
+ : super(name, span);
+
+ @override
+ PseudoClassFunctionSelector clone() =>
+ PseudoClassFunctionSelector(_name as Identifier, argument, span);
+
+ Selector get selector => argument as Selector;
+ SelectorExpression get expression => argument as SelectorExpression;
+
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitPseudoClassFunctionSelector(this);
+}
+
+// ::pseudoElementFunction(expression)
+class PseudoElementFunctionSelector extends PseudoElementSelector {
+ final SelectorExpression expression;
+
+ PseudoElementFunctionSelector(
+ Identifier name, this.expression, SourceSpan? span)
+ : super(name, span);
+
+ @override
+ PseudoElementFunctionSelector clone() =>
+ PseudoElementFunctionSelector(_name as Identifier, expression, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitPseudoElementFunctionSelector(this);
+}
+
+class SelectorExpression extends TreeNode {
+ final List<Expression> expressions;
+
+ SelectorExpression(this.expressions, SourceSpan? span) : super(span);
+
+ @override
+ SourceSpan get span => super.span!;
+
+ @override
+ SelectorExpression clone() =>
+ SelectorExpression(expressions.map((e) => e.clone()).toList(), span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitSelectorExpression(this);
+}
+
+// :NOT(negation_arg)
+class NegationSelector extends SimpleSelector {
+ final SimpleSelector? negationArg;
+
+ NegationSelector(this.negationArg, SourceSpan? span)
+ : super(Negation(span), span);
+
+ @override
+ NegationSelector clone() => NegationSelector(negationArg, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitNegationSelector(this);
+}
+
+class NoOp extends TreeNode {
+ NoOp() : super(null);
+
+ @override
+ NoOp clone() => NoOp();
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitNoOp(this);
+}
+
+class StyleSheet extends TreeNode {
+ /// Contains charset, ruleset, directives (media, page, etc.), and selectors.
+ final List<TreeNode> topLevels;
+
+ StyleSheet(this.topLevels, SourceSpan? span) : super(span) {
+ for (final node in topLevels) {
+ assert(node is TopLevelProduction || node is Directive);
+ }
+ }
+
+ /// Selectors only in this tree.
+ StyleSheet.selector(this.topLevels, SourceSpan? span) : super(span);
+
+ @override
+ SourceSpan get span => super.span!;
+
+ @override
+ StyleSheet clone() {
+ var clonedTopLevels = topLevels.map((e) => e.clone()).toList();
+ return StyleSheet(clonedTopLevels, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitStyleSheet(this);
+}
+
+class TopLevelProduction extends TreeNode {
+ TopLevelProduction(super.span);
+ @override
+ SourceSpan get span => super.span!;
+ @override
+ TopLevelProduction clone() => TopLevelProduction(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitTopLevelProduction(this);
+}
+
+class RuleSet extends TopLevelProduction {
+ final SelectorGroup? selectorGroup;
+ final DeclarationGroup declarationGroup;
+
+ RuleSet(this.selectorGroup, this.declarationGroup, SourceSpan? span)
+ : super(span);
+
+ @override
+ RuleSet clone() {
+ var cloneSelectorGroup = selectorGroup!.clone();
+ var cloneDeclarationGroup = declarationGroup.clone();
+ return RuleSet(cloneSelectorGroup, cloneDeclarationGroup, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitRuleSet(this);
+}
+
+class Directive extends TreeNode {
+ Directive(super.span);
+
+ bool get isBuiltIn => true; // Known CSS directive?
+ bool get isExtension => false; // SCSS extension?
+
+ @override
+ SourceSpan get span => super.span!;
+
+ @override
+ Directive clone() => Directive(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitDirective(this);
+}
+
+class DocumentDirective extends Directive {
+ final List<LiteralTerm> functions;
+ final List<TreeNode> groupRuleBody;
+
+ DocumentDirective(this.functions, this.groupRuleBody, SourceSpan? span)
+ : super(span);
+
+ @override
+ DocumentDirective clone() {
+ var clonedFunctions = <LiteralTerm>[];
+ for (var function in functions) {
+ clonedFunctions.add(function.clone());
+ }
+ var clonedGroupRuleBody = <TreeNode>[];
+ for (var rule in groupRuleBody) {
+ clonedGroupRuleBody.add(rule.clone());
+ }
+ return DocumentDirective(clonedFunctions, clonedGroupRuleBody, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitDocumentDirective(this);
+}
+
+class SupportsDirective extends Directive {
+ final SupportsCondition? condition;
+ final List<TreeNode> groupRuleBody;
+
+ SupportsDirective(this.condition, this.groupRuleBody, SourceSpan? span)
+ : super(span);
+
+ @override
+ SupportsDirective clone() {
+ var clonedCondition = condition!.clone() as SupportsCondition;
+ var clonedGroupRuleBody = <TreeNode>[];
+ for (var rule in groupRuleBody) {
+ clonedGroupRuleBody.add(rule.clone());
+ }
+ return SupportsDirective(clonedCondition, clonedGroupRuleBody, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitSupportsDirective(this);
+}
+
+abstract class SupportsCondition extends TreeNode {
+ SupportsCondition(super.span);
+ @override
+ SourceSpan get span => super.span!;
+}
+
+class SupportsConditionInParens extends SupportsCondition {
+ /// A [Declaration] or nested [SupportsCondition].
+ final TreeNode? condition;
+
+ SupportsConditionInParens(Declaration? declaration, super.span)
+ : condition = declaration;
+
+ SupportsConditionInParens.nested(this.condition, SourceSpan? span)
+ : super(span);
+
+ @override
+ SupportsConditionInParens clone() =>
+ SupportsConditionInParens(condition!.clone() as Declaration, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitSupportsConditionInParens(this);
+}
+
+class SupportsNegation extends SupportsCondition {
+ final SupportsConditionInParens condition;
+
+ SupportsNegation(this.condition, SourceSpan? span) : super(span);
+
+ @override
+ SupportsNegation clone() => SupportsNegation(condition.clone(), span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitSupportsNegation(this);
+}
+
+class SupportsConjunction extends SupportsCondition {
+ final List<SupportsConditionInParens> conditions;
+
+ SupportsConjunction(this.conditions, SourceSpan? span) : super(span);
+
+ @override
+ SupportsConjunction clone() {
+ var clonedConditions = <SupportsConditionInParens>[];
+ for (var condition in conditions) {
+ clonedConditions.add(condition.clone());
+ }
+ return SupportsConjunction(clonedConditions, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitSupportsConjunction(this);
+}
+
+class SupportsDisjunction extends SupportsCondition {
+ final List<SupportsConditionInParens> conditions;
+
+ SupportsDisjunction(this.conditions, SourceSpan? span) : super(span);
+
+ @override
+ SupportsDisjunction clone() {
+ var clonedConditions = <SupportsConditionInParens>[];
+ for (var condition in conditions) {
+ clonedConditions.add(condition.clone());
+ }
+ return SupportsDisjunction(clonedConditions, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitSupportsDisjunction(this);
+}
+
+class ViewportDirective extends Directive {
+ final String name;
+ final DeclarationGroup declarations;
+
+ ViewportDirective(this.name, this.declarations, SourceSpan? span)
+ : super(span);
+
+ @override
+ ViewportDirective clone() =>
+ ViewportDirective(name, declarations.clone(), span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitViewportDirective(this);
+}
+
+class ImportDirective extends Directive {
+ /// import name specified.
+ final String import;
+
+ /// Any media queries for this import.
+ final List<MediaQuery> mediaQueries;
+
+ ImportDirective(this.import, this.mediaQueries, SourceSpan? span)
+ : super(span);
+
+ @override
+ ImportDirective clone() {
+ var cloneMediaQueries = <MediaQuery>[];
+ for (var mediaQuery in mediaQueries) {
+ cloneMediaQueries.add(mediaQuery.clone());
+ }
+ return ImportDirective(import, cloneMediaQueries, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitImportDirective(this);
+}
+
+/// MediaExpression grammar:
+///
+/// '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+class MediaExpression extends TreeNode {
+ final bool andOperator;
+ final Identifier _mediaFeature;
+ final Expressions exprs;
+
+ MediaExpression(
+ this.andOperator, this._mediaFeature, this.exprs, SourceSpan? span)
+ : super(span);
+
+ String get mediaFeature => _mediaFeature.name;
+
+ @override
+ SourceSpan get span => super.span!;
+
+ @override
+ MediaExpression clone() {
+ var clonedExprs = exprs.clone();
+ return MediaExpression(andOperator, _mediaFeature, clonedExprs, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitMediaExpression(this);
+}
+
+/// MediaQuery grammar:
+///
+/// : [ONLY | NOT]? S* media_type S* [ AND S* media_expression ]*
+/// | media_expression [ AND S* media_expression ]*
+/// media_type
+/// : IDENT
+/// media_expression
+/// : '(' S* media_feature S* [ ':' S* expr ]? ')' S*
+/// media_feature
+/// : IDENT
+class MediaQuery extends TreeNode {
+ /// not, only or no operator.
+ final int _mediaUnary;
+ final Identifier? _mediaType;
+ final List<MediaExpression> expressions;
+
+ MediaQuery(
+ this._mediaUnary, this._mediaType, this.expressions, SourceSpan? span)
+ : super(span);
+
+ bool get hasMediaType => _mediaType != null;
+ String get mediaType => _mediaType!.name;
+
+ bool get hasUnary => _mediaUnary != -1;
+ String get unary =>
+ TokenKind.idToValue(TokenKind.MEDIA_OPERATORS, _mediaUnary)!
+ .toUpperCase();
+
+ @override
+ SourceSpan get span => super.span!;
+
+ @override
+ MediaQuery clone() {
+ var cloneExpressions = <MediaExpression>[];
+ for (var expr in expressions) {
+ cloneExpressions.add(expr.clone());
+ }
+ return MediaQuery(_mediaUnary, _mediaType, cloneExpressions, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitMediaQuery(this);
+}
+
+class MediaDirective extends Directive {
+ final List<MediaQuery> mediaQueries;
+ final List<TreeNode> rules;
+
+ MediaDirective(this.mediaQueries, this.rules, SourceSpan? span) : super(span);
+
+ @override
+ MediaDirective clone() {
+ var cloneQueries = <MediaQuery>[];
+ for (var mediaQuery in mediaQueries) {
+ cloneQueries.add(mediaQuery.clone());
+ }
+ var cloneRules = <TreeNode>[];
+ for (var rule in rules) {
+ cloneRules.add(rule.clone());
+ }
+ return MediaDirective(cloneQueries, cloneRules, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitMediaDirective(this);
+}
+
+class HostDirective extends Directive {
+ final List<TreeNode> rules;
+
+ HostDirective(this.rules, SourceSpan? span) : super(span);
+
+ @override
+ HostDirective clone() {
+ var cloneRules = <TreeNode>[];
+ for (var rule in rules) {
+ cloneRules.add(rule.clone());
+ }
+ return HostDirective(cloneRules, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitHostDirective(this);
+}
+
+class PageDirective extends Directive {
+ final String? _ident;
+ final String? _pseudoPage;
+ final List<DeclarationGroup> _declsMargin;
+
+ PageDirective(
+ this._ident, this._pseudoPage, this._declsMargin, SourceSpan? span)
+ : super(span);
+
+ @override
+ PageDirective clone() {
+ var cloneDeclsMargin = <DeclarationGroup>[];
+ for (var declMargin in _declsMargin) {
+ cloneDeclsMargin.add(declMargin.clone());
+ }
+ return PageDirective(_ident, _pseudoPage, cloneDeclsMargin, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitPageDirective(this);
+
+ bool get hasIdent => _ident?.isNotEmpty ?? false;
+ bool get hasPseudoPage => _pseudoPage?.isNotEmpty ?? false;
+}
+
+class CharsetDirective extends Directive {
+ final String charEncoding;
+
+ CharsetDirective(this.charEncoding, SourceSpan? span) : super(span);
+ @override
+ CharsetDirective clone() => CharsetDirective(charEncoding, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitCharsetDirective(this);
+}
+
+class KeyFrameDirective extends Directive {
+ // Either @keyframe or keyframe prefixed with @-webkit-, @-moz-, @-ms-, @-o-.
+ final int _keyframeName;
+ final Identifier? name;
+ final List<KeyFrameBlock> _blocks;
+
+ KeyFrameDirective(this._keyframeName, this.name, SourceSpan? span)
+ : _blocks = [],
+ super(span);
+
+ void add(KeyFrameBlock block) {
+ _blocks.add(block);
+ }
+
+ String? get keyFrameName => switch (_keyframeName) {
+ TokenKind.DIRECTIVE_KEYFRAMES ||
+ TokenKind.DIRECTIVE_MS_KEYFRAMES =>
+ '@keyframes',
+ TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES => '@-webkit-keyframes',
+ TokenKind.DIRECTIVE_MOZ_KEYFRAMES => '@-moz-keyframes',
+ TokenKind.DIRECTIVE_O_KEYFRAMES => '@-o-keyframes',
+ _ => null
+ };
+
+ @override
+ KeyFrameDirective clone() {
+ var directive = KeyFrameDirective(_keyframeName, name!.clone(), span);
+ for (var block in _blocks) {
+ directive.add(block.clone());
+ }
+ return directive;
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitKeyFrameDirective(this);
+}
+
+class KeyFrameBlock extends Expression {
+ final Expressions _blockSelectors;
+ final DeclarationGroup _declarations;
+
+ KeyFrameBlock(this._blockSelectors, this._declarations, SourceSpan? span)
+ : super(span);
+
+ @override
+ KeyFrameBlock clone() =>
+ KeyFrameBlock(_blockSelectors.clone(), _declarations.clone(), span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitKeyFrameBlock(this);
+}
+
+class FontFaceDirective extends Directive {
+ final DeclarationGroup _declarations;
+
+ FontFaceDirective(this._declarations, SourceSpan? span) : super(span);
+
+ @override
+ FontFaceDirective clone() => FontFaceDirective(_declarations.clone(), span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitFontFaceDirective(this);
+}
+
+class StyletDirective extends Directive {
+ final String dartClassName;
+ final List<TreeNode> rules;
+
+ StyletDirective(this.dartClassName, this.rules, SourceSpan? span)
+ : super(span);
+
+ @override
+ bool get isBuiltIn => false;
+ @override
+ bool get isExtension => true;
+
+ @override
+ StyletDirective clone() {
+ var cloneRules = <TreeNode>[];
+ for (var rule in rules) {
+ cloneRules.add(rule.clone());
+ }
+ return StyletDirective(dartClassName, cloneRules, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitStyletDirective(this);
+}
+
+class NamespaceDirective extends Directive {
+ /// Namespace prefix.
+ final String _prefix;
+
+ /// URI associated with this namespace.
+ final String? _uri;
+
+ NamespaceDirective(this._prefix, this._uri, SourceSpan? span) : super(span);
+
+ @override
+ NamespaceDirective clone() => NamespaceDirective(_prefix, _uri, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitNamespaceDirective(this);
+
+ String get prefix => _prefix.isNotEmpty ? '$_prefix ' : '';
+}
+
+/// To support Less syntax @name: expression
+class VarDefinitionDirective extends Directive {
+ final VarDefinition def;
+
+ VarDefinitionDirective(this.def, SourceSpan? span) : super(span);
+
+ @override
+ VarDefinitionDirective clone() => VarDefinitionDirective(def.clone(), span);
+
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitVarDefinitionDirective(this);
+}
+
+class MixinDefinition extends Directive {
+ final String name;
+ final List<TreeNode> definedArgs;
+ final bool varArgs;
+
+ MixinDefinition(this.name, this.definedArgs, this.varArgs, SourceSpan? span)
+ : super(span);
+
+ @override
+ MixinDefinition clone() {
+ var cloneDefinedArgs = <TreeNode>[];
+ for (var definedArg in definedArgs) {
+ cloneDefinedArgs.add(definedArg.clone());
+ }
+ return MixinDefinition(name, cloneDefinedArgs, varArgs, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitMixinDefinition(this);
+}
+
+/// Support a Sass @mixin. See http://sass-lang.com for description.
+class MixinRulesetDirective extends MixinDefinition {
+ final List<TreeNode> rulesets;
+
+ MixinRulesetDirective(String name, List<TreeNode> args, bool varArgs,
+ this.rulesets, SourceSpan? span)
+ : super(name, args, varArgs, span);
+
+ @override
+ MixinRulesetDirective clone() {
+ var clonedArgs = <VarDefinition>[];
+ for (var arg in definedArgs) {
+ clonedArgs.add(arg.clone() as VarDefinition);
+ }
+ var clonedRulesets = <TreeNode>[];
+ for (var ruleset in rulesets) {
+ clonedRulesets.add(ruleset.clone());
+ }
+ return MixinRulesetDirective(
+ name, clonedArgs, varArgs, clonedRulesets, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitMixinRulesetDirective(this);
+}
+
+class MixinDeclarationDirective extends MixinDefinition {
+ final DeclarationGroup declarations;
+
+ MixinDeclarationDirective(String name, List<TreeNode> args, bool varArgs,
+ this.declarations, SourceSpan? span)
+ : super(name, args, varArgs, span);
+
+ @override
+ MixinDeclarationDirective clone() {
+ var clonedArgs = <TreeNode>[];
+ for (var arg in definedArgs) {
+ clonedArgs.add(arg.clone());
+ }
+ return MixinDeclarationDirective(
+ name, clonedArgs, varArgs, declarations.clone(), span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitMixinDeclarationDirective(this);
+}
+
+/// To support consuming a Sass mixin @include.
+class IncludeDirective extends Directive {
+ final String name;
+ final List<List<Expression>> args;
+
+ IncludeDirective(this.name, this.args, SourceSpan? span) : super(span);
+
+ @override
+ IncludeDirective clone() {
+ var cloneArgs = <List<Expression>>[];
+ for (var arg in args) {
+ cloneArgs.add(arg.map((term) => term.clone()).toList());
+ }
+ return IncludeDirective(name, cloneArgs, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitIncludeDirective(this);
+}
+
+/// To support Sass @content.
+class ContentDirective extends Directive {
+ ContentDirective(super.span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitContentDirective(this);
+}
+
+class Declaration extends TreeNode {
+ final Identifier? _property;
+ final Expression? expression;
+
+ /// Style exposed to Dart.
+ DartStyleExpression? dartStyle;
+ final bool important;
+
+ /// IE CSS hacks that can only be read by a particular IE version.
+ /// 7 implies IE 7 or older property (e.g., `*background: blue;`)
+ ///
+ /// * Note: IE 8 or older property (e.g., `background: green\9;`) is handled
+ /// by IE8Term in declaration expression handling.
+ /// * Note: IE 6 only property with a leading underscore is a valid IDENT
+ /// since an ident can start with underscore (e.g., `_background: red;`)
+ final bool isIE7;
+
+ Declaration(this._property, this.expression, this.dartStyle, SourceSpan? span,
+ {this.important = false, bool ie7 = false})
+ : isIE7 = ie7,
+ super(span);
+
+ String get property => isIE7 ? '*${_property!.name}' : _property!.name;
+
+ bool get hasDartStyle => dartStyle != null;
+
+ @override
+ SourceSpan get span => super.span!;
+
+ @override
+ Declaration clone() =>
+ Declaration(_property!.clone(), expression!.clone(), dartStyle, span,
+ important: important);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitDeclaration(this);
+}
+
+// TODO(terry): Consider 2 kinds of VarDefinitions static at top-level and
+// dynamic when in a declaration. Currently, Less syntax
+// '@foo: expression' and 'var-foo: expression' in a declaration
+// are statically resolved. Better solution, if @foo or var-foo
+// are top-level are then statically resolved and var-foo in a
+// declaration group (surrounded by a selector) would be dynamic.
+class VarDefinition extends Declaration {
+ bool badUsage = false;
+
+ VarDefinition(Identifier? definedName, Expression? expr, SourceSpan? span)
+ : super(definedName, expr, null, span);
+
+ String get definedName => _property!.name;
+
+ @override
+ VarDefinition clone() =>
+ VarDefinition(_property!.clone(), expression?.clone(), span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitVarDefinition(this);
+}
+
+/// Node for usage of @include mixin[(args,...)] found in a declaration group
+/// instead of at a ruleset (toplevel) e.g.,
+///
+/// div {
+/// @include mixin1;
+/// }
+class IncludeMixinAtDeclaration extends Declaration {
+ final IncludeDirective include;
+
+ IncludeMixinAtDeclaration(this.include, SourceSpan? span)
+ : super(null, null, null, span);
+
+ @override
+ IncludeMixinAtDeclaration clone() =>
+ IncludeMixinAtDeclaration(include.clone(), span);
+
+ @override
+ dynamic visit(VisitorBase visitor) =>
+ visitor.visitIncludeMixinAtDeclaration(this);
+}
+
+class ExtendDeclaration extends Declaration {
+ final List<TreeNode> selectors;
+
+ ExtendDeclaration(this.selectors, SourceSpan? span)
+ : super(null, null, null, span);
+
+ @override
+ ExtendDeclaration clone() {
+ var newSelector = selectors.map((s) => s.clone()).toList();
+ return ExtendDeclaration(newSelector, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitExtendDeclaration(this);
+}
+
+class DeclarationGroup extends TreeNode {
+ /// Can be either Declaration or RuleSet (if nested selector).
+ final List<TreeNode> declarations;
+
+ DeclarationGroup(this.declarations, SourceSpan? span) : super(span);
+
+ @override
+ SourceSpan get span => super.span!;
+
+ @override
+ DeclarationGroup clone() {
+ var clonedDecls = declarations.map((d) => d.clone()).toList();
+ return DeclarationGroup(clonedDecls, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitDeclarationGroup(this);
+}
+
+class MarginGroup extends DeclarationGroup {
+ // ignore: non_constant_identifier_names
+ final int margin_sym; // TokenType for for @margin sym.
+
+ MarginGroup(this.margin_sym, List<TreeNode> decls, SourceSpan? span)
+ : super(decls, span);
+ @override
+ MarginGroup clone() =>
+ MarginGroup(margin_sym, super.clone().declarations, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitMarginGroup(this);
+}
+
+class VarUsage extends Expression {
+ final String name;
+ final List<Expression> defaultValues;
+
+ VarUsage(this.name, this.defaultValues, SourceSpan? span) : super(span);
+
+ @override
+ VarUsage clone() {
+ var clonedValues = <Expression>[];
+ for (var expr in defaultValues) {
+ clonedValues.add(expr.clone());
+ }
+ return VarUsage(name, clonedValues, span);
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitVarUsage(this);
+}
+
+class OperatorSlash extends Expression {
+ OperatorSlash(super.span);
+ @override
+ OperatorSlash clone() => OperatorSlash(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitOperatorSlash(this);
+}
+
+class OperatorComma extends Expression {
+ OperatorComma(super.span);
+ @override
+ OperatorComma clone() => OperatorComma(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitOperatorComma(this);
+}
+
+class OperatorPlus extends Expression {
+ OperatorPlus(super.span);
+ @override
+ OperatorPlus clone() => OperatorPlus(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitOperatorPlus(this);
+}
+
+class OperatorMinus extends Expression {
+ OperatorMinus(super.span);
+ @override
+ OperatorMinus clone() => OperatorMinus(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitOperatorMinus(this);
+}
+
+class UnicodeRangeTerm extends Expression {
+ final String? first;
+ final String? second;
+
+ UnicodeRangeTerm(this.first, this.second, SourceSpan? span) : super(span);
+
+ bool get hasSecond => second != null;
+
+ @override
+ UnicodeRangeTerm clone() => UnicodeRangeTerm(first, second, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitUnicodeRangeTerm(this);
+}
+
+class LiteralTerm extends Expression {
+ // TODO(terry): value and text fields can be made final once all CSS resources
+ // are copied/symlink'd in the build tool and UriVisitor in
+ // web_ui is removed.
+ Object value;
+ String text;
+
+ LiteralTerm(this.value, this.text, SourceSpan? span) : super(span);
+
+ @override
+ LiteralTerm clone() => LiteralTerm(value, text, span);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitLiteralTerm(this);
+}
+
+class NumberTerm extends LiteralTerm {
+ NumberTerm(super.value, super.text, super.span);
+ @override
+ NumberTerm clone() => NumberTerm(value, text, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitNumberTerm(this);
+}
+
+class UnitTerm extends LiteralTerm {
+ final int unit;
+
+ UnitTerm(super.value, super.text, super.span, this.unit);
+
+ @override
+ UnitTerm clone() => UnitTerm(value, text, span, unit);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitUnitTerm(this);
+
+ String? unitToString() => TokenKind.unitToString(unit);
+
+ @override
+ String toString() => '$text${unitToString()}';
+}
+
+class LengthTerm extends UnitTerm {
+ LengthTerm(super.value, super.text, super.span,
+ [super.unit = TokenKind.UNIT_LENGTH_PX]) {
+ assert(unit == TokenKind.UNIT_LENGTH_PX ||
+ unit == TokenKind.UNIT_LENGTH_CM ||
+ unit == TokenKind.UNIT_LENGTH_MM ||
+ unit == TokenKind.UNIT_LENGTH_IN ||
+ unit == TokenKind.UNIT_LENGTH_PT ||
+ unit == TokenKind.UNIT_LENGTH_PC);
+ }
+ @override
+ LengthTerm clone() => LengthTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitLengthTerm(this);
+}
+
+class PercentageTerm extends LiteralTerm {
+ PercentageTerm(super.value, super.text, super.span);
+ @override
+ PercentageTerm clone() => PercentageTerm(value, text, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitPercentageTerm(this);
+}
+
+class EmTerm extends LiteralTerm {
+ EmTerm(super.value, super.text, super.span);
+ @override
+ EmTerm clone() => EmTerm(value, text, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitEmTerm(this);
+}
+
+class ExTerm extends LiteralTerm {
+ ExTerm(super.value, super.text, super.span);
+ @override
+ ExTerm clone() => ExTerm(value, text, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitExTerm(this);
+}
+
+class AngleTerm extends UnitTerm {
+ AngleTerm(super.value, super.text, super.span,
+ [super.unit = TokenKind.UNIT_LENGTH_PX]) {
+ assert(unit == TokenKind.UNIT_ANGLE_DEG ||
+ unit == TokenKind.UNIT_ANGLE_RAD ||
+ unit == TokenKind.UNIT_ANGLE_GRAD ||
+ unit == TokenKind.UNIT_ANGLE_TURN);
+ }
+
+ @override
+ AngleTerm clone() => AngleTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitAngleTerm(this);
+}
+
+class TimeTerm extends UnitTerm {
+ TimeTerm(super.value, super.text, super.span,
+ [super.unit = TokenKind.UNIT_LENGTH_PX]) {
+ assert(unit == TokenKind.UNIT_ANGLE_DEG ||
+ unit == TokenKind.UNIT_TIME_MS ||
+ unit == TokenKind.UNIT_TIME_S);
+ }
+
+ @override
+ TimeTerm clone() => TimeTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitTimeTerm(this);
+}
+
+class FreqTerm extends UnitTerm {
+ FreqTerm(Object value, String text, SourceSpan? span,
+ [int unit = TokenKind.UNIT_LENGTH_PX])
+ : super(value, text, span, unit) {
+ assert(unit == TokenKind.UNIT_FREQ_HZ || unit == TokenKind.UNIT_FREQ_KHZ);
+ }
+
+ @override
+ FreqTerm clone() => FreqTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitFreqTerm(this);
+}
+
+class FractionTerm extends LiteralTerm {
+ FractionTerm(super.value, super.text, super.span);
+
+ @override
+ FractionTerm clone() => FractionTerm(value, text, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitFractionTerm(this);
+}
+
+class UriTerm extends LiteralTerm {
+ UriTerm(String value, SourceSpan? span) : super(value, value, span);
+
+ @override
+ UriTerm clone() => UriTerm(value as String, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitUriTerm(this);
+}
+
+class ResolutionTerm extends UnitTerm {
+ ResolutionTerm(Object value, String text, SourceSpan? span,
+ [int unit = TokenKind.UNIT_LENGTH_PX])
+ : super(value, text, span, unit) {
+ assert(unit == TokenKind.UNIT_RESOLUTION_DPI ||
+ unit == TokenKind.UNIT_RESOLUTION_DPCM ||
+ unit == TokenKind.UNIT_RESOLUTION_DPPX);
+ }
+
+ @override
+ ResolutionTerm clone() => ResolutionTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitResolutionTerm(this);
+}
+
+class ChTerm extends UnitTerm {
+ ChTerm(Object value, String text, SourceSpan? span,
+ [int unit = TokenKind.UNIT_LENGTH_PX])
+ : super(value, text, span, unit) {
+ assert(unit == TokenKind.UNIT_CH);
+ }
+
+ @override
+ ChTerm clone() => ChTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitChTerm(this);
+}
+
+class RemTerm extends UnitTerm {
+ RemTerm(Object value, String text, SourceSpan? span,
+ [int unit = TokenKind.UNIT_LENGTH_PX])
+ : super(value, text, span, unit) {
+ assert(unit == TokenKind.UNIT_REM);
+ }
+
+ @override
+ RemTerm clone() => RemTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitRemTerm(this);
+}
+
+class LineHeightTerm extends UnitTerm {
+ LineHeightTerm(Object value, String text, SourceSpan? span, int unit)
+ : super(value, text, span, unit) {
+ assert(unit == TokenKind.UNIT_LH || unit == TokenKind.UNIT_RLH);
+ }
+ @override
+ LineHeightTerm clone() => LineHeightTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitLineHeightTerm(this);
+}
+
+class ViewportTerm extends UnitTerm {
+ ViewportTerm(Object value, String text, SourceSpan? span,
+ [int unit = TokenKind.UNIT_LENGTH_PX])
+ : super(value, text, span, unit) {
+ assert(unit == TokenKind.UNIT_VIEWPORT_VW ||
+ unit == TokenKind.UNIT_VIEWPORT_VH ||
+ unit == TokenKind.UNIT_VIEWPORT_VMIN ||
+ unit == TokenKind.UNIT_VIEWPORT_VMAX);
+ }
+
+ @override
+ ViewportTerm clone() => ViewportTerm(value, text, span, unit);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitViewportTerm(this);
+}
+
+/// Type to signal a bad hex value for HexColorTerm.value.
+// ignore: camel_case_types
+class BAD_HEX_VALUE {}
+
+class HexColorTerm extends LiteralTerm {
+ HexColorTerm(super.value, super.text, super.span);
+
+ @override
+ HexColorTerm clone() => HexColorTerm(value, text, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitHexColorTerm(this);
+}
+
+class FunctionTerm extends LiteralTerm {
+ final Expressions _params;
+
+ FunctionTerm(Object value, String text, this._params, SourceSpan? span)
+ : super(value, text, span);
+
+ @override
+ FunctionTerm clone() => FunctionTerm(value, text, _params.clone(), span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitFunctionTerm(this);
+}
+
+/// A "\9" was encountered at the end of the expression and before a semi-colon.
+/// This is an IE trick to ignore a property or value except by IE 8 and older
+/// browsers.
+class IE8Term extends LiteralTerm {
+ IE8Term(SourceSpan? span) : super('\\9', '\\9', span);
+ @override
+ IE8Term clone() => IE8Term(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitIE8Term(this);
+}
+
+class GroupTerm extends Expression {
+ final List<LiteralTerm> _terms;
+
+ GroupTerm(super.span) : _terms = [];
+
+ void add(LiteralTerm term) {
+ _terms.add(term);
+ }
+
+ @override
+ GroupTerm clone() => GroupTerm(span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitGroupTerm(this);
+}
+
+class ItemTerm extends NumberTerm {
+ ItemTerm(super.value, super.text, super.span);
+
+ @override
+ ItemTerm clone() => ItemTerm(value, text, span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitItemTerm(this);
+}
+
+class Expressions extends Expression {
+ final List<Expression> expressions = [];
+
+ Expressions(super.span);
+
+ void add(Expression expression) {
+ expressions.add(expression);
+ }
+
+ @override
+ Expressions clone() {
+ var clonedExprs = Expressions(span);
+ for (var expr in expressions) {
+ clonedExprs.add(expr.clone());
+ }
+ return clonedExprs;
+ }
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitExpressions(this);
+}
+
+class BinaryExpression extends Expression {
+ final Token op;
+ final Expression x;
+ final Expression y;
+
+ BinaryExpression(this.op, this.x, this.y, SourceSpan? span) : super(span);
+
+ @override
+ BinaryExpression clone() => BinaryExpression(op, x.clone(), y.clone(), span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitBinaryExpression(this);
+}
+
+class UnaryExpression extends Expression {
+ final Token op;
+ final Expression self;
+
+ UnaryExpression(this.op, this.self, SourceSpan? span) : super(span);
+
+ @override
+ UnaryExpression clone() => UnaryExpression(op, self.clone(), span);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitUnaryExpression(this);
+}
+
+abstract class DartStyleExpression extends TreeNode {
+ static const int unknownType = 0;
+ static const int fontStyle = 1;
+ static const int marginStyle = 2;
+ static const int borderStyle = 3;
+ static const int paddingStyle = 4;
+ static const int heightStyle = 5;
+ static const int widthStyle = 6;
+
+ final int? _styleType;
+ int? priority;
+
+ DartStyleExpression(this._styleType, SourceSpan? span) : super(span);
+
+ // Merges give 2 DartStyleExpression (or derived from DartStyleExpression,
+ // e.g., FontExpression, etc.) will merge if the two expressions are of the
+ // same property name (implies same exact type e.g, FontExpression).
+ DartStyleExpression? merged(DartStyleExpression newDartExpr);
+
+ bool get isUnknown => _styleType == 0 || _styleType == null;
+ bool get isFont => _styleType == fontStyle;
+ bool get isMargin => _styleType == marginStyle;
+ bool get isBorder => _styleType == borderStyle;
+ bool get isPadding => _styleType == paddingStyle;
+ bool get isHeight => _styleType == heightStyle;
+ bool get isWidth => _styleType == widthStyle;
+ bool get isBoxExpression => isMargin || isBorder || isPadding;
+
+ bool isSame(DartStyleExpression other) => _styleType == other._styleType;
+
+ @override
+ SourceSpan get span => super.span!;
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitDartStyleExpression(this);
+}
+
+class FontExpression extends DartStyleExpression {
+ final Font font;
+
+ // font-style font-variant font-weight font-size/line-height font-family
+ // TODO(terry): Only px/pt for now need to handle all possible units to
+ // support calc expressions on units.
+ FontExpression(SourceSpan? span,
+ {Object? /* LengthTerm | num */ size,
+ List<String>? family,
+ int? weight,
+ String? style,
+ String? variant,
+ LineHeight? lineHeight})
+ : font = Font(
+ size: (size is LengthTerm ? size.value : size) as num?,
+ family: family,
+ weight: weight,
+ style: style,
+ variant: variant,
+ lineHeight: lineHeight),
+ super(DartStyleExpression.fontStyle, span);
+
+ @override
+ FontExpression? merged(DartStyleExpression newDartExpr) {
+ if (newDartExpr is FontExpression && isFont && newDartExpr.isFont) {
+ return FontExpression.merge(this, newDartExpr);
+ }
+ return null;
+ }
+
+ /// Merge the two FontExpression and return the result.
+ factory FontExpression.merge(FontExpression x, FontExpression y) =>
+ FontExpression._merge(x, y, y.span);
+
+ FontExpression._merge(FontExpression x, FontExpression y, SourceSpan? span)
+ : font = Font.merge(x.font, y.font)!,
+ super(DartStyleExpression.fontStyle, span);
+
+ @override
+ FontExpression clone() => FontExpression(span,
+ size: font.size,
+ family: font.family,
+ weight: font.weight,
+ style: font.style,
+ variant: font.variant,
+ lineHeight: font.lineHeight);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitFontExpression(this);
+}
+
+abstract class BoxExpression extends DartStyleExpression {
+ final BoxEdge? box;
+
+ BoxExpression(super.styleType, super.span, this.box);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitBoxExpression(this);
+
+ String get formattedBoxEdge {
+ if (box!.top == box!.left &&
+ box!.top == box!.bottom &&
+ box!.top == box!.right) {
+ return '.uniform(${box!.top})';
+ } else {
+ var left = box!.left ?? 0;
+ var top = box!.top ?? 0;
+ var right = box!.right ?? 0;
+ var bottom = box!.bottom ?? 0;
+ return '.clockwiseFromTop($top,$right,$bottom,$left)';
+ }
+ }
+}
+
+class MarginExpression extends BoxExpression {
+ // TODO(terry): Does auto for margin need to be exposed to Dart UI framework?
+ /// Margin expression ripped apart.
+ MarginExpression(SourceSpan? span,
+ {num? top, num? right, num? bottom, num? left})
+ : super(DartStyleExpression.marginStyle, span,
+ BoxEdge(left, top, right, bottom));
+
+ MarginExpression.boxEdge(SourceSpan? span, BoxEdge? box)
+ : super(DartStyleExpression.marginStyle, span, box);
+
+ @override
+ MarginExpression? merged(DartStyleExpression newDartExpr) {
+ if (newDartExpr is MarginExpression && isMargin && newDartExpr.isMargin) {
+ return MarginExpression.merge(this, newDartExpr);
+ }
+
+ return null;
+ }
+
+ /// Merge the two MarginExpressions and return the result.
+ factory MarginExpression.merge(MarginExpression x, MarginExpression y) =>
+ MarginExpression._merge(x, y, y.span);
+
+ MarginExpression._merge(
+ MarginExpression x, MarginExpression y, SourceSpan? span)
+ : super(x._styleType, span, BoxEdge.merge(x.box, y.box));
+
+ @override
+ MarginExpression clone() => MarginExpression(span,
+ top: box!.top, right: box!.right, bottom: box!.bottom, left: box!.left);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitMarginExpression(this);
+}
+
+class BorderExpression extends BoxExpression {
+ /// Border expression ripped apart.
+ BorderExpression(SourceSpan? span,
+ {num? top, num? right, num? bottom, num? left})
+ : super(DartStyleExpression.borderStyle, span,
+ BoxEdge(left, top, right, bottom));
+
+ BorderExpression.boxEdge(SourceSpan? span, BoxEdge box)
+ : super(DartStyleExpression.borderStyle, span, box);
+
+ @override
+ BorderExpression? merged(DartStyleExpression newDartExpr) {
+ if (newDartExpr is BorderExpression && isBorder && newDartExpr.isBorder) {
+ return BorderExpression.merge(this, newDartExpr);
+ }
+
+ return null;
+ }
+
+ /// Merge the two BorderExpression and return the result.
+ factory BorderExpression.merge(BorderExpression x, BorderExpression y) =>
+ BorderExpression._merge(x, y, y.span);
+
+ BorderExpression._merge(
+ BorderExpression x, BorderExpression y, SourceSpan? span)
+ : super(
+ DartStyleExpression.borderStyle, span, BoxEdge.merge(x.box, y.box));
+
+ @override
+ BorderExpression clone() => BorderExpression(span,
+ top: box!.top, right: box!.right, bottom: box!.bottom, left: box!.left);
+
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitBorderExpression(this);
+}
+
+class HeightExpression extends DartStyleExpression {
+ final dynamic height;
+
+ HeightExpression(SourceSpan? span, this.height)
+ : super(DartStyleExpression.heightStyle, span);
+
+ @override
+ HeightExpression? merged(DartStyleExpression newDartExpr) {
+ if (isHeight && newDartExpr.isHeight) {
+ return newDartExpr as HeightExpression;
+ }
+
+ return null;
+ }
+
+ @override
+ HeightExpression clone() => HeightExpression(span, height);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitHeightExpression(this);
+}
+
+class WidthExpression extends DartStyleExpression {
+ final dynamic width;
+
+ WidthExpression(SourceSpan? span, this.width)
+ : super(DartStyleExpression.widthStyle, span);
+
+ @override
+ WidthExpression? merged(DartStyleExpression newDartExpr) {
+ if (newDartExpr is WidthExpression && isWidth && newDartExpr.isWidth) {
+ return newDartExpr;
+ }
+
+ return null;
+ }
+
+ @override
+ WidthExpression clone() => WidthExpression(span, width);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitWidthExpression(this);
+}
+
+class PaddingExpression extends BoxExpression {
+ /// Padding expression ripped apart.
+ PaddingExpression(SourceSpan? span,
+ {num? top, num? right, num? bottom, num? left})
+ : super(DartStyleExpression.paddingStyle, span,
+ BoxEdge(left, top, right, bottom));
+
+ PaddingExpression.boxEdge(SourceSpan? span, BoxEdge? box)
+ : super(DartStyleExpression.paddingStyle, span, box);
+
+ @override
+ PaddingExpression? merged(DartStyleExpression newDartExpr) {
+ if (newDartExpr is PaddingExpression &&
+ isPadding &&
+ newDartExpr.isPadding) {
+ return PaddingExpression.merge(this, newDartExpr);
+ }
+
+ return null;
+ }
+
+ /// Merge the two PaddingExpression and return the result.
+ factory PaddingExpression.merge(PaddingExpression x, PaddingExpression y) =>
+ PaddingExpression._merge(x, y, y.span);
+
+ PaddingExpression._merge(
+ PaddingExpression x, PaddingExpression y, SourceSpan? span)
+ : super(DartStyleExpression.paddingStyle, span,
+ BoxEdge.merge(x.box, y.box));
+
+ @override
+ PaddingExpression clone() => PaddingExpression(span,
+ top: box!.top, right: box!.right, bottom: box!.bottom, left: box!.left);
+ @override
+ dynamic visit(VisitorBase visitor) => visitor.visitPaddingExpression(this);
+}
diff --git a/pkgs/csslib/lib/src/tree_base.dart b/pkgs/csslib/lib/src/tree_base.dart
new file mode 100644
index 0000000..af55fdd
--- /dev/null
+++ b/pkgs/csslib/lib/src/tree_base.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../visitor.dart';
+
+/// The base type for all nodes in a CSS abstract syntax tree.
+abstract class TreeNode {
+ /// The source code this [TreeNode] represents.
+ final SourceSpan? span;
+
+ TreeNode(this.span);
+
+ TreeNode clone();
+
+ /// Classic double-dispatch visitor for implementing passes.
+ dynamic visit(VisitorBase visitor);
+
+ /// A multiline string showing the node and its children.
+ String toDebugString() {
+ var to = TreeOutput();
+ var tp = _TreePrinter(to, true);
+ visit(tp);
+ return to.buf.toString();
+ }
+}
+
+/// The base type for expressions.
+abstract class Expression extends TreeNode {
+ Expression(super.span);
+ @override
+ Expression clone();
+}
+
+/// Simple class to provide a textual dump of trees for debugging.
+class TreeOutput {
+ int depth = 0;
+ final StringBuffer buf = StringBuffer();
+ VisitorBase? printer;
+
+ void write(String s) {
+ for (var i = 0; i < depth; i++) {
+ buf.write(' ');
+ }
+ buf.write(s);
+ }
+
+ void writeln(String s) {
+ write(s);
+ buf.write('\n');
+ }
+
+ void heading(String name, [SourceSpan? span]) {
+ write(name);
+ if (span != null) {
+ buf.write(' (${span.message('')})');
+ }
+ buf.write('\n');
+ }
+
+ String toValue(dynamic value) {
+ if (value == null) {
+ return 'null';
+ } else if (value is Identifier) {
+ return value.name;
+ } else {
+ return value.toString();
+ }
+ }
+
+ void writeNode(String label, TreeNode? node) {
+ write('$label: ');
+ depth += 1;
+ if (node != null) {
+ node.visit(printer!);
+ } else {
+ writeln('null');
+ }
+ depth -= 1;
+ }
+
+ void writeValue(String label, dynamic value) {
+ var v = toValue(value);
+ writeln('$label: $v');
+ }
+
+ void writeNodeList(String label, List<TreeNode>? list) {
+ writeln('$label [');
+ if (list != null) {
+ depth += 1;
+ for (var node in list) {
+ node.visit(printer!);
+ }
+ depth -= 1;
+ writeln(']');
+ }
+ }
+
+ @override
+ String toString() => buf.toString();
+}
diff --git a/pkgs/csslib/lib/src/tree_printer.dart b/pkgs/csslib/lib/src/tree_printer.dart
new file mode 100644
index 0000000..2e11e9e
--- /dev/null
+++ b/pkgs/csslib/lib/src/tree_printer.dart
@@ -0,0 +1,700 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../visitor.dart';
+
+// TODO(terry): Enable class for debug only; when conditional imports enabled.
+
+/// Helper function to dump the CSS AST.
+String treeToDebugString(StyleSheet styleSheet, [bool useSpan = false]) {
+ var to = TreeOutput();
+ _TreePrinter(to, useSpan).visitTree(styleSheet);
+ return to.toString();
+}
+
+/// Tree dump for debug output of the CSS AST.
+class _TreePrinter extends Visitor {
+ final TreeOutput output;
+ final bool useSpan;
+
+ _TreePrinter(this.output, this.useSpan) {
+ output.printer = this;
+ }
+
+ @override
+ void visitTree(StyleSheet tree) => visitStylesheet(tree);
+
+ void heading(String heading, TreeNode node) {
+ if (useSpan) {
+ output.heading(heading, node.span);
+ } else {
+ output.heading(heading);
+ }
+ }
+
+ void visitStylesheet(StyleSheet node) {
+ heading('Stylesheet', node);
+ output.depth++;
+ super.visitStyleSheet(node);
+ output.depth--;
+ }
+
+ @override
+ void visitTopLevelProduction(TopLevelProduction node) {
+ heading('TopLevelProduction', node);
+ }
+
+ @override
+ void visitDirective(Directive node) {
+ heading('Directive', node);
+ }
+
+ @override
+ void visitCalcTerm(CalcTerm node) {
+ heading('CalcTerm', node);
+ output.depth++;
+ super.visitCalcTerm(node);
+ output.depth--;
+ }
+
+ @override
+ void visitCssComment(CssComment node) {
+ heading('Comment', node);
+ output.depth++;
+ output.writeValue('comment value', node.comment);
+ output.depth--;
+ }
+
+ @override
+ void visitCommentDefinition(CommentDefinition node) {
+ heading('CommentDefinition (CDO/CDC)', node);
+ output.depth++;
+ output.writeValue('comment value', node.comment);
+ output.depth--;
+ }
+
+ @override
+ void visitMediaExpression(MediaExpression node) {
+ heading('MediaExpression', node);
+ output.writeValue('feature', node.mediaFeature);
+ if (node.andOperator) output.writeValue('AND operator', '');
+ visitExpressions(node.exprs);
+ }
+
+ void visitMediaQueries(MediaQuery query) {
+ output.heading('MediaQueries');
+ output.writeValue('unary', query.unary);
+ output.writeValue('media type', query.mediaType);
+ output.writeNodeList('media expressions', query.expressions);
+ }
+
+ @override
+ void visitMediaDirective(MediaDirective node) {
+ heading('MediaDirective', node);
+ output.depth++;
+ output.writeNodeList('media queries', node.mediaQueries);
+ output.writeNodeList('rule sets', node.rules);
+ super.visitMediaDirective(node);
+ output.depth--;
+ }
+
+ @override
+ void visitDocumentDirective(DocumentDirective node) {
+ heading('DocumentDirective', node);
+ output.depth++;
+ output.writeNodeList('functions', node.functions);
+ output.writeNodeList('group rule body', node.groupRuleBody);
+ output.depth--;
+ }
+
+ @override
+ void visitSupportsDirective(SupportsDirective node) {
+ heading('SupportsDirective', node);
+ output.depth++;
+ output.writeNode('condition', node.condition);
+ output.writeNodeList('group rule body', node.groupRuleBody);
+ output.depth--;
+ }
+
+ @override
+ void visitSupportsConditionInParens(SupportsConditionInParens node) {
+ heading('SupportsConditionInParens', node);
+ output.depth++;
+ output.writeNode('condition', node.condition);
+ output.depth--;
+ }
+
+ @override
+ void visitSupportsNegation(SupportsNegation node) {
+ heading('SupportsNegation', node);
+ output.depth++;
+ output.writeNode('condition', node.condition);
+ output.depth--;
+ }
+
+ @override
+ void visitSupportsConjunction(SupportsConjunction node) {
+ heading('SupportsConjunction', node);
+ output.depth++;
+ output.writeNodeList('conditions', node.conditions);
+ output.depth--;
+ }
+
+ @override
+ void visitSupportsDisjunction(SupportsDisjunction node) {
+ heading('SupportsDisjunction', node);
+ output.depth++;
+ output.writeNodeList('conditions', node.conditions);
+ output.depth--;
+ }
+
+ @override
+ void visitViewportDirective(ViewportDirective node) {
+ heading('ViewportDirective', node);
+ output.depth++;
+ super.visitViewportDirective(node);
+ output.depth--;
+ }
+
+ @override
+ void visitPageDirective(PageDirective node) {
+ heading('PageDirective', node);
+ output.depth++;
+ output.writeValue('pseudo page', node._pseudoPage);
+ super.visitPageDirective(node);
+ output.depth--;
+ }
+
+ @override
+ void visitCharsetDirective(CharsetDirective node) {
+ heading('Charset Directive', node);
+ output.writeValue('charset encoding', node.charEncoding);
+ }
+
+ @override
+ void visitImportDirective(ImportDirective node) {
+ heading('ImportDirective', node);
+ output.depth++;
+ output.writeValue('import', node.import);
+ super.visitImportDirective(node);
+ output.writeNodeList('media', node.mediaQueries);
+ output.depth--;
+ }
+
+ @override
+ void visitContentDirective(ContentDirective node) {
+ print('ContentDirective not implemented');
+ }
+
+ @override
+ void visitKeyFrameDirective(KeyFrameDirective node) {
+ heading('KeyFrameDirective', node);
+ output.depth++;
+ output.writeValue('keyframe', node.keyFrameName);
+ output.writeValue('name', node.name);
+ output.writeNodeList('blocks', node._blocks);
+ output.depth--;
+ }
+
+ @override
+ void visitKeyFrameBlock(KeyFrameBlock node) {
+ heading('KeyFrameBlock', node);
+ output.depth++;
+ super.visitKeyFrameBlock(node);
+ output.depth--;
+ }
+
+ @override
+ void visitFontFaceDirective(FontFaceDirective node) {
+ // TODO(terry): To Be Implemented
+ }
+
+ @override
+ void visitStyletDirective(StyletDirective node) {
+ heading('StyletDirective', node);
+ output.writeValue('dartClassName', node.dartClassName);
+ output.depth++;
+ output.writeNodeList('rulesets', node.rules);
+ output.depth--;
+ }
+
+ @override
+ void visitNamespaceDirective(NamespaceDirective node) {
+ heading('NamespaceDirective', node);
+ output.depth++;
+ output.writeValue('prefix', node._prefix);
+ output.writeValue('uri', node._uri);
+ output.depth--;
+ }
+
+ @override
+ void visitVarDefinitionDirective(VarDefinitionDirective node) {
+ heading('Less variable definition', node);
+ output.depth++;
+ visitVarDefinition(node.def);
+ output.depth--;
+ }
+
+ @override
+ void visitMixinRulesetDirective(MixinRulesetDirective node) {
+ heading('Mixin top-level ${node.name}', node);
+ output.writeNodeList('parameters', node.definedArgs);
+ output.depth++;
+ _visitNodeList(node.rulesets);
+ output.depth--;
+ }
+
+ @override
+ void visitMixinDeclarationDirective(MixinDeclarationDirective node) {
+ heading('Mixin declaration ${node.name}', node);
+ output.writeNodeList('parameters', node.definedArgs);
+ output.depth++;
+ visitDeclarationGroup(node.declarations);
+ output.depth--;
+ }
+
+ /// Added optional newLine for handling @include at top-level vs/ inside of
+ /// a declaration group.
+ @override
+ void visitIncludeDirective(IncludeDirective node) {
+ heading('IncludeDirective ${node.name}', node);
+ var flattened = node.args.expand((e) => e).toList();
+ output.writeNodeList('parameters', flattened);
+ }
+
+ @override
+ void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) {
+ heading('IncludeMixinAtDeclaration ${node.include.name}', node);
+ output.depth++;
+ visitIncludeDirective(node.include);
+ output.depth--;
+ }
+
+ @override
+ void visitExtendDeclaration(ExtendDeclaration node) {
+ heading('ExtendDeclaration', node);
+ output.depth++;
+ _visitNodeList(node.selectors);
+ output.depth--;
+ }
+
+ @override
+ void visitRuleSet(RuleSet node) {
+ heading('Ruleset', node);
+ output.depth++;
+ super.visitRuleSet(node);
+ output.depth--;
+ }
+
+ @override
+ void visitDeclarationGroup(DeclarationGroup node) {
+ heading('DeclarationGroup', node);
+ output.depth++;
+ output.writeNodeList('declarations', node.declarations);
+ output.depth--;
+ }
+
+ @override
+ void visitMarginGroup(MarginGroup node) {
+ heading('MarginGroup', node);
+ output.depth++;
+ output.writeValue('@directive', node.margin_sym);
+ output.writeNodeList('declarations', node.declarations);
+ output.depth--;
+ }
+
+ @override
+ void visitDeclaration(Declaration node) {
+ heading('Declaration', node);
+ output.depth++;
+ if (node.isIE7) output.write('IE7 property');
+ output.write('property');
+ super.visitDeclaration(node);
+ output.writeNode('expression', node.expression);
+ if (node.important) {
+ output.writeValue('!important', 'true');
+ }
+ output.depth--;
+ }
+
+ @override
+ void visitVarDefinition(VarDefinition node) {
+ heading('Var', node);
+ output.depth++;
+ output.write('definition');
+ super.visitVarDefinition(node);
+ output.writeNode('expression', node.expression);
+ output.depth--;
+ }
+
+ @override
+ void visitSelectorGroup(SelectorGroup node) {
+ heading('Selector Group', node);
+ output.depth++;
+ output.writeNodeList('selectors', node.selectors);
+ output.depth--;
+ }
+
+ @override
+ void visitSelector(Selector node) {
+ heading('Selector', node);
+ output.depth++;
+ output.writeNodeList(
+ 'simpleSelectorsSequences', node.simpleSelectorSequences);
+ output.depth--;
+ }
+
+ @override
+ void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
+ heading('SimpleSelectorSequence', node);
+ output.depth++;
+ if (node.isCombinatorNone) {
+ output.writeValue('combinator', 'NONE');
+ } else if (node.isCombinatorDescendant) {
+ output.writeValue('combinator', 'descendant');
+ } else if (node.isCombinatorPlus) {
+ output.writeValue('combinator', '+');
+ } else if (node.isCombinatorGreater) {
+ output.writeValue('combinator', '>');
+ } else if (node.isCombinatorTilde) {
+ output.writeValue('combinator', '~');
+ } else {
+ output.writeValue('combinator', 'ERROR UNKNOWN');
+ }
+
+ super.visitSimpleSelectorSequence(node);
+
+ output.depth--;
+ }
+
+ @override
+ void visitNamespaceSelector(NamespaceSelector node) {
+ heading('Namespace Selector', node);
+ output.depth++;
+
+ super.visitNamespaceSelector(node);
+
+ visitSimpleSelector(node.nameAsSimpleSelector!);
+ output.depth--;
+ }
+
+ @override
+ void visitElementSelector(ElementSelector node) {
+ heading('Element Selector', node);
+ output.depth++;
+ super.visitElementSelector(node);
+ output.depth--;
+ }
+
+ @override
+ void visitAttributeSelector(AttributeSelector node) {
+ heading('AttributeSelector', node);
+ output.depth++;
+ super.visitAttributeSelector(node);
+ var tokenStr = node.matchOperatorAsTokenString();
+ output.writeValue('operator', '${node.matchOperator()} ($tokenStr)');
+ output.writeValue('value', node.valueToString());
+ output.depth--;
+ }
+
+ @override
+ void visitIdSelector(IdSelector node) {
+ heading('Id Selector', node);
+ output.depth++;
+ super.visitIdSelector(node);
+ output.depth--;
+ }
+
+ @override
+ void visitClassSelector(ClassSelector node) {
+ heading('Class Selector', node);
+ output.depth++;
+ super.visitClassSelector(node);
+ output.depth--;
+ }
+
+ @override
+ void visitPseudoClassSelector(PseudoClassSelector node) {
+ heading('Pseudo Class Selector', node);
+ output.depth++;
+ super.visitPseudoClassSelector(node);
+ output.depth--;
+ }
+
+ @override
+ void visitPseudoElementSelector(PseudoElementSelector node) {
+ heading('Pseudo Element Selector', node);
+ output.depth++;
+ super.visitPseudoElementSelector(node);
+ output.depth--;
+ }
+
+ @override
+ void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) {
+ heading('Pseudo Class Function Selector', node);
+ output.depth++;
+ node.argument.visit(this);
+ super.visitPseudoClassFunctionSelector(node);
+ output.depth--;
+ }
+
+ @override
+ void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) {
+ heading('Pseudo Element Function Selector', node);
+ output.depth++;
+ visitSelectorExpression(node.expression);
+ super.visitPseudoElementFunctionSelector(node);
+ output.depth--;
+ }
+
+ @override
+ void visitSelectorExpression(SelectorExpression node) {
+ heading('Selector Expression', node);
+ output.depth++;
+ output.writeNodeList('expressions', node.expressions);
+ output.depth--;
+ }
+
+ @override
+ void visitNegationSelector(NegationSelector node) {
+ super.visitNegationSelector(node);
+ output.depth++;
+ heading('Negation Selector', node);
+ output.writeNode('Negation arg', node.negationArg);
+ output.depth--;
+ }
+
+ @override
+ void visitUnicodeRangeTerm(UnicodeRangeTerm node) {
+ heading('UnicodeRangeTerm', node);
+ output.depth++;
+ output.writeValue('1st value', node.first);
+ output.writeValue('2nd value', node.second);
+ output.depth--;
+ }
+
+ @override
+ void visitLiteralTerm(LiteralTerm node) {
+ heading('LiteralTerm', node);
+ output.depth++;
+ output.writeValue('value', node.text);
+ output.depth--;
+ }
+
+ @override
+ void visitHexColorTerm(HexColorTerm node) {
+ heading('HexColorTerm', node);
+ output.depth++;
+ output.writeValue('hex value', node.text);
+ output.writeValue('decimal value', node.value);
+ output.depth--;
+ }
+
+ @override
+ void visitNumberTerm(NumberTerm node) {
+ heading('NumberTerm', node);
+ output.depth++;
+ output.writeValue('value', node.text);
+ output.depth--;
+ }
+
+ @override
+ void visitUnitTerm(UnitTerm node) {
+ output.depth++;
+ output.writeValue('value', node.text);
+ output.writeValue('unit', node.unitToString());
+ output.depth--;
+ }
+
+ @override
+ void visitLengthTerm(LengthTerm node) {
+ heading('LengthTerm', node);
+ super.visitLengthTerm(node);
+ }
+
+ @override
+ void visitPercentageTerm(PercentageTerm node) {
+ heading('PercentageTerm', node);
+ output.depth++;
+ super.visitPercentageTerm(node);
+ output.depth--;
+ }
+
+ @override
+ void visitEmTerm(EmTerm node) {
+ heading('EmTerm', node);
+ output.depth++;
+ super.visitEmTerm(node);
+ output.depth--;
+ }
+
+ @override
+ void visitExTerm(ExTerm node) {
+ heading('ExTerm', node);
+ output.depth++;
+ super.visitExTerm(node);
+ output.depth--;
+ }
+
+ @override
+ void visitAngleTerm(AngleTerm node) {
+ heading('AngleTerm', node);
+ super.visitAngleTerm(node);
+ }
+
+ @override
+ void visitTimeTerm(TimeTerm node) {
+ heading('TimeTerm', node);
+ super.visitTimeTerm(node);
+ }
+
+ @override
+ void visitFreqTerm(FreqTerm node) {
+ heading('FreqTerm', node);
+ super.visitFreqTerm(node);
+ }
+
+ @override
+ void visitFractionTerm(FractionTerm node) {
+ heading('FractionTerm', node);
+ output.depth++;
+ super.visitFractionTerm(node);
+ output.depth--;
+ }
+
+ @override
+ void visitUriTerm(UriTerm node) {
+ heading('UriTerm', node);
+ output.depth++;
+ super.visitUriTerm(node);
+ output.depth--;
+ }
+
+ @override
+ void visitFunctionTerm(FunctionTerm node) {
+ heading('FunctionTerm', node);
+ output.depth++;
+ super.visitFunctionTerm(node);
+ output.depth--;
+ }
+
+ @override
+ void visitGroupTerm(GroupTerm node) {
+ heading('GroupTerm', node);
+ output.depth++;
+ output.writeNodeList('grouped terms', node._terms);
+ output.depth--;
+ }
+
+ @override
+ void visitItemTerm(ItemTerm node) {
+ heading('ItemTerm', node);
+ super.visitItemTerm(node);
+ }
+
+ @override
+ void visitIE8Term(IE8Term node) {
+ heading('IE8Term', node);
+ visitLiteralTerm(node);
+ }
+
+ @override
+ void visitOperatorSlash(OperatorSlash node) {
+ heading('OperatorSlash', node);
+ }
+
+ @override
+ void visitOperatorComma(OperatorComma node) {
+ heading('OperatorComma', node);
+ }
+
+ @override
+ void visitOperatorPlus(OperatorPlus node) {
+ heading('OperatorPlus', node);
+ }
+
+ @override
+ void visitOperatorMinus(OperatorMinus node) {
+ heading('OperatorMinus', node);
+ }
+
+ @override
+ void visitVarUsage(VarUsage node) {
+ heading('Var', node);
+ output.depth++;
+ output.write('usage ${node.name}');
+ output.writeNodeList('default values', node.defaultValues);
+ output.depth--;
+ }
+
+ @override
+ void visitExpressions(Expressions node) {
+ heading('Expressions', node);
+ output.depth++;
+ output.writeNodeList('expressions', node.expressions);
+ output.depth--;
+ }
+
+ @override
+ void visitBinaryExpression(BinaryExpression node) {
+ heading('BinaryExpression', node);
+ // TODO(terry): TBD
+ }
+
+ @override
+ void visitUnaryExpression(UnaryExpression node) {
+ heading('UnaryExpression', node);
+ // TODO(terry): TBD
+ }
+
+ @override
+ void visitIdentifier(Identifier node) {
+ heading('Identifier(${output.toValue(node.name)})', node);
+ }
+
+ @override
+ void visitWildcard(Wildcard node) {
+ heading('Wildcard(*)', node);
+ }
+
+ @override
+ void visitDartStyleExpression(DartStyleExpression node) {
+ heading('DartStyleExpression', node);
+ }
+
+ @override
+ void visitFontExpression(FontExpression node) {
+ heading('Dart Style FontExpression', node);
+ }
+
+ @override
+ void visitBoxExpression(BoxExpression node) {
+ heading('Dart Style BoxExpression', node);
+ }
+
+ @override
+ void visitMarginExpression(MarginExpression node) {
+ heading('Dart Style MarginExpression', node);
+ }
+
+ @override
+ void visitBorderExpression(BorderExpression node) {
+ heading('Dart Style BorderExpression', node);
+ }
+
+ @override
+ void visitHeightExpression(HeightExpression node) {
+ heading('Dart Style HeightExpression', node);
+ }
+
+ @override
+ void visitPaddingExpression(PaddingExpression node) {
+ heading('Dart Style PaddingExpression', node);
+ }
+
+ @override
+ void visitWidthExpression(WidthExpression node) {
+ heading('Dart Style WidthExpression', node);
+ }
+}
diff --git a/pkgs/csslib/lib/src/validate.dart b/pkgs/csslib/lib/src/validate.dart
new file mode 100644
index 0000000..608c093
--- /dev/null
+++ b/pkgs/csslib/lib/src/validate.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+import '../visitor.dart';
+
+/// Can be thrown on any Css runtime problem includes source location.
+class CssSelectorException extends SourceSpanException {
+ CssSelectorException(super.message, [super.span]);
+}
+
+List<String> classes = [];
+List<String> ids = [];
+
+class Validate {
+ static int _classNameCheck(SimpleSelectorSequence selector, int matches) {
+ if (selector.isCombinatorDescendant ||
+ (selector.isCombinatorNone && matches == 0)) {
+ if (matches < 0) {
+ var tooMany = selector.simpleSelector.toString();
+ throw CssSelectorException(
+ 'Can not mix Id selector with class selector(s). Id '
+ 'selector must be singleton too many starting at $tooMany');
+ }
+
+ return matches + 1;
+ } else {
+ var error = selector.toString();
+ throw CssSelectorException(
+ 'Selectors can not have combinators (>, +, or ~) before $error');
+ }
+ }
+
+ static int _elementIdCheck(SimpleSelectorSequence selector, int matches) {
+ if (selector.isCombinatorNone && matches == 0) {
+ // Perfect just one element id returns matches of -1.
+ return -1;
+ } else if (selector.isCombinatorDescendant) {
+ var tooMany = selector.simpleSelector.toString();
+ throw CssSelectorException(
+ 'Use of Id selector must be singleton starting at $tooMany');
+ } else {
+ var error = selector.simpleSelector.toString();
+ throw CssSelectorException(
+ 'Selectors can not have combinators (>, +, or ~) before $error');
+ }
+ }
+
+ // Validate the @{css expression} only .class and #elementId are valid inside
+ // of @{...}.
+ static void template(List<Selector> selectors) {
+ var found = false; // signal if a selector is matched.
+ var matches = 0; // < 0 IdSelectors, > 0 ClassSelector
+
+ // At most one selector group (any number of simple selector sequences).
+ assert(selectors.length <= 1);
+
+ for (final sels in selectors) {
+ for (final selector in sels.simpleSelectorSequences) {
+ found = false;
+ var simpleSelector = selector.simpleSelector;
+ if (simpleSelector is ClassSelector) {
+ // Any class name starting with an underscore is a private class name
+ // that doesn't have to match the world of known classes.
+ if (!simpleSelector.name.startsWith('_')) {
+ // TODO(terry): For now iterate through all classes look for faster
+ // mechanism hash map, etc.
+ for (final className in classes) {
+ if (selector.simpleSelector.name == className) {
+ matches = _classNameCheck(selector, matches);
+ found = true; // .class found.
+ break;
+ }
+ for (final className2 in classes) {
+ print(className2);
+ }
+ }
+ } else {
+ // Don't check any class name that is prefixed with an underscore.
+ // However, signal as found and bump up matches; it's a valid class
+ // name.
+ matches = _classNameCheck(selector, matches);
+ found = true; // ._class are always okay.
+ }
+ } else if (simpleSelector is IdSelector) {
+ // Any element id starting with an underscore is a private element id
+ // that doesn't have to match the world of known element ids.
+ if (!simpleSelector.name.startsWith('_')) {
+ for (final id in ids) {
+ if (simpleSelector.name == id) {
+ matches = _elementIdCheck(selector, matches);
+ found = true; // #id found.
+ break;
+ }
+ }
+ } else {
+ // Don't check any element ID that is prefixed with an underscore.
+ // Signal as found and bump up matches; it's a valid element ID.
+ matches = _elementIdCheck(selector, matches);
+ found = true; // #_id are always okay
+ }
+ } else {
+ var badSelector = simpleSelector.toString();
+ throw CssSelectorException('Invalid template selector $badSelector');
+ }
+
+ if (!found) {
+ var unknownName = simpleSelector.toString();
+ throw CssSelectorException('Unknown selector name $unknownName');
+ }
+ }
+ }
+
+ // Every selector must match.
+ var selector = selectors[0];
+ assert((matches >= 0 ? matches : -matches) ==
+ selector.simpleSelectorSequences.length);
+ }
+}
diff --git a/pkgs/csslib/lib/visitor.dart b/pkgs/csslib/lib/visitor.dart
new file mode 100644
index 0000000..4cfd9f0
--- /dev/null
+++ b/pkgs/csslib/lib/visitor.dart
@@ -0,0 +1,596 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+import 'parser.dart';
+
+part 'src/css_printer.dart';
+part 'src/tree.dart';
+part 'src/tree_base.dart';
+part 'src/tree_printer.dart';
+
+abstract class VisitorBase {
+ dynamic visitCalcTerm(CalcTerm node);
+ dynamic visitCssComment(CssComment node);
+ dynamic visitCommentDefinition(CommentDefinition node);
+ dynamic visitStyleSheet(StyleSheet node);
+ dynamic visitNoOp(NoOp node);
+ dynamic visitTopLevelProduction(TopLevelProduction node);
+ dynamic visitDirective(Directive node);
+ dynamic visitDocumentDirective(DocumentDirective node);
+ dynamic visitSupportsDirective(SupportsDirective node);
+ dynamic visitSupportsConditionInParens(SupportsConditionInParens node);
+ dynamic visitSupportsNegation(SupportsNegation node);
+ dynamic visitSupportsConjunction(SupportsConjunction node);
+ dynamic visitSupportsDisjunction(SupportsDisjunction node);
+ dynamic visitViewportDirective(ViewportDirective node);
+ dynamic visitMediaExpression(MediaExpression node);
+ dynamic visitMediaQuery(MediaQuery node);
+ dynamic visitMediaDirective(MediaDirective node);
+ dynamic visitHostDirective(HostDirective node);
+ dynamic visitPageDirective(PageDirective node);
+ dynamic visitCharsetDirective(CharsetDirective node);
+ dynamic visitImportDirective(ImportDirective node);
+ dynamic visitKeyFrameDirective(KeyFrameDirective node);
+ dynamic visitKeyFrameBlock(KeyFrameBlock node);
+ dynamic visitFontFaceDirective(FontFaceDirective node);
+ dynamic visitStyletDirective(StyletDirective node);
+ dynamic visitNamespaceDirective(NamespaceDirective node);
+ dynamic visitVarDefinitionDirective(VarDefinitionDirective node);
+ dynamic visitMixinDefinition(MixinDefinition node);
+ dynamic visitMixinRulesetDirective(MixinRulesetDirective node);
+ dynamic visitMixinDeclarationDirective(MixinDeclarationDirective node);
+ dynamic visitIncludeDirective(IncludeDirective node);
+ dynamic visitContentDirective(ContentDirective node);
+
+ dynamic visitRuleSet(RuleSet node);
+ dynamic visitDeclarationGroup(DeclarationGroup node);
+ dynamic visitMarginGroup(MarginGroup node);
+ dynamic visitDeclaration(Declaration node);
+ dynamic visitVarDefinition(VarDefinition node);
+ dynamic visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node);
+ dynamic visitExtendDeclaration(ExtendDeclaration node);
+ dynamic visitSelectorGroup(SelectorGroup node);
+ dynamic visitSelector(Selector node);
+ dynamic visitSimpleSelectorSequence(SimpleSelectorSequence node);
+ dynamic visitSimpleSelector(SimpleSelector node);
+ dynamic visitElementSelector(ElementSelector node);
+ dynamic visitNamespaceSelector(NamespaceSelector node);
+ dynamic visitAttributeSelector(AttributeSelector node);
+ dynamic visitIdSelector(IdSelector node);
+ dynamic visitClassSelector(ClassSelector node);
+ dynamic visitPseudoClassSelector(PseudoClassSelector node);
+ dynamic visitPseudoElementSelector(PseudoElementSelector node);
+ dynamic visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node);
+ dynamic visitPseudoElementFunctionSelector(
+ PseudoElementFunctionSelector node);
+ dynamic visitNegationSelector(NegationSelector node);
+ dynamic visitSelectorExpression(SelectorExpression node);
+
+ dynamic visitUnicodeRangeTerm(UnicodeRangeTerm node);
+ dynamic visitLiteralTerm(LiteralTerm node);
+ dynamic visitHexColorTerm(HexColorTerm node);
+ dynamic visitNumberTerm(NumberTerm node);
+ dynamic visitUnitTerm(UnitTerm node);
+ dynamic visitLengthTerm(LengthTerm node);
+ dynamic visitPercentageTerm(PercentageTerm node);
+ dynamic visitEmTerm(EmTerm node);
+ dynamic visitExTerm(ExTerm node);
+ dynamic visitAngleTerm(AngleTerm node);
+ dynamic visitTimeTerm(TimeTerm node);
+ dynamic visitFreqTerm(FreqTerm node);
+ dynamic visitFractionTerm(FractionTerm node);
+ dynamic visitUriTerm(UriTerm node);
+ dynamic visitResolutionTerm(ResolutionTerm node);
+ dynamic visitChTerm(ChTerm node);
+ dynamic visitRemTerm(RemTerm node);
+ dynamic visitViewportTerm(ViewportTerm node);
+ dynamic visitLineHeightTerm(LineHeightTerm node);
+ dynamic visitFunctionTerm(FunctionTerm node);
+ dynamic visitGroupTerm(GroupTerm node);
+ dynamic visitItemTerm(ItemTerm node);
+ dynamic visitIE8Term(IE8Term node);
+ dynamic visitOperatorSlash(OperatorSlash node);
+ dynamic visitOperatorComma(OperatorComma node);
+ dynamic visitOperatorPlus(OperatorPlus node);
+ dynamic visitOperatorMinus(OperatorMinus node);
+ dynamic visitVarUsage(VarUsage node);
+
+ dynamic visitExpressions(Expressions node);
+ dynamic visitBinaryExpression(BinaryExpression node);
+ dynamic visitUnaryExpression(UnaryExpression node);
+
+ dynamic visitIdentifier(Identifier node);
+ dynamic visitWildcard(Wildcard node);
+ dynamic visitThisOperator(ThisOperator node);
+ dynamic visitNegation(Negation node);
+
+ dynamic visitDartStyleExpression(DartStyleExpression node);
+ dynamic visitFontExpression(FontExpression node);
+ dynamic visitBoxExpression(BoxExpression node);
+ dynamic visitMarginExpression(MarginExpression node);
+ dynamic visitBorderExpression(BorderExpression node);
+ dynamic visitHeightExpression(HeightExpression node);
+ dynamic visitPaddingExpression(PaddingExpression node);
+ dynamic visitWidthExpression(WidthExpression node);
+}
+
+/// Base vistor class for the style sheet AST.
+class Visitor implements VisitorBase {
+ /// Helper function to walk a list of nodes.
+ void _visitNodeList(List<TreeNode> list) {
+ // Don't use iterable otherwise the list can't grow while using Visitor.
+ // It certainly can't have items deleted before the index being iterated
+ // but items could be added after the index.
+ for (var index = 0; index < list.length; index++) {
+ list[index].visit(this);
+ }
+ }
+
+ dynamic visitTree(StyleSheet tree) => visitStyleSheet(tree);
+
+ @override
+ dynamic visitStyleSheet(StyleSheet ss) {
+ _visitNodeList(ss.topLevels);
+ }
+
+ @override
+ dynamic visitNoOp(NoOp node) {}
+
+ @override
+ dynamic visitTopLevelProduction(TopLevelProduction node) {}
+
+ @override
+ dynamic visitDirective(Directive node) {}
+
+ @override
+ dynamic visitCalcTerm(CalcTerm node) {
+ visitLiteralTerm(node);
+ visitLiteralTerm(node.expr);
+ }
+
+ @override
+ dynamic visitCssComment(CssComment node) {}
+
+ @override
+ dynamic visitCommentDefinition(CommentDefinition node) {}
+
+ @override
+ dynamic visitMediaExpression(MediaExpression node) {
+ visitExpressions(node.exprs);
+ }
+
+ @override
+ dynamic visitMediaQuery(MediaQuery node) {
+ for (var mediaExpr in node.expressions) {
+ visitMediaExpression(mediaExpr);
+ }
+ }
+
+ @override
+ dynamic visitDocumentDirective(DocumentDirective node) {
+ _visitNodeList(node.functions);
+ _visitNodeList(node.groupRuleBody);
+ }
+
+ @override
+ dynamic visitSupportsDirective(SupportsDirective node) {
+ node.condition!.visit(this);
+ _visitNodeList(node.groupRuleBody);
+ }
+
+ @override
+ dynamic visitSupportsConditionInParens(SupportsConditionInParens node) {
+ node.condition!.visit(this);
+ }
+
+ @override
+ dynamic visitSupportsNegation(SupportsNegation node) {
+ node.condition.visit(this);
+ }
+
+ @override
+ dynamic visitSupportsConjunction(SupportsConjunction node) {
+ _visitNodeList(node.conditions);
+ }
+
+ @override
+ dynamic visitSupportsDisjunction(SupportsDisjunction node) {
+ _visitNodeList(node.conditions);
+ }
+
+ @override
+ dynamic visitViewportDirective(ViewportDirective node) {
+ node.declarations.visit(this);
+ }
+
+ @override
+ dynamic visitMediaDirective(MediaDirective node) {
+ _visitNodeList(node.mediaQueries);
+ _visitNodeList(node.rules);
+ }
+
+ @override
+ dynamic visitHostDirective(HostDirective node) {
+ _visitNodeList(node.rules);
+ }
+
+ @override
+ dynamic visitPageDirective(PageDirective node) {
+ for (var declGroup in node._declsMargin) {
+ if (declGroup is MarginGroup) {
+ visitMarginGroup(declGroup);
+ } else {
+ visitDeclarationGroup(declGroup);
+ }
+ }
+ }
+
+ @override
+ dynamic visitCharsetDirective(CharsetDirective node) {}
+
+ @override
+ dynamic visitImportDirective(ImportDirective node) {
+ for (var mediaQuery in node.mediaQueries) {
+ visitMediaQuery(mediaQuery);
+ }
+ }
+
+ @override
+ dynamic visitKeyFrameDirective(KeyFrameDirective node) {
+ visitIdentifier(node.name!);
+ _visitNodeList(node._blocks);
+ }
+
+ @override
+ dynamic visitKeyFrameBlock(KeyFrameBlock node) {
+ visitExpressions(node._blockSelectors);
+ visitDeclarationGroup(node._declarations);
+ }
+
+ @override
+ dynamic visitFontFaceDirective(FontFaceDirective node) {
+ visitDeclarationGroup(node._declarations);
+ }
+
+ @override
+ dynamic visitStyletDirective(StyletDirective node) {
+ _visitNodeList(node.rules);
+ }
+
+ @override
+ dynamic visitNamespaceDirective(NamespaceDirective node) {}
+
+ @override
+ dynamic visitVarDefinitionDirective(VarDefinitionDirective node) {
+ visitVarDefinition(node.def);
+ }
+
+ @override
+ dynamic visitMixinRulesetDirective(MixinRulesetDirective node) {
+ _visitNodeList(node.rulesets);
+ }
+
+ @override
+ dynamic visitMixinDefinition(MixinDefinition node) {}
+
+ @override
+ dynamic visitMixinDeclarationDirective(MixinDeclarationDirective node) {
+ visitDeclarationGroup(node.declarations);
+ }
+
+ @override
+ dynamic visitIncludeDirective(IncludeDirective node) {
+ for (var index = 0; index < node.args.length; index++) {
+ var param = node.args[index];
+ _visitNodeList(param);
+ }
+ }
+
+ @override
+ dynamic visitContentDirective(ContentDirective node) {
+ // TODO(terry): TBD
+ }
+
+ @override
+ dynamic visitRuleSet(RuleSet node) {
+ visitSelectorGroup(node.selectorGroup!);
+ visitDeclarationGroup(node.declarationGroup);
+ }
+
+ @override
+ dynamic visitDeclarationGroup(DeclarationGroup node) {
+ _visitNodeList(node.declarations);
+ }
+
+ @override
+ dynamic visitMarginGroup(MarginGroup node) => visitDeclarationGroup(node);
+
+ @override
+ dynamic visitDeclaration(Declaration node) {
+ visitIdentifier(node._property!);
+ if (node.expression != null) node.expression!.visit(this);
+ }
+
+ @override
+ dynamic visitVarDefinition(VarDefinition node) {
+ visitIdentifier(node._property!);
+ if (node.expression != null) node.expression!.visit(this);
+ }
+
+ @override
+ dynamic visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) {
+ visitIncludeDirective(node.include);
+ }
+
+ @override
+ dynamic visitExtendDeclaration(ExtendDeclaration node) {
+ _visitNodeList(node.selectors);
+ }
+
+ @override
+ dynamic visitSelectorGroup(SelectorGroup node) {
+ _visitNodeList(node.selectors);
+ }
+
+ @override
+ dynamic visitSelector(Selector node) {
+ _visitNodeList(node.simpleSelectorSequences);
+ }
+
+ @override
+ dynamic visitSimpleSelectorSequence(SimpleSelectorSequence node) {
+ node.simpleSelector.visit(this);
+ }
+
+ @override
+ dynamic visitSimpleSelector(SimpleSelector node) =>
+ (node._name as TreeNode).visit(this);
+
+ @override
+ dynamic visitNamespaceSelector(NamespaceSelector node) {
+ if (node._namespace != null) (node._namespace as TreeNode).visit(this);
+ if (node.nameAsSimpleSelector != null) {
+ node.nameAsSimpleSelector!.visit(this);
+ }
+ }
+
+ @override
+ dynamic visitElementSelector(ElementSelector node) =>
+ visitSimpleSelector(node);
+
+ @override
+ dynamic visitAttributeSelector(AttributeSelector node) {
+ visitSimpleSelector(node);
+ }
+
+ @override
+ dynamic visitIdSelector(IdSelector node) => visitSimpleSelector(node);
+
+ @override
+ dynamic visitClassSelector(ClassSelector node) => visitSimpleSelector(node);
+
+ @override
+ dynamic visitPseudoClassSelector(PseudoClassSelector node) =>
+ visitSimpleSelector(node);
+
+ @override
+ dynamic visitPseudoElementSelector(PseudoElementSelector node) =>
+ visitSimpleSelector(node);
+
+ @override
+ dynamic visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) =>
+ visitSimpleSelector(node);
+
+ @override
+ dynamic visitPseudoElementFunctionSelector(
+ PseudoElementFunctionSelector node) =>
+ visitSimpleSelector(node);
+
+ @override
+ dynamic visitNegationSelector(NegationSelector node) =>
+ visitSimpleSelector(node);
+
+ @override
+ dynamic visitSelectorExpression(SelectorExpression node) {
+ _visitNodeList(node.expressions);
+ }
+
+ @override
+ dynamic visitUnicodeRangeTerm(UnicodeRangeTerm node) {}
+
+ @override
+ dynamic visitLiteralTerm(LiteralTerm node) {}
+
+ @override
+ dynamic visitHexColorTerm(HexColorTerm node) {}
+
+ @override
+ dynamic visitNumberTerm(NumberTerm node) {}
+
+ @override
+ dynamic visitUnitTerm(UnitTerm node) {}
+
+ @override
+ dynamic visitLengthTerm(LengthTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitPercentageTerm(PercentageTerm node) {
+ visitLiteralTerm(node);
+ }
+
+ @override
+ dynamic visitEmTerm(EmTerm node) {
+ visitLiteralTerm(node);
+ }
+
+ @override
+ dynamic visitExTerm(ExTerm node) {
+ visitLiteralTerm(node);
+ }
+
+ @override
+ dynamic visitAngleTerm(AngleTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitTimeTerm(TimeTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitFreqTerm(FreqTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitFractionTerm(FractionTerm node) {
+ visitLiteralTerm(node);
+ }
+
+ @override
+ dynamic visitUriTerm(UriTerm node) {
+ visitLiteralTerm(node);
+ }
+
+ @override
+ dynamic visitResolutionTerm(ResolutionTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitChTerm(ChTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitRemTerm(RemTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitViewportTerm(ViewportTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitLineHeightTerm(LineHeightTerm node) {
+ visitUnitTerm(node);
+ }
+
+ @override
+ dynamic visitFunctionTerm(FunctionTerm node) {
+ visitLiteralTerm(node);
+ visitExpressions(node._params);
+ }
+
+ @override
+ dynamic visitGroupTerm(GroupTerm node) {
+ for (var term in node._terms) {
+ term.visit(this);
+ }
+ }
+
+ @override
+ dynamic visitItemTerm(ItemTerm node) {
+ visitNumberTerm(node);
+ }
+
+ @override
+ dynamic visitIE8Term(IE8Term node) {}
+
+ @override
+ dynamic visitOperatorSlash(OperatorSlash node) {}
+
+ @override
+ dynamic visitOperatorComma(OperatorComma node) {}
+
+ @override
+ dynamic visitOperatorPlus(OperatorPlus node) {}
+
+ @override
+ dynamic visitOperatorMinus(OperatorMinus node) {}
+
+ @override
+ dynamic visitVarUsage(VarUsage node) {
+ _visitNodeList(node.defaultValues);
+ }
+
+ @override
+ dynamic visitExpressions(Expressions node) {
+ _visitNodeList(node.expressions);
+ }
+
+ @override
+ dynamic visitBinaryExpression(BinaryExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError();
+ }
+
+ @override
+ dynamic visitUnaryExpression(UnaryExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError();
+ }
+
+ @override
+ dynamic visitIdentifier(Identifier node) {}
+
+ @override
+ dynamic visitWildcard(Wildcard node) {}
+
+ @override
+ dynamic visitThisOperator(ThisOperator node) {}
+
+ @override
+ dynamic visitNegation(Negation node) {}
+
+ @override
+ dynamic visitDartStyleExpression(DartStyleExpression node) {}
+
+ @override
+ dynamic visitFontExpression(FontExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError();
+ }
+
+ @override
+ dynamic visitBoxExpression(BoxExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError();
+ }
+
+ @override
+ dynamic visitMarginExpression(MarginExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError();
+ }
+
+ @override
+ dynamic visitBorderExpression(BorderExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError();
+ }
+
+ @override
+ dynamic visitHeightExpression(HeightExpression node) {
+ // TODO(terry): TB
+ throw UnimplementedError();
+ }
+
+ @override
+ dynamic visitPaddingExpression(PaddingExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError();
+ }
+
+ @override
+ dynamic visitWidthExpression(WidthExpression node) {
+ // TODO(terry): TBD
+ throw UnimplementedError();
+ }
+}
diff --git a/pkgs/csslib/pubspec.yaml b/pkgs/csslib/pubspec.yaml
new file mode 100644
index 0000000..74e2069
--- /dev/null
+++ b/pkgs/csslib/pubspec.yaml
@@ -0,0 +1,20 @@
+name: csslib
+version: 1.0.2
+description: A library for parsing and analyzing CSS (Cascading Style Sheets).
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/csslib
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acsslib
+
+topics:
+ - css
+
+environment:
+ sdk: ^3.1.0
+
+dependencies:
+ source_span: ^1.8.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ path: ^1.8.0
+ term_glyph: ^1.2.0
+ test: ^1.16.0
diff --git a/pkgs/csslib/test/big_1_test.dart b/pkgs/csslib/test/big_1_test.dart
new file mode 100644
index 0000000..6db7980
--- /dev/null
+++ b/pkgs/csslib/test/big_1_test.dart
@@ -0,0 +1,1165 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/src/messages.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void compilePolyfillAndValidate(String input, String generated) {
+ var errors = <Message>[];
+ var stylesheet = polyFillCompileCss(input, errors: errors, opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void bigTest() {
+ var input = r'''
+/********************************************************************
+ * Kennedy colors
+ ********************************************************************/
+@kennedy-red: #dd4b39;
+@kennedy-blue: #4d90fe;
+@kennedy-green: #3d9400;
+
+/********************************************************************
+ * link colors
+ ********************************************************************/
+@link-color-1: #1155cc;
+@link-color-2: #666666;
+
+/********************************************************************
+ * text and header colors
+ ********************************************************************/
+@text-color-emphasized-1: #222222;
+@text-color-emphasized-2: #333333;
+@text-color-regular: #666666;
+@text-color-deemphasized-1: #777777;
+@text-color-deemphasized-2: #999999;
+
+/********************************************************************
+ * icon colors
+ ********************************************************************/
+@zippy-icon-color: #b2b2b2;
+@zippy-icon-color-hover: #666666;
+
+@mutate-icon-color: #b2b2b2;
+
+@silhouette-color: #8bb7fe;
+
+/********************************************************************
+ * Panel and Card colors
+ ********************************************************************/
+@panel-header-color: #f7f7f7;
+@panel-body-color: #ffffff;
+@panel-border-color: #dcdcdc;
+
+/********************************************************************
+ * App area colors
+ ********************************************************************/
+ @apparea-background-color: #f2f2f2;
+
+/********************************************************************
+ * Table colors
+ ********************************************************************/
+@table-row-numbers: #666666;
+@table-row-item-links: #1155cc;
+@table-row-item: #666666;
+
+/* Borders */
+@table-border-color: #dcdcdc;
+@table-header-border-color: #dcdcdc;
+@table-row-data-border-color: #eaeaea;
+
+/* General column - USED: We are not currently spec'ing different colors
+ * for the currently sorted/unsorted on column.
+ */
+@table-header-label-color: #666666;
+@table-header-background-color: #f8f8f8;
+@table-column-background-color: #ffffff;
+
+
+/* Sorted column - UNUSED: We are not currently spec'ing different colors
+ * for the currently sorted/unsorted on column.
+ */
+@table-sorted-header-label-color: #666666;
+@table-sorted-header-background-color: #e6e6e6;
+@table-sorted-column-background-color: #f8f8f8;
+
+/* Unsorted column - UNUSED: We are not currently spec'ing different colors
+ * for the currently sorted/unsorted on column.
+ */
+@table-unsorted-header-label-color: #999999;
+@table-unsorted-header-background-color: #f8f8f8;
+@table-unsorted-column-background-color: #ffffff;
+
+@acux-border-color-1: #e5e5e5;
+@acux-border-color-2: #3b7bea;
+@acux-link-color: #3b7bea;
+@acux-shell-background-color: #f2f2f2;
+
+/********************************************************************
+ * Tooltip and popup colors
+ ********************************************************************/
+@tooltip-border-color: #333;
+@tooltip-color: #fff;
+@popup-border-color: #fff;
+
+/* Border radii */
+@button-radius: 2px;
+
+@mixin button-gradient(@from, @to) {
+ background-color: @from;
+ background-image: -webkit-linear-gradient(top, @from, @to);
+ background-image: linear-gradient(top, @from, @to);
+}
+
+@mixin button-transition(@property, @time) {
+ -webkit-transition: @property @time;
+ transition: @property @time;
+}
+
+@mixin text-not-selectable() {
+ -webkit-user-select: none;
+ user-select: none;
+}
+
+/*
+ * Buttons and their states
+ */
+@mixin btn-base {
+ display: inline-block;
+ min-width: 62px;
+ text-align: center;
+ font-size: 11px;
+ font-weight: bold;
+ height: 28px;
+ padding: 0 8px;
+ line-height: 27px;
+ border-radius: @button-radius;
+ cursor: default;
+
+ color: #444;
+ border: 1px solid rgba(0,0,0,0.1);
+ @include button-transition(all, 0.218s);
+ @include button-gradient(#f5f5f5, #f1f1f1);
+
+ &:hover {
+ border: 1px solid #C6C6C6;
+ color: #222;
+ box-shadow: 0px 1px 1px rgba(0,0,0,0.1);
+ @include button-transition(all, 0s);
+ @include button-gradient(#f8f8f8, #f1f1f1);
+ }
+
+ &:active {
+ border: 1px solid #C6C6C6;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0,0,0,0.1);
+ @include button-gradient(#f6f6f6, #f1f1f1);
+ }
+
+ &:focus {
+ outline: none;
+ border: 1px solid #4D90FE;
+ z-index: 4 !important;
+ }
+
+ &.selected, &.popup-open {
+ border: 1px solid #CCC;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0,0,0,0.1);
+ @include button-gradient(#EEEEEE, #E0E0E0);
+ }
+
+ &.disabled, &.disabled:hover, &.disabled:active,
+ &[disabled], &[disabled]:hover, &[disabled]:active {
+ background: none;
+ color: #b8b8b8;
+ border: 1px solid rgba(0,0,0,0.05);
+ cursor: default;
+ pointer-events: none;
+ }
+
+ &.flat {
+ background: none;
+ border-color: transparent;
+ padding: 0;
+ box-shadow: none;
+ }
+
+ &.invalid {
+ outline: none;
+ border: 1px solid @kennedy-red;
+ box-shadow: inset 0px 1px 2px rgba(0,0,0,0.3);
+ }
+}
+
+.btn-container {
+ padding: 10px;
+}
+
+.btn {
+ @include btn-base;
+}
+
+.btn-small {
+ /* TODO(prsd): Implement using a mix-in. */
+ min-width: 30px;
+}
+
+.btn-left {
+ @include btn-base;
+ border-radius: @button-radius 0 0 @button-radius;
+ margin-right: 0;
+ padding: 0;
+ min-width: 30px;
+}
+
+.btn-right {
+ @include btn-base;
+ border-radius: 0 @button-radius @button-radius 0;
+ border-left: none;
+ margin-left: 0;
+ padding: 0;
+ min-width: 30px;
+}
+
+.btn + .btn {
+ margin-left: 5px;
+}
+
+/* Primary Button and it's states */
+.btn-primary {
+ color: #FFF !important;
+ width: 94px;
+ border-color: #3079ed;
+ @include button-gradient(#4d90fe, #4787ed);
+
+ &:hover, &:active {
+ border-color: #2f5bb7;
+ @include button-gradient(#4d90fe, #357ae8);
+ }
+
+ &:focus {
+ border-color: #4D90FE;
+ box-shadow:inset 0 0 0 1px rgba(255,255,255,0.5);
+ }
+
+ &:focus:hover {
+ box-shadow:inset 0 0 0 1px #fff, 0px 1px 1px rgba(0,0,0,0.1);
+ }
+
+ &.disabled, &.disabled:hover, &.disabled:active,
+ &[disabled], &[disabled]:hover, &[disabled]:active {
+ border-color:#3079ed;
+ background-color: #4d90fe;
+ opacity: 0.7;
+ }
+}
+
+/* Checkbox displayed as a toggled button
+ * Invisible checkbox followed by a label with 'for' set to checkbox */
+input[type="checkbox"].toggle-button {
+ display: none;
+
+ & + label {
+ @extend .btn;
+ }
+
+ &:checked + label,
+ & + label.popup-open {
+ border: 1px solid #CCC;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0,0,0,0.1);
+ @include button-gradient(#EEEEEE, #E0E0E0);
+ }
+}
+
+.txt-input {
+ display:inline-block;
+ *display:inline;
+ *zoom:1;
+ padding:4px 12px;
+ margin-bottom:0;
+ font-size:14px;
+ line-height:20px;
+ vertical-align:middle;
+ color:#333333;
+ border-color:#e6e6e6 #e6e6e6 #bfbfbf;
+ border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ border:1px solid #cccccc;
+ *border:0;
+ border-bottom-color:#b3b3b3;
+ -webkit-border-radius:4px;
+ -moz-border-radius:4px;
+ border-radius:4px;
+ *margin-left:.3em;
+ -webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px
+ rgba(0,0,0,.05);
+ -moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+ box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
+}
+
+input[type="text"], input:not([type]), .txt-input {
+ height: 29px;
+ background-color: white;
+ padding: 4px 0 4px 8px;
+ color: 333;
+ border: 1px solid #d9d9d9;
+ border-top: 1px solid #c0c0c0;
+ display: inline-block;
+ vertical-align: top;
+ box-sizing: border-box;
+ border-radius: 1px;
+
+ &:hover {
+ border: 1px solid #b9b9b9;
+ border-top: 1px solid #a0a0a0;
+ box-shadow: inset 0px 1px 2px rgba(0,0,0,0.1);
+ }
+
+ &:focus {
+ outline: none;
+ border: 1px solid @kennedy-blue;
+ box-shadow: inset 0px 1px 2px rgba(0,0,0,0.3);
+ }
+
+ &.disabled, &.disabled:hover, &.disabled:active, &:disabled {
+ background: #fff;
+ border: 1px solid #f3f3f3;
+ border: 1px solid rgba(0,0,0,0.05);
+ color: #b8b8b8;
+ cursor: default;
+ pointer-events: none;
+ }
+
+ &.invalid, &:focus:invalid, &:required:invalid {
+ outline: none;
+ border: 1px solid @kennedy-red;
+ box-shadow: inset 0px 1px 2px rgba(0,0,0,0.3);
+ }
+}
+
+/* Text area */
+textarea {
+ @extend .txt-input;
+ height: 3em;
+}
+
+/* Hide the spin button in datepickers */
+input[type="date"]::-webkit-inner-spin-button,
+input[type="datetime"]::-webkit-inner-spin-button,
+input[type="datetime-local"]::-webkit-inner-spin-button,
+input[type="month"]::-webkit-inner-spin-button,
+input[type="time"]::-webkit-inner-spin-button,
+input[type="week"]::-webkit-inner-spin-button {
+ display: none;
+}
+
+
+/*
+ * Selects & Dropdowns
+ */
+.dropdown-menu,
+.popup {
+ width: auto;
+ padding: 0;
+ margin: 0 0 0 1px;
+ background: white;
+ text-align: left;
+ z-index: 1000;
+ outline: 1px solid rgba(0,0,0,0.2);
+ white-space: nowrap;
+ list-style: none;
+ box-shadow: 0px 2px 4px rgba(0,0,0,0.2);
+ @include button-transition(opacity, 0.218s);
+}
+
+.popup {
+ padding: 0 0 6px;
+}
+.dropdown-menu,
+.popup {
+ pointer-events: all;
+}
+
+.popup ul {
+ margin: 0;
+ padding: 0;
+}
+.popup li {
+ list-style-type: none;
+ padding: 5px 10px;
+ cursor: default;
+}
+.popup .header {
+ padding: 5px 10px;
+}
+
+ /* existing styles defined here */
+.popup .divider,
+.dropdown-menu .divider {
+ width:100%;
+ height:1px;
+ padding: 0;
+ overflow:hidden;
+ background-color:#c0c0c0;
+ border-bottom:1px solid @popup-border-color;
+}
+
+.dropdown-menu {
+ max-height: 600px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.popup {
+ overflow: hidden;
+}
+
+.dropdown-menuitem,
+.dropdown-menu > li {
+ display: block;
+ padding: 6px 44px 6px 16px;
+ color: #666;
+ font-size:13px;
+ font-weight: normal;
+ cursor: default;
+ margin: 0;
+ text-decoration: none;
+ @include text-not-selectable();
+
+ &.disabled {
+ color: #CCC;
+ background-color: #FFF;
+ }
+
+ &:hover, &.selected {
+ color: #222;
+ background-color: #F1F1F1;
+ }
+}
+
+.dropdown-menuheader {
+ padding: 6px 44px 6px 16px;
+ color: #666;
+ font-size:11px;
+ font-weight: bold;
+ cursor: default;
+ margin: 0;
+ text-decoration: none;
+ background-color: #F1F1F1;
+ @include text-not-selectable();
+}
+
+li.dropdown-menudivider {
+ width:100%;
+ height:1px;
+ padding: 0;
+ overflow:hidden;
+ background-color:#D0D0D0;
+ border-bottom:1px solid #ffffff;
+}
+
+.btn-container {
+ padding: 10px;
+}
+
+/*
+ * Modal dialogs
+ */
+
+.modal-frame {
+ position: relative;
+ background-color: white;
+ outline: 1px solid rgba(0, 0, 0, 0.2);
+ padding: 30px 42px;
+ min-width: 480px;
+ z-index: 9000;
+ pointer-events: auto;
+ box-shadow: 0 4px 16px 0 rgba(0,0,0,0.2);
+
+ @include button-transition(all, 0.218s);
+
+ &.medium {
+ padding: 28px 32px;
+ min-width: 280px;
+ }
+
+ &.small {
+ padding: 16px 20px;
+ }
+
+}
+
+.modal-backdrop {
+ background-color: rgba(0,0,0,0.1);
+ position: fixed;
+ height: 100%;
+ width: 100%;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 99;
+ margin: 0;
+
+ display: none;
+ opacity: 0;
+ @include button-transition(all, 0.218s);
+
+ &.visible {
+ display: -webkit-flex;
+ display: flex;
+ -webkit-align-items: center;
+ align-items: center;
+ -webkit-justify-content: space-around;
+ justify-content: space-around;
+ opacity: 1;
+ }
+}
+
+/*
+ * Scrollbars
+ */
+
+::-webkit-scrollbar {
+ width: 10px;
+ height: 10px;
+ background: white;
+}
+
+::-webkit-scrollbar-button {
+ height: 0px;
+ width: 0px;
+
+ &:start:decrement,
+ &:end:increment {
+ display: block;
+ }
+
+ &:vertical:start:increment,
+ &:vertical:end:decrement {
+ display: none;
+ }
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: rgba(0, 0, 0, .2);
+ background-clip: padding-box;
+ border: solid transparent;
+ border-width: 1px 1px 1px 2px;
+ min-height: 28px;
+ padding: 100px 0 0;
+ box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1),
+ inset 0 -1px 0 rgba(0, 0, 0, .07);
+
+ &:hover {
+ background-color: rgba(0,0,0,0.4);
+ -webkit-box-shadow: inset 1px 1px 1px rgba(0,0,0,0.25);
+ }
+
+ &:active {
+ -webkit-box-shadow: inset 1px 1px 3px rgba(0,0,0,0.35);
+ background-color: rgba(0,0,0,0.5);
+ }
+
+ &:vertical {
+ border-top: 0px solid transparent;
+ border-bottom: 0px solid transparent;
+ border-right: 0px solid transparent;
+ border-left: 1px solid transparent;
+ }
+
+ &:horizontal {
+ border-top: 1px solid transparent;
+ border-bottom: 0px solid transparent;
+ border-right: 0px solid transparent;
+ border-left: 0px solid transparent;
+ }
+}
+
+::-webkit-scrollbar-track {
+ background-clip: padding-box;
+ background-color: white;
+
+ &:hover {
+ background-color: rgba(0,0,0,0.05);
+ -webkit-box-shadow: inset 1px 0px 0px rgba(0,0,0,0.10);
+ }
+
+ &:active {
+ background-color: rgba(0,0,0,0.05);
+ -webkit-box-shadow: inset 1px 0px 0px rgba(0,0,0,0.14),
+ inset -1px -1px 0px rgba(0,0,0,0.07);
+ }
+
+ &:vertical {
+ border-right: 0px solid transparent;
+ border-left: 1px solid transparent;
+ }
+
+ &:horizontal {
+ border-bottom: 0px solid transparent;
+ border-top: 1px solid transparent;
+ }
+}
+
+/* Tooltips */
+.tooltip {
+ background: @tooltip-border-color;
+ border-radius: 2px;
+ color: @tooltip-color;
+ padding: 4px 8px;
+ font-size: 10px;
+}
+
+.tooltip a,
+.tooltip div,
+.tooltip span {
+ color: @tooltip-color;
+}
+''';
+
+ var generated = r'''.btn-container {
+ padding: 10px;
+}
+.btn, input[type="checkbox"].toggle-button + label {
+ display: inline-block;
+ min-width: 62px;
+ text-align: center;
+ font-size: 11px;
+ font-weight: bold;
+ height: 28px;
+ padding: 0 8px;
+ line-height: 27px;
+ border-radius: 2px;
+ cursor: default;
+ color: #444;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ -webkit-transition: all 0.218s;
+ transition: all 0.218s;
+ background-color: #f5f5f5;
+ background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
+ background-image: linear-gradient(top, #f5f5f5, #f1f1f1);
+}
+.btn:hover, input[type="checkbox"].toggle-button + label:hover {
+ border: 1px solid #C6C6C6;
+ color: #222;
+ box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
+ -webkit-transition: all 0s;
+ transition: all 0s;
+ background-color: #f8f8f8;
+ background-image: -webkit-linear-gradient(top, #f8f8f8, #f1f1f1);
+ background-image: linear-gradient(top, #f8f8f8, #f1f1f1);
+}
+.btn:active, input[type="checkbox"].toggle-button + label:active {
+ border: 1px solid #C6C6C6;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1);
+ background-color: #f6f6f6;
+ background-image: -webkit-linear-gradient(top, #f6f6f6, #f1f1f1);
+ background-image: linear-gradient(top, #f6f6f6, #f1f1f1);
+}
+.btn:focus, input[type="checkbox"].toggle-button + label:focus {
+ outline: none;
+ border: 1px solid #4D90FE;
+ z-index: 4 !important;
+}
+.btn.selected, .btn.popup-open, input[type="checkbox"].toggle-button + label.selected, input[type="checkbox"].toggle-button + label.popup-open {
+ border: 1px solid #CCC;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1);
+ background-color: #EEE;
+ background-image: -webkit-linear-gradient(top, #EEE, #E0E0E0);
+ background-image: linear-gradient(top, #EEE, #E0E0E0);
+}
+.btn.disabled, .btn.disabled:hover, .btn.disabled:active, .btn[disabled], .btn[disabled]:hover, .btn[disabled]:active, input[type="checkbox"].toggle-button + label.disabled, input[type="checkbox"].toggle-button + label.disabled:hover, input[type="checkbox"].toggle-button + label.disabled:active, input[type="checkbox"].toggle-button + label[disabled], input[type="checkbox"].toggle-button + label[disabled]:hover, input[type="checkbox"].toggle-button + label[disabled]:active {
+ background: none;
+ color: #b8b8b8;
+ border: 1px solid rgba(0, 0, 0, 0.05);
+ cursor: default;
+ pointer-events: none;
+}
+.btn.flat, input[type="checkbox"].toggle-button + label.flat {
+ background: none;
+ border-color: transparent;
+ padding: 0;
+ box-shadow: none;
+}
+.btn.invalid, input[type="checkbox"].toggle-button + label.invalid {
+ outline: none;
+ border: 1px solid #dd4b39;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.3);
+}
+.btn-small {
+ min-width: 30px;
+}
+.btn-left {
+ display: inline-block;
+ min-width: 62px;
+ text-align: center;
+ font-size: 11px;
+ font-weight: bold;
+ height: 28px;
+ padding: 0 8px;
+ line-height: 27px;
+ border-radius: 2px;
+ cursor: default;
+ color: #444;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ -webkit-transition: all 0.218s;
+ transition: all 0.218s;
+ background-color: #f5f5f5;
+ background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
+ background-image: linear-gradient(top, #f5f5f5, #f1f1f1);
+ border-radius: 2px 0 0 2px;
+ margin-right: 0;
+ padding: 0;
+ min-width: 30px;
+}
+.btn-left:hover {
+ border: 1px solid #C6C6C6;
+ color: #222;
+ box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
+ -webkit-transition: all 0s;
+ transition: all 0s;
+ background-color: #f8f8f8;
+ background-image: -webkit-linear-gradient(top, #f8f8f8, #f1f1f1);
+ background-image: linear-gradient(top, #f8f8f8, #f1f1f1);
+}
+.btn-left:active {
+ border: 1px solid #C6C6C6;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1);
+ background-color: #f6f6f6;
+ background-image: -webkit-linear-gradient(top, #f6f6f6, #f1f1f1);
+ background-image: linear-gradient(top, #f6f6f6, #f1f1f1);
+}
+.btn-left:focus {
+ outline: none;
+ border: 1px solid #4D90FE;
+ z-index: 4 !important;
+}
+.btn-left.selected, .btn-left.popup-open {
+ border: 1px solid #CCC;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1);
+ background-color: #EEE;
+ background-image: -webkit-linear-gradient(top, #EEE, #E0E0E0);
+ background-image: linear-gradient(top, #EEE, #E0E0E0);
+}
+.btn-left.disabled, .btn-left.disabled:hover, .btn-left.disabled:active, .btn-left[disabled], .btn-left[disabled]:hover, .btn-left[disabled]:active {
+ background: none;
+ color: #b8b8b8;
+ border: 1px solid rgba(0, 0, 0, 0.05);
+ cursor: default;
+ pointer-events: none;
+}
+.btn-left.flat {
+ background: none;
+ border-color: transparent;
+ padding: 0;
+ box-shadow: none;
+}
+.btn-left.invalid {
+ outline: none;
+ border: 1px solid #dd4b39;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.3);
+}
+.btn-right {
+ display: inline-block;
+ min-width: 62px;
+ text-align: center;
+ font-size: 11px;
+ font-weight: bold;
+ height: 28px;
+ padding: 0 8px;
+ line-height: 27px;
+ border-radius: 2px;
+ cursor: default;
+ color: #444;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ -webkit-transition: all 0.218s;
+ transition: all 0.218s;
+ background-color: #f5f5f5;
+ background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
+ background-image: linear-gradient(top, #f5f5f5, #f1f1f1);
+ border-radius: 0 2px 2px 0;
+ border-left: none;
+ margin-left: 0;
+ padding: 0;
+ min-width: 30px;
+}
+.btn-right:hover {
+ border: 1px solid #C6C6C6;
+ color: #222;
+ box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
+ -webkit-transition: all 0s;
+ transition: all 0s;
+ background-color: #f8f8f8;
+ background-image: -webkit-linear-gradient(top, #f8f8f8, #f1f1f1);
+ background-image: linear-gradient(top, #f8f8f8, #f1f1f1);
+}
+.btn-right:active {
+ border: 1px solid #C6C6C6;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1);
+ background-color: #f6f6f6;
+ background-image: -webkit-linear-gradient(top, #f6f6f6, #f1f1f1);
+ background-image: linear-gradient(top, #f6f6f6, #f1f1f1);
+}
+.btn-right:focus {
+ outline: none;
+ border: 1px solid #4D90FE;
+ z-index: 4 !important;
+}
+.btn-right.selected, .btn-right.popup-open {
+ border: 1px solid #CCC;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1);
+ background-color: #EEE;
+ background-image: -webkit-linear-gradient(top, #EEE, #E0E0E0);
+ background-image: linear-gradient(top, #EEE, #E0E0E0);
+}
+.btn-right.disabled, .btn-right.disabled:hover, .btn-right.disabled:active, .btn-right[disabled], .btn-right[disabled]:hover, .btn-right[disabled]:active {
+ background: none;
+ color: #b8b8b8;
+ border: 1px solid rgba(0, 0, 0, 0.05);
+ cursor: default;
+ pointer-events: none;
+}
+.btn-right.flat {
+ background: none;
+ border-color: transparent;
+ padding: 0;
+ box-shadow: none;
+}
+.btn-right.invalid {
+ outline: none;
+ border: 1px solid #dd4b39;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.3);
+}
+.btn + .btn, input[type="checkbox"].toggle-button + label + .btn, .btn + input[type="checkbox"].toggle-button + label, input[type="checkbox"].toggle-button + label + input[type="checkbox"].toggle-button + label, input[type="checkbox"].toggle-button + label + input[type="checkbox"].toggle-button + label {
+ margin-left: 5px;
+}
+.btn-primary {
+ color: #FFF !important;
+ width: 94px;
+ border-color: #3079ed;
+ background-color: #4d90fe;
+ background-image: -webkit-linear-gradient(top, #4d90fe, #4787ed);
+ background-image: linear-gradient(top, #4d90fe, #4787ed);
+}
+.btn-primary:hover, .btn-primary:active {
+ border-color: #2f5bb7;
+ background-color: #4d90fe;
+ background-image: -webkit-linear-gradient(top, #4d90fe, #357ae8);
+ background-image: linear-gradient(top, #4d90fe, #357ae8);
+}
+.btn-primary:focus {
+ border-color: #4D90FE;
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5);
+}
+.btn-primary:focus:hover {
+ box-shadow: inset 0 0 0 1px #fff, 0px 1px 1px rgba(0, 0, 0, 0.1);
+}
+.btn-primary.disabled, .btn-primary.disabled:hover, .btn-primary.disabled:active, .btn-primary[disabled], .btn-primary[disabled]:hover, .btn-primary[disabled]:active {
+ border-color: #3079ed;
+ background-color: #4d90fe;
+ opacity: 0.7;
+}
+input[type="checkbox"].toggle-button {
+ display: none;
+}
+input[type="checkbox"].toggle-button + label {
+}
+input[type="checkbox"].toggle-button:checked + label, input[type="checkbox"].toggle-button + label.popup-open {
+ border: 1px solid #CCC;
+ color: #666;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1);
+ background-color: #EEE;
+ background-image: -webkit-linear-gradient(top, #EEE, #E0E0E0);
+ background-image: linear-gradient(top, #EEE, #E0E0E0);
+}
+.txt-input, textarea {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ padding: 4px 12px;
+ margin-bottom: 0;
+ font-size: 14px;
+ line-height: 20px;
+ vertical-align: middle;
+ color: #333;
+ border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ border: 1px solid #ccc;
+ *border: 0;
+ border-bottom-color: #b3b3b3;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ *margin-left: .3em;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 1px 2px rgba(0, 0, 0, .05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 1px 2px rgba(0, 0, 0, .05);
+}
+input[type="text"], input:not([type]), .txt-input, textarea {
+ height: 29px;
+ background-color: #fff;
+ padding: 4px 0 4px 8px;
+ color: 333;
+ border: 1px solid #d9d9d9;
+ border-top: 1px solid #c0c0c0;
+ display: inline-block;
+ vertical-align: top;
+ box-sizing: border-box;
+ border-radius: 1px;
+}
+input[type="text"]:hover, input:not([type]):hover, .txt-input:hover, textarea:hover {
+ border: 1px solid #b9b9b9;
+ border-top: 1px solid #a0a0a0;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.1);
+}
+input[type="text"]:focus, input:not([type]):focus, .txt-input:focus, textarea:focus {
+ outline: none;
+ border: 1px solid #4d90fe;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.3);
+}
+input[type="text"].disabled, input:not([type]).disabled, .txt-input.disabled, input[type="text"].disabled:hover, input:not([type]).disabled:hover, .txt-input.disabled:hover, input[type="text"].disabled:active, input:not([type]).disabled:active, .txt-input.disabled:active, input[type="text"]:disabled, input:not([type]):disabled, .txt-input:disabled, textarea.disabled, textarea.disabled:hover, textarea.disabled:active, textarea:disabled {
+ background: #fff;
+ border: 1px solid #f3f3f3;
+ border: 1px solid rgba(0, 0, 0, 0.05);
+ color: #b8b8b8;
+ cursor: default;
+ pointer-events: none;
+}
+input[type="text"].invalid, input:not([type]).invalid, .txt-input.invalid, input[type="text"]:focus:invalid, input:not([type]):focus:invalid, .txt-input:focus:invalid, input[type="text"]:required:invalid, input:not([type]):required:invalid, .txt-input:required:invalid, textarea.invalid, textarea:focus:invalid, textarea:required:invalid {
+ outline: none;
+ border: 1px solid #dd4b39;
+ box-shadow: inset 0px 1px 2px rgba(0, 0, 0, 0.3);
+}
+textarea {
+ height: 3em;
+}
+input[type="date"]::-webkit-inner-spin-button, input[type="datetime"]::-webkit-inner-spin-button, input[type="datetime-local"]::-webkit-inner-spin-button, input[type="month"]::-webkit-inner-spin-button, input[type="time"]::-webkit-inner-spin-button, input[type="week"]::-webkit-inner-spin-button {
+ display: none;
+}
+.dropdown-menu, .popup {
+ width: auto;
+ padding: 0;
+ margin: 0 0 0 1px;
+ background: #fff;
+ text-align: left;
+ z-index: 1000;
+ outline: 1px solid rgba(0, 0, 0, 0.2);
+ white-space: nowrap;
+ list-style: none;
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2);
+ -webkit-transition: opacity 0.218s;
+ transition: opacity 0.218s;
+}
+.popup {
+ padding: 0 0 6px;
+}
+.dropdown-menu, .popup {
+ pointer-events: all;
+}
+.popup ul {
+ margin: 0;
+ padding: 0;
+}
+.popup li {
+ list-style-type: none;
+ padding: 5px 10px;
+ cursor: default;
+}
+.popup .header {
+ padding: 5px 10px;
+}
+.popup .divider, .dropdown-menu .divider {
+ width: 100%;
+ height: 1px;
+ padding: 0;
+ overflow: hidden;
+ background-color: #c0c0c0;
+ border-bottom: 1px solid #fff;
+}
+.dropdown-menu {
+ max-height: 600px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.popup {
+ overflow: hidden;
+}
+.dropdown-menuitem, .dropdown-menu > li {
+ display: block;
+ padding: 6px 44px 6px 16px;
+ color: #666;
+ font-size: 13px;
+ font-weight: normal;
+ cursor: default;
+ margin: 0;
+ text-decoration: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
+.dropdown-menuitem.disabled, .dropdown-menu > li.disabled {
+ color: #CCC;
+ background-color: #FFF;
+}
+.dropdown-menuitem:hover, .dropdown-menu > li:hover, .dropdown-menuitem.selected, .dropdown-menu > li.selected {
+ color: #222;
+ background-color: #F1F1F1;
+}
+.dropdown-menuheader {
+ padding: 6px 44px 6px 16px;
+ color: #666;
+ font-size: 11px;
+ font-weight: bold;
+ cursor: default;
+ margin: 0;
+ text-decoration: none;
+ background-color: #F1F1F1;
+ -webkit-user-select: none;
+ user-select: none;
+}
+li.dropdown-menudivider {
+ width: 100%;
+ height: 1px;
+ padding: 0;
+ overflow: hidden;
+ background-color: #D0D0D0;
+ border-bottom: 1px solid #fff;
+}
+.btn-container {
+ padding: 10px;
+}
+.modal-frame {
+ position: relative;
+ background-color: #fff;
+ outline: 1px solid rgba(0, 0, 0, 0.2);
+ padding: 30px 42px;
+ min-width: 480px;
+ z-index: 9000;
+ pointer-events: auto;
+ box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.2);
+ -webkit-transition: all 0.218s;
+ transition: all 0.218s;
+}
+.modal-frame.medium {
+ padding: 28px 32px;
+ min-width: 280px;
+}
+.modal-frame.small {
+ padding: 16px 20px;
+}
+.modal-backdrop {
+ background-color: rgba(0, 0, 0, 0.1);
+ position: fixed;
+ height: 100%;
+ width: 100%;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 99;
+ margin: 0;
+ display: none;
+ opacity: 0;
+ -webkit-transition: all 0.218s;
+ transition: all 0.218s;
+}
+.modal-backdrop.visible {
+ display: -webkit-flex;
+ display: flex;
+ -webkit-align-items: center;
+ align-items: center;
+ -webkit-justify-content: space-around;
+ justify-content: space-around;
+ opacity: 1;
+}
+::-webkit-scrollbar {
+ width: 10px;
+ height: 10px;
+ background: #fff;
+}
+::-webkit-scrollbar-button {
+ height: 0px;
+ width: 0px;
+}
+::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment {
+ display: block;
+}
+::-webkit-scrollbar-button:vertical:start:increment, ::-webkit-scrollbar-button:vertical:end:decrement {
+ display: none;
+}
+::-webkit-scrollbar-thumb {
+ background-color: rgba(0, 0, 0, .2);
+ background-clip: padding-box;
+ border: solid transparent;
+ border-width: 1px 1px 1px 2px;
+ min-height: 28px;
+ padding: 100px 0 0;
+ box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1), inset 0 -1px 0 rgba(0, 0, 0, .07);
+}
+::-webkit-scrollbar-thumb:hover {
+ background-color: rgba(0, 0, 0, 0.4);
+ -webkit-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25);
+}
+::-webkit-scrollbar-thumb:active {
+ -webkit-box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.35);
+ background-color: rgba(0, 0, 0, 0.5);
+}
+::-webkit-scrollbar-thumb:vertical {
+ border-top: 0px solid transparent;
+ border-bottom: 0px solid transparent;
+ border-right: 0px solid transparent;
+ border-left: 1px solid transparent;
+}
+::-webkit-scrollbar-thumb:horizontal {
+ border-top: 1px solid transparent;
+ border-bottom: 0px solid transparent;
+ border-right: 0px solid transparent;
+ border-left: 0px solid transparent;
+}
+::-webkit-scrollbar-track {
+ background-clip: padding-box;
+ background-color: #fff;
+}
+::-webkit-scrollbar-track:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+ -webkit-box-shadow: inset 1px 0px 0px rgba(0, 0, 0, 0.10);
+}
+::-webkit-scrollbar-track:active {
+ background-color: rgba(0, 0, 0, 0.05);
+ -webkit-box-shadow: inset 1px 0px 0px rgba(0, 0, 0, 0.14), inset -1px -1px 0px rgba(0, 0, 0, 0.07);
+}
+::-webkit-scrollbar-track:vertical {
+ border-right: 0px solid transparent;
+ border-left: 1px solid transparent;
+}
+::-webkit-scrollbar-track:horizontal {
+ border-bottom: 0px solid transparent;
+ border-top: 1px solid transparent;
+}
+.tooltip {
+ background: #333;
+ border-radius: 2px;
+ color: #fff;
+ padding: 4px 8px;
+ font-size: 10px;
+}
+.tooltip a, .tooltip div, .tooltip span {
+ color: #fff;
+}''';
+
+ compilePolyfillAndValidate(input, generated);
+}
+
+void main() {
+ test('big #1', bigTest);
+}
diff --git a/pkgs/csslib/test/color_test.dart b/pkgs/csslib/test/color_test.dart
new file mode 100644
index 0000000..9231848
--- /dev/null
+++ b/pkgs/csslib/test/color_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/parser.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('css', () {
+ test('rgb', () {
+ final color = Color.css('rgb(0, 0, 255)');
+ expect(color, equals(Color(0x0000FF)));
+ });
+
+ test('rgba', () {
+ final color = Color.css('rgba(0, 0, 255, 1.0)');
+ expect(color, equals(Color.createRgba(0, 0, 255, 1.0)));
+ });
+ });
+}
diff --git a/pkgs/csslib/test/compiler_test.dart b/pkgs/csslib/test/compiler_test.dart
new file mode 100644
index 0000000..ba0c71e
--- /dev/null
+++ b/pkgs/csslib/test/compiler_test.dart
@@ -0,0 +1,750 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void testClass() {
+ var errors = <Message>[];
+ var input = '.foobar {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var selectorSeqs =
+ ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+ expect(selectorSeqs.length, 1);
+ final simpSelector = selectorSeqs[0].simpleSelector;
+ expect(simpSelector is ClassSelector, true);
+ expect(selectorSeqs[0].isCombinatorNone, true);
+ expect(simpSelector.name, 'foobar');
+}
+
+void testClass2() {
+ var errors = <Message>[];
+ var input = '.foobar .bar .no-story {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+ expect(simpleSeqs.length, 3);
+
+ var simpSelector0 = simpleSeqs[0].simpleSelector;
+ expect(simpSelector0 is ClassSelector, true);
+ expect(simpleSeqs[0].isCombinatorNone, true);
+ expect(simpSelector0.name, 'foobar');
+
+ var simpSelector1 = simpleSeqs[1].simpleSelector;
+ expect(simpSelector1 is ClassSelector, true);
+ expect(simpleSeqs[1].isCombinatorDescendant, true);
+ expect(simpSelector1.name, 'bar');
+
+ var simpSelector2 = simpleSeqs[2].simpleSelector;
+ expect(simpSelector2 is ClassSelector, true);
+ expect(simpleSeqs[2].isCombinatorDescendant, true);
+ expect(simpSelector2.name, 'no-story');
+}
+
+void testId() {
+ var errors = <Message>[];
+ var input = '#elemId {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 1);
+ var simpSelector = simpleSeqs[0].simpleSelector;
+ expect(simpSelector is IdSelector, true);
+ expect(simpleSeqs[0].isCombinatorNone, true);
+ expect(simpSelector.name, 'elemId');
+}
+
+void testElement() {
+ var errors = <Message>[];
+ var input = 'div {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 1);
+
+ final simpSelector = simpleSeqs[0].simpleSelector;
+ expect(simpSelector is ElementSelector, true);
+ expect(simpleSeqs[0].isCombinatorNone, true);
+ expect(simpSelector.name, 'div');
+
+ input = 'div div span {}';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 3);
+
+ var simpSelector0 = simpleSeqs[0].simpleSelector;
+ expect(simpSelector0 is ElementSelector, true);
+ expect(simpleSeqs[0].isCombinatorNone, true);
+ expect(simpSelector0.name, 'div');
+
+ var simpSelector1 = simpleSeqs[1].simpleSelector;
+ expect(simpSelector1 is ElementSelector, true);
+ expect(simpleSeqs[1].isCombinatorDescendant, true);
+ expect(simpSelector1.name, 'div');
+
+ var simpSelector2 = simpleSeqs[2].simpleSelector;
+ expect(simpSelector2 is ElementSelector, true);
+ expect(simpleSeqs[2].isCombinatorDescendant, true);
+ expect(simpSelector2.name, 'span');
+}
+
+void testNamespace() {
+ var errors = <Message>[];
+ var input = 'ns1|div {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 1);
+ expect(simpleSeqs[0].simpleSelector is NamespaceSelector, true);
+ var simpSelector = simpleSeqs[0].simpleSelector as NamespaceSelector;
+ expect(simpleSeqs[0].isCombinatorNone, true);
+ expect(simpSelector.isNamespaceWildcard, false);
+ expect(simpSelector.namespace, 'ns1');
+ var elementSelector = simpSelector.nameAsSimpleSelector;
+ expect(elementSelector is ElementSelector, true);
+ expect(elementSelector!.isWildcard, false);
+ expect(elementSelector.name, 'div');
+}
+
+void testNamespace2() {
+ var errors = <Message>[];
+ var input = 'ns1|div div ns2|span .foobar {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 4);
+
+ expect(simpleSeqs[0].simpleSelector is NamespaceSelector, true);
+ var simpSelector0 = simpleSeqs[0].simpleSelector as NamespaceSelector;
+ expect(simpleSeqs[0].isCombinatorNone, true);
+ expect(simpSelector0.namespace, 'ns1');
+ var elementSelector0 = simpSelector0.nameAsSimpleSelector;
+ expect(elementSelector0 is ElementSelector, true);
+ expect(elementSelector0!.isWildcard, false);
+ expect(elementSelector0.name, 'div');
+
+ var simpSelector1 = simpleSeqs[1].simpleSelector;
+ expect(simpSelector1 is ElementSelector, true);
+ expect(simpleSeqs[1].isCombinatorDescendant, true);
+ expect(simpSelector1.name, 'div');
+
+ expect(simpleSeqs[2].simpleSelector is NamespaceSelector, true);
+ var simpSelector2 = simpleSeqs[2].simpleSelector as NamespaceSelector;
+ expect(simpleSeqs[2].isCombinatorDescendant, true);
+ expect(simpSelector2.namespace, 'ns2');
+ var elementSelector2 = simpSelector2.nameAsSimpleSelector;
+ expect(elementSelector2 is ElementSelector, true);
+ expect(elementSelector2!.isWildcard, false);
+ expect(elementSelector2.name, 'span');
+
+ var simpSelector3 = simpleSeqs[3].simpleSelector;
+ expect(simpSelector3 is ClassSelector, true);
+ expect(simpleSeqs[3].isCombinatorDescendant, true);
+ expect(simpSelector3.name, 'foobar');
+}
+
+void testSelectorGroups() {
+ var errors = <Message>[];
+ var input =
+ 'div, .foobar ,#elemId, .xyzzy .test, ns1|div div #elemId .foobar {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 5);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var groupSelector0 = ruleset.selectorGroup!.selectors[0];
+ expect(groupSelector0.simpleSelectorSequences.length, 1);
+ var selector0 = groupSelector0.simpleSelectorSequences[0];
+ var simpleSelector0 = selector0.simpleSelector;
+ expect(simpleSelector0 is ElementSelector, true);
+ expect(selector0.isCombinatorNone, true);
+ expect(simpleSelector0.name, 'div');
+
+ var groupSelector1 = ruleset.selectorGroup!.selectors[1];
+ expect(groupSelector1.simpleSelectorSequences.length, 1);
+ var selector1 = groupSelector1.simpleSelectorSequences[0];
+ var simpleSelector1 = selector1.simpleSelector;
+ expect(simpleSelector1 is ClassSelector, true);
+ expect(selector1.isCombinatorNone, true);
+ expect(simpleSelector1.name, 'foobar');
+
+ var groupSelector2 = ruleset.selectorGroup!.selectors[2];
+ expect(groupSelector2.simpleSelectorSequences.length, 1);
+ var selector2 = groupSelector2.simpleSelectorSequences[0];
+ var simpleSelector2 = selector2.simpleSelector;
+ expect(simpleSelector2 is IdSelector, true);
+ expect(selector2.isCombinatorNone, true);
+ expect(simpleSelector2.name, 'elemId');
+
+ var groupSelector3 = ruleset.selectorGroup!.selectors[3];
+ expect(groupSelector3.simpleSelectorSequences.length, 2);
+
+ var selector30 = groupSelector3.simpleSelectorSequences[0];
+ var simpleSelector30 = selector30.simpleSelector;
+ expect(simpleSelector30 is ClassSelector, true);
+ expect(selector30.isCombinatorNone, true);
+ expect(simpleSelector30.name, 'xyzzy');
+
+ var selector31 = groupSelector3.simpleSelectorSequences[1];
+ var simpleSelector31 = selector31.simpleSelector;
+ expect(simpleSelector31 is ClassSelector, true);
+ expect(selector31.isCombinatorDescendant, true);
+ expect(simpleSelector31.name, 'test');
+
+ var groupSelector4 = ruleset.selectorGroup!.selectors[4];
+ expect(groupSelector4.simpleSelectorSequences.length, 4);
+
+ var selector40 = groupSelector4.simpleSelectorSequences[0];
+ expect(selector40.simpleSelector is NamespaceSelector, true);
+ var simpleSelector40 = selector40.simpleSelector as NamespaceSelector;
+ expect(selector40.isCombinatorNone, true);
+ expect(simpleSelector40.namespace, 'ns1');
+ var elementSelector = simpleSelector40.nameAsSimpleSelector;
+ expect(elementSelector is ElementSelector, true);
+ expect(elementSelector!.isWildcard, false);
+ expect(elementSelector.name, 'div');
+
+ var selector41 = groupSelector4.simpleSelectorSequences[1];
+ var simpleSelector41 = selector41.simpleSelector;
+ expect(simpleSelector41 is ElementSelector, true);
+ expect(selector41.isCombinatorDescendant, true);
+ expect(simpleSelector41.name, 'div');
+
+ var selector42 = groupSelector4.simpleSelectorSequences[2];
+ var simpleSelector42 = selector42.simpleSelector;
+ expect(simpleSelector42 is IdSelector, true);
+ expect(selector42.isCombinatorDescendant, true);
+ expect(simpleSelector42.name, 'elemId');
+
+ var selector43 = groupSelector4.simpleSelectorSequences[3];
+ var simpleSelector43 = selector43.simpleSelector;
+ expect(selector43.isCombinatorDescendant, true);
+ expect(simpleSelector43.name, 'foobar');
+}
+
+void testCombinator() {
+ var errors = <Message>[];
+ var input = '.foobar > .bar + .no-story ~ myNs|div #elemId {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 5);
+
+ var selector0 = simpleSeqs[0];
+ var simpleSelector0 = selector0.simpleSelector;
+ expect(simpleSelector0 is ClassSelector, true);
+ expect(selector0.isCombinatorNone, true);
+ expect(simpleSelector0.name, 'foobar');
+
+ var selector1 = simpleSeqs[1];
+ var simpleSelector1 = selector1.simpleSelector;
+ expect(simpleSelector1 is ClassSelector, true);
+ expect(selector1.isCombinatorGreater, true);
+ expect(simpleSelector1.name, 'bar');
+
+ var selector2 = simpleSeqs[2];
+ var simpleSelector2 = selector2.simpleSelector;
+ expect(simpleSelector2 is ClassSelector, true);
+ expect(selector2.isCombinatorPlus, true);
+ expect(simpleSelector2.name, 'no-story');
+
+ var selector3 = simpleSeqs[3];
+ expect(selector3.simpleSelector is NamespaceSelector, true);
+ var simpleSelector3 = selector3.simpleSelector as NamespaceSelector;
+ expect(selector3.isCombinatorTilde, true);
+ expect(simpleSelector3.namespace, 'myNs');
+ var elementSelector = simpleSelector3.nameAsSimpleSelector;
+ expect(elementSelector is ElementSelector, true);
+ expect(elementSelector!.isWildcard, false);
+ expect(elementSelector.name, 'div');
+
+ var selector4 = simpleSeqs[4];
+ var simpleSelector4 = selector4.simpleSelector;
+ expect(simpleSelector4 is IdSelector, true);
+ expect(selector4.isCombinatorDescendant, true);
+ expect(simpleSelector4.name, 'elemId');
+}
+
+void testWildcard() {
+ var errors = <Message>[];
+ var input = '* {}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ var ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ var simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 1);
+ var simpSelector = simpleSeqs[0].simpleSelector;
+ expect(simpSelector is ElementSelector, true);
+ expect(simpleSeqs[0].isCombinatorNone, true);
+ expect(simpSelector.isWildcard, true);
+ expect(simpSelector.name, '*');
+
+ input = '*.foobar {}';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 2);
+
+ {
+ var selector0 = simpleSeqs[0];
+ var simpleSelector0 = selector0.simpleSelector;
+ expect(simpleSelector0 is ElementSelector, true);
+ expect(selector0.isCombinatorNone, true);
+ expect(simpleSelector0.isWildcard, true);
+ expect(simpleSelector0.name, '*');
+ }
+
+ var selector1 = simpleSeqs[1];
+ var simpleSelector1 = selector1.simpleSelector;
+ expect(simpleSelector1 is ClassSelector, true);
+ expect(selector1.isCombinatorNone, true);
+ expect(simpleSelector1.name, 'foobar');
+
+ input = 'myNs|*.foobar {}';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels.length, 1);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 2);
+
+ {
+ var selector0 = simpleSeqs[0];
+ expect(selector0.simpleSelector is NamespaceSelector, true);
+ var simpleSelector0 = selector0.simpleSelector as NamespaceSelector;
+ expect(selector0.isCombinatorNone, true);
+ expect(simpleSelector0.isNamespaceWildcard, false);
+ var elementSelector = simpleSelector0.nameAsSimpleSelector;
+ expect('myNs', simpleSelector0.namespace);
+ expect(elementSelector!.isWildcard, true);
+ expect('*', elementSelector.name);
+ }
+
+ selector1 = simpleSeqs[1];
+ simpleSelector1 = selector1.simpleSelector;
+ expect(simpleSelector1 is ClassSelector, true);
+ expect(selector1.isCombinatorNone, true);
+ expect('foobar', simpleSelector1.name);
+
+ input = '*|*.foobar {}';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(stylesheet.topLevels[0] is RuleSet, true);
+ ruleset = stylesheet.topLevels[0] as RuleSet;
+ expect(ruleset.selectorGroup!.selectors.length, 1);
+ expect(ruleset.declarationGroup.declarations.length, 0);
+
+ simpleSeqs = ruleset.selectorGroup!.selectors[0].simpleSelectorSequences;
+
+ expect(simpleSeqs.length, 2);
+
+ {
+ var selector0 = simpleSeqs[0];
+ expect(selector0.simpleSelector is NamespaceSelector, true);
+ var simpleSelector0 = selector0.simpleSelector as NamespaceSelector;
+ expect(selector0.isCombinatorNone, true);
+ expect(simpleSelector0.isNamespaceWildcard, true);
+ expect('*', simpleSelector0.namespace);
+ var elementSelector = simpleSelector0.nameAsSimpleSelector;
+ expect(elementSelector!.isWildcard, true);
+ expect('*', elementSelector.name);
+ }
+
+ selector1 = simpleSeqs[1];
+ simpleSelector1 = selector1.simpleSelector;
+ expect(simpleSelector1 is ClassSelector, true);
+ expect(selector1.isCombinatorNone, true);
+ expect('foobar', simpleSelector1.name);
+}
+
+// Test List<int> as input to parser.
+void testArrayOfChars() {
+ var errors = <Message>[];
+ var input = '<![CDATA[.foo { '
+ 'color: red; left: 20px; top: 20px; width: 100px; height:200px'
+ '}'
+ '#div {'
+ 'color : #00F578; border-color: #878787;'
+ '}]]>';
+
+ var stylesheet = parse(utf8.encode(input), errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ expect(prettyPrint(stylesheet), r'''
+.foo {
+ color: #f00;
+ left: 20px;
+ top: 20px;
+ width: 100px;
+ height: 200px;
+}
+#div {
+ color: #00F578;
+ border-color: #878787;
+}''');
+}
+
+void testPseudo() {
+ var errors = <Message>[];
+
+ final input = r'''
+html:lang(fr-ca) { quotes: '" ' ' "' }
+zoom: { }
+
+a:link { color: red }
+:link { color: blue }
+
+a:focus { background: yellow }
+a:focus:hover { background: white }
+
+p.special:first-letter {color: #ffd800}
+
+p:not(#example){
+ background-color: yellow;
+}
+
+input:not([DISABLED]){
+ background-color: yellow;
+}
+
+html|*:not(:link):not(:visited) {
+ border: 1px solid black;
+}
+
+*:not(FOO) {
+ height: 20px;
+}
+
+*|*:not(*) {
+ color: orange;
+}
+
+*|*:not(:hover) {
+ color: magenta;
+}
+
+p:nth-child(3n-3) { }
+
+div:nth-child(2n) { color : red; }
+''';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), r'''
+html:lang(fr-ca) {
+ quotes: '" ' ' "';
+}
+zoom {
+}
+a:link {
+ color: #f00;
+}
+:link {
+ color: #00f;
+}
+a:focus {
+ background: #ff0;
+}
+a:focus:hover {
+ background: #fff;
+}
+p.special:first-letter {
+ color: #ffd800;
+}
+p:not(#example) {
+ background-color: #ff0;
+}
+input:not([DISABLED]) {
+ background-color: #ff0;
+}
+html|*:not(:link):not(:visited) {
+ border: 1px solid #000;
+}
+*:not(FOO) {
+ height: 20px;
+}
+*|*:not(*) {
+ color: #ffa500;
+}
+*|*:not(:hover) {
+ color: #f0f;
+}
+p:nth-child(3n-3) {
+}
+div:nth-child(2n) {
+ color: #f00;
+}''');
+}
+
+void testAttribute() {
+ // TODO(terry): Implement
+}
+
+void testNegation() {
+ // TODO(terry): Implement
+}
+
+void testHost() {
+ var errors = <Message>[];
+ var input = '@host { '
+ ':scope {'
+ 'white-space: nowrap;'
+ 'overflow-style: marquee-line;'
+ 'overflow-x: marquee;'
+ '}'
+ '* { color: red; }'
+ '*:hover { font-weight: bold; }'
+ ':nth-child(odd) { color: blue; }'
+ '}';
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), r'''
+@host {
+ :scope {
+ white-space: nowrap;
+ overflow-style: marquee-line;
+ overflow-x: marquee;
+ }
+ * {
+ color: #f00;
+ }
+ *:hover {
+ font-weight: bold;
+ }
+ :nth-child(odd) {
+ color: #00f;
+ }
+}''');
+}
+
+void testStringEscape() {
+ var errors = <Message>[];
+ var input = r'''a { foo: '{"text" : "a\\\""}' }''';
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ expect(prettyPrint(stylesheet), r'''
+a {
+ foo: '{"text" : "a\\\""}';
+}''');
+}
+
+// TODO(terry): Move to emitter_test.dart when real emitter exist.
+void testEmitter() {
+ var errors = <Message>[];
+ var input = '.foo { '
+ 'color: red; left: 20px; top: 20px; width: 100px; height:200px'
+ '}'
+ '#div {'
+ 'color : #00F578; border-color: #878787;'
+ '}';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(prettyPrint(stylesheet), r'''
+.foo {
+ color: #f00;
+ left: 20px;
+ top: 20px;
+ width: 100px;
+ height: 200px;
+}
+#div {
+ color: #00F578;
+ border-color: #878787;
+}''');
+}
+
+void testExpressionParsing() {
+ var errors = <Message>[];
+ var input = r'''
+.foobar {
+ border-radius: calc(0 - 1px);
+ border-width: calc(0 + 1px);
+}''';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ walkTree(stylesheet);
+
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ border-radius: calc(0 - 1px);
+ border-width: calc(0 + 1px);
+}''');
+}
+
+void main() {
+ test('Classes', testClass);
+ test('Classes 2', testClass2);
+ test('Ids', testId);
+ test('Elements', testElement);
+ test('Namespace', testNamespace);
+ test('Namespace 2', testNamespace2);
+ test('Selector Groups', testSelectorGroups);
+ test('Combinator', testCombinator);
+ test('Wildcards', testWildcard);
+ test('Pseudo', testPseudo);
+ test('Attributes', testAttribute);
+ test('Negation', testNegation);
+ test('@host', testHost);
+ test('stringEscape', testStringEscape);
+ test('Parse List<int> as input', testArrayOfChars);
+ test('Simple Emitter', testEmitter);
+ test('Expression parsing', testExpressionParsing);
+}
diff --git a/pkgs/csslib/test/debug_test.dart b/pkgs/csslib/test/debug_test.dart
new file mode 100644
index 0000000..878493b
--- /dev/null
+++ b/pkgs/csslib/test/debug_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void main() {
+ test('exercise debug', () {
+ var style = parseCss(_input);
+
+ var debugValue = style.toDebugString();
+ expect(debugValue, isNotNull);
+
+ var style2 = style.clone();
+
+ expect(style2.toDebugString(), debugValue);
+ });
+}
+
+const String _input = r'''
+.foo {
+background-color: #191919;
+width: 10PX;
+height: 22mM !important;
+border-width: 20cm;
+margin-width: 33%;
+border-height: 30EM;
+width: .6in;
+length: 1.2in;
+-web-stuff: -10Px;
+}''';
diff --git a/pkgs/csslib/test/declaration_test.dart b/pkgs/csslib/test/declaration_test.dart
new file mode 100644
index 0000000..6406efd
--- /dev/null
+++ b/pkgs/csslib/test/declaration_test.dart
@@ -0,0 +1,1489 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: lines_longer_than_80_chars
+
+import 'package:csslib/src/messages.dart';
+import 'package:csslib/visitor.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void expectCss(String css, String expected) {
+ var errors = <Message>[];
+ var styleSheet = parseCss(css, errors: errors, opts: simpleOptions);
+ expect(styleSheet, isNotNull);
+ expect(errors, isEmpty);
+ expect(prettyPrint(styleSheet), expected);
+}
+
+void testSimpleTerms() {
+ var errors = <Message>[];
+ final input = r'''
+@ import url("test.css");
+.foo {
+ background-color: #191919;
+ content: "u+0041";
+ width: 10PX;
+ height: 22mM !important;
+ border-width: 20cm;
+ margin-width: 33%;
+ border-height: 30EM;
+ width: .6in;
+ length: 1.2in;
+ -web-stuff: -10Px;
+}''';
+ final generated = r'''
+@import "test.css";
+.foo {
+ background-color: #191919;
+ content: "u+0041";
+ width: 10px;
+ height: 22mm !important;
+ border-width: 20cm;
+ margin-width: 33%;
+ border-height: 30em;
+ width: .6in;
+ length: 1.2in;
+ -web-stuff: -10px;
+}''';
+
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ final input2 = r'''
+* {
+ border-color: green;
+}''';
+ final generated2 = r'''
+* {
+ border-color: #008000;
+}''';
+
+ stylesheet = parseCss(input2, errors: errors..clear());
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated2);
+
+ // Regression test to ensure invalid percentages don't throw an exception and
+ // instead print a useful error message when not in checked mode.
+ var css = '''
+.foo {
+ width: Infinity%;
+}''';
+ stylesheet = parseCss(css, errors: errors..clear(), opts: simpleOptions);
+ expect(errors, isNotEmpty);
+ expect(errors.first.message, 'expected }, but found %');
+ expect(errors.first.span!.text, '%');
+}
+
+/// Declarations with comments, references with single-quotes, double-quotes,
+/// no quotes. Hex values with # and letters, and functions (rgba, url, etc.)
+void testDeclarations() {
+ var errors = <Message>[];
+ final input = r'''
+.more {
+ color: white;
+ color: black;
+ color: cyan;
+ color: red;
+ color: #aabbcc; /* test -- 3 */
+ color: blue;
+ background-image: url(http://test.jpeg);
+ background-image: url("http://double_quote.html");
+ background-image: url('http://single_quote.html');
+ color: rgba(10,20,255); <!-- test CDO/CDC -->
+ color: #123aef; /* hex # part integer and part identifier */
+}''';
+ final generated = r'''
+.more {
+ color: #fff;
+ color: #000;
+ color: #0ff;
+ color: #f00;
+ color: #abc;
+ color: #00f;
+ background-image: url("http://test.jpeg");
+ background-image: url("http://double_quote.html");
+ background-image: url("http://single_quote.html");
+ color: rgba(10, 20, 255);
+ color: #123aef;
+}''';
+
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testIdentifiers() {
+ var errors = <Message>[];
+ final input = r'''
+#da {
+ height: 100px;
+}
+#foo {
+ width: 10px;
+ color: #ff00cc;
+}
+''';
+ final generated = r'''
+#da {
+ height: 100px;
+}
+#foo {
+ width: 10px;
+ color: #f0c;
+}''';
+
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testComposites() {
+ var errors = <Message>[];
+ final input = r'''
+.xyzzy {
+ border: 10px 80px 90px 100px;
+ width: 99%;
+}
+@-webkit-keyframes pulsate {
+ 0% {
+ -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+ }
+}''';
+ final generated = r'''
+.xyzzy {
+ border: 10px 80px 90px 100px;
+ width: 99%;
+}
+@-webkit-keyframes pulsate {
+ 0% {
+ -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+ }
+}''';
+
+ var stylesheet = parseCss(input, errors: errors);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testUnits() {
+ var errors = <Message>[];
+ final input = r'''
+#id-1 {
+ transition: color 0.4s;
+ animation-duration: 500ms;
+ top: 1em;
+ left: 200ex;
+ right: 300px;
+ bottom: 400cm;
+ border-width: 2.5mm;
+ margin-top: -.5in;
+ margin-left: +5pc;
+ margin-right: 5ex;
+ margin-bottom: 5ch;
+ font-size: 10pt;
+ padding-top: 22rem;
+ padding-left: 33vw;
+ padding-right: 34vh;
+ padding-bottom: 3vmin;
+ transform: rotate(20deg);
+ voice-pitch: 10hz;
+ height: 4lh;
+ width: 40rlh;
+}
+#id-2 {
+ left: 2fr;
+ font-size: 10vmax;
+ transform: rotatex(20rad);
+ voice-pitch: 10khz;
+ -web-kit-resolution: 2dpi; /* Bogus property name testing dpi unit. */
+}
+#id-3 {
+ -web-kit-resolution: 3dpcm; /* Bogus property name testing dpi unit. */
+ transform: rotatey(20grad);
+}
+#id-4 {
+ -web-kit-resolution: 4dppx; /* Bogus property name testing dpi unit. */
+ transform: rotatez(20turn);
+}
+''';
+
+ final generated = r'''
+#id-1 {
+ transition: color 0.4s;
+ animation-duration: 500ms;
+ top: 1em;
+ left: 200ex;
+ right: 300px;
+ bottom: 400cm;
+ border-width: 2.5mm;
+ margin-top: -.5in;
+ margin-left: +5pc;
+ margin-right: 5ex;
+ margin-bottom: 5ch;
+ font-size: 10pt;
+ padding-top: 22rem;
+ padding-left: 33vw;
+ padding-right: 34vh;
+ padding-bottom: 3vmin;
+ transform: rotate(20deg);
+ voice-pitch: 10hz;
+ height: 4lh;
+ width: 40rlh;
+}
+#id-2 {
+ left: 2fr;
+ font-size: 10vmax;
+ transform: rotatex(20rad);
+ voice-pitch: 10khz;
+ -web-kit-resolution: 2dpi;
+}
+#id-3 {
+ -web-kit-resolution: 3dpcm;
+ transform: rotatey(20grad);
+}
+#id-4 {
+ -web-kit-resolution: 4dppx;
+ transform: rotatez(20turn);
+}''';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testNoValues() {
+ var errors = <Message>[];
+ final input = r'''
+.foo {
+ color: ;
+}
+.bar {
+ font:;
+ color: blue;
+}
+''';
+
+ final generated = r'''
+.foo {
+ color: ;
+}
+.bar {
+ font: ;
+ color: #00f;
+}''';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testUnicode() {
+ var errors = <Message>[];
+ final input = r'''
+.toggle:after {
+ content: '✔';
+ line-height: 43px;
+ font-size: 20px;
+ color: #d9d9d9;
+ text-shadow: 0 -1px 0 #bfbfbf;
+}
+''';
+
+ final generated = r'''
+.toggle:after {
+ content: '✔';
+ line-height: 43px;
+ font-size: 20px;
+ color: #d9d9d9;
+ text-shadow: 0 -1px 0 #bfbfbf;
+}''';
+
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testNewerCss() {
+ var errors = <Message>[];
+ final input = r'''
+@media screen,print {
+ .foobar_screen {
+ width: 10px;
+ }
+}
+@page {
+ height: 22px;
+ size: 3in 3in;
+}
+@page : left {
+ width: 10px;
+}
+@page bar : left { @top-left { margin: 8px; } }
+@page { @top-left { margin: 8px; } width: 10px; }
+@charset "ISO-8859-1";
+@charset 'ASCII';''';
+
+ final generated = r'''
+@media screen, print {
+ .foobar_screen {
+ width: 10px;
+ }
+}
+@page {
+ height: 22px;
+ size: 3in 3in;
+}
+@page:left {
+ width: 10px;
+}
+@page bar:left {
+ @top-left {
+ margin: 8px;
+ }
+}
+@page {
+ @top-left {
+ margin: 8px;
+ }
+ width: 10px;
+}
+@charset "ISO-8859-1";
+@charset "ASCII";''';
+
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testMediaQueries() {
+ var errors = <Message>[];
+ var input = '''
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+ .todo-item .toggle {
+ background: none;
+ }
+ #todo-item .toggle {
+ height: 40px;
+ }
+}''';
+ var generated = '''
+@media screen AND (-webkit-min-device-pixel-ratio:0) {
+ .todo-item .toggle {
+ background: none;
+ }
+ #todo-item .toggle {
+ height: 40px;
+ }
+}''';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ input = '''
+ @media handheld and (min-width: 20em),
+ screen and (min-width: 20em) {
+ #id { color: red; }
+ .myclass { height: 20px; }
+ }
+ @media print and (min-resolution: 300dpi) {
+ #anotherId {
+ color: #fff;
+ }
+ }
+ @media print and (min-resolution: 280dpcm) {
+ #finalId {
+ color: #aaa;
+ }
+ .class2 {
+ border: 20px;
+ }
+ }''';
+ generated = '''
+@media handheld AND (min-width:20em), screen AND (min-width:20em) {
+ #id {
+ color: #f00;
+ }
+ .myclass {
+ height: 20px;
+ }
+}
+@media print AND (min-resolution:300dpi) {
+ #anotherId {
+ color: #fff;
+ }
+}
+@media print AND (min-resolution:280dpcm) {
+ #finalId {
+ color: #aaa;
+ }
+ .class2 {
+ border: 20px;
+ }
+}''';
+
+ stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ input = '''
+@media only screen and (min-device-width: 4000px) and
+ (min-device-height: 2000px), screen AND (another: 100px) {
+ html {
+ font-size: 10em;
+ }
+ }''';
+ generated = '''
+@media ONLY screen AND (min-device-width:4000px) AND (min-device-height:2000px), screen AND (another:100px) {
+ html {
+ font-size: 10em;
+ }
+}''';
+
+ stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ input = '''
+@media screen,print AND (min-device-width: 4000px) and
+ (min-device-height: 2000px), screen AND (another: 100px) {
+ html {
+ font-size: 10em;
+ }
+ }''';
+ generated = '@media screen, print AND (min-device-width:4000px) AND '
+ '(min-device-height:2000px), screen AND (another:100px) {\n'
+ ' html {\n font-size: 10em;\n }\n}';
+
+ stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ input = '''
+@import "test.css" ONLY screen, NOT print AND (min-device-width: 4000px);''';
+ generated = '@import "test.css" ONLY screen, '
+ 'NOT print AND (min-device-width:4000px);';
+
+ stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ var css = '@media (min-device-width:400px) {\n}';
+ expectCss(css, css);
+
+ css = '@media all AND (tranform-3d), (-webkit-transform-3d) {\n}';
+ expectCss(css, css);
+
+ // Test that AND operator is required between media type and expressions.
+ css = '@media screen (min-device-width:400px';
+ stylesheet = parseCss(css, errors: errors..clear(), opts: simpleOptions);
+ expect(errors, isNotEmpty);
+ expect(
+ errors.first.message, contains('expected { after media before ruleset'));
+ expect(errors.first.span!.text, '(');
+
+ // Test nested at-rules.
+ input = '''
+@media (min-width: 840px) {
+ .cell {
+ width: calc(33% - 16px);
+ }
+ @supports (display: grid) {
+ .cell {
+ grid-column-end: span 4;
+ }
+ }
+}''';
+ generated = '''
+@media (min-width:840px) {
+ .cell {
+ width: calc(33% - 16px);
+ }
+ @supports (display: grid) {
+ .cell {
+ grid-column-end: span 4;
+ }
+ }
+}''';
+ expectCss(input, generated);
+}
+
+void testMozDocument() {
+ var errors = <Message>[];
+ // Test empty url-prefix, commonly used for browser detection.
+ var css = '''
+@-moz-document url-prefix() {
+ div {
+ color: #000;
+ }
+}''';
+ var expected = '''
+@-moz-document url-prefix() {
+ div {
+ color: #000;
+ }
+}''';
+ var styleSheet = parseCss(css, errors: errors);
+ expect(styleSheet, isNotNull);
+ expect(errors, isEmpty);
+ expect(prettyPrint(styleSheet), expected);
+
+ // Test url-prefix with unquoted parameter
+ css = '''
+@-moz-document url-prefix(http://www.w3.org/Style/) {
+ div {
+ color: #000;
+ }
+}''';
+ expected = '''
+@-moz-document url-prefix("http://www.w3.org/Style/") {
+ div {
+ color: #000;
+ }
+}''';
+ styleSheet = parseCss(css, errors: errors);
+ expect(styleSheet, isNotNull);
+ expect(errors, isEmpty);
+ expect(prettyPrint(styleSheet), expected);
+
+ // Test domain with unquoted parameter
+ css = '''
+@-moz-document domain(google.com) {
+ div {
+ color: #000;
+ }
+}''';
+ expected = '''
+@-moz-document domain("google.com") {
+ div {
+ color: #000;
+ }
+}''';
+ styleSheet = parseCss(css, errors: errors);
+ expect(styleSheet, isNotNull);
+ expect(errors, isEmpty);
+ expect(prettyPrint(styleSheet), expected);
+
+ // Test all document functions combined.
+ css = '@-moz-document '
+ 'url(http://www.w3.org/), '
+ "url-prefix('http://www.w3.org/Style/'), "
+ 'domain("google.com"), '
+ 'regexp("https:.*") { div { color: #000; } }';
+ expected = '@-moz-document '
+ 'url("http://www.w3.org/"), '
+ 'url-prefix("http://www.w3.org/Style/"), '
+ 'domain("google.com"), '
+ 'regexp("https:.*") {\n div {\n color: #000;\n }\n}';
+ styleSheet = parseCss(css, errors: errors);
+ expect(styleSheet, isNotNull);
+ expect(errors, isEmpty);
+ expect(prettyPrint(styleSheet), expected);
+}
+
+void testSupports() {
+ // Test single declaration condition.
+ var css = '''
+@supports (-webkit-appearance: none) {
+ div {
+ -webkit-appearance: none;
+ }
+}''';
+ var expected = '''
+@supports (-webkit-appearance: none) {
+ div {
+ -webkit-appearance: none;
+ }
+}''';
+ expectCss(css, expected);
+
+ // Test negation.
+ css = '''
+@supports not ( display: flex ) {
+ body { width: 100%; }
+}''';
+ expected = '''
+@supports not (display: flex) {
+ body {
+ width: 100%;
+ }
+}''';
+ expectCss(css, expected);
+
+ // Test clause with multiple conditions.
+ css = '''
+@supports (box-shadow: 0 0 2px black inset) or
+ (-moz-box-shadow: 0 0 2px black inset) or
+ (-webkit-box-shadow: 0 0 2px black inset) or
+ (-o-box-shadow: 0 0 2px black inset) {
+ .box {
+ box-shadow: 0 0 2px black inset;
+ }
+}''';
+ expected = '@supports (box-shadow: 0 0 2px #000 inset) or '
+ '(-moz-box-shadow: 0 0 2px #000 inset) or '
+ '(-webkit-box-shadow: 0 0 2px #000 inset) or '
+ '(-o-box-shadow: 0 0 2px #000 inset) {\n'
+ ' .box {\n'
+ ' box-shadow: 0 0 2px #000 inset;\n'
+ ' }\n'
+ '}';
+ expectCss(css, expected);
+
+ // Test conjunction and disjunction together.
+ css = '''
+@supports ((transition-property: color) or (animation-name: foo)) and
+ (transform: rotate(10deg)) {
+ div {
+ transition-property: color;
+ transform: rotate(10deg);
+ }
+}''';
+
+ expected = '@supports '
+ '((transition-property: color) or (animation-name: foo)) and '
+ '(transform: rotate(10deg)) {\n'
+ ' div {\n'
+ ' transition-property: color;\n'
+ ' transform: rotate(10deg);\n'
+ ' }\n'
+ '}';
+ expectCss(css, expected);
+
+ // Test that operators can't be mixed without parentheses.
+ css = '@supports (a: 1) and (b: 2) or (c: 3) {}';
+ var errors = <Message>[];
+ var styleSheet = parseCss(css, errors: errors, opts: simpleOptions);
+ expect(styleSheet, isNotNull);
+ expect(errors, isNotEmpty);
+ expect(errors.first.message,
+ "Operators can't be mixed without a layer of parentheses");
+ expect(errors.first.span!.text, 'or');
+}
+
+void testViewport() {
+ // No declarations.
+ var css = '@viewport {\n}';
+ expectCss(css, css);
+
+ // All declarations.
+ css = '''
+@viewport {
+ min-width: auto;
+ max-width: 800px;
+ width: 400px;
+ min-height: 50%;
+ max-height: 200px;
+ height: 100px 200px;
+ zoom: auto;
+ min-zoom: 0.75;
+ max-zoom: 40%;
+ user-zoom: fixed;
+ orientation: landscape;
+}''';
+ expectCss(css, css);
+
+ // Vendor specific.
+ css = '''
+@-ms-viewport {
+ width: device-width;
+}''';
+ expectCss(css, css);
+}
+
+void testFontFace() {
+ var errors = <Message>[];
+
+ final input = '''
+@font-face {
+ font-family: BBCBengali;
+ src: url(fonts/BBCBengali.ttf) format("opentype");
+ unicode-range: U+0A-FF, U+980-9FF, U+????, U+3???;
+}''';
+ final generated = '''@font-face {
+ font-family: BBCBengali;
+ src: url("fonts/BBCBengali.ttf") format("opentype");
+ unicode-range: U+0A-FF, U+980-9FF, U+????, U+3???;
+}''';
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ final input1 = '''
+@font-face {
+ font-family: Gentium;
+ src: url(http://example.com/fonts/Gentium.ttf);
+ src: url(http://example.com/fonts/Gentium.ttf);
+}''';
+ final generated1 = '''@font-face {
+ font-family: Gentium;
+ src: url("http://example.com/fonts/Gentium.ttf");
+ src: url("http://example.com/fonts/Gentium.ttf");
+}''';
+
+ stylesheet = parseCss(input1, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated1);
+
+ final input2 = '''
+@font-face {
+src: url(ideal-sans-serif.woff) format("woff"),
+ url(basic-sans-serif.ttf) format("opentype"),
+ local(Gentium Bold);
+}''';
+ final generated2 = '@font-face {\n'
+ ' src: url("ideal-sans-serif.woff") '
+ 'format("woff"), url("basic-sans-serif.ttf") '
+ 'format("opentype"), local(Gentium Bold);\n}';
+
+ stylesheet = parseCss(input2, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated2);
+
+ final input3 = '''
+@font-face {
+ font-family: MyGentium Text Ornaments;
+ src: local(Gentium Bold), /* full font name */
+ local(Gentium-Bold), /* Postscript name */
+ url(GentiumBold.ttf); /* otherwise, download it */
+ font-weight: bold;
+}''';
+ final generated3 = '''
+@font-face {
+ font-family: MyGentium Text Ornaments;
+ src: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+ font-weight: bold;
+}''';
+
+ stylesheet = parseCss(input3, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated3);
+
+ final input4 = '''
+@font-face {
+ font-family: STIXGeneral;
+ src: local(STIXGeneral), url(/stixfonts/STIXGeneral.otf);
+ unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+}''';
+ final generated4 = '''@font-face {
+ font-family: STIXGeneral;
+ src: local(STIXGeneral), url("/stixfonts/STIXGeneral.otf");
+ unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+}''';
+ stylesheet = parseCss(input4, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated4);
+}
+
+void testFontFamily() {
+ test('quoted', () {
+ var errors = <Message>[];
+ var stylesheet = parseCss('''
+body {
+ font-family: "Arial Narrow";
+}''', errors: errors..clear(), opts: simpleOptions);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), '''
+body {
+ font-family: "Arial Narrow";
+}''');
+ var ruleSet = stylesheet.topLevels.first as RuleSet;
+ var declaration =
+ ruleSet.declarationGroup.declarations.first as Declaration;
+ var expressions = declaration.expression as Expressions;
+ expect(declaration.property, 'font-family');
+ expect(printExpressions(expressions), '"Arial Narrow"');
+ });
+
+ test('without quotes', () {
+ var errors = <Message>[];
+ var stylesheet = parseCss('''
+body {
+ font-family: Arial Narrow;
+}''', errors: errors..clear(), opts: simpleOptions);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), '''
+body {
+ font-family: Arial Narrow;
+}''');
+ var ruleSet = stylesheet.topLevels.first as RuleSet;
+ var declaration =
+ ruleSet.declarationGroup.declarations.first as Declaration;
+ var expressions = declaration.expression as Expressions;
+ expect(declaration.property, 'font-family');
+ expect(printExpressions(expressions), 'Arial Narrow');
+ });
+
+ test('starts with identifier', () {
+ var errors = <Message>[];
+ var stylesheet = parseCss('''
+body {
+ font-family: PT Sans;
+}''', errors: errors..clear(), opts: simpleOptions);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), '''
+body {
+ font-family: PT Sans;
+}''');
+ var ruleSet = stylesheet.topLevels.first as RuleSet;
+ var declaration =
+ ruleSet.declarationGroup.declarations.first as Declaration;
+ var expressions = declaration.expression as Expressions;
+ expect(declaration.property, 'font-family');
+ expect(printExpressions(expressions), 'PT Sans');
+ });
+}
+
+void testCssFile() {
+ var errors = <Message>[];
+ final input = r'''
+@import 'simple.css'
+@import "test.css" print
+@import url(test.css) screen, print
+@import url(http://google.com/maps/maps.css);
+
+div[href^='test'] {
+ height: 10px;
+}
+
+@-webkit-keyframes pulsate {
+ from {
+ -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+ }
+ 10% {
+ -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+ }
+ 30% {
+ -webkit-transform: translate3d(0, 2, 0) scale(1.0);
+ }
+}
+
+.foobar {
+ grid-columns: 10px ("content" 1fr 10px)[4];
+}
+
+.test-background {
+ background: url(http://www.foo.com/bar.png);
+}
+
+.test-background-with-multiple-properties {
+ background: #000 url(http://www.foo.com/bar.png);
+}
+''';
+
+ final generated = '''
+@import "simple.css";
+@import "test.css" print;
+@import "test.css" screen, print;
+@import "http://google.com/maps/maps.css";
+div[href^="test"] {
+ height: 10px;
+}
+@-webkit-keyframes pulsate {
+ from {
+ -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+ }
+ 10% {
+ -webkit-transform: translate3d(0, 0, 0) scale(1.0);
+ }
+ 30% {
+ -webkit-transform: translate3d(0, 2, 0) scale(1.0);
+ }
+}
+.foobar {
+ grid-columns: 10px ("content" 1fr 10px) [4];
+}
+.test-background {
+ background: url("http://www.foo.com/bar.png");
+}
+.test-background-with-multiple-properties {
+ background: #000 url("http://www.foo.com/bar.png");
+}''';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testCompactEmitter() {
+ var errors = <Message>[];
+
+ // Check !import compactly emitted.
+ final input = r'''
+div {
+ color: green !important;
+ background: red blue green;
+}
+.foo p[bar] {
+ color: blue;
+}
+@page {
+ @top-left {
+ color: red;
+ }
+}
+@page : first{}
+@page foo : first {}
+@media screen AND (max-width: 800px) {
+ div {
+ font-size: 24px;
+ }
+}
+@keyframes foo {
+ 0% {
+ transform: scaleX(0);
+ }
+}
+div {
+ color: rgba(0, 0, 0, 0.2);
+}
+''';
+ final generated = '''
+div{color:green!important;background:red blue green}.foo p[bar]{color:blue}@page{@top-left{color:red}}@page:first{}@page foo:first{}@media screen AND (max-width:800px){div{font-size:24px}}@keyframes foo{0%{transform:scaleX(0)}}div{color:rgba(0,0,0,0.2)}''';
+
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(compactOutput(stylesheet), generated);
+
+ // Check namespace directive compactly emitted.
+ final input2 = '@namespace a url(http://www.example.org/a);';
+ final generated2 = '@namespace a url(http://www.example.org/a);';
+
+ var stylesheet2 = parseCss(input2, errors: errors..clear());
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(compactOutput(stylesheet2), generated2);
+}
+
+void testNotSelectors() {
+ var errors = <Message>[];
+
+ final input = r'''
+.details:not(.open-details) x-element,
+.details:not(.open-details) .summary {
+ overflow: hidden;
+}
+
+.details:not(.open-details) x-icon {
+ margin-left: 99px;
+}
+
+.kind-class .details:not(.open-details) x-icon {
+ margin-left: 0px;
+}
+
+.name {
+ margin-left: 0px;
+}
+
+.details:not(.open-details) .the-class {
+ width: 80px;
+}
+
+*:focus
+{
+ outline: none;
+}
+
+body > h2:not(:first-of-type):not(:last-of-type) {
+ color: red;
+}
+
+.details-1:not([DISABLED]) {
+ outline: none;
+}
+
+html|*:not(:link):not(:visited) {
+ width: 92%;
+}
+
+*|*:not(*) {
+ font-weight: bold;
+}
+
+*:not(:not([disabled])) { color: blue; }
+''';
+ final generated = r'''
+.details:not(.open-details) x-element, .details:not(.open-details) .summary {
+ overflow: hidden;
+}
+.details:not(.open-details) x-icon {
+ margin-left: 99px;
+}
+.kind-class .details:not(.open-details) x-icon {
+ margin-left: 0px;
+}
+.name {
+ margin-left: 0px;
+}
+.details:not(.open-details) .the-class {
+ width: 80px;
+}
+*:focus {
+ outline: none;
+}
+body > h2:not(:first-of-type):not(:last-of-type) {
+ color: #f00;
+}
+.details-1:not([DISABLED]) {
+ outline: none;
+}
+html|*:not(:link):not(:visited) {
+ width: 92%;
+}
+*|*:not(*) {
+ font-weight: bold;
+}
+*:not(:not([disabled])) {
+ color: #00f;
+}''';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testIE() {
+ var errors = <Message>[];
+ final input = '.test {\n'
+ ' filter: progid:DXImageTransform.Microsoft.gradient'
+ "(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');\n"
+ '}';
+ final generated = '.test {\n'
+ ' filter: progid:DXImageTransform.Microsoft.gradient'
+ "(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');\n"
+ '}';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ final input2 = '.test {\n'
+ ' filter: progid:DXImageTransform.Microsoft.gradient'
+ "(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670')\n"
+ ' progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n'
+ '}';
+
+ final generated2 = '.test {\n'
+ ' filter: progid:DXImageTransform.Microsoft.gradient'
+ "(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670')\n"
+ ' progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n'
+ '}';
+
+ stylesheet = parseCss(input2, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated2);
+
+ final input3 = '''
+div {
+ filter: alpha(opacity=80); /* IE7 and under */
+ -ms-filter: "Alpha(Opacity=40)"; /* IE8 and newer */
+
+ Filter: Blur(Add = 0, Direction = 225, Strength = 10);
+ Filter: FlipV;
+ Filter: Gray;
+ FILTER: Chroma(Color = #000000) Mask(Color=#00FF00);
+ Filter: Alpha(Opacity=100, FinishOpacity=0, Style=2, StartX=20, StartY=40,
+ FinishX=0, FinishY=0) Wave(Add=0, Freq=5, LightStrength=20,
+ Phase=220, Strength=10);
+}
+''';
+ final generated3 = 'div {\n filter: alpha(opacity=80);\n'
+ ' -ms-filter: "Alpha(Opacity=40)";\n'
+ ' Filter: Blur(Add = 0, Direction = 225, Strength = 10);\n'
+ ' Filter: FlipV;\n Filter: Gray;\n'
+ ' FILTER: Chroma(Color = #000000) Mask(Color=#00FF00);\n'
+ ' Filter: Alpha(Opacity=100, FinishOpacity=0, Style=2, '
+ 'StartX=20, StartY=40,\n'
+ ' FinishX=0, FinishY=0) Wave(Add=0, Freq=5, LightStrength=20,\n'
+ ' Phase=220, Strength=10);\n}';
+
+ stylesheet = parseCss(input3, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated3);
+
+ final input4 = '''
+div {
+ filter: FlipH;
+}''';
+
+ stylesheet = parseCss(input4, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), input4);
+}
+
+/// Test IE specific declaration syntax:
+/// IE6 property name prefixed with _ (normal CSS property name can start
+/// with an underscore).
+///
+/// IE7 or below property add asterisk before the CSS property.
+///
+/// IE8 or below add \9 at end of declaration expression e.g.,
+/// background: red\9;
+void testIEDeclaration() {
+ var errors = <Message>[];
+
+ final input = '''
+.testIE-6 {
+ _zoom : 5;
+}
+.clearfix {
+ *zoom: 1;
+}
+audio, video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+input {
+ *overflow: visible;
+ line-height: normal;
+}
+.uneditable-input:focus {
+ border-color: rgba(82, 168, 236, 0.8);
+ outline: 0;
+ outline: thin dotted \\9; /* IE6-9 */
+}
+
+input[type="radio"], input[type="checkbox"] {
+ margin-top: 1px \\9;
+ *margin-top: 0;
+}
+
+input.search-query {
+ padding-right: 14px;
+ padding-right: 4px \\9;
+ padding-left: 14px;
+ padding-left: 4px \\9; /* IE7-8 no border-radius, don't indent padding. */
+}
+
+.btn.active {
+ background-color: #cccccc \\9;
+}
+
+@-webkit-keyframes progress-bar-stripes {
+from {
+background-position: 40px 0;
+}
+to {
+background-position: 0 0;
+}
+}
+
+@-moz-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+@-ms-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+@-o-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}''';
+
+ final generated = '''
+.testIE-6 {
+ _zoom: 5;
+}
+.clearfix {
+ *zoom: 1;
+}
+audio, video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+input {
+ *overflow: visible;
+ line-height: normal;
+}
+.uneditable-input:focus {
+ border-color: rgba(82, 168, 236, 0.8);
+ outline: 0;
+ outline: thin dotted \\9;
+}
+input[type="radio"], input[type="checkbox"] {
+ margin-top: 1px \\9;
+ *margin-top: 0;
+}
+input.search-query {
+ padding-right: 14px;
+ padding-right: 4px \\9;
+ padding-left: 14px;
+ padding-left: 4px \\9;
+}
+.btn.active {
+ background-color: #ccc \\9;
+}
+@-webkit-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@-moz-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@-o-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}''';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void testHangs() {
+ var errors = <Message>[];
+
+ // Bad hexvalue had caused a hang in processTerm.
+ final input = r'''#a { color: #ebebeburl(0/IE8+9+); }''';
+ parseCss(input, errors: errors, opts: options);
+
+ expect(errors.length, 3, reason: errors.toString());
+
+ var errorMessage = errors[0];
+ expect(errorMessage.message, contains('Bad hex number'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 0);
+ expect(errorMessage.span!.start.column, 12);
+ expect(errorMessage.span!.text, '#ebebeburl');
+
+ errorMessage = errors[1];
+ expect(errorMessage.message, contains('expected }, but found +'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 0);
+ expect(errorMessage.span!.start.column, 30);
+ expect(errorMessage.span!.text, '+');
+
+ errorMessage = errors[2];
+ expect(errorMessage.message, contains('premature end of file unknown CSS'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 0);
+ expect(errorMessage.span!.start.column, 31);
+ expect(errorMessage.span!.text, ')');
+
+ // Missing closing parenthesis for keyframes.
+ final input2 = r'''@-ms-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+''';
+
+ parseCss(input2, errors: errors..clear(), opts: options);
+
+ expect(errors.length, 1, reason: errors.toString());
+
+ errorMessage = errors[0];
+ expect(errorMessage.message, contains('unexpected end of file'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 7);
+ expect(errorMessage.span!.start.column, 0);
+ expect(errorMessage.span!.text.trim(), '');
+}
+
+void testExpressionSpans() {
+ final input = r'''.foo { width: 50px; }''';
+
+ var stylesheet = parseCss(input);
+ var ruleSet = stylesheet.topLevels.single as RuleSet;
+
+ var declaration = ruleSet.declarationGroup.declarations.single as Declaration;
+ expect(declaration.span.text, 'width: 50px');
+
+ var expressions = declaration.expression as Expressions;
+ expect(expressions.expressions.first.span!.text, '50px');
+}
+
+void testComments() {
+ final css = '''/* This comment has a nested HTML comment...
+* <html>
+* <!-- Nested HTML comment... -->
+* <div></div>
+* </html>
+*/''';
+ expectCss(css, '');
+}
+
+void simpleCalc() {
+ final input = r'''.foo { height: calc(100% - 55px); }''';
+ var stylesheet = parseCss(input);
+ var decl = (stylesheet.topLevels.single as RuleSet)
+ .declarationGroup
+ .declarations
+ .single;
+ expect(decl.span!.text, 'height: calc(100% - 55px)');
+}
+
+void complexCalc() {
+ final input = r'''.foo { left: calc((100%/3 - 2) * 1em - 2 * 1px); }''';
+ var stylesheet = parseCss(input);
+ var decl = (stylesheet.topLevels.single as RuleSet)
+ .declarationGroup
+ .declarations
+ .single;
+ expect(decl.span!.text, 'left: calc((100%/3 - 2) * 1em - 2 * 1px)');
+}
+
+void twoCalcs() {
+ final input = r'''.foo { margin: calc(1rem - 2px) calc(1rem - 1px); }''';
+ var stylesheet = parseCss(input);
+ var decl = (stylesheet.topLevels.single as RuleSet)
+ .declarationGroup
+ .declarations
+ .single;
+ expect(decl.span!.text, 'margin: calc(1rem - 2px) calc(1rem - 1px)');
+}
+
+void selectorWithCalcs() {
+ var errors = <Message>[];
+ final input = r'''
+.foo {
+ width: calc(1em + 5 * 2em);
+ height: calc(1px + 2%) !important;
+ border: 5px calc(1pt + 2cm) 6px calc(1em + 1in + 2px) red;
+ border: calc(5px + 1em) 0px 1px calc(10 + 20 + 1px);
+ margin: 25px calc(50px + (100% / (3 - 1em) - 20%)) calc(10px + 10 * 20) calc(100% - 10px);
+}''';
+ final generated = r'''
+.foo {
+ width: calc(1em + 5 * 2em);
+ height: calc(1px + 2%) !important;
+ border: 5px calc(1pt + 2cm) 6px calc(1em + 1in + 2px) #f00;
+ border: calc(5px + 1em) 0px 1px calc(10 + 20 + 1px);
+ margin: 25px calc(50px + (100% / (3 - 1em) - 20%)) calc(10px + 10 * 20) calc(100% - 10px);
+}''';
+
+ var stylesheet = parseCss(input, errors: errors);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void vendorPrefixedCalc() {
+ var css = '''
+.foo {
+ width: -webkit-calc((100% - 15px*1) / 1);
+}''';
+ expectCss(css, css);
+
+ css = '''
+.foo {
+ width: -moz-calc((100% - 15px*1) / 1);
+}''';
+ expectCss(css, css);
+}
+
+void main() {
+ test('Simple Terms', testSimpleTerms);
+ test('Declarations', testDeclarations);
+ test('Identifiers', testIdentifiers);
+ test('Composites', testComposites);
+ test('Units', testUnits);
+ test('No Values', testNoValues);
+ test('Unicode', testUnicode);
+ test('Newer CSS', testNewerCss);
+ test('Media Queries', testMediaQueries);
+ test('Document', testMozDocument);
+ test('Supports', testSupports);
+ test('Viewport', testViewport);
+ test('Font-Face', testFontFace);
+ group('font-family', testFontFamily);
+ test('CSS file', testCssFile);
+ test('Compact Emitter', testCompactEmitter);
+ test('Selector Negation', testNotSelectors);
+ test('IE stuff', testIE);
+ test('IE declaration syntax', testIEDeclaration);
+ test('Hanging bugs', testHangs);
+ test('Expression spans', testExpressionSpans);
+ test('Comments', testComments);
+ group('calc function', () {
+ test('simple calc', simpleCalc);
+ test('single complex', complexCalc);
+ test('two calc terms for same declaration', twoCalcs);
+ test('selector with many calc declarations', selectorWithCalcs);
+ test('vendor prefixed calc', vendorPrefixedCalc);
+ });
+}
diff --git a/pkgs/csslib/test/error_test.dart b/pkgs/csslib/test/error_test.dart
new file mode 100644
index 0000000..030fc24
--- /dev/null
+++ b/pkgs/csslib/test/error_test.dart
@@ -0,0 +1,359 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/src/messages.dart';
+import 'package:term_glyph/term_glyph.dart' as glyph;
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+/// Test for unsupported font-weights values of bolder, lighter and inherit.
+void testUnsupportedFontWeights() {
+ var errors = <Message>[];
+
+ // TODO(terry): Need to support bolder.
+ // font-weight value bolder.
+ var input = '.foobar { font-weight: bolder; }';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 24: Unknown property value bolder
+ ,
+1 | .foobar { font-weight: bolder; }
+ | ^^^^^^
+ \'''');
+
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ font-weight: bolder;
+}''');
+
+ // TODO(terry): Need to support lighter.
+ // font-weight value lighter.
+ input = '.foobar { font-weight: lighter; }';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 24: Unknown property value lighter
+ ,
+1 | .foobar { font-weight: lighter; }
+ | ^^^^^^^
+ \'''');
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ font-weight: lighter;
+}''');
+
+ // TODO(terry): Need to support inherit.
+ // font-weight value inherit.
+ input = '.foobar { font-weight: inherit; }';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 24: Unknown property value inherit
+ ,
+1 | .foobar { font-weight: inherit; }
+ | ^^^^^^^
+ \'''');
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ font-weight: inherit;
+}''');
+}
+
+/// Test for unsupported line-height values of units other than px, pt and
+/// inherit.
+void testUnsupportedLineHeights() {
+ var errors = <Message>[];
+
+ // line-height value in percentage unit.
+ var input = '.foobar { line-height: 120%; }';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 24: Unexpected value for line-height
+ ,
+1 | .foobar { line-height: 120%; }
+ | ^^^^
+ \'''');
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ line-height: 120%;
+}''');
+
+ // TODO(terry): Need to support all units.
+ // line-height value in cm unit.
+ input = '.foobar { line-height: 20cm; }';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 24: Unexpected unit for line-height
+ ,
+1 | .foobar { line-height: 20cm; }
+ | ^^^^
+ \'''');
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ line-height: 20cm;
+}''');
+
+ // TODO(terry): Need to support inherit.
+ // line-height value inherit.
+ input = '.foobar { line-height: inherit; }';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 24: Unknown property value inherit
+ ,
+1 | .foobar { line-height: inherit; }
+ | ^^^^^^^
+ \'''');
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ line-height: inherit;
+}''');
+}
+
+/// Test for bad selectors.
+void testBadSelectors() {
+ var errors = <Message>[];
+
+ // Invalid id selector.
+ var input = '# foo { color: #ff00ff; }';
+ parseCss(input, errors: errors);
+
+ expect(errors, isNotEmpty);
+ expect(errors[0].toString(), '''
+error on line 1, column 1: Not a valid ID selector expected #id
+ ,
+1 | # foo { color: #ff00ff; }
+ | ^
+ \'''');
+
+ // Invalid class selector.
+ input = '. foo { color: #ff00ff; }';
+ parseCss(input, errors: errors..clear());
+
+ expect(errors, isNotEmpty);
+ expect(errors[0].toString(), '''
+error on line 1, column 1: Not a valid class selector expected .className
+ ,
+1 | . foo { color: #ff00ff; }
+ | ^
+ \'''');
+}
+
+/// Test for bad hex values.
+void testBadHexValues() {
+ var errors = <Message>[];
+
+ // Invalid hex value.
+ var input = '.foobar { color: #AH787; }';
+ var stylesheet = parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 18: Bad hex number
+ ,
+1 | .foobar { color: #AH787; }
+ | ^^^^^^
+ \'''');
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ color: #AH787;
+}''');
+
+ // Bad color constant.
+ input = '.foobar { color: redder; }';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 18: Unknown property value redder
+ ,
+1 | .foobar { color: redder; }
+ | ^^^^^^
+ \'''');
+
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ color: redder;
+}''');
+
+ // Bad hex color #<space>ffffff.
+ input = '.foobar { color: # ffffff; }';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 18: Expected hex number
+ ,
+1 | .foobar { color: # ffffff; }
+ | ^
+ \'''');
+
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ color: # ffffff;
+}''');
+
+ // Bad hex color #<space>123fff.
+ input = '.foobar { color: # 123fff; }';
+ stylesheet = parseCss(input, errors: errors..clear());
+
+ expect(errors.isEmpty, false);
+ expect(errors[0].toString(), '''
+error on line 1, column 18: Expected hex number
+ ,
+1 | .foobar { color: # 123fff; }
+ | ^
+ \'''');
+
+ // Formating is off with an extra space. However, the entire value is bad
+ // and isn't processed anyway.
+ expect(prettyPrint(stylesheet), r'''
+.foobar {
+ color: # 123 fff;
+}''');
+}
+
+void testBadUnicode() {
+ var errors = <Message>[];
+ final input = '''
+@font-face {
+ src: url(fonts/BBCBengali.ttf) format("opentype");
+ unicode-range: U+400-200;
+}''';
+
+ parseCss(input, errors: errors);
+
+ expect(errors.isEmpty, false);
+ expect(
+ errors[0].toString(),
+ 'error on line 3, column 20: unicode first range can not be greater than '
+ 'last\n'
+ ' ,\n'
+ '3 | unicode-range: U+400-200;\n'
+ ' | ^^^^^^^\n'
+ ' \'');
+
+ final input2 = '''
+@font-face {
+ src: url(fonts/BBCBengali.ttf) format("opentype");
+ unicode-range: U+12FFFF;
+}''';
+
+ parseCss(input2, errors: errors..clear());
+
+ expect(errors.isEmpty, false);
+ expect(
+ errors[0].toString(),
+ 'error on line 3, column 20: unicode range must be less than 10FFFF\n'
+ ' ,\n'
+ '3 | unicode-range: U+12FFFF;\n'
+ ' | ^^^^^^\n'
+ ' \'');
+}
+
+void testBadNesting() {
+ var errors = <Message>[];
+
+ // Test for bad declaration in a nested rule.
+ final input = '''
+div {
+ width: 20px;
+ span + ul { color: blue; }
+ span + ul > #aaaa {
+ color: #ffghghgh;
+ }
+ background-color: red;
+}
+''';
+
+ parseCss(input, errors: errors);
+ expect(errors.length, 1);
+ var errorMessage = messages.messages[0];
+ expect(errorMessage.message, contains('Bad hex number'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 4);
+ expect(errorMessage.span!.start.column, 11);
+ expect(errorMessage.span!.text, '#ffghghgh');
+
+ // Test for bad selector syntax.
+ final input2 = '''
+div {
+ span + ul #aaaa > (3333) {
+ color: #ffghghgh;
+ }
+}
+''';
+ parseCss(input2, errors: errors..clear());
+ expect(errors.length, 4);
+ errorMessage = messages.messages[0];
+ expect(errorMessage.message, contains(':, but found +'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 1);
+ expect(errorMessage.span!.start.column, 7);
+ expect(errorMessage.span!.text, '+');
+
+ errorMessage = messages.messages[1];
+ expect(errorMessage.message, contains('Unknown property value ul'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 1);
+ expect(errorMessage.span!.start.column, 9);
+ expect(errorMessage.span!.text, 'ul');
+
+ errorMessage = messages.messages[2];
+ expect(errorMessage.message, contains('expected }, but found >'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 1);
+ expect(errorMessage.span!.start.column, 18);
+ expect(errorMessage.span!.text, '>');
+
+ errorMessage = messages.messages[3];
+ expect(errorMessage.message, contains('premature end of file unknown CSS'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 1);
+ expect(errorMessage.span!.start.column, 20);
+ expect(errorMessage.span!.text, '(');
+
+ // Test for missing close braces and bad declaration.
+ final input3 = '''
+div {
+ span {
+ color: #green;
+}
+''';
+ parseCss(input3, errors: errors..clear());
+ expect(errors.length, 2);
+ errorMessage = messages.messages[0];
+ expect(errorMessage.message, contains('Bad hex number'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 2);
+ expect(errorMessage.span!.start.column, 11);
+ expect(errorMessage.span!.text, '#green');
+
+ errorMessage = messages.messages[1];
+ expect(errorMessage.message, contains('expected }, but found end of file'));
+ expect(errorMessage.span, isNotNull);
+ expect(errorMessage.span!.start.line, 3);
+ expect(errorMessage.span!.start.column, 1);
+ expect(errorMessage.span!.text, '\n');
+}
+
+void main() {
+ glyph.ascii = true;
+ test('font-weight value errors', testUnsupportedFontWeights);
+ test('line-height value errors', testUnsupportedLineHeights);
+ test('bad selectors', testBadSelectors);
+ test('bad Hex values', testBadHexValues);
+ test('bad unicode ranges', testBadUnicode);
+ test('nested rules', testBadNesting);
+}
diff --git a/pkgs/csslib/test/escape_codes_test.dart b/pkgs/csslib/test/escape_codes_test.dart
new file mode 100644
index 0000000..0973021
--- /dev/null
+++ b/pkgs/csslib/test/escape_codes_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/parser.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void main() {
+ final errors = <Message>[];
+
+ tearDown(errors.clear);
+
+ group('handles escape codes', () {
+ group('in an identifier', () {
+ test('with trailing space', () {
+ final selectorAst = selector(r'.\35 00px', errors: errors);
+ expect(errors, isEmpty);
+ expect(compactOutput(selectorAst), r'.\35 00px');
+ });
+
+ test('in an attribute selector value', () {
+ final selectorAst = selector(r'[elevation=\31]', errors: errors);
+ expect(errors, isEmpty);
+ expect(compactOutput(selectorAst), r'[elevation=\31]');
+ });
+ });
+ });
+}
diff --git a/pkgs/csslib/test/extend_test.dart b/pkgs/csslib/test/extend_test.dart
new file mode 100644
index 0000000..0990490
--- /dev/null
+++ b/pkgs/csslib/test/extend_test.dart
@@ -0,0 +1,243 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/src/messages.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void compileAndValidate(String input, String generated) {
+ var errors = <Message>[];
+ var stylesheet = compileCss(input, errors: errors, opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void simpleExtend() {
+ compileAndValidate(r'''
+.error {
+ border: 1px red;
+ background-color: #fdd;
+}
+.seriousError {
+ @extend .error;
+ border-width: 3px;
+}
+''', r'''
+.error, .seriousError {
+ border: 1px #f00;
+ background-color: #fdd;
+}
+.seriousError {
+ border-width: 3px;
+}''');
+}
+
+void complexSelectors() {
+ compileAndValidate(r'''
+.error {
+ border: 1px #f00;
+ background-color: #fdd;
+}
+.error.intrusion {
+ background-image: url("/image/hacked.png");
+}
+.seriousError {
+ @extend .error;
+ border-width: 3px;
+}
+''', r'''
+.error, .seriousError {
+ border: 1px #f00;
+ background-color: #fdd;
+}
+.error.intrusion, .seriousError.intrusion {
+ background-image: url("/image/hacked.png");
+}
+.seriousError {
+ border-width: 3px;
+}''');
+
+ compileAndValidate(r'''
+a:hover {
+ text-decoration: underline;
+}
+.hoverlink {
+ @extend a:hover;
+}
+''', r'''
+a:hover, .hoverlink {
+ text-decoration: underline;
+}
+.hoverlink {
+}''');
+}
+
+void multipleExtends() {
+ compileAndValidate(r'''
+.error {
+ border: 1px #f00;
+ background-color: #fdd;
+}
+.attention {
+ font-size: 3em;
+ background-color: #ff0;
+}
+.seriousError {
+ @extend .error;
+ @extend .attention;
+ border-width: 3px;
+}
+''', r'''
+.error, .seriousError {
+ border: 1px #f00;
+ background-color: #fdd;
+}
+.attention, .seriousError {
+ font-size: 3em;
+ background-color: #ff0;
+}
+.seriousError {
+ border-width: 3px;
+}''');
+}
+
+void chaining() {
+ compileAndValidate(r'''
+.error {
+ border: 1px #f00;
+ background-color: #fdd;
+}
+.seriousError {
+ @extend .error;
+ border-width: 3px;
+}
+.criticalError {
+ @extend .seriousError;
+ position: fixed;
+ top: 10%;
+ bottom: 10%;
+ left: 10%;
+ right: 10%;
+}
+''', r'''
+.error, .seriousError, .criticalError {
+ border: 1px #f00;
+ background-color: #fdd;
+}
+.seriousError, .criticalError {
+ border-width: 3px;
+}
+.criticalError {
+ position: fixed;
+ top: 10%;
+ bottom: 10%;
+ left: 10%;
+ right: 10%;
+}''');
+}
+
+void nestedSelectors() {
+ compileAndValidate(r'''
+a {
+ color: blue;
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+#fake-links .link {
+ @extend a;
+}
+''', r'''
+a, #fake-links .link {
+ color: #00f;
+}
+a:hover, #fake-links .link:hover {
+ text-decoration: underline;
+}
+#fake-links .link {
+}''');
+}
+
+void nestedMulty() {
+ compileAndValidate(r'''
+.btn {
+ display: inline-block;
+}
+
+input[type="checkbox"].toggle-button {
+ color: red;
+
+ + label {
+ @extend .btn;
+ }
+}
+''', r'''
+.btn, input[type="checkbox"].toggle-button label {
+ display: inline-block;
+}
+input[type="checkbox"].toggle-button {
+ color: #f00;
+}
+input[type="checkbox"].toggle-button label {
+}''');
+}
+
+void nWayExtends() {
+ compileAndValidate(
+ r'''
+.btn > .btn {
+ margin-left: 5px;
+}
+input.second + label {
+ @extend .btn;
+}
+''',
+ '.btn > .btn, '
+ 'input.second + label > .btn, '
+ '.btn > input.second + label, '
+ 'input.second + label > input.second + label, '
+ 'input.second + label > input.second + label {\n'
+ ' margin-left: 5px;\n}\n'
+ 'input.second + label {\n'
+ '}');
+
+ // TODO(terry): Optimize merge selectors would be:
+ //
+ // .btn + .btn, input.second + label + .btn, input.second.btn + label {
+ // margin-left: 5px;
+ // }
+ // input.second + label {
+ // color: blue;
+ // }
+ compileAndValidate(
+ r'''
+.btn + .btn {
+ margin-left: 5px;
+}
+input.second + label {
+ @extend .btn;
+ color: blue;
+}
+''',
+ '.btn + .btn, '
+ 'input.second + label + .btn, '
+ '.btn + input.second + label, '
+ 'input.second + label + input.second + label, '
+ 'input.second + label + input.second + label {\n'
+ ' margin-left: 5px;\n}\n'
+ 'input.second + label {\n'
+ ' color: #00f;\n}');
+}
+
+void main() {
+ test('Simple Extend', simpleExtend);
+ test('complex', complexSelectors);
+ test('multiple', multipleExtends);
+ test('chaining', chaining);
+ test('nested selectors', nestedSelectors);
+ test('nested many selector sequences', nestedMulty);
+ test('N-way extends', nWayExtends);
+}
diff --git a/pkgs/csslib/test/keyframes_test.dart b/pkgs/csslib/test/keyframes_test.dart
new file mode 100644
index 0000000..3560c0d
--- /dev/null
+++ b/pkgs/csslib/test/keyframes_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/src/messages.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void main() {
+ test('keyframes', () {
+ final input =
+ r'@keyframes ping { 75%, 100% { transform: scale(2); opacity: 0; } }';
+ var errors = <Message>[];
+ var stylesheet = compileCss(input, errors: errors, opts: options);
+ expect(errors, isEmpty);
+ final expected = r'''
+@keyframes ping {
+ 75%, 100% {
+ transform: scale(2);
+ opacity: 0;
+ }
+}''';
+ expect(prettyPrint(stylesheet), expected);
+ });
+}
diff --git a/pkgs/csslib/test/mixin_test.dart b/pkgs/csslib/test/mixin_test.dart
new file mode 100644
index 0000000..684f914
--- /dev/null
+++ b/pkgs/csslib/test/mixin_test.dart
@@ -0,0 +1,644 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/src/messages.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void compileAndValidate(String input, String generated) {
+ var errors = <Message>[];
+ var stylesheet = compileCss(input, errors: errors, opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void compilePolyfillAndValidate(String input, String generated) {
+ var errors = <Message>[];
+ var stylesheet = polyFillCompileCss(input, errors: errors, opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void topLevelMixin() {
+ compileAndValidate(r'''
+@mixin silly-links {
+ a {
+ color: blue;
+ background-color: red;
+ }
+}
+
+@include silly-links;
+''', r'''
+a {
+ color: #00f;
+ background-color: #f00;
+}''');
+}
+
+void topLevelMixinTwoIncludes() {
+ compileAndValidate(r'''
+@mixin a {
+ a {
+ color: blue;
+ background-color: red;
+ }
+}
+@mixin b {
+ span {
+ color: black;
+ background-color: orange;
+ }
+}
+@include a;
+@include b;
+''', r'''
+a {
+ color: #00f;
+ background-color: #f00;
+}
+span {
+ color: #000;
+ background-color: #ffa500;
+}''');
+}
+
+/// Tests top-level mixins that includes another mixin.
+void topLevelMixinMultiRulesets() {
+ compileAndValidate(r'''
+@mixin a {
+ a {
+ color: blue;
+ background-color: red;
+ }
+}
+@mixin b {
+ #foo-id {
+ border-top: 1px solid red;
+ border-bottom: 2px solid green;
+ }
+}
+@mixin c {
+ span {
+ color: black;
+ background-color: orange;
+ }
+ @include b;
+}
+@include a;
+@include c;
+''', r'''
+a {
+ color: #00f;
+ background-color: #f00;
+}
+span {
+ color: #000;
+ background-color: #ffa500;
+}
+#foo-id {
+ border-top: 1px solid #f00;
+ border-bottom: 2px solid #008000;
+}''');
+}
+
+void topLevelMixinDeeplyNestedRulesets() {
+ compileAndValidate(r'''
+@mixin a {
+ a {
+ color: blue;
+ background-color: red;
+ }
+}
+@mixin b {
+ #foo-id {
+ border-top: 1px solid red;
+ border-bottom: 2px solid green;
+ }
+}
+@mixin f {
+ #split-bar div {
+ border: 1px solid lightgray;
+ }
+}
+@mixin e {
+ #split-bar:visited {
+ color: gray;
+ }
+ @include f;
+}
+@mixin d {
+ a:hover {
+ cursor: arrow;
+ }
+ @include e
+}
+@mixin c {
+ @include a;
+ span {
+ color: black;
+ background-color: orange;
+ }
+ @include b;
+ @include d;
+}
+@include c;
+''', r'''
+a {
+ color: #00f;
+ background-color: #f00;
+}
+span {
+ color: #000;
+ background-color: #ffa500;
+}
+#foo-id {
+ border-top: 1px solid #f00;
+ border-bottom: 2px solid #008000;
+}
+a:hover {
+ cursor: arrow;
+}
+#split-bar:visited {
+ color: #808080;
+}
+#split-bar div {
+ border: 1px solid #d3d3d3;
+}''');
+}
+
+/// Tests selector groups and other combinators.
+void topLevelMixinSelectors() {
+ compileAndValidate(r'''
+@mixin a {
+ a, b {
+ color: blue;
+ background-color: red;
+ }
+ div > span {
+ color: black;
+ background-color: orange;
+ }
+}
+
+@include a;
+''', r'''
+a, b {
+ color: #00f;
+ background-color: #f00;
+}
+div > span {
+ color: #000;
+ background-color: #ffa500;
+}''');
+}
+
+void declSimpleMixin() {
+ compileAndValidate(r'''
+@mixin div-border {
+ border: 2px dashed red;
+}
+div {
+ @include div-border;
+}
+''', r'''
+div {
+ border: 2px dashed #f00;
+}''');
+}
+
+void declMixinTwoIncludes() {
+ compileAndValidate(r'''
+@mixin div-border {
+ border: 2px dashed red;
+}
+@mixin div-color {
+ color: blue;
+}
+div {
+ @include div-border;
+ @include div-color;
+}
+''', r'''
+div {
+ border: 2px dashed #f00;
+ color: #00f;
+}''');
+}
+
+void declMixinNestedIncludes() {
+ compileAndValidate(r'''
+@mixin div-border {
+ border: 2px dashed red;
+}
+@mixin div-padding {
+ padding: .5em;
+}
+@mixin div-margin {
+ margin: 5px;
+}
+@mixin div-color {
+ @include div-padding;
+ color: blue;
+ @include div-margin;
+}
+div {
+ @include div-border;
+ @include div-color;
+}
+''', r'''
+div {
+ border: 2px dashed #f00;
+ padding: .5em;
+ color: #00f;
+ margin: 5px;
+}''');
+}
+
+void declMixinDeeperNestedIncludes() {
+ compileAndValidate(r'''
+@mixin div-border {
+ border: 2px dashed red;
+}
+@mixin div-padding {
+ padding: .5em;
+}
+@mixin div-margin {
+ margin: 5px;
+}
+@mixin div-color {
+ @include div-padding;
+ @include div-margin;
+}
+div {
+ @include div-border;
+ @include div-color;
+}
+''', r'''
+div {
+ border: 2px dashed #f00;
+ padding: .5em;
+ margin: 5px;
+}''');
+}
+
+void mixinArg() {
+ compileAndValidate(r'''
+@mixin div-border-1 {
+ border: 2px dashed red;
+}
+@mixin div-border-2() {
+ border: 22px solid blue;
+}
+@mixin div-left(@dist) {
+ margin-left: @dist;
+}
+@mixin div-right(var-margin) {
+ margin-right: var(margin);
+}
+div-1 {
+ @include div-left(10px);
+ @include div-right(100px);
+ @include div-border-1;
+}
+div-2 {
+ @include div-left(20em);
+ @include div-right(5in);
+ @include div-border-2();
+}
+div-3 {
+ @include div-border-1();
+}
+div-4 {
+ @include div-border-2;
+}
+''', r'''
+div-1 {
+ margin-left: 10px;
+ margin-right: 100px;
+ border: 2px dashed #f00;
+}
+div-2 {
+ margin-left: 20em;
+ margin-right: 5in;
+ border: 22px solid #00f;
+}
+div-3 {
+ border: 2px dashed #f00;
+}
+div-4 {
+ border: 22px solid #00f;
+}''');
+}
+
+void mixinArgs() {
+ compileAndValidate(r'''
+@mixin box-shadow(@shadows...) {
+ -moz-box-shadow: @shadows;
+ -webkit-box-shadow: @shadows;
+ box-shadow: var(shadows);
+}
+
+.shadows {
+ @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
+}''', r'''
+.shadowed {
+ -moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
+ -webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
+ box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
+}
+''');
+}
+
+void mixinManyArgs() {
+ compileAndValidate(r'''
+@mixin border(@border-values) {
+ border: @border-values
+}
+
+.primary {
+ @include border(3px solid green);
+}
+''', r'''
+.primary {
+ border: 3px solid #008000;
+}''');
+
+ compileAndValidate(r'''
+@mixin setup(@border-color, @border-style, @border-size, @color) {
+ border: @border-size @border-style @border-color;
+ color: @color;
+}
+
+.primary {
+ @include setup(red, solid, 5px, blue);
+}
+''', r'''
+.primary {
+ border: 5px solid #f00;
+ color: #00f;
+}''');
+
+ // Test passing a declaration that is multiple parameters.
+ compileAndValidate(r'''
+@mixin colors(@text, @background, @border) {
+ color: @text;
+ background-color: @background;
+ border-color: @border;
+}
+
+@values: #ff0000, #00ff00, #0000ff;
+.primary {
+ @include colors(@values);
+}
+''', r'''
+var-values: #f00, #0f0, #00f;
+.primary {
+ color: #f00;
+ background-color: #0f0;
+ border-color: #00f;
+}''');
+
+ compilePolyfillAndValidate(r'''
+@mixin colors(@text, @background, @border) {
+ color: @text;
+ background-color: @background;
+ border-color: @border;
+}
+
+@values: #ff0000, #00ff00, #0000ff;
+.primary {
+ @include colors(@values);
+}
+''', r'''
+.primary {
+ color: #f00;
+ background-color: #0f0;
+ border-color: #00f;
+}''');
+}
+
+void badDeclarationInclude() {
+ final errors = <Message>[];
+ final input = r'''
+@mixin a {
+ #foo-id {
+ color: red;
+ }
+}
+@mixin b {
+ span {
+ border: 2px dashed red;
+ @include a;
+ }
+}
+@include b;
+''';
+
+ compileCss(input, errors: errors, opts: options);
+
+ expect(errors.isNotEmpty, true);
+ expect(errors.length, 1, reason: errors.toString());
+ var error = errors[0];
+ expect(error.message, 'Using top-level mixin a as a declaration');
+ expect(error.span!.start.line, 8);
+ expect(error.span!.end.offset, 105);
+}
+
+void badTopInclude() {
+ final errors = <Message>[];
+ final input = r'''
+@mixin b {
+ color: red;
+}
+
+@mixin a {
+ span {
+ border: 2px dashed red;
+ }
+ @include b;
+}
+
+@include a;
+ ''';
+
+ compileCss(input, errors: errors, opts: options);
+
+ expect(errors.length, 1, reason: errors.toString());
+ var error = errors[0];
+ expect(error.message, 'Using declaration mixin b as top-level mixin');
+ expect(error.span!.start.line, 8);
+ expect(error.span!.end.offset, 90);
+}
+
+void emptyMixin() {
+ final errors = <Message>[];
+ final input = r'''
+@mixin a {
+}
+@mixin b {
+ border: 2px dashed red;
+ @include a;
+}
+div {
+ @include b;
+}
+ ''';
+
+ var generated = r'''
+div {
+ border: 2px dashed #f00;
+}''';
+
+ var stylesheet = compileCss(input, errors: errors, opts: options);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void undefinedTopLevel() {
+ final errors = <Message>[];
+ final input = r'''
+@mixin a {
+ @include b;
+}
+@mixin b {
+ span {
+ border: 2px dashed red;
+ }
+ @include a;
+}
+
+@include b;
+
+ ''';
+
+ compileCss(input, errors: errors, opts: options);
+
+ expect(errors.isNotEmpty, true);
+ expect(errors.length, 1, reason: errors.toString());
+ var error = errors[0];
+ expect(error.message, 'Undefined mixin b');
+ expect(error.span!.start.line, 1);
+ expect(error.span!.start.offset, 14);
+}
+
+void undefinedDeclaration() {
+ final errors = <Message>[];
+ final input = r'''
+@mixin a {
+ @include b;
+}
+@mixin b {
+ border: 2px dashed red;
+ @include a;
+}
+div {
+ @include b;
+}
+ ''';
+
+ compileCss(input, errors: errors, opts: options);
+
+ expect(errors.isNotEmpty, true);
+ expect(errors.length, 1, reason: errors.toString());
+ var error = errors[0];
+ expect(error.message, 'Undefined mixin b');
+ expect(error.span!.start.line, 1);
+ expect(error.span!.start.offset, 14);
+}
+
+void includeGrammar() {
+ compileAndValidate(r'''
+@mixin a {
+ foo { color: red }
+}
+
+@mixin b {
+ @include a;
+ @include a;
+}
+
+@include b;
+''', r'''
+foo {
+ color: #f00;
+}
+foo {
+ color: #f00;
+}''');
+
+ compileAndValidate(r'''
+@mixin a {
+ color: red
+}
+
+foo {
+ @include a;
+ @include a
+}
+''', r'''
+foo {
+ color: #f00;
+ color: #f00;
+}''');
+
+ var errors = <Message>[];
+ var input = r'''
+@mixin a {
+ foo { color: red }
+}
+
+@mixin b {
+ @include a
+ @include a
+}
+
+@include b
+''';
+
+ compileCss(input, errors: errors, opts: options);
+
+ expect(errors, hasLength(4));
+ expect(errors[0].describe, '7:4:parsing error expected ;');
+ expect(errors[1].describe, '8:1:expected :, but found }');
+ expect(errors[2].describe, '10:11:expected }, but found end of file');
+ expect(errors[3].describe, '6:4:Using top-level mixin a as a declaration');
+}
+
+void main() {
+ group('Basic mixin', () {
+ test('include grammar', includeGrammar);
+ test('empty mixin content', emptyMixin);
+ });
+
+ group('Top-level mixin', () {
+ test('simple mixin', topLevelMixin);
+ test('mixin with two @includes', topLevelMixinTwoIncludes);
+ test('multi rulesets', topLevelMixinMultiRulesets);
+ test('multi rulesets and nesting', topLevelMixinDeeplyNestedRulesets);
+ test('selector groups', topLevelMixinSelectors);
+ });
+
+ group('Declaration mixin', () {
+ test('simple', declSimpleMixin);
+ test('with two @includes', declMixinTwoIncludes);
+ test('with includes', declMixinNestedIncludes);
+ test('with deeper nesting', declMixinDeeperNestedIncludes);
+ });
+
+ group('Mixin arguments', () {
+ test('simple arg', mixinArg);
+ test('many args', mixinArgs, skip: 'hangs at runtime');
+ test('multiple args and var decls as args', mixinManyArgs);
+ });
+
+ group('Mixin warnings', () {
+ test('undefined top-level', undefinedTopLevel);
+ test('undefined declaration', undefinedDeclaration);
+ test('detect bad top-level as declaration', badDeclarationInclude);
+ test('detect bad declaration as top-level', badTopInclude);
+ });
+}
diff --git a/pkgs/csslib/test/nested_test.dart b/pkgs/csslib/test/nested_test.dart
new file mode 100644
index 0000000..4ec72ea
--- /dev/null
+++ b/pkgs/csslib/test/nested_test.dart
@@ -0,0 +1,630 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/src/messages.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void compileAndValidate(String input, String generated) {
+ var errors = <Message>[];
+ var stylesheet = compileCss(input, errors: errors, opts: simpleOptions);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void selectorVariations() {
+ final input1 = r'''html { color: red; }''';
+ final generated1 = r'''html {
+ color: #f00;
+}''';
+ compileAndValidate(input1, generated1);
+
+ final input2 = r'''button { span { height: 200 } }''';
+ final generated2 = r'''button {
+}
+button span {
+ height: 200;
+}''';
+ compileAndValidate(input2, generated2);
+
+ final input3 = r'''div { color: red; } button { span { height: 200 } }''';
+ final generated3 = r'''div {
+ color: #f00;
+}
+button {
+}
+button span {
+ height: 200;
+}''';
+ compileAndValidate(input3, generated3);
+
+ final input4 = r'''#header { color: red; h1 { font-size: 26px; } }''';
+ final generated4 = r'''#header {
+ color: #f00;
+}
+#header h1 {
+ font-size: 26px;
+}''';
+ compileAndValidate(input4, generated4);
+
+ final input5 = r'''
+#header {
+ color: red;
+ h1 { font-size: 26px; }
+ background-color: blue;
+}''';
+ final generated5 = r'''#header {
+ color: #f00;
+ background-color: #00f;
+}
+#header h1 {
+ font-size: 26px;
+}''';
+ compileAndValidate(input5, generated5);
+
+ final input6 = r'''html { body {color: red; }}''';
+ final generated6 = r'''html {
+}
+html body {
+ color: #f00;
+}''';
+ compileAndValidate(input6, generated6);
+
+ final input7 = r'''html body {color: red; }''';
+ final generated7 = r'''html body {
+ color: #f00;
+}''';
+ compileAndValidate(input7, generated7);
+
+ final input8 = r'''
+html, body { color: red; }
+button { height: 200 }
+body { width: 300px; }''';
+ final generated8 = r'''html, body {
+ color: #f00;
+}
+button {
+ height: 200;
+}
+body {
+ width: 300px;
+}''';
+ compileAndValidate(input8, generated8);
+
+ final input9 = '''
+html, body {
+ color: red;
+ button { height: 200 }
+ div { width: 300px; }
+}''';
+ final generated9 = r'''html, body {
+ color: #f00;
+}
+html button, body button {
+ height: 200;
+}
+html div, body div {
+ width: 300px;
+}''';
+ compileAndValidate(input9, generated9);
+
+ final input10 = '''
+html {
+ color: red;
+ button, div { height: 200 }
+ body { width: 300px; }
+}''';
+ final generated10 = r'''html {
+ color: #f00;
+}
+html button, html div {
+ height: 200;
+}
+html body {
+ width: 300px;
+}''';
+ compileAndValidate(input10, generated10);
+
+ final input11 = '''
+html, body {
+ color: red;
+ button, div { height: 200 }
+ table { width: 300px; }
+}''';
+ final generated11 = r'''html, body {
+ color: #f00;
+}
+html button, body button, html div, body div {
+ height: 200;
+}
+html table, body table {
+ width: 300px;
+}''';
+ compileAndValidate(input11, generated11);
+
+ final input12 = '''
+html, body {
+ color: red;
+ button, div {
+ span, a, ul { height: 200 }
+ }
+ table { width: 300px; }
+}''';
+ final generated12 = r'''html, body {
+ color: #f00;
+}
+'''
+ 'html button span, body button span, html div span, body div span, '
+ 'html button a, body button a, html div a, body div a, html button ul, '
+ r'''body button ul, html div ul, body div ul {
+ height: 200;
+}
+html table, body table {
+ width: 300px;
+}''';
+ compileAndValidate(input12, generated12);
+
+ final input13 = r'''
+#header {
+ div {
+ width: 100px;
+ a { height: 200px; }
+ }
+ color: blue;
+}
+span { color: #1f1f1f; }
+''';
+ final generated13 = r'''#header {
+ color: #00f;
+}
+#header div {
+ width: 100px;
+}
+#header div a {
+ height: 200px;
+}
+span {
+ color: #1f1f1f;
+}''';
+ compileAndValidate(input13, generated13);
+}
+
+void simpleNest() {
+ final input = '''
+div span { color: green; }
+#header {
+ color: red;
+ h1 {
+ font-size: 26px;
+ font-weight: bold;
+ }
+ p {
+ font-size: 12px;
+ a {
+ text-decoration: none;
+ }
+ }
+ background-color: blue;
+}
+div > span[attr="foo"] { color: yellow; }
+''';
+
+ final generated = r'''div span {
+ color: #008000;
+}
+#header {
+ color: #f00;
+ background-color: #00f;
+}
+#header h1 {
+ font-size: 26px;
+ font-weight: bold;
+}
+#header p {
+ font-size: 12px;
+}
+#header p a {
+ text-decoration: none;
+}
+div > span[attr="foo"] {
+ color: #ff0;
+}''';
+ compileAndValidate(input, generated);
+}
+
+void complexNest() {
+ final input = '''
+@font-face { font-family: arial; }
+div { color: #f0f0f0; }
+#header + div {
+ color: url(abc.png);
+ *[attr="bar"] {
+ font-size: 26px;
+ font-weight: bold;
+ }
+ p~ul {
+ font-size: 12px;
+ :not(p) {
+ text-decoration: none;
+ div > span[attr="foo"] { color: yellow; }
+ }
+ }
+ background-color: blue;
+ span {
+ color: red;
+ .one { color: blue; }
+ .two { color: green; }
+ .three { color: yellow; }
+ .four {
+ .four-1 { background-color: #00000f; }
+ .four-2 { background-color: #0000ff; }
+ .four-3 { background-color: #000fff; }
+ .four-4 {
+ height: 44px;
+ .four-4-1 { height: 10px; }
+ .four-4-2 { height: 20px; }
+ .four-4-3 { height: 30px; }
+ width: 44px;
+ }
+ }
+ }
+}
+span { color: #1f1f2f; }
+''';
+
+ final generated = r'''@font-face {
+ font-family: arial;
+}
+div {
+ color: #f0f0f0;
+}
+#header + div {
+ color: url("abc.png");
+ background-color: #00f;
+}
+#header + div *[attr="bar"] {
+ font-size: 26px;
+ font-weight: bold;
+}
+#header + div p ~ ul {
+ font-size: 12px;
+}
+#header + div p ~ ul :not(p) {
+ text-decoration: none;
+}
+#header + div p ~ ul :not(p) div > span[attr="foo"] {
+ color: #ff0;
+}
+#header + div span {
+ color: #f00;
+}
+#header + div span .one {
+ color: #00f;
+}
+#header + div span .two {
+ color: #008000;
+}
+#header + div span .three {
+ color: #ff0;
+}
+#header + div span .four .four-1 {
+ background-color: #00000f;
+}
+#header + div span .four .four-2 {
+ background-color: #00f;
+}
+#header + div span .four .four-3 {
+ background-color: #000fff;
+}
+#header + div span .four .four-4 {
+ height: 44px;
+ width: 44px;
+}
+#header + div span .four .four-4 .four-4-1 {
+ height: 10px;
+}
+#header + div span .four .four-4 .four-4-2 {
+ height: 20px;
+}
+#header + div span .four .four-4 .four-4-3 {
+ height: 30px;
+}
+span {
+ color: #1f1f2f;
+}''';
+
+ compileAndValidate(input, generated);
+}
+
+void mediaNesting() {
+ final input = r'''
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+ #toggle-all {
+ image: url(test.jpb);
+ div, table {
+ background: none;
+ a { width: 100px; }
+ }
+ color: red;
+ }
+}
+''';
+ final generated = r'''
+@media screen AND (-webkit-min-device-pixel-ratio:0) {
+ #toggle-all {
+ image: url("test.jpb");
+ color: #f00;
+ }
+ #toggle-all div, #toggle-all table {
+ background: none;
+ }
+ #toggle-all div a, #toggle-all table a {
+ width: 100px;
+ }
+}''';
+
+ compileAndValidate(input, generated);
+}
+
+void simpleThis() {
+ final input = '''#header {
+ h1 {
+ font-size: 26px;
+ font-weight: bold;
+ }
+ p { font-size: 12px;
+ a { text-decoration: none;
+ &:hover { border-width: 1px }
+ }
+ }
+}
+''';
+
+ final generated = r'''#header {
+}
+#header h1 {
+ font-size: 26px;
+ font-weight: bold;
+}
+#header p {
+ font-size: 12px;
+}
+#header p a {
+ text-decoration: none;
+}
+#header p a:hover {
+ border-width: 1px;
+}''';
+
+ compileAndValidate(input, generated);
+}
+
+void complexThis() {
+ final input1 = r'''
+.light {
+ .leftCol {
+ .textLink {
+ color: fooL1;
+ &:hover { color: barL1;}
+ }
+ .picLink {
+ background-image: url(/fooL1.jpg);
+ &:hover { background-image: url(/barL1.jpg);}
+ }
+ .textWithIconLink {
+ color: fooL2;
+ background-image: url(/fooL2.jpg);
+ &:hover { color: barL2; background-image: url(/barL2.jpg);}
+ }
+ }
+}''';
+
+ final generated1 = r'''.light {
+}
+.light .leftCol .textLink {
+ color: fooL1;
+}
+.light .leftCol .textLink:hover {
+ color: barL1;
+}
+.light .leftCol .picLink {
+ background-image: url("/fooL1.jpg");
+}
+.light .leftCol .picLink:hover {
+ background-image: url("/barL1.jpg");
+}
+.light .leftCol .textWithIconLink {
+ color: fooL2;
+ background-image: url("/fooL2.jpg");
+}
+.light .leftCol .textWithIconLink:hover {
+ color: barL2;
+ background-image: url("/barL2.jpg");
+}''';
+
+ compileAndValidate(input1, generated1);
+
+ final input2 = r'''
+.textLink {
+ .light .leftCol & {
+ color: fooL1;
+ &:hover { color: barL1; }
+ }
+ .light .rightCol & {
+ color: fooL3;
+ &:hover { color: barL3; }
+ }
+}''';
+
+ final generated2 = r'''
+.textLink {
+}
+.light .leftCol .textLink {
+ color: fooL1;
+}
+.light .leftCol .textLink:hover {
+ color: barL1;
+}
+.light .rightCol .textLink {
+ color: fooL3;
+}
+.light .rightCol .textLink:hover {
+ color: barL3;
+}''';
+
+ compileAndValidate(input2, generated2);
+}
+
+void variationsThis() {
+ final input1 = r'''
+.textLink {
+ a {
+ light .leftCol & {
+ color: red;
+ }
+ }
+}''';
+ final generated1 = r'''.textLink {
+}
+light .leftCol .textLink a {
+ color: #f00;
+}''';
+
+ compileAndValidate(input1, generated1);
+
+ final input2 = r'''.textLink {
+ a {
+ & light .leftCol & {
+ color: red;
+ }
+ }
+}''';
+ final generated2 = r'''.textLink {
+}
+.textLink a light .leftCol .textLink a {
+ color: #f00;
+}''';
+ compileAndValidate(input2, generated2);
+
+ final input3 = r'''
+.textLink {
+ a {
+ & light .leftCol { color: red; }
+ }
+}''';
+ final generated3 = r'''.textLink {
+}
+.textLink a light .leftCol {
+ color: #f00;
+}''';
+ compileAndValidate(input3, generated3);
+
+ final input4 = r'''
+.textLink {
+ a {
+ & light .leftCol { color: red; }
+ &:hover { width: 100px; }
+ }
+}''';
+ final generated4 = r'''.textLink {
+}
+.textLink a light .leftCol {
+ color: #f00;
+}
+.textLink a:hover {
+ width: 100px;
+}''';
+ compileAndValidate(input4, generated4);
+
+ final input5 = r'''.textLink { a { &:hover { color: red; } } }''';
+ final generated5 = r'''.textLink {
+}
+.textLink a:hover {
+ color: #f00;
+}''';
+
+ compileAndValidate(input5, generated5);
+
+ final input6 = r'''.textLink { &:hover { color: red; } }''';
+ final generated6 = r'''.textLink {
+}
+.textLink:hover {
+ color: #f00;
+}''';
+ compileAndValidate(input6, generated6);
+
+ final input7 = r'''.textLink { a { & + & { color: red; } } }''';
+ final generated7 = r'''.textLink {
+}
+.textLink a + .textLink a {
+ color: #f00;
+}''';
+ compileAndValidate(input7, generated7);
+
+ final input8 = r'''.textLink { a { & { color: red; } } }''';
+ final generated8 = r'''.textLink {
+}
+.textLink a {
+ color: #f00;
+}''';
+ compileAndValidate(input8, generated8);
+
+ final input9 = r'''.textLink { a { & ~ & { color: red; } } }''';
+ final generated9 = r'''.textLink {
+}
+.textLink a ~ .textLink a {
+ color: #f00;
+}''';
+ compileAndValidate(input9, generated9);
+
+ final input10 = r'''.textLink { a { & & { color: red; } } }''';
+ final generated10 = r'''.textLink {
+}
+.textLink a .textLink a {
+ color: #f00;
+}''';
+ compileAndValidate(input10, generated10);
+}
+
+void thisCombinator() {
+ var input = r'''
+.btn {
+ color: red;
+}
+.btn + .btn {
+ margin-left: 5px;
+}
+input.second {
+ & + label {
+ color: blue;
+ }
+}
+''';
+
+ var generated = r'''.btn {
+ color: #f00;
+}
+.btn + .btn {
+ margin-left: 5px;
+}
+input.second {
+}
+input.second + label {
+ color: #00f;
+}''';
+
+ compileAndValidate(input, generated);
+}
+
+void main() {
+ test('Selector and Nested Variations', selectorVariations);
+ test('Simple nesting', simpleNest);
+ test('Complex nesting', complexNest);
+ test('@media nesting', mediaNesting);
+ test('Simple &', simpleThis);
+ test('Variations &', variationsThis);
+ test('Complex &', complexThis);
+ test('& with + selector', thisCombinator);
+}
diff --git a/pkgs/csslib/test/repros_test.dart b/pkgs/csslib/test/repros_test.dart
new file mode 100644
index 0000000..ef359ca
--- /dev/null
+++ b/pkgs/csslib/test/repros_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+import 'package:test/test.dart';
+
+const options = PreprocessorOptions(
+ useColors: false,
+ warningsAsErrors: true,
+ inputFile: 'memory',
+);
+
+void main() {
+ // Repro test for https://github.com/dart-lang/csslib/issues/136.
+ test('repro_136', () {
+ final errors = <Message>[];
+
+ final css = '''
+.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),
+.hero.is-white strong {
+ color: inherit;
+}
+''';
+ final stylesheet = parse(css, errors: errors, options: options);
+ expect(stylesheet.topLevels, hasLength(1));
+ var ruleset = stylesheet.topLevels.first as RuleSet;
+
+ // This should be length 2.
+ expect(ruleset.selectorGroup!.selectors, hasLength(1));
+
+ // This test is expected to start to fail once we better support pseudo
+ // selectors.
+ // This should be empty.
+ expect(errors, hasLength(3));
+ });
+
+ // Repro test for https://github.com/dart-lang/csslib/issues/171.
+ test('repro_171', () {
+ final errors = <Message>[];
+ var stylesheet =
+ parse('body { width: 1000 px; }', errors: errors, options: options);
+ expect(errors, isEmpty);
+
+ expect(stylesheet.topLevels, hasLength(1));
+ var ruleset = stylesheet.topLevels.first as RuleSet;
+ expect(ruleset.selectorGroup!.selectors, hasLength(1));
+ expect(ruleset.declarationGroup.declarations, hasLength(1));
+
+ errors.clear();
+ stylesheet =
+ parse('body { width: 1000px; }', errors: errors, options: options);
+ expect(errors, isEmpty);
+
+ expect(stylesheet.topLevels, hasLength(1));
+ ruleset = stylesheet.topLevels.first as RuleSet;
+ expect(ruleset.selectorGroup!.selectors, hasLength(1));
+ expect(ruleset.declarationGroup.declarations, hasLength(1));
+ });
+}
diff --git a/pkgs/csslib/test/selector_test.dart b/pkgs/csslib/test/selector_test.dart
new file mode 100644
index 0000000..6d63cf8
--- /dev/null
+++ b/pkgs/csslib/test/selector_test.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/parser.dart';
+import 'package:term_glyph/term_glyph.dart' as glyph;
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void testSelectorSuccesses() {
+ var errors = <Message>[];
+ var selectorAst = selector('#div .foo', errors: errors);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect('#div .foo', compactOutput(selectorAst));
+
+ // Valid selectors for class names.
+ selectorAst = selector('.foo', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect('.foo', compactOutput(selectorAst));
+
+ selectorAst = selector('.foobar .xyzzy', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect('.foobar .xyzzy', compactOutput(selectorAst));
+
+ selectorAst = selector('.foobar .a-story .xyzzy', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect('.foobar .a-story .xyzzy', compactOutput(selectorAst));
+
+ selectorAst =
+ selector('.foobar .xyzzy .a-story .b-story', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect('.foobar .xyzzy .a-story .b-story', compactOutput(selectorAst));
+
+ // Valid selectors for element IDs.
+ selectorAst = selector('#id1', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect('#id1', compactOutput(selectorAst));
+
+ selectorAst = selector('#id-number-3', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect('#id-number-3', compactOutput(selectorAst));
+
+ selectorAst = selector('#_privateId', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect('#_privateId', compactOutput(selectorAst));
+
+ selectorAst = selector(':host', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(compactOutput(selectorAst), ':host');
+
+ selectorAst = selector(':host(.foo)', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(compactOutput(selectorAst), ':host(.foo)');
+
+ selectorAst = selector(':host-context(.foo)', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(compactOutput(selectorAst), ':host-context(.foo)');
+}
+
+// TODO(terry): Move this failure case to a failure_test.dart when the analyzer
+// and validator exit then they'll be a bunch more checks.
+void testSelectorFailures() {
+ var errors = <Message>[];
+
+ // Test for invalid class name (can't start with number).
+ selector('.foobar .1a-story .xyzzy', errors: errors);
+ expect(errors.isEmpty, false);
+ expect(
+ errors[0].toString(),
+ 'error on line 1, column 9: name must start with a alpha character, but '
+ 'found a number\n'
+ ' ,\n'
+ '1 | .foobar .1a-story .xyzzy\n'
+ ' | ^^\n'
+ ' \'');
+
+ selector(':host()', errors: errors..clear());
+ expect(
+ errors.first.toString(),
+ 'error on line 1, column 7: expected a selector argument, but found )\n'
+ ' ,\n'
+ '1 | :host()\n'
+ ' | ^\n'
+ ' \'');
+}
+
+void main() {
+ glyph.ascii = true;
+ test('Valid Selectors', testSelectorSuccesses);
+ test('Invalid Selectors', testSelectorFailures);
+}
diff --git a/pkgs/csslib/test/testing.dart b/pkgs/csslib/test/testing.dart
new file mode 100644
index 0000000..2c76e58
--- /dev/null
+++ b/pkgs/csslib/test/testing.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Common definitions used for setting up the test environment.
+library;
+
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+
+export 'package:csslib/src/preprocessor_options.dart';
+
+const PreprocessorOptions simpleOptionsWithCheckedAndWarningsAsErrors =
+ PreprocessorOptions(
+ useColors: false,
+ checked: true,
+ warningsAsErrors: true,
+ inputFile: 'memory',
+);
+
+const PreprocessorOptions simpleOptions =
+ PreprocessorOptions(useColors: false, inputFile: 'memory');
+
+const PreprocessorOptions options = PreprocessorOptions(
+ useColors: false, warningsAsErrors: true, inputFile: 'memory');
+
+/// Spin-up CSS parser in checked mode to detect any problematic CSS. Normally,
+/// CSS will allow any property/value pairs regardless of validity; all of our
+/// tests (by default) will ensure that the CSS is really valid.
+StyleSheet parseCss(String cssInput,
+ {List<Message>? errors, PreprocessorOptions? opts}) =>
+ parse(cssInput,
+ errors: errors,
+ options: opts ?? simpleOptionsWithCheckedAndWarningsAsErrors);
+
+/// Spin-up CSS parser in checked mode to detect any problematic CSS. Normally,
+/// CSS will allow any property/value pairs regardless of validity; all of our
+/// tests (by default) will ensure that the CSS is really valid.
+StyleSheet compileCss(String cssInput,
+ {List<Message>? errors,
+ PreprocessorOptions? opts,
+ bool polyfill = false,
+ List<StyleSheet>? includes}) =>
+ compile(cssInput,
+ errors: errors,
+ options: opts ?? simpleOptionsWithCheckedAndWarningsAsErrors,
+ polyfill: polyfill,
+ includes: includes);
+
+StyleSheet polyFillCompileCss(String input,
+ {List<Message>? errors, PreprocessorOptions? opts}) =>
+ compileCss(input, errors: errors, polyfill: true, opts: opts);
+
+/// Pretty printer for CSS.
+String prettyPrint(StyleSheet ss) {
+ // Walk the tree testing basic Visitor class.
+ walkTree(ss);
+ return (CssPrinter()..visitTree(ss, pretty: true)).toString();
+}
+
+/// Helper function to emit compact (non-pretty printed) CSS for suite test
+/// comparisons. Spaces, new lines, etc. are reduced for easier comparisons of
+/// expected suite test results.
+String compactOutput(StyleSheet ss) {
+ walkTree(ss);
+ return (CssPrinter()..visitTree(ss, pretty: false)).toString();
+}
+
+String printExpressions(Expressions node) {
+ var printer = CssPrinter();
+ // TODO: It would be nice if TreeNode had an `accept` method.
+ printer.visitExpressions(node);
+ return printer.toString();
+}
+
+/// Walks the style sheet tree does nothing; insures the basic walker works.
+void walkTree(StyleSheet ss) {
+ Visitor().visitTree(ss);
+}
+
+String dumpTree(StyleSheet ss) => treeToDebugString(ss);
diff --git a/pkgs/csslib/test/third_party_samples_test.dart b/pkgs/csslib/test/third_party_samples_test.dart
new file mode 100644
index 0000000..f4aee70
--- /dev/null
+++ b/pkgs/csslib/test/third_party_samples_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'dart:io';
+
+import 'package:csslib/parser.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+const testOptions = PreprocessorOptions(
+ useColors: false,
+ checked: false,
+ warningsAsErrors: true,
+ inputFile: 'memory',
+);
+
+void testCSSFile(File cssFile) {
+ final errors = <Message>[];
+ final css = cssFile.readAsStringSync();
+ final stylesheet = parse(css, errors: errors, options: testOptions);
+
+ expect(stylesheet, isNotNull);
+ expect(errors, isEmpty, reason: errors.toString());
+}
+
+void main() async {
+ // Iterate over all sub-folders of third_party,
+ // and then all css files in those.
+ final thirdParty = path.join(Directory.current.path, 'third_party');
+ for (var entity in Directory(thirdParty).listSync()) {
+ if (await FileSystemEntity.isDirectory(entity.path)) {
+ for (var element in Directory(entity.path).listSync()) {
+ if (element is File && element.uri.pathSegments.last.endsWith('.css')) {
+ test(element.uri.pathSegments.last, () => testCSSFile(element));
+ }
+ }
+ }
+ }
+}
diff --git a/pkgs/csslib/test/var_test.dart b/pkgs/csslib/test/var_test.dart
new file mode 100644
index 0000000..b3b0933
--- /dev/null
+++ b/pkgs/csslib/test/var_test.dart
@@ -0,0 +1,952 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/src/messages.dart';
+import 'package:term_glyph/term_glyph.dart' as glyph;
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+void compileAndValidate(String input, String generated) {
+ var errors = <Message>[];
+ var stylesheet = compileCss(input, errors: errors, opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void compilePolyfillAndValidate(String input, String generated) {
+ var errors = <Message>[];
+ var stylesheet = polyFillCompileCss(input, errors: errors, opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+}
+
+void simpleVar() {
+ final input = '''
+:root {
+ var-color-background: red;
+ var-color-foreground: blue;
+
+ var-c: #00ff00;
+ var-b: var(c);
+ var-a: var(b);
+ var-level-1-normal: 1px;
+}
+.testIt {
+ color: var(color-foreground);
+ background: var(color-background);
+ border-radius: var(level-1-normal);
+}
+''';
+
+ final generated = '''
+:root {
+ var-color-background: #f00;
+ var-color-foreground: #00f;
+ var-c: #0f0;
+ var-b: var(c);
+ var-a: var(b);
+ var-level-1-normal: 1px;
+}
+.testIt {
+ color: var(color-foreground);
+ background: var(color-background);
+ border-radius: var(level-1-normal);
+}''';
+
+ final generatedPolyfill = '''
+:root {
+}
+.testIt {
+ color: #00f;
+ background: #f00;
+ border-radius: 1px;
+}''';
+
+ compileAndValidate(input, generated);
+ compilePolyfillAndValidate(input, generatedPolyfill);
+}
+
+void expressionsVar() {
+ final input = '''
+:root {
+ var-color-background: red;
+ var-color-foreground: blue;
+
+ var-c: #00ff00;
+ var-b: var(c);
+ var-a: var(b);
+
+ var-image: url(test.png);
+
+ var-b-width: 20cm;
+ var-m-width: 33%;
+ var-b-height: 30EM;
+ var-width: .6in;
+ var-length: 1.2in;
+ var-web-stuff: -10Px;
+ var-rgba: rgba(10,20,255);
+ var-transition: color 0.4s;
+ var-transform: rotate(20deg);
+ var-content: "✔";
+ var-text-shadow: 0 -1px 0 #bfbfbf;
+ var-font-family: Gentium;
+ var-src: url("http://example.com/fonts/Gentium.ttf");
+ var-src-1: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+ var-unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+ var-unicode-range-1: U+0A-FF, U+980-9FF, U+????, U+3???;
+ var-grid-columns: 10px ("content" 1fr 10px) [4];
+}
+
+.testIt {
+ color: var(color-foreground);
+ background: var(c);
+ background-image: var(image);
+
+ border-width: var(b-width);
+ margin-width: var(m-width);
+ border-height: var(b-height);
+ width: var(width);
+ length: var(length);
+ -web-stuff: var(web-stuff);
+ background-color: var(rgba);
+
+ transition: var(transition);
+ transform: var(transform);
+ content: var(content);
+ text-shadow: var(text-shadow);
+}
+
+@font-face {
+ font-family: var(font-family);
+ src: var(src);
+ unicode-range: var(unicode-range);
+}
+
+@font-face {
+ font-family: var(font-family);
+ src: var(src-1);
+ unicode-range: var(unicode-range-1);
+}
+
+.foobar {
+ grid-columns: var(grid-columns);
+}
+''';
+
+ final generated = '''
+:root {
+ var-color-background: #f00;
+ var-color-foreground: #00f;
+ var-c: #0f0;
+ var-b: var(c);
+ var-a: var(b);
+ var-image: url("test.png");
+ var-b-width: 20cm;
+ var-m-width: 33%;
+ var-b-height: 30em;
+ var-width: .6in;
+ var-length: 1.2in;
+ var-web-stuff: -10px;
+ var-rgba: rgba(10, 20, 255);
+ var-transition: color 0.4s;
+ var-transform: rotate(20deg);
+ var-content: "✔";
+ var-text-shadow: 0 -1px 0 #bfbfbf;
+ var-font-family: Gentium;
+ var-src: url("http://example.com/fonts/Gentium.ttf");
+ var-src-1: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+ var-unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+ var-unicode-range-1: U+0A-FF, U+980-9FF, U+????, U+3???;
+ var-grid-columns: 10px ("content" 1fr 10px) [4];
+}
+.testIt {
+ color: var(color-foreground);
+ background: var(c);
+ background-image: var(image);
+ border-width: var(b-width);
+ margin-width: var(m-width);
+ border-height: var(b-height);
+ width: var(width);
+ length: var(length);
+ -web-stuff: var(web-stuff);
+ background-color: var(rgba);
+ transition: var(transition);
+ transform: var(transform);
+ content: var(content);
+ text-shadow: var(text-shadow);
+}
+@font-face {
+ font-family: var(font-family);
+ src: var(src);
+ unicode-range: var(unicode-range);
+}
+@font-face {
+ font-family: var(font-family);
+ src: var(src-1);
+ unicode-range: var(unicode-range-1);
+}
+.foobar {
+ grid-columns: var(grid-columns);
+}''';
+
+ compileAndValidate(input, generated);
+
+ var generatedPolyfill = r'''
+:root {
+}
+.testIt {
+ color: #00f;
+ background: #0f0;
+ background-image: url("test.png");
+ border-width: 20cm;
+ margin-width: 33%;
+ border-height: 30em;
+ width: .6in;
+ length: 1.2in;
+ -web-stuff: -10px;
+ background-color: rgba(10, 20, 255);
+ transition: color 0.4s;
+ transform: rotate(20deg);
+ content: "✔";
+ text-shadow: 0 -1px 0 #bfbfbf;
+}
+@font-face {
+ font-family: Gentium;
+ src: url("http://example.com/fonts/Gentium.ttf");
+ unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+}
+@font-face {
+ font-family: Gentium;
+ src: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+ unicode-range: U+0A-FF, U+980-9FF, U+????, U+3???;
+}
+.foobar {
+ grid-columns: 10px ("content" 1fr 10px) [4];
+}''';
+
+ compilePolyfillAndValidate(input, generatedPolyfill);
+}
+
+void defaultVar() {
+ final input = '''
+:root {
+ var-color-background: red;
+ var-color-foreground: blue;
+
+ var-a: var(b, #0a0);
+ var-b: var(c, #0b0);
+ var-c: #00ff00;
+
+ var-image: url(test.png);
+
+ var-b-width: 20cm;
+ var-m-width: 33%;
+ var-b-height: 30EM;
+}
+
+.test {
+ background-color: var(test, orange);
+}
+
+body {
+ background: var(a) var(image) no-repeat right top;
+}
+
+div {
+ background: var(color-background) url('img_tree.png') no-repeat right top;
+}
+
+.test-2 {
+ background: var(color-background) var(image-2, url('img_1.png'))
+ no-repeat right top;
+}
+
+.test-3 {
+ background: var(color-background) var(image) no-repeat right top;
+}
+
+.test-4 {
+ background: #ffff00 var(image) no-repeat right top;
+}
+
+.test-5 {
+ background: var(test-color, var(a)) var(image) no-repeat right top;
+}
+
+.test-6 {
+ border: red var(a-1, solid 20px);
+}
+''';
+
+ final generated = '''
+:root {
+ var-color-background: #f00;
+ var-color-foreground: #00f;
+ var-a: var(b, #0a0);
+ var-b: var(c, #0b0);
+ var-c: #0f0;
+ var-image: url("test.png");
+ var-b-width: 20cm;
+ var-m-width: 33%;
+ var-b-height: 30em;
+}
+.test {
+ background-color: var(test, #ffa500);
+}
+body {
+ background: var(a) var(image) no-repeat right top;
+}
+div {
+ background: var(color-background) url("img_tree.png") no-repeat right top;
+}
+.test-2 {
+ background: var(color-background) var(image-2, url("img_1.png")) no-repeat right top;
+}
+.test-3 {
+ background: var(color-background) var(image) no-repeat right top;
+}
+.test-4 {
+ background: #ff0 var(image) no-repeat right top;
+}
+.test-5 {
+ background: var(test-color, var(a)) var(image) no-repeat right top;
+}
+.test-6 {
+ border: #f00 var(a-1, solid 20px);
+}''';
+
+ compileAndValidate(input, generated);
+
+ var generatedPolyfill = r'''
+:root {
+}
+.test {
+ background-color: #ffa500;
+}
+body {
+ background: #0a0 url("test.png") no-repeat right top;
+}
+div {
+ background: #f00 url("img_tree.png") no-repeat right top;
+}
+.test-2 {
+ background: #f00 url("img_1.png") no-repeat right top;
+}
+.test-3 {
+ background: #f00 url("test.png") no-repeat right top;
+}
+.test-4 {
+ background: #ff0 url("test.png") no-repeat right top;
+}
+.test-5 {
+ background: #0a0 url("test.png") no-repeat right top;
+}
+.test-6 {
+ border: #f00 solid 20px;
+}''';
+
+ compilePolyfillAndValidate(input, generatedPolyfill);
+}
+
+void undefinedVars() {
+ final errors = <Message>[];
+ final input = '''
+:root {
+ var-color-background: red;
+ var-color-foreground: blue;
+
+ var-a: var(b);
+ var-b: var(c);
+ var-c: #00ff00;
+
+ var-one: var(two);
+ var-two: var(one);
+
+ var-four: var(five);
+ var-five: var(six);
+ var-six: var(four);
+
+ var-def-1: var(def-2);
+ var-def-2: var(def-3);
+ var-def-3: var(def-2);
+}
+
+.testIt {
+ color: var(color-foreground);
+ background: var(color-background);
+}
+.test-1 {
+ color: var(c);
+}
+.test-2 {
+ color: var(one);
+ background: var(six);
+}
+''';
+
+ final generatedPolyfill = '''
+:root {
+}
+.testIt {
+ color: #00f;
+ background: #f00;
+}
+.test-1 {
+ color: #0f0;
+}
+.test-2 {
+ color: ;
+ background: ;
+}''';
+
+ var errorStrings = [
+ 'error on line 5, column 14: Variable is not defined.\n'
+ ' ,\n'
+ '5 | var-a: var(b);\n'
+ ' | ^^\n'
+ ' \'',
+ 'error on line 6, column 14: Variable is not defined.\n'
+ ' ,\n'
+ '6 | var-b: var(c);\n'
+ ' | ^^\n'
+ ' \'',
+ 'error on line 9, column 16: Variable is not defined.\n'
+ ' ,\n'
+ '9 | var-one: var(two);\n'
+ ' | ^^^^\n'
+ ' \'',
+ 'error on line 12, column 17: Variable is not defined.\n'
+ ' ,\n'
+ '12 | var-four: var(five);\n'
+ ' | ^^^^^\n'
+ ' \'',
+ 'error on line 13, column 17: Variable is not defined.\n'
+ ' ,\n'
+ '13 | var-five: var(six);\n'
+ ' | ^^^^\n'
+ ' \'',
+ 'error on line 16, column 18: Variable is not defined.\n'
+ ' ,\n'
+ '16 | var-def-1: var(def-2);\n'
+ ' | ^^^^^^\n'
+ ' \'',
+ 'error on line 17, column 18: Variable is not defined.\n'
+ ' ,\n'
+ '17 | var-def-2: var(def-3);\n'
+ ' | ^^^^^^\n'
+ ' \'',
+ ];
+
+ var generated = r'''
+:root {
+ var-color-background: #f00;
+ var-color-foreground: #00f;
+ var-a: var(b);
+ var-b: var(c);
+ var-c: #0f0;
+ var-one: var(two);
+ var-two: var(one);
+ var-four: var(five);
+ var-five: var(six);
+ var-six: var(four);
+ var-def-1: var(def-2);
+ var-def-2: var(def-3);
+ var-def-3: var(def-2);
+}
+.testIt {
+ color: var(color-foreground);
+ background: var(color-background);
+}
+.test-1 {
+ color: var(c);
+}
+.test-2 {
+ color: var(one);
+ background: var(six);
+}''';
+ var testBitMap = 0;
+
+ compileAndValidate(input, generated);
+
+ var stylesheet =
+ polyFillCompileCss(input, errors: errors..clear(), opts: options);
+
+ expect(errors.length, errorStrings.length, reason: errors.toString());
+ testBitMap = 0;
+
+ outer:
+ for (var error in errors) {
+ var errorString = error.toString();
+ for (var i = 0; i < errorStrings.length; i++) {
+ if (errorString == errorStrings[i]) {
+ testBitMap |= 1 << i;
+ continue outer;
+ }
+ }
+ fail('Unexpected error string: $errorString');
+ }
+ expect(testBitMap, equals((1 << errorStrings.length) - 1));
+ expect(prettyPrint(stylesheet), generatedPolyfill);
+}
+
+void parserVar() {
+ final input = '''
+:root {
+ var-color-background: red;
+ var-color-foreground: blue;
+
+ var-c: #00ff00;
+ var-b: var(c);
+ var-a: var(b);
+
+ var-image: url(test.png);
+
+ var-b-width: 20cm;
+ var-m-width: 33%;
+ var-b-height: 30EM;
+ var-width: .6in;
+ var-length: 1.2in;
+ var-web-stuff: -10Px;
+ var-rgba: rgba(10,20,255);
+ var-transition: color 0.4s;
+ var-transform: rotate(20deg);
+ var-content: "✔";
+ var-text-shadow: 0 -1px 0 #bfbfbf;
+ var-font-family: Gentium;
+ var-src: url("http://example.com/fonts/Gentium.ttf");
+ var-src-1: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+ var-unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+ var-unicode-range-1: U+0A-FF, U+980-9FF, U+????, U+3???;
+ var-grid-columns: 10px ("content" 1fr 10px) [4];
+}
+
+.testIt {
+ color: var(color-foreground);
+ background: var(c);
+ background-image: var(image);
+
+ border-width: var(b-width);
+ margin-width: var(m-width);
+ border-height: var(b-height);
+ width: var(width);
+ length: var(length);
+ -web-stuff: var(web-stuff);
+ background-color: var(rgba);
+
+ transition: var(transition);
+ transform: var(transform);
+ content: var(content);
+ text-shadow: var(text-shadow);
+}
+
+@font-face {
+ font-family: var(font-family);
+ src: var(src);
+ unicode-range: var(unicode-range);
+}
+
+@font-face {
+ font-family: var(font-family);
+ src: var(src-1);
+ unicode-range: var(unicode-range-1);
+}
+
+.foobar {
+ grid-columns: var(grid-columns);
+}
+''';
+
+ final generated = '''
+:root {
+ var-color-background: #f00;
+ var-color-foreground: #00f;
+ var-c: #0f0;
+ var-b: var(c);
+ var-a: var(b);
+ var-image: url("test.png");
+ var-b-width: 20cm;
+ var-m-width: 33%;
+ var-b-height: 30em;
+ var-width: .6in;
+ var-length: 1.2in;
+ var-web-stuff: -10px;
+ var-rgba: rgba(10, 20, 255);
+ var-transition: color 0.4s;
+ var-transform: rotate(20deg);
+ var-content: "✔";
+ var-text-shadow: 0 -1px 0 #bfbfbf;
+ var-font-family: Gentium;
+ var-src: url("http://example.com/fonts/Gentium.ttf");
+ var-src-1: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+ var-unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+ var-unicode-range-1: U+0A-FF, U+980-9FF, U+????, U+3???;
+ var-grid-columns: 10px ("content" 1fr 10px) [4];
+}
+.testIt {
+ color: var(color-foreground);
+ background: var(c);
+ background-image: var(image);
+ border-width: var(b-width);
+ margin-width: var(m-width);
+ border-height: var(b-height);
+ width: var(width);
+ length: var(length);
+ -web-stuff: var(web-stuff);
+ background-color: var(rgba);
+ transition: var(transition);
+ transform: var(transform);
+ content: var(content);
+ text-shadow: var(text-shadow);
+}
+@font-face {
+ font-family: var(font-family);
+ src: var(src);
+ unicode-range: var(unicode-range);
+}
+@font-face {
+ font-family: var(font-family);
+ src: var(src-1);
+ unicode-range: var(unicode-range-1);
+}
+.foobar {
+ grid-columns: var(grid-columns);
+}''';
+
+ compileAndValidate(input, generated);
+
+ var generatedPolyfill = r'''
+:root {
+}
+.testIt {
+ color: #00f;
+ background: #0f0;
+ background-image: url("test.png");
+ border-width: 20cm;
+ margin-width: 33%;
+ border-height: 30em;
+ width: .6in;
+ length: 1.2in;
+ -web-stuff: -10px;
+ background-color: rgba(10, 20, 255);
+ transition: color 0.4s;
+ transform: rotate(20deg);
+ content: "✔";
+ text-shadow: 0 -1px 0 #bfbfbf;
+}
+@font-face {
+ font-family: Gentium;
+ src: url("http://example.com/fonts/Gentium.ttf");
+ unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
+}
+@font-face {
+ font-family: Gentium;
+ src: local(Gentium Bold), local(Gentium-Bold), url("GentiumBold.ttf");
+ unicode-range: U+0A-FF, U+980-9FF, U+????, U+3???;
+}
+.foobar {
+ grid-columns: 10px ("content" 1fr 10px) [4];
+}''';
+ compilePolyfillAndValidate(input, generatedPolyfill);
+}
+
+void testVar() {
+ final errors = <Message>[];
+ final input = '''
+@color-background: red;
+@color-foreground: blue;
+
+.test {
+ background-color: var(color-background);
+ color: var(color-foreground);
+}
+''';
+ final generated = '''
+var-color-background: #f00;
+var-color-foreground: #00f;
+.test {
+ background-color: var(color-background);
+ color: var(color-foreground);
+}''';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ compileAndValidate(input, generated);
+
+ final input2 = '''
+@color-background: red;
+@color-foreground: blue;
+
+.test {
+ background-color: @color-background;
+ color: @color-foreground;
+}
+''';
+ final generated2 = '''
+var-color-background: #f00;
+var-color-foreground: #00f;
+.test {
+ background-color: var(color-background);
+ color: var(color-foreground);
+}''';
+
+ stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated2);
+
+ compileAndValidate(input2, generated2);
+}
+
+void testLess() {
+ final errors = <Message>[];
+ final input = '''
+@color-background: red;
+@color-foreground: blue;
+
+.test {
+ background-color: var(color-background);
+ color: var(color-foreground);
+}
+''';
+ final generated = '''
+var-color-background: #f00;
+var-color-foreground: #00f;
+.test {
+ background-color: var(color-background);
+ color: var(color-foreground);
+}''';
+
+ var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated);
+
+ compileAndValidate(input, generated);
+
+ final input2 = '''
+@color-background: red;
+@color-foreground: blue;
+
+.test {
+ background-color: @color-background;
+ color: @color-foreground;
+}
+''';
+ final generated2 = '''
+var-color-background: #f00;
+var-color-foreground: #00f;
+.test {
+ background-color: var(color-background);
+ color: var(color-foreground);
+}''';
+
+ stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet), generated2);
+
+ compileAndValidate(input2, generated2);
+}
+
+void polyfill() {
+ compilePolyfillAndValidate(r'''
+@color-background: red;
+@color-foreground: blue;
+.test {
+ background-color: @color-background;
+ color: @color-foreground;
+}''', r'''
+.test {
+ background-color: #f00;
+ color: #00f;
+}''');
+}
+
+void testIndirects() {
+ compilePolyfillAndValidate('''
+:root {
+ var-redef: #0f0;
+
+ var-a1: #fff;
+ var-a2: var(a1);
+ var-a3: var(a2);
+
+ var-redef: #000;
+}
+.test {
+ background-color: @a1;
+ color: @a2;
+ border-color: @a3;
+}
+.test-1 {
+ color: @redef;
+}''', r'''
+:root {
+}
+.test {
+ background-color: #fff;
+ color: #fff;
+ border-color: #fff;
+}
+.test-1 {
+ color: #000;
+}''');
+}
+
+void includes() {
+ var errors = <Message>[];
+ var file1Input = r'''
+:root {
+ var-redef: #0f0;
+
+ var-a1: #fff;
+ var-a2: var(a1);
+ var-a3: var(a2);
+
+ var-redef: #000;
+}
+.test-1 {
+ background-color: @a1;
+ color: @a2;
+ border-color: @a3;
+}
+.test-1a {
+ color: @redef;
+}
+''';
+
+ var file2Input = r'''
+:root {
+ var-redef: #0b0;
+ var-b3: var(a3);
+}
+.test-2 {
+ color: var(b3);
+ background-color: var(redef);
+ border-color: var(a3);
+}
+''';
+
+ var input = r'''
+:root {
+ var-redef: #0c0;
+}
+.test-main {
+ color: var(b3);
+ background-color: var(redef);
+ border-color: var(a3);
+}
+''';
+
+ var generated1 = r'''
+:root {
+ var-redef: #0f0;
+ var-a1: #fff;
+ var-a2: var(a1);
+ var-a3: var(a2);
+ var-redef: #000;
+}
+.test-1 {
+ background-color: var(a1);
+ color: var(a2);
+ border-color: var(a3);
+}
+.test-1a {
+ color: var(redef);
+}''';
+
+ var stylesheet1 = compileCss(file1Input, errors: errors, opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet1), generated1);
+
+ var generated2 = r'''
+:root {
+ var-redef: #0b0;
+ var-b3: var(a3);
+}
+.test-2 {
+ color: var(b3);
+ background-color: var(redef);
+ border-color: var(a3);
+}''';
+
+ var stylesheet2 = compileCss(file2Input,
+ includes: [stylesheet1], errors: errors..clear(), opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheet2), generated2);
+
+ var generatedPolyfill1 = r'''
+:root {
+}
+.test-1 {
+ background-color: #fff;
+ color: #fff;
+ border-color: #fff;
+}
+.test-1a {
+ color: #000;
+}''';
+ var styleSheet1Polyfill = compileCss(file1Input,
+ errors: errors..clear(), polyfill: true, opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(styleSheet1Polyfill), generatedPolyfill1);
+
+ var generatedPolyfill2 = r'''
+:root {
+}
+.test-2 {
+ color: #fff;
+ background-color: #0b0;
+ border-color: #fff;
+}''';
+ var styleSheet2Polyfill = compileCss(file2Input,
+ includes: [stylesheet1],
+ errors: errors..clear(),
+ polyfill: true,
+ opts: options);
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(styleSheet2Polyfill), generatedPolyfill2);
+
+ // Make sure includes didn't change.
+ expect(prettyPrint(stylesheet1), generated1);
+
+ var generatedPolyfill = r'''
+:root {
+}
+.test-main {
+ color: #fff;
+ background-color: #0c0;
+ border-color: #fff;
+}''';
+ var stylesheetPolyfill = compileCss(input,
+ includes: [stylesheet1, stylesheet2],
+ errors: errors..clear(),
+ polyfill: true,
+ opts: options);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(prettyPrint(stylesheetPolyfill), generatedPolyfill);
+
+ // Make sure includes didn't change.
+ expect(prettyPrint(stylesheet1), generated1);
+ expect(prettyPrint(stylesheet2), generated2);
+}
+
+void main() {
+ glyph.ascii = true;
+ test('Simple var', simpleVar);
+ test('Expressions var', expressionsVar);
+ test('Default value in var()', defaultVar);
+ test('CSS Parser only var', parserVar);
+ test('Var syntax', testVar);
+ test('Indirects', testIndirects);
+ test('Forward Refs', undefinedVars);
+ test('Less syntax', testLess);
+ test('Polyfill', polyfill);
+ test('Multi-file', includes);
+}
diff --git a/pkgs/csslib/test/visitor_test.dart b/pkgs/csslib/test/visitor_test.dart
new file mode 100644
index 0000000..5442903
--- /dev/null
+++ b/pkgs/csslib/test/visitor_test.dart
@@ -0,0 +1,136 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:csslib/src/messages.dart';
+import 'package:csslib/visitor.dart';
+import 'package:test/test.dart';
+
+import 'testing.dart';
+
+class ClassVisitor extends Visitor {
+ final List<String> expectedClasses;
+ final foundClasses = <String>{};
+
+ ClassVisitor(this.expectedClasses);
+
+ @override
+ void visitClassSelector(ClassSelector node) {
+ foundClasses.add(node.name);
+ }
+
+ bool get matches {
+ var match = true;
+ for (var value in foundClasses) {
+ match = match && expectedClasses.contains(value);
+ }
+ for (var value in expectedClasses) {
+ match = match && foundClasses.contains(value);
+ }
+
+ return match;
+ }
+}
+
+void testClassVisitors() {
+ var errors = <Message>[];
+ var in1 = '.foobar { }';
+
+ var s = parseCss(in1, errors: errors);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ var clsVisits = ClassVisitor(['foobar'])..visitTree(s);
+ expect(clsVisits.matches, true);
+
+ in1 = '''
+ .foobar1 { }
+ .xyzzy .foo #my-div { color: red; }
+ div.hello { font: arial; }
+ ''';
+
+ s = parseCss(in1, errors: errors..clear(), opts: simpleOptions);
+
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ clsVisits = ClassVisitor(['foobar1', 'xyzzy', 'foo', 'hello'])..visitTree(s);
+ expect(clsVisits.matches, true);
+
+ expect(prettyPrint(s), r'''
+.foobar1 {
+}
+.xyzzy .foo #my-div {
+ color: #f00;
+}
+div.hello {
+ font: arial;
+}''');
+}
+
+class PolyfillEmitter extends CssPrinter {
+ final String _prefix;
+
+ PolyfillEmitter(this._prefix);
+
+ @override
+ void visitClassSelector(ClassSelector node) {
+ emit('.${_prefix}_${node.name}');
+ }
+}
+
+String polyfillPrint(String prefix, StyleSheet ss) =>
+ (PolyfillEmitter(prefix)..visitTree(ss, pretty: true)).toString();
+
+void testPolyFill() {
+ var errors = <Message>[];
+ final input = r'''
+.foobar { }
+div.xyzzy { }
+#foo .foo .bar .foobar { }
+''';
+
+ final generated = r'''
+.myComponent_foobar {
+}
+div.myComponent_xyzzy {
+}
+#foo .myComponent_foo .myComponent_bar .myComponent_foobar {
+}''';
+
+ var s = parseCss(input, errors: errors);
+ expect(errors.isEmpty, true, reason: errors.toString());
+
+ final emitted = polyfillPrint('myComponent', s);
+ expect(emitted, generated);
+}
+
+void main() {
+ test('Class Visitors', testClassVisitors);
+ test('Polyfill', testPolyFill);
+ test('pretty-print', testPrettyPrint);
+}
+
+void testPrettyPrint() {
+ final input = '''
+.good { color: red; }@media screen { .better { color: blue; } }.best { color: green }''';
+
+ var styleSheet = parseCss(input);
+
+ // pretty print
+ expect(prettyPrint(styleSheet), '''
+.good {
+ color: #f00;
+}
+@media screen {
+ .better {
+ color: #00f;
+ }
+}
+.best {
+ color: #008000;
+}''');
+
+ // compact output
+ expect(compactOutput(styleSheet), '''
+.good{color:red}@media screen{.better{color:blue}}.best{color:green}''');
+}
diff --git a/pkgs/csslib/third_party/README.md b/pkgs/csslib/third_party/README.md
new file mode 100644
index 0000000..a68a963
--- /dev/null
+++ b/pkgs/csslib/third_party/README.md
@@ -0,0 +1,2 @@
+This folder contains resources from third parties.
+See each subfolder for details.
diff --git a/pkgs/csslib/third_party/base/README.md b/pkgs/csslib/third_party/base/README.md
new file mode 100644
index 0000000..3e2b261
--- /dev/null
+++ b/pkgs/csslib/third_party/base/README.md
@@ -0,0 +1,5 @@
+This folder contains a sample css file from the open-source project
+https://github.com/getbase/base.
+
+This code was included under the
+[MIT Open Source](https://opensource.org/licenses/MIT) license.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/base/index.css b/pkgs/csslib/third_party/base/index.css
new file mode 100644
index 0000000..95156ce
--- /dev/null
+++ b/pkgs/csslib/third_party/base/index.css
@@ -0,0 +1 @@
+*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}.sr{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1rem}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}table{text-align:left;border-collapse:collapse;border-spacing:0;width:100%;margin:0;border:1px solid #e9e9e9}table td,table th{padding:1rem;border-bottom:1px solid #e9e9e9;border-right:1px solid #e9e9e9}table tr:nth-child(2n){background-color:#f6f8fa}body{font-family:sans-serif;font-size:16px;line-height:22px;color:#232323;font-weight:400;background:#fff}details,main{display:block}a{background-color:rgba(0,0,0,0)}.b,.strong,b,strong{font-weight:700}.em,em{font-style:italic}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.small,small{font-size:.8125rem}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}[hidden],template{display:none}h1,h2,h3,h4,h5,h6{font-family:sans-serif;margin:.5rem 0}.h1,h1{font-size:32px;line-height:38px}.h2,h2{font-size:26px;line-height:32px}.h3,h3{font-size:22px;line-height:28px}.h4,h4{font-size:18px;line-height:24px}.h5,h5{font-size:16px;line-height:22px}.h6,h6{font-size:14px;line-height:20px}.container{max-width:1168px;padding-left:16px;padding-right:16px;margin-left:auto;margin-right:auto}@media only screen and (min-width:768px){.container-m{width:736px;max-width:auto;padding-left:16px;padding-right:16px;margin-left:auto;margin-right:auto}}@media only screen and (min-width:980px){.container-l{width:948px;max-width:auto;padding-left:16px;padding-right:16px;margin-left:auto;margin-right:auto}}@media only screen and (min-width:1200px){.container-xl{width:1168px;max-width:auto;padding-left:16px;padding-right:16px;margin-left:auto;margin-right:auto}}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;position:relative;margin-left:-16px;margin-right:-16px}.col-1,.col-1-2,.col-1-3,.col-1-4,.col-1-5,.col-2,.col-2-3,.col-2-5,.col-3,.col-3-4,.col-3-5,.col-4,.col-4-5,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;padding-left:16px;padding-right:16px}.col-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-1,.col-2{-webkit-box-flex:0}.col-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-3,.col-4{-webkit-box-flex:0}.col-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-5,.col-6{-webkit-box-flex:0}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-7,.col-8{-webkit-box-flex:0}.col-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-9,.col-10{-webkit-box-flex:0}.col-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-11,.col-12{-webkit-box-flex:0}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.col-1-2{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-1-2,.col-1-3{-webkit-box-flex:0}.col-1-3{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-2-3{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-1-4,.col-2-3{-webkit-box-flex:0}.col-1-4{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-3-4{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-1-5,.col-3-4{-webkit-box-flex:0}.col-1-5{-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.col-2-5{-ms-flex:0 0 40%;flex:0 0 40%;max-width:40%}.col-2-5,.col-3-5{-webkit-box-flex:0}.col-3-5{-ms-flex:0 0 60%;flex:0 0 60%;max-width:60%}.col-4-5{-webkit-box-flex:0;-ms-flex:0 0 80%;flex:0 0 80%;max-width:80%}.col-full{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-preferred-size:0;flex-basis:0;max-width:100%}@media only screen and (min-width:768px){.row-m{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;position:relative;margin-left:-16px;margin-right:-16px}.col-1-2-m,.col-1-3-m,.col-1-4-m,.col-1-5-m,.col-1-m,.col-2-3-m,.col-2-5-m,.col-2-m,.col-3-4-m,.col-3-5-m,.col-3-m,.col-4-5-m,.col-4-m,.col-5-m,.col-6-m,.col-7-m,.col-8-m,.col-9-m,.col-10-m,.col-11-m,.col-12-m{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;padding-left:16px;padding-right:16px}.col-1-m{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-1-m,.col-2-m{-webkit-box-flex:0}.col-2-m{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-3-m{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-3-m,.col-4-m{-webkit-box-flex:0}.col-4-m{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-5-m{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-5-m,.col-6-m{-webkit-box-flex:0}.col-6-m{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7-m{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-7-m,.col-8-m{-webkit-box-flex:0}.col-8-m{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-9-m{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10-m{-webkit-box-flex:0;-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-11-m{-webkit-box-flex:0;-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-12-m{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.col-1-2-m{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-1-3-m{-webkit-box-flex:0;-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-2-3-m{-webkit-box-flex:0;-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-1-4-m{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-3-4-m{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-1-5-m{-webkit-box-flex:0;-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.col-2-5-m{-webkit-box-flex:0;-ms-flex:0 0 40%;flex:0 0 40%;max-width:40%}.col-3-5-m{-webkit-box-flex:0;-ms-flex:0 0 60%;flex:0 0 60%;max-width:60%}.col-4-5-m{-webkit-box-flex:0;-ms-flex:0 0 80%;flex:0 0 80%;max-width:80%}.col-full-m{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-preferred-size:0;flex-basis:0;max-width:100%}}@media only screen and (min-width:980px){.row-l{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;position:relative;margin-left:-16px;margin-right:-16px}.col-1-2-l,.col-1-3-l,.col-1-4-l,.col-1-5-l,.col-1-l,.col-2-3-l,.col-2-5-l,.col-2-l,.col-3-4-l,.col-3-5-l,.col-3-l,.col-4-5-l,.col-4-l,.col-5-l,.col-6-l,.col-7-l,.col-8-l,.col-9-l,.col-10-l,.col-11-l,.col-12-l{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;padding-left:16px;padding-right:16px}.col-1-l{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-1-l,.col-2-l{-webkit-box-flex:0}.col-2-l{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-3-l{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-3-l,.col-4-l{-webkit-box-flex:0}.col-4-l{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-5-l{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-5-l,.col-6-l{-webkit-box-flex:0}.col-6-l{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7-l{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-7-l,.col-8-l{-webkit-box-flex:0}.col-8-l{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-9-l{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10-l{-webkit-box-flex:0;-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-11-l{-webkit-box-flex:0;-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-12-l{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.col-1-2-l{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-1-3-l{-webkit-box-flex:0;-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-2-3-l{-webkit-box-flex:0;-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-1-4-l{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-3-4-l{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-1-5-l{-webkit-box-flex:0;-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.col-2-5-l{-webkit-box-flex:0;-ms-flex:0 0 40%;flex:0 0 40%;max-width:40%}.col-3-5-l{-webkit-box-flex:0;-ms-flex:0 0 60%;flex:0 0 60%;max-width:60%}.col-4-5-l{-webkit-box-flex:0;-ms-flex:0 0 80%;flex:0 0 80%;max-width:80%}.col-full-l{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-preferred-size:0;flex-basis:0;max-width:100%}}@media only screen and (min-width:1200px){.row-xl{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;position:relative;margin-left:-16px;margin-right:-16px}.col-1-2-xl,.col-1-3-xl,.col-1-4-xl,.col-1-5-xl,.col-1-xl,.col-2-3-xl,.col-2-5-xl,.col-2-xl,.col-3-4-xl,.col-3-5-xl,.col-3-xl,.col-4-5-xl,.col-4-xl,.col-5-xl,.col-6-xl,.col-7-xl,.col-8-xl,.col-9-xl,.col-10-xl,.col-11-xl,.col-12-xl{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;padding-left:16px;padding-right:16px}.col-1-xl{-webkit-box-flex:0;-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-2-xl{-webkit-box-flex:0;-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-3-xl{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4-xl{-webkit-box-flex:0;-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-5-xl{-webkit-box-flex:0;-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-6-xl{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7-xl{-webkit-box-flex:0;-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-8-xl{-webkit-box-flex:0;-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-9-xl{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10-xl{-webkit-box-flex:0;-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-11-xl{-webkit-box-flex:0;-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-12-xl{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.col-1-2-xl{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-1-3-xl{-webkit-box-flex:0;-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-2-3-xl{-webkit-box-flex:0;-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-1-4-xl{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-3-4-xl{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-1-5-xl{-webkit-box-flex:0;-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.col-2-5-xl{-webkit-box-flex:0;-ms-flex:0 0 40%;flex:0 0 40%;max-width:40%}.col-3-5-xl{-webkit-box-flex:0;-ms-flex:0 0 60%;flex:0 0 60%;max-width:60%}.col-4-5-xl{-webkit-box-flex:0;-ms-flex:0 0 80%;flex:0 0 80%;max-width:80%}.col-full-xl{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-preferred-size:0;flex-basis:0;max-width:100%}}.padding-left-0-25rem{padding-left:.25rem}.padding-left-0-5rem{padding-left:.5rem}.padding-left-1rem{padding-left:1rem}.padding-left-1-5rem{padding-left:1.5rem}.padding-left-2rem{padding-left:2rem}.padding-left-3rem{padding-left:3rem}.padding-left-4rem{padding-left:4rem}.padding-left-5rem{padding-left:5rem}.padding-right-0-25rem{padding-right:.25rem}.padding-right-0-5rem{padding-right:.5rem}.padding-right-1rem{padding-right:1rem}.padding-right-1-5rem{padding-right:1.5rem}.padding-right-2rem{padding-right:2rem}.padding-right-3rem{padding-right:3rem}.padding-right-4rem{padding-right:4rem}.padding-right-5rem{padding-right:5rem}@media only screen and (min-width:768px){.padding-left-0-m{padding-left:0}.padding-left-0-25rem-m{padding-left:.25rem}.padding-left-0-5rem-m{padding-left:.5rem}.padding-left-1rem-m{padding-left:1rem}.padding-left-1-5rem-m{padding-left:1.5rem}.padding-left-2rem-m{padding-left:2rem}.padding-left-3rem-m{padding-left:3rem}.padding-left-4rem-m{padding-left:4rem}.padding-left-5rem-m{padding-left:5rem}.padding-right-0-m{padding-right:0}.padding-right-0-25rem-m{padding-right:.25rem}.padding-right-0-5rem-m{padding-right:.5rem}.padding-right-1rem-m{padding-right:1rem}.padding-right-1-5rem-m{padding-right:1.5rem}.padding-right-2rem-m{padding-right:2rem}.padding-right-3rem-m{padding-right:3rem}.padding-right-4rem-m{padding-right:4rem}.padding-right-5rem-m{padding-right:5rem}}@media only screen and (min-width:980px){.padding-left-0-l{padding-left:0}.padding-left-0-25rem-l{padding-left:.25rem}.padding-left-0-5rem-l{padding-left:.5rem}.padding-left-1rem-l{padding-left:1rem}.padding-left-1-5rem-l{padding-left:1.5rem}.padding-left-2rem-l{padding-left:2rem}.padding-left-3rem-l{padding-left:3rem}.padding-left-4rem-l{padding-left:4rem}.padding-left-5rem-l{padding-left:5rem}.padding-right-0-l{padding-right:0}.padding-right-0-25rem-l{padding-right:.25rem}.padding-right-0-5rem-l{padding-right:.5rem}.padding-right-1rem-l{padding-right:1rem}.padding-right-1-5rem-l{padding-right:1.5rem}.padding-right-2rem-l{padding-right:2rem}.padding-right-3rem-l{padding-right:3rem}.padding-right-4rem-l{padding-right:4rem}.padding-right-5rem-l{padding-right:5rem}}@media only screen and (min-width:1200px){.padding-left-0-xl{padding-left:0}.padding-left-0-25rem-xl{padding-left:.25rem}.padding-left-0-5rem-xl{padding-left:.5rem}.padding-left-1rem-xl{padding-left:1rem}.padding-left-1-5rem-xl{padding-left:1.5rem}.padding-left-2rem-xl{padding-left:2rem}.padding-left-3rem-xl{padding-left:3rem}.padding-left-4rem-xl{padding-left:4rem}.padding-left-5rem-xl{padding-left:5rem}.padding-right-0-xl{padding-right:0}.padding-right-0-25rem-xl{padding-right:.25rem}.padding-right-0-5rem-xl{padding-right:.5rem}.padding-right-1rem-xl{padding-right:1rem}.padding-right-1-5rem-xl{padding-right:1.5rem}.padding-right-2rem-xl{padding-right:2rem}.padding-right-3rem-xl{padding-right:3rem}.padding-right-4rem-xl{padding-right:4rem}.padding-right-5rem-xl{padding-right:5rem}}.padding-top-0-25rem{padding-top:.25rem}.padding-top-0-5rem{padding-top:.5rem}.padding-top-1rem{padding-top:1rem}.padding-top-1-5rem{padding-top:1.5rem}.padding-top-2rem{padding-top:2rem}.padding-top-3rem{padding-top:3rem}.padding-top-4rem{padding-top:4rem}.padding-top-5rem{padding-top:5rem}.padding-bottom-0-25rem{padding-bottom:.25rem}.padding-bottom-0-5rem{padding-bottom:.5rem}.padding-bottom-1rem{padding-bottom:1rem}.padding-bottom-1-5rem{padding-bottom:1.5rem}.padding-bottom-2rem{padding-bottom:2rem}.padding-bottom-3rem{padding-bottom:3rem}.padding-bottom-4rem{padding-bottom:4rem}.padding-bottom-5rem{padding-bottom:5rem}@media only screen and (min-width:768px){.padding-top-0-m{padding-top:0}.padding-top-0-25rem-m{padding-top:.25rem}.padding-top-0-5rem-m{padding-top:.5rem}.padding-top-1rem-m{padding-top:1rem}.padding-top-1-5rem-m{padding-top:1.5rem}.padding-top-2rem-m{padding-top:2rem}.padding-top-3rem-m{padding-top:3rem}.padding-top-4rem-m{padding-top:4rem}.padding-top-5rem-m{padding-top:5rem}.padding-bottom-0-m{padding-bottom:0}.padding-bottom-0-25rem-m{padding-bottom:.25rem}.padding-bottom-0-5rem-m{padding-bottom:.5rem}.padding-bottom-1rem-m{padding-bottom:1rem}.padding-bottom-1-5rem-m{padding-bottom:1.5rem}.padding-bottom-2rem-m{padding-bottom:2rem}.padding-bottom-3rem-m{padding-bottom:3rem}.padding-bottom-4rem-m{padding-bottom:4rem}.padding-bottom-5rem-m{padding-bottom:5rem}}@media only screen and (min-width:980px){.padding-top-0-l{padding-top:0}.padding-top-0-25rem-l{padding-top:.25rem}.padding-top-0-5rem-l{padding-top:.5rem}.padding-top-1rem-l{padding-top:1rem}.padding-top-1-5rem-l{padding-top:1.5rem}.padding-top-2rem-l{padding-top:2rem}.padding-top-3rem-l{padding-top:3rem}.padding-top-4rem-l{padding-top:4rem}.padding-top-5rem-l{padding-top:5rem}.padding-bottom-0-l{padding-bottom:0}.padding-bottom-0-25rem-l{padding-bottom:.25rem}.padding-bottom-0-5rem-l{padding-bottom:.5rem}.padding-bottom-1rem-l{padding-bottom:1rem}.padding-bottom-1-5rem-l{padding-bottom:1.5rem}.padding-bottom-2rem-l{padding-bottom:2rem}.padding-bottom-3rem-l{padding-bottom:3rem}.padding-bottom-4rem-l{padding-bottom:4rem}.padding-bottom-5rem-l{padding-bottom:5rem}}@media only screen and (min-width:1200px){.padding-top-0-xl{padding-top:0}.padding-top-0-25rem-xl{padding-top:.25rem}.padding-top-0-5rem-xl{padding-top:.5rem}.padding-top-1rem-xl{padding-top:1rem}.padding-top-1-5rem-xl{padding-top:1.5rem}.padding-top-2rem-xl{padding-top:2rem}.padding-top-3rem-xl{padding-top:3rem}.padding-top-4rem-xl{padding-top:4rem}.padding-top-5rem-xl{padding-top:5rem}.padding-bottom-0-xl{padding-bottom:0}.padding-bottom-0-25rem-xl{padding-bottom:.25rem}.padding-bottom-0-5rem-xl{padding-bottom:.5rem}.padding-bottom-1rem-xl{padding-bottom:1rem}.padding-bottom-1-5rem-xl{padding-bottom:1.5rem}.padding-bottom-2rem-xl{padding-bottom:2rem}.padding-bottom-3rem-xl{padding-bottom:3rem}.padding-bottom-4rem-xl{padding-bottom:4rem}.padding-bottom-5rem-xl{padding-bottom:5rem}}.padding-0{padding:0}.padding-0-25rem{padding:.25rem}.padding-0-5rem{padding:.5rem}.padding-1rem{padding:1rem}.padding-1-5rem{padding:1.5rem}.padding-2rem{padding:2rem}.padding-3rem{padding:3rem}.padding-4rem{padding:4rem}.padding-5rem{padding:5rem}@media only screen and (min-width:768px){.padding-0-m{padding:0}.padding-0-25rem-m{padding:.25rem}.padding-0-5rem-m{padding:.5rem}.padding-1rem-m{padding:1rem}.padding-1-5rem-m{padding:1.5rem}.padding-2rem-m{padding:2rem}.padding-3rem-m{padding:3rem}.padding-4rem-m{padding:4rem}.padding-5rem-m{padding:5rem}}@media only screen and (min-width:980px){.padding-0-l{padding:0}.padding-0-25rem-l{padding:.25rem}.padding-0-5rem-l{padding:.5rem}.padding-1rem-l{padding:1rem}.padding-1-5rem-l{padding:1.5rem}.padding-2rem-l{padding:2rem}.padding-3rem-l{padding:3rem}.padding-4rem-l{padding:4rem}.padding-5rem-l{padding:5rem}}@media only screen and (min-width:1200px){.padding-0-xl{padding:0}.padding-0-25rem-xl{padding:.25rem}.padding-0-5rem-xl{padding:.5rem}.padding-1rem-xl{padding:1rem}.padding-1-5rem-xl{padding:1.5rem}.padding-2rem-xl{padding:2rem}.padding-3rem-xl{padding:3rem}.padding-4rem-xl{padding:4rem}.padding-5rem-xl{padding:5rem}}.none{display:none}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}@media only screen and (min-width:768px){.none-m{display:none}.block-m{display:block}.inline-block-m{display:inline-block}.inline-m{display:inline}.flex-m{display:-webkit-box;display:-ms-flexbox;display:flex}}@media only screen and (min-width:980px){.none-l{display:none}.block-l{display:block}.inline-block-l{display:inline-block}.inline-l{display:inline}.flex-l{display:-webkit-box;display:-ms-flexbox;display:flex}}@media only screen and (min-width:1200px){.block-xl,.none-xl{display:block}.inline-block-xl{display:inline-block}.inline-xl{display:inline}.flex-xl{display:-webkit-box;display:-ms-flexbox;display:flex}}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-nowrap{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-align-items-bottom,.flex-align-items-center,.flex-align-items-top{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.flex-justify-left{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.flex-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.flex-justify-right{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.flex-space-around{-ms-flex-pack:distribute;justify-content:space-around}.flex-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.flex-row{-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.flex-row,.flex-row-reverse{-webkit-box-orient:horizontal}.flex-row-reverse{-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.flex-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.flex-column-reverse{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}@media only screen and (min-width:768px){.flex-wrap-m{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-nowrap-m{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-align-items-bottom-m,.flex-align-items-center-m,.flex-align-items-top-m{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.flex-justify-left-m{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.flex-justify-center-m{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.flex-justify-right-m{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.flex-space-around-m{-ms-flex-pack:distribute;justify-content:space-around}.flex-space-between-m{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.flex-row-m{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.flex-row-reverse-m{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.flex-column-m{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.flex-column-reverse-m{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}}@media only screen and (min-width:980px){.flex-wrap-l{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-nowrap-l{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-align-items-bottom-l,.flex-align-items-center-l,.flex-align-items-top-l{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.flex-justify-left-l{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.flex-justify-center-l{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.flex-justify-right-l{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.flex-space-around-l{-ms-flex-pack:distribute;justify-content:space-around}.flex-space-between-l{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.flex-row-l{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.flex-row-reverse-l{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.flex-column-l{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.flex-column-reverse-l{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}}@media only screen and (min-width:1200px){.flex-wrap-xl{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-nowrap-xl{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-align-items-bottom-xl,.flex-align-items-center-xl,.flex-align-items-top-xl{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.flex-justify-left-xl{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.flex-justify-center-xl{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.flex-justify-right-xl{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.flex-space-around-xl{-ms-flex-pack:distribute;justify-content:space-around}.flex-space-between-xl{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.flex-row-xl{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.flex-row-reverse-xl{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.flex-column-xl{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.flex-column-reverse-xl{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}}.relative{position:relative}.absolute{position:absolute}.static{position:static}.fixed{position:fixed}.sticky{position:-webkit-sticky;position:sticky}@media only screen and (min-width:768px){.relative-m{position:relative}.absolute-m{position:absolute}.static-m{position:static}.fixed-m{position:fixed}.sticky-m{position:-webkit-sticky;position:sticky}}@media only screen and (min-width:980px){.relative-l{position:relative}.absolute-l{position:absolute}.static-l{position:static}.fixed-l{position:fixed}.sticky-l{position:-webkit-sticky;position:sticky}}@media only screen and (min-width:1200px){.relative-xl{position:relative}.absolute-xl{position:absolute}.static-xl{position:static}.fixed-xl{position:fixed}.sticky-xl{position:-webkit-sticky;position:sticky}}.no-select{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.font-100{font-weight:100}.font-200{font-weight:200}.font-300{font-weight:300}.font-400{font-weight:400}.font-500{font-weight:500}.font-600{font-weight:600}.font-700{font-weight:700}.font-800{font-weight:800}.font-900{font-weight:900}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}@media only screen and (min-width:768px){.text-left-m{text-align:left}.text-right-m{text-align:right}.text-center-m{text-align:center}}@media only screen and (min-width:980px){.text-left-l{text-align:left}.text-right-l{text-align:right}.text-center-l{text-align:center}}@media only screen and (min-width:1200px){.text-left-xl{text-align:left}.text-right-xl{text-align:right}.text-center-xl{text-align:center}}
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/bootstrap/LICENSE b/pkgs/csslib/third_party/bootstrap/LICENSE
new file mode 100644
index 0000000..72dda23
--- /dev/null
+++ b/pkgs/csslib/third_party/bootstrap/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2021 Twitter, Inc.
+Copyright (c) 2011-2021 The Bootstrap Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/pkgs/csslib/third_party/bootstrap/README.md b/pkgs/csslib/third_party/bootstrap/README.md
new file mode 100644
index 0000000..bb1d3bb
--- /dev/null
+++ b/pkgs/csslib/third_party/bootstrap/README.md
@@ -0,0 +1,4 @@
+This folder contains sample css files from the open-source project
+https://github.com/twbs/bootstrap.
+
+This code was included under the terms in the `LICENSE` file.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/bootstrap/bootstrap-grid.css b/pkgs/csslib/third_party/bootstrap/bootstrap-grid.css
new file mode 100644
index 0000000..e6af9ab
--- /dev/null
+++ b/pkgs/csslib/third_party/bootstrap/bootstrap-grid.css
@@ -0,0 +1,5051 @@
+/*!
+ * Bootstrap Grid v5.1.1 (https://getbootstrap.com/)
+ * Copyright 2011-2021 The Bootstrap Authors
+ * Copyright 2011-2021 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */
+:root {
+ --bs-blue: #0d6efd;
+ --bs-indigo: #6610f2;
+ --bs-purple: #6f42c1;
+ --bs-pink: #d63384;
+ --bs-red: #dc3545;
+ --bs-orange: #fd7e14;
+ --bs-yellow: #ffc107;
+ --bs-green: #198754;
+ --bs-teal: #20c997;
+ --bs-cyan: #0dcaf0;
+ --bs-white: #fff;
+ --bs-gray: #6c757d;
+ --bs-gray-dark: #343a40;
+ --bs-gray-100: #f8f9fa;
+ --bs-gray-200: #e9ecef;
+ --bs-gray-300: #dee2e6;
+ --bs-gray-400: #ced4da;
+ --bs-gray-500: #adb5bd;
+ --bs-gray-600: #6c757d;
+ --bs-gray-700: #495057;
+ --bs-gray-800: #343a40;
+ --bs-gray-900: #212529;
+ --bs-primary: #0d6efd;
+ --bs-secondary: #6c757d;
+ --bs-success: #198754;
+ --bs-info: #0dcaf0;
+ --bs-warning: #ffc107;
+ --bs-danger: #dc3545;
+ --bs-light: #f8f9fa;
+ --bs-dark: #212529;
+ --bs-primary-rgb: 13, 110, 253;
+ --bs-secondary-rgb: 108, 117, 125;
+ --bs-success-rgb: 25, 135, 84;
+ --bs-info-rgb: 13, 202, 240;
+ --bs-warning-rgb: 255, 193, 7;
+ --bs-danger-rgb: 220, 53, 69;
+ --bs-light-rgb: 248, 249, 250;
+ --bs-dark-rgb: 33, 37, 41;
+ --bs-white-rgb: 255, 255, 255;
+ --bs-black-rgb: 0, 0, 0;
+ --bs-body-color-rgb: 33, 37, 41;
+ --bs-body-bg-rgb: 255, 255, 255;
+ --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
+ --bs-body-font-family: var(--bs-font-sans-serif);
+ --bs-body-font-size: 1rem;
+ --bs-body-font-weight: 400;
+ --bs-body-line-height: 1.5;
+ --bs-body-color: #212529;
+ --bs-body-bg: #fff;
+}
+
+.container,
+.container-fluid,
+.container-xxl,
+.container-xl,
+.container-lg,
+.container-md,
+.container-sm {
+ width: 100%;
+ padding-right: var(--bs-gutter-x, 0.75rem);
+ padding-left: var(--bs-gutter-x, 0.75rem);
+ margin-right: auto;
+ margin-left: auto;
+}
+
+@media (min-width: 576px) {
+ .container-sm, .container {
+ max-width: 540px;
+ }
+}
+@media (min-width: 768px) {
+ .container-md, .container-sm, .container {
+ max-width: 720px;
+ }
+}
+@media (min-width: 992px) {
+ .container-lg, .container-md, .container-sm, .container {
+ max-width: 960px;
+ }
+}
+@media (min-width: 1200px) {
+ .container-xl, .container-lg, .container-md, .container-sm, .container {
+ max-width: 1140px;
+ }
+}
+@media (min-width: 1400px) {
+ .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {
+ max-width: 1320px;
+ }
+}
+.row {
+ --bs-gutter-x: 1.5rem;
+ --bs-gutter-y: 0;
+ display: flex;
+ flex-wrap: wrap;
+ margin-top: calc(var(--bs-gutter-y) * -1);
+ margin-right: calc(var(--bs-gutter-x) * -.5);
+ margin-left: calc(var(--bs-gutter-x) * -.5);
+}
+.row > * {
+ box-sizing: border-box;
+ flex-shrink: 0;
+ width: 100%;
+ max-width: 100%;
+ padding-right: calc(var(--bs-gutter-x) * .5);
+ padding-left: calc(var(--bs-gutter-x) * .5);
+ margin-top: var(--bs-gutter-y);
+}
+
+.col {
+ flex: 1 0 0%;
+}
+
+.row-cols-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+}
+
+.row-cols-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+}
+
+.row-cols-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+}
+
+.row-cols-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+}
+
+.row-cols-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+}
+
+.row-cols-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+}
+
+.row-cols-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+}
+
+.col-auto {
+ flex: 0 0 auto;
+ width: auto;
+}
+
+.col-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+}
+
+.col-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+}
+
+.col-3 {
+ flex: 0 0 auto;
+ width: 25%;
+}
+
+.col-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+}
+
+.col-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+}
+
+.col-6 {
+ flex: 0 0 auto;
+ width: 50%;
+}
+
+.col-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+}
+
+.col-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+}
+
+.col-9 {
+ flex: 0 0 auto;
+ width: 75%;
+}
+
+.col-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+}
+
+.col-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+}
+
+.col-12 {
+ flex: 0 0 auto;
+ width: 100%;
+}
+
+.offset-1 {
+ margin-left: 8.33333333%;
+}
+
+.offset-2 {
+ margin-left: 16.66666667%;
+}
+
+.offset-3 {
+ margin-left: 25%;
+}
+
+.offset-4 {
+ margin-left: 33.33333333%;
+}
+
+.offset-5 {
+ margin-left: 41.66666667%;
+}
+
+.offset-6 {
+ margin-left: 50%;
+}
+
+.offset-7 {
+ margin-left: 58.33333333%;
+}
+
+.offset-8 {
+ margin-left: 66.66666667%;
+}
+
+.offset-9 {
+ margin-left: 75%;
+}
+
+.offset-10 {
+ margin-left: 83.33333333%;
+}
+
+.offset-11 {
+ margin-left: 91.66666667%;
+}
+
+.g-0,
+.gx-0 {
+ --bs-gutter-x: 0;
+}
+
+.g-0,
+.gy-0 {
+ --bs-gutter-y: 0;
+}
+
+.g-1,
+.gx-1 {
+ --bs-gutter-x: 0.25rem;
+}
+
+.g-1,
+.gy-1 {
+ --bs-gutter-y: 0.25rem;
+}
+
+.g-2,
+.gx-2 {
+ --bs-gutter-x: 0.5rem;
+}
+
+.g-2,
+.gy-2 {
+ --bs-gutter-y: 0.5rem;
+}
+
+.g-3,
+.gx-3 {
+ --bs-gutter-x: 1rem;
+}
+
+.g-3,
+.gy-3 {
+ --bs-gutter-y: 1rem;
+}
+
+.g-4,
+.gx-4 {
+ --bs-gutter-x: 1.5rem;
+}
+
+.g-4,
+.gy-4 {
+ --bs-gutter-y: 1.5rem;
+}
+
+.g-5,
+.gx-5 {
+ --bs-gutter-x: 3rem;
+}
+
+.g-5,
+.gy-5 {
+ --bs-gutter-y: 3rem;
+}
+
+@media (min-width: 576px) {
+ .col-sm {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-sm-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-sm-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-sm-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-sm-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-sm-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-sm-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-sm-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-sm-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-sm-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-sm-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-sm-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-sm-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-sm-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-sm-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-sm-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-sm-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-sm-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-sm-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-sm-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-sm-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-sm-0 {
+ margin-left: 0;
+ }
+
+ .offset-sm-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-sm-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-sm-3 {
+ margin-left: 25%;
+ }
+
+ .offset-sm-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-sm-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-sm-6 {
+ margin-left: 50%;
+ }
+
+ .offset-sm-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-sm-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-sm-9 {
+ margin-left: 75%;
+ }
+
+ .offset-sm-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-sm-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-sm-0,
+.gx-sm-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-sm-0,
+.gy-sm-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-sm-1,
+.gx-sm-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-sm-1,
+.gy-sm-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-sm-2,
+.gx-sm-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-sm-2,
+.gy-sm-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-sm-3,
+.gx-sm-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-sm-3,
+.gy-sm-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-sm-4,
+.gx-sm-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-sm-4,
+.gy-sm-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-sm-5,
+.gx-sm-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-sm-5,
+.gy-sm-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+@media (min-width: 768px) {
+ .col-md {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-md-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-md-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-md-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-md-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-md-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-md-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-md-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-md-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-md-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-md-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-md-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-md-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-md-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-md-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-md-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-md-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-md-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-md-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-md-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-md-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-md-0 {
+ margin-left: 0;
+ }
+
+ .offset-md-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-md-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-md-3 {
+ margin-left: 25%;
+ }
+
+ .offset-md-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-md-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-md-6 {
+ margin-left: 50%;
+ }
+
+ .offset-md-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-md-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-md-9 {
+ margin-left: 75%;
+ }
+
+ .offset-md-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-md-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-md-0,
+.gx-md-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-md-0,
+.gy-md-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-md-1,
+.gx-md-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-md-1,
+.gy-md-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-md-2,
+.gx-md-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-md-2,
+.gy-md-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-md-3,
+.gx-md-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-md-3,
+.gy-md-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-md-4,
+.gx-md-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-md-4,
+.gy-md-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-md-5,
+.gx-md-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-md-5,
+.gy-md-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+@media (min-width: 992px) {
+ .col-lg {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-lg-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-lg-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-lg-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-lg-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-lg-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-lg-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-lg-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-lg-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-lg-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-lg-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-lg-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-lg-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-lg-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-lg-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-lg-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-lg-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-lg-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-lg-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-lg-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-lg-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-lg-0 {
+ margin-left: 0;
+ }
+
+ .offset-lg-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-lg-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-lg-3 {
+ margin-left: 25%;
+ }
+
+ .offset-lg-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-lg-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-lg-6 {
+ margin-left: 50%;
+ }
+
+ .offset-lg-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-lg-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-lg-9 {
+ margin-left: 75%;
+ }
+
+ .offset-lg-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-lg-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-lg-0,
+.gx-lg-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-lg-0,
+.gy-lg-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-lg-1,
+.gx-lg-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-lg-1,
+.gy-lg-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-lg-2,
+.gx-lg-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-lg-2,
+.gy-lg-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-lg-3,
+.gx-lg-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-lg-3,
+.gy-lg-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-lg-4,
+.gx-lg-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-lg-4,
+.gy-lg-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-lg-5,
+.gx-lg-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-lg-5,
+.gy-lg-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+@media (min-width: 1200px) {
+ .col-xl {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-xl-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-xl-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-xl-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-xl-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-xl-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-xl-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-xl-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-xl-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-xl-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-xl-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-xl-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-xl-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-xl-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-xl-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-xl-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-xl-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-xl-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-xl-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-xl-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-xl-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-xl-0 {
+ margin-left: 0;
+ }
+
+ .offset-xl-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-xl-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-xl-3 {
+ margin-left: 25%;
+ }
+
+ .offset-xl-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-xl-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-xl-6 {
+ margin-left: 50%;
+ }
+
+ .offset-xl-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-xl-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-xl-9 {
+ margin-left: 75%;
+ }
+
+ .offset-xl-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-xl-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-xl-0,
+.gx-xl-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-xl-0,
+.gy-xl-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-xl-1,
+.gx-xl-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-xl-1,
+.gy-xl-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-xl-2,
+.gx-xl-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-xl-2,
+.gy-xl-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-xl-3,
+.gx-xl-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-xl-3,
+.gy-xl-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-xl-4,
+.gx-xl-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-xl-4,
+.gy-xl-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-xl-5,
+.gx-xl-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-xl-5,
+.gy-xl-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+@media (min-width: 1400px) {
+ .col-xxl {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-xxl-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-xxl-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-xxl-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-xxl-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-xxl-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-xxl-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-xxl-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-xxl-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-xxl-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-xxl-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-xxl-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-xxl-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-xxl-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-xxl-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-xxl-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-xxl-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-xxl-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-xxl-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-xxl-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-xxl-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-xxl-0 {
+ margin-left: 0;
+ }
+
+ .offset-xxl-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-xxl-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-xxl-3 {
+ margin-left: 25%;
+ }
+
+ .offset-xxl-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-xxl-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-xxl-6 {
+ margin-left: 50%;
+ }
+
+ .offset-xxl-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-xxl-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-xxl-9 {
+ margin-left: 75%;
+ }
+
+ .offset-xxl-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-xxl-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-xxl-0,
+.gx-xxl-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-xxl-0,
+.gy-xxl-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-xxl-1,
+.gx-xxl-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-xxl-1,
+.gy-xxl-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-xxl-2,
+.gx-xxl-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-xxl-2,
+.gy-xxl-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-xxl-3,
+.gx-xxl-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-xxl-3,
+.gy-xxl-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-xxl-4,
+.gx-xxl-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-xxl-4,
+.gy-xxl-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-xxl-5,
+.gx-xxl-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-xxl-5,
+.gy-xxl-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+.d-inline {
+ display: inline !important;
+}
+
+.d-inline-block {
+ display: inline-block !important;
+}
+
+.d-block {
+ display: block !important;
+}
+
+.d-grid {
+ display: grid !important;
+}
+
+.d-table {
+ display: table !important;
+}
+
+.d-table-row {
+ display: table-row !important;
+}
+
+.d-table-cell {
+ display: table-cell !important;
+}
+
+.d-flex {
+ display: flex !important;
+}
+
+.d-inline-flex {
+ display: inline-flex !important;
+}
+
+.d-none {
+ display: none !important;
+}
+
+.flex-fill {
+ flex: 1 1 auto !important;
+}
+
+.flex-row {
+ flex-direction: row !important;
+}
+
+.flex-column {
+ flex-direction: column !important;
+}
+
+.flex-row-reverse {
+ flex-direction: row-reverse !important;
+}
+
+.flex-column-reverse {
+ flex-direction: column-reverse !important;
+}
+
+.flex-grow-0 {
+ flex-grow: 0 !important;
+}
+
+.flex-grow-1 {
+ flex-grow: 1 !important;
+}
+
+.flex-shrink-0 {
+ flex-shrink: 0 !important;
+}
+
+.flex-shrink-1 {
+ flex-shrink: 1 !important;
+}
+
+.flex-wrap {
+ flex-wrap: wrap !important;
+}
+
+.flex-nowrap {
+ flex-wrap: nowrap !important;
+}
+
+.flex-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+}
+
+.justify-content-start {
+ justify-content: flex-start !important;
+}
+
+.justify-content-end {
+ justify-content: flex-end !important;
+}
+
+.justify-content-center {
+ justify-content: center !important;
+}
+
+.justify-content-between {
+ justify-content: space-between !important;
+}
+
+.justify-content-around {
+ justify-content: space-around !important;
+}
+
+.justify-content-evenly {
+ justify-content: space-evenly !important;
+}
+
+.align-items-start {
+ align-items: flex-start !important;
+}
+
+.align-items-end {
+ align-items: flex-end !important;
+}
+
+.align-items-center {
+ align-items: center !important;
+}
+
+.align-items-baseline {
+ align-items: baseline !important;
+}
+
+.align-items-stretch {
+ align-items: stretch !important;
+}
+
+.align-content-start {
+ align-content: flex-start !important;
+}
+
+.align-content-end {
+ align-content: flex-end !important;
+}
+
+.align-content-center {
+ align-content: center !important;
+}
+
+.align-content-between {
+ align-content: space-between !important;
+}
+
+.align-content-around {
+ align-content: space-around !important;
+}
+
+.align-content-stretch {
+ align-content: stretch !important;
+}
+
+.align-self-auto {
+ align-self: auto !important;
+}
+
+.align-self-start {
+ align-self: flex-start !important;
+}
+
+.align-self-end {
+ align-self: flex-end !important;
+}
+
+.align-self-center {
+ align-self: center !important;
+}
+
+.align-self-baseline {
+ align-self: baseline !important;
+}
+
+.align-self-stretch {
+ align-self: stretch !important;
+}
+
+.order-first {
+ order: -1 !important;
+}
+
+.order-0 {
+ order: 0 !important;
+}
+
+.order-1 {
+ order: 1 !important;
+}
+
+.order-2 {
+ order: 2 !important;
+}
+
+.order-3 {
+ order: 3 !important;
+}
+
+.order-4 {
+ order: 4 !important;
+}
+
+.order-5 {
+ order: 5 !important;
+}
+
+.order-last {
+ order: 6 !important;
+}
+
+.m-0 {
+ margin: 0 !important;
+}
+
+.m-1 {
+ margin: 0.25rem !important;
+}
+
+.m-2 {
+ margin: 0.5rem !important;
+}
+
+.m-3 {
+ margin: 1rem !important;
+}
+
+.m-4 {
+ margin: 1.5rem !important;
+}
+
+.m-5 {
+ margin: 3rem !important;
+}
+
+.m-auto {
+ margin: auto !important;
+}
+
+.mx-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+}
+
+.mx-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+}
+
+.mx-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+}
+
+.mx-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+}
+
+.mx-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+}
+
+.mx-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+}
+
+.mx-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+}
+
+.my-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+}
+
+.my-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+}
+
+.my-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+}
+
+.my-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+}
+
+.my-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+}
+
+.my-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+}
+
+.my-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+}
+
+.mt-0 {
+ margin-top: 0 !important;
+}
+
+.mt-1 {
+ margin-top: 0.25rem !important;
+}
+
+.mt-2 {
+ margin-top: 0.5rem !important;
+}
+
+.mt-3 {
+ margin-top: 1rem !important;
+}
+
+.mt-4 {
+ margin-top: 1.5rem !important;
+}
+
+.mt-5 {
+ margin-top: 3rem !important;
+}
+
+.mt-auto {
+ margin-top: auto !important;
+}
+
+.me-0 {
+ margin-right: 0 !important;
+}
+
+.me-1 {
+ margin-right: 0.25rem !important;
+}
+
+.me-2 {
+ margin-right: 0.5rem !important;
+}
+
+.me-3 {
+ margin-right: 1rem !important;
+}
+
+.me-4 {
+ margin-right: 1.5rem !important;
+}
+
+.me-5 {
+ margin-right: 3rem !important;
+}
+
+.me-auto {
+ margin-right: auto !important;
+}
+
+.mb-0 {
+ margin-bottom: 0 !important;
+}
+
+.mb-1 {
+ margin-bottom: 0.25rem !important;
+}
+
+.mb-2 {
+ margin-bottom: 0.5rem !important;
+}
+
+.mb-3 {
+ margin-bottom: 1rem !important;
+}
+
+.mb-4 {
+ margin-bottom: 1.5rem !important;
+}
+
+.mb-5 {
+ margin-bottom: 3rem !important;
+}
+
+.mb-auto {
+ margin-bottom: auto !important;
+}
+
+.ms-0 {
+ margin-left: 0 !important;
+}
+
+.ms-1 {
+ margin-left: 0.25rem !important;
+}
+
+.ms-2 {
+ margin-left: 0.5rem !important;
+}
+
+.ms-3 {
+ margin-left: 1rem !important;
+}
+
+.ms-4 {
+ margin-left: 1.5rem !important;
+}
+
+.ms-5 {
+ margin-left: 3rem !important;
+}
+
+.ms-auto {
+ margin-left: auto !important;
+}
+
+.p-0 {
+ padding: 0 !important;
+}
+
+.p-1 {
+ padding: 0.25rem !important;
+}
+
+.p-2 {
+ padding: 0.5rem !important;
+}
+
+.p-3 {
+ padding: 1rem !important;
+}
+
+.p-4 {
+ padding: 1.5rem !important;
+}
+
+.p-5 {
+ padding: 3rem !important;
+}
+
+.px-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+}
+
+.px-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+}
+
+.px-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+}
+
+.px-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+}
+
+.px-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+}
+
+.px-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+}
+
+.py-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+}
+
+.py-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+}
+
+.py-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+}
+
+.py-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+}
+
+.py-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+}
+
+.py-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+}
+
+.pt-0 {
+ padding-top: 0 !important;
+}
+
+.pt-1 {
+ padding-top: 0.25rem !important;
+}
+
+.pt-2 {
+ padding-top: 0.5rem !important;
+}
+
+.pt-3 {
+ padding-top: 1rem !important;
+}
+
+.pt-4 {
+ padding-top: 1.5rem !important;
+}
+
+.pt-5 {
+ padding-top: 3rem !important;
+}
+
+.pe-0 {
+ padding-right: 0 !important;
+}
+
+.pe-1 {
+ padding-right: 0.25rem !important;
+}
+
+.pe-2 {
+ padding-right: 0.5rem !important;
+}
+
+.pe-3 {
+ padding-right: 1rem !important;
+}
+
+.pe-4 {
+ padding-right: 1.5rem !important;
+}
+
+.pe-5 {
+ padding-right: 3rem !important;
+}
+
+.pb-0 {
+ padding-bottom: 0 !important;
+}
+
+.pb-1 {
+ padding-bottom: 0.25rem !important;
+}
+
+.pb-2 {
+ padding-bottom: 0.5rem !important;
+}
+
+.pb-3 {
+ padding-bottom: 1rem !important;
+}
+
+.pb-4 {
+ padding-bottom: 1.5rem !important;
+}
+
+.pb-5 {
+ padding-bottom: 3rem !important;
+}
+
+.ps-0 {
+ padding-left: 0 !important;
+}
+
+.ps-1 {
+ padding-left: 0.25rem !important;
+}
+
+.ps-2 {
+ padding-left: 0.5rem !important;
+}
+
+.ps-3 {
+ padding-left: 1rem !important;
+}
+
+.ps-4 {
+ padding-left: 1.5rem !important;
+}
+
+.ps-5 {
+ padding-left: 3rem !important;
+}
+
+@media (min-width: 576px) {
+ .d-sm-inline {
+ display: inline !important;
+ }
+
+ .d-sm-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-sm-block {
+ display: block !important;
+ }
+
+ .d-sm-grid {
+ display: grid !important;
+ }
+
+ .d-sm-table {
+ display: table !important;
+ }
+
+ .d-sm-table-row {
+ display: table-row !important;
+ }
+
+ .d-sm-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-sm-flex {
+ display: flex !important;
+ }
+
+ .d-sm-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-sm-none {
+ display: none !important;
+ }
+
+ .flex-sm-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-sm-row {
+ flex-direction: row !important;
+ }
+
+ .flex-sm-column {
+ flex-direction: column !important;
+ }
+
+ .flex-sm-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-sm-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-sm-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-sm-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-sm-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-sm-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-sm-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-sm-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-sm-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .justify-content-sm-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-sm-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-sm-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-sm-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-sm-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-sm-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-sm-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-sm-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-sm-center {
+ align-items: center !important;
+ }
+
+ .align-items-sm-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-sm-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-sm-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-sm-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-sm-center {
+ align-content: center !important;
+ }
+
+ .align-content-sm-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-sm-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-sm-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-sm-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-sm-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-sm-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-sm-center {
+ align-self: center !important;
+ }
+
+ .align-self-sm-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-sm-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-sm-first {
+ order: -1 !important;
+ }
+
+ .order-sm-0 {
+ order: 0 !important;
+ }
+
+ .order-sm-1 {
+ order: 1 !important;
+ }
+
+ .order-sm-2 {
+ order: 2 !important;
+ }
+
+ .order-sm-3 {
+ order: 3 !important;
+ }
+
+ .order-sm-4 {
+ order: 4 !important;
+ }
+
+ .order-sm-5 {
+ order: 5 !important;
+ }
+
+ .order-sm-last {
+ order: 6 !important;
+ }
+
+ .m-sm-0 {
+ margin: 0 !important;
+ }
+
+ .m-sm-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-sm-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-sm-3 {
+ margin: 1rem !important;
+ }
+
+ .m-sm-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-sm-5 {
+ margin: 3rem !important;
+ }
+
+ .m-sm-auto {
+ margin: auto !important;
+ }
+
+ .mx-sm-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-sm-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-sm-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-sm-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-sm-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-sm-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-sm-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-sm-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-sm-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-sm-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-sm-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-sm-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-sm-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-sm-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-sm-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-sm-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-sm-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-sm-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-sm-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-sm-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-sm-auto {
+ margin-top: auto !important;
+ }
+
+ .me-sm-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-sm-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-sm-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-sm-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-sm-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-sm-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-sm-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-sm-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-sm-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-sm-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-sm-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-sm-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-sm-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-sm-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-sm-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-sm-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-sm-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-sm-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-sm-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-sm-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-sm-auto {
+ margin-left: auto !important;
+ }
+
+ .p-sm-0 {
+ padding: 0 !important;
+ }
+
+ .p-sm-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-sm-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-sm-3 {
+ padding: 1rem !important;
+ }
+
+ .p-sm-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-sm-5 {
+ padding: 3rem !important;
+ }
+
+ .px-sm-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-sm-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-sm-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-sm-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-sm-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-sm-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-sm-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-sm-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-sm-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-sm-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-sm-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-sm-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-sm-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-sm-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-sm-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-sm-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-sm-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-sm-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-sm-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-sm-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-sm-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-sm-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-sm-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-sm-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-sm-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-sm-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-sm-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-sm-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-sm-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-sm-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-sm-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-sm-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-sm-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-sm-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-sm-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-sm-5 {
+ padding-left: 3rem !important;
+ }
+}
+@media (min-width: 768px) {
+ .d-md-inline {
+ display: inline !important;
+ }
+
+ .d-md-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-md-block {
+ display: block !important;
+ }
+
+ .d-md-grid {
+ display: grid !important;
+ }
+
+ .d-md-table {
+ display: table !important;
+ }
+
+ .d-md-table-row {
+ display: table-row !important;
+ }
+
+ .d-md-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-md-flex {
+ display: flex !important;
+ }
+
+ .d-md-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-md-none {
+ display: none !important;
+ }
+
+ .flex-md-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-md-row {
+ flex-direction: row !important;
+ }
+
+ .flex-md-column {
+ flex-direction: column !important;
+ }
+
+ .flex-md-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-md-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-md-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-md-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-md-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-md-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-md-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-md-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-md-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .justify-content-md-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-md-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-md-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-md-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-md-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-md-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-md-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-md-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-md-center {
+ align-items: center !important;
+ }
+
+ .align-items-md-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-md-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-md-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-md-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-md-center {
+ align-content: center !important;
+ }
+
+ .align-content-md-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-md-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-md-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-md-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-md-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-md-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-md-center {
+ align-self: center !important;
+ }
+
+ .align-self-md-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-md-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-md-first {
+ order: -1 !important;
+ }
+
+ .order-md-0 {
+ order: 0 !important;
+ }
+
+ .order-md-1 {
+ order: 1 !important;
+ }
+
+ .order-md-2 {
+ order: 2 !important;
+ }
+
+ .order-md-3 {
+ order: 3 !important;
+ }
+
+ .order-md-4 {
+ order: 4 !important;
+ }
+
+ .order-md-5 {
+ order: 5 !important;
+ }
+
+ .order-md-last {
+ order: 6 !important;
+ }
+
+ .m-md-0 {
+ margin: 0 !important;
+ }
+
+ .m-md-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-md-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-md-3 {
+ margin: 1rem !important;
+ }
+
+ .m-md-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-md-5 {
+ margin: 3rem !important;
+ }
+
+ .m-md-auto {
+ margin: auto !important;
+ }
+
+ .mx-md-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-md-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-md-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-md-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-md-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-md-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-md-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-md-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-md-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-md-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-md-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-md-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-md-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-md-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-md-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-md-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-md-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-md-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-md-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-md-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-md-auto {
+ margin-top: auto !important;
+ }
+
+ .me-md-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-md-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-md-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-md-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-md-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-md-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-md-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-md-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-md-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-md-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-md-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-md-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-md-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-md-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-md-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-md-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-md-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-md-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-md-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-md-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-md-auto {
+ margin-left: auto !important;
+ }
+
+ .p-md-0 {
+ padding: 0 !important;
+ }
+
+ .p-md-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-md-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-md-3 {
+ padding: 1rem !important;
+ }
+
+ .p-md-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-md-5 {
+ padding: 3rem !important;
+ }
+
+ .px-md-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-md-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-md-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-md-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-md-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-md-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-md-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-md-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-md-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-md-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-md-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-md-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-md-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-md-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-md-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-md-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-md-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-md-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-md-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-md-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-md-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-md-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-md-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-md-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-md-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-md-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-md-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-md-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-md-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-md-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-md-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-md-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-md-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-md-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-md-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-md-5 {
+ padding-left: 3rem !important;
+ }
+}
+@media (min-width: 992px) {
+ .d-lg-inline {
+ display: inline !important;
+ }
+
+ .d-lg-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-lg-block {
+ display: block !important;
+ }
+
+ .d-lg-grid {
+ display: grid !important;
+ }
+
+ .d-lg-table {
+ display: table !important;
+ }
+
+ .d-lg-table-row {
+ display: table-row !important;
+ }
+
+ .d-lg-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-lg-flex {
+ display: flex !important;
+ }
+
+ .d-lg-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-lg-none {
+ display: none !important;
+ }
+
+ .flex-lg-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-lg-row {
+ flex-direction: row !important;
+ }
+
+ .flex-lg-column {
+ flex-direction: column !important;
+ }
+
+ .flex-lg-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-lg-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-lg-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-lg-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-lg-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-lg-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-lg-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-lg-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-lg-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .justify-content-lg-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-lg-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-lg-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-lg-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-lg-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-lg-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-lg-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-lg-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-lg-center {
+ align-items: center !important;
+ }
+
+ .align-items-lg-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-lg-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-lg-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-lg-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-lg-center {
+ align-content: center !important;
+ }
+
+ .align-content-lg-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-lg-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-lg-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-lg-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-lg-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-lg-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-lg-center {
+ align-self: center !important;
+ }
+
+ .align-self-lg-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-lg-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-lg-first {
+ order: -1 !important;
+ }
+
+ .order-lg-0 {
+ order: 0 !important;
+ }
+
+ .order-lg-1 {
+ order: 1 !important;
+ }
+
+ .order-lg-2 {
+ order: 2 !important;
+ }
+
+ .order-lg-3 {
+ order: 3 !important;
+ }
+
+ .order-lg-4 {
+ order: 4 !important;
+ }
+
+ .order-lg-5 {
+ order: 5 !important;
+ }
+
+ .order-lg-last {
+ order: 6 !important;
+ }
+
+ .m-lg-0 {
+ margin: 0 !important;
+ }
+
+ .m-lg-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-lg-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-lg-3 {
+ margin: 1rem !important;
+ }
+
+ .m-lg-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-lg-5 {
+ margin: 3rem !important;
+ }
+
+ .m-lg-auto {
+ margin: auto !important;
+ }
+
+ .mx-lg-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-lg-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-lg-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-lg-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-lg-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-lg-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-lg-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-lg-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-lg-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-lg-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-lg-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-lg-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-lg-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-lg-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-lg-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-lg-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-lg-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-lg-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-lg-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-lg-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-lg-auto {
+ margin-top: auto !important;
+ }
+
+ .me-lg-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-lg-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-lg-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-lg-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-lg-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-lg-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-lg-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-lg-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-lg-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-lg-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-lg-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-lg-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-lg-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-lg-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-lg-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-lg-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-lg-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-lg-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-lg-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-lg-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-lg-auto {
+ margin-left: auto !important;
+ }
+
+ .p-lg-0 {
+ padding: 0 !important;
+ }
+
+ .p-lg-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-lg-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-lg-3 {
+ padding: 1rem !important;
+ }
+
+ .p-lg-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-lg-5 {
+ padding: 3rem !important;
+ }
+
+ .px-lg-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-lg-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-lg-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-lg-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-lg-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-lg-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-lg-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-lg-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-lg-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-lg-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-lg-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-lg-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-lg-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-lg-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-lg-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-lg-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-lg-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-lg-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-lg-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-lg-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-lg-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-lg-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-lg-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-lg-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-lg-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-lg-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-lg-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-lg-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-lg-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-lg-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-lg-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-lg-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-lg-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-lg-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-lg-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-lg-5 {
+ padding-left: 3rem !important;
+ }
+}
+@media (min-width: 1200px) {
+ .d-xl-inline {
+ display: inline !important;
+ }
+
+ .d-xl-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-xl-block {
+ display: block !important;
+ }
+
+ .d-xl-grid {
+ display: grid !important;
+ }
+
+ .d-xl-table {
+ display: table !important;
+ }
+
+ .d-xl-table-row {
+ display: table-row !important;
+ }
+
+ .d-xl-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-xl-flex {
+ display: flex !important;
+ }
+
+ .d-xl-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-xl-none {
+ display: none !important;
+ }
+
+ .flex-xl-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-xl-row {
+ flex-direction: row !important;
+ }
+
+ .flex-xl-column {
+ flex-direction: column !important;
+ }
+
+ .flex-xl-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-xl-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-xl-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-xl-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-xl-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-xl-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-xl-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-xl-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-xl-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .justify-content-xl-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-xl-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-xl-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-xl-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-xl-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-xl-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-xl-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-xl-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-xl-center {
+ align-items: center !important;
+ }
+
+ .align-items-xl-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-xl-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-xl-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-xl-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-xl-center {
+ align-content: center !important;
+ }
+
+ .align-content-xl-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-xl-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-xl-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-xl-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-xl-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-xl-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-xl-center {
+ align-self: center !important;
+ }
+
+ .align-self-xl-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-xl-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-xl-first {
+ order: -1 !important;
+ }
+
+ .order-xl-0 {
+ order: 0 !important;
+ }
+
+ .order-xl-1 {
+ order: 1 !important;
+ }
+
+ .order-xl-2 {
+ order: 2 !important;
+ }
+
+ .order-xl-3 {
+ order: 3 !important;
+ }
+
+ .order-xl-4 {
+ order: 4 !important;
+ }
+
+ .order-xl-5 {
+ order: 5 !important;
+ }
+
+ .order-xl-last {
+ order: 6 !important;
+ }
+
+ .m-xl-0 {
+ margin: 0 !important;
+ }
+
+ .m-xl-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-xl-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-xl-3 {
+ margin: 1rem !important;
+ }
+
+ .m-xl-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-xl-5 {
+ margin: 3rem !important;
+ }
+
+ .m-xl-auto {
+ margin: auto !important;
+ }
+
+ .mx-xl-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-xl-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-xl-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-xl-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-xl-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-xl-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-xl-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-xl-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-xl-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-xl-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-xl-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-xl-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-xl-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-xl-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-xl-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-xl-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-xl-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-xl-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-xl-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-xl-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-xl-auto {
+ margin-top: auto !important;
+ }
+
+ .me-xl-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-xl-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-xl-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-xl-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-xl-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-xl-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-xl-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-xl-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-xl-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-xl-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-xl-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-xl-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-xl-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-xl-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-xl-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-xl-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-xl-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-xl-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-xl-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-xl-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-xl-auto {
+ margin-left: auto !important;
+ }
+
+ .p-xl-0 {
+ padding: 0 !important;
+ }
+
+ .p-xl-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-xl-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-xl-3 {
+ padding: 1rem !important;
+ }
+
+ .p-xl-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-xl-5 {
+ padding: 3rem !important;
+ }
+
+ .px-xl-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-xl-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-xl-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-xl-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-xl-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-xl-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-xl-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-xl-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-xl-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-xl-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-xl-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-xl-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-xl-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-xl-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-xl-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-xl-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-xl-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-xl-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-xl-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-xl-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-xl-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-xl-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-xl-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-xl-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-xl-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-xl-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-xl-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-xl-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-xl-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-xl-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-xl-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-xl-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-xl-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-xl-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-xl-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-xl-5 {
+ padding-left: 3rem !important;
+ }
+}
+@media (min-width: 1400px) {
+ .d-xxl-inline {
+ display: inline !important;
+ }
+
+ .d-xxl-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-xxl-block {
+ display: block !important;
+ }
+
+ .d-xxl-grid {
+ display: grid !important;
+ }
+
+ .d-xxl-table {
+ display: table !important;
+ }
+
+ .d-xxl-table-row {
+ display: table-row !important;
+ }
+
+ .d-xxl-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-xxl-flex {
+ display: flex !important;
+ }
+
+ .d-xxl-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-xxl-none {
+ display: none !important;
+ }
+
+ .flex-xxl-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-xxl-row {
+ flex-direction: row !important;
+ }
+
+ .flex-xxl-column {
+ flex-direction: column !important;
+ }
+
+ .flex-xxl-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-xxl-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-xxl-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-xxl-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-xxl-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-xxl-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-xxl-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-xxl-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-xxl-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .justify-content-xxl-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-xxl-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-xxl-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-xxl-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-xxl-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-xxl-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-xxl-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-xxl-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-xxl-center {
+ align-items: center !important;
+ }
+
+ .align-items-xxl-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-xxl-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-xxl-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-xxl-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-xxl-center {
+ align-content: center !important;
+ }
+
+ .align-content-xxl-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-xxl-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-xxl-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-xxl-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-xxl-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-xxl-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-xxl-center {
+ align-self: center !important;
+ }
+
+ .align-self-xxl-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-xxl-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-xxl-first {
+ order: -1 !important;
+ }
+
+ .order-xxl-0 {
+ order: 0 !important;
+ }
+
+ .order-xxl-1 {
+ order: 1 !important;
+ }
+
+ .order-xxl-2 {
+ order: 2 !important;
+ }
+
+ .order-xxl-3 {
+ order: 3 !important;
+ }
+
+ .order-xxl-4 {
+ order: 4 !important;
+ }
+
+ .order-xxl-5 {
+ order: 5 !important;
+ }
+
+ .order-xxl-last {
+ order: 6 !important;
+ }
+
+ .m-xxl-0 {
+ margin: 0 !important;
+ }
+
+ .m-xxl-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-xxl-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-xxl-3 {
+ margin: 1rem !important;
+ }
+
+ .m-xxl-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-xxl-5 {
+ margin: 3rem !important;
+ }
+
+ .m-xxl-auto {
+ margin: auto !important;
+ }
+
+ .mx-xxl-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-xxl-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-xxl-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-xxl-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-xxl-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-xxl-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-xxl-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-xxl-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-xxl-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-xxl-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-xxl-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-xxl-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-xxl-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-xxl-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-xxl-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-xxl-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-xxl-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-xxl-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-xxl-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-xxl-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-xxl-auto {
+ margin-top: auto !important;
+ }
+
+ .me-xxl-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-xxl-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-xxl-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-xxl-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-xxl-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-xxl-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-xxl-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-xxl-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-xxl-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-xxl-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-xxl-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-xxl-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-xxl-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-xxl-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-xxl-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-xxl-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-xxl-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-xxl-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-xxl-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-xxl-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-xxl-auto {
+ margin-left: auto !important;
+ }
+
+ .p-xxl-0 {
+ padding: 0 !important;
+ }
+
+ .p-xxl-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-xxl-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-xxl-3 {
+ padding: 1rem !important;
+ }
+
+ .p-xxl-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-xxl-5 {
+ padding: 3rem !important;
+ }
+
+ .px-xxl-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-xxl-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-xxl-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-xxl-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-xxl-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-xxl-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-xxl-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-xxl-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-xxl-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-xxl-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-xxl-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-xxl-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-xxl-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-xxl-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-xxl-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-xxl-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-xxl-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-xxl-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-xxl-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-xxl-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-xxl-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-xxl-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-xxl-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-xxl-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-xxl-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-xxl-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-xxl-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-xxl-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-xxl-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-xxl-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-xxl-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-xxl-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-xxl-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-xxl-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-xxl-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-xxl-5 {
+ padding-left: 3rem !important;
+ }
+}
+@media print {
+ .d-print-inline {
+ display: inline !important;
+ }
+
+ .d-print-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-print-block {
+ display: block !important;
+ }
+
+ .d-print-grid {
+ display: grid !important;
+ }
+
+ .d-print-table {
+ display: table !important;
+ }
+
+ .d-print-table-row {
+ display: table-row !important;
+ }
+
+ .d-print-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-print-flex {
+ display: flex !important;
+ }
+
+ .d-print-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-print-none {
+ display: none !important;
+ }
+}
+
+/*# sourceMappingURL=bootstrap-grid.css.map */
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/bootstrap/bootstrap.css b/pkgs/csslib/third_party/bootstrap/bootstrap.css
new file mode 100644
index 0000000..f78e177
--- /dev/null
+++ b/pkgs/csslib/third_party/bootstrap/bootstrap.css
@@ -0,0 +1,11222 @@
+@charset "UTF-8";
+/*!
+ * Bootstrap v5.1.1 (https://getbootstrap.com/)
+ * Copyright 2011-2021 The Bootstrap Authors
+ * Copyright 2011-2021 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */
+:root {
+ --bs-blue: #0d6efd;
+ --bs-indigo: #6610f2;
+ --bs-purple: #6f42c1;
+ --bs-pink: #d63384;
+ --bs-red: #dc3545;
+ --bs-orange: #fd7e14;
+ --bs-yellow: #ffc107;
+ --bs-green: #198754;
+ --bs-teal: #20c997;
+ --bs-cyan: #0dcaf0;
+ --bs-white: #fff;
+ --bs-gray: #6c757d;
+ --bs-gray-dark: #343a40;
+ --bs-gray-100: #f8f9fa;
+ --bs-gray-200: #e9ecef;
+ --bs-gray-300: #dee2e6;
+ --bs-gray-400: #ced4da;
+ --bs-gray-500: #adb5bd;
+ --bs-gray-600: #6c757d;
+ --bs-gray-700: #495057;
+ --bs-gray-800: #343a40;
+ --bs-gray-900: #212529;
+ --bs-primary: #0d6efd;
+ --bs-secondary: #6c757d;
+ --bs-success: #198754;
+ --bs-info: #0dcaf0;
+ --bs-warning: #ffc107;
+ --bs-danger: #dc3545;
+ --bs-light: #f8f9fa;
+ --bs-dark: #212529;
+ --bs-primary-rgb: 13, 110, 253;
+ --bs-secondary-rgb: 108, 117, 125;
+ --bs-success-rgb: 25, 135, 84;
+ --bs-info-rgb: 13, 202, 240;
+ --bs-warning-rgb: 255, 193, 7;
+ --bs-danger-rgb: 220, 53, 69;
+ --bs-light-rgb: 248, 249, 250;
+ --bs-dark-rgb: 33, 37, 41;
+ --bs-white-rgb: 255, 255, 255;
+ --bs-black-rgb: 0, 0, 0;
+ --bs-body-color-rgb: 33, 37, 41;
+ --bs-body-bg-rgb: 255, 255, 255;
+ --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
+ --bs-body-font-family: var(--bs-font-sans-serif);
+ --bs-body-font-size: 1rem;
+ --bs-body-font-weight: 400;
+ --bs-body-line-height: 1.5;
+ --bs-body-color: #212529;
+ --bs-body-bg: #fff;
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ :root {
+ scroll-behavior: smooth;
+ }
+}
+
+body {
+ margin: 0;
+ font-family: var(--bs-body-font-family);
+ font-size: var(--bs-body-font-size);
+ font-weight: var(--bs-body-font-weight);
+ line-height: var(--bs-body-line-height);
+ color: var(--bs-body-color);
+ text-align: var(--bs-body-text-align);
+ background-color: var(--bs-body-bg);
+ -webkit-text-size-adjust: 100%;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+hr {
+ margin: 1rem 0;
+ color: inherit;
+ background-color: currentColor;
+ border: 0;
+ opacity: 0.25;
+}
+
+hr:not([size]) {
+ height: 1px;
+}
+
+h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 {
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+ font-weight: 500;
+ line-height: 1.2;
+}
+
+h1, .h1 {
+ font-size: calc(1.375rem + 1.5vw);
+}
+@media (min-width: 1200px) {
+ h1, .h1 {
+ font-size: 2.5rem;
+ }
+}
+
+h2, .h2 {
+ font-size: calc(1.325rem + 0.9vw);
+}
+@media (min-width: 1200px) {
+ h2, .h2 {
+ font-size: 2rem;
+ }
+}
+
+h3, .h3 {
+ font-size: calc(1.3rem + 0.6vw);
+}
+@media (min-width: 1200px) {
+ h3, .h3 {
+ font-size: 1.75rem;
+ }
+}
+
+h4, .h4 {
+ font-size: calc(1.275rem + 0.3vw);
+}
+@media (min-width: 1200px) {
+ h4, .h4 {
+ font-size: 1.5rem;
+ }
+}
+
+h5, .h5 {
+ font-size: 1.25rem;
+}
+
+h6, .h6 {
+ font-size: 1rem;
+}
+
+p {
+ margin-top: 0;
+ margin-bottom: 1rem;
+}
+
+abbr[title],
+abbr[data-bs-original-title] {
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted;
+ cursor: help;
+ -webkit-text-decoration-skip-ink: none;
+ text-decoration-skip-ink: none;
+}
+
+address {
+ margin-bottom: 1rem;
+ font-style: normal;
+ line-height: inherit;
+}
+
+ol,
+ul {
+ padding-left: 2rem;
+}
+
+ol,
+ul,
+dl {
+ margin-top: 0;
+ margin-bottom: 1rem;
+}
+
+ol ol,
+ul ul,
+ol ul,
+ul ol {
+ margin-bottom: 0;
+}
+
+dt {
+ font-weight: 700;
+}
+
+dd {
+ margin-bottom: 0.5rem;
+ margin-left: 0;
+}
+
+blockquote {
+ margin: 0 0 1rem;
+}
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+small, .small {
+ font-size: 0.875em;
+}
+
+mark, .mark {
+ padding: 0.2em;
+ background-color: #fcf8e3;
+}
+
+sub,
+sup {
+ position: relative;
+ font-size: 0.75em;
+ line-height: 0;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+a {
+ color: #0d6efd;
+ text-decoration: underline;
+}
+a:hover {
+ color: #0a58ca;
+}
+
+a:not([href]):not([class]), a:not([href]):not([class]):hover {
+ color: inherit;
+ text-decoration: none;
+}
+
+pre,
+code,
+kbd,
+samp {
+ font-family: var(--bs-font-monospace);
+ font-size: 1em;
+ direction: ltr /* rtl:ignore */;
+ unicode-bidi: bidi-override;
+}
+
+pre {
+ display: block;
+ margin-top: 0;
+ margin-bottom: 1rem;
+ overflow: auto;
+ font-size: 0.875em;
+}
+pre code {
+ font-size: inherit;
+ color: inherit;
+ word-break: normal;
+}
+
+code {
+ font-size: 0.875em;
+ color: #d63384;
+ word-wrap: break-word;
+}
+a > code {
+ color: inherit;
+}
+
+kbd {
+ padding: 0.2rem 0.4rem;
+ font-size: 0.875em;
+ color: #fff;
+ background-color: #212529;
+ border-radius: 0.2rem;
+}
+kbd kbd {
+ padding: 0;
+ font-size: 1em;
+ font-weight: 700;
+}
+
+figure {
+ margin: 0 0 1rem;
+}
+
+img,
+svg {
+ vertical-align: middle;
+}
+
+table {
+ caption-side: bottom;
+ border-collapse: collapse;
+}
+
+caption {
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ color: #6c757d;
+ text-align: left;
+}
+
+th {
+ text-align: inherit;
+ text-align: -webkit-match-parent;
+}
+
+thead,
+tbody,
+tfoot,
+tr,
+td,
+th {
+ border-color: inherit;
+ border-style: solid;
+ border-width: 0;
+}
+
+label {
+ display: inline-block;
+}
+
+button {
+ border-radius: 0;
+}
+
+button:focus:not(:focus-visible) {
+ outline: 0;
+}
+
+input,
+button,
+select,
+optgroup,
+textarea {
+ margin: 0;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+button,
+select {
+ text-transform: none;
+}
+
+[role=button] {
+ cursor: pointer;
+}
+
+select {
+ word-wrap: normal;
+}
+select:disabled {
+ opacity: 1;
+}
+
+[list]::-webkit-calendar-picker-indicator {
+ display: none;
+}
+
+button,
+[type=button],
+[type=reset],
+[type=submit] {
+ -webkit-appearance: button;
+}
+button:not(:disabled),
+[type=button]:not(:disabled),
+[type=reset]:not(:disabled),
+[type=submit]:not(:disabled) {
+ cursor: pointer;
+}
+
+::-moz-focus-inner {
+ padding: 0;
+ border-style: none;
+}
+
+textarea {
+ resize: vertical;
+}
+
+fieldset {
+ min-width: 0;
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+
+legend {
+ float: left;
+ width: 100%;
+ padding: 0;
+ margin-bottom: 0.5rem;
+ font-size: calc(1.275rem + 0.3vw);
+ line-height: inherit;
+}
+@media (min-width: 1200px) {
+ legend {
+ font-size: 1.5rem;
+ }
+}
+legend + * {
+ clear: left;
+}
+
+::-webkit-datetime-edit-fields-wrapper,
+::-webkit-datetime-edit-text,
+::-webkit-datetime-edit-minute,
+::-webkit-datetime-edit-hour-field,
+::-webkit-datetime-edit-day-field,
+::-webkit-datetime-edit-month-field,
+::-webkit-datetime-edit-year-field {
+ padding: 0;
+}
+
+::-webkit-inner-spin-button {
+ height: auto;
+}
+
+[type=search] {
+ outline-offset: -2px;
+ -webkit-appearance: textfield;
+}
+
+/* rtl:raw:
+[type="tel"],
+[type="url"],
+[type="email"],
+[type="number"] {
+ direction: ltr;
+}
+*/
+::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+::-webkit-color-swatch-wrapper {
+ padding: 0;
+}
+
+::file-selector-button {
+ font: inherit;
+}
+
+::-webkit-file-upload-button {
+ font: inherit;
+ -webkit-appearance: button;
+}
+
+output {
+ display: inline-block;
+}
+
+iframe {
+ border: 0;
+}
+
+summary {
+ display: list-item;
+ cursor: pointer;
+}
+
+progress {
+ vertical-align: baseline;
+}
+
+[hidden] {
+ display: none !important;
+}
+
+.lead {
+ font-size: 1.25rem;
+ font-weight: 300;
+}
+
+.display-1 {
+ font-size: calc(1.625rem + 4.5vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-1 {
+ font-size: 5rem;
+ }
+}
+
+.display-2 {
+ font-size: calc(1.575rem + 3.9vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-2 {
+ font-size: 4.5rem;
+ }
+}
+
+.display-3 {
+ font-size: calc(1.525rem + 3.3vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-3 {
+ font-size: 4rem;
+ }
+}
+
+.display-4 {
+ font-size: calc(1.475rem + 2.7vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-4 {
+ font-size: 3.5rem;
+ }
+}
+
+.display-5 {
+ font-size: calc(1.425rem + 2.1vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-5 {
+ font-size: 3rem;
+ }
+}
+
+.display-6 {
+ font-size: calc(1.375rem + 1.5vw);
+ font-weight: 300;
+ line-height: 1.2;
+}
+@media (min-width: 1200px) {
+ .display-6 {
+ font-size: 2.5rem;
+ }
+}
+
+.list-unstyled {
+ padding-left: 0;
+ list-style: none;
+}
+
+.list-inline {
+ padding-left: 0;
+ list-style: none;
+}
+
+.list-inline-item {
+ display: inline-block;
+}
+.list-inline-item:not(:last-child) {
+ margin-right: 0.5rem;
+}
+
+.initialism {
+ font-size: 0.875em;
+ text-transform: uppercase;
+}
+
+.blockquote {
+ margin-bottom: 1rem;
+ font-size: 1.25rem;
+}
+.blockquote > :last-child {
+ margin-bottom: 0;
+}
+
+.blockquote-footer {
+ margin-top: -1rem;
+ margin-bottom: 1rem;
+ font-size: 0.875em;
+ color: #6c757d;
+}
+.blockquote-footer::before {
+ content: "— ";
+}
+
+.img-fluid {
+ max-width: 100%;
+ height: auto;
+}
+
+.img-thumbnail {
+ padding: 0.25rem;
+ background-color: #fff;
+ border: 1px solid #dee2e6;
+ border-radius: 0.25rem;
+ max-width: 100%;
+ height: auto;
+}
+
+.figure {
+ display: inline-block;
+}
+
+.figure-img {
+ margin-bottom: 0.5rem;
+ line-height: 1;
+}
+
+.figure-caption {
+ font-size: 0.875em;
+ color: #6c757d;
+}
+
+.container,
+.container-fluid,
+.container-xxl,
+.container-xl,
+.container-lg,
+.container-md,
+.container-sm {
+ width: 100%;
+ padding-right: var(--bs-gutter-x, 0.75rem);
+ padding-left: var(--bs-gutter-x, 0.75rem);
+ margin-right: auto;
+ margin-left: auto;
+}
+
+@media (min-width: 576px) {
+ .container-sm, .container {
+ max-width: 540px;
+ }
+}
+@media (min-width: 768px) {
+ .container-md, .container-sm, .container {
+ max-width: 720px;
+ }
+}
+@media (min-width: 992px) {
+ .container-lg, .container-md, .container-sm, .container {
+ max-width: 960px;
+ }
+}
+@media (min-width: 1200px) {
+ .container-xl, .container-lg, .container-md, .container-sm, .container {
+ max-width: 1140px;
+ }
+}
+@media (min-width: 1400px) {
+ .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {
+ max-width: 1320px;
+ }
+}
+.row {
+ --bs-gutter-x: 1.5rem;
+ --bs-gutter-y: 0;
+ display: flex;
+ flex-wrap: wrap;
+ margin-top: calc(var(--bs-gutter-y) * -1);
+ margin-right: calc(var(--bs-gutter-x) * -.5);
+ margin-left: calc(var(--bs-gutter-x) * -.5);
+}
+.row > * {
+ flex-shrink: 0;
+ width: 100%;
+ max-width: 100%;
+ padding-right: calc(var(--bs-gutter-x) * .5);
+ padding-left: calc(var(--bs-gutter-x) * .5);
+ margin-top: var(--bs-gutter-y);
+}
+
+.col {
+ flex: 1 0 0%;
+}
+
+.row-cols-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+}
+
+.row-cols-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+}
+
+.row-cols-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+}
+
+.row-cols-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+}
+
+.row-cols-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+}
+
+.row-cols-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+}
+
+.row-cols-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+}
+
+.col-auto {
+ flex: 0 0 auto;
+ width: auto;
+}
+
+.col-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+}
+
+.col-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+}
+
+.col-3 {
+ flex: 0 0 auto;
+ width: 25%;
+}
+
+.col-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+}
+
+.col-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+}
+
+.col-6 {
+ flex: 0 0 auto;
+ width: 50%;
+}
+
+.col-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+}
+
+.col-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+}
+
+.col-9 {
+ flex: 0 0 auto;
+ width: 75%;
+}
+
+.col-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+}
+
+.col-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+}
+
+.col-12 {
+ flex: 0 0 auto;
+ width: 100%;
+}
+
+.offset-1 {
+ margin-left: 8.33333333%;
+}
+
+.offset-2 {
+ margin-left: 16.66666667%;
+}
+
+.offset-3 {
+ margin-left: 25%;
+}
+
+.offset-4 {
+ margin-left: 33.33333333%;
+}
+
+.offset-5 {
+ margin-left: 41.66666667%;
+}
+
+.offset-6 {
+ margin-left: 50%;
+}
+
+.offset-7 {
+ margin-left: 58.33333333%;
+}
+
+.offset-8 {
+ margin-left: 66.66666667%;
+}
+
+.offset-9 {
+ margin-left: 75%;
+}
+
+.offset-10 {
+ margin-left: 83.33333333%;
+}
+
+.offset-11 {
+ margin-left: 91.66666667%;
+}
+
+.g-0,
+.gx-0 {
+ --bs-gutter-x: 0;
+}
+
+.g-0,
+.gy-0 {
+ --bs-gutter-y: 0;
+}
+
+.g-1,
+.gx-1 {
+ --bs-gutter-x: 0.25rem;
+}
+
+.g-1,
+.gy-1 {
+ --bs-gutter-y: 0.25rem;
+}
+
+.g-2,
+.gx-2 {
+ --bs-gutter-x: 0.5rem;
+}
+
+.g-2,
+.gy-2 {
+ --bs-gutter-y: 0.5rem;
+}
+
+.g-3,
+.gx-3 {
+ --bs-gutter-x: 1rem;
+}
+
+.g-3,
+.gy-3 {
+ --bs-gutter-y: 1rem;
+}
+
+.g-4,
+.gx-4 {
+ --bs-gutter-x: 1.5rem;
+}
+
+.g-4,
+.gy-4 {
+ --bs-gutter-y: 1.5rem;
+}
+
+.g-5,
+.gx-5 {
+ --bs-gutter-x: 3rem;
+}
+
+.g-5,
+.gy-5 {
+ --bs-gutter-y: 3rem;
+}
+
+@media (min-width: 576px) {
+ .col-sm {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-sm-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-sm-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-sm-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-sm-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-sm-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-sm-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-sm-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-sm-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-sm-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-sm-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-sm-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-sm-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-sm-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-sm-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-sm-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-sm-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-sm-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-sm-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-sm-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-sm-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-sm-0 {
+ margin-left: 0;
+ }
+
+ .offset-sm-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-sm-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-sm-3 {
+ margin-left: 25%;
+ }
+
+ .offset-sm-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-sm-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-sm-6 {
+ margin-left: 50%;
+ }
+
+ .offset-sm-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-sm-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-sm-9 {
+ margin-left: 75%;
+ }
+
+ .offset-sm-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-sm-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-sm-0,
+.gx-sm-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-sm-0,
+.gy-sm-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-sm-1,
+.gx-sm-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-sm-1,
+.gy-sm-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-sm-2,
+.gx-sm-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-sm-2,
+.gy-sm-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-sm-3,
+.gx-sm-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-sm-3,
+.gy-sm-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-sm-4,
+.gx-sm-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-sm-4,
+.gy-sm-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-sm-5,
+.gx-sm-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-sm-5,
+.gy-sm-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+@media (min-width: 768px) {
+ .col-md {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-md-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-md-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-md-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-md-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-md-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-md-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-md-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-md-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-md-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-md-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-md-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-md-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-md-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-md-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-md-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-md-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-md-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-md-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-md-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-md-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-md-0 {
+ margin-left: 0;
+ }
+
+ .offset-md-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-md-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-md-3 {
+ margin-left: 25%;
+ }
+
+ .offset-md-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-md-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-md-6 {
+ margin-left: 50%;
+ }
+
+ .offset-md-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-md-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-md-9 {
+ margin-left: 75%;
+ }
+
+ .offset-md-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-md-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-md-0,
+.gx-md-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-md-0,
+.gy-md-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-md-1,
+.gx-md-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-md-1,
+.gy-md-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-md-2,
+.gx-md-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-md-2,
+.gy-md-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-md-3,
+.gx-md-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-md-3,
+.gy-md-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-md-4,
+.gx-md-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-md-4,
+.gy-md-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-md-5,
+.gx-md-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-md-5,
+.gy-md-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+@media (min-width: 992px) {
+ .col-lg {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-lg-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-lg-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-lg-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-lg-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-lg-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-lg-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-lg-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-lg-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-lg-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-lg-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-lg-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-lg-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-lg-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-lg-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-lg-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-lg-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-lg-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-lg-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-lg-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-lg-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-lg-0 {
+ margin-left: 0;
+ }
+
+ .offset-lg-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-lg-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-lg-3 {
+ margin-left: 25%;
+ }
+
+ .offset-lg-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-lg-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-lg-6 {
+ margin-left: 50%;
+ }
+
+ .offset-lg-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-lg-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-lg-9 {
+ margin-left: 75%;
+ }
+
+ .offset-lg-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-lg-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-lg-0,
+.gx-lg-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-lg-0,
+.gy-lg-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-lg-1,
+.gx-lg-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-lg-1,
+.gy-lg-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-lg-2,
+.gx-lg-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-lg-2,
+.gy-lg-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-lg-3,
+.gx-lg-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-lg-3,
+.gy-lg-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-lg-4,
+.gx-lg-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-lg-4,
+.gy-lg-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-lg-5,
+.gx-lg-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-lg-5,
+.gy-lg-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+@media (min-width: 1200px) {
+ .col-xl {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-xl-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-xl-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-xl-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-xl-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-xl-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-xl-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-xl-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-xl-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-xl-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-xl-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-xl-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-xl-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-xl-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-xl-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-xl-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-xl-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-xl-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-xl-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-xl-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-xl-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-xl-0 {
+ margin-left: 0;
+ }
+
+ .offset-xl-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-xl-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-xl-3 {
+ margin-left: 25%;
+ }
+
+ .offset-xl-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-xl-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-xl-6 {
+ margin-left: 50%;
+ }
+
+ .offset-xl-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-xl-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-xl-9 {
+ margin-left: 75%;
+ }
+
+ .offset-xl-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-xl-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-xl-0,
+.gx-xl-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-xl-0,
+.gy-xl-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-xl-1,
+.gx-xl-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-xl-1,
+.gy-xl-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-xl-2,
+.gx-xl-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-xl-2,
+.gy-xl-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-xl-3,
+.gx-xl-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-xl-3,
+.gy-xl-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-xl-4,
+.gx-xl-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-xl-4,
+.gy-xl-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-xl-5,
+.gx-xl-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-xl-5,
+.gy-xl-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+@media (min-width: 1400px) {
+ .col-xxl {
+ flex: 1 0 0%;
+ }
+
+ .row-cols-xxl-auto > * {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .row-cols-xxl-1 > * {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .row-cols-xxl-2 > * {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .row-cols-xxl-3 > * {
+ flex: 0 0 auto;
+ width: 33.3333333333%;
+ }
+
+ .row-cols-xxl-4 > * {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .row-cols-xxl-5 > * {
+ flex: 0 0 auto;
+ width: 20%;
+ }
+
+ .row-cols-xxl-6 > * {
+ flex: 0 0 auto;
+ width: 16.6666666667%;
+ }
+
+ .col-xxl-auto {
+ flex: 0 0 auto;
+ width: auto;
+ }
+
+ .col-xxl-1 {
+ flex: 0 0 auto;
+ width: 8.33333333%;
+ }
+
+ .col-xxl-2 {
+ flex: 0 0 auto;
+ width: 16.66666667%;
+ }
+
+ .col-xxl-3 {
+ flex: 0 0 auto;
+ width: 25%;
+ }
+
+ .col-xxl-4 {
+ flex: 0 0 auto;
+ width: 33.33333333%;
+ }
+
+ .col-xxl-5 {
+ flex: 0 0 auto;
+ width: 41.66666667%;
+ }
+
+ .col-xxl-6 {
+ flex: 0 0 auto;
+ width: 50%;
+ }
+
+ .col-xxl-7 {
+ flex: 0 0 auto;
+ width: 58.33333333%;
+ }
+
+ .col-xxl-8 {
+ flex: 0 0 auto;
+ width: 66.66666667%;
+ }
+
+ .col-xxl-9 {
+ flex: 0 0 auto;
+ width: 75%;
+ }
+
+ .col-xxl-10 {
+ flex: 0 0 auto;
+ width: 83.33333333%;
+ }
+
+ .col-xxl-11 {
+ flex: 0 0 auto;
+ width: 91.66666667%;
+ }
+
+ .col-xxl-12 {
+ flex: 0 0 auto;
+ width: 100%;
+ }
+
+ .offset-xxl-0 {
+ margin-left: 0;
+ }
+
+ .offset-xxl-1 {
+ margin-left: 8.33333333%;
+ }
+
+ .offset-xxl-2 {
+ margin-left: 16.66666667%;
+ }
+
+ .offset-xxl-3 {
+ margin-left: 25%;
+ }
+
+ .offset-xxl-4 {
+ margin-left: 33.33333333%;
+ }
+
+ .offset-xxl-5 {
+ margin-left: 41.66666667%;
+ }
+
+ .offset-xxl-6 {
+ margin-left: 50%;
+ }
+
+ .offset-xxl-7 {
+ margin-left: 58.33333333%;
+ }
+
+ .offset-xxl-8 {
+ margin-left: 66.66666667%;
+ }
+
+ .offset-xxl-9 {
+ margin-left: 75%;
+ }
+
+ .offset-xxl-10 {
+ margin-left: 83.33333333%;
+ }
+
+ .offset-xxl-11 {
+ margin-left: 91.66666667%;
+ }
+
+ .g-xxl-0,
+.gx-xxl-0 {
+ --bs-gutter-x: 0;
+ }
+
+ .g-xxl-0,
+.gy-xxl-0 {
+ --bs-gutter-y: 0;
+ }
+
+ .g-xxl-1,
+.gx-xxl-1 {
+ --bs-gutter-x: 0.25rem;
+ }
+
+ .g-xxl-1,
+.gy-xxl-1 {
+ --bs-gutter-y: 0.25rem;
+ }
+
+ .g-xxl-2,
+.gx-xxl-2 {
+ --bs-gutter-x: 0.5rem;
+ }
+
+ .g-xxl-2,
+.gy-xxl-2 {
+ --bs-gutter-y: 0.5rem;
+ }
+
+ .g-xxl-3,
+.gx-xxl-3 {
+ --bs-gutter-x: 1rem;
+ }
+
+ .g-xxl-3,
+.gy-xxl-3 {
+ --bs-gutter-y: 1rem;
+ }
+
+ .g-xxl-4,
+.gx-xxl-4 {
+ --bs-gutter-x: 1.5rem;
+ }
+
+ .g-xxl-4,
+.gy-xxl-4 {
+ --bs-gutter-y: 1.5rem;
+ }
+
+ .g-xxl-5,
+.gx-xxl-5 {
+ --bs-gutter-x: 3rem;
+ }
+
+ .g-xxl-5,
+.gy-xxl-5 {
+ --bs-gutter-y: 3rem;
+ }
+}
+.table {
+ --bs-table-bg: transparent;
+ --bs-table-accent-bg: transparent;
+ --bs-table-striped-color: #212529;
+ --bs-table-striped-bg: rgba(0, 0, 0, 0.05);
+ --bs-table-active-color: #212529;
+ --bs-table-active-bg: rgba(0, 0, 0, 0.1);
+ --bs-table-hover-color: #212529;
+ --bs-table-hover-bg: rgba(0, 0, 0, 0.075);
+ width: 100%;
+ margin-bottom: 1rem;
+ color: #212529;
+ vertical-align: top;
+ border-color: #dee2e6;
+}
+.table > :not(caption) > * > * {
+ padding: 0.5rem 0.5rem;
+ background-color: var(--bs-table-bg);
+ border-bottom-width: 1px;
+ box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg);
+}
+.table > tbody {
+ vertical-align: inherit;
+}
+.table > thead {
+ vertical-align: bottom;
+}
+.table > :not(:last-child) > :last-child > * {
+ border-bottom-color: currentColor;
+}
+
+.caption-top {
+ caption-side: top;
+}
+
+.table-sm > :not(caption) > * > * {
+ padding: 0.25rem 0.25rem;
+}
+
+.table-bordered > :not(caption) > * {
+ border-width: 1px 0;
+}
+.table-bordered > :not(caption) > * > * {
+ border-width: 0 1px;
+}
+
+.table-borderless > :not(caption) > * > * {
+ border-bottom-width: 0;
+}
+
+.table-striped > tbody > tr:nth-of-type(odd) {
+ --bs-table-accent-bg: var(--bs-table-striped-bg);
+ color: var(--bs-table-striped-color);
+}
+
+.table-active {
+ --bs-table-accent-bg: var(--bs-table-active-bg);
+ color: var(--bs-table-active-color);
+}
+
+.table-hover > tbody > tr:hover {
+ --bs-table-accent-bg: var(--bs-table-hover-bg);
+ color: var(--bs-table-hover-color);
+}
+
+.table-primary {
+ --bs-table-bg: #cfe2ff;
+ --bs-table-striped-bg: #c5d7f2;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #bacbe6;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #bfd1ec;
+ --bs-table-hover-color: #000;
+ color: #000;
+ border-color: #bacbe6;
+}
+
+.table-secondary {
+ --bs-table-bg: #e2e3e5;
+ --bs-table-striped-bg: #d7d8da;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #cbccce;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #d1d2d4;
+ --bs-table-hover-color: #000;
+ color: #000;
+ border-color: #cbccce;
+}
+
+.table-success {
+ --bs-table-bg: #d1e7dd;
+ --bs-table-striped-bg: #c7dbd2;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #bcd0c7;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #c1d6cc;
+ --bs-table-hover-color: #000;
+ color: #000;
+ border-color: #bcd0c7;
+}
+
+.table-info {
+ --bs-table-bg: #cff4fc;
+ --bs-table-striped-bg: #c5e8ef;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #badce3;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #bfe2e9;
+ --bs-table-hover-color: #000;
+ color: #000;
+ border-color: #badce3;
+}
+
+.table-warning {
+ --bs-table-bg: #fff3cd;
+ --bs-table-striped-bg: #f2e7c3;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #e6dbb9;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #ece1be;
+ --bs-table-hover-color: #000;
+ color: #000;
+ border-color: #e6dbb9;
+}
+
+.table-danger {
+ --bs-table-bg: #f8d7da;
+ --bs-table-striped-bg: #eccccf;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #dfc2c4;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #e5c7ca;
+ --bs-table-hover-color: #000;
+ color: #000;
+ border-color: #dfc2c4;
+}
+
+.table-light {
+ --bs-table-bg: #f8f9fa;
+ --bs-table-striped-bg: #ecedee;
+ --bs-table-striped-color: #000;
+ --bs-table-active-bg: #dfe0e1;
+ --bs-table-active-color: #000;
+ --bs-table-hover-bg: #e5e6e7;
+ --bs-table-hover-color: #000;
+ color: #000;
+ border-color: #dfe0e1;
+}
+
+.table-dark {
+ --bs-table-bg: #212529;
+ --bs-table-striped-bg: #2c3034;
+ --bs-table-striped-color: #fff;
+ --bs-table-active-bg: #373b3e;
+ --bs-table-active-color: #fff;
+ --bs-table-hover-bg: #323539;
+ --bs-table-hover-color: #fff;
+ color: #fff;
+ border-color: #373b3e;
+}
+
+.table-responsive {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+@media (max-width: 575.98px) {
+ .table-responsive-sm {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+}
+@media (max-width: 767.98px) {
+ .table-responsive-md {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+}
+@media (max-width: 991.98px) {
+ .table-responsive-lg {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+}
+@media (max-width: 1199.98px) {
+ .table-responsive-xl {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+}
+@media (max-width: 1399.98px) {
+ .table-responsive-xxl {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+}
+.form-label {
+ margin-bottom: 0.5rem;
+}
+
+.col-form-label {
+ padding-top: calc(0.375rem + 1px);
+ padding-bottom: calc(0.375rem + 1px);
+ margin-bottom: 0;
+ font-size: inherit;
+ line-height: 1.5;
+}
+
+.col-form-label-lg {
+ padding-top: calc(0.5rem + 1px);
+ padding-bottom: calc(0.5rem + 1px);
+ font-size: 1.25rem;
+}
+
+.col-form-label-sm {
+ padding-top: calc(0.25rem + 1px);
+ padding-bottom: calc(0.25rem + 1px);
+ font-size: 0.875rem;
+}
+
+.form-text {
+ margin-top: 0.25rem;
+ font-size: 0.875em;
+ color: #6c757d;
+}
+
+.form-control {
+ display: block;
+ width: 100%;
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #212529;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ced4da;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ border-radius: 0.25rem;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-control {
+ transition: none;
+ }
+}
+.form-control[type=file] {
+ overflow: hidden;
+}
+.form-control[type=file]:not(:disabled):not([readonly]) {
+ cursor: pointer;
+}
+.form-control:focus {
+ color: #212529;
+ background-color: #fff;
+ border-color: #86b7fe;
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+.form-control::-webkit-date-and-time-value {
+ height: 1.5em;
+}
+.form-control::-moz-placeholder {
+ color: #6c757d;
+ opacity: 1;
+}
+.form-control::placeholder {
+ color: #6c757d;
+ opacity: 1;
+}
+.form-control:disabled, .form-control[readonly] {
+ background-color: #e9ecef;
+ opacity: 1;
+}
+.form-control::file-selector-button {
+ padding: 0.375rem 0.75rem;
+ margin: -0.375rem -0.75rem;
+ -webkit-margin-end: 0.75rem;
+ margin-inline-end: 0.75rem;
+ color: #212529;
+ background-color: #e9ecef;
+ pointer-events: none;
+ border-color: inherit;
+ border-style: solid;
+ border-width: 0;
+ border-inline-end-width: 1px;
+ border-radius: 0;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-control::file-selector-button {
+ transition: none;
+ }
+}
+.form-control:hover:not(:disabled):not([readonly])::file-selector-button {
+ background-color: #dde0e3;
+}
+.form-control::-webkit-file-upload-button {
+ padding: 0.375rem 0.75rem;
+ margin: -0.375rem -0.75rem;
+ -webkit-margin-end: 0.75rem;
+ margin-inline-end: 0.75rem;
+ color: #212529;
+ background-color: #e9ecef;
+ pointer-events: none;
+ border-color: inherit;
+ border-style: solid;
+ border-width: 0;
+ border-inline-end-width: 1px;
+ border-radius: 0;
+ -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-control::-webkit-file-upload-button {
+ -webkit-transition: none;
+ transition: none;
+ }
+}
+.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {
+ background-color: #dde0e3;
+}
+
+.form-control-plaintext {
+ display: block;
+ width: 100%;
+ padding: 0.375rem 0;
+ margin-bottom: 0;
+ line-height: 1.5;
+ color: #212529;
+ background-color: transparent;
+ border: solid transparent;
+ border-width: 1px 0;
+}
+.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+.form-control-sm {
+ min-height: calc(1.5em + 0.5rem + 2px);
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ border-radius: 0.2rem;
+}
+.form-control-sm::file-selector-button {
+ padding: 0.25rem 0.5rem;
+ margin: -0.25rem -0.5rem;
+ -webkit-margin-end: 0.5rem;
+ margin-inline-end: 0.5rem;
+}
+.form-control-sm::-webkit-file-upload-button {
+ padding: 0.25rem 0.5rem;
+ margin: -0.25rem -0.5rem;
+ -webkit-margin-end: 0.5rem;
+ margin-inline-end: 0.5rem;
+}
+
+.form-control-lg {
+ min-height: calc(1.5em + 1rem + 2px);
+ padding: 0.5rem 1rem;
+ font-size: 1.25rem;
+ border-radius: 0.3rem;
+}
+.form-control-lg::file-selector-button {
+ padding: 0.5rem 1rem;
+ margin: -0.5rem -1rem;
+ -webkit-margin-end: 1rem;
+ margin-inline-end: 1rem;
+}
+.form-control-lg::-webkit-file-upload-button {
+ padding: 0.5rem 1rem;
+ margin: -0.5rem -1rem;
+ -webkit-margin-end: 1rem;
+ margin-inline-end: 1rem;
+}
+
+textarea.form-control {
+ min-height: calc(1.5em + 0.75rem + 2px);
+}
+textarea.form-control-sm {
+ min-height: calc(1.5em + 0.5rem + 2px);
+}
+textarea.form-control-lg {
+ min-height: calc(1.5em + 1rem + 2px);
+}
+
+.form-control-color {
+ width: 3rem;
+ height: auto;
+ padding: 0.375rem;
+}
+.form-control-color:not(:disabled):not([readonly]) {
+ cursor: pointer;
+}
+.form-control-color::-moz-color-swatch {
+ height: 1.5em;
+ border-radius: 0.25rem;
+}
+.form-control-color::-webkit-color-swatch {
+ height: 1.5em;
+ border-radius: 0.25rem;
+}
+
+.form-select {
+ display: block;
+ width: 100%;
+ padding: 0.375rem 2.25rem 0.375rem 0.75rem;
+ -moz-padding-start: calc(0.75rem - 3px);
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #212529;
+ background-color: #fff;
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
+ background-repeat: no-repeat;
+ background-position: right 0.75rem center;
+ background-size: 16px 12px;
+ border: 1px solid #ced4da;
+ border-radius: 0.25rem;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-select {
+ transition: none;
+ }
+}
+.form-select:focus {
+ border-color: #86b7fe;
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+.form-select[multiple], .form-select[size]:not([size="1"]) {
+ padding-right: 0.75rem;
+ background-image: none;
+}
+.form-select:disabled {
+ background-color: #e9ecef;
+}
+.form-select:-moz-focusring {
+ color: transparent;
+ text-shadow: 0 0 0 #212529;
+}
+
+.form-select-sm {
+ padding-top: 0.25rem;
+ padding-bottom: 0.25rem;
+ padding-left: 0.5rem;
+ font-size: 0.875rem;
+}
+
+.form-select-lg {
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ padding-left: 1rem;
+ font-size: 1.25rem;
+}
+
+.form-check {
+ display: block;
+ min-height: 1.5rem;
+ padding-left: 1.5em;
+ margin-bottom: 0.125rem;
+}
+.form-check .form-check-input {
+ float: left;
+ margin-left: -1.5em;
+}
+
+.form-check-input {
+ width: 1em;
+ height: 1em;
+ margin-top: 0.25em;
+ vertical-align: top;
+ background-color: #fff;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: contain;
+ border: 1px solid rgba(0, 0, 0, 0.25);
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ -webkit-print-color-adjust: exact;
+ color-adjust: exact;
+}
+.form-check-input[type=checkbox] {
+ border-radius: 0.25em;
+}
+.form-check-input[type=radio] {
+ border-radius: 50%;
+}
+.form-check-input:active {
+ filter: brightness(90%);
+}
+.form-check-input:focus {
+ border-color: #86b7fe;
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+.form-check-input:checked {
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+}
+.form-check-input:checked[type=checkbox] {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e");
+}
+.form-check-input:checked[type=radio] {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e");
+}
+.form-check-input[type=checkbox]:indeterminate {
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e");
+}
+.form-check-input:disabled {
+ pointer-events: none;
+ filter: none;
+ opacity: 0.5;
+}
+.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label {
+ opacity: 0.5;
+}
+
+.form-switch {
+ padding-left: 2.5em;
+}
+.form-switch .form-check-input {
+ width: 2em;
+ margin-left: -2.5em;
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
+ background-position: left center;
+ border-radius: 2em;
+ transition: background-position 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-switch .form-check-input {
+ transition: none;
+ }
+}
+.form-switch .form-check-input:focus {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e");
+}
+.form-switch .form-check-input:checked {
+ background-position: right center;
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
+}
+
+.form-check-inline {
+ display: inline-block;
+ margin-right: 1rem;
+}
+
+.btn-check {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
+}
+.btn-check[disabled] + .btn, .btn-check:disabled + .btn {
+ pointer-events: none;
+ filter: none;
+ opacity: 0.65;
+}
+
+.form-range {
+ width: 100%;
+ height: 1.5rem;
+ padding: 0;
+ background-color: transparent;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+.form-range:focus {
+ outline: 0;
+}
+.form-range:focus::-webkit-slider-thumb {
+ box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+.form-range:focus::-moz-range-thumb {
+ box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+.form-range::-moz-focus-outer {
+ border: 0;
+}
+.form-range::-webkit-slider-thumb {
+ width: 1rem;
+ height: 1rem;
+ margin-top: -0.25rem;
+ background-color: #0d6efd;
+ border: 0;
+ border-radius: 1rem;
+ -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ -webkit-appearance: none;
+ appearance: none;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-range::-webkit-slider-thumb {
+ -webkit-transition: none;
+ transition: none;
+ }
+}
+.form-range::-webkit-slider-thumb:active {
+ background-color: #b6d4fe;
+}
+.form-range::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 0.5rem;
+ color: transparent;
+ cursor: pointer;
+ background-color: #dee2e6;
+ border-color: transparent;
+ border-radius: 1rem;
+}
+.form-range::-moz-range-thumb {
+ width: 1rem;
+ height: 1rem;
+ background-color: #0d6efd;
+ border: 0;
+ border-radius: 1rem;
+ -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+ -moz-appearance: none;
+ appearance: none;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-range::-moz-range-thumb {
+ -moz-transition: none;
+ transition: none;
+ }
+}
+.form-range::-moz-range-thumb:active {
+ background-color: #b6d4fe;
+}
+.form-range::-moz-range-track {
+ width: 100%;
+ height: 0.5rem;
+ color: transparent;
+ cursor: pointer;
+ background-color: #dee2e6;
+ border-color: transparent;
+ border-radius: 1rem;
+}
+.form-range:disabled {
+ pointer-events: none;
+}
+.form-range:disabled::-webkit-slider-thumb {
+ background-color: #adb5bd;
+}
+.form-range:disabled::-moz-range-thumb {
+ background-color: #adb5bd;
+}
+
+.form-floating {
+ position: relative;
+}
+.form-floating > .form-control,
+.form-floating > .form-select {
+ height: calc(3.5rem + 2px);
+ line-height: 1.25;
+}
+.form-floating > label {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ padding: 1rem 0.75rem;
+ pointer-events: none;
+ border: 1px solid transparent;
+ transform-origin: 0 0;
+ transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .form-floating > label {
+ transition: none;
+ }
+}
+.form-floating > .form-control {
+ padding: 1rem 0.75rem;
+}
+.form-floating > .form-control::-moz-placeholder {
+ color: transparent;
+}
+.form-floating > .form-control::placeholder {
+ color: transparent;
+}
+.form-floating > .form-control:not(:-moz-placeholder-shown) {
+ padding-top: 1.625rem;
+ padding-bottom: 0.625rem;
+}
+.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown) {
+ padding-top: 1.625rem;
+ padding-bottom: 0.625rem;
+}
+.form-floating > .form-control:-webkit-autofill {
+ padding-top: 1.625rem;
+ padding-bottom: 0.625rem;
+}
+.form-floating > .form-select {
+ padding-top: 1.625rem;
+ padding-bottom: 0.625rem;
+}
+.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label {
+ opacity: 0.65;
+ transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
+}
+.form-floating > .form-control:focus ~ label,
+.form-floating > .form-control:not(:placeholder-shown) ~ label,
+.form-floating > .form-select ~ label {
+ opacity: 0.65;
+ transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
+}
+.form-floating > .form-control:-webkit-autofill ~ label {
+ opacity: 0.65;
+ transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
+}
+
+.input-group {
+ position: relative;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: stretch;
+ width: 100%;
+}
+.input-group > .form-control,
+.input-group > .form-select {
+ position: relative;
+ flex: 1 1 auto;
+ width: 1%;
+ min-width: 0;
+}
+.input-group > .form-control:focus,
+.input-group > .form-select:focus {
+ z-index: 3;
+}
+.input-group .btn {
+ position: relative;
+ z-index: 2;
+}
+.input-group .btn:focus {
+ z-index: 3;
+}
+
+.input-group-text {
+ display: flex;
+ align-items: center;
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #212529;
+ text-align: center;
+ white-space: nowrap;
+ background-color: #e9ecef;
+ border: 1px solid #ced4da;
+ border-radius: 0.25rem;
+}
+
+.input-group-lg > .form-control,
+.input-group-lg > .form-select,
+.input-group-lg > .input-group-text,
+.input-group-lg > .btn {
+ padding: 0.5rem 1rem;
+ font-size: 1.25rem;
+ border-radius: 0.3rem;
+}
+
+.input-group-sm > .form-control,
+.input-group-sm > .form-select,
+.input-group-sm > .input-group-text,
+.input-group-sm > .btn {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ border-radius: 0.2rem;
+}
+
+.input-group-lg > .form-select,
+.input-group-sm > .form-select {
+ padding-right: 3rem;
+}
+
+.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),
+.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu),
+.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
+ margin-left: -1px;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.valid-feedback {
+ display: none;
+ width: 100%;
+ margin-top: 0.25rem;
+ font-size: 0.875em;
+ color: #198754;
+}
+
+.valid-tooltip {
+ position: absolute;
+ top: 100%;
+ z-index: 5;
+ display: none;
+ max-width: 100%;
+ padding: 0.25rem 0.5rem;
+ margin-top: 0.1rem;
+ font-size: 0.875rem;
+ color: #fff;
+ background-color: rgba(25, 135, 84, 0.9);
+ border-radius: 0.25rem;
+}
+
+.was-validated :valid ~ .valid-feedback,
+.was-validated :valid ~ .valid-tooltip,
+.is-valid ~ .valid-feedback,
+.is-valid ~ .valid-tooltip {
+ display: block;
+}
+
+.was-validated .form-control:valid, .form-control.is-valid {
+ border-color: #198754;
+ padding-right: calc(1.5em + 0.75rem);
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
+ background-repeat: no-repeat;
+ background-position: right calc(0.375em + 0.1875rem) center;
+ background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+}
+.was-validated .form-control:valid:focus, .form-control.is-valid:focus {
+ border-color: #198754;
+ box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
+}
+
+.was-validated textarea.form-control:valid, textarea.form-control.is-valid {
+ padding-right: calc(1.5em + 0.75rem);
+ background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);
+}
+
+.was-validated .form-select:valid, .form-select.is-valid {
+ border-color: #198754;
+}
+.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size="1"] {
+ padding-right: 4.125rem;
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
+ background-position: right 0.75rem center, center right 2.25rem;
+ background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+}
+.was-validated .form-select:valid:focus, .form-select.is-valid:focus {
+ border-color: #198754;
+ box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
+}
+
+.was-validated .form-check-input:valid, .form-check-input.is-valid {
+ border-color: #198754;
+}
+.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked {
+ background-color: #198754;
+}
+.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus {
+ box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
+}
+.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {
+ color: #198754;
+}
+
+.form-check-inline .form-check-input ~ .valid-feedback {
+ margin-left: 0.5em;
+}
+
+.was-validated .input-group .form-control:valid, .input-group .form-control.is-valid,
+.was-validated .input-group .form-select:valid,
+.input-group .form-select.is-valid {
+ z-index: 1;
+}
+.was-validated .input-group .form-control:valid:focus, .input-group .form-control.is-valid:focus,
+.was-validated .input-group .form-select:valid:focus,
+.input-group .form-select.is-valid:focus {
+ z-index: 3;
+}
+
+.invalid-feedback {
+ display: none;
+ width: 100%;
+ margin-top: 0.25rem;
+ font-size: 0.875em;
+ color: #dc3545;
+}
+
+.invalid-tooltip {
+ position: absolute;
+ top: 100%;
+ z-index: 5;
+ display: none;
+ max-width: 100%;
+ padding: 0.25rem 0.5rem;
+ margin-top: 0.1rem;
+ font-size: 0.875rem;
+ color: #fff;
+ background-color: rgba(220, 53, 69, 0.9);
+ border-radius: 0.25rem;
+}
+
+.was-validated :invalid ~ .invalid-feedback,
+.was-validated :invalid ~ .invalid-tooltip,
+.is-invalid ~ .invalid-feedback,
+.is-invalid ~ .invalid-tooltip {
+ display: block;
+}
+
+.was-validated .form-control:invalid, .form-control.is-invalid {
+ border-color: #dc3545;
+ padding-right: calc(1.5em + 0.75rem);
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
+ background-repeat: no-repeat;
+ background-position: right calc(0.375em + 0.1875rem) center;
+ background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+}
+.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {
+ border-color: #dc3545;
+ box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
+}
+
+.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {
+ padding-right: calc(1.5em + 0.75rem);
+ background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);
+}
+
+.was-validated .form-select:invalid, .form-select.is-invalid {
+ border-color: #dc3545;
+}
+.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size="1"] {
+ padding-right: 4.125rem;
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
+ background-position: right 0.75rem center, center right 2.25rem;
+ background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
+}
+.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus {
+ border-color: #dc3545;
+ box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
+}
+
+.was-validated .form-check-input:invalid, .form-check-input.is-invalid {
+ border-color: #dc3545;
+}
+.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked {
+ background-color: #dc3545;
+}
+.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus {
+ box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
+}
+.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {
+ color: #dc3545;
+}
+
+.form-check-inline .form-check-input ~ .invalid-feedback {
+ margin-left: 0.5em;
+}
+
+.was-validated .input-group .form-control:invalid, .input-group .form-control.is-invalid,
+.was-validated .input-group .form-select:invalid,
+.input-group .form-select.is-invalid {
+ z-index: 2;
+}
+.was-validated .input-group .form-control:invalid:focus, .input-group .form-control.is-invalid:focus,
+.was-validated .input-group .form-select:invalid:focus,
+.input-group .form-select.is-invalid:focus {
+ z-index: 3;
+}
+
+.btn {
+ display: inline-block;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #212529;
+ text-align: center;
+ text-decoration: none;
+ vertical-align: middle;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ background-color: transparent;
+ border: 1px solid transparent;
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ border-radius: 0.25rem;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .btn {
+ transition: none;
+ }
+}
+.btn:hover {
+ color: #212529;
+}
+.btn-check:focus + .btn, .btn:focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+.btn:disabled, .btn.disabled, fieldset:disabled .btn {
+ pointer-events: none;
+ opacity: 0.65;
+}
+
+.btn-primary {
+ color: #fff;
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+}
+.btn-primary:hover {
+ color: #fff;
+ background-color: #0b5ed7;
+ border-color: #0a58ca;
+}
+.btn-check:focus + .btn-primary, .btn-primary:focus {
+ color: #fff;
+ background-color: #0b5ed7;
+ border-color: #0a58ca;
+ box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, 0.5);
+}
+.btn-check:checked + .btn-primary, .btn-check:active + .btn-primary, .btn-primary:active, .btn-primary.active, .show > .btn-primary.dropdown-toggle {
+ color: #fff;
+ background-color: #0a58ca;
+ border-color: #0a53be;
+}
+.btn-check:checked + .btn-primary:focus, .btn-check:active + .btn-primary:focus, .btn-primary:active:focus, .btn-primary.active:focus, .show > .btn-primary.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, 0.5);
+}
+.btn-primary:disabled, .btn-primary.disabled {
+ color: #fff;
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+}
+
+.btn-secondary {
+ color: #fff;
+ background-color: #6c757d;
+ border-color: #6c757d;
+}
+.btn-secondary:hover {
+ color: #fff;
+ background-color: #5c636a;
+ border-color: #565e64;
+}
+.btn-check:focus + .btn-secondary, .btn-secondary:focus {
+ color: #fff;
+ background-color: #5c636a;
+ border-color: #565e64;
+ box-shadow: 0 0 0 0.25rem rgba(130, 138, 145, 0.5);
+}
+.btn-check:checked + .btn-secondary, .btn-check:active + .btn-secondary, .btn-secondary:active, .btn-secondary.active, .show > .btn-secondary.dropdown-toggle {
+ color: #fff;
+ background-color: #565e64;
+ border-color: #51585e;
+}
+.btn-check:checked + .btn-secondary:focus, .btn-check:active + .btn-secondary:focus, .btn-secondary:active:focus, .btn-secondary.active:focus, .show > .btn-secondary.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.25rem rgba(130, 138, 145, 0.5);
+}
+.btn-secondary:disabled, .btn-secondary.disabled {
+ color: #fff;
+ background-color: #6c757d;
+ border-color: #6c757d;
+}
+
+.btn-success {
+ color: #fff;
+ background-color: #198754;
+ border-color: #198754;
+}
+.btn-success:hover {
+ color: #fff;
+ background-color: #157347;
+ border-color: #146c43;
+}
+.btn-check:focus + .btn-success, .btn-success:focus {
+ color: #fff;
+ background-color: #157347;
+ border-color: #146c43;
+ box-shadow: 0 0 0 0.25rem rgba(60, 153, 110, 0.5);
+}
+.btn-check:checked + .btn-success, .btn-check:active + .btn-success, .btn-success:active, .btn-success.active, .show > .btn-success.dropdown-toggle {
+ color: #fff;
+ background-color: #146c43;
+ border-color: #13653f;
+}
+.btn-check:checked + .btn-success:focus, .btn-check:active + .btn-success:focus, .btn-success:active:focus, .btn-success.active:focus, .show > .btn-success.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.25rem rgba(60, 153, 110, 0.5);
+}
+.btn-success:disabled, .btn-success.disabled {
+ color: #fff;
+ background-color: #198754;
+ border-color: #198754;
+}
+
+.btn-info {
+ color: #000;
+ background-color: #0dcaf0;
+ border-color: #0dcaf0;
+}
+.btn-info:hover {
+ color: #000;
+ background-color: #31d2f2;
+ border-color: #25cff2;
+}
+.btn-check:focus + .btn-info, .btn-info:focus {
+ color: #000;
+ background-color: #31d2f2;
+ border-color: #25cff2;
+ box-shadow: 0 0 0 0.25rem rgba(11, 172, 204, 0.5);
+}
+.btn-check:checked + .btn-info, .btn-check:active + .btn-info, .btn-info:active, .btn-info.active, .show > .btn-info.dropdown-toggle {
+ color: #000;
+ background-color: #3dd5f3;
+ border-color: #25cff2;
+}
+.btn-check:checked + .btn-info:focus, .btn-check:active + .btn-info:focus, .btn-info:active:focus, .btn-info.active:focus, .show > .btn-info.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.25rem rgba(11, 172, 204, 0.5);
+}
+.btn-info:disabled, .btn-info.disabled {
+ color: #000;
+ background-color: #0dcaf0;
+ border-color: #0dcaf0;
+}
+
+.btn-warning {
+ color: #000;
+ background-color: #ffc107;
+ border-color: #ffc107;
+}
+.btn-warning:hover {
+ color: #000;
+ background-color: #ffca2c;
+ border-color: #ffc720;
+}
+.btn-check:focus + .btn-warning, .btn-warning:focus {
+ color: #000;
+ background-color: #ffca2c;
+ border-color: #ffc720;
+ box-shadow: 0 0 0 0.25rem rgba(217, 164, 6, 0.5);
+}
+.btn-check:checked + .btn-warning, .btn-check:active + .btn-warning, .btn-warning:active, .btn-warning.active, .show > .btn-warning.dropdown-toggle {
+ color: #000;
+ background-color: #ffcd39;
+ border-color: #ffc720;
+}
+.btn-check:checked + .btn-warning:focus, .btn-check:active + .btn-warning:focus, .btn-warning:active:focus, .btn-warning.active:focus, .show > .btn-warning.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.25rem rgba(217, 164, 6, 0.5);
+}
+.btn-warning:disabled, .btn-warning.disabled {
+ color: #000;
+ background-color: #ffc107;
+ border-color: #ffc107;
+}
+
+.btn-danger {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+.btn-danger:hover {
+ color: #fff;
+ background-color: #bb2d3b;
+ border-color: #b02a37;
+}
+.btn-check:focus + .btn-danger, .btn-danger:focus {
+ color: #fff;
+ background-color: #bb2d3b;
+ border-color: #b02a37;
+ box-shadow: 0 0 0 0.25rem rgba(225, 83, 97, 0.5);
+}
+.btn-check:checked + .btn-danger, .btn-check:active + .btn-danger, .btn-danger:active, .btn-danger.active, .show > .btn-danger.dropdown-toggle {
+ color: #fff;
+ background-color: #b02a37;
+ border-color: #a52834;
+}
+.btn-check:checked + .btn-danger:focus, .btn-check:active + .btn-danger:focus, .btn-danger:active:focus, .btn-danger.active:focus, .show > .btn-danger.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.25rem rgba(225, 83, 97, 0.5);
+}
+.btn-danger:disabled, .btn-danger.disabled {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+
+.btn-light {
+ color: #000;
+ background-color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+.btn-light:hover {
+ color: #000;
+ background-color: #f9fafb;
+ border-color: #f9fafb;
+}
+.btn-check:focus + .btn-light, .btn-light:focus {
+ color: #000;
+ background-color: #f9fafb;
+ border-color: #f9fafb;
+ box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);
+}
+.btn-check:checked + .btn-light, .btn-check:active + .btn-light, .btn-light:active, .btn-light.active, .show > .btn-light.dropdown-toggle {
+ color: #000;
+ background-color: #f9fafb;
+ border-color: #f9fafb;
+}
+.btn-check:checked + .btn-light:focus, .btn-check:active + .btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, .show > .btn-light.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);
+}
+.btn-light:disabled, .btn-light.disabled {
+ color: #000;
+ background-color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+
+.btn-dark {
+ color: #fff;
+ background-color: #212529;
+ border-color: #212529;
+}
+.btn-dark:hover {
+ color: #fff;
+ background-color: #1c1f23;
+ border-color: #1a1e21;
+}
+.btn-check:focus + .btn-dark, .btn-dark:focus {
+ color: #fff;
+ background-color: #1c1f23;
+ border-color: #1a1e21;
+ box-shadow: 0 0 0 0.25rem rgba(66, 70, 73, 0.5);
+}
+.btn-check:checked + .btn-dark, .btn-check:active + .btn-dark, .btn-dark:active, .btn-dark.active, .show > .btn-dark.dropdown-toggle {
+ color: #fff;
+ background-color: #1a1e21;
+ border-color: #191c1f;
+}
+.btn-check:checked + .btn-dark:focus, .btn-check:active + .btn-dark:focus, .btn-dark:active:focus, .btn-dark.active:focus, .show > .btn-dark.dropdown-toggle:focus {
+ box-shadow: 0 0 0 0.25rem rgba(66, 70, 73, 0.5);
+}
+.btn-dark:disabled, .btn-dark.disabled {
+ color: #fff;
+ background-color: #212529;
+ border-color: #212529;
+}
+
+.btn-outline-primary {
+ color: #0d6efd;
+ border-color: #0d6efd;
+}
+.btn-outline-primary:hover {
+ color: #fff;
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+}
+.btn-check:focus + .btn-outline-primary, .btn-outline-primary:focus {
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.5);
+}
+.btn-check:checked + .btn-outline-primary, .btn-check:active + .btn-outline-primary, .btn-outline-primary:active, .btn-outline-primary.active, .btn-outline-primary.dropdown-toggle.show {
+ color: #fff;
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+}
+.btn-check:checked + .btn-outline-primary:focus, .btn-check:active + .btn-outline-primary:focus, .btn-outline-primary:active:focus, .btn-outline-primary.active:focus, .btn-outline-primary.dropdown-toggle.show:focus {
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.5);
+}
+.btn-outline-primary:disabled, .btn-outline-primary.disabled {
+ color: #0d6efd;
+ background-color: transparent;
+}
+
+.btn-outline-secondary {
+ color: #6c757d;
+ border-color: #6c757d;
+}
+.btn-outline-secondary:hover {
+ color: #fff;
+ background-color: #6c757d;
+ border-color: #6c757d;
+}
+.btn-check:focus + .btn-outline-secondary, .btn-outline-secondary:focus {
+ box-shadow: 0 0 0 0.25rem rgba(108, 117, 125, 0.5);
+}
+.btn-check:checked + .btn-outline-secondary, .btn-check:active + .btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
+ color: #fff;
+ background-color: #6c757d;
+ border-color: #6c757d;
+}
+.btn-check:checked + .btn-outline-secondary:focus, .btn-check:active + .btn-outline-secondary:focus, .btn-outline-secondary:active:focus, .btn-outline-secondary.active:focus, .btn-outline-secondary.dropdown-toggle.show:focus {
+ box-shadow: 0 0 0 0.25rem rgba(108, 117, 125, 0.5);
+}
+.btn-outline-secondary:disabled, .btn-outline-secondary.disabled {
+ color: #6c757d;
+ background-color: transparent;
+}
+
+.btn-outline-success {
+ color: #198754;
+ border-color: #198754;
+}
+.btn-outline-success:hover {
+ color: #fff;
+ background-color: #198754;
+ border-color: #198754;
+}
+.btn-check:focus + .btn-outline-success, .btn-outline-success:focus {
+ box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.5);
+}
+.btn-check:checked + .btn-outline-success, .btn-check:active + .btn-outline-success, .btn-outline-success:active, .btn-outline-success.active, .btn-outline-success.dropdown-toggle.show {
+ color: #fff;
+ background-color: #198754;
+ border-color: #198754;
+}
+.btn-check:checked + .btn-outline-success:focus, .btn-check:active + .btn-outline-success:focus, .btn-outline-success:active:focus, .btn-outline-success.active:focus, .btn-outline-success.dropdown-toggle.show:focus {
+ box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.5);
+}
+.btn-outline-success:disabled, .btn-outline-success.disabled {
+ color: #198754;
+ background-color: transparent;
+}
+
+.btn-outline-info {
+ color: #0dcaf0;
+ border-color: #0dcaf0;
+}
+.btn-outline-info:hover {
+ color: #000;
+ background-color: #0dcaf0;
+ border-color: #0dcaf0;
+}
+.btn-check:focus + .btn-outline-info, .btn-outline-info:focus {
+ box-shadow: 0 0 0 0.25rem rgba(13, 202, 240, 0.5);
+}
+.btn-check:checked + .btn-outline-info, .btn-check:active + .btn-outline-info, .btn-outline-info:active, .btn-outline-info.active, .btn-outline-info.dropdown-toggle.show {
+ color: #000;
+ background-color: #0dcaf0;
+ border-color: #0dcaf0;
+}
+.btn-check:checked + .btn-outline-info:focus, .btn-check:active + .btn-outline-info:focus, .btn-outline-info:active:focus, .btn-outline-info.active:focus, .btn-outline-info.dropdown-toggle.show:focus {
+ box-shadow: 0 0 0 0.25rem rgba(13, 202, 240, 0.5);
+}
+.btn-outline-info:disabled, .btn-outline-info.disabled {
+ color: #0dcaf0;
+ background-color: transparent;
+}
+
+.btn-outline-warning {
+ color: #ffc107;
+ border-color: #ffc107;
+}
+.btn-outline-warning:hover {
+ color: #000;
+ background-color: #ffc107;
+ border-color: #ffc107;
+}
+.btn-check:focus + .btn-outline-warning, .btn-outline-warning:focus {
+ box-shadow: 0 0 0 0.25rem rgba(255, 193, 7, 0.5);
+}
+.btn-check:checked + .btn-outline-warning, .btn-check:active + .btn-outline-warning, .btn-outline-warning:active, .btn-outline-warning.active, .btn-outline-warning.dropdown-toggle.show {
+ color: #000;
+ background-color: #ffc107;
+ border-color: #ffc107;
+}
+.btn-check:checked + .btn-outline-warning:focus, .btn-check:active + .btn-outline-warning:focus, .btn-outline-warning:active:focus, .btn-outline-warning.active:focus, .btn-outline-warning.dropdown-toggle.show:focus {
+ box-shadow: 0 0 0 0.25rem rgba(255, 193, 7, 0.5);
+}
+.btn-outline-warning:disabled, .btn-outline-warning.disabled {
+ color: #ffc107;
+ background-color: transparent;
+}
+
+.btn-outline-danger {
+ color: #dc3545;
+ border-color: #dc3545;
+}
+.btn-outline-danger:hover {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+.btn-check:focus + .btn-outline-danger, .btn-outline-danger:focus {
+ box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.5);
+}
+.btn-check:checked + .btn-outline-danger, .btn-check:active + .btn-outline-danger, .btn-outline-danger:active, .btn-outline-danger.active, .btn-outline-danger.dropdown-toggle.show {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+.btn-check:checked + .btn-outline-danger:focus, .btn-check:active + .btn-outline-danger:focus, .btn-outline-danger:active:focus, .btn-outline-danger.active:focus, .btn-outline-danger.dropdown-toggle.show:focus {
+ box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.5);
+}
+.btn-outline-danger:disabled, .btn-outline-danger.disabled {
+ color: #dc3545;
+ background-color: transparent;
+}
+
+.btn-outline-light {
+ color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+.btn-outline-light:hover {
+ color: #000;
+ background-color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+.btn-check:focus + .btn-outline-light, .btn-outline-light:focus {
+ box-shadow: 0 0 0 0.25rem rgba(248, 249, 250, 0.5);
+}
+.btn-check:checked + .btn-outline-light, .btn-check:active + .btn-outline-light, .btn-outline-light:active, .btn-outline-light.active, .btn-outline-light.dropdown-toggle.show {
+ color: #000;
+ background-color: #f8f9fa;
+ border-color: #f8f9fa;
+}
+.btn-check:checked + .btn-outline-light:focus, .btn-check:active + .btn-outline-light:focus, .btn-outline-light:active:focus, .btn-outline-light.active:focus, .btn-outline-light.dropdown-toggle.show:focus {
+ box-shadow: 0 0 0 0.25rem rgba(248, 249, 250, 0.5);
+}
+.btn-outline-light:disabled, .btn-outline-light.disabled {
+ color: #f8f9fa;
+ background-color: transparent;
+}
+
+.btn-outline-dark {
+ color: #212529;
+ border-color: #212529;
+}
+.btn-outline-dark:hover {
+ color: #fff;
+ background-color: #212529;
+ border-color: #212529;
+}
+.btn-check:focus + .btn-outline-dark, .btn-outline-dark:focus {
+ box-shadow: 0 0 0 0.25rem rgba(33, 37, 41, 0.5);
+}
+.btn-check:checked + .btn-outline-dark, .btn-check:active + .btn-outline-dark, .btn-outline-dark:active, .btn-outline-dark.active, .btn-outline-dark.dropdown-toggle.show {
+ color: #fff;
+ background-color: #212529;
+ border-color: #212529;
+}
+.btn-check:checked + .btn-outline-dark:focus, .btn-check:active + .btn-outline-dark:focus, .btn-outline-dark:active:focus, .btn-outline-dark.active:focus, .btn-outline-dark.dropdown-toggle.show:focus {
+ box-shadow: 0 0 0 0.25rem rgba(33, 37, 41, 0.5);
+}
+.btn-outline-dark:disabled, .btn-outline-dark.disabled {
+ color: #212529;
+ background-color: transparent;
+}
+
+.btn-link {
+ font-weight: 400;
+ color: #0d6efd;
+ text-decoration: underline;
+}
+.btn-link:hover {
+ color: #0a58ca;
+}
+.btn-link:disabled, .btn-link.disabled {
+ color: #6c757d;
+}
+
+.btn-lg, .btn-group-lg > .btn {
+ padding: 0.5rem 1rem;
+ font-size: 1.25rem;
+ border-radius: 0.3rem;
+}
+
+.btn-sm, .btn-group-sm > .btn {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ border-radius: 0.2rem;
+}
+
+.fade {
+ transition: opacity 0.15s linear;
+}
+@media (prefers-reduced-motion: reduce) {
+ .fade {
+ transition: none;
+ }
+}
+.fade:not(.show) {
+ opacity: 0;
+}
+
+.collapse:not(.show) {
+ display: none;
+}
+
+.collapsing {
+ height: 0;
+ overflow: hidden;
+ transition: height 0.35s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .collapsing {
+ transition: none;
+ }
+}
+.collapsing.collapse-horizontal {
+ width: 0;
+ height: auto;
+ transition: width 0.35s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .collapsing.collapse-horizontal {
+ transition: none;
+ }
+}
+
+.dropup,
+.dropend,
+.dropdown,
+.dropstart {
+ position: relative;
+}
+
+.dropdown-toggle {
+ white-space: nowrap;
+}
+.dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid;
+ border-right: 0.3em solid transparent;
+ border-bottom: 0;
+ border-left: 0.3em solid transparent;
+}
+.dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+
+.dropdown-menu {
+ position: absolute;
+ z-index: 1000;
+ display: none;
+ min-width: 10rem;
+ padding: 0.5rem 0;
+ margin: 0;
+ font-size: 1rem;
+ color: #212529;
+ text-align: left;
+ list-style: none;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ border-radius: 0.25rem;
+}
+.dropdown-menu[data-bs-popper] {
+ top: 100%;
+ left: 0;
+ margin-top: 0.125rem;
+}
+
+.dropdown-menu-start {
+ --bs-position: start;
+}
+.dropdown-menu-start[data-bs-popper] {
+ right: auto;
+ left: 0;
+}
+
+.dropdown-menu-end {
+ --bs-position: end;
+}
+.dropdown-menu-end[data-bs-popper] {
+ right: 0;
+ left: auto;
+}
+
+@media (min-width: 576px) {
+ .dropdown-menu-sm-start {
+ --bs-position: start;
+ }
+ .dropdown-menu-sm-start[data-bs-popper] {
+ right: auto;
+ left: 0;
+ }
+
+ .dropdown-menu-sm-end {
+ --bs-position: end;
+ }
+ .dropdown-menu-sm-end[data-bs-popper] {
+ right: 0;
+ left: auto;
+ }
+}
+@media (min-width: 768px) {
+ .dropdown-menu-md-start {
+ --bs-position: start;
+ }
+ .dropdown-menu-md-start[data-bs-popper] {
+ right: auto;
+ left: 0;
+ }
+
+ .dropdown-menu-md-end {
+ --bs-position: end;
+ }
+ .dropdown-menu-md-end[data-bs-popper] {
+ right: 0;
+ left: auto;
+ }
+}
+@media (min-width: 992px) {
+ .dropdown-menu-lg-start {
+ --bs-position: start;
+ }
+ .dropdown-menu-lg-start[data-bs-popper] {
+ right: auto;
+ left: 0;
+ }
+
+ .dropdown-menu-lg-end {
+ --bs-position: end;
+ }
+ .dropdown-menu-lg-end[data-bs-popper] {
+ right: 0;
+ left: auto;
+ }
+}
+@media (min-width: 1200px) {
+ .dropdown-menu-xl-start {
+ --bs-position: start;
+ }
+ .dropdown-menu-xl-start[data-bs-popper] {
+ right: auto;
+ left: 0;
+ }
+
+ .dropdown-menu-xl-end {
+ --bs-position: end;
+ }
+ .dropdown-menu-xl-end[data-bs-popper] {
+ right: 0;
+ left: auto;
+ }
+}
+@media (min-width: 1400px) {
+ .dropdown-menu-xxl-start {
+ --bs-position: start;
+ }
+ .dropdown-menu-xxl-start[data-bs-popper] {
+ right: auto;
+ left: 0;
+ }
+
+ .dropdown-menu-xxl-end {
+ --bs-position: end;
+ }
+ .dropdown-menu-xxl-end[data-bs-popper] {
+ right: 0;
+ left: auto;
+ }
+}
+.dropup .dropdown-menu[data-bs-popper] {
+ top: auto;
+ bottom: 100%;
+ margin-top: 0;
+ margin-bottom: 0.125rem;
+}
+.dropup .dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0;
+ border-right: 0.3em solid transparent;
+ border-bottom: 0.3em solid;
+ border-left: 0.3em solid transparent;
+}
+.dropup .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+
+.dropend .dropdown-menu[data-bs-popper] {
+ top: 0;
+ right: auto;
+ left: 100%;
+ margin-top: 0;
+ margin-left: 0.125rem;
+}
+.dropend .dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid transparent;
+ border-right: 0;
+ border-bottom: 0.3em solid transparent;
+ border-left: 0.3em solid;
+}
+.dropend .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+.dropend .dropdown-toggle::after {
+ vertical-align: 0;
+}
+
+.dropstart .dropdown-menu[data-bs-popper] {
+ top: 0;
+ right: 100%;
+ left: auto;
+ margin-top: 0;
+ margin-right: 0.125rem;
+}
+.dropstart .dropdown-toggle::after {
+ display: inline-block;
+ margin-left: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+}
+.dropstart .dropdown-toggle::after {
+ display: none;
+}
+.dropstart .dropdown-toggle::before {
+ display: inline-block;
+ margin-right: 0.255em;
+ vertical-align: 0.255em;
+ content: "";
+ border-top: 0.3em solid transparent;
+ border-right: 0.3em solid;
+ border-bottom: 0.3em solid transparent;
+}
+.dropstart .dropdown-toggle:empty::after {
+ margin-left: 0;
+}
+.dropstart .dropdown-toggle::before {
+ vertical-align: 0;
+}
+
+.dropdown-divider {
+ height: 0;
+ margin: 0.5rem 0;
+ overflow: hidden;
+ border-top: 1px solid rgba(0, 0, 0, 0.15);
+}
+
+.dropdown-item {
+ display: block;
+ width: 100%;
+ padding: 0.25rem 1rem;
+ clear: both;
+ font-weight: 400;
+ color: #212529;
+ text-align: inherit;
+ text-decoration: none;
+ white-space: nowrap;
+ background-color: transparent;
+ border: 0;
+}
+.dropdown-item:hover, .dropdown-item:focus {
+ color: #1e2125;
+ background-color: #e9ecef;
+}
+.dropdown-item.active, .dropdown-item:active {
+ color: #fff;
+ text-decoration: none;
+ background-color: #0d6efd;
+}
+.dropdown-item.disabled, .dropdown-item:disabled {
+ color: #adb5bd;
+ pointer-events: none;
+ background-color: transparent;
+}
+
+.dropdown-menu.show {
+ display: block;
+}
+
+.dropdown-header {
+ display: block;
+ padding: 0.5rem 1rem;
+ margin-bottom: 0;
+ font-size: 0.875rem;
+ color: #6c757d;
+ white-space: nowrap;
+}
+
+.dropdown-item-text {
+ display: block;
+ padding: 0.25rem 1rem;
+ color: #212529;
+}
+
+.dropdown-menu-dark {
+ color: #dee2e6;
+ background-color: #343a40;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+.dropdown-menu-dark .dropdown-item {
+ color: #dee2e6;
+}
+.dropdown-menu-dark .dropdown-item:hover, .dropdown-menu-dark .dropdown-item:focus {
+ color: #fff;
+ background-color: rgba(255, 255, 255, 0.15);
+}
+.dropdown-menu-dark .dropdown-item.active, .dropdown-menu-dark .dropdown-item:active {
+ color: #fff;
+ background-color: #0d6efd;
+}
+.dropdown-menu-dark .dropdown-item.disabled, .dropdown-menu-dark .dropdown-item:disabled {
+ color: #adb5bd;
+}
+.dropdown-menu-dark .dropdown-divider {
+ border-color: rgba(0, 0, 0, 0.15);
+}
+.dropdown-menu-dark .dropdown-item-text {
+ color: #dee2e6;
+}
+.dropdown-menu-dark .dropdown-header {
+ color: #adb5bd;
+}
+
+.btn-group,
+.btn-group-vertical {
+ position: relative;
+ display: inline-flex;
+ vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+ position: relative;
+ flex: 1 1 auto;
+}
+.btn-group > .btn-check:checked + .btn,
+.btn-group > .btn-check:focus + .btn,
+.btn-group > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn-check:checked + .btn,
+.btn-group-vertical > .btn-check:focus + .btn,
+.btn-group-vertical > .btn:hover,
+.btn-group-vertical > .btn:focus,
+.btn-group-vertical > .btn:active,
+.btn-group-vertical > .btn.active {
+ z-index: 1;
+}
+
+.btn-toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+}
+.btn-toolbar .input-group {
+ width: auto;
+}
+
+.btn-group > .btn:not(:first-child),
+.btn-group > .btn-group:not(:first-child) {
+ margin-left: -1px;
+}
+.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
+.btn-group > .btn-group:not(:last-child) > .btn {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn:nth-child(n+3),
+.btn-group > :not(.btn-check) + .btn,
+.btn-group > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.dropdown-toggle-split {
+ padding-right: 0.5625rem;
+ padding-left: 0.5625rem;
+}
+.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after {
+ margin-left: 0;
+}
+.dropstart .dropdown-toggle-split::before {
+ margin-right: 0;
+}
+
+.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {
+ padding-right: 0.375rem;
+ padding-left: 0.375rem;
+}
+
+.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {
+ padding-right: 0.75rem;
+ padding-left: 0.75rem;
+}
+
+.btn-group-vertical {
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: center;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group {
+ width: 100%;
+}
+.btn-group-vertical > .btn:not(:first-child),
+.btn-group-vertical > .btn-group:not(:first-child) {
+ margin-top: -1px;
+}
+.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
+.btn-group-vertical > .btn-group:not(:last-child) > .btn {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn ~ .btn,
+.btn-group-vertical > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.nav {
+ display: flex;
+ flex-wrap: wrap;
+ padding-left: 0;
+ margin-bottom: 0;
+ list-style: none;
+}
+
+.nav-link {
+ display: block;
+ padding: 0.5rem 1rem;
+ color: #0d6efd;
+ text-decoration: none;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .nav-link {
+ transition: none;
+ }
+}
+.nav-link:hover, .nav-link:focus {
+ color: #0a58ca;
+}
+.nav-link.disabled {
+ color: #6c757d;
+ pointer-events: none;
+ cursor: default;
+}
+
+.nav-tabs {
+ border-bottom: 1px solid #dee2e6;
+}
+.nav-tabs .nav-link {
+ margin-bottom: -1px;
+ background: none;
+ border: 1px solid transparent;
+ border-top-left-radius: 0.25rem;
+ border-top-right-radius: 0.25rem;
+}
+.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
+ border-color: #e9ecef #e9ecef #dee2e6;
+ isolation: isolate;
+}
+.nav-tabs .nav-link.disabled {
+ color: #6c757d;
+ background-color: transparent;
+ border-color: transparent;
+}
+.nav-tabs .nav-link.active,
+.nav-tabs .nav-item.show .nav-link {
+ color: #495057;
+ background-color: #fff;
+ border-color: #dee2e6 #dee2e6 #fff;
+}
+.nav-tabs .dropdown-menu {
+ margin-top: -1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.nav-pills .nav-link {
+ background: none;
+ border: 0;
+ border-radius: 0.25rem;
+}
+.nav-pills .nav-link.active,
+.nav-pills .show > .nav-link {
+ color: #fff;
+ background-color: #0d6efd;
+}
+
+.nav-fill > .nav-link,
+.nav-fill .nav-item {
+ flex: 1 1 auto;
+ text-align: center;
+}
+
+.nav-justified > .nav-link,
+.nav-justified .nav-item {
+ flex-basis: 0;
+ flex-grow: 1;
+ text-align: center;
+}
+
+.nav-fill .nav-item .nav-link,
+.nav-justified .nav-item .nav-link {
+ width: 100%;
+}
+
+.tab-content > .tab-pane {
+ display: none;
+}
+.tab-content > .active {
+ display: block;
+}
+
+.navbar {
+ position: relative;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: space-between;
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+}
+.navbar > .container,
+.navbar > .container-fluid,
+.navbar > .container-sm,
+.navbar > .container-md,
+.navbar > .container-lg,
+.navbar > .container-xl,
+.navbar > .container-xxl {
+ display: flex;
+ flex-wrap: inherit;
+ align-items: center;
+ justify-content: space-between;
+}
+.navbar-brand {
+ padding-top: 0.3125rem;
+ padding-bottom: 0.3125rem;
+ margin-right: 1rem;
+ font-size: 1.25rem;
+ text-decoration: none;
+ white-space: nowrap;
+}
+.navbar-nav {
+ display: flex;
+ flex-direction: column;
+ padding-left: 0;
+ margin-bottom: 0;
+ list-style: none;
+}
+.navbar-nav .nav-link {
+ padding-right: 0;
+ padding-left: 0;
+}
+.navbar-nav .dropdown-menu {
+ position: static;
+}
+
+.navbar-text {
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+}
+
+.navbar-collapse {
+ flex-basis: 100%;
+ flex-grow: 1;
+ align-items: center;
+}
+
+.navbar-toggler {
+ padding: 0.25rem 0.75rem;
+ font-size: 1.25rem;
+ line-height: 1;
+ background-color: transparent;
+ border: 1px solid transparent;
+ border-radius: 0.25rem;
+ transition: box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .navbar-toggler {
+ transition: none;
+ }
+}
+.navbar-toggler:hover {
+ text-decoration: none;
+}
+.navbar-toggler:focus {
+ text-decoration: none;
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem;
+}
+
+.navbar-toggler-icon {
+ display: inline-block;
+ width: 1.5em;
+ height: 1.5em;
+ vertical-align: middle;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: 100%;
+}
+
+.navbar-nav-scroll {
+ max-height: var(--bs-scroll-height, 75vh);
+ overflow-y: auto;
+}
+
+@media (min-width: 576px) {
+ .navbar-expand-sm {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-sm .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-sm .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-sm .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-sm .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-sm .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-sm .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-sm .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-sm .offcanvas {
+ position: inherit;
+ bottom: 0;
+ z-index: 1000;
+ flex-grow: 1;
+ visibility: visible !important;
+ background-color: transparent;
+ border-right: 0;
+ border-left: 0;
+ transition: none;
+ transform: none;
+ }
+ .navbar-expand-sm .offcanvas-top,
+.navbar-expand-sm .offcanvas-bottom {
+ height: auto;
+ border-top: 0;
+ border-bottom: 0;
+ }
+ .navbar-expand-sm .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-expand-md {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-md .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-md .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-md .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-md .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-md .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-md .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-md .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-md .offcanvas {
+ position: inherit;
+ bottom: 0;
+ z-index: 1000;
+ flex-grow: 1;
+ visibility: visible !important;
+ background-color: transparent;
+ border-right: 0;
+ border-left: 0;
+ transition: none;
+ transform: none;
+ }
+ .navbar-expand-md .offcanvas-top,
+.navbar-expand-md .offcanvas-bottom {
+ height: auto;
+ border-top: 0;
+ border-bottom: 0;
+ }
+ .navbar-expand-md .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+@media (min-width: 992px) {
+ .navbar-expand-lg {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-lg .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-lg .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-lg .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-lg .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-lg .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-lg .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-lg .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-lg .offcanvas {
+ position: inherit;
+ bottom: 0;
+ z-index: 1000;
+ flex-grow: 1;
+ visibility: visible !important;
+ background-color: transparent;
+ border-right: 0;
+ border-left: 0;
+ transition: none;
+ transform: none;
+ }
+ .navbar-expand-lg .offcanvas-top,
+.navbar-expand-lg .offcanvas-bottom {
+ height: auto;
+ border-top: 0;
+ border-bottom: 0;
+ }
+ .navbar-expand-lg .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+@media (min-width: 1200px) {
+ .navbar-expand-xl {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-xl .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-xl .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-xl .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-xl .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-xl .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-xl .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-xl .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-xl .offcanvas {
+ position: inherit;
+ bottom: 0;
+ z-index: 1000;
+ flex-grow: 1;
+ visibility: visible !important;
+ background-color: transparent;
+ border-right: 0;
+ border-left: 0;
+ transition: none;
+ transform: none;
+ }
+ .navbar-expand-xl .offcanvas-top,
+.navbar-expand-xl .offcanvas-bottom {
+ height: auto;
+ border-top: 0;
+ border-bottom: 0;
+ }
+ .navbar-expand-xl .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+@media (min-width: 1400px) {
+ .navbar-expand-xxl {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+ .navbar-expand-xxl .navbar-nav {
+ flex-direction: row;
+ }
+ .navbar-expand-xxl .navbar-nav .dropdown-menu {
+ position: absolute;
+ }
+ .navbar-expand-xxl .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ }
+ .navbar-expand-xxl .navbar-nav-scroll {
+ overflow: visible;
+ }
+ .navbar-expand-xxl .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+ }
+ .navbar-expand-xxl .navbar-toggler {
+ display: none;
+ }
+ .navbar-expand-xxl .offcanvas-header {
+ display: none;
+ }
+ .navbar-expand-xxl .offcanvas {
+ position: inherit;
+ bottom: 0;
+ z-index: 1000;
+ flex-grow: 1;
+ visibility: visible !important;
+ background-color: transparent;
+ border-right: 0;
+ border-left: 0;
+ transition: none;
+ transform: none;
+ }
+ .navbar-expand-xxl .offcanvas-top,
+.navbar-expand-xxl .offcanvas-bottom {
+ height: auto;
+ border-top: 0;
+ border-bottom: 0;
+ }
+ .navbar-expand-xxl .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+ }
+}
+.navbar-expand {
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+}
+.navbar-expand .navbar-nav {
+ flex-direction: row;
+}
+.navbar-expand .navbar-nav .dropdown-menu {
+ position: absolute;
+}
+.navbar-expand .navbar-nav .nav-link {
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+}
+.navbar-expand .navbar-nav-scroll {
+ overflow: visible;
+}
+.navbar-expand .navbar-collapse {
+ display: flex !important;
+ flex-basis: auto;
+}
+.navbar-expand .navbar-toggler {
+ display: none;
+}
+.navbar-expand .offcanvas-header {
+ display: none;
+}
+.navbar-expand .offcanvas {
+ position: inherit;
+ bottom: 0;
+ z-index: 1000;
+ flex-grow: 1;
+ visibility: visible !important;
+ background-color: transparent;
+ border-right: 0;
+ border-left: 0;
+ transition: none;
+ transform: none;
+}
+.navbar-expand .offcanvas-top,
+.navbar-expand .offcanvas-bottom {
+ height: auto;
+ border-top: 0;
+ border-bottom: 0;
+}
+.navbar-expand .offcanvas-body {
+ display: flex;
+ flex-grow: 0;
+ padding: 0;
+ overflow-y: visible;
+}
+
+.navbar-light .navbar-brand {
+ color: rgba(0, 0, 0, 0.9);
+}
+.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {
+ color: rgba(0, 0, 0, 0.9);
+}
+.navbar-light .navbar-nav .nav-link {
+ color: rgba(0, 0, 0, 0.55);
+}
+.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {
+ color: rgba(0, 0, 0, 0.7);
+}
+.navbar-light .navbar-nav .nav-link.disabled {
+ color: rgba(0, 0, 0, 0.3);
+}
+.navbar-light .navbar-nav .show > .nav-link,
+.navbar-light .navbar-nav .nav-link.active {
+ color: rgba(0, 0, 0, 0.9);
+}
+.navbar-light .navbar-toggler {
+ color: rgba(0, 0, 0, 0.55);
+ border-color: rgba(0, 0, 0, 0.1);
+}
+.navbar-light .navbar-toggler-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
+}
+.navbar-light .navbar-text {
+ color: rgba(0, 0, 0, 0.55);
+}
+.navbar-light .navbar-text a,
+.navbar-light .navbar-text a:hover,
+.navbar-light .navbar-text a:focus {
+ color: rgba(0, 0, 0, 0.9);
+}
+
+.navbar-dark .navbar-brand {
+ color: #fff;
+}
+.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {
+ color: #fff;
+}
+.navbar-dark .navbar-nav .nav-link {
+ color: rgba(255, 255, 255, 0.55);
+}
+.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {
+ color: rgba(255, 255, 255, 0.75);
+}
+.navbar-dark .navbar-nav .nav-link.disabled {
+ color: rgba(255, 255, 255, 0.25);
+}
+.navbar-dark .navbar-nav .show > .nav-link,
+.navbar-dark .navbar-nav .nav-link.active {
+ color: #fff;
+}
+.navbar-dark .navbar-toggler {
+ color: rgba(255, 255, 255, 0.55);
+ border-color: rgba(255, 255, 255, 0.1);
+}
+.navbar-dark .navbar-toggler-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
+}
+.navbar-dark .navbar-text {
+ color: rgba(255, 255, 255, 0.55);
+}
+.navbar-dark .navbar-text a,
+.navbar-dark .navbar-text a:hover,
+.navbar-dark .navbar-text a:focus {
+ color: #fff;
+}
+
+.card {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+ word-wrap: break-word;
+ background-color: #fff;
+ background-clip: border-box;
+ border: 1px solid rgba(0, 0, 0, 0.125);
+ border-radius: 0.25rem;
+}
+.card > hr {
+ margin-right: 0;
+ margin-left: 0;
+}
+.card > .list-group {
+ border-top: inherit;
+ border-bottom: inherit;
+}
+.card > .list-group:first-child {
+ border-top-width: 0;
+ border-top-left-radius: calc(0.25rem - 1px);
+ border-top-right-radius: calc(0.25rem - 1px);
+}
+.card > .list-group:last-child {
+ border-bottom-width: 0;
+ border-bottom-right-radius: calc(0.25rem - 1px);
+ border-bottom-left-radius: calc(0.25rem - 1px);
+}
+.card > .card-header + .list-group,
+.card > .list-group + .card-footer {
+ border-top: 0;
+}
+
+.card-body {
+ flex: 1 1 auto;
+ padding: 1rem 1rem;
+}
+
+.card-title {
+ margin-bottom: 0.5rem;
+}
+
+.card-subtitle {
+ margin-top: -0.25rem;
+ margin-bottom: 0;
+}
+
+.card-text:last-child {
+ margin-bottom: 0;
+}
+
+.card-link + .card-link {
+ margin-left: 1rem;
+}
+
+.card-header {
+ padding: 0.5rem 1rem;
+ margin-bottom: 0;
+ background-color: rgba(0, 0, 0, 0.03);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.125);
+}
+.card-header:first-child {
+ border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;
+}
+
+.card-footer {
+ padding: 0.5rem 1rem;
+ background-color: rgba(0, 0, 0, 0.03);
+ border-top: 1px solid rgba(0, 0, 0, 0.125);
+}
+.card-footer:last-child {
+ border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);
+}
+
+.card-header-tabs {
+ margin-right: -0.5rem;
+ margin-bottom: -0.5rem;
+ margin-left: -0.5rem;
+ border-bottom: 0;
+}
+
+.card-header-pills {
+ margin-right: -0.5rem;
+ margin-left: -0.5rem;
+}
+
+.card-img-overlay {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ padding: 1rem;
+ border-radius: calc(0.25rem - 1px);
+}
+
+.card-img,
+.card-img-top,
+.card-img-bottom {
+ width: 100%;
+}
+
+.card-img,
+.card-img-top {
+ border-top-left-radius: calc(0.25rem - 1px);
+ border-top-right-radius: calc(0.25rem - 1px);
+}
+
+.card-img,
+.card-img-bottom {
+ border-bottom-right-radius: calc(0.25rem - 1px);
+ border-bottom-left-radius: calc(0.25rem - 1px);
+}
+
+.card-group > .card {
+ margin-bottom: 0.75rem;
+}
+@media (min-width: 576px) {
+ .card-group {
+ display: flex;
+ flex-flow: row wrap;
+ }
+ .card-group > .card {
+ flex: 1 0 0%;
+ margin-bottom: 0;
+ }
+ .card-group > .card + .card {
+ margin-left: 0;
+ border-left: 0;
+ }
+ .card-group > .card:not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+ .card-group > .card:not(:last-child) .card-img-top,
+.card-group > .card:not(:last-child) .card-header {
+ border-top-right-radius: 0;
+ }
+ .card-group > .card:not(:last-child) .card-img-bottom,
+.card-group > .card:not(:last-child) .card-footer {
+ border-bottom-right-radius: 0;
+ }
+ .card-group > .card:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+ .card-group > .card:not(:first-child) .card-img-top,
+.card-group > .card:not(:first-child) .card-header {
+ border-top-left-radius: 0;
+ }
+ .card-group > .card:not(:first-child) .card-img-bottom,
+.card-group > .card:not(:first-child) .card-footer {
+ border-bottom-left-radius: 0;
+ }
+}
+
+.accordion-button {
+ position: relative;
+ display: flex;
+ align-items: center;
+ width: 100%;
+ padding: 1rem 1.25rem;
+ font-size: 1rem;
+ color: #212529;
+ text-align: left;
+ background-color: #fff;
+ border: 0;
+ border-radius: 0;
+ overflow-anchor: none;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .accordion-button {
+ transition: none;
+ }
+}
+.accordion-button:not(.collapsed) {
+ color: #0c63e4;
+ background-color: #e7f1ff;
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.125);
+}
+.accordion-button:not(.collapsed)::after {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+ transform: rotate(-180deg);
+}
+.accordion-button::after {
+ flex-shrink: 0;
+ width: 1.25rem;
+ height: 1.25rem;
+ margin-left: auto;
+ content: "";
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+ background-repeat: no-repeat;
+ background-size: 1.25rem;
+ transition: transform 0.2s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .accordion-button::after {
+ transition: none;
+ }
+}
+.accordion-button:hover {
+ z-index: 2;
+}
+.accordion-button:focus {
+ z-index: 3;
+ border-color: #86b7fe;
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+
+.accordion-header {
+ margin-bottom: 0;
+}
+
+.accordion-item {
+ background-color: #fff;
+ border: 1px solid rgba(0, 0, 0, 0.125);
+}
+.accordion-item:first-of-type {
+ border-top-left-radius: 0.25rem;
+ border-top-right-radius: 0.25rem;
+}
+.accordion-item:first-of-type .accordion-button {
+ border-top-left-radius: calc(0.25rem - 1px);
+ border-top-right-radius: calc(0.25rem - 1px);
+}
+.accordion-item:not(:first-of-type) {
+ border-top: 0;
+}
+.accordion-item:last-of-type {
+ border-bottom-right-radius: 0.25rem;
+ border-bottom-left-radius: 0.25rem;
+}
+.accordion-item:last-of-type .accordion-button.collapsed {
+ border-bottom-right-radius: calc(0.25rem - 1px);
+ border-bottom-left-radius: calc(0.25rem - 1px);
+}
+.accordion-item:last-of-type .accordion-collapse {
+ border-bottom-right-radius: 0.25rem;
+ border-bottom-left-radius: 0.25rem;
+}
+
+.accordion-body {
+ padding: 1rem 1.25rem;
+}
+
+.accordion-flush .accordion-collapse {
+ border-width: 0;
+}
+.accordion-flush .accordion-item {
+ border-right: 0;
+ border-left: 0;
+ border-radius: 0;
+}
+.accordion-flush .accordion-item:first-child {
+ border-top: 0;
+}
+.accordion-flush .accordion-item:last-child {
+ border-bottom: 0;
+}
+.accordion-flush .accordion-item .accordion-button {
+ border-radius: 0;
+}
+
+.breadcrumb {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 0 0;
+ margin-bottom: 1rem;
+ list-style: none;
+}
+
+.breadcrumb-item + .breadcrumb-item {
+ padding-left: 0.5rem;
+}
+.breadcrumb-item + .breadcrumb-item::before {
+ float: left;
+ padding-right: 0.5rem;
+ color: #6c757d;
+ content: var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */;
+}
+.breadcrumb-item.active {
+ color: #6c757d;
+}
+
+.pagination {
+ display: flex;
+ padding-left: 0;
+ list-style: none;
+}
+
+.page-link {
+ position: relative;
+ display: block;
+ color: #0d6efd;
+ text-decoration: none;
+ background-color: #fff;
+ border: 1px solid #dee2e6;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .page-link {
+ transition: none;
+ }
+}
+.page-link:hover {
+ z-index: 2;
+ color: #0a58ca;
+ background-color: #e9ecef;
+ border-color: #dee2e6;
+}
+.page-link:focus {
+ z-index: 3;
+ color: #0a58ca;
+ background-color: #e9ecef;
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+
+.page-item:not(:first-child) .page-link {
+ margin-left: -1px;
+}
+.page-item.active .page-link {
+ z-index: 3;
+ color: #fff;
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+}
+.page-item.disabled .page-link {
+ color: #6c757d;
+ pointer-events: none;
+ background-color: #fff;
+ border-color: #dee2e6;
+}
+
+.page-link {
+ padding: 0.375rem 0.75rem;
+}
+
+.page-item:first-child .page-link {
+ border-top-left-radius: 0.25rem;
+ border-bottom-left-radius: 0.25rem;
+}
+.page-item:last-child .page-link {
+ border-top-right-radius: 0.25rem;
+ border-bottom-right-radius: 0.25rem;
+}
+
+.pagination-lg .page-link {
+ padding: 0.75rem 1.5rem;
+ font-size: 1.25rem;
+}
+.pagination-lg .page-item:first-child .page-link {
+ border-top-left-radius: 0.3rem;
+ border-bottom-left-radius: 0.3rem;
+}
+.pagination-lg .page-item:last-child .page-link {
+ border-top-right-radius: 0.3rem;
+ border-bottom-right-radius: 0.3rem;
+}
+
+.pagination-sm .page-link {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+}
+.pagination-sm .page-item:first-child .page-link {
+ border-top-left-radius: 0.2rem;
+ border-bottom-left-radius: 0.2rem;
+}
+.pagination-sm .page-item:last-child .page-link {
+ border-top-right-radius: 0.2rem;
+ border-bottom-right-radius: 0.2rem;
+}
+
+.badge {
+ display: inline-block;
+ padding: 0.35em 0.65em;
+ font-size: 0.75em;
+ font-weight: 700;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: 0.25rem;
+}
+.badge:empty {
+ display: none;
+}
+
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+
+.alert {
+ position: relative;
+ padding: 1rem 1rem;
+ margin-bottom: 1rem;
+ border: 1px solid transparent;
+ border-radius: 0.25rem;
+}
+
+.alert-heading {
+ color: inherit;
+}
+
+.alert-link {
+ font-weight: 700;
+}
+
+.alert-dismissible {
+ padding-right: 3rem;
+}
+.alert-dismissible .btn-close {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 2;
+ padding: 1.25rem 1rem;
+}
+
+.alert-primary {
+ color: #084298;
+ background-color: #cfe2ff;
+ border-color: #b6d4fe;
+}
+.alert-primary .alert-link {
+ color: #06357a;
+}
+
+.alert-secondary {
+ color: #41464b;
+ background-color: #e2e3e5;
+ border-color: #d3d6d8;
+}
+.alert-secondary .alert-link {
+ color: #34383c;
+}
+
+.alert-success {
+ color: #0f5132;
+ background-color: #d1e7dd;
+ border-color: #badbcc;
+}
+.alert-success .alert-link {
+ color: #0c4128;
+}
+
+.alert-info {
+ color: #055160;
+ background-color: #cff4fc;
+ border-color: #b6effb;
+}
+.alert-info .alert-link {
+ color: #04414d;
+}
+
+.alert-warning {
+ color: #664d03;
+ background-color: #fff3cd;
+ border-color: #ffecb5;
+}
+.alert-warning .alert-link {
+ color: #523e02;
+}
+
+.alert-danger {
+ color: #842029;
+ background-color: #f8d7da;
+ border-color: #f5c2c7;
+}
+.alert-danger .alert-link {
+ color: #6a1a21;
+}
+
+.alert-light {
+ color: #636464;
+ background-color: #fefefe;
+ border-color: #fdfdfe;
+}
+.alert-light .alert-link {
+ color: #4f5050;
+}
+
+.alert-dark {
+ color: #141619;
+ background-color: #d3d3d4;
+ border-color: #bcbebf;
+}
+.alert-dark .alert-link {
+ color: #101214;
+}
+
+@-webkit-keyframes progress-bar-stripes {
+ 0% {
+ background-position-x: 1rem;
+ }
+}
+
+@keyframes progress-bar-stripes {
+ 0% {
+ background-position-x: 1rem;
+ }
+}
+.progress {
+ display: flex;
+ height: 1rem;
+ overflow: hidden;
+ font-size: 0.75rem;
+ background-color: #e9ecef;
+ border-radius: 0.25rem;
+}
+
+.progress-bar {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ overflow: hidden;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ background-color: #0d6efd;
+ transition: width 0.6s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .progress-bar {
+ transition: none;
+ }
+}
+
+.progress-bar-striped {
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-size: 1rem 1rem;
+}
+
+.progress-bar-animated {
+ -webkit-animation: 1s linear infinite progress-bar-stripes;
+ animation: 1s linear infinite progress-bar-stripes;
+}
+@media (prefers-reduced-motion: reduce) {
+ .progress-bar-animated {
+ -webkit-animation: none;
+ animation: none;
+ }
+}
+
+.list-group {
+ display: flex;
+ flex-direction: column;
+ padding-left: 0;
+ margin-bottom: 0;
+ border-radius: 0.25rem;
+}
+
+.list-group-numbered {
+ list-style-type: none;
+ counter-reset: section;
+}
+.list-group-numbered > li::before {
+ content: counters(section, ".") ". ";
+ counter-increment: section;
+}
+
+.list-group-item-action {
+ width: 100%;
+ color: #495057;
+ text-align: inherit;
+}
+.list-group-item-action:hover, .list-group-item-action:focus {
+ z-index: 1;
+ color: #495057;
+ text-decoration: none;
+ background-color: #f8f9fa;
+}
+.list-group-item-action:active {
+ color: #212529;
+ background-color: #e9ecef;
+}
+
+.list-group-item {
+ position: relative;
+ display: block;
+ padding: 0.5rem 1rem;
+ color: #212529;
+ text-decoration: none;
+ background-color: #fff;
+ border: 1px solid rgba(0, 0, 0, 0.125);
+}
+.list-group-item:first-child {
+ border-top-left-radius: inherit;
+ border-top-right-radius: inherit;
+}
+.list-group-item:last-child {
+ border-bottom-right-radius: inherit;
+ border-bottom-left-radius: inherit;
+}
+.list-group-item.disabled, .list-group-item:disabled {
+ color: #6c757d;
+ pointer-events: none;
+ background-color: #fff;
+}
+.list-group-item.active {
+ z-index: 2;
+ color: #fff;
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+}
+.list-group-item + .list-group-item {
+ border-top-width: 0;
+}
+.list-group-item + .list-group-item.active {
+ margin-top: -1px;
+ border-top-width: 1px;
+}
+
+.list-group-horizontal {
+ flex-direction: row;
+}
+.list-group-horizontal > .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+}
+.list-group-horizontal > .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+}
+.list-group-horizontal > .list-group-item.active {
+ margin-top: 0;
+}
+.list-group-horizontal > .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+}
+.list-group-horizontal > .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+}
+
+@media (min-width: 576px) {
+ .list-group-horizontal-sm {
+ flex-direction: row;
+ }
+ .list-group-horizontal-sm > .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-sm > .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-sm > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-sm > .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-sm > .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+@media (min-width: 768px) {
+ .list-group-horizontal-md {
+ flex-direction: row;
+ }
+ .list-group-horizontal-md > .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-md > .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-md > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-md > .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-md > .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+@media (min-width: 992px) {
+ .list-group-horizontal-lg {
+ flex-direction: row;
+ }
+ .list-group-horizontal-lg > .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-lg > .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-lg > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-lg > .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-lg > .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+@media (min-width: 1200px) {
+ .list-group-horizontal-xl {
+ flex-direction: row;
+ }
+ .list-group-horizontal-xl > .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-xl > .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-xl > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-xl > .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-xl > .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+@media (min-width: 1400px) {
+ .list-group-horizontal-xxl {
+ flex-direction: row;
+ }
+ .list-group-horizontal-xxl > .list-group-item:first-child {
+ border-bottom-left-radius: 0.25rem;
+ border-top-right-radius: 0;
+ }
+ .list-group-horizontal-xxl > .list-group-item:last-child {
+ border-top-right-radius: 0.25rem;
+ border-bottom-left-radius: 0;
+ }
+ .list-group-horizontal-xxl > .list-group-item.active {
+ margin-top: 0;
+ }
+ .list-group-horizontal-xxl > .list-group-item + .list-group-item {
+ border-top-width: 1px;
+ border-left-width: 0;
+ }
+ .list-group-horizontal-xxl > .list-group-item + .list-group-item.active {
+ margin-left: -1px;
+ border-left-width: 1px;
+ }
+}
+.list-group-flush {
+ border-radius: 0;
+}
+.list-group-flush > .list-group-item {
+ border-width: 0 0 1px;
+}
+.list-group-flush > .list-group-item:last-child {
+ border-bottom-width: 0;
+}
+
+.list-group-item-primary {
+ color: #084298;
+ background-color: #cfe2ff;
+}
+.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {
+ color: #084298;
+ background-color: #bacbe6;
+}
+.list-group-item-primary.list-group-item-action.active {
+ color: #fff;
+ background-color: #084298;
+ border-color: #084298;
+}
+
+.list-group-item-secondary {
+ color: #41464b;
+ background-color: #e2e3e5;
+}
+.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {
+ color: #41464b;
+ background-color: #cbccce;
+}
+.list-group-item-secondary.list-group-item-action.active {
+ color: #fff;
+ background-color: #41464b;
+ border-color: #41464b;
+}
+
+.list-group-item-success {
+ color: #0f5132;
+ background-color: #d1e7dd;
+}
+.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {
+ color: #0f5132;
+ background-color: #bcd0c7;
+}
+.list-group-item-success.list-group-item-action.active {
+ color: #fff;
+ background-color: #0f5132;
+ border-color: #0f5132;
+}
+
+.list-group-item-info {
+ color: #055160;
+ background-color: #cff4fc;
+}
+.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {
+ color: #055160;
+ background-color: #badce3;
+}
+.list-group-item-info.list-group-item-action.active {
+ color: #fff;
+ background-color: #055160;
+ border-color: #055160;
+}
+
+.list-group-item-warning {
+ color: #664d03;
+ background-color: #fff3cd;
+}
+.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {
+ color: #664d03;
+ background-color: #e6dbb9;
+}
+.list-group-item-warning.list-group-item-action.active {
+ color: #fff;
+ background-color: #664d03;
+ border-color: #664d03;
+}
+
+.list-group-item-danger {
+ color: #842029;
+ background-color: #f8d7da;
+}
+.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {
+ color: #842029;
+ background-color: #dfc2c4;
+}
+.list-group-item-danger.list-group-item-action.active {
+ color: #fff;
+ background-color: #842029;
+ border-color: #842029;
+}
+
+.list-group-item-light {
+ color: #636464;
+ background-color: #fefefe;
+}
+.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {
+ color: #636464;
+ background-color: #e5e5e5;
+}
+.list-group-item-light.list-group-item-action.active {
+ color: #fff;
+ background-color: #636464;
+ border-color: #636464;
+}
+
+.list-group-item-dark {
+ color: #141619;
+ background-color: #d3d3d4;
+}
+.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {
+ color: #141619;
+ background-color: #bebebf;
+}
+.list-group-item-dark.list-group-item-action.active {
+ color: #fff;
+ background-color: #141619;
+ border-color: #141619;
+}
+
+.btn-close {
+ box-sizing: content-box;
+ width: 1em;
+ height: 1em;
+ padding: 0.25em 0.25em;
+ color: #000;
+ background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;
+ border: 0;
+ border-radius: 0.25rem;
+ opacity: 0.5;
+}
+.btn-close:hover {
+ color: #000;
+ text-decoration: none;
+ opacity: 0.75;
+}
+.btn-close:focus {
+ outline: 0;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+ opacity: 1;
+}
+.btn-close:disabled, .btn-close.disabled {
+ pointer-events: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ opacity: 0.25;
+}
+
+.btn-close-white {
+ filter: invert(1) grayscale(100%) brightness(200%);
+}
+
+.toast {
+ width: 350px;
+ max-width: 100%;
+ font-size: 0.875rem;
+ pointer-events: auto;
+ background-color: rgba(255, 255, 255, 0.85);
+ background-clip: padding-box;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+ border-radius: 0.25rem;
+}
+.toast.showing {
+ opacity: 0;
+}
+.toast:not(.show) {
+ display: none;
+}
+
+.toast-container {
+ width: -webkit-max-content;
+ width: -moz-max-content;
+ width: max-content;
+ max-width: 100%;
+ pointer-events: none;
+}
+.toast-container > :not(:last-child) {
+ margin-bottom: 0.75rem;
+}
+
+.toast-header {
+ display: flex;
+ align-items: center;
+ padding: 0.5rem 0.75rem;
+ color: #6c757d;
+ background-color: rgba(255, 255, 255, 0.85);
+ background-clip: padding-box;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+ border-top-left-radius: calc(0.25rem - 1px);
+ border-top-right-radius: calc(0.25rem - 1px);
+}
+.toast-header .btn-close {
+ margin-right: -0.375rem;
+ margin-left: 0.75rem;
+}
+
+.toast-body {
+ padding: 0.75rem;
+ word-wrap: break-word;
+}
+
+.modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1055;
+ display: none;
+ width: 100%;
+ height: 100%;
+ overflow-x: hidden;
+ overflow-y: auto;
+ outline: 0;
+}
+
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 0.5rem;
+ pointer-events: none;
+}
+.modal.fade .modal-dialog {
+ transition: transform 0.3s ease-out;
+ transform: translate(0, -50px);
+}
+@media (prefers-reduced-motion: reduce) {
+ .modal.fade .modal-dialog {
+ transition: none;
+ }
+}
+.modal.show .modal-dialog {
+ transform: none;
+}
+.modal.modal-static .modal-dialog {
+ transform: scale(1.02);
+}
+
+.modal-dialog-scrollable {
+ height: calc(100% - 1rem);
+}
+.modal-dialog-scrollable .modal-content {
+ max-height: 100%;
+ overflow: hidden;
+}
+.modal-dialog-scrollable .modal-body {
+ overflow-y: auto;
+}
+
+.modal-dialog-centered {
+ display: flex;
+ align-items: center;
+ min-height: calc(100% - 1rem);
+}
+
+.modal-content {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ pointer-events: auto;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 0.3rem;
+ outline: 0;
+}
+
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1050;
+ width: 100vw;
+ height: 100vh;
+ background-color: #000;
+}
+.modal-backdrop.fade {
+ opacity: 0;
+}
+.modal-backdrop.show {
+ opacity: 0.5;
+}
+
+.modal-header {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: space-between;
+ padding: 1rem 1rem;
+ border-bottom: 1px solid #dee2e6;
+ border-top-left-radius: calc(0.3rem - 1px);
+ border-top-right-radius: calc(0.3rem - 1px);
+}
+.modal-header .btn-close {
+ padding: 0.5rem 0.5rem;
+ margin: -0.5rem -0.5rem -0.5rem auto;
+}
+
+.modal-title {
+ margin-bottom: 0;
+ line-height: 1.5;
+}
+
+.modal-body {
+ position: relative;
+ flex: 1 1 auto;
+ padding: 1rem;
+}
+
+.modal-footer {
+ display: flex;
+ flex-wrap: wrap;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: flex-end;
+ padding: 0.75rem;
+ border-top: 1px solid #dee2e6;
+ border-bottom-right-radius: calc(0.3rem - 1px);
+ border-bottom-left-radius: calc(0.3rem - 1px);
+}
+.modal-footer > * {
+ margin: 0.25rem;
+}
+
+@media (min-width: 576px) {
+ .modal-dialog {
+ max-width: 500px;
+ margin: 1.75rem auto;
+ }
+
+ .modal-dialog-scrollable {
+ height: calc(100% - 3.5rem);
+ }
+
+ .modal-dialog-centered {
+ min-height: calc(100% - 3.5rem);
+ }
+
+ .modal-sm {
+ max-width: 300px;
+ }
+}
+@media (min-width: 992px) {
+ .modal-lg,
+.modal-xl {
+ max-width: 800px;
+ }
+}
+@media (min-width: 1200px) {
+ .modal-xl {
+ max-width: 1140px;
+ }
+}
+.modal-fullscreen {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+}
+.modal-fullscreen .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+}
+.modal-fullscreen .modal-header {
+ border-radius: 0;
+}
+.modal-fullscreen .modal-body {
+ overflow-y: auto;
+}
+.modal-fullscreen .modal-footer {
+ border-radius: 0;
+}
+
+@media (max-width: 575.98px) {
+ .modal-fullscreen-sm-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-sm-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-sm-down .modal-header {
+ border-radius: 0;
+ }
+ .modal-fullscreen-sm-down .modal-body {
+ overflow-y: auto;
+ }
+ .modal-fullscreen-sm-down .modal-footer {
+ border-radius: 0;
+ }
+}
+@media (max-width: 767.98px) {
+ .modal-fullscreen-md-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-md-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-md-down .modal-header {
+ border-radius: 0;
+ }
+ .modal-fullscreen-md-down .modal-body {
+ overflow-y: auto;
+ }
+ .modal-fullscreen-md-down .modal-footer {
+ border-radius: 0;
+ }
+}
+@media (max-width: 991.98px) {
+ .modal-fullscreen-lg-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-lg-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-lg-down .modal-header {
+ border-radius: 0;
+ }
+ .modal-fullscreen-lg-down .modal-body {
+ overflow-y: auto;
+ }
+ .modal-fullscreen-lg-down .modal-footer {
+ border-radius: 0;
+ }
+}
+@media (max-width: 1199.98px) {
+ .modal-fullscreen-xl-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-xl-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-xl-down .modal-header {
+ border-radius: 0;
+ }
+ .modal-fullscreen-xl-down .modal-body {
+ overflow-y: auto;
+ }
+ .modal-fullscreen-xl-down .modal-footer {
+ border-radius: 0;
+ }
+}
+@media (max-width: 1399.98px) {
+ .modal-fullscreen-xxl-down {
+ width: 100vw;
+ max-width: none;
+ height: 100%;
+ margin: 0;
+ }
+ .modal-fullscreen-xxl-down .modal-content {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ }
+ .modal-fullscreen-xxl-down .modal-header {
+ border-radius: 0;
+ }
+ .modal-fullscreen-xxl-down .modal-body {
+ overflow-y: auto;
+ }
+ .modal-fullscreen-xxl-down .modal-footer {
+ border-radius: 0;
+ }
+}
+.tooltip {
+ position: absolute;
+ z-index: 1080;
+ display: block;
+ margin: 0;
+ font-family: var(--bs-font-sans-serif);
+ font-style: normal;
+ font-weight: 400;
+ line-height: 1.5;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ white-space: normal;
+ line-break: auto;
+ font-size: 0.875rem;
+ word-wrap: break-word;
+ opacity: 0;
+}
+.tooltip.show {
+ opacity: 0.9;
+}
+.tooltip .tooltip-arrow {
+ position: absolute;
+ display: block;
+ width: 0.8rem;
+ height: 0.4rem;
+}
+.tooltip .tooltip-arrow::before {
+ position: absolute;
+ content: "";
+ border-color: transparent;
+ border-style: solid;
+}
+
+.bs-tooltip-top, .bs-tooltip-auto[data-popper-placement^=top] {
+ padding: 0.4rem 0;
+}
+.bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow {
+ bottom: 0;
+}
+.bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before {
+ top: -1px;
+ border-width: 0.4rem 0.4rem 0;
+ border-top-color: #000;
+}
+
+.bs-tooltip-end, .bs-tooltip-auto[data-popper-placement^=right] {
+ padding: 0 0.4rem;
+}
+.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow {
+ left: 0;
+ width: 0.4rem;
+ height: 0.8rem;
+}
+.bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before {
+ right: -1px;
+ border-width: 0.4rem 0.4rem 0.4rem 0;
+ border-right-color: #000;
+}
+
+.bs-tooltip-bottom, .bs-tooltip-auto[data-popper-placement^=bottom] {
+ padding: 0.4rem 0;
+}
+.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow {
+ top: 0;
+}
+.bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before {
+ bottom: -1px;
+ border-width: 0 0.4rem 0.4rem;
+ border-bottom-color: #000;
+}
+
+.bs-tooltip-start, .bs-tooltip-auto[data-popper-placement^=left] {
+ padding: 0 0.4rem;
+}
+.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow {
+ right: 0;
+ width: 0.4rem;
+ height: 0.8rem;
+}
+.bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before {
+ left: -1px;
+ border-width: 0.4rem 0 0.4rem 0.4rem;
+ border-left-color: #000;
+}
+
+.tooltip-inner {
+ max-width: 200px;
+ padding: 0.25rem 0.5rem;
+ color: #fff;
+ text-align: center;
+ background-color: #000;
+ border-radius: 0.25rem;
+}
+
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0 /* rtl:ignore */;
+ z-index: 1070;
+ display: block;
+ max-width: 276px;
+ font-family: var(--bs-font-sans-serif);
+ font-style: normal;
+ font-weight: 400;
+ line-height: 1.5;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ white-space: normal;
+ line-break: auto;
+ font-size: 0.875rem;
+ word-wrap: break-word;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 0.3rem;
+}
+.popover .popover-arrow {
+ position: absolute;
+ display: block;
+ width: 1rem;
+ height: 0.5rem;
+}
+.popover .popover-arrow::before, .popover .popover-arrow::after {
+ position: absolute;
+ display: block;
+ content: "";
+ border-color: transparent;
+ border-style: solid;
+}
+
+.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow {
+ bottom: calc(-0.5rem - 1px);
+}
+.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before {
+ bottom: 0;
+ border-width: 0.5rem 0.5rem 0;
+ border-top-color: rgba(0, 0, 0, 0.25);
+}
+.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {
+ bottom: 1px;
+ border-width: 0.5rem 0.5rem 0;
+ border-top-color: #fff;
+}
+
+.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow {
+ left: calc(-0.5rem - 1px);
+ width: 0.5rem;
+ height: 1rem;
+}
+.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before {
+ left: 0;
+ border-width: 0.5rem 0.5rem 0.5rem 0;
+ border-right-color: rgba(0, 0, 0, 0.25);
+}
+.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after {
+ left: 1px;
+ border-width: 0.5rem 0.5rem 0.5rem 0;
+ border-right-color: #fff;
+}
+
+.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow {
+ top: calc(-0.5rem - 1px);
+}
+.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before {
+ top: 0;
+ border-width: 0 0.5rem 0.5rem 0.5rem;
+ border-bottom-color: rgba(0, 0, 0, 0.25);
+}
+.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {
+ top: 1px;
+ border-width: 0 0.5rem 0.5rem 0.5rem;
+ border-bottom-color: #fff;
+}
+.bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ display: block;
+ width: 1rem;
+ margin-left: -0.5rem;
+ content: "";
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow {
+ right: calc(-0.5rem - 1px);
+ width: 0.5rem;
+ height: 1rem;
+}
+.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before {
+ right: 0;
+ border-width: 0.5rem 0 0.5rem 0.5rem;
+ border-left-color: rgba(0, 0, 0, 0.25);
+}
+.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after {
+ right: 1px;
+ border-width: 0.5rem 0 0.5rem 0.5rem;
+ border-left-color: #fff;
+}
+
+.popover-header {
+ padding: 0.5rem 1rem;
+ margin-bottom: 0;
+ font-size: 1rem;
+ background-color: #f0f0f0;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.2);
+ border-top-left-radius: calc(0.3rem - 1px);
+ border-top-right-radius: calc(0.3rem - 1px);
+}
+.popover-header:empty {
+ display: none;
+}
+
+.popover-body {
+ padding: 1rem 1rem;
+ color: #212529;
+}
+
+.carousel {
+ position: relative;
+}
+
+.carousel.pointer-event {
+ touch-action: pan-y;
+}
+
+.carousel-inner {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+.carousel-inner::after {
+ display: block;
+ clear: both;
+ content: "";
+}
+
+.carousel-item {
+ position: relative;
+ display: none;
+ float: left;
+ width: 100%;
+ margin-right: -100%;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ transition: transform 0.6s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .carousel-item {
+ transition: none;
+ }
+}
+
+.carousel-item.active,
+.carousel-item-next,
+.carousel-item-prev {
+ display: block;
+}
+
+/* rtl:begin:ignore */
+.carousel-item-next:not(.carousel-item-start),
+.active.carousel-item-end {
+ transform: translateX(100%);
+}
+
+.carousel-item-prev:not(.carousel-item-end),
+.active.carousel-item-start {
+ transform: translateX(-100%);
+}
+
+/* rtl:end:ignore */
+.carousel-fade .carousel-item {
+ opacity: 0;
+ transition-property: opacity;
+ transform: none;
+}
+.carousel-fade .carousel-item.active,
+.carousel-fade .carousel-item-next.carousel-item-start,
+.carousel-fade .carousel-item-prev.carousel-item-end {
+ z-index: 1;
+ opacity: 1;
+}
+.carousel-fade .active.carousel-item-start,
+.carousel-fade .active.carousel-item-end {
+ z-index: 0;
+ opacity: 0;
+ transition: opacity 0s 0.6s;
+}
+@media (prefers-reduced-motion: reduce) {
+ .carousel-fade .active.carousel-item-start,
+.carousel-fade .active.carousel-item-end {
+ transition: none;
+ }
+}
+
+.carousel-control-prev,
+.carousel-control-next {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 15%;
+ padding: 0;
+ color: #fff;
+ text-align: center;
+ background: none;
+ border: 0;
+ opacity: 0.5;
+ transition: opacity 0.15s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .carousel-control-prev,
+.carousel-control-next {
+ transition: none;
+ }
+}
+.carousel-control-prev:hover, .carousel-control-prev:focus,
+.carousel-control-next:hover,
+.carousel-control-next:focus {
+ color: #fff;
+ text-decoration: none;
+ outline: 0;
+ opacity: 0.9;
+}
+
+.carousel-control-prev {
+ left: 0;
+}
+
+.carousel-control-next {
+ right: 0;
+}
+
+.carousel-control-prev-icon,
+.carousel-control-next-icon {
+ display: inline-block;
+ width: 2rem;
+ height: 2rem;
+ background-repeat: no-repeat;
+ background-position: 50%;
+ background-size: 100% 100%;
+}
+
+/* rtl:options: {
+ "autoRename": true,
+ "stringMap":[ {
+ "name" : "prev-next",
+ "search" : "prev",
+ "replace" : "next"
+ } ]
+} */
+.carousel-control-prev-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e");
+}
+
+.carousel-control-next-icon {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+}
+
+.carousel-indicators {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 2;
+ display: flex;
+ justify-content: center;
+ padding: 0;
+ margin-right: 15%;
+ margin-bottom: 1rem;
+ margin-left: 15%;
+ list-style: none;
+}
+.carousel-indicators [data-bs-target] {
+ box-sizing: content-box;
+ flex: 0 1 auto;
+ width: 30px;
+ height: 3px;
+ padding: 0;
+ margin-right: 3px;
+ margin-left: 3px;
+ text-indent: -999px;
+ cursor: pointer;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 0;
+ border-top: 10px solid transparent;
+ border-bottom: 10px solid transparent;
+ opacity: 0.5;
+ transition: opacity 0.6s ease;
+}
+@media (prefers-reduced-motion: reduce) {
+ .carousel-indicators [data-bs-target] {
+ transition: none;
+ }
+}
+.carousel-indicators .active {
+ opacity: 1;
+}
+
+.carousel-caption {
+ position: absolute;
+ right: 15%;
+ bottom: 1.25rem;
+ left: 15%;
+ padding-top: 1.25rem;
+ padding-bottom: 1.25rem;
+ color: #fff;
+ text-align: center;
+}
+
+.carousel-dark .carousel-control-prev-icon,
+.carousel-dark .carousel-control-next-icon {
+ filter: invert(1) grayscale(100);
+}
+.carousel-dark .carousel-indicators [data-bs-target] {
+ background-color: #000;
+}
+.carousel-dark .carousel-caption {
+ color: #000;
+}
+
+@-webkit-keyframes spinner-border {
+ to {
+ transform: rotate(360deg) /* rtl:ignore */;
+ }
+}
+
+@keyframes spinner-border {
+ to {
+ transform: rotate(360deg) /* rtl:ignore */;
+ }
+}
+.spinner-border {
+ display: inline-block;
+ width: 2rem;
+ height: 2rem;
+ vertical-align: -0.125em;
+ border: 0.25em solid currentColor;
+ border-right-color: transparent;
+ border-radius: 50%;
+ -webkit-animation: 0.75s linear infinite spinner-border;
+ animation: 0.75s linear infinite spinner-border;
+}
+
+.spinner-border-sm {
+ width: 1rem;
+ height: 1rem;
+ border-width: 0.2em;
+}
+
+@-webkit-keyframes spinner-grow {
+ 0% {
+ transform: scale(0);
+ }
+ 50% {
+ opacity: 1;
+ transform: none;
+ }
+}
+
+@keyframes spinner-grow {
+ 0% {
+ transform: scale(0);
+ }
+ 50% {
+ opacity: 1;
+ transform: none;
+ }
+}
+.spinner-grow {
+ display: inline-block;
+ width: 2rem;
+ height: 2rem;
+ vertical-align: -0.125em;
+ background-color: currentColor;
+ border-radius: 50%;
+ opacity: 0;
+ -webkit-animation: 0.75s linear infinite spinner-grow;
+ animation: 0.75s linear infinite spinner-grow;
+}
+
+.spinner-grow-sm {
+ width: 1rem;
+ height: 1rem;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .spinner-border,
+.spinner-grow {
+ -webkit-animation-duration: 1.5s;
+ animation-duration: 1.5s;
+ }
+}
+.offcanvas {
+ position: fixed;
+ bottom: 0;
+ z-index: 1045;
+ display: flex;
+ flex-direction: column;
+ max-width: 100%;
+ visibility: hidden;
+ background-color: #fff;
+ background-clip: padding-box;
+ outline: 0;
+ transition: transform 0.3s ease-in-out;
+}
+@media (prefers-reduced-motion: reduce) {
+ .offcanvas {
+ transition: none;
+ }
+}
+
+.offcanvas-backdrop {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1040;
+ width: 100vw;
+ height: 100vh;
+ background-color: #000;
+}
+.offcanvas-backdrop.fade {
+ opacity: 0;
+}
+.offcanvas-backdrop.show {
+ opacity: 0.5;
+}
+
+.offcanvas-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 1rem 1rem;
+}
+.offcanvas-header .btn-close {
+ padding: 0.5rem 0.5rem;
+ margin-top: -0.5rem;
+ margin-right: -0.5rem;
+ margin-bottom: -0.5rem;
+}
+
+.offcanvas-title {
+ margin-bottom: 0;
+ line-height: 1.5;
+}
+
+.offcanvas-body {
+ flex-grow: 1;
+ padding: 1rem 1rem;
+ overflow-y: auto;
+}
+
+.offcanvas-start {
+ top: 0;
+ left: 0;
+ width: 400px;
+ border-right: 1px solid rgba(0, 0, 0, 0.2);
+ transform: translateX(-100%);
+}
+
+.offcanvas-end {
+ top: 0;
+ right: 0;
+ width: 400px;
+ border-left: 1px solid rgba(0, 0, 0, 0.2);
+ transform: translateX(100%);
+}
+
+.offcanvas-top {
+ top: 0;
+ right: 0;
+ left: 0;
+ height: 30vh;
+ max-height: 100%;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.2);
+ transform: translateY(-100%);
+}
+
+.offcanvas-bottom {
+ right: 0;
+ left: 0;
+ height: 30vh;
+ max-height: 100%;
+ border-top: 1px solid rgba(0, 0, 0, 0.2);
+ transform: translateY(100%);
+}
+
+.offcanvas.show {
+ transform: none;
+}
+
+.placeholder {
+ display: inline-block;
+ min-height: 1em;
+ vertical-align: middle;
+ cursor: wait;
+ background-color: currentColor;
+ opacity: 0.5;
+}
+.placeholder.btn::before {
+ display: inline-block;
+ content: "";
+}
+
+.placeholder-xs {
+ min-height: 0.6em;
+}
+
+.placeholder-sm {
+ min-height: 0.8em;
+}
+
+.placeholder-lg {
+ min-height: 1.2em;
+}
+
+.placeholder-glow .placeholder {
+ -webkit-animation: placeholder-glow 2s ease-in-out infinite;
+ animation: placeholder-glow 2s ease-in-out infinite;
+}
+
+@-webkit-keyframes placeholder-glow {
+ 50% {
+ opacity: 0.2;
+ }
+}
+
+@keyframes placeholder-glow {
+ 50% {
+ opacity: 0.2;
+ }
+}
+.placeholder-wave {
+ -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);
+ mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);
+ -webkit-mask-size: 200% 100%;
+ mask-size: 200% 100%;
+ -webkit-animation: placeholder-wave 2s linear infinite;
+ animation: placeholder-wave 2s linear infinite;
+}
+
+@-webkit-keyframes placeholder-wave {
+ 100% {
+ -webkit-mask-position: -200% 0%;
+ mask-position: -200% 0%;
+ }
+}
+
+@keyframes placeholder-wave {
+ 100% {
+ -webkit-mask-position: -200% 0%;
+ mask-position: -200% 0%;
+ }
+}
+.clearfix::after {
+ display: block;
+ clear: both;
+ content: "";
+}
+
+.link-primary {
+ color: #0d6efd;
+}
+.link-primary:hover, .link-primary:focus {
+ color: #0a58ca;
+}
+
+.link-secondary {
+ color: #6c757d;
+}
+.link-secondary:hover, .link-secondary:focus {
+ color: #565e64;
+}
+
+.link-success {
+ color: #198754;
+}
+.link-success:hover, .link-success:focus {
+ color: #146c43;
+}
+
+.link-info {
+ color: #0dcaf0;
+}
+.link-info:hover, .link-info:focus {
+ color: #3dd5f3;
+}
+
+.link-warning {
+ color: #ffc107;
+}
+.link-warning:hover, .link-warning:focus {
+ color: #ffcd39;
+}
+
+.link-danger {
+ color: #dc3545;
+}
+.link-danger:hover, .link-danger:focus {
+ color: #b02a37;
+}
+
+.link-light {
+ color: #f8f9fa;
+}
+.link-light:hover, .link-light:focus {
+ color: #f9fafb;
+}
+
+.link-dark {
+ color: #212529;
+}
+.link-dark:hover, .link-dark:focus {
+ color: #1a1e21;
+}
+
+.ratio {
+ position: relative;
+ width: 100%;
+}
+.ratio::before {
+ display: block;
+ padding-top: var(--bs-aspect-ratio);
+ content: "";
+}
+.ratio > * {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.ratio-1x1 {
+ --bs-aspect-ratio: 100%;
+}
+
+.ratio-4x3 {
+ --bs-aspect-ratio: calc(3 / 4 * 100%);
+}
+
+.ratio-16x9 {
+ --bs-aspect-ratio: calc(9 / 16 * 100%);
+}
+
+.ratio-21x9 {
+ --bs-aspect-ratio: calc(9 / 21 * 100%);
+}
+
+.fixed-top {
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+}
+
+.fixed-bottom {
+ position: fixed;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1030;
+}
+
+.sticky-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+}
+
+@media (min-width: 576px) {
+ .sticky-sm-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+}
+@media (min-width: 768px) {
+ .sticky-md-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+}
+@media (min-width: 992px) {
+ .sticky-lg-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+}
+@media (min-width: 1200px) {
+ .sticky-xl-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+}
+@media (min-width: 1400px) {
+ .sticky-xxl-top {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ }
+}
+.hstack {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ align-self: stretch;
+}
+
+.vstack {
+ display: flex;
+ flex: 1 1 auto;
+ flex-direction: column;
+ align-self: stretch;
+}
+
+.visually-hidden,
+.visually-hidden-focusable:not(:focus):not(:focus-within) {
+ position: absolute !important;
+ width: 1px !important;
+ height: 1px !important;
+ padding: 0 !important;
+ margin: -1px !important;
+ overflow: hidden !important;
+ clip: rect(0, 0, 0, 0) !important;
+ white-space: nowrap !important;
+ border: 0 !important;
+}
+
+.stretched-link::after {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1;
+ content: "";
+}
+
+.text-truncate {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.vr {
+ display: inline-block;
+ align-self: stretch;
+ width: 1px;
+ min-height: 1em;
+ background-color: currentColor;
+ opacity: 0.25;
+}
+
+.align-baseline {
+ vertical-align: baseline !important;
+}
+
+.align-top {
+ vertical-align: top !important;
+}
+
+.align-middle {
+ vertical-align: middle !important;
+}
+
+.align-bottom {
+ vertical-align: bottom !important;
+}
+
+.align-text-bottom {
+ vertical-align: text-bottom !important;
+}
+
+.align-text-top {
+ vertical-align: text-top !important;
+}
+
+.float-start {
+ float: left !important;
+}
+
+.float-end {
+ float: right !important;
+}
+
+.float-none {
+ float: none !important;
+}
+
+.opacity-0 {
+ opacity: 0 !important;
+}
+
+.opacity-25 {
+ opacity: 0.25 !important;
+}
+
+.opacity-50 {
+ opacity: 0.5 !important;
+}
+
+.opacity-75 {
+ opacity: 0.75 !important;
+}
+
+.opacity-100 {
+ opacity: 1 !important;
+}
+
+.overflow-auto {
+ overflow: auto !important;
+}
+
+.overflow-hidden {
+ overflow: hidden !important;
+}
+
+.overflow-visible {
+ overflow: visible !important;
+}
+
+.overflow-scroll {
+ overflow: scroll !important;
+}
+
+.d-inline {
+ display: inline !important;
+}
+
+.d-inline-block {
+ display: inline-block !important;
+}
+
+.d-block {
+ display: block !important;
+}
+
+.d-grid {
+ display: grid !important;
+}
+
+.d-table {
+ display: table !important;
+}
+
+.d-table-row {
+ display: table-row !important;
+}
+
+.d-table-cell {
+ display: table-cell !important;
+}
+
+.d-flex {
+ display: flex !important;
+}
+
+.d-inline-flex {
+ display: inline-flex !important;
+}
+
+.d-none {
+ display: none !important;
+}
+
+.shadow {
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
+}
+
+.shadow-sm {
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;
+}
+
+.shadow-lg {
+ box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;
+}
+
+.shadow-none {
+ box-shadow: none !important;
+}
+
+.position-static {
+ position: static !important;
+}
+
+.position-relative {
+ position: relative !important;
+}
+
+.position-absolute {
+ position: absolute !important;
+}
+
+.position-fixed {
+ position: fixed !important;
+}
+
+.position-sticky {
+ position: -webkit-sticky !important;
+ position: sticky !important;
+}
+
+.top-0 {
+ top: 0 !important;
+}
+
+.top-50 {
+ top: 50% !important;
+}
+
+.top-100 {
+ top: 100% !important;
+}
+
+.bottom-0 {
+ bottom: 0 !important;
+}
+
+.bottom-50 {
+ bottom: 50% !important;
+}
+
+.bottom-100 {
+ bottom: 100% !important;
+}
+
+.start-0 {
+ left: 0 !important;
+}
+
+.start-50 {
+ left: 50% !important;
+}
+
+.start-100 {
+ left: 100% !important;
+}
+
+.end-0 {
+ right: 0 !important;
+}
+
+.end-50 {
+ right: 50% !important;
+}
+
+.end-100 {
+ right: 100% !important;
+}
+
+.translate-middle {
+ transform: translate(-50%, -50%) !important;
+}
+
+.translate-middle-x {
+ transform: translateX(-50%) !important;
+}
+
+.translate-middle-y {
+ transform: translateY(-50%) !important;
+}
+
+.border {
+ border: 1px solid #dee2e6 !important;
+}
+
+.border-0 {
+ border: 0 !important;
+}
+
+.border-top {
+ border-top: 1px solid #dee2e6 !important;
+}
+
+.border-top-0 {
+ border-top: 0 !important;
+}
+
+.border-end {
+ border-right: 1px solid #dee2e6 !important;
+}
+
+.border-end-0 {
+ border-right: 0 !important;
+}
+
+.border-bottom {
+ border-bottom: 1px solid #dee2e6 !important;
+}
+
+.border-bottom-0 {
+ border-bottom: 0 !important;
+}
+
+.border-start {
+ border-left: 1px solid #dee2e6 !important;
+}
+
+.border-start-0 {
+ border-left: 0 !important;
+}
+
+.border-primary {
+ border-color: #0d6efd !important;
+}
+
+.border-secondary {
+ border-color: #6c757d !important;
+}
+
+.border-success {
+ border-color: #198754 !important;
+}
+
+.border-info {
+ border-color: #0dcaf0 !important;
+}
+
+.border-warning {
+ border-color: #ffc107 !important;
+}
+
+.border-danger {
+ border-color: #dc3545 !important;
+}
+
+.border-light {
+ border-color: #f8f9fa !important;
+}
+
+.border-dark {
+ border-color: #212529 !important;
+}
+
+.border-white {
+ border-color: #fff !important;
+}
+
+.border-1 {
+ border-width: 1px !important;
+}
+
+.border-2 {
+ border-width: 2px !important;
+}
+
+.border-3 {
+ border-width: 3px !important;
+}
+
+.border-4 {
+ border-width: 4px !important;
+}
+
+.border-5 {
+ border-width: 5px !important;
+}
+
+.w-25 {
+ width: 25% !important;
+}
+
+.w-50 {
+ width: 50% !important;
+}
+
+.w-75 {
+ width: 75% !important;
+}
+
+.w-100 {
+ width: 100% !important;
+}
+
+.w-auto {
+ width: auto !important;
+}
+
+.mw-100 {
+ max-width: 100% !important;
+}
+
+.vw-100 {
+ width: 100vw !important;
+}
+
+.min-vw-100 {
+ min-width: 100vw !important;
+}
+
+.h-25 {
+ height: 25% !important;
+}
+
+.h-50 {
+ height: 50% !important;
+}
+
+.h-75 {
+ height: 75% !important;
+}
+
+.h-100 {
+ height: 100% !important;
+}
+
+.h-auto {
+ height: auto !important;
+}
+
+.mh-100 {
+ max-height: 100% !important;
+}
+
+.vh-100 {
+ height: 100vh !important;
+}
+
+.min-vh-100 {
+ min-height: 100vh !important;
+}
+
+.flex-fill {
+ flex: 1 1 auto !important;
+}
+
+.flex-row {
+ flex-direction: row !important;
+}
+
+.flex-column {
+ flex-direction: column !important;
+}
+
+.flex-row-reverse {
+ flex-direction: row-reverse !important;
+}
+
+.flex-column-reverse {
+ flex-direction: column-reverse !important;
+}
+
+.flex-grow-0 {
+ flex-grow: 0 !important;
+}
+
+.flex-grow-1 {
+ flex-grow: 1 !important;
+}
+
+.flex-shrink-0 {
+ flex-shrink: 0 !important;
+}
+
+.flex-shrink-1 {
+ flex-shrink: 1 !important;
+}
+
+.flex-wrap {
+ flex-wrap: wrap !important;
+}
+
+.flex-nowrap {
+ flex-wrap: nowrap !important;
+}
+
+.flex-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+}
+
+.gap-0 {
+ gap: 0 !important;
+}
+
+.gap-1 {
+ gap: 0.25rem !important;
+}
+
+.gap-2 {
+ gap: 0.5rem !important;
+}
+
+.gap-3 {
+ gap: 1rem !important;
+}
+
+.gap-4 {
+ gap: 1.5rem !important;
+}
+
+.gap-5 {
+ gap: 3rem !important;
+}
+
+.justify-content-start {
+ justify-content: flex-start !important;
+}
+
+.justify-content-end {
+ justify-content: flex-end !important;
+}
+
+.justify-content-center {
+ justify-content: center !important;
+}
+
+.justify-content-between {
+ justify-content: space-between !important;
+}
+
+.justify-content-around {
+ justify-content: space-around !important;
+}
+
+.justify-content-evenly {
+ justify-content: space-evenly !important;
+}
+
+.align-items-start {
+ align-items: flex-start !important;
+}
+
+.align-items-end {
+ align-items: flex-end !important;
+}
+
+.align-items-center {
+ align-items: center !important;
+}
+
+.align-items-baseline {
+ align-items: baseline !important;
+}
+
+.align-items-stretch {
+ align-items: stretch !important;
+}
+
+.align-content-start {
+ align-content: flex-start !important;
+}
+
+.align-content-end {
+ align-content: flex-end !important;
+}
+
+.align-content-center {
+ align-content: center !important;
+}
+
+.align-content-between {
+ align-content: space-between !important;
+}
+
+.align-content-around {
+ align-content: space-around !important;
+}
+
+.align-content-stretch {
+ align-content: stretch !important;
+}
+
+.align-self-auto {
+ align-self: auto !important;
+}
+
+.align-self-start {
+ align-self: flex-start !important;
+}
+
+.align-self-end {
+ align-self: flex-end !important;
+}
+
+.align-self-center {
+ align-self: center !important;
+}
+
+.align-self-baseline {
+ align-self: baseline !important;
+}
+
+.align-self-stretch {
+ align-self: stretch !important;
+}
+
+.order-first {
+ order: -1 !important;
+}
+
+.order-0 {
+ order: 0 !important;
+}
+
+.order-1 {
+ order: 1 !important;
+}
+
+.order-2 {
+ order: 2 !important;
+}
+
+.order-3 {
+ order: 3 !important;
+}
+
+.order-4 {
+ order: 4 !important;
+}
+
+.order-5 {
+ order: 5 !important;
+}
+
+.order-last {
+ order: 6 !important;
+}
+
+.m-0 {
+ margin: 0 !important;
+}
+
+.m-1 {
+ margin: 0.25rem !important;
+}
+
+.m-2 {
+ margin: 0.5rem !important;
+}
+
+.m-3 {
+ margin: 1rem !important;
+}
+
+.m-4 {
+ margin: 1.5rem !important;
+}
+
+.m-5 {
+ margin: 3rem !important;
+}
+
+.m-auto {
+ margin: auto !important;
+}
+
+.mx-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+}
+
+.mx-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+}
+
+.mx-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+}
+
+.mx-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+}
+
+.mx-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+}
+
+.mx-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+}
+
+.mx-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+}
+
+.my-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+}
+
+.my-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+}
+
+.my-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+}
+
+.my-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+}
+
+.my-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+}
+
+.my-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+}
+
+.my-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+}
+
+.mt-0 {
+ margin-top: 0 !important;
+}
+
+.mt-1 {
+ margin-top: 0.25rem !important;
+}
+
+.mt-2 {
+ margin-top: 0.5rem !important;
+}
+
+.mt-3 {
+ margin-top: 1rem !important;
+}
+
+.mt-4 {
+ margin-top: 1.5rem !important;
+}
+
+.mt-5 {
+ margin-top: 3rem !important;
+}
+
+.mt-auto {
+ margin-top: auto !important;
+}
+
+.me-0 {
+ margin-right: 0 !important;
+}
+
+.me-1 {
+ margin-right: 0.25rem !important;
+}
+
+.me-2 {
+ margin-right: 0.5rem !important;
+}
+
+.me-3 {
+ margin-right: 1rem !important;
+}
+
+.me-4 {
+ margin-right: 1.5rem !important;
+}
+
+.me-5 {
+ margin-right: 3rem !important;
+}
+
+.me-auto {
+ margin-right: auto !important;
+}
+
+.mb-0 {
+ margin-bottom: 0 !important;
+}
+
+.mb-1 {
+ margin-bottom: 0.25rem !important;
+}
+
+.mb-2 {
+ margin-bottom: 0.5rem !important;
+}
+
+.mb-3 {
+ margin-bottom: 1rem !important;
+}
+
+.mb-4 {
+ margin-bottom: 1.5rem !important;
+}
+
+.mb-5 {
+ margin-bottom: 3rem !important;
+}
+
+.mb-auto {
+ margin-bottom: auto !important;
+}
+
+.ms-0 {
+ margin-left: 0 !important;
+}
+
+.ms-1 {
+ margin-left: 0.25rem !important;
+}
+
+.ms-2 {
+ margin-left: 0.5rem !important;
+}
+
+.ms-3 {
+ margin-left: 1rem !important;
+}
+
+.ms-4 {
+ margin-left: 1.5rem !important;
+}
+
+.ms-5 {
+ margin-left: 3rem !important;
+}
+
+.ms-auto {
+ margin-left: auto !important;
+}
+
+.p-0 {
+ padding: 0 !important;
+}
+
+.p-1 {
+ padding: 0.25rem !important;
+}
+
+.p-2 {
+ padding: 0.5rem !important;
+}
+
+.p-3 {
+ padding: 1rem !important;
+}
+
+.p-4 {
+ padding: 1.5rem !important;
+}
+
+.p-5 {
+ padding: 3rem !important;
+}
+
+.px-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+}
+
+.px-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+}
+
+.px-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+}
+
+.px-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+}
+
+.px-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+}
+
+.px-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+}
+
+.py-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+}
+
+.py-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+}
+
+.py-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+}
+
+.py-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+}
+
+.py-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+}
+
+.py-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+}
+
+.pt-0 {
+ padding-top: 0 !important;
+}
+
+.pt-1 {
+ padding-top: 0.25rem !important;
+}
+
+.pt-2 {
+ padding-top: 0.5rem !important;
+}
+
+.pt-3 {
+ padding-top: 1rem !important;
+}
+
+.pt-4 {
+ padding-top: 1.5rem !important;
+}
+
+.pt-5 {
+ padding-top: 3rem !important;
+}
+
+.pe-0 {
+ padding-right: 0 !important;
+}
+
+.pe-1 {
+ padding-right: 0.25rem !important;
+}
+
+.pe-2 {
+ padding-right: 0.5rem !important;
+}
+
+.pe-3 {
+ padding-right: 1rem !important;
+}
+
+.pe-4 {
+ padding-right: 1.5rem !important;
+}
+
+.pe-5 {
+ padding-right: 3rem !important;
+}
+
+.pb-0 {
+ padding-bottom: 0 !important;
+}
+
+.pb-1 {
+ padding-bottom: 0.25rem !important;
+}
+
+.pb-2 {
+ padding-bottom: 0.5rem !important;
+}
+
+.pb-3 {
+ padding-bottom: 1rem !important;
+}
+
+.pb-4 {
+ padding-bottom: 1.5rem !important;
+}
+
+.pb-5 {
+ padding-bottom: 3rem !important;
+}
+
+.ps-0 {
+ padding-left: 0 !important;
+}
+
+.ps-1 {
+ padding-left: 0.25rem !important;
+}
+
+.ps-2 {
+ padding-left: 0.5rem !important;
+}
+
+.ps-3 {
+ padding-left: 1rem !important;
+}
+
+.ps-4 {
+ padding-left: 1.5rem !important;
+}
+
+.ps-5 {
+ padding-left: 3rem !important;
+}
+
+.font-monospace {
+ font-family: var(--bs-font-monospace) !important;
+}
+
+.fs-1 {
+ font-size: calc(1.375rem + 1.5vw) !important;
+}
+
+.fs-2 {
+ font-size: calc(1.325rem + 0.9vw) !important;
+}
+
+.fs-3 {
+ font-size: calc(1.3rem + 0.6vw) !important;
+}
+
+.fs-4 {
+ font-size: calc(1.275rem + 0.3vw) !important;
+}
+
+.fs-5 {
+ font-size: 1.25rem !important;
+}
+
+.fs-6 {
+ font-size: 1rem !important;
+}
+
+.fst-italic {
+ font-style: italic !important;
+}
+
+.fst-normal {
+ font-style: normal !important;
+}
+
+.fw-light {
+ font-weight: 300 !important;
+}
+
+.fw-lighter {
+ font-weight: lighter !important;
+}
+
+.fw-normal {
+ font-weight: 400 !important;
+}
+
+.fw-bold {
+ font-weight: 700 !important;
+}
+
+.fw-bolder {
+ font-weight: bolder !important;
+}
+
+.lh-1 {
+ line-height: 1 !important;
+}
+
+.lh-sm {
+ line-height: 1.25 !important;
+}
+
+.lh-base {
+ line-height: 1.5 !important;
+}
+
+.lh-lg {
+ line-height: 2 !important;
+}
+
+.text-start {
+ text-align: left !important;
+}
+
+.text-end {
+ text-align: right !important;
+}
+
+.text-center {
+ text-align: center !important;
+}
+
+.text-decoration-none {
+ text-decoration: none !important;
+}
+
+.text-decoration-underline {
+ text-decoration: underline !important;
+}
+
+.text-decoration-line-through {
+ text-decoration: line-through !important;
+}
+
+.text-lowercase {
+ text-transform: lowercase !important;
+}
+
+.text-uppercase {
+ text-transform: uppercase !important;
+}
+
+.text-capitalize {
+ text-transform: capitalize !important;
+}
+
+.text-wrap {
+ white-space: normal !important;
+}
+
+.text-nowrap {
+ white-space: nowrap !important;
+}
+
+/* rtl:begin:remove */
+.text-break {
+ word-wrap: break-word !important;
+ word-break: break-word !important;
+}
+
+/* rtl:end:remove */
+.text-primary {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-secondary {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-success {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-info {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-warning {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-danger {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-light {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-dark {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-black {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-white {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-body {
+ --bs-text-opacity: 1;
+ color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important;
+}
+
+.text-muted {
+ --bs-text-opacity: 1;
+ color: #6c757d !important;
+}
+
+.text-black-50 {
+ --bs-text-opacity: 1;
+ color: rgba(0, 0, 0, 0.5) !important;
+}
+
+.text-white-50 {
+ --bs-text-opacity: 1;
+ color: rgba(255, 255, 255, 0.5) !important;
+}
+
+.text-reset {
+ --bs-text-opacity: 1;
+ color: inherit !important;
+}
+
+.text-opacity-25 {
+ --bs-text-opacity: 0.25;
+}
+
+.text-opacity-50 {
+ --bs-text-opacity: 0.5;
+}
+
+.text-opacity-75 {
+ --bs-text-opacity: 0.75;
+}
+
+.text-opacity-100 {
+ --bs-text-opacity: 1;
+}
+
+.bg-primary {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-secondary {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-success {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-info {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-warning {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-danger {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-light {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-dark {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-black {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-white {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-body {
+ --bs-bg-opacity: 1;
+ background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
+}
+
+.bg-transparent {
+ --bs-bg-opacity: 1;
+ background-color: transparent !important;
+}
+
+.bg-opacity-10 {
+ --bs-bg-opacity: 0.1;
+}
+
+.bg-opacity-25 {
+ --bs-bg-opacity: 0.25;
+}
+
+.bg-opacity-50 {
+ --bs-bg-opacity: 0.5;
+}
+
+.bg-opacity-75 {
+ --bs-bg-opacity: 0.75;
+}
+
+.bg-opacity-100 {
+ --bs-bg-opacity: 1;
+}
+
+.bg-gradient {
+ background-image: var(--bs-gradient) !important;
+}
+
+.user-select-all {
+ -webkit-user-select: all !important;
+ -moz-user-select: all !important;
+ user-select: all !important;
+}
+
+.user-select-auto {
+ -webkit-user-select: auto !important;
+ -moz-user-select: auto !important;
+ user-select: auto !important;
+}
+
+.user-select-none {
+ -webkit-user-select: none !important;
+ -moz-user-select: none !important;
+ user-select: none !important;
+}
+
+.pe-none {
+ pointer-events: none !important;
+}
+
+.pe-auto {
+ pointer-events: auto !important;
+}
+
+.rounded {
+ border-radius: 0.25rem !important;
+}
+
+.rounded-0 {
+ border-radius: 0 !important;
+}
+
+.rounded-1 {
+ border-radius: 0.2rem !important;
+}
+
+.rounded-2 {
+ border-radius: 0.25rem !important;
+}
+
+.rounded-3 {
+ border-radius: 0.3rem !important;
+}
+
+.rounded-circle {
+ border-radius: 50% !important;
+}
+
+.rounded-pill {
+ border-radius: 50rem !important;
+}
+
+.rounded-top {
+ border-top-left-radius: 0.25rem !important;
+ border-top-right-radius: 0.25rem !important;
+}
+
+.rounded-end {
+ border-top-right-radius: 0.25rem !important;
+ border-bottom-right-radius: 0.25rem !important;
+}
+
+.rounded-bottom {
+ border-bottom-right-radius: 0.25rem !important;
+ border-bottom-left-radius: 0.25rem !important;
+}
+
+.rounded-start {
+ border-bottom-left-radius: 0.25rem !important;
+ border-top-left-radius: 0.25rem !important;
+}
+
+.visible {
+ visibility: visible !important;
+}
+
+.invisible {
+ visibility: hidden !important;
+}
+
+@media (min-width: 576px) {
+ .float-sm-start {
+ float: left !important;
+ }
+
+ .float-sm-end {
+ float: right !important;
+ }
+
+ .float-sm-none {
+ float: none !important;
+ }
+
+ .d-sm-inline {
+ display: inline !important;
+ }
+
+ .d-sm-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-sm-block {
+ display: block !important;
+ }
+
+ .d-sm-grid {
+ display: grid !important;
+ }
+
+ .d-sm-table {
+ display: table !important;
+ }
+
+ .d-sm-table-row {
+ display: table-row !important;
+ }
+
+ .d-sm-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-sm-flex {
+ display: flex !important;
+ }
+
+ .d-sm-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-sm-none {
+ display: none !important;
+ }
+
+ .flex-sm-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-sm-row {
+ flex-direction: row !important;
+ }
+
+ .flex-sm-column {
+ flex-direction: column !important;
+ }
+
+ .flex-sm-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-sm-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-sm-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-sm-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-sm-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-sm-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-sm-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-sm-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-sm-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .gap-sm-0 {
+ gap: 0 !important;
+ }
+
+ .gap-sm-1 {
+ gap: 0.25rem !important;
+ }
+
+ .gap-sm-2 {
+ gap: 0.5rem !important;
+ }
+
+ .gap-sm-3 {
+ gap: 1rem !important;
+ }
+
+ .gap-sm-4 {
+ gap: 1.5rem !important;
+ }
+
+ .gap-sm-5 {
+ gap: 3rem !important;
+ }
+
+ .justify-content-sm-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-sm-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-sm-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-sm-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-sm-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-sm-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-sm-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-sm-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-sm-center {
+ align-items: center !important;
+ }
+
+ .align-items-sm-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-sm-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-sm-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-sm-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-sm-center {
+ align-content: center !important;
+ }
+
+ .align-content-sm-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-sm-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-sm-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-sm-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-sm-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-sm-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-sm-center {
+ align-self: center !important;
+ }
+
+ .align-self-sm-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-sm-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-sm-first {
+ order: -1 !important;
+ }
+
+ .order-sm-0 {
+ order: 0 !important;
+ }
+
+ .order-sm-1 {
+ order: 1 !important;
+ }
+
+ .order-sm-2 {
+ order: 2 !important;
+ }
+
+ .order-sm-3 {
+ order: 3 !important;
+ }
+
+ .order-sm-4 {
+ order: 4 !important;
+ }
+
+ .order-sm-5 {
+ order: 5 !important;
+ }
+
+ .order-sm-last {
+ order: 6 !important;
+ }
+
+ .m-sm-0 {
+ margin: 0 !important;
+ }
+
+ .m-sm-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-sm-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-sm-3 {
+ margin: 1rem !important;
+ }
+
+ .m-sm-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-sm-5 {
+ margin: 3rem !important;
+ }
+
+ .m-sm-auto {
+ margin: auto !important;
+ }
+
+ .mx-sm-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-sm-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-sm-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-sm-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-sm-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-sm-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-sm-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-sm-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-sm-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-sm-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-sm-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-sm-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-sm-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-sm-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-sm-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-sm-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-sm-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-sm-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-sm-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-sm-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-sm-auto {
+ margin-top: auto !important;
+ }
+
+ .me-sm-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-sm-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-sm-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-sm-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-sm-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-sm-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-sm-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-sm-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-sm-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-sm-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-sm-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-sm-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-sm-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-sm-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-sm-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-sm-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-sm-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-sm-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-sm-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-sm-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-sm-auto {
+ margin-left: auto !important;
+ }
+
+ .p-sm-0 {
+ padding: 0 !important;
+ }
+
+ .p-sm-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-sm-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-sm-3 {
+ padding: 1rem !important;
+ }
+
+ .p-sm-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-sm-5 {
+ padding: 3rem !important;
+ }
+
+ .px-sm-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-sm-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-sm-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-sm-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-sm-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-sm-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-sm-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-sm-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-sm-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-sm-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-sm-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-sm-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-sm-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-sm-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-sm-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-sm-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-sm-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-sm-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-sm-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-sm-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-sm-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-sm-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-sm-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-sm-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-sm-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-sm-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-sm-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-sm-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-sm-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-sm-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-sm-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-sm-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-sm-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-sm-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-sm-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-sm-5 {
+ padding-left: 3rem !important;
+ }
+
+ .text-sm-start {
+ text-align: left !important;
+ }
+
+ .text-sm-end {
+ text-align: right !important;
+ }
+
+ .text-sm-center {
+ text-align: center !important;
+ }
+}
+@media (min-width: 768px) {
+ .float-md-start {
+ float: left !important;
+ }
+
+ .float-md-end {
+ float: right !important;
+ }
+
+ .float-md-none {
+ float: none !important;
+ }
+
+ .d-md-inline {
+ display: inline !important;
+ }
+
+ .d-md-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-md-block {
+ display: block !important;
+ }
+
+ .d-md-grid {
+ display: grid !important;
+ }
+
+ .d-md-table {
+ display: table !important;
+ }
+
+ .d-md-table-row {
+ display: table-row !important;
+ }
+
+ .d-md-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-md-flex {
+ display: flex !important;
+ }
+
+ .d-md-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-md-none {
+ display: none !important;
+ }
+
+ .flex-md-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-md-row {
+ flex-direction: row !important;
+ }
+
+ .flex-md-column {
+ flex-direction: column !important;
+ }
+
+ .flex-md-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-md-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-md-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-md-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-md-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-md-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-md-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-md-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-md-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .gap-md-0 {
+ gap: 0 !important;
+ }
+
+ .gap-md-1 {
+ gap: 0.25rem !important;
+ }
+
+ .gap-md-2 {
+ gap: 0.5rem !important;
+ }
+
+ .gap-md-3 {
+ gap: 1rem !important;
+ }
+
+ .gap-md-4 {
+ gap: 1.5rem !important;
+ }
+
+ .gap-md-5 {
+ gap: 3rem !important;
+ }
+
+ .justify-content-md-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-md-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-md-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-md-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-md-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-md-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-md-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-md-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-md-center {
+ align-items: center !important;
+ }
+
+ .align-items-md-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-md-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-md-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-md-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-md-center {
+ align-content: center !important;
+ }
+
+ .align-content-md-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-md-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-md-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-md-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-md-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-md-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-md-center {
+ align-self: center !important;
+ }
+
+ .align-self-md-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-md-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-md-first {
+ order: -1 !important;
+ }
+
+ .order-md-0 {
+ order: 0 !important;
+ }
+
+ .order-md-1 {
+ order: 1 !important;
+ }
+
+ .order-md-2 {
+ order: 2 !important;
+ }
+
+ .order-md-3 {
+ order: 3 !important;
+ }
+
+ .order-md-4 {
+ order: 4 !important;
+ }
+
+ .order-md-5 {
+ order: 5 !important;
+ }
+
+ .order-md-last {
+ order: 6 !important;
+ }
+
+ .m-md-0 {
+ margin: 0 !important;
+ }
+
+ .m-md-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-md-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-md-3 {
+ margin: 1rem !important;
+ }
+
+ .m-md-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-md-5 {
+ margin: 3rem !important;
+ }
+
+ .m-md-auto {
+ margin: auto !important;
+ }
+
+ .mx-md-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-md-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-md-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-md-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-md-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-md-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-md-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-md-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-md-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-md-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-md-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-md-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-md-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-md-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-md-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-md-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-md-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-md-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-md-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-md-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-md-auto {
+ margin-top: auto !important;
+ }
+
+ .me-md-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-md-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-md-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-md-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-md-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-md-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-md-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-md-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-md-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-md-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-md-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-md-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-md-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-md-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-md-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-md-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-md-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-md-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-md-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-md-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-md-auto {
+ margin-left: auto !important;
+ }
+
+ .p-md-0 {
+ padding: 0 !important;
+ }
+
+ .p-md-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-md-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-md-3 {
+ padding: 1rem !important;
+ }
+
+ .p-md-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-md-5 {
+ padding: 3rem !important;
+ }
+
+ .px-md-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-md-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-md-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-md-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-md-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-md-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-md-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-md-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-md-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-md-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-md-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-md-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-md-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-md-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-md-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-md-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-md-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-md-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-md-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-md-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-md-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-md-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-md-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-md-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-md-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-md-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-md-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-md-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-md-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-md-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-md-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-md-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-md-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-md-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-md-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-md-5 {
+ padding-left: 3rem !important;
+ }
+
+ .text-md-start {
+ text-align: left !important;
+ }
+
+ .text-md-end {
+ text-align: right !important;
+ }
+
+ .text-md-center {
+ text-align: center !important;
+ }
+}
+@media (min-width: 992px) {
+ .float-lg-start {
+ float: left !important;
+ }
+
+ .float-lg-end {
+ float: right !important;
+ }
+
+ .float-lg-none {
+ float: none !important;
+ }
+
+ .d-lg-inline {
+ display: inline !important;
+ }
+
+ .d-lg-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-lg-block {
+ display: block !important;
+ }
+
+ .d-lg-grid {
+ display: grid !important;
+ }
+
+ .d-lg-table {
+ display: table !important;
+ }
+
+ .d-lg-table-row {
+ display: table-row !important;
+ }
+
+ .d-lg-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-lg-flex {
+ display: flex !important;
+ }
+
+ .d-lg-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-lg-none {
+ display: none !important;
+ }
+
+ .flex-lg-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-lg-row {
+ flex-direction: row !important;
+ }
+
+ .flex-lg-column {
+ flex-direction: column !important;
+ }
+
+ .flex-lg-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-lg-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-lg-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-lg-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-lg-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-lg-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-lg-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-lg-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-lg-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .gap-lg-0 {
+ gap: 0 !important;
+ }
+
+ .gap-lg-1 {
+ gap: 0.25rem !important;
+ }
+
+ .gap-lg-2 {
+ gap: 0.5rem !important;
+ }
+
+ .gap-lg-3 {
+ gap: 1rem !important;
+ }
+
+ .gap-lg-4 {
+ gap: 1.5rem !important;
+ }
+
+ .gap-lg-5 {
+ gap: 3rem !important;
+ }
+
+ .justify-content-lg-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-lg-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-lg-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-lg-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-lg-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-lg-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-lg-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-lg-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-lg-center {
+ align-items: center !important;
+ }
+
+ .align-items-lg-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-lg-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-lg-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-lg-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-lg-center {
+ align-content: center !important;
+ }
+
+ .align-content-lg-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-lg-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-lg-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-lg-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-lg-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-lg-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-lg-center {
+ align-self: center !important;
+ }
+
+ .align-self-lg-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-lg-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-lg-first {
+ order: -1 !important;
+ }
+
+ .order-lg-0 {
+ order: 0 !important;
+ }
+
+ .order-lg-1 {
+ order: 1 !important;
+ }
+
+ .order-lg-2 {
+ order: 2 !important;
+ }
+
+ .order-lg-3 {
+ order: 3 !important;
+ }
+
+ .order-lg-4 {
+ order: 4 !important;
+ }
+
+ .order-lg-5 {
+ order: 5 !important;
+ }
+
+ .order-lg-last {
+ order: 6 !important;
+ }
+
+ .m-lg-0 {
+ margin: 0 !important;
+ }
+
+ .m-lg-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-lg-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-lg-3 {
+ margin: 1rem !important;
+ }
+
+ .m-lg-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-lg-5 {
+ margin: 3rem !important;
+ }
+
+ .m-lg-auto {
+ margin: auto !important;
+ }
+
+ .mx-lg-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-lg-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-lg-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-lg-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-lg-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-lg-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-lg-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-lg-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-lg-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-lg-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-lg-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-lg-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-lg-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-lg-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-lg-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-lg-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-lg-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-lg-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-lg-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-lg-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-lg-auto {
+ margin-top: auto !important;
+ }
+
+ .me-lg-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-lg-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-lg-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-lg-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-lg-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-lg-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-lg-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-lg-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-lg-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-lg-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-lg-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-lg-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-lg-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-lg-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-lg-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-lg-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-lg-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-lg-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-lg-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-lg-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-lg-auto {
+ margin-left: auto !important;
+ }
+
+ .p-lg-0 {
+ padding: 0 !important;
+ }
+
+ .p-lg-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-lg-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-lg-3 {
+ padding: 1rem !important;
+ }
+
+ .p-lg-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-lg-5 {
+ padding: 3rem !important;
+ }
+
+ .px-lg-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-lg-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-lg-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-lg-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-lg-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-lg-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-lg-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-lg-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-lg-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-lg-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-lg-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-lg-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-lg-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-lg-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-lg-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-lg-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-lg-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-lg-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-lg-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-lg-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-lg-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-lg-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-lg-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-lg-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-lg-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-lg-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-lg-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-lg-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-lg-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-lg-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-lg-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-lg-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-lg-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-lg-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-lg-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-lg-5 {
+ padding-left: 3rem !important;
+ }
+
+ .text-lg-start {
+ text-align: left !important;
+ }
+
+ .text-lg-end {
+ text-align: right !important;
+ }
+
+ .text-lg-center {
+ text-align: center !important;
+ }
+}
+@media (min-width: 1200px) {
+ .float-xl-start {
+ float: left !important;
+ }
+
+ .float-xl-end {
+ float: right !important;
+ }
+
+ .float-xl-none {
+ float: none !important;
+ }
+
+ .d-xl-inline {
+ display: inline !important;
+ }
+
+ .d-xl-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-xl-block {
+ display: block !important;
+ }
+
+ .d-xl-grid {
+ display: grid !important;
+ }
+
+ .d-xl-table {
+ display: table !important;
+ }
+
+ .d-xl-table-row {
+ display: table-row !important;
+ }
+
+ .d-xl-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-xl-flex {
+ display: flex !important;
+ }
+
+ .d-xl-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-xl-none {
+ display: none !important;
+ }
+
+ .flex-xl-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-xl-row {
+ flex-direction: row !important;
+ }
+
+ .flex-xl-column {
+ flex-direction: column !important;
+ }
+
+ .flex-xl-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-xl-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-xl-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-xl-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-xl-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-xl-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-xl-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-xl-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-xl-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .gap-xl-0 {
+ gap: 0 !important;
+ }
+
+ .gap-xl-1 {
+ gap: 0.25rem !important;
+ }
+
+ .gap-xl-2 {
+ gap: 0.5rem !important;
+ }
+
+ .gap-xl-3 {
+ gap: 1rem !important;
+ }
+
+ .gap-xl-4 {
+ gap: 1.5rem !important;
+ }
+
+ .gap-xl-5 {
+ gap: 3rem !important;
+ }
+
+ .justify-content-xl-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-xl-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-xl-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-xl-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-xl-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-xl-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-xl-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-xl-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-xl-center {
+ align-items: center !important;
+ }
+
+ .align-items-xl-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-xl-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-xl-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-xl-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-xl-center {
+ align-content: center !important;
+ }
+
+ .align-content-xl-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-xl-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-xl-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-xl-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-xl-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-xl-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-xl-center {
+ align-self: center !important;
+ }
+
+ .align-self-xl-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-xl-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-xl-first {
+ order: -1 !important;
+ }
+
+ .order-xl-0 {
+ order: 0 !important;
+ }
+
+ .order-xl-1 {
+ order: 1 !important;
+ }
+
+ .order-xl-2 {
+ order: 2 !important;
+ }
+
+ .order-xl-3 {
+ order: 3 !important;
+ }
+
+ .order-xl-4 {
+ order: 4 !important;
+ }
+
+ .order-xl-5 {
+ order: 5 !important;
+ }
+
+ .order-xl-last {
+ order: 6 !important;
+ }
+
+ .m-xl-0 {
+ margin: 0 !important;
+ }
+
+ .m-xl-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-xl-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-xl-3 {
+ margin: 1rem !important;
+ }
+
+ .m-xl-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-xl-5 {
+ margin: 3rem !important;
+ }
+
+ .m-xl-auto {
+ margin: auto !important;
+ }
+
+ .mx-xl-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-xl-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-xl-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-xl-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-xl-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-xl-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-xl-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-xl-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-xl-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-xl-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-xl-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-xl-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-xl-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-xl-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-xl-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-xl-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-xl-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-xl-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-xl-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-xl-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-xl-auto {
+ margin-top: auto !important;
+ }
+
+ .me-xl-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-xl-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-xl-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-xl-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-xl-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-xl-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-xl-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-xl-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-xl-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-xl-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-xl-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-xl-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-xl-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-xl-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-xl-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-xl-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-xl-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-xl-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-xl-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-xl-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-xl-auto {
+ margin-left: auto !important;
+ }
+
+ .p-xl-0 {
+ padding: 0 !important;
+ }
+
+ .p-xl-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-xl-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-xl-3 {
+ padding: 1rem !important;
+ }
+
+ .p-xl-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-xl-5 {
+ padding: 3rem !important;
+ }
+
+ .px-xl-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-xl-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-xl-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-xl-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-xl-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-xl-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-xl-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-xl-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-xl-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-xl-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-xl-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-xl-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-xl-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-xl-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-xl-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-xl-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-xl-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-xl-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-xl-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-xl-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-xl-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-xl-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-xl-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-xl-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-xl-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-xl-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-xl-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-xl-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-xl-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-xl-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-xl-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-xl-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-xl-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-xl-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-xl-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-xl-5 {
+ padding-left: 3rem !important;
+ }
+
+ .text-xl-start {
+ text-align: left !important;
+ }
+
+ .text-xl-end {
+ text-align: right !important;
+ }
+
+ .text-xl-center {
+ text-align: center !important;
+ }
+}
+@media (min-width: 1400px) {
+ .float-xxl-start {
+ float: left !important;
+ }
+
+ .float-xxl-end {
+ float: right !important;
+ }
+
+ .float-xxl-none {
+ float: none !important;
+ }
+
+ .d-xxl-inline {
+ display: inline !important;
+ }
+
+ .d-xxl-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-xxl-block {
+ display: block !important;
+ }
+
+ .d-xxl-grid {
+ display: grid !important;
+ }
+
+ .d-xxl-table {
+ display: table !important;
+ }
+
+ .d-xxl-table-row {
+ display: table-row !important;
+ }
+
+ .d-xxl-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-xxl-flex {
+ display: flex !important;
+ }
+
+ .d-xxl-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-xxl-none {
+ display: none !important;
+ }
+
+ .flex-xxl-fill {
+ flex: 1 1 auto !important;
+ }
+
+ .flex-xxl-row {
+ flex-direction: row !important;
+ }
+
+ .flex-xxl-column {
+ flex-direction: column !important;
+ }
+
+ .flex-xxl-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+
+ .flex-xxl-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+
+ .flex-xxl-grow-0 {
+ flex-grow: 0 !important;
+ }
+
+ .flex-xxl-grow-1 {
+ flex-grow: 1 !important;
+ }
+
+ .flex-xxl-shrink-0 {
+ flex-shrink: 0 !important;
+ }
+
+ .flex-xxl-shrink-1 {
+ flex-shrink: 1 !important;
+ }
+
+ .flex-xxl-wrap {
+ flex-wrap: wrap !important;
+ }
+
+ .flex-xxl-nowrap {
+ flex-wrap: nowrap !important;
+ }
+
+ .flex-xxl-wrap-reverse {
+ flex-wrap: wrap-reverse !important;
+ }
+
+ .gap-xxl-0 {
+ gap: 0 !important;
+ }
+
+ .gap-xxl-1 {
+ gap: 0.25rem !important;
+ }
+
+ .gap-xxl-2 {
+ gap: 0.5rem !important;
+ }
+
+ .gap-xxl-3 {
+ gap: 1rem !important;
+ }
+
+ .gap-xxl-4 {
+ gap: 1.5rem !important;
+ }
+
+ .gap-xxl-5 {
+ gap: 3rem !important;
+ }
+
+ .justify-content-xxl-start {
+ justify-content: flex-start !important;
+ }
+
+ .justify-content-xxl-end {
+ justify-content: flex-end !important;
+ }
+
+ .justify-content-xxl-center {
+ justify-content: center !important;
+ }
+
+ .justify-content-xxl-between {
+ justify-content: space-between !important;
+ }
+
+ .justify-content-xxl-around {
+ justify-content: space-around !important;
+ }
+
+ .justify-content-xxl-evenly {
+ justify-content: space-evenly !important;
+ }
+
+ .align-items-xxl-start {
+ align-items: flex-start !important;
+ }
+
+ .align-items-xxl-end {
+ align-items: flex-end !important;
+ }
+
+ .align-items-xxl-center {
+ align-items: center !important;
+ }
+
+ .align-items-xxl-baseline {
+ align-items: baseline !important;
+ }
+
+ .align-items-xxl-stretch {
+ align-items: stretch !important;
+ }
+
+ .align-content-xxl-start {
+ align-content: flex-start !important;
+ }
+
+ .align-content-xxl-end {
+ align-content: flex-end !important;
+ }
+
+ .align-content-xxl-center {
+ align-content: center !important;
+ }
+
+ .align-content-xxl-between {
+ align-content: space-between !important;
+ }
+
+ .align-content-xxl-around {
+ align-content: space-around !important;
+ }
+
+ .align-content-xxl-stretch {
+ align-content: stretch !important;
+ }
+
+ .align-self-xxl-auto {
+ align-self: auto !important;
+ }
+
+ .align-self-xxl-start {
+ align-self: flex-start !important;
+ }
+
+ .align-self-xxl-end {
+ align-self: flex-end !important;
+ }
+
+ .align-self-xxl-center {
+ align-self: center !important;
+ }
+
+ .align-self-xxl-baseline {
+ align-self: baseline !important;
+ }
+
+ .align-self-xxl-stretch {
+ align-self: stretch !important;
+ }
+
+ .order-xxl-first {
+ order: -1 !important;
+ }
+
+ .order-xxl-0 {
+ order: 0 !important;
+ }
+
+ .order-xxl-1 {
+ order: 1 !important;
+ }
+
+ .order-xxl-2 {
+ order: 2 !important;
+ }
+
+ .order-xxl-3 {
+ order: 3 !important;
+ }
+
+ .order-xxl-4 {
+ order: 4 !important;
+ }
+
+ .order-xxl-5 {
+ order: 5 !important;
+ }
+
+ .order-xxl-last {
+ order: 6 !important;
+ }
+
+ .m-xxl-0 {
+ margin: 0 !important;
+ }
+
+ .m-xxl-1 {
+ margin: 0.25rem !important;
+ }
+
+ .m-xxl-2 {
+ margin: 0.5rem !important;
+ }
+
+ .m-xxl-3 {
+ margin: 1rem !important;
+ }
+
+ .m-xxl-4 {
+ margin: 1.5rem !important;
+ }
+
+ .m-xxl-5 {
+ margin: 3rem !important;
+ }
+
+ .m-xxl-auto {
+ margin: auto !important;
+ }
+
+ .mx-xxl-0 {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+ }
+
+ .mx-xxl-1 {
+ margin-right: 0.25rem !important;
+ margin-left: 0.25rem !important;
+ }
+
+ .mx-xxl-2 {
+ margin-right: 0.5rem !important;
+ margin-left: 0.5rem !important;
+ }
+
+ .mx-xxl-3 {
+ margin-right: 1rem !important;
+ margin-left: 1rem !important;
+ }
+
+ .mx-xxl-4 {
+ margin-right: 1.5rem !important;
+ margin-left: 1.5rem !important;
+ }
+
+ .mx-xxl-5 {
+ margin-right: 3rem !important;
+ margin-left: 3rem !important;
+ }
+
+ .mx-xxl-auto {
+ margin-right: auto !important;
+ margin-left: auto !important;
+ }
+
+ .my-xxl-0 {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ .my-xxl-1 {
+ margin-top: 0.25rem !important;
+ margin-bottom: 0.25rem !important;
+ }
+
+ .my-xxl-2 {
+ margin-top: 0.5rem !important;
+ margin-bottom: 0.5rem !important;
+ }
+
+ .my-xxl-3 {
+ margin-top: 1rem !important;
+ margin-bottom: 1rem !important;
+ }
+
+ .my-xxl-4 {
+ margin-top: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ }
+
+ .my-xxl-5 {
+ margin-top: 3rem !important;
+ margin-bottom: 3rem !important;
+ }
+
+ .my-xxl-auto {
+ margin-top: auto !important;
+ margin-bottom: auto !important;
+ }
+
+ .mt-xxl-0 {
+ margin-top: 0 !important;
+ }
+
+ .mt-xxl-1 {
+ margin-top: 0.25rem !important;
+ }
+
+ .mt-xxl-2 {
+ margin-top: 0.5rem !important;
+ }
+
+ .mt-xxl-3 {
+ margin-top: 1rem !important;
+ }
+
+ .mt-xxl-4 {
+ margin-top: 1.5rem !important;
+ }
+
+ .mt-xxl-5 {
+ margin-top: 3rem !important;
+ }
+
+ .mt-xxl-auto {
+ margin-top: auto !important;
+ }
+
+ .me-xxl-0 {
+ margin-right: 0 !important;
+ }
+
+ .me-xxl-1 {
+ margin-right: 0.25rem !important;
+ }
+
+ .me-xxl-2 {
+ margin-right: 0.5rem !important;
+ }
+
+ .me-xxl-3 {
+ margin-right: 1rem !important;
+ }
+
+ .me-xxl-4 {
+ margin-right: 1.5rem !important;
+ }
+
+ .me-xxl-5 {
+ margin-right: 3rem !important;
+ }
+
+ .me-xxl-auto {
+ margin-right: auto !important;
+ }
+
+ .mb-xxl-0 {
+ margin-bottom: 0 !important;
+ }
+
+ .mb-xxl-1 {
+ margin-bottom: 0.25rem !important;
+ }
+
+ .mb-xxl-2 {
+ margin-bottom: 0.5rem !important;
+ }
+
+ .mb-xxl-3 {
+ margin-bottom: 1rem !important;
+ }
+
+ .mb-xxl-4 {
+ margin-bottom: 1.5rem !important;
+ }
+
+ .mb-xxl-5 {
+ margin-bottom: 3rem !important;
+ }
+
+ .mb-xxl-auto {
+ margin-bottom: auto !important;
+ }
+
+ .ms-xxl-0 {
+ margin-left: 0 !important;
+ }
+
+ .ms-xxl-1 {
+ margin-left: 0.25rem !important;
+ }
+
+ .ms-xxl-2 {
+ margin-left: 0.5rem !important;
+ }
+
+ .ms-xxl-3 {
+ margin-left: 1rem !important;
+ }
+
+ .ms-xxl-4 {
+ margin-left: 1.5rem !important;
+ }
+
+ .ms-xxl-5 {
+ margin-left: 3rem !important;
+ }
+
+ .ms-xxl-auto {
+ margin-left: auto !important;
+ }
+
+ .p-xxl-0 {
+ padding: 0 !important;
+ }
+
+ .p-xxl-1 {
+ padding: 0.25rem !important;
+ }
+
+ .p-xxl-2 {
+ padding: 0.5rem !important;
+ }
+
+ .p-xxl-3 {
+ padding: 1rem !important;
+ }
+
+ .p-xxl-4 {
+ padding: 1.5rem !important;
+ }
+
+ .p-xxl-5 {
+ padding: 3rem !important;
+ }
+
+ .px-xxl-0 {
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .px-xxl-1 {
+ padding-right: 0.25rem !important;
+ padding-left: 0.25rem !important;
+ }
+
+ .px-xxl-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 0.5rem !important;
+ }
+
+ .px-xxl-3 {
+ padding-right: 1rem !important;
+ padding-left: 1rem !important;
+ }
+
+ .px-xxl-4 {
+ padding-right: 1.5rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .px-xxl-5 {
+ padding-right: 3rem !important;
+ padding-left: 3rem !important;
+ }
+
+ .py-xxl-0 {
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+ }
+
+ .py-xxl-1 {
+ padding-top: 0.25rem !important;
+ padding-bottom: 0.25rem !important;
+ }
+
+ .py-xxl-2 {
+ padding-top: 0.5rem !important;
+ padding-bottom: 0.5rem !important;
+ }
+
+ .py-xxl-3 {
+ padding-top: 1rem !important;
+ padding-bottom: 1rem !important;
+ }
+
+ .py-xxl-4 {
+ padding-top: 1.5rem !important;
+ padding-bottom: 1.5rem !important;
+ }
+
+ .py-xxl-5 {
+ padding-top: 3rem !important;
+ padding-bottom: 3rem !important;
+ }
+
+ .pt-xxl-0 {
+ padding-top: 0 !important;
+ }
+
+ .pt-xxl-1 {
+ padding-top: 0.25rem !important;
+ }
+
+ .pt-xxl-2 {
+ padding-top: 0.5rem !important;
+ }
+
+ .pt-xxl-3 {
+ padding-top: 1rem !important;
+ }
+
+ .pt-xxl-4 {
+ padding-top: 1.5rem !important;
+ }
+
+ .pt-xxl-5 {
+ padding-top: 3rem !important;
+ }
+
+ .pe-xxl-0 {
+ padding-right: 0 !important;
+ }
+
+ .pe-xxl-1 {
+ padding-right: 0.25rem !important;
+ }
+
+ .pe-xxl-2 {
+ padding-right: 0.5rem !important;
+ }
+
+ .pe-xxl-3 {
+ padding-right: 1rem !important;
+ }
+
+ .pe-xxl-4 {
+ padding-right: 1.5rem !important;
+ }
+
+ .pe-xxl-5 {
+ padding-right: 3rem !important;
+ }
+
+ .pb-xxl-0 {
+ padding-bottom: 0 !important;
+ }
+
+ .pb-xxl-1 {
+ padding-bottom: 0.25rem !important;
+ }
+
+ .pb-xxl-2 {
+ padding-bottom: 0.5rem !important;
+ }
+
+ .pb-xxl-3 {
+ padding-bottom: 1rem !important;
+ }
+
+ .pb-xxl-4 {
+ padding-bottom: 1.5rem !important;
+ }
+
+ .pb-xxl-5 {
+ padding-bottom: 3rem !important;
+ }
+
+ .ps-xxl-0 {
+ padding-left: 0 !important;
+ }
+
+ .ps-xxl-1 {
+ padding-left: 0.25rem !important;
+ }
+
+ .ps-xxl-2 {
+ padding-left: 0.5rem !important;
+ }
+
+ .ps-xxl-3 {
+ padding-left: 1rem !important;
+ }
+
+ .ps-xxl-4 {
+ padding-left: 1.5rem !important;
+ }
+
+ .ps-xxl-5 {
+ padding-left: 3rem !important;
+ }
+
+ .text-xxl-start {
+ text-align: left !important;
+ }
+
+ .text-xxl-end {
+ text-align: right !important;
+ }
+
+ .text-xxl-center {
+ text-align: center !important;
+ }
+}
+@media (min-width: 1200px) {
+ .fs-1 {
+ font-size: 2.5rem !important;
+ }
+
+ .fs-2 {
+ font-size: 2rem !important;
+ }
+
+ .fs-3 {
+ font-size: 1.75rem !important;
+ }
+
+ .fs-4 {
+ font-size: 1.5rem !important;
+ }
+}
+@media print {
+ .d-print-inline {
+ display: inline !important;
+ }
+
+ .d-print-inline-block {
+ display: inline-block !important;
+ }
+
+ .d-print-block {
+ display: block !important;
+ }
+
+ .d-print-grid {
+ display: grid !important;
+ }
+
+ .d-print-table {
+ display: table !important;
+ }
+
+ .d-print-table-row {
+ display: table-row !important;
+ }
+
+ .d-print-table-cell {
+ display: table-cell !important;
+ }
+
+ .d-print-flex {
+ display: flex !important;
+ }
+
+ .d-print-inline-flex {
+ display: inline-flex !important;
+ }
+
+ .d-print-none {
+ display: none !important;
+ }
+}
+
+/*# sourceMappingURL=bootstrap.css.map */
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/foundation/LICENSE b/pkgs/csslib/third_party/foundation/LICENSE
new file mode 100644
index 0000000..cfa9e05
--- /dev/null
+++ b/pkgs/csslib/third_party/foundation/LICENSE
@@ -0,0 +1,22 @@
+Copyright © 2011-2020 ZURB, Inc.
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/pkgs/csslib/third_party/foundation/README.md b/pkgs/csslib/third_party/foundation/README.md
new file mode 100644
index 0000000..a79a2a8
--- /dev/null
+++ b/pkgs/csslib/third_party/foundation/README.md
@@ -0,0 +1,4 @@
+This folder contains sample css files from the open-source project
+https://github.com/foundation/foundation-sites.
+
+This code was included under the terms in the `LICENSE` file.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/foundation/foundation.css b/pkgs/csslib/third_party/foundation/foundation.css
new file mode 100644
index 0000000..eb68cfd
--- /dev/null
+++ b/pkgs/csslib/third_party/foundation/foundation.css
@@ -0,0 +1,5616 @@
+@charset "UTF-8";
+/**
+ * Foundation for Sites
+ * Version 6.7.2
+ * https://get.foundation
+ * Licensed under MIT Open Source
+ */
+@media print, screen and (min-width: 40em) {
+ .reveal, .reveal.tiny, .reveal.small, .reveal.large {
+ right: auto;
+ left: auto;
+ margin: 0 auto; } }
+
+/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */
+html {
+ line-height: 1.15;
+ -webkit-text-size-adjust: 100%; }
+
+body {
+ margin: 0; }
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0; }
+
+hr {
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+ overflow: visible; }
+
+pre {
+ font-family: monospace, monospace;
+ font-size: 1em; }
+
+a {
+ background-color: transparent; }
+
+abbr[title] {
+ border-bottom: none;
+ text-decoration: underline;
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted; }
+
+b,
+strong {
+ font-weight: bolder; }
+
+code,
+kbd,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em; }
+
+small {
+ font-size: 80%; }
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline; }
+
+sub {
+ bottom: -0.25em; }
+
+sup {
+ top: -0.5em; }
+
+img {
+ border-style: none; }
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit;
+ font-size: 100%;
+ line-height: 1.15;
+ margin: 0; }
+
+button,
+input {
+ overflow: visible; }
+
+button,
+select {
+ text-transform: none; }
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button; }
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0; }
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText; }
+
+fieldset {
+ padding: 0.35em 0.75em 0.625em; }
+
+legend {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ color: inherit;
+ display: table;
+ max-width: 100%;
+ padding: 0;
+ white-space: normal; }
+
+progress {
+ vertical-align: baseline; }
+
+textarea {
+ overflow: auto; }
+
+[type="checkbox"],
+[type="radio"] {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 0; }
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto; }
+
+[type="search"] {
+ -webkit-appearance: textfield;
+ outline-offset: -2px; }
+
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none; }
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button;
+ font: inherit; }
+
+details {
+ display: block; }
+
+summary {
+ display: list-item; }
+
+template {
+ display: none; }
+
+[hidden] {
+ display: none; }
+
+.foundation-mq {
+ font-family: "small=0em&medium=40em&large=64em&xlarge=75em&xxlarge=90em"; }
+
+html {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ font-size: 100%; }
+
+*,
+*::before,
+*::after {
+ -webkit-box-sizing: inherit;
+ box-sizing: inherit; }
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #fefefe;
+ font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+ font-weight: normal;
+ line-height: 1.5;
+ color: #0a0a0a;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale; }
+
+img {
+ display: inline-block;
+ vertical-align: middle;
+ max-width: 100%;
+ height: auto;
+ -ms-interpolation-mode: bicubic; }
+
+textarea {
+ height: auto;
+ min-height: 50px;
+ border-radius: 0; }
+
+select {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ border-radius: 0; }
+
+.map_canvas img,
+.map_canvas embed,
+.map_canvas object,
+.mqa-display img,
+.mqa-display embed,
+.mqa-display object {
+ max-width: none !important; }
+
+button {
+ padding: 0;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ border: 0;
+ border-radius: 0;
+ background: transparent;
+ line-height: 1;
+ cursor: auto; }
+ [data-whatinput='mouse'] button {
+ outline: 0; }
+
+pre {
+ overflow: auto; }
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; }
+
+.is-visible {
+ display: block !important; }
+
+.is-hidden {
+ display: none !important; }
+
+[type='text'], [type='password'], [type='date'], [type='datetime'], [type='datetime-local'], [type='month'], [type='week'], [type='email'], [type='number'], [type='search'], [type='tel'], [type='time'], [type='url'], [type='color'],
+textarea {
+ display: block;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ height: 2.4375rem;
+ margin: 0 0 1rem;
+ padding: 0.5rem;
+ border: 1px solid #cacaca;
+ border-radius: 0;
+ background-color: #fefefe;
+ -webkit-box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1);
+ box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1);
+ font-family: inherit;
+ font-size: 1rem;
+ font-weight: normal;
+ line-height: 1.5;
+ color: #0a0a0a;
+ -webkit-transition: border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ transition: border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ transition: box-shadow 0.5s, border-color 0.25s ease-in-out;
+ transition: box-shadow 0.5s, border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none; }
+ [type='text']:focus, [type='password']:focus, [type='date']:focus, [type='datetime']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='week']:focus, [type='email']:focus, [type='number']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='url']:focus, [type='color']:focus,
+ textarea:focus {
+ outline: none;
+ border: 1px solid #8a8a8a;
+ background-color: #fefefe;
+ -webkit-box-shadow: 0 0 5px #cacaca;
+ box-shadow: 0 0 5px #cacaca;
+ -webkit-transition: border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ transition: border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ transition: box-shadow 0.5s, border-color 0.25s ease-in-out;
+ transition: box-shadow 0.5s, border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s; }
+
+textarea {
+ max-width: 100%; }
+ textarea[rows] {
+ height: auto; }
+
+input:disabled, input[readonly],
+textarea:disabled,
+textarea[readonly] {
+ background-color: #e6e6e6;
+ cursor: not-allowed; }
+
+[type='submit'],
+[type='button'] {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ border-radius: 0; }
+
+input[type='search'] {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box; }
+
+::-webkit-input-placeholder {
+ color: #cacaca; }
+
+::-moz-placeholder {
+ color: #cacaca; }
+
+:-ms-input-placeholder {
+ color: #cacaca; }
+
+::-ms-input-placeholder {
+ color: #cacaca; }
+
+::placeholder {
+ color: #cacaca; }
+
+[type='file'],
+[type='checkbox'],
+[type='radio'] {
+ margin: 0 0 1rem; }
+
+[type='checkbox'] + label,
+[type='radio'] + label {
+ display: inline-block;
+ vertical-align: baseline;
+ margin-left: 0.5rem;
+ margin-right: 1rem;
+ margin-bottom: 0; }
+ [type='checkbox'] + label[for],
+ [type='radio'] + label[for] {
+ cursor: pointer; }
+
+label > [type='checkbox'],
+label > [type='radio'] {
+ margin-right: 0.5rem; }
+
+[type='file'] {
+ width: 100%; }
+
+label {
+ display: block;
+ margin: 0;
+ font-size: 0.875rem;
+ font-weight: normal;
+ line-height: 1.8;
+ color: #0a0a0a; }
+ label.middle {
+ margin: 0 0 1rem;
+ line-height: 1.5;
+ padding: 0.5625rem 0; }
+
+.help-text {
+ margin-top: -0.5rem;
+ font-size: 0.8125rem;
+ font-style: italic;
+ color: #0a0a0a; }
+
+.input-group {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ width: 100%;
+ margin-bottom: 1rem;
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch; }
+ .input-group > :first-child, .input-group > :first-child.input-group-button > * {
+ border-radius: 0 0 0 0; }
+ .input-group > :last-child, .input-group > :last-child.input-group-button > * {
+ border-radius: 0 0 0 0; }
+
+.input-group-label, .input-group-field, .input-group-button, .input-group-button a,
+.input-group-button input,
+.input-group-button button,
+.input-group-button label {
+ margin: 0;
+ white-space: nowrap; }
+
+.input-group-label {
+ padding: 0 1rem;
+ border: 1px solid #cacaca;
+ background: #e6e6e6;
+ color: #0a0a0a;
+ text-align: center;
+ white-space: nowrap;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ -webkit-box-align: center;
+ -webkit-align-items: center;
+ -ms-flex-align: center;
+ align-items: center; }
+ .input-group-label:first-child {
+ border-right: 0; }
+ .input-group-label:last-child {
+ border-left: 0; }
+
+.input-group-field {
+ border-radius: 0;
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px;
+ min-width: 0; }
+
+.input-group-button {
+ padding-top: 0;
+ padding-bottom: 0;
+ text-align: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+ .input-group-button a,
+ .input-group-button input,
+ .input-group-button button,
+ .input-group-button label {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ height: auto;
+ padding-top: 0;
+ padding-bottom: 0;
+ font-size: 1rem; }
+
+fieldset {
+ margin: 0;
+ padding: 0;
+ border: 0; }
+
+legend {
+ max-width: 100%;
+ margin-bottom: 0.5rem; }
+
+.fieldset {
+ margin: 1.125rem 0;
+ padding: 1.25rem;
+ border: 1px solid #cacaca; }
+ .fieldset legend {
+ margin: 0;
+ margin-left: -0.1875rem;
+ padding: 0 0.1875rem; }
+
+select {
+ height: 2.4375rem;
+ margin: 0 0 1rem;
+ padding: 0.5rem;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ border: 1px solid #cacaca;
+ border-radius: 0;
+ background-color: #fefefe;
+ font-family: inherit;
+ font-size: 1rem;
+ font-weight: normal;
+ line-height: 1.5;
+ color: #0a0a0a;
+ background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='32' height='24' viewBox='0 0 32 24'><polygon points='0,0 32,0 16,24' style='fill: rgb%28138, 138, 138%29'></polygon></svg>");
+ background-origin: content-box;
+ background-position: right -1rem center;
+ background-repeat: no-repeat;
+ background-size: 9px 6px;
+ padding-right: 1.5rem;
+ -webkit-transition: border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ transition: border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ transition: box-shadow 0.5s, border-color 0.25s ease-in-out;
+ transition: box-shadow 0.5s, border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s; }
+ @media screen and (min-width: 0\0) {
+ select {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIpJREFUeNrEkckNgDAMBBfRkEt0ObRBBdsGXUDgmQfK4XhH2m8czQAAy27R3tsw4Qfe2x8uOO6oYLb6GlOor3GF+swURAOmUJ+RwtEJs9WvTGEYxBXqI1MQAZhCfUQKRzDMVj+TwrAIV6jvSUEkYAr1LSkcyTBb/V+KYfX7xAeusq3sLDtGH3kEGACPWIflNZfhRQAAAABJRU5ErkJggg=="); } }
+ select:focus {
+ outline: none;
+ border: 1px solid #8a8a8a;
+ background-color: #fefefe;
+ -webkit-box-shadow: 0 0 5px #cacaca;
+ box-shadow: 0 0 5px #cacaca;
+ -webkit-transition: border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ transition: border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s;
+ transition: box-shadow 0.5s, border-color 0.25s ease-in-out;
+ transition: box-shadow 0.5s, border-color 0.25s ease-in-out, -webkit-box-shadow 0.5s; }
+ select:disabled {
+ background-color: #e6e6e6;
+ cursor: not-allowed; }
+ select::-ms-expand {
+ display: none; }
+ select[multiple] {
+ height: auto;
+ background-image: none; }
+ select:not([multiple]) {
+ padding-top: 0;
+ padding-bottom: 0; }
+
+.is-invalid-input:not(:focus) {
+ border-color: #cc4b37;
+ background-color: #f9ecea; }
+ .is-invalid-input:not(:focus)::-webkit-input-placeholder {
+ color: #cc4b37; }
+ .is-invalid-input:not(:focus)::-moz-placeholder {
+ color: #cc4b37; }
+ .is-invalid-input:not(:focus):-ms-input-placeholder {
+ color: #cc4b37; }
+ .is-invalid-input:not(:focus)::-ms-input-placeholder {
+ color: #cc4b37; }
+ .is-invalid-input:not(:focus)::placeholder {
+ color: #cc4b37; }
+
+.is-invalid-label {
+ color: #cc4b37; }
+
+.form-error {
+ display: none;
+ margin-top: -0.5rem;
+ margin-bottom: 1rem;
+ font-size: 0.75rem;
+ font-weight: bold;
+ color: #cc4b37; }
+ .form-error.is-visible {
+ display: block; }
+
+div,
+dl,
+dt,
+dd,
+ul,
+ol,
+li,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+pre,
+form,
+p,
+blockquote,
+th,
+td {
+ margin: 0;
+ padding: 0; }
+
+p {
+ margin-bottom: 1rem;
+ font-size: inherit;
+ line-height: 1.6;
+ text-rendering: optimizeLegibility; }
+
+em,
+i {
+ font-style: italic;
+ line-height: inherit; }
+
+strong,
+b {
+ font-weight: bold;
+ line-height: inherit; }
+
+small {
+ font-size: 80%;
+ line-height: inherit; }
+
+h1, .h1,
+h2, .h2,
+h3, .h3,
+h4, .h4,
+h5, .h5,
+h6, .h6 {
+ font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ color: inherit;
+ text-rendering: optimizeLegibility; }
+ h1 small, .h1 small,
+ h2 small, .h2 small,
+ h3 small, .h3 small,
+ h4 small, .h4 small,
+ h5 small, .h5 small,
+ h6 small, .h6 small {
+ line-height: 0;
+ color: #cacaca; }
+
+h1, .h1 {
+ font-size: 1.5rem;
+ line-height: 1.4;
+ margin-top: 0;
+ margin-bottom: 0.5rem; }
+
+h2, .h2 {
+ font-size: 1.25rem;
+ line-height: 1.4;
+ margin-top: 0;
+ margin-bottom: 0.5rem; }
+
+h3, .h3 {
+ font-size: 1.1875rem;
+ line-height: 1.4;
+ margin-top: 0;
+ margin-bottom: 0.5rem; }
+
+h4, .h4 {
+ font-size: 1.125rem;
+ line-height: 1.4;
+ margin-top: 0;
+ margin-bottom: 0.5rem; }
+
+h5, .h5 {
+ font-size: 1.0625rem;
+ line-height: 1.4;
+ margin-top: 0;
+ margin-bottom: 0.5rem; }
+
+h6, .h6 {
+ font-size: 1rem;
+ line-height: 1.4;
+ margin-top: 0;
+ margin-bottom: 0.5rem; }
+
+@media print, screen and (min-width: 40em) {
+ h1, .h1 {
+ font-size: 3rem; }
+ h2, .h2 {
+ font-size: 2.5rem; }
+ h3, .h3 {
+ font-size: 1.9375rem; }
+ h4, .h4 {
+ font-size: 1.5625rem; }
+ h5, .h5 {
+ font-size: 1.25rem; }
+ h6, .h6 {
+ font-size: 1rem; } }
+
+a {
+ line-height: inherit;
+ color: #1779ba;
+ text-decoration: none;
+ cursor: pointer; }
+ a:hover, a:focus {
+ color: #1468a0; }
+ a img {
+ border: 0; }
+
+hr {
+ clear: both;
+ max-width: 75rem;
+ height: 0;
+ margin: 1.25rem auto;
+ border-top: 0;
+ border-right: 0;
+ border-bottom: 1px solid #cacaca;
+ border-left: 0; }
+
+ul,
+ol,
+dl {
+ margin-bottom: 1rem;
+ list-style-position: outside;
+ line-height: 1.6; }
+
+li {
+ font-size: inherit; }
+
+ul {
+ margin-left: 1.25rem;
+ list-style-type: disc; }
+
+ol {
+ margin-left: 1.25rem; }
+
+ul ul, ol ul, ul ol, ol ol {
+ margin-left: 1.25rem;
+ margin-bottom: 0; }
+
+dl {
+ margin-bottom: 1rem; }
+ dl dt {
+ margin-bottom: 0.3rem;
+ font-weight: bold; }
+
+blockquote {
+ margin: 0 0 1rem;
+ padding: 0.5625rem 1.25rem 0 1.1875rem;
+ border-left: 1px solid #cacaca; }
+ blockquote, blockquote p {
+ line-height: 1.6;
+ color: #8a8a8a; }
+
+abbr, abbr[title] {
+ border-bottom: 1px dotted #0a0a0a;
+ cursor: help;
+ text-decoration: none; }
+
+figure {
+ margin: 0; }
+
+kbd {
+ margin: 0;
+ padding: 0.125rem 0.25rem 0;
+ background-color: #e6e6e6;
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+ color: #0a0a0a; }
+
+.subheader {
+ margin-top: 0.2rem;
+ margin-bottom: 0.5rem;
+ font-weight: normal;
+ line-height: 1.4;
+ color: #8a8a8a; }
+
+.lead {
+ font-size: 125%;
+ line-height: 1.6; }
+
+.stat {
+ font-size: 2.5rem;
+ line-height: 1; }
+ p + .stat {
+ margin-top: -1rem; }
+
+ul.no-bullet, ol.no-bullet {
+ margin-left: 0;
+ list-style: none; }
+
+.cite-block, cite {
+ display: block;
+ color: #8a8a8a;
+ font-size: 0.8125rem; }
+ .cite-block:before, cite:before {
+ content: "— "; }
+
+.code-inline, code {
+ border: 1px solid #cacaca;
+ background-color: #e6e6e6;
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+ font-weight: normal;
+ color: #0a0a0a;
+ display: inline;
+ max-width: 100%;
+ word-wrap: break-word;
+ padding: 0.125rem 0.3125rem 0.0625rem; }
+
+.code-block {
+ border: 1px solid #cacaca;
+ background-color: #e6e6e6;
+ font-family: Consolas, "Liberation Mono", Courier, monospace;
+ font-weight: normal;
+ color: #0a0a0a;
+ display: block;
+ overflow: auto;
+ white-space: pre;
+ padding: 1rem;
+ margin-bottom: 1.5rem; }
+
+.text-left {
+ text-align: left; }
+
+.text-right {
+ text-align: right; }
+
+.text-center {
+ text-align: center; }
+
+.text-justify {
+ text-align: justify; }
+
+@media print, screen and (min-width: 40em) {
+ .medium-text-left {
+ text-align: left; }
+ .medium-text-right {
+ text-align: right; }
+ .medium-text-center {
+ text-align: center; }
+ .medium-text-justify {
+ text-align: justify; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-text-left {
+ text-align: left; }
+ .large-text-right {
+ text-align: right; }
+ .large-text-center {
+ text-align: center; }
+ .large-text-justify {
+ text-align: justify; } }
+
+.show-for-print {
+ display: none !important; }
+
+@media print {
+ * {
+ background: transparent !important;
+ color: black !important;
+ -webkit-print-color-adjust: economy;
+ color-adjust: economy;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+ text-shadow: none !important; }
+ .show-for-print {
+ display: block !important; }
+ .hide-for-print {
+ display: none !important; }
+ table.show-for-print {
+ display: table !important; }
+ thead.show-for-print {
+ display: table-header-group !important; }
+ tbody.show-for-print {
+ display: table-row-group !important; }
+ tr.show-for-print {
+ display: table-row !important; }
+ td.show-for-print {
+ display: table-cell !important; }
+ th.show-for-print {
+ display: table-cell !important; }
+ a,
+ a:visited {
+ text-decoration: underline; }
+ a[href]:after {
+ content: " (" attr(href) ")"; }
+ .ir a:after,
+ a[href^='javascript:']:after,
+ a[href^='#']:after {
+ content: ''; }
+ abbr[title]:after {
+ content: " (" attr(title) ")"; }
+ pre,
+ blockquote {
+ border: 1px solid #8a8a8a;
+ page-break-inside: avoid; }
+ thead {
+ display: table-header-group; }
+ tr,
+ img {
+ page-break-inside: avoid; }
+ img {
+ max-width: 100% !important; }
+ @page {
+ margin: 0.5cm; }
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3; }
+ h2,
+ h3 {
+ page-break-after: avoid; }
+ .print-break-inside {
+ page-break-inside: auto; } }
+
+.grid-container {
+ padding-right: 0.625rem;
+ padding-left: 0.625rem;
+ max-width: 75rem;
+ margin-left: auto;
+ margin-right: auto; }
+ @media print, screen and (min-width: 40em) {
+ .grid-container {
+ padding-right: 0.9375rem;
+ padding-left: 0.9375rem; } }
+ .grid-container.fluid {
+ padding-right: 0.625rem;
+ padding-left: 0.625rem;
+ max-width: 100%;
+ margin-left: auto;
+ margin-right: auto; }
+ @media print, screen and (min-width: 40em) {
+ .grid-container.fluid {
+ padding-right: 0.9375rem;
+ padding-left: 0.9375rem; } }
+ .grid-container.full {
+ padding-right: 0;
+ padding-left: 0;
+ max-width: 100%;
+ margin-left: auto;
+ margin-right: auto; }
+
+.grid-x {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-flow: row wrap;
+ -ms-flex-flow: row wrap;
+ flex-flow: row wrap; }
+
+.cell {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ min-height: 0px;
+ min-width: 0px;
+ width: 100%; }
+ .cell.auto {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; }
+ .cell.shrink {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+
+.grid-x > .auto {
+ width: auto; }
+
+.grid-x > .shrink {
+ width: auto; }
+
+.grid-x > .small-shrink, .grid-x > .small-full, .grid-x > .small-1, .grid-x > .small-2, .grid-x > .small-3, .grid-x > .small-4, .grid-x > .small-5, .grid-x > .small-6, .grid-x > .small-7, .grid-x > .small-8, .grid-x > .small-9, .grid-x > .small-10, .grid-x > .small-11, .grid-x > .small-12 {
+ -webkit-flex-basis: auto;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto; }
+
+@media print, screen and (min-width: 40em) {
+ .grid-x > .medium-shrink, .grid-x > .medium-full, .grid-x > .medium-1, .grid-x > .medium-2, .grid-x > .medium-3, .grid-x > .medium-4, .grid-x > .medium-5, .grid-x > .medium-6, .grid-x > .medium-7, .grid-x > .medium-8, .grid-x > .medium-9, .grid-x > .medium-10, .grid-x > .medium-11, .grid-x > .medium-12 {
+ -webkit-flex-basis: auto;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto; } }
+
+@media print, screen and (min-width: 64em) {
+ .grid-x > .large-shrink, .grid-x > .large-full, .grid-x > .large-1, .grid-x > .large-2, .grid-x > .large-3, .grid-x > .large-4, .grid-x > .large-5, .grid-x > .large-6, .grid-x > .large-7, .grid-x > .large-8, .grid-x > .large-9, .grid-x > .large-10, .grid-x > .large-11, .grid-x > .large-12 {
+ -webkit-flex-basis: auto;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto; } }
+
+.grid-x > .small-1, .grid-x > .small-2, .grid-x > .small-3, .grid-x > .small-4, .grid-x > .small-5, .grid-x > .small-6, .grid-x > .small-7, .grid-x > .small-8, .grid-x > .small-9, .grid-x > .small-10, .grid-x > .small-11, .grid-x > .small-12 {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+
+.grid-x > .small-1 {
+ width: 8.33333%; }
+
+.grid-x > .small-2 {
+ width: 16.66667%; }
+
+.grid-x > .small-3 {
+ width: 25%; }
+
+.grid-x > .small-4 {
+ width: 33.33333%; }
+
+.grid-x > .small-5 {
+ width: 41.66667%; }
+
+.grid-x > .small-6 {
+ width: 50%; }
+
+.grid-x > .small-7 {
+ width: 58.33333%; }
+
+.grid-x > .small-8 {
+ width: 66.66667%; }
+
+.grid-x > .small-9 {
+ width: 75%; }
+
+.grid-x > .small-10 {
+ width: 83.33333%; }
+
+.grid-x > .small-11 {
+ width: 91.66667%; }
+
+.grid-x > .small-12 {
+ width: 100%; }
+
+@media print, screen and (min-width: 40em) {
+ .grid-x > .medium-auto {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px;
+ width: auto; }
+ .grid-x > .medium-shrink, .grid-x > .medium-1, .grid-x > .medium-2, .grid-x > .medium-3, .grid-x > .medium-4, .grid-x > .medium-5, .grid-x > .medium-6, .grid-x > .medium-7, .grid-x > .medium-8, .grid-x > .medium-9, .grid-x > .medium-10, .grid-x > .medium-11, .grid-x > .medium-12 {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+ .grid-x > .medium-shrink {
+ width: auto; }
+ .grid-x > .medium-1 {
+ width: 8.33333%; }
+ .grid-x > .medium-2 {
+ width: 16.66667%; }
+ .grid-x > .medium-3 {
+ width: 25%; }
+ .grid-x > .medium-4 {
+ width: 33.33333%; }
+ .grid-x > .medium-5 {
+ width: 41.66667%; }
+ .grid-x > .medium-6 {
+ width: 50%; }
+ .grid-x > .medium-7 {
+ width: 58.33333%; }
+ .grid-x > .medium-8 {
+ width: 66.66667%; }
+ .grid-x > .medium-9 {
+ width: 75%; }
+ .grid-x > .medium-10 {
+ width: 83.33333%; }
+ .grid-x > .medium-11 {
+ width: 91.66667%; }
+ .grid-x > .medium-12 {
+ width: 100%; } }
+
+@media print, screen and (min-width: 64em) {
+ .grid-x > .large-auto {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px;
+ width: auto; }
+ .grid-x > .large-shrink, .grid-x > .large-1, .grid-x > .large-2, .grid-x > .large-3, .grid-x > .large-4, .grid-x > .large-5, .grid-x > .large-6, .grid-x > .large-7, .grid-x > .large-8, .grid-x > .large-9, .grid-x > .large-10, .grid-x > .large-11, .grid-x > .large-12 {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+ .grid-x > .large-shrink {
+ width: auto; }
+ .grid-x > .large-1 {
+ width: 8.33333%; }
+ .grid-x > .large-2 {
+ width: 16.66667%; }
+ .grid-x > .large-3 {
+ width: 25%; }
+ .grid-x > .large-4 {
+ width: 33.33333%; }
+ .grid-x > .large-5 {
+ width: 41.66667%; }
+ .grid-x > .large-6 {
+ width: 50%; }
+ .grid-x > .large-7 {
+ width: 58.33333%; }
+ .grid-x > .large-8 {
+ width: 66.66667%; }
+ .grid-x > .large-9 {
+ width: 75%; }
+ .grid-x > .large-10 {
+ width: 83.33333%; }
+ .grid-x > .large-11 {
+ width: 91.66667%; }
+ .grid-x > .large-12 {
+ width: 100%; } }
+
+.grid-margin-x:not(.grid-x) > .cell {
+ width: auto; }
+
+.grid-margin-y:not(.grid-y) > .cell {
+ height: auto; }
+
+.grid-margin-x {
+ margin-left: -0.625rem;
+ margin-right: -0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-x {
+ margin-left: -0.9375rem;
+ margin-right: -0.9375rem; } }
+ .grid-margin-x > .cell {
+ width: calc(100% - 1.25rem);
+ margin-left: 0.625rem;
+ margin-right: 0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-x > .cell {
+ width: calc(100% - 1.875rem);
+ margin-left: 0.9375rem;
+ margin-right: 0.9375rem; } }
+ .grid-margin-x > .auto {
+ width: auto; }
+ .grid-margin-x > .shrink {
+ width: auto; }
+ .grid-margin-x > .small-1 {
+ width: calc(8.33333% - 1.25rem); }
+ .grid-margin-x > .small-2 {
+ width: calc(16.66667% - 1.25rem); }
+ .grid-margin-x > .small-3 {
+ width: calc(25% - 1.25rem); }
+ .grid-margin-x > .small-4 {
+ width: calc(33.33333% - 1.25rem); }
+ .grid-margin-x > .small-5 {
+ width: calc(41.66667% - 1.25rem); }
+ .grid-margin-x > .small-6 {
+ width: calc(50% - 1.25rem); }
+ .grid-margin-x > .small-7 {
+ width: calc(58.33333% - 1.25rem); }
+ .grid-margin-x > .small-8 {
+ width: calc(66.66667% - 1.25rem); }
+ .grid-margin-x > .small-9 {
+ width: calc(75% - 1.25rem); }
+ .grid-margin-x > .small-10 {
+ width: calc(83.33333% - 1.25rem); }
+ .grid-margin-x > .small-11 {
+ width: calc(91.66667% - 1.25rem); }
+ .grid-margin-x > .small-12 {
+ width: calc(100% - 1.25rem); }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-x > .auto {
+ width: auto; }
+ .grid-margin-x > .shrink {
+ width: auto; }
+ .grid-margin-x > .small-1 {
+ width: calc(8.33333% - 1.875rem); }
+ .grid-margin-x > .small-2 {
+ width: calc(16.66667% - 1.875rem); }
+ .grid-margin-x > .small-3 {
+ width: calc(25% - 1.875rem); }
+ .grid-margin-x > .small-4 {
+ width: calc(33.33333% - 1.875rem); }
+ .grid-margin-x > .small-5 {
+ width: calc(41.66667% - 1.875rem); }
+ .grid-margin-x > .small-6 {
+ width: calc(50% - 1.875rem); }
+ .grid-margin-x > .small-7 {
+ width: calc(58.33333% - 1.875rem); }
+ .grid-margin-x > .small-8 {
+ width: calc(66.66667% - 1.875rem); }
+ .grid-margin-x > .small-9 {
+ width: calc(75% - 1.875rem); }
+ .grid-margin-x > .small-10 {
+ width: calc(83.33333% - 1.875rem); }
+ .grid-margin-x > .small-11 {
+ width: calc(91.66667% - 1.875rem); }
+ .grid-margin-x > .small-12 {
+ width: calc(100% - 1.875rem); }
+ .grid-margin-x > .medium-auto {
+ width: auto; }
+ .grid-margin-x > .medium-shrink {
+ width: auto; }
+ .grid-margin-x > .medium-1 {
+ width: calc(8.33333% - 1.875rem); }
+ .grid-margin-x > .medium-2 {
+ width: calc(16.66667% - 1.875rem); }
+ .grid-margin-x > .medium-3 {
+ width: calc(25% - 1.875rem); }
+ .grid-margin-x > .medium-4 {
+ width: calc(33.33333% - 1.875rem); }
+ .grid-margin-x > .medium-5 {
+ width: calc(41.66667% - 1.875rem); }
+ .grid-margin-x > .medium-6 {
+ width: calc(50% - 1.875rem); }
+ .grid-margin-x > .medium-7 {
+ width: calc(58.33333% - 1.875rem); }
+ .grid-margin-x > .medium-8 {
+ width: calc(66.66667% - 1.875rem); }
+ .grid-margin-x > .medium-9 {
+ width: calc(75% - 1.875rem); }
+ .grid-margin-x > .medium-10 {
+ width: calc(83.33333% - 1.875rem); }
+ .grid-margin-x > .medium-11 {
+ width: calc(91.66667% - 1.875rem); }
+ .grid-margin-x > .medium-12 {
+ width: calc(100% - 1.875rem); } }
+ @media print, screen and (min-width: 64em) {
+ .grid-margin-x > .large-auto {
+ width: auto; }
+ .grid-margin-x > .large-shrink {
+ width: auto; }
+ .grid-margin-x > .large-1 {
+ width: calc(8.33333% - 1.875rem); }
+ .grid-margin-x > .large-2 {
+ width: calc(16.66667% - 1.875rem); }
+ .grid-margin-x > .large-3 {
+ width: calc(25% - 1.875rem); }
+ .grid-margin-x > .large-4 {
+ width: calc(33.33333% - 1.875rem); }
+ .grid-margin-x > .large-5 {
+ width: calc(41.66667% - 1.875rem); }
+ .grid-margin-x > .large-6 {
+ width: calc(50% - 1.875rem); }
+ .grid-margin-x > .large-7 {
+ width: calc(58.33333% - 1.875rem); }
+ .grid-margin-x > .large-8 {
+ width: calc(66.66667% - 1.875rem); }
+ .grid-margin-x > .large-9 {
+ width: calc(75% - 1.875rem); }
+ .grid-margin-x > .large-10 {
+ width: calc(83.33333% - 1.875rem); }
+ .grid-margin-x > .large-11 {
+ width: calc(91.66667% - 1.875rem); }
+ .grid-margin-x > .large-12 {
+ width: calc(100% - 1.875rem); } }
+
+.grid-padding-x .grid-padding-x {
+ margin-right: -0.625rem;
+ margin-left: -0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-padding-x .grid-padding-x {
+ margin-right: -0.9375rem;
+ margin-left: -0.9375rem; } }
+
+.grid-container:not(.full) > .grid-padding-x {
+ margin-right: -0.625rem;
+ margin-left: -0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-container:not(.full) > .grid-padding-x {
+ margin-right: -0.9375rem;
+ margin-left: -0.9375rem; } }
+
+.grid-padding-x > .cell {
+ padding-right: 0.625rem;
+ padding-left: 0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-padding-x > .cell {
+ padding-right: 0.9375rem;
+ padding-left: 0.9375rem; } }
+
+.small-up-1 > .cell {
+ width: 100%; }
+
+.small-up-2 > .cell {
+ width: 50%; }
+
+.small-up-3 > .cell {
+ width: 33.33333%; }
+
+.small-up-4 > .cell {
+ width: 25%; }
+
+.small-up-5 > .cell {
+ width: 20%; }
+
+.small-up-6 > .cell {
+ width: 16.66667%; }
+
+.small-up-7 > .cell {
+ width: 14.28571%; }
+
+.small-up-8 > .cell {
+ width: 12.5%; }
+
+@media print, screen and (min-width: 40em) {
+ .medium-up-1 > .cell {
+ width: 100%; }
+ .medium-up-2 > .cell {
+ width: 50%; }
+ .medium-up-3 > .cell {
+ width: 33.33333%; }
+ .medium-up-4 > .cell {
+ width: 25%; }
+ .medium-up-5 > .cell {
+ width: 20%; }
+ .medium-up-6 > .cell {
+ width: 16.66667%; }
+ .medium-up-7 > .cell {
+ width: 14.28571%; }
+ .medium-up-8 > .cell {
+ width: 12.5%; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-up-1 > .cell {
+ width: 100%; }
+ .large-up-2 > .cell {
+ width: 50%; }
+ .large-up-3 > .cell {
+ width: 33.33333%; }
+ .large-up-4 > .cell {
+ width: 25%; }
+ .large-up-5 > .cell {
+ width: 20%; }
+ .large-up-6 > .cell {
+ width: 16.66667%; }
+ .large-up-7 > .cell {
+ width: 14.28571%; }
+ .large-up-8 > .cell {
+ width: 12.5%; } }
+
+.grid-margin-x.small-up-1 > .cell {
+ width: calc(100% - 1.25rem); }
+
+.grid-margin-x.small-up-2 > .cell {
+ width: calc(50% - 1.25rem); }
+
+.grid-margin-x.small-up-3 > .cell {
+ width: calc(33.33333% - 1.25rem); }
+
+.grid-margin-x.small-up-4 > .cell {
+ width: calc(25% - 1.25rem); }
+
+.grid-margin-x.small-up-5 > .cell {
+ width: calc(20% - 1.25rem); }
+
+.grid-margin-x.small-up-6 > .cell {
+ width: calc(16.66667% - 1.25rem); }
+
+.grid-margin-x.small-up-7 > .cell {
+ width: calc(14.28571% - 1.25rem); }
+
+.grid-margin-x.small-up-8 > .cell {
+ width: calc(12.5% - 1.25rem); }
+
+@media print, screen and (min-width: 40em) {
+ .grid-margin-x.small-up-1 > .cell {
+ width: calc(100% - 1.875rem); }
+ .grid-margin-x.small-up-2 > .cell {
+ width: calc(50% - 1.875rem); }
+ .grid-margin-x.small-up-3 > .cell {
+ width: calc(33.33333% - 1.875rem); }
+ .grid-margin-x.small-up-4 > .cell {
+ width: calc(25% - 1.875rem); }
+ .grid-margin-x.small-up-5 > .cell {
+ width: calc(20% - 1.875rem); }
+ .grid-margin-x.small-up-6 > .cell {
+ width: calc(16.66667% - 1.875rem); }
+ .grid-margin-x.small-up-7 > .cell {
+ width: calc(14.28571% - 1.875rem); }
+ .grid-margin-x.small-up-8 > .cell {
+ width: calc(12.5% - 1.875rem); }
+ .grid-margin-x.medium-up-1 > .cell {
+ width: calc(100% - 1.875rem); }
+ .grid-margin-x.medium-up-2 > .cell {
+ width: calc(50% - 1.875rem); }
+ .grid-margin-x.medium-up-3 > .cell {
+ width: calc(33.33333% - 1.875rem); }
+ .grid-margin-x.medium-up-4 > .cell {
+ width: calc(25% - 1.875rem); }
+ .grid-margin-x.medium-up-5 > .cell {
+ width: calc(20% - 1.875rem); }
+ .grid-margin-x.medium-up-6 > .cell {
+ width: calc(16.66667% - 1.875rem); }
+ .grid-margin-x.medium-up-7 > .cell {
+ width: calc(14.28571% - 1.875rem); }
+ .grid-margin-x.medium-up-8 > .cell {
+ width: calc(12.5% - 1.875rem); } }
+
+@media print, screen and (min-width: 64em) {
+ .grid-margin-x.large-up-1 > .cell {
+ width: calc(100% - 1.875rem); }
+ .grid-margin-x.large-up-2 > .cell {
+ width: calc(50% - 1.875rem); }
+ .grid-margin-x.large-up-3 > .cell {
+ width: calc(33.33333% - 1.875rem); }
+ .grid-margin-x.large-up-4 > .cell {
+ width: calc(25% - 1.875rem); }
+ .grid-margin-x.large-up-5 > .cell {
+ width: calc(20% - 1.875rem); }
+ .grid-margin-x.large-up-6 > .cell {
+ width: calc(16.66667% - 1.875rem); }
+ .grid-margin-x.large-up-7 > .cell {
+ width: calc(14.28571% - 1.875rem); }
+ .grid-margin-x.large-up-8 > .cell {
+ width: calc(12.5% - 1.875rem); } }
+
+.small-margin-collapse {
+ margin-right: 0;
+ margin-left: 0; }
+ .small-margin-collapse > .cell {
+ margin-right: 0;
+ margin-left: 0; }
+ .small-margin-collapse > .small-1 {
+ width: 8.33333%; }
+ .small-margin-collapse > .small-2 {
+ width: 16.66667%; }
+ .small-margin-collapse > .small-3 {
+ width: 25%; }
+ .small-margin-collapse > .small-4 {
+ width: 33.33333%; }
+ .small-margin-collapse > .small-5 {
+ width: 41.66667%; }
+ .small-margin-collapse > .small-6 {
+ width: 50%; }
+ .small-margin-collapse > .small-7 {
+ width: 58.33333%; }
+ .small-margin-collapse > .small-8 {
+ width: 66.66667%; }
+ .small-margin-collapse > .small-9 {
+ width: 75%; }
+ .small-margin-collapse > .small-10 {
+ width: 83.33333%; }
+ .small-margin-collapse > .small-11 {
+ width: 91.66667%; }
+ .small-margin-collapse > .small-12 {
+ width: 100%; }
+ @media print, screen and (min-width: 40em) {
+ .small-margin-collapse > .medium-1 {
+ width: 8.33333%; }
+ .small-margin-collapse > .medium-2 {
+ width: 16.66667%; }
+ .small-margin-collapse > .medium-3 {
+ width: 25%; }
+ .small-margin-collapse > .medium-4 {
+ width: 33.33333%; }
+ .small-margin-collapse > .medium-5 {
+ width: 41.66667%; }
+ .small-margin-collapse > .medium-6 {
+ width: 50%; }
+ .small-margin-collapse > .medium-7 {
+ width: 58.33333%; }
+ .small-margin-collapse > .medium-8 {
+ width: 66.66667%; }
+ .small-margin-collapse > .medium-9 {
+ width: 75%; }
+ .small-margin-collapse > .medium-10 {
+ width: 83.33333%; }
+ .small-margin-collapse > .medium-11 {
+ width: 91.66667%; }
+ .small-margin-collapse > .medium-12 {
+ width: 100%; } }
+ @media print, screen and (min-width: 64em) {
+ .small-margin-collapse > .large-1 {
+ width: 8.33333%; }
+ .small-margin-collapse > .large-2 {
+ width: 16.66667%; }
+ .small-margin-collapse > .large-3 {
+ width: 25%; }
+ .small-margin-collapse > .large-4 {
+ width: 33.33333%; }
+ .small-margin-collapse > .large-5 {
+ width: 41.66667%; }
+ .small-margin-collapse > .large-6 {
+ width: 50%; }
+ .small-margin-collapse > .large-7 {
+ width: 58.33333%; }
+ .small-margin-collapse > .large-8 {
+ width: 66.66667%; }
+ .small-margin-collapse > .large-9 {
+ width: 75%; }
+ .small-margin-collapse > .large-10 {
+ width: 83.33333%; }
+ .small-margin-collapse > .large-11 {
+ width: 91.66667%; }
+ .small-margin-collapse > .large-12 {
+ width: 100%; } }
+
+.small-padding-collapse {
+ margin-right: 0;
+ margin-left: 0; }
+ .small-padding-collapse > .cell {
+ padding-right: 0;
+ padding-left: 0; }
+
+@media print, screen and (min-width: 40em) {
+ .medium-margin-collapse {
+ margin-right: 0;
+ margin-left: 0; }
+ .medium-margin-collapse > .cell {
+ margin-right: 0;
+ margin-left: 0; } }
+
+@media print, screen and (min-width: 40em) {
+ .medium-margin-collapse > .small-1 {
+ width: 8.33333%; }
+ .medium-margin-collapse > .small-2 {
+ width: 16.66667%; }
+ .medium-margin-collapse > .small-3 {
+ width: 25%; }
+ .medium-margin-collapse > .small-4 {
+ width: 33.33333%; }
+ .medium-margin-collapse > .small-5 {
+ width: 41.66667%; }
+ .medium-margin-collapse > .small-6 {
+ width: 50%; }
+ .medium-margin-collapse > .small-7 {
+ width: 58.33333%; }
+ .medium-margin-collapse > .small-8 {
+ width: 66.66667%; }
+ .medium-margin-collapse > .small-9 {
+ width: 75%; }
+ .medium-margin-collapse > .small-10 {
+ width: 83.33333%; }
+ .medium-margin-collapse > .small-11 {
+ width: 91.66667%; }
+ .medium-margin-collapse > .small-12 {
+ width: 100%; } }
+
+@media print, screen and (min-width: 40em) {
+ .medium-margin-collapse > .medium-1 {
+ width: 8.33333%; }
+ .medium-margin-collapse > .medium-2 {
+ width: 16.66667%; }
+ .medium-margin-collapse > .medium-3 {
+ width: 25%; }
+ .medium-margin-collapse > .medium-4 {
+ width: 33.33333%; }
+ .medium-margin-collapse > .medium-5 {
+ width: 41.66667%; }
+ .medium-margin-collapse > .medium-6 {
+ width: 50%; }
+ .medium-margin-collapse > .medium-7 {
+ width: 58.33333%; }
+ .medium-margin-collapse > .medium-8 {
+ width: 66.66667%; }
+ .medium-margin-collapse > .medium-9 {
+ width: 75%; }
+ .medium-margin-collapse > .medium-10 {
+ width: 83.33333%; }
+ .medium-margin-collapse > .medium-11 {
+ width: 91.66667%; }
+ .medium-margin-collapse > .medium-12 {
+ width: 100%; } }
+
+@media print, screen and (min-width: 64em) {
+ .medium-margin-collapse > .large-1 {
+ width: 8.33333%; }
+ .medium-margin-collapse > .large-2 {
+ width: 16.66667%; }
+ .medium-margin-collapse > .large-3 {
+ width: 25%; }
+ .medium-margin-collapse > .large-4 {
+ width: 33.33333%; }
+ .medium-margin-collapse > .large-5 {
+ width: 41.66667%; }
+ .medium-margin-collapse > .large-6 {
+ width: 50%; }
+ .medium-margin-collapse > .large-7 {
+ width: 58.33333%; }
+ .medium-margin-collapse > .large-8 {
+ width: 66.66667%; }
+ .medium-margin-collapse > .large-9 {
+ width: 75%; }
+ .medium-margin-collapse > .large-10 {
+ width: 83.33333%; }
+ .medium-margin-collapse > .large-11 {
+ width: 91.66667%; }
+ .medium-margin-collapse > .large-12 {
+ width: 100%; } }
+
+@media print, screen and (min-width: 40em) {
+ .medium-padding-collapse {
+ margin-right: 0;
+ margin-left: 0; }
+ .medium-padding-collapse > .cell {
+ padding-right: 0;
+ padding-left: 0; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-margin-collapse {
+ margin-right: 0;
+ margin-left: 0; }
+ .large-margin-collapse > .cell {
+ margin-right: 0;
+ margin-left: 0; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-margin-collapse > .small-1 {
+ width: 8.33333%; }
+ .large-margin-collapse > .small-2 {
+ width: 16.66667%; }
+ .large-margin-collapse > .small-3 {
+ width: 25%; }
+ .large-margin-collapse > .small-4 {
+ width: 33.33333%; }
+ .large-margin-collapse > .small-5 {
+ width: 41.66667%; }
+ .large-margin-collapse > .small-6 {
+ width: 50%; }
+ .large-margin-collapse > .small-7 {
+ width: 58.33333%; }
+ .large-margin-collapse > .small-8 {
+ width: 66.66667%; }
+ .large-margin-collapse > .small-9 {
+ width: 75%; }
+ .large-margin-collapse > .small-10 {
+ width: 83.33333%; }
+ .large-margin-collapse > .small-11 {
+ width: 91.66667%; }
+ .large-margin-collapse > .small-12 {
+ width: 100%; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-margin-collapse > .medium-1 {
+ width: 8.33333%; }
+ .large-margin-collapse > .medium-2 {
+ width: 16.66667%; }
+ .large-margin-collapse > .medium-3 {
+ width: 25%; }
+ .large-margin-collapse > .medium-4 {
+ width: 33.33333%; }
+ .large-margin-collapse > .medium-5 {
+ width: 41.66667%; }
+ .large-margin-collapse > .medium-6 {
+ width: 50%; }
+ .large-margin-collapse > .medium-7 {
+ width: 58.33333%; }
+ .large-margin-collapse > .medium-8 {
+ width: 66.66667%; }
+ .large-margin-collapse > .medium-9 {
+ width: 75%; }
+ .large-margin-collapse > .medium-10 {
+ width: 83.33333%; }
+ .large-margin-collapse > .medium-11 {
+ width: 91.66667%; }
+ .large-margin-collapse > .medium-12 {
+ width: 100%; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-margin-collapse > .large-1 {
+ width: 8.33333%; }
+ .large-margin-collapse > .large-2 {
+ width: 16.66667%; }
+ .large-margin-collapse > .large-3 {
+ width: 25%; }
+ .large-margin-collapse > .large-4 {
+ width: 33.33333%; }
+ .large-margin-collapse > .large-5 {
+ width: 41.66667%; }
+ .large-margin-collapse > .large-6 {
+ width: 50%; }
+ .large-margin-collapse > .large-7 {
+ width: 58.33333%; }
+ .large-margin-collapse > .large-8 {
+ width: 66.66667%; }
+ .large-margin-collapse > .large-9 {
+ width: 75%; }
+ .large-margin-collapse > .large-10 {
+ width: 83.33333%; }
+ .large-margin-collapse > .large-11 {
+ width: 91.66667%; }
+ .large-margin-collapse > .large-12 {
+ width: 100%; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-padding-collapse {
+ margin-right: 0;
+ margin-left: 0; }
+ .large-padding-collapse > .cell {
+ padding-right: 0;
+ padding-left: 0; } }
+
+.small-offset-0 {
+ margin-left: 0%; }
+
+.grid-margin-x > .small-offset-0 {
+ margin-left: calc(0% + 1.25rem / 2); }
+
+.small-offset-1 {
+ margin-left: 8.33333%; }
+
+.grid-margin-x > .small-offset-1 {
+ margin-left: calc(8.33333% + 1.25rem / 2); }
+
+.small-offset-2 {
+ margin-left: 16.66667%; }
+
+.grid-margin-x > .small-offset-2 {
+ margin-left: calc(16.66667% + 1.25rem / 2); }
+
+.small-offset-3 {
+ margin-left: 25%; }
+
+.grid-margin-x > .small-offset-3 {
+ margin-left: calc(25% + 1.25rem / 2); }
+
+.small-offset-4 {
+ margin-left: 33.33333%; }
+
+.grid-margin-x > .small-offset-4 {
+ margin-left: calc(33.33333% + 1.25rem / 2); }
+
+.small-offset-5 {
+ margin-left: 41.66667%; }
+
+.grid-margin-x > .small-offset-5 {
+ margin-left: calc(41.66667% + 1.25rem / 2); }
+
+.small-offset-6 {
+ margin-left: 50%; }
+
+.grid-margin-x > .small-offset-6 {
+ margin-left: calc(50% + 1.25rem / 2); }
+
+.small-offset-7 {
+ margin-left: 58.33333%; }
+
+.grid-margin-x > .small-offset-7 {
+ margin-left: calc(58.33333% + 1.25rem / 2); }
+
+.small-offset-8 {
+ margin-left: 66.66667%; }
+
+.grid-margin-x > .small-offset-8 {
+ margin-left: calc(66.66667% + 1.25rem / 2); }
+
+.small-offset-9 {
+ margin-left: 75%; }
+
+.grid-margin-x > .small-offset-9 {
+ margin-left: calc(75% + 1.25rem / 2); }
+
+.small-offset-10 {
+ margin-left: 83.33333%; }
+
+.grid-margin-x > .small-offset-10 {
+ margin-left: calc(83.33333% + 1.25rem / 2); }
+
+.small-offset-11 {
+ margin-left: 91.66667%; }
+
+.grid-margin-x > .small-offset-11 {
+ margin-left: calc(91.66667% + 1.25rem / 2); }
+
+@media print, screen and (min-width: 40em) {
+ .medium-offset-0 {
+ margin-left: 0%; }
+ .grid-margin-x > .medium-offset-0 {
+ margin-left: calc(0% + 1.875rem / 2); }
+ .medium-offset-1 {
+ margin-left: 8.33333%; }
+ .grid-margin-x > .medium-offset-1 {
+ margin-left: calc(8.33333% + 1.875rem / 2); }
+ .medium-offset-2 {
+ margin-left: 16.66667%; }
+ .grid-margin-x > .medium-offset-2 {
+ margin-left: calc(16.66667% + 1.875rem / 2); }
+ .medium-offset-3 {
+ margin-left: 25%; }
+ .grid-margin-x > .medium-offset-3 {
+ margin-left: calc(25% + 1.875rem / 2); }
+ .medium-offset-4 {
+ margin-left: 33.33333%; }
+ .grid-margin-x > .medium-offset-4 {
+ margin-left: calc(33.33333% + 1.875rem / 2); }
+ .medium-offset-5 {
+ margin-left: 41.66667%; }
+ .grid-margin-x > .medium-offset-5 {
+ margin-left: calc(41.66667% + 1.875rem / 2); }
+ .medium-offset-6 {
+ margin-left: 50%; }
+ .grid-margin-x > .medium-offset-6 {
+ margin-left: calc(50% + 1.875rem / 2); }
+ .medium-offset-7 {
+ margin-left: 58.33333%; }
+ .grid-margin-x > .medium-offset-7 {
+ margin-left: calc(58.33333% + 1.875rem / 2); }
+ .medium-offset-8 {
+ margin-left: 66.66667%; }
+ .grid-margin-x > .medium-offset-8 {
+ margin-left: calc(66.66667% + 1.875rem / 2); }
+ .medium-offset-9 {
+ margin-left: 75%; }
+ .grid-margin-x > .medium-offset-9 {
+ margin-left: calc(75% + 1.875rem / 2); }
+ .medium-offset-10 {
+ margin-left: 83.33333%; }
+ .grid-margin-x > .medium-offset-10 {
+ margin-left: calc(83.33333% + 1.875rem / 2); }
+ .medium-offset-11 {
+ margin-left: 91.66667%; }
+ .grid-margin-x > .medium-offset-11 {
+ margin-left: calc(91.66667% + 1.875rem / 2); } }
+
+@media print, screen and (min-width: 64em) {
+ .large-offset-0 {
+ margin-left: 0%; }
+ .grid-margin-x > .large-offset-0 {
+ margin-left: calc(0% + 1.875rem / 2); }
+ .large-offset-1 {
+ margin-left: 8.33333%; }
+ .grid-margin-x > .large-offset-1 {
+ margin-left: calc(8.33333% + 1.875rem / 2); }
+ .large-offset-2 {
+ margin-left: 16.66667%; }
+ .grid-margin-x > .large-offset-2 {
+ margin-left: calc(16.66667% + 1.875rem / 2); }
+ .large-offset-3 {
+ margin-left: 25%; }
+ .grid-margin-x > .large-offset-3 {
+ margin-left: calc(25% + 1.875rem / 2); }
+ .large-offset-4 {
+ margin-left: 33.33333%; }
+ .grid-margin-x > .large-offset-4 {
+ margin-left: calc(33.33333% + 1.875rem / 2); }
+ .large-offset-5 {
+ margin-left: 41.66667%; }
+ .grid-margin-x > .large-offset-5 {
+ margin-left: calc(41.66667% + 1.875rem / 2); }
+ .large-offset-6 {
+ margin-left: 50%; }
+ .grid-margin-x > .large-offset-6 {
+ margin-left: calc(50% + 1.875rem / 2); }
+ .large-offset-7 {
+ margin-left: 58.33333%; }
+ .grid-margin-x > .large-offset-7 {
+ margin-left: calc(58.33333% + 1.875rem / 2); }
+ .large-offset-8 {
+ margin-left: 66.66667%; }
+ .grid-margin-x > .large-offset-8 {
+ margin-left: calc(66.66667% + 1.875rem / 2); }
+ .large-offset-9 {
+ margin-left: 75%; }
+ .grid-margin-x > .large-offset-9 {
+ margin-left: calc(75% + 1.875rem / 2); }
+ .large-offset-10 {
+ margin-left: 83.33333%; }
+ .grid-margin-x > .large-offset-10 {
+ margin-left: calc(83.33333% + 1.875rem / 2); }
+ .large-offset-11 {
+ margin-left: 91.66667%; }
+ .grid-margin-x > .large-offset-11 {
+ margin-left: calc(91.66667% + 1.875rem / 2); } }
+
+.grid-y {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-flow: column nowrap;
+ -ms-flex-flow: column nowrap;
+ flex-flow: column nowrap; }
+ .grid-y > .cell {
+ height: auto;
+ max-height: none; }
+ .grid-y > .auto {
+ height: auto; }
+ .grid-y > .shrink {
+ height: auto; }
+ .grid-y > .small-shrink, .grid-y > .small-full, .grid-y > .small-1, .grid-y > .small-2, .grid-y > .small-3, .grid-y > .small-4, .grid-y > .small-5, .grid-y > .small-6, .grid-y > .small-7, .grid-y > .small-8, .grid-y > .small-9, .grid-y > .small-10, .grid-y > .small-11, .grid-y > .small-12 {
+ -webkit-flex-basis: auto;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto; }
+ @media print, screen and (min-width: 40em) {
+ .grid-y > .medium-shrink, .grid-y > .medium-full, .grid-y > .medium-1, .grid-y > .medium-2, .grid-y > .medium-3, .grid-y > .medium-4, .grid-y > .medium-5, .grid-y > .medium-6, .grid-y > .medium-7, .grid-y > .medium-8, .grid-y > .medium-9, .grid-y > .medium-10, .grid-y > .medium-11, .grid-y > .medium-12 {
+ -webkit-flex-basis: auto;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto; } }
+ @media print, screen and (min-width: 64em) {
+ .grid-y > .large-shrink, .grid-y > .large-full, .grid-y > .large-1, .grid-y > .large-2, .grid-y > .large-3, .grid-y > .large-4, .grid-y > .large-5, .grid-y > .large-6, .grid-y > .large-7, .grid-y > .large-8, .grid-y > .large-9, .grid-y > .large-10, .grid-y > .large-11, .grid-y > .large-12 {
+ -webkit-flex-basis: auto;
+ -ms-flex-preferred-size: auto;
+ flex-basis: auto; } }
+ .grid-y > .small-1, .grid-y > .small-2, .grid-y > .small-3, .grid-y > .small-4, .grid-y > .small-5, .grid-y > .small-6, .grid-y > .small-7, .grid-y > .small-8, .grid-y > .small-9, .grid-y > .small-10, .grid-y > .small-11, .grid-y > .small-12 {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+ .grid-y > .small-1 {
+ height: 8.33333%; }
+ .grid-y > .small-2 {
+ height: 16.66667%; }
+ .grid-y > .small-3 {
+ height: 25%; }
+ .grid-y > .small-4 {
+ height: 33.33333%; }
+ .grid-y > .small-5 {
+ height: 41.66667%; }
+ .grid-y > .small-6 {
+ height: 50%; }
+ .grid-y > .small-7 {
+ height: 58.33333%; }
+ .grid-y > .small-8 {
+ height: 66.66667%; }
+ .grid-y > .small-9 {
+ height: 75%; }
+ .grid-y > .small-10 {
+ height: 83.33333%; }
+ .grid-y > .small-11 {
+ height: 91.66667%; }
+ .grid-y > .small-12 {
+ height: 100%; }
+ @media print, screen and (min-width: 40em) {
+ .grid-y > .medium-auto {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px;
+ height: auto; }
+ .grid-y > .medium-shrink, .grid-y > .medium-1, .grid-y > .medium-2, .grid-y > .medium-3, .grid-y > .medium-4, .grid-y > .medium-5, .grid-y > .medium-6, .grid-y > .medium-7, .grid-y > .medium-8, .grid-y > .medium-9, .grid-y > .medium-10, .grid-y > .medium-11, .grid-y > .medium-12 {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+ .grid-y > .medium-shrink {
+ height: auto; }
+ .grid-y > .medium-1 {
+ height: 8.33333%; }
+ .grid-y > .medium-2 {
+ height: 16.66667%; }
+ .grid-y > .medium-3 {
+ height: 25%; }
+ .grid-y > .medium-4 {
+ height: 33.33333%; }
+ .grid-y > .medium-5 {
+ height: 41.66667%; }
+ .grid-y > .medium-6 {
+ height: 50%; }
+ .grid-y > .medium-7 {
+ height: 58.33333%; }
+ .grid-y > .medium-8 {
+ height: 66.66667%; }
+ .grid-y > .medium-9 {
+ height: 75%; }
+ .grid-y > .medium-10 {
+ height: 83.33333%; }
+ .grid-y > .medium-11 {
+ height: 91.66667%; }
+ .grid-y > .medium-12 {
+ height: 100%; } }
+ @media print, screen and (min-width: 64em) {
+ .grid-y > .large-auto {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px;
+ height: auto; }
+ .grid-y > .large-shrink, .grid-y > .large-1, .grid-y > .large-2, .grid-y > .large-3, .grid-y > .large-4, .grid-y > .large-5, .grid-y > .large-6, .grid-y > .large-7, .grid-y > .large-8, .grid-y > .large-9, .grid-y > .large-10, .grid-y > .large-11, .grid-y > .large-12 {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+ .grid-y > .large-shrink {
+ height: auto; }
+ .grid-y > .large-1 {
+ height: 8.33333%; }
+ .grid-y > .large-2 {
+ height: 16.66667%; }
+ .grid-y > .large-3 {
+ height: 25%; }
+ .grid-y > .large-4 {
+ height: 33.33333%; }
+ .grid-y > .large-5 {
+ height: 41.66667%; }
+ .grid-y > .large-6 {
+ height: 50%; }
+ .grid-y > .large-7 {
+ height: 58.33333%; }
+ .grid-y > .large-8 {
+ height: 66.66667%; }
+ .grid-y > .large-9 {
+ height: 75%; }
+ .grid-y > .large-10 {
+ height: 83.33333%; }
+ .grid-y > .large-11 {
+ height: 91.66667%; }
+ .grid-y > .large-12 {
+ height: 100%; } }
+
+.grid-padding-y .grid-padding-y {
+ margin-top: -0.625rem;
+ margin-bottom: -0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-padding-y .grid-padding-y {
+ margin-top: -0.9375rem;
+ margin-bottom: -0.9375rem; } }
+
+.grid-padding-y > .cell {
+ padding-top: 0.625rem;
+ padding-bottom: 0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-padding-y > .cell {
+ padding-top: 0.9375rem;
+ padding-bottom: 0.9375rem; } }
+
+.grid-margin-y {
+ margin-top: -0.625rem;
+ margin-bottom: -0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-y {
+ margin-top: -0.9375rem;
+ margin-bottom: -0.9375rem; } }
+ .grid-margin-y > .cell {
+ height: calc(100% - 1.25rem);
+ margin-top: 0.625rem;
+ margin-bottom: 0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-y > .cell {
+ height: calc(100% - 1.875rem);
+ margin-top: 0.9375rem;
+ margin-bottom: 0.9375rem; } }
+ .grid-margin-y > .auto {
+ height: auto; }
+ .grid-margin-y > .shrink {
+ height: auto; }
+ .grid-margin-y > .small-1 {
+ height: calc(8.33333% - 1.25rem); }
+ .grid-margin-y > .small-2 {
+ height: calc(16.66667% - 1.25rem); }
+ .grid-margin-y > .small-3 {
+ height: calc(25% - 1.25rem); }
+ .grid-margin-y > .small-4 {
+ height: calc(33.33333% - 1.25rem); }
+ .grid-margin-y > .small-5 {
+ height: calc(41.66667% - 1.25rem); }
+ .grid-margin-y > .small-6 {
+ height: calc(50% - 1.25rem); }
+ .grid-margin-y > .small-7 {
+ height: calc(58.33333% - 1.25rem); }
+ .grid-margin-y > .small-8 {
+ height: calc(66.66667% - 1.25rem); }
+ .grid-margin-y > .small-9 {
+ height: calc(75% - 1.25rem); }
+ .grid-margin-y > .small-10 {
+ height: calc(83.33333% - 1.25rem); }
+ .grid-margin-y > .small-11 {
+ height: calc(91.66667% - 1.25rem); }
+ .grid-margin-y > .small-12 {
+ height: calc(100% - 1.25rem); }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-y > .auto {
+ height: auto; }
+ .grid-margin-y > .shrink {
+ height: auto; }
+ .grid-margin-y > .small-1 {
+ height: calc(8.33333% - 1.875rem); }
+ .grid-margin-y > .small-2 {
+ height: calc(16.66667% - 1.875rem); }
+ .grid-margin-y > .small-3 {
+ height: calc(25% - 1.875rem); }
+ .grid-margin-y > .small-4 {
+ height: calc(33.33333% - 1.875rem); }
+ .grid-margin-y > .small-5 {
+ height: calc(41.66667% - 1.875rem); }
+ .grid-margin-y > .small-6 {
+ height: calc(50% - 1.875rem); }
+ .grid-margin-y > .small-7 {
+ height: calc(58.33333% - 1.875rem); }
+ .grid-margin-y > .small-8 {
+ height: calc(66.66667% - 1.875rem); }
+ .grid-margin-y > .small-9 {
+ height: calc(75% - 1.875rem); }
+ .grid-margin-y > .small-10 {
+ height: calc(83.33333% - 1.875rem); }
+ .grid-margin-y > .small-11 {
+ height: calc(91.66667% - 1.875rem); }
+ .grid-margin-y > .small-12 {
+ height: calc(100% - 1.875rem); }
+ .grid-margin-y > .medium-auto {
+ height: auto; }
+ .grid-margin-y > .medium-shrink {
+ height: auto; }
+ .grid-margin-y > .medium-1 {
+ height: calc(8.33333% - 1.875rem); }
+ .grid-margin-y > .medium-2 {
+ height: calc(16.66667% - 1.875rem); }
+ .grid-margin-y > .medium-3 {
+ height: calc(25% - 1.875rem); }
+ .grid-margin-y > .medium-4 {
+ height: calc(33.33333% - 1.875rem); }
+ .grid-margin-y > .medium-5 {
+ height: calc(41.66667% - 1.875rem); }
+ .grid-margin-y > .medium-6 {
+ height: calc(50% - 1.875rem); }
+ .grid-margin-y > .medium-7 {
+ height: calc(58.33333% - 1.875rem); }
+ .grid-margin-y > .medium-8 {
+ height: calc(66.66667% - 1.875rem); }
+ .grid-margin-y > .medium-9 {
+ height: calc(75% - 1.875rem); }
+ .grid-margin-y > .medium-10 {
+ height: calc(83.33333% - 1.875rem); }
+ .grid-margin-y > .medium-11 {
+ height: calc(91.66667% - 1.875rem); }
+ .grid-margin-y > .medium-12 {
+ height: calc(100% - 1.875rem); } }
+ @media print, screen and (min-width: 64em) {
+ .grid-margin-y > .large-auto {
+ height: auto; }
+ .grid-margin-y > .large-shrink {
+ height: auto; }
+ .grid-margin-y > .large-1 {
+ height: calc(8.33333% - 1.875rem); }
+ .grid-margin-y > .large-2 {
+ height: calc(16.66667% - 1.875rem); }
+ .grid-margin-y > .large-3 {
+ height: calc(25% - 1.875rem); }
+ .grid-margin-y > .large-4 {
+ height: calc(33.33333% - 1.875rem); }
+ .grid-margin-y > .large-5 {
+ height: calc(41.66667% - 1.875rem); }
+ .grid-margin-y > .large-6 {
+ height: calc(50% - 1.875rem); }
+ .grid-margin-y > .large-7 {
+ height: calc(58.33333% - 1.875rem); }
+ .grid-margin-y > .large-8 {
+ height: calc(66.66667% - 1.875rem); }
+ .grid-margin-y > .large-9 {
+ height: calc(75% - 1.875rem); }
+ .grid-margin-y > .large-10 {
+ height: calc(83.33333% - 1.875rem); }
+ .grid-margin-y > .large-11 {
+ height: calc(91.66667% - 1.875rem); }
+ .grid-margin-y > .large-12 {
+ height: calc(100% - 1.875rem); } }
+
+.grid-frame {
+ overflow: hidden;
+ position: relative;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ width: 100vw; }
+
+.cell .grid-frame {
+ width: 100%; }
+
+.cell-block {
+ overflow-x: auto;
+ max-width: 100%;
+ -webkit-overflow-scrolling: touch;
+ -ms-overflow-style: -ms-autohiding-scrollbar; }
+
+.cell-block-y {
+ overflow-y: auto;
+ max-height: 100%;
+ min-height: 100%;
+ -webkit-overflow-scrolling: touch;
+ -ms-overflow-style: -ms-autohiding-scrollbar; }
+
+.cell-block-container {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ max-height: 100%; }
+ .cell-block-container > .grid-x {
+ max-height: 100%;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap; }
+
+@media print, screen and (min-width: 40em) {
+ .medium-grid-frame {
+ overflow: hidden;
+ position: relative;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ width: 100vw; }
+ .cell .medium-grid-frame {
+ width: 100%; }
+ .medium-cell-block {
+ overflow-x: auto;
+ max-width: 100%;
+ -webkit-overflow-scrolling: touch;
+ -ms-overflow-style: -ms-autohiding-scrollbar; }
+ .medium-cell-block-container {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ max-height: 100%; }
+ .medium-cell-block-container > .grid-x {
+ max-height: 100%;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap; }
+ .medium-cell-block-y {
+ overflow-y: auto;
+ max-height: 100%;
+ min-height: 100%;
+ -webkit-overflow-scrolling: touch;
+ -ms-overflow-style: -ms-autohiding-scrollbar; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-grid-frame {
+ overflow: hidden;
+ position: relative;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ width: 100vw; }
+ .cell .large-grid-frame {
+ width: 100%; }
+ .large-cell-block {
+ overflow-x: auto;
+ max-width: 100%;
+ -webkit-overflow-scrolling: touch;
+ -ms-overflow-style: -ms-autohiding-scrollbar; }
+ .large-cell-block-container {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ max-height: 100%; }
+ .large-cell-block-container > .grid-x {
+ max-height: 100%;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap; }
+ .large-cell-block-y {
+ overflow-y: auto;
+ max-height: 100%;
+ min-height: 100%;
+ -webkit-overflow-scrolling: touch;
+ -ms-overflow-style: -ms-autohiding-scrollbar; } }
+
+.grid-y.grid-frame {
+ width: auto;
+ overflow: hidden;
+ position: relative;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ height: 100vh; }
+
+@media print, screen and (min-width: 40em) {
+ .grid-y.medium-grid-frame {
+ width: auto;
+ overflow: hidden;
+ position: relative;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ height: 100vh; } }
+
+@media print, screen and (min-width: 64em) {
+ .grid-y.large-grid-frame {
+ width: auto;
+ overflow: hidden;
+ position: relative;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ height: 100vh; } }
+
+.cell .grid-y.grid-frame {
+ height: 100%; }
+
+@media print, screen and (min-width: 40em) {
+ .cell .grid-y.medium-grid-frame {
+ height: 100%; } }
+
+@media print, screen and (min-width: 64em) {
+ .cell .grid-y.large-grid-frame {
+ height: 100%; } }
+
+.grid-margin-y {
+ margin-top: -0.625rem;
+ margin-bottom: -0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-y {
+ margin-top: -0.9375rem;
+ margin-bottom: -0.9375rem; } }
+ .grid-margin-y > .cell {
+ height: calc(100% - 1.25rem);
+ margin-top: 0.625rem;
+ margin-bottom: 0.625rem; }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-y > .cell {
+ height: calc(100% - 1.875rem);
+ margin-top: 0.9375rem;
+ margin-bottom: 0.9375rem; } }
+ .grid-margin-y > .auto {
+ height: auto; }
+ .grid-margin-y > .shrink {
+ height: auto; }
+ .grid-margin-y > .small-1 {
+ height: calc(8.33333% - 1.25rem); }
+ .grid-margin-y > .small-2 {
+ height: calc(16.66667% - 1.25rem); }
+ .grid-margin-y > .small-3 {
+ height: calc(25% - 1.25rem); }
+ .grid-margin-y > .small-4 {
+ height: calc(33.33333% - 1.25rem); }
+ .grid-margin-y > .small-5 {
+ height: calc(41.66667% - 1.25rem); }
+ .grid-margin-y > .small-6 {
+ height: calc(50% - 1.25rem); }
+ .grid-margin-y > .small-7 {
+ height: calc(58.33333% - 1.25rem); }
+ .grid-margin-y > .small-8 {
+ height: calc(66.66667% - 1.25rem); }
+ .grid-margin-y > .small-9 {
+ height: calc(75% - 1.25rem); }
+ .grid-margin-y > .small-10 {
+ height: calc(83.33333% - 1.25rem); }
+ .grid-margin-y > .small-11 {
+ height: calc(91.66667% - 1.25rem); }
+ .grid-margin-y > .small-12 {
+ height: calc(100% - 1.25rem); }
+ @media print, screen and (min-width: 40em) {
+ .grid-margin-y > .auto {
+ height: auto; }
+ .grid-margin-y > .shrink {
+ height: auto; }
+ .grid-margin-y > .small-1 {
+ height: calc(8.33333% - 1.875rem); }
+ .grid-margin-y > .small-2 {
+ height: calc(16.66667% - 1.875rem); }
+ .grid-margin-y > .small-3 {
+ height: calc(25% - 1.875rem); }
+ .grid-margin-y > .small-4 {
+ height: calc(33.33333% - 1.875rem); }
+ .grid-margin-y > .small-5 {
+ height: calc(41.66667% - 1.875rem); }
+ .grid-margin-y > .small-6 {
+ height: calc(50% - 1.875rem); }
+ .grid-margin-y > .small-7 {
+ height: calc(58.33333% - 1.875rem); }
+ .grid-margin-y > .small-8 {
+ height: calc(66.66667% - 1.875rem); }
+ .grid-margin-y > .small-9 {
+ height: calc(75% - 1.875rem); }
+ .grid-margin-y > .small-10 {
+ height: calc(83.33333% - 1.875rem); }
+ .grid-margin-y > .small-11 {
+ height: calc(91.66667% - 1.875rem); }
+ .grid-margin-y > .small-12 {
+ height: calc(100% - 1.875rem); }
+ .grid-margin-y > .medium-auto {
+ height: auto; }
+ .grid-margin-y > .medium-shrink {
+ height: auto; }
+ .grid-margin-y > .medium-1 {
+ height: calc(8.33333% - 1.875rem); }
+ .grid-margin-y > .medium-2 {
+ height: calc(16.66667% - 1.875rem); }
+ .grid-margin-y > .medium-3 {
+ height: calc(25% - 1.875rem); }
+ .grid-margin-y > .medium-4 {
+ height: calc(33.33333% - 1.875rem); }
+ .grid-margin-y > .medium-5 {
+ height: calc(41.66667% - 1.875rem); }
+ .grid-margin-y > .medium-6 {
+ height: calc(50% - 1.875rem); }
+ .grid-margin-y > .medium-7 {
+ height: calc(58.33333% - 1.875rem); }
+ .grid-margin-y > .medium-8 {
+ height: calc(66.66667% - 1.875rem); }
+ .grid-margin-y > .medium-9 {
+ height: calc(75% - 1.875rem); }
+ .grid-margin-y > .medium-10 {
+ height: calc(83.33333% - 1.875rem); }
+ .grid-margin-y > .medium-11 {
+ height: calc(91.66667% - 1.875rem); }
+ .grid-margin-y > .medium-12 {
+ height: calc(100% - 1.875rem); } }
+ @media print, screen and (min-width: 64em) {
+ .grid-margin-y > .large-auto {
+ height: auto; }
+ .grid-margin-y > .large-shrink {
+ height: auto; }
+ .grid-margin-y > .large-1 {
+ height: calc(8.33333% - 1.875rem); }
+ .grid-margin-y > .large-2 {
+ height: calc(16.66667% - 1.875rem); }
+ .grid-margin-y > .large-3 {
+ height: calc(25% - 1.875rem); }
+ .grid-margin-y > .large-4 {
+ height: calc(33.33333% - 1.875rem); }
+ .grid-margin-y > .large-5 {
+ height: calc(41.66667% - 1.875rem); }
+ .grid-margin-y > .large-6 {
+ height: calc(50% - 1.875rem); }
+ .grid-margin-y > .large-7 {
+ height: calc(58.33333% - 1.875rem); }
+ .grid-margin-y > .large-8 {
+ height: calc(66.66667% - 1.875rem); }
+ .grid-margin-y > .large-9 {
+ height: calc(75% - 1.875rem); }
+ .grid-margin-y > .large-10 {
+ height: calc(83.33333% - 1.875rem); }
+ .grid-margin-y > .large-11 {
+ height: calc(91.66667% - 1.875rem); }
+ .grid-margin-y > .large-12 {
+ height: calc(100% - 1.875rem); } }
+
+.grid-frame.grid-margin-y {
+ height: calc(100vh + 1.25rem); }
+ @media print, screen and (min-width: 40em) {
+ .grid-frame.grid-margin-y {
+ height: calc(100vh + 1.875rem); } }
+ @media print, screen and (min-width: 64em) {
+ .grid-frame.grid-margin-y {
+ height: calc(100vh + 1.875rem); } }
+
+@media print, screen and (min-width: 40em) {
+ .grid-margin-y.medium-grid-frame {
+ height: calc(100vh + 1.875rem); } }
+
+@media print, screen and (min-width: 64em) {
+ .grid-margin-y.large-grid-frame {
+ height: calc(100vh + 1.875rem); } }
+
+.button {
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0 0 1rem 0;
+ padding: 0.85em 1em;
+ border: 1px solid transparent;
+ border-radius: 0;
+ -webkit-transition: background-color 0.25s ease-out, color 0.25s ease-out;
+ transition: background-color 0.25s ease-out, color 0.25s ease-out;
+ font-family: inherit;
+ font-size: 0.9rem;
+ -webkit-appearance: none;
+ line-height: 1;
+ text-align: center;
+ cursor: pointer; }
+ [data-whatinput='mouse'] .button {
+ outline: 0; }
+ .button.tiny {
+ font-size: 0.6rem; }
+ .button.small {
+ font-size: 0.75rem; }
+ .button.large {
+ font-size: 1.25rem; }
+ .button.expanded {
+ display: block;
+ width: 100%;
+ margin-right: 0;
+ margin-left: 0; }
+ .button, .button.disabled, .button[disabled], .button.disabled:hover, .button[disabled]:hover, .button.disabled:focus, .button[disabled]:focus {
+ background-color: #1779ba;
+ color: #fefefe; }
+ .button:hover, .button:focus {
+ background-color: #14679e;
+ color: #fefefe; }
+ .button.primary, .button.primary.disabled, .button.primary[disabled], .button.primary.disabled:hover, .button.primary[disabled]:hover, .button.primary.disabled:focus, .button.primary[disabled]:focus {
+ background-color: #1779ba;
+ color: #fefefe; }
+ .button.primary:hover, .button.primary:focus {
+ background-color: #126195;
+ color: #fefefe; }
+ .button.secondary, .button.secondary.disabled, .button.secondary[disabled], .button.secondary.disabled:hover, .button.secondary[disabled]:hover, .button.secondary.disabled:focus, .button.secondary[disabled]:focus {
+ background-color: #767676;
+ color: #fefefe; }
+ .button.secondary:hover, .button.secondary:focus {
+ background-color: #5e5e5e;
+ color: #fefefe; }
+ .button.success, .button.success.disabled, .button.success[disabled], .button.success.disabled:hover, .button.success[disabled]:hover, .button.success.disabled:focus, .button.success[disabled]:focus {
+ background-color: #3adb76;
+ color: #0a0a0a; }
+ .button.success:hover, .button.success:focus {
+ background-color: #22bb5b;
+ color: #0a0a0a; }
+ .button.warning, .button.warning.disabled, .button.warning[disabled], .button.warning.disabled:hover, .button.warning[disabled]:hover, .button.warning.disabled:focus, .button.warning[disabled]:focus {
+ background-color: #ffae00;
+ color: #0a0a0a; }
+ .button.warning:hover, .button.warning:focus {
+ background-color: #cc8b00;
+ color: #0a0a0a; }
+ .button.alert, .button.alert.disabled, .button.alert[disabled], .button.alert.disabled:hover, .button.alert[disabled]:hover, .button.alert.disabled:focus, .button.alert[disabled]:focus {
+ background-color: #cc4b37;
+ color: #fefefe; }
+ .button.alert:hover, .button.alert:focus {
+ background-color: #a53b2a;
+ color: #fefefe; }
+ .button.hollow, .button.hollow:hover, .button.hollow:focus, .button.hollow.disabled, .button.hollow.disabled:hover, .button.hollow.disabled:focus, .button.hollow[disabled], .button.hollow[disabled]:hover, .button.hollow[disabled]:focus {
+ background-color: transparent; }
+ .button.hollow, .button.hollow.disabled, .button.hollow[disabled], .button.hollow.disabled:hover, .button.hollow[disabled]:hover, .button.hollow.disabled:focus, .button.hollow[disabled]:focus {
+ border: 1px solid #1779ba;
+ color: #1779ba; }
+ .button.hollow:hover, .button.hollow:focus {
+ border-color: #0c3d5d;
+ color: #0c3d5d; }
+ .button.hollow.primary, .button.hollow.primary.disabled, .button.hollow.primary[disabled], .button.hollow.primary.disabled:hover, .button.hollow.primary[disabled]:hover, .button.hollow.primary.disabled:focus, .button.hollow.primary[disabled]:focus {
+ border: 1px solid #1779ba;
+ color: #1779ba; }
+ .button.hollow.primary:hover, .button.hollow.primary:focus {
+ border-color: #0c3d5d;
+ color: #0c3d5d; }
+ .button.hollow.secondary, .button.hollow.secondary.disabled, .button.hollow.secondary[disabled], .button.hollow.secondary.disabled:hover, .button.hollow.secondary[disabled]:hover, .button.hollow.secondary.disabled:focus, .button.hollow.secondary[disabled]:focus {
+ border: 1px solid #767676;
+ color: #767676; }
+ .button.hollow.secondary:hover, .button.hollow.secondary:focus {
+ border-color: #3b3b3b;
+ color: #3b3b3b; }
+ .button.hollow.success, .button.hollow.success.disabled, .button.hollow.success[disabled], .button.hollow.success.disabled:hover, .button.hollow.success[disabled]:hover, .button.hollow.success.disabled:focus, .button.hollow.success[disabled]:focus {
+ border: 1px solid #3adb76;
+ color: #3adb76; }
+ .button.hollow.success:hover, .button.hollow.success:focus {
+ border-color: #157539;
+ color: #157539; }
+ .button.hollow.warning, .button.hollow.warning.disabled, .button.hollow.warning[disabled], .button.hollow.warning.disabled:hover, .button.hollow.warning[disabled]:hover, .button.hollow.warning.disabled:focus, .button.hollow.warning[disabled]:focus {
+ border: 1px solid #ffae00;
+ color: #ffae00; }
+ .button.hollow.warning:hover, .button.hollow.warning:focus {
+ border-color: #805700;
+ color: #805700; }
+ .button.hollow.alert, .button.hollow.alert.disabled, .button.hollow.alert[disabled], .button.hollow.alert.disabled:hover, .button.hollow.alert[disabled]:hover, .button.hollow.alert.disabled:focus, .button.hollow.alert[disabled]:focus {
+ border: 1px solid #cc4b37;
+ color: #cc4b37; }
+ .button.hollow.alert:hover, .button.hollow.alert:focus {
+ border-color: #67251a;
+ color: #67251a; }
+ .button.clear, .button.clear:hover, .button.clear:focus, .button.clear.disabled, .button.clear.disabled:hover, .button.clear.disabled:focus, .button.clear[disabled], .button.clear[disabled]:hover, .button.clear[disabled]:focus {
+ border-color: transparent;
+ background-color: transparent; }
+ .button.clear, .button.clear.disabled, .button.clear[disabled], .button.clear.disabled:hover, .button.clear[disabled]:hover, .button.clear.disabled:focus, .button.clear[disabled]:focus {
+ color: #1779ba; }
+ .button.clear:hover, .button.clear:focus {
+ color: #0c3d5d; }
+ .button.clear.primary, .button.clear.primary.disabled, .button.clear.primary[disabled], .button.clear.primary.disabled:hover, .button.clear.primary[disabled]:hover, .button.clear.primary.disabled:focus, .button.clear.primary[disabled]:focus {
+ color: #1779ba; }
+ .button.clear.primary:hover, .button.clear.primary:focus {
+ color: #0c3d5d; }
+ .button.clear.secondary, .button.clear.secondary.disabled, .button.clear.secondary[disabled], .button.clear.secondary.disabled:hover, .button.clear.secondary[disabled]:hover, .button.clear.secondary.disabled:focus, .button.clear.secondary[disabled]:focus {
+ color: #767676; }
+ .button.clear.secondary:hover, .button.clear.secondary:focus {
+ color: #3b3b3b; }
+ .button.clear.success, .button.clear.success.disabled, .button.clear.success[disabled], .button.clear.success.disabled:hover, .button.clear.success[disabled]:hover, .button.clear.success.disabled:focus, .button.clear.success[disabled]:focus {
+ color: #3adb76; }
+ .button.clear.success:hover, .button.clear.success:focus {
+ color: #157539; }
+ .button.clear.warning, .button.clear.warning.disabled, .button.clear.warning[disabled], .button.clear.warning.disabled:hover, .button.clear.warning[disabled]:hover, .button.clear.warning.disabled:focus, .button.clear.warning[disabled]:focus {
+ color: #ffae00; }
+ .button.clear.warning:hover, .button.clear.warning:focus {
+ color: #805700; }
+ .button.clear.alert, .button.clear.alert.disabled, .button.clear.alert[disabled], .button.clear.alert.disabled:hover, .button.clear.alert[disabled]:hover, .button.clear.alert.disabled:focus, .button.clear.alert[disabled]:focus {
+ color: #cc4b37; }
+ .button.clear.alert:hover, .button.clear.alert:focus {
+ color: #67251a; }
+ .button.disabled, .button[disabled] {
+ opacity: 0.25;
+ cursor: not-allowed; }
+ .button.dropdown::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 0.4em;
+ content: '';
+ border-bottom-width: 0;
+ border-color: #fefefe transparent transparent;
+ position: relative;
+ top: 0.4em;
+ display: inline-block;
+ float: right;
+ margin-left: 1em; }
+ .button.dropdown.hollow::after, .button.dropdown.clear::after {
+ border-top-color: #1779ba; }
+ .button.dropdown.hollow.primary::after, .button.dropdown.clear.primary::after {
+ border-top-color: #1779ba; }
+ .button.dropdown.hollow.secondary::after, .button.dropdown.clear.secondary::after {
+ border-top-color: #767676; }
+ .button.dropdown.hollow.success::after, .button.dropdown.clear.success::after {
+ border-top-color: #3adb76; }
+ .button.dropdown.hollow.warning::after, .button.dropdown.clear.warning::after {
+ border-top-color: #ffae00; }
+ .button.dropdown.hollow.alert::after, .button.dropdown.clear.alert::after {
+ border-top-color: #cc4b37; }
+ .button.arrow-only::after {
+ top: -0.1em;
+ float: none;
+ margin-left: 0; }
+
+a.button:hover, a.button:focus {
+ text-decoration: none; }
+
+.button-group {
+ margin-bottom: 1rem;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ -webkit-box-flex: 1;
+ -webkit-flex-grow: 1;
+ -ms-flex-positive: 1;
+ flex-grow: 1; }
+ .button-group::before, .button-group::after {
+ display: table;
+ content: ' ';
+ -webkit-flex-basis: 0;
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -webkit-box-ordinal-group: 2;
+ -webkit-order: 1;
+ -ms-flex-order: 1;
+ order: 1; }
+ .button-group::after {
+ clear: both; }
+ .button-group::before, .button-group::after {
+ display: none; }
+ .button-group .button {
+ margin: 0;
+ margin-right: 1px;
+ margin-bottom: 1px;
+ font-size: 0.9rem;
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+ .button-group .button:last-child {
+ margin-right: 0; }
+ .button-group.tiny .button {
+ font-size: 0.6rem; }
+ .button-group.small .button {
+ font-size: 0.75rem; }
+ .button-group.large .button {
+ font-size: 1.25rem; }
+ .button-group.expanded .button {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; }
+ .button-group.primary .button, .button-group.primary .button.disabled, .button-group.primary .button[disabled], .button-group.primary .button.disabled:hover, .button-group.primary .button[disabled]:hover, .button-group.primary .button.disabled:focus, .button-group.primary .button[disabled]:focus {
+ background-color: #1779ba;
+ color: #fefefe; }
+ .button-group.primary .button:hover, .button-group.primary .button:focus {
+ background-color: #126195;
+ color: #fefefe; }
+ .button-group.secondary .button, .button-group.secondary .button.disabled, .button-group.secondary .button[disabled], .button-group.secondary .button.disabled:hover, .button-group.secondary .button[disabled]:hover, .button-group.secondary .button.disabled:focus, .button-group.secondary .button[disabled]:focus {
+ background-color: #767676;
+ color: #fefefe; }
+ .button-group.secondary .button:hover, .button-group.secondary .button:focus {
+ background-color: #5e5e5e;
+ color: #fefefe; }
+ .button-group.success .button, .button-group.success .button.disabled, .button-group.success .button[disabled], .button-group.success .button.disabled:hover, .button-group.success .button[disabled]:hover, .button-group.success .button.disabled:focus, .button-group.success .button[disabled]:focus {
+ background-color: #3adb76;
+ color: #0a0a0a; }
+ .button-group.success .button:hover, .button-group.success .button:focus {
+ background-color: #22bb5b;
+ color: #0a0a0a; }
+ .button-group.warning .button, .button-group.warning .button.disabled, .button-group.warning .button[disabled], .button-group.warning .button.disabled:hover, .button-group.warning .button[disabled]:hover, .button-group.warning .button.disabled:focus, .button-group.warning .button[disabled]:focus {
+ background-color: #ffae00;
+ color: #0a0a0a; }
+ .button-group.warning .button:hover, .button-group.warning .button:focus {
+ background-color: #cc8b00;
+ color: #0a0a0a; }
+ .button-group.alert .button, .button-group.alert .button.disabled, .button-group.alert .button[disabled], .button-group.alert .button.disabled:hover, .button-group.alert .button[disabled]:hover, .button-group.alert .button.disabled:focus, .button-group.alert .button[disabled]:focus {
+ background-color: #cc4b37;
+ color: #fefefe; }
+ .button-group.alert .button:hover, .button-group.alert .button:focus {
+ background-color: #a53b2a;
+ color: #fefefe; }
+ .button-group.hollow .button, .button-group.hollow .button:hover, .button-group.hollow .button:focus, .button-group.hollow .button.disabled, .button-group.hollow .button.disabled:hover, .button-group.hollow .button.disabled:focus, .button-group.hollow .button[disabled], .button-group.hollow .button[disabled]:hover, .button-group.hollow .button[disabled]:focus {
+ background-color: transparent; }
+ .button-group.hollow .button, .button-group.hollow .button.disabled, .button-group.hollow .button[disabled], .button-group.hollow .button.disabled:hover, .button-group.hollow .button[disabled]:hover, .button-group.hollow .button.disabled:focus, .button-group.hollow .button[disabled]:focus {
+ border: 1px solid #1779ba;
+ color: #1779ba; }
+ .button-group.hollow .button:hover, .button-group.hollow .button:focus {
+ border-color: #0c3d5d;
+ color: #0c3d5d; }
+ .button-group.hollow.primary .button, .button-group.hollow.primary .button.disabled, .button-group.hollow.primary .button[disabled], .button-group.hollow.primary .button.disabled:hover, .button-group.hollow.primary .button[disabled]:hover, .button-group.hollow.primary .button.disabled:focus, .button-group.hollow.primary .button[disabled]:focus, .button-group.hollow .button.primary, .button-group.hollow .button.primary.disabled, .button-group.hollow .button.primary[disabled], .button-group.hollow .button.primary.disabled:hover, .button-group.hollow .button.primary[disabled]:hover, .button-group.hollow .button.primary.disabled:focus, .button-group.hollow .button.primary[disabled]:focus {
+ border: 1px solid #1779ba;
+ color: #1779ba; }
+ .button-group.hollow.primary .button:hover, .button-group.hollow.primary .button:focus, .button-group.hollow .button.primary:hover, .button-group.hollow .button.primary:focus {
+ border-color: #0c3d5d;
+ color: #0c3d5d; }
+ .button-group.hollow.secondary .button, .button-group.hollow.secondary .button.disabled, .button-group.hollow.secondary .button[disabled], .button-group.hollow.secondary .button.disabled:hover, .button-group.hollow.secondary .button[disabled]:hover, .button-group.hollow.secondary .button.disabled:focus, .button-group.hollow.secondary .button[disabled]:focus, .button-group.hollow .button.secondary, .button-group.hollow .button.secondary.disabled, .button-group.hollow .button.secondary[disabled], .button-group.hollow .button.secondary.disabled:hover, .button-group.hollow .button.secondary[disabled]:hover, .button-group.hollow .button.secondary.disabled:focus, .button-group.hollow .button.secondary[disabled]:focus {
+ border: 1px solid #767676;
+ color: #767676; }
+ .button-group.hollow.secondary .button:hover, .button-group.hollow.secondary .button:focus, .button-group.hollow .button.secondary:hover, .button-group.hollow .button.secondary:focus {
+ border-color: #3b3b3b;
+ color: #3b3b3b; }
+ .button-group.hollow.success .button, .button-group.hollow.success .button.disabled, .button-group.hollow.success .button[disabled], .button-group.hollow.success .button.disabled:hover, .button-group.hollow.success .button[disabled]:hover, .button-group.hollow.success .button.disabled:focus, .button-group.hollow.success .button[disabled]:focus, .button-group.hollow .button.success, .button-group.hollow .button.success.disabled, .button-group.hollow .button.success[disabled], .button-group.hollow .button.success.disabled:hover, .button-group.hollow .button.success[disabled]:hover, .button-group.hollow .button.success.disabled:focus, .button-group.hollow .button.success[disabled]:focus {
+ border: 1px solid #3adb76;
+ color: #3adb76; }
+ .button-group.hollow.success .button:hover, .button-group.hollow.success .button:focus, .button-group.hollow .button.success:hover, .button-group.hollow .button.success:focus {
+ border-color: #157539;
+ color: #157539; }
+ .button-group.hollow.warning .button, .button-group.hollow.warning .button.disabled, .button-group.hollow.warning .button[disabled], .button-group.hollow.warning .button.disabled:hover, .button-group.hollow.warning .button[disabled]:hover, .button-group.hollow.warning .button.disabled:focus, .button-group.hollow.warning .button[disabled]:focus, .button-group.hollow .button.warning, .button-group.hollow .button.warning.disabled, .button-group.hollow .button.warning[disabled], .button-group.hollow .button.warning.disabled:hover, .button-group.hollow .button.warning[disabled]:hover, .button-group.hollow .button.warning.disabled:focus, .button-group.hollow .button.warning[disabled]:focus {
+ border: 1px solid #ffae00;
+ color: #ffae00; }
+ .button-group.hollow.warning .button:hover, .button-group.hollow.warning .button:focus, .button-group.hollow .button.warning:hover, .button-group.hollow .button.warning:focus {
+ border-color: #805700;
+ color: #805700; }
+ .button-group.hollow.alert .button, .button-group.hollow.alert .button.disabled, .button-group.hollow.alert .button[disabled], .button-group.hollow.alert .button.disabled:hover, .button-group.hollow.alert .button[disabled]:hover, .button-group.hollow.alert .button.disabled:focus, .button-group.hollow.alert .button[disabled]:focus, .button-group.hollow .button.alert, .button-group.hollow .button.alert.disabled, .button-group.hollow .button.alert[disabled], .button-group.hollow .button.alert.disabled:hover, .button-group.hollow .button.alert[disabled]:hover, .button-group.hollow .button.alert.disabled:focus, .button-group.hollow .button.alert[disabled]:focus {
+ border: 1px solid #cc4b37;
+ color: #cc4b37; }
+ .button-group.hollow.alert .button:hover, .button-group.hollow.alert .button:focus, .button-group.hollow .button.alert:hover, .button-group.hollow .button.alert:focus {
+ border-color: #67251a;
+ color: #67251a; }
+ .button-group.clear .button, .button-group.clear .button:hover, .button-group.clear .button:focus, .button-group.clear .button.disabled, .button-group.clear .button.disabled:hover, .button-group.clear .button.disabled:focus, .button-group.clear .button[disabled], .button-group.clear .button[disabled]:hover, .button-group.clear .button[disabled]:focus {
+ border-color: transparent;
+ background-color: transparent; }
+ .button-group.clear .button, .button-group.clear .button.disabled, .button-group.clear .button[disabled], .button-group.clear .button.disabled:hover, .button-group.clear .button[disabled]:hover, .button-group.clear .button.disabled:focus, .button-group.clear .button[disabled]:focus {
+ color: #1779ba; }
+ .button-group.clear .button:hover, .button-group.clear .button:focus {
+ color: #0c3d5d; }
+ .button-group.clear.primary .button, .button-group.clear.primary .button.disabled, .button-group.clear.primary .button[disabled], .button-group.clear.primary .button.disabled:hover, .button-group.clear.primary .button[disabled]:hover, .button-group.clear.primary .button.disabled:focus, .button-group.clear.primary .button[disabled]:focus, .button-group.clear .button.primary, .button-group.clear .button.primary.disabled, .button-group.clear .button.primary[disabled], .button-group.clear .button.primary.disabled:hover, .button-group.clear .button.primary[disabled]:hover, .button-group.clear .button.primary.disabled:focus, .button-group.clear .button.primary[disabled]:focus {
+ color: #1779ba; }
+ .button-group.clear.primary .button:hover, .button-group.clear.primary .button:focus, .button-group.clear .button.primary:hover, .button-group.clear .button.primary:focus {
+ color: #0c3d5d; }
+ .button-group.clear.secondary .button, .button-group.clear.secondary .button.disabled, .button-group.clear.secondary .button[disabled], .button-group.clear.secondary .button.disabled:hover, .button-group.clear.secondary .button[disabled]:hover, .button-group.clear.secondary .button.disabled:focus, .button-group.clear.secondary .button[disabled]:focus, .button-group.clear .button.secondary, .button-group.clear .button.secondary.disabled, .button-group.clear .button.secondary[disabled], .button-group.clear .button.secondary.disabled:hover, .button-group.clear .button.secondary[disabled]:hover, .button-group.clear .button.secondary.disabled:focus, .button-group.clear .button.secondary[disabled]:focus {
+ color: #767676; }
+ .button-group.clear.secondary .button:hover, .button-group.clear.secondary .button:focus, .button-group.clear .button.secondary:hover, .button-group.clear .button.secondary:focus {
+ color: #3b3b3b; }
+ .button-group.clear.success .button, .button-group.clear.success .button.disabled, .button-group.clear.success .button[disabled], .button-group.clear.success .button.disabled:hover, .button-group.clear.success .button[disabled]:hover, .button-group.clear.success .button.disabled:focus, .button-group.clear.success .button[disabled]:focus, .button-group.clear .button.success, .button-group.clear .button.success.disabled, .button-group.clear .button.success[disabled], .button-group.clear .button.success.disabled:hover, .button-group.clear .button.success[disabled]:hover, .button-group.clear .button.success.disabled:focus, .button-group.clear .button.success[disabled]:focus {
+ color: #3adb76; }
+ .button-group.clear.success .button:hover, .button-group.clear.success .button:focus, .button-group.clear .button.success:hover, .button-group.clear .button.success:focus {
+ color: #157539; }
+ .button-group.clear.warning .button, .button-group.clear.warning .button.disabled, .button-group.clear.warning .button[disabled], .button-group.clear.warning .button.disabled:hover, .button-group.clear.warning .button[disabled]:hover, .button-group.clear.warning .button.disabled:focus, .button-group.clear.warning .button[disabled]:focus, .button-group.clear .button.warning, .button-group.clear .button.warning.disabled, .button-group.clear .button.warning[disabled], .button-group.clear .button.warning.disabled:hover, .button-group.clear .button.warning[disabled]:hover, .button-group.clear .button.warning.disabled:focus, .button-group.clear .button.warning[disabled]:focus {
+ color: #ffae00; }
+ .button-group.clear.warning .button:hover, .button-group.clear.warning .button:focus, .button-group.clear .button.warning:hover, .button-group.clear .button.warning:focus {
+ color: #805700; }
+ .button-group.clear.alert .button, .button-group.clear.alert .button.disabled, .button-group.clear.alert .button[disabled], .button-group.clear.alert .button.disabled:hover, .button-group.clear.alert .button[disabled]:hover, .button-group.clear.alert .button.disabled:focus, .button-group.clear.alert .button[disabled]:focus, .button-group.clear .button.alert, .button-group.clear .button.alert.disabled, .button-group.clear .button.alert[disabled], .button-group.clear .button.alert.disabled:hover, .button-group.clear .button.alert[disabled]:hover, .button-group.clear .button.alert.disabled:focus, .button-group.clear .button.alert[disabled]:focus {
+ color: #cc4b37; }
+ .button-group.clear.alert .button:hover, .button-group.clear.alert .button:focus, .button-group.clear .button.alert:hover, .button-group.clear .button.alert:focus {
+ color: #67251a; }
+ .button-group.no-gaps .button {
+ margin-right: -0.0625rem; }
+ .button-group.no-gaps .button + .button {
+ border-left-color: transparent; }
+ .button-group.stacked, .button-group.stacked-for-small, .button-group.stacked-for-medium {
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap; }
+ .button-group.stacked .button, .button-group.stacked-for-small .button, .button-group.stacked-for-medium .button {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 100%;
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%; }
+ .button-group.stacked .button:last-child, .button-group.stacked-for-small .button:last-child, .button-group.stacked-for-medium .button:last-child {
+ margin-bottom: 0; }
+ .button-group.stacked.expanded .button, .button-group.stacked-for-small.expanded .button, .button-group.stacked-for-medium.expanded .button {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; }
+ @media print, screen and (min-width: 40em) {
+ .button-group.stacked-for-small .button {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ margin-bottom: 0; } }
+ @media print, screen and (min-width: 64em) {
+ .button-group.stacked-for-medium .button {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ margin-bottom: 0; } }
+ @media print, screen and (max-width: 39.99875em) {
+ .button-group.stacked-for-small.expanded {
+ display: block; }
+ .button-group.stacked-for-small.expanded .button {
+ display: block;
+ margin-right: 0; } }
+ @media print, screen and (max-width: 63.99875em) {
+ .button-group.stacked-for-medium.expanded {
+ display: block; }
+ .button-group.stacked-for-medium.expanded .button {
+ display: block;
+ margin-right: 0; } }
+
+.close-button {
+ position: absolute;
+ z-index: 10;
+ color: #8a8a8a;
+ cursor: pointer; }
+ [data-whatinput='mouse'] .close-button {
+ outline: 0; }
+ .close-button:hover, .close-button:focus {
+ color: #0a0a0a; }
+ .close-button.small {
+ right: 0.66rem;
+ top: 0.33em;
+ font-size: 1.5em;
+ line-height: 1; }
+ .close-button.medium, .close-button {
+ right: 1rem;
+ top: 0.5rem;
+ font-size: 2em;
+ line-height: 1; }
+
+.label {
+ display: inline-block;
+ padding: 0.33333rem 0.5rem;
+ border-radius: 0;
+ font-size: 0.8rem;
+ line-height: 1;
+ white-space: nowrap;
+ cursor: default;
+ background: #1779ba;
+ color: #fefefe; }
+ .label.primary {
+ background: #1779ba;
+ color: #fefefe; }
+ .label.secondary {
+ background: #767676;
+ color: #fefefe; }
+ .label.success {
+ background: #3adb76;
+ color: #0a0a0a; }
+ .label.warning {
+ background: #ffae00;
+ color: #0a0a0a; }
+ .label.alert {
+ background: #cc4b37;
+ color: #fefefe; }
+
+.progress {
+ height: 1rem;
+ margin-bottom: 1rem;
+ border-radius: 0;
+ background-color: #cacaca; }
+ .progress.primary .progress-meter {
+ background-color: #1779ba; }
+ .progress.secondary .progress-meter {
+ background-color: #767676; }
+ .progress.success .progress-meter {
+ background-color: #3adb76; }
+ .progress.warning .progress-meter {
+ background-color: #ffae00; }
+ .progress.alert .progress-meter {
+ background-color: #cc4b37; }
+
+.progress-meter {
+ position: relative;
+ display: block;
+ width: 0%;
+ height: 100%;
+ background-color: #1779ba; }
+
+.progress-meter-text {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ margin: 0;
+ font-size: 0.75rem;
+ font-weight: bold;
+ color: #fefefe;
+ white-space: nowrap; }
+
+.slider {
+ position: relative;
+ height: 0.5rem;
+ margin-top: 1.25rem;
+ margin-bottom: 2.25rem;
+ background-color: #e6e6e6;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -ms-touch-action: none;
+ touch-action: none; }
+
+.slider-fill {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: inline-block;
+ max-width: 100%;
+ height: 0.5rem;
+ background-color: #cacaca;
+ -webkit-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out; }
+ .slider-fill.is-dragging {
+ -webkit-transition: all 0s linear;
+ transition: all 0s linear; }
+
+.slider-handle {
+ position: absolute;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ -ms-transform: translateY(-50%);
+ transform: translateY(-50%);
+ left: 0;
+ z-index: 1;
+ display: inline-block;
+ width: 1.4rem;
+ height: 1.4rem;
+ border-radius: 0;
+ background-color: #1779ba;
+ -webkit-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out;
+ -ms-touch-action: manipulation;
+ touch-action: manipulation; }
+ [data-whatinput='mouse'] .slider-handle {
+ outline: 0; }
+ .slider-handle:hover {
+ background-color: #14679e; }
+ .slider-handle.is-dragging {
+ -webkit-transition: all 0s linear;
+ transition: all 0s linear; }
+
+.slider.disabled,
+.slider[disabled] {
+ opacity: 0.25;
+ cursor: not-allowed; }
+
+.slider.vertical {
+ display: inline-block;
+ width: 0.5rem;
+ height: 12.5rem;
+ margin: 0 1.25rem;
+ -webkit-transform: scale(1, -1);
+ -ms-transform: scale(1, -1);
+ transform: scale(1, -1); }
+ .slider.vertical .slider-fill {
+ top: 0;
+ width: 0.5rem;
+ max-height: 100%; }
+ .slider.vertical .slider-handle {
+ position: absolute;
+ top: 0;
+ left: 50%;
+ width: 1.4rem;
+ height: 1.4rem;
+ -webkit-transform: translateX(-50%);
+ -ms-transform: translateX(-50%);
+ transform: translateX(-50%); }
+
+.switch {
+ height: 2rem;
+ position: relative;
+ margin-bottom: 1rem;
+ outline: 0;
+ font-size: 0.875rem;
+ font-weight: bold;
+ color: #fefefe;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none; }
+
+.switch-input {
+ position: absolute;
+ margin-bottom: 0;
+ opacity: 0; }
+
+.switch-paddle {
+ position: relative;
+ display: block;
+ width: 4rem;
+ height: 2rem;
+ border-radius: 0;
+ background: #cacaca;
+ -webkit-transition: all 0.25s ease-out;
+ transition: all 0.25s ease-out;
+ font-weight: inherit;
+ color: inherit;
+ cursor: pointer; }
+ input + .switch-paddle {
+ margin: 0; }
+ .switch-paddle::after {
+ position: absolute;
+ top: 0.25rem;
+ left: 0.25rem;
+ display: block;
+ width: 1.5rem;
+ height: 1.5rem;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ border-radius: 0;
+ background: #fefefe;
+ -webkit-transition: all 0.25s ease-out;
+ transition: all 0.25s ease-out;
+ content: ''; }
+ input:checked ~ .switch-paddle {
+ background: #1779ba; }
+ input:checked ~ .switch-paddle::after {
+ left: 2.25rem; }
+ input:disabled ~ .switch-paddle {
+ cursor: not-allowed;
+ opacity: 0.5; }
+ [data-whatinput='mouse'] input:focus ~ .switch-paddle {
+ outline: 0; }
+
+.switch-active, .switch-inactive {
+ position: absolute;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ -ms-transform: translateY(-50%);
+ transform: translateY(-50%); }
+
+.switch-active {
+ left: 8%;
+ display: none; }
+ input:checked + label > .switch-active {
+ display: block; }
+
+.switch-inactive {
+ right: 15%; }
+ input:checked + label > .switch-inactive {
+ display: none; }
+
+.switch.tiny {
+ height: 1.5rem; }
+ .switch.tiny .switch-paddle {
+ width: 3rem;
+ height: 1.5rem;
+ font-size: 0.625rem; }
+ .switch.tiny .switch-paddle::after {
+ top: 0.25rem;
+ left: 0.25rem;
+ width: 1rem;
+ height: 1rem; }
+ .switch.tiny input:checked ~ .switch-paddle::after {
+ left: 1.75rem; }
+
+.switch.small {
+ height: 1.75rem; }
+ .switch.small .switch-paddle {
+ width: 3.5rem;
+ height: 1.75rem;
+ font-size: 0.75rem; }
+ .switch.small .switch-paddle::after {
+ top: 0.25rem;
+ left: 0.25rem;
+ width: 1.25rem;
+ height: 1.25rem; }
+ .switch.small input:checked ~ .switch-paddle::after {
+ left: 2rem; }
+
+.switch.large {
+ height: 2.5rem; }
+ .switch.large .switch-paddle {
+ width: 5rem;
+ height: 2.5rem;
+ font-size: 1rem; }
+ .switch.large .switch-paddle::after {
+ top: 0.25rem;
+ left: 0.25rem;
+ width: 2rem;
+ height: 2rem; }
+ .switch.large input:checked ~ .switch-paddle::after {
+ left: 2.75rem; }
+
+table {
+ border-collapse: collapse;
+ width: 100%;
+ margin-bottom: 1rem;
+ border-radius: 0; }
+ thead,
+ tbody,
+ tfoot {
+ border: 1px solid #f1f1f1;
+ background-color: #fefefe; }
+ caption {
+ padding: 0.5rem 0.625rem 0.625rem;
+ font-weight: bold; }
+ thead {
+ background: #f8f8f8;
+ color: #0a0a0a; }
+ tfoot {
+ background: #f1f1f1;
+ color: #0a0a0a; }
+ thead tr,
+ tfoot tr {
+ background: transparent; }
+ thead th,
+ thead td,
+ tfoot th,
+ tfoot td {
+ padding: 0.5rem 0.625rem 0.625rem;
+ font-weight: bold;
+ text-align: left; }
+ tbody th,
+ tbody td {
+ padding: 0.5rem 0.625rem 0.625rem; }
+ tbody tr:nth-child(even) {
+ border-bottom: 0;
+ background-color: #f1f1f1; }
+ table.unstriped tbody {
+ background-color: #fefefe; }
+ table.unstriped tbody tr {
+ border-bottom: 0;
+ border-bottom: 1px solid #f1f1f1;
+ background-color: #fefefe; }
+
+@media print, screen and (max-width: 63.99875em) {
+ table.stack thead {
+ display: none; }
+ table.stack tfoot {
+ display: none; }
+ table.stack tr,
+ table.stack th,
+ table.stack td {
+ display: block; }
+ table.stack td {
+ border-top: 0; } }
+
+table.scroll {
+ display: block;
+ width: 100%;
+ overflow-x: auto; }
+
+table.hover thead tr:hover {
+ background-color: #f3f3f3; }
+
+table.hover tfoot tr:hover {
+ background-color: #ececec; }
+
+table.hover tbody tr:hover {
+ background-color: #f9f9f9; }
+
+table.hover:not(.unstriped) tr:nth-of-type(even):hover {
+ background-color: #ececec; }
+
+.table-scroll {
+ overflow-x: auto; }
+
+.badge {
+ display: inline-block;
+ min-width: 2.1em;
+ padding: 0.3em;
+ border-radius: 50%;
+ font-size: 0.6rem;
+ text-align: center;
+ background: #1779ba;
+ color: #fefefe; }
+ .badge.primary {
+ background: #1779ba;
+ color: #fefefe; }
+ .badge.secondary {
+ background: #767676;
+ color: #fefefe; }
+ .badge.success {
+ background: #3adb76;
+ color: #0a0a0a; }
+ .badge.warning {
+ background: #ffae00;
+ color: #0a0a0a; }
+ .badge.alert {
+ background: #cc4b37;
+ color: #fefefe; }
+
+.breadcrumbs {
+ margin: 0 0 1rem 0;
+ list-style: none; }
+ .breadcrumbs::before, .breadcrumbs::after {
+ display: table;
+ content: ' ';
+ -webkit-flex-basis: 0;
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -webkit-box-ordinal-group: 2;
+ -webkit-order: 1;
+ -ms-flex-order: 1;
+ order: 1; }
+ .breadcrumbs::after {
+ clear: both; }
+ .breadcrumbs li {
+ float: left;
+ font-size: 0.6875rem;
+ color: #0a0a0a;
+ cursor: default;
+ text-transform: uppercase; }
+ .breadcrumbs li:not(:last-child)::after {
+ position: relative;
+ margin: 0 0.75rem;
+ opacity: 1;
+ content: "/";
+ color: #cacaca; }
+ .breadcrumbs a {
+ color: #1779ba; }
+ .breadcrumbs a:hover {
+ text-decoration: underline; }
+ .breadcrumbs .disabled {
+ color: #cacaca;
+ cursor: not-allowed; }
+
+.callout {
+ position: relative;
+ margin: 0 0 1rem 0;
+ padding: 1rem;
+ border: 1px solid rgba(10, 10, 10, 0.25);
+ border-radius: 0;
+ background-color: white;
+ color: #0a0a0a; }
+ .callout > :first-child {
+ margin-top: 0; }
+ .callout > :last-child {
+ margin-bottom: 0; }
+ .callout.primary {
+ background-color: #d7ecfa;
+ color: #0a0a0a; }
+ .callout.secondary {
+ background-color: #eaeaea;
+ color: #0a0a0a; }
+ .callout.success {
+ background-color: #e1faea;
+ color: #0a0a0a; }
+ .callout.warning {
+ background-color: #fff3d9;
+ color: #0a0a0a; }
+ .callout.alert {
+ background-color: #f7e4e1;
+ color: #0a0a0a; }
+ .callout.small {
+ padding-top: 0.5rem;
+ padding-right: 0.5rem;
+ padding-bottom: 0.5rem;
+ padding-left: 0.5rem; }
+ .callout.large {
+ padding-top: 3rem;
+ padding-right: 3rem;
+ padding-bottom: 3rem;
+ padding-left: 3rem; }
+
+.card {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-box-flex: 1;
+ -webkit-flex-grow: 1;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ margin-bottom: 1rem;
+ border: 1px solid #e6e6e6;
+ border-radius: 0;
+ background: #fefefe;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ overflow: hidden;
+ color: #0a0a0a; }
+ .card > :last-child {
+ margin-bottom: 0; }
+
+.card-divider {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 1 auto;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto;
+ padding: 1rem;
+ background: #e6e6e6; }
+ .card-divider > :last-child {
+ margin-bottom: 0; }
+
+.card-section {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 0 auto;
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto;
+ padding: 1rem; }
+ .card-section > :last-child {
+ margin-bottom: 0; }
+
+.card-image {
+ min-height: 1px; }
+
+.dropdown-pane {
+ position: absolute;
+ z-index: 10;
+ display: none;
+ width: 300px;
+ padding: 1rem;
+ visibility: hidden;
+ border: 1px solid #cacaca;
+ border-radius: 0;
+ background-color: #fefefe;
+ font-size: 1rem; }
+ .dropdown-pane.is-opening {
+ display: block; }
+ .dropdown-pane.is-open {
+ display: block;
+ visibility: visible; }
+
+.dropdown-pane.tiny {
+ width: 100px; }
+
+.dropdown-pane.small {
+ width: 200px; }
+
+.dropdown-pane.large {
+ width: 400px; }
+
+.pagination {
+ margin-left: 0;
+ margin-bottom: 1rem; }
+ .pagination::before, .pagination::after {
+ display: table;
+ content: ' ';
+ -webkit-flex-basis: 0;
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -webkit-box-ordinal-group: 2;
+ -webkit-order: 1;
+ -ms-flex-order: 1;
+ order: 1; }
+ .pagination::after {
+ clear: both; }
+ .pagination li {
+ margin-right: 0.0625rem;
+ border-radius: 0;
+ font-size: 0.875rem;
+ display: none; }
+ .pagination li:last-child, .pagination li:first-child {
+ display: inline-block; }
+ @media print, screen and (min-width: 40em) {
+ .pagination li {
+ display: inline-block; } }
+ .pagination a,
+ .pagination button {
+ display: block;
+ padding: 0.1875rem 0.625rem;
+ border-radius: 0;
+ color: #0a0a0a; }
+ .pagination a:hover,
+ .pagination button:hover {
+ background: #e6e6e6; }
+ .pagination .current {
+ padding: 0.1875rem 0.625rem;
+ background: #1779ba;
+ color: #fefefe;
+ cursor: default; }
+ .pagination .disabled {
+ padding: 0.1875rem 0.625rem;
+ color: #cacaca;
+ cursor: not-allowed; }
+ .pagination .disabled:hover {
+ background: transparent; }
+ .pagination .ellipsis::after {
+ padding: 0.1875rem 0.625rem;
+ content: '\2026';
+ color: #0a0a0a; }
+
+.pagination-previous a::before,
+.pagination-previous.disabled::before {
+ display: inline-block;
+ margin-right: 0.5rem;
+ content: "«"; }
+
+.pagination-next a::after,
+.pagination-next.disabled::after {
+ display: inline-block;
+ margin-left: 0.5rem;
+ content: "»"; }
+
+.has-tip {
+ position: relative;
+ display: inline-block;
+ border-bottom: dotted 1px #8a8a8a;
+ font-weight: bold;
+ cursor: help; }
+
+.tooltip {
+ position: absolute;
+ top: calc(100% + 0.6495rem);
+ z-index: 1200;
+ max-width: 10rem;
+ padding: 0.75rem;
+ border-radius: 0;
+ background-color: #0a0a0a;
+ font-size: 80%;
+ color: #fefefe; }
+ .tooltip::before {
+ position: absolute; }
+ .tooltip.bottom::before {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 0.75rem;
+ content: '';
+ border-top-width: 0;
+ border-color: transparent transparent #0a0a0a;
+ bottom: 100%; }
+ .tooltip.bottom.align-center::before {
+ left: 50%;
+ -webkit-transform: translateX(-50%);
+ -ms-transform: translateX(-50%);
+ transform: translateX(-50%); }
+ .tooltip.top::before {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 0.75rem;
+ content: '';
+ border-bottom-width: 0;
+ border-color: #0a0a0a transparent transparent;
+ top: 100%;
+ bottom: auto; }
+ .tooltip.top.align-center::before {
+ left: 50%;
+ -webkit-transform: translateX(-50%);
+ -ms-transform: translateX(-50%);
+ transform: translateX(-50%); }
+ .tooltip.left::before {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 0.75rem;
+ content: '';
+ border-right-width: 0;
+ border-color: transparent transparent transparent #0a0a0a;
+ left: 100%; }
+ .tooltip.left.align-center::before {
+ bottom: auto;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ -ms-transform: translateY(-50%);
+ transform: translateY(-50%); }
+ .tooltip.right::before {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 0.75rem;
+ content: '';
+ border-left-width: 0;
+ border-color: transparent #0a0a0a transparent transparent;
+ right: 100%;
+ left: auto; }
+ .tooltip.right.align-center::before {
+ bottom: auto;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ -ms-transform: translateY(-50%);
+ transform: translateY(-50%); }
+ .tooltip.align-top::before {
+ bottom: auto;
+ top: 10%; }
+ .tooltip.align-bottom::before {
+ bottom: 10%;
+ top: auto; }
+ .tooltip.align-left::before {
+ left: 10%;
+ right: auto; }
+ .tooltip.align-right::before {
+ left: auto;
+ right: 10%; }
+
+.accordion {
+ margin-left: 0;
+ background: #fefefe;
+ list-style-type: none; }
+ .accordion[disabled] .accordion-title {
+ cursor: not-allowed; }
+
+.accordion-item:first-child > :first-child {
+ border-radius: 0 0 0 0; }
+
+.accordion-item:last-child > :last-child {
+ border-radius: 0 0 0 0; }
+
+.accordion-title {
+ position: relative;
+ display: block;
+ padding: 1.25rem 1rem;
+ border: 1px solid #e6e6e6;
+ border-bottom: 0;
+ font-size: 0.75rem;
+ line-height: 1;
+ color: #1779ba; }
+ :last-child:not(.is-active) > .accordion-title {
+ border-bottom: 1px solid #e6e6e6;
+ border-radius: 0 0 0 0; }
+ .accordion-title:hover, .accordion-title:focus {
+ background-color: #e6e6e6; }
+ .accordion-title::before {
+ position: absolute;
+ top: 50%;
+ right: 1rem;
+ margin-top: -0.5rem;
+ content: "+"; }
+ .is-active > .accordion-title::before {
+ content: "–"; }
+
+.accordion-content {
+ display: none;
+ padding: 1rem;
+ border: 1px solid #e6e6e6;
+ border-bottom: 0;
+ background-color: #fefefe;
+ color: #0a0a0a; }
+ :last-child > .accordion-content:last-child {
+ border-bottom: 1px solid #e6e6e6; }
+
+.media-object {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ margin-bottom: 1rem;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap; }
+ .media-object img {
+ max-width: none; }
+ @media print, screen and (max-width: 39.99875em) {
+ .media-object.stack-for-small {
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap; } }
+
+.media-object-section {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 1 auto;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto; }
+ .media-object-section:first-child {
+ padding-right: 1rem; }
+ .media-object-section:last-child:not(:nth-child(2)) {
+ padding-left: 1rem; }
+ .media-object-section > :last-child {
+ margin-bottom: 0; }
+ @media print, screen and (max-width: 39.99875em) {
+ .stack-for-small .media-object-section {
+ padding: 0;
+ padding-bottom: 1rem;
+ -webkit-flex-basis: 100%;
+ -ms-flex-preferred-size: 100%;
+ flex-basis: 100%;
+ max-width: 100%; }
+ .stack-for-small .media-object-section img {
+ width: 100%; } }
+ .media-object-section.main-section {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; }
+
+.orbit {
+ position: relative; }
+
+.orbit-container {
+ position: relative;
+ height: 0;
+ margin: 0;
+ list-style: none;
+ overflow: hidden; }
+
+.orbit-slide {
+ width: 100%;
+ position: absolute; }
+ .orbit-slide.no-motionui.is-active {
+ top: 0;
+ left: 0; }
+
+.orbit-figure {
+ margin: 0; }
+
+.orbit-image {
+ width: 100%;
+ max-width: 100%;
+ margin: 0; }
+
+.orbit-caption {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ margin-bottom: 0;
+ padding: 1rem;
+ background-color: rgba(10, 10, 10, 0.5);
+ color: #fefefe; }
+
+.orbit-previous, .orbit-next {
+ position: absolute;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ -ms-transform: translateY(-50%);
+ transform: translateY(-50%);
+ z-index: 10;
+ padding: 1rem;
+ color: #fefefe; }
+ [data-whatinput='mouse'] .orbit-previous, [data-whatinput='mouse'] .orbit-next {
+ outline: 0; }
+ .orbit-previous:hover, .orbit-next:hover, .orbit-previous:active, .orbit-next:active, .orbit-previous:focus, .orbit-next:focus {
+ background-color: rgba(10, 10, 10, 0.5); }
+
+.orbit-previous {
+ left: 0; }
+
+.orbit-next {
+ left: auto;
+ right: 0; }
+
+.orbit-bullets {
+ position: relative;
+ margin-top: 0.8rem;
+ margin-bottom: 0.8rem;
+ text-align: center; }
+ [data-whatinput='mouse'] .orbit-bullets {
+ outline: 0; }
+ .orbit-bullets button {
+ width: 1.2rem;
+ height: 1.2rem;
+ margin: 0.1rem;
+ border-radius: 50%;
+ background-color: #cacaca; }
+ .orbit-bullets button:hover {
+ background-color: #8a8a8a; }
+ .orbit-bullets button.is-active {
+ background-color: #8a8a8a; }
+
+.responsive-embed,
+.flex-video {
+ position: relative;
+ height: 0;
+ margin-bottom: 1rem;
+ padding-bottom: 75%;
+ overflow: hidden; }
+ .responsive-embed iframe,
+ .responsive-embed object,
+ .responsive-embed embed,
+ .responsive-embed video,
+ .flex-video iframe,
+ .flex-video object,
+ .flex-video embed,
+ .flex-video video {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%; }
+ .responsive-embed.widescreen,
+ .flex-video.widescreen {
+ padding-bottom: 56.25%; }
+
+.tabs {
+ margin: 0;
+ border: 1px solid #e6e6e6;
+ background: #fefefe;
+ list-style-type: none; }
+ .tabs::before, .tabs::after {
+ display: table;
+ content: ' ';
+ -webkit-flex-basis: 0;
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -webkit-box-ordinal-group: 2;
+ -webkit-order: 1;
+ -ms-flex-order: 1;
+ order: 1; }
+ .tabs::after {
+ clear: both; }
+
+.tabs.vertical > li {
+ display: block;
+ float: none;
+ width: auto; }
+
+.tabs.simple > li > a {
+ padding: 0; }
+ .tabs.simple > li > a:hover {
+ background: transparent; }
+
+.tabs.primary {
+ background: #1779ba; }
+ .tabs.primary > li > a {
+ color: #fefefe; }
+ .tabs.primary > li > a:hover, .tabs.primary > li > a:focus {
+ background: #1673b1; }
+
+.tabs-title {
+ float: left; }
+ .tabs-title > a {
+ display: block;
+ padding: 1.25rem 1.5rem;
+ font-size: 0.75rem;
+ line-height: 1;
+ color: #1779ba; }
+ [data-whatinput='mouse'] .tabs-title > a {
+ outline: 0; }
+ .tabs-title > a:hover {
+ background: #fefefe;
+ color: #1468a0; }
+ .tabs-title > a:focus, .tabs-title > a[aria-selected='true'] {
+ background: #e6e6e6;
+ color: #1779ba; }
+
+.tabs-content {
+ border: 1px solid #e6e6e6;
+ border-top: 0;
+ background: #fefefe;
+ color: #0a0a0a;
+ -webkit-transition: all 0.5s ease;
+ transition: all 0.5s ease; }
+
+.tabs-content.vertical {
+ border: 1px solid #e6e6e6;
+ border-left: 0; }
+
+.tabs-panel {
+ display: none;
+ padding: 1rem; }
+ .tabs-panel.is-active {
+ display: block; }
+
+.thumbnail {
+ display: inline-block;
+ max-width: 100%;
+ margin-bottom: 1rem;
+ border: 4px solid #fefefe;
+ border-radius: 0;
+ -webkit-box-shadow: 0 0 0 1px rgba(10, 10, 10, 0.2);
+ box-shadow: 0 0 0 1px rgba(10, 10, 10, 0.2);
+ line-height: 0; }
+
+a.thumbnail {
+ -webkit-transition: -webkit-box-shadow 200ms ease-out;
+ transition: -webkit-box-shadow 200ms ease-out;
+ transition: box-shadow 200ms ease-out;
+ transition: box-shadow 200ms ease-out, -webkit-box-shadow 200ms ease-out; }
+ a.thumbnail:hover, a.thumbnail:focus {
+ -webkit-box-shadow: 0 0 6px 1px rgba(23, 121, 186, 0.5);
+ box-shadow: 0 0 6px 1px rgba(23, 121, 186, 0.5); }
+ a.thumbnail image {
+ -webkit-box-shadow: none;
+ box-shadow: none; }
+
+.menu {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ position: relative;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap; }
+ [data-whatinput='mouse'] .menu li {
+ outline: 0; }
+ .menu a,
+ .menu .button {
+ line-height: 1;
+ text-decoration: none;
+ display: block;
+ padding: 0.7rem 1rem; }
+ .menu input,
+ .menu select,
+ .menu a,
+ .menu button {
+ margin-bottom: 0; }
+ .menu input {
+ display: inline-block; }
+ .menu, .menu.horizontal {
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row; }
+ .menu.vertical {
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column; }
+ .menu.vertical.icon-top li a img,
+ .menu.vertical.icon-top li a i,
+ .menu.vertical.icon-top li a svg, .menu.vertical.icon-bottom li a img,
+ .menu.vertical.icon-bottom li a i,
+ .menu.vertical.icon-bottom li a svg {
+ text-align: left; }
+ .menu.expanded li {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; }
+ .menu.expanded.icon-top li a img,
+ .menu.expanded.icon-top li a i,
+ .menu.expanded.icon-top li a svg, .menu.expanded.icon-bottom li a img,
+ .menu.expanded.icon-bottom li a i,
+ .menu.expanded.icon-bottom li a svg {
+ text-align: left; }
+ .menu.simple {
+ -webkit-box-align: center;
+ -webkit-align-items: center;
+ -ms-flex-align: center;
+ align-items: center; }
+ .menu.simple li + li {
+ margin-left: 1rem; }
+ .menu.simple a {
+ padding: 0; }
+ @media print, screen and (min-width: 40em) {
+ .menu.medium-horizontal {
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row; }
+ .menu.medium-vertical {
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column; }
+ .menu.medium-expanded li {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; }
+ .menu.medium-simple li {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; } }
+ @media print, screen and (min-width: 64em) {
+ .menu.large-horizontal {
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row; }
+ .menu.large-vertical {
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column; }
+ .menu.large-expanded li {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; }
+ .menu.large-simple li {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; } }
+ .menu.nested {
+ margin-right: 0;
+ margin-left: 1rem; }
+ .menu.icons a {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex; }
+ .menu.icon-top a, .menu.icon-right a, .menu.icon-bottom a, .menu.icon-left a {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex; }
+ .menu.icon-left li a, .menu.nested.icon-left li a {
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-flow: row nowrap;
+ -ms-flex-flow: row nowrap;
+ flex-flow: row nowrap; }
+ .menu.icon-left li a img,
+ .menu.icon-left li a i,
+ .menu.icon-left li a svg, .menu.nested.icon-left li a img,
+ .menu.nested.icon-left li a i,
+ .menu.nested.icon-left li a svg {
+ margin-right: 0.25rem; }
+ .menu.icon-right li a, .menu.nested.icon-right li a {
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-flow: row nowrap;
+ -ms-flex-flow: row nowrap;
+ flex-flow: row nowrap; }
+ .menu.icon-right li a img,
+ .menu.icon-right li a i,
+ .menu.icon-right li a svg, .menu.nested.icon-right li a img,
+ .menu.nested.icon-right li a i,
+ .menu.nested.icon-right li a svg {
+ margin-left: 0.25rem; }
+ .menu.icon-top li a, .menu.nested.icon-top li a {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-flow: column nowrap;
+ -ms-flex-flow: column nowrap;
+ flex-flow: column nowrap; }
+ .menu.icon-top li a img,
+ .menu.icon-top li a i,
+ .menu.icon-top li a svg, .menu.nested.icon-top li a img,
+ .menu.nested.icon-top li a i,
+ .menu.nested.icon-top li a svg {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ margin-bottom: 0.25rem;
+ text-align: center; }
+ .menu.icon-bottom li a, .menu.nested.icon-bottom li a {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-flow: column nowrap;
+ -ms-flex-flow: column nowrap;
+ flex-flow: column nowrap; }
+ .menu.icon-bottom li a img,
+ .menu.icon-bottom li a i,
+ .menu.icon-bottom li a svg, .menu.nested.icon-bottom li a img,
+ .menu.nested.icon-bottom li a i,
+ .menu.nested.icon-bottom li a svg {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ margin-bottom: 0.25rem;
+ text-align: center; }
+ .menu .is-active > a {
+ background: #1779ba;
+ color: #fefefe; }
+ .menu .active > a {
+ background: #1779ba;
+ color: #fefefe; }
+ .menu.align-left {
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start; }
+ .menu.align-right li {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: end;
+ -webkit-justify-content: flex-end;
+ -ms-flex-pack: end;
+ justify-content: flex-end; }
+ .menu.align-right li .submenu li {
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start; }
+ .menu.align-right.vertical li {
+ display: block;
+ text-align: right; }
+ .menu.align-right.vertical li .submenu li {
+ text-align: right; }
+ .menu.align-right.icon-top li a img,
+ .menu.align-right.icon-top li a i,
+ .menu.align-right.icon-top li a svg, .menu.align-right.icon-bottom li a img,
+ .menu.align-right.icon-bottom li a i,
+ .menu.align-right.icon-bottom li a svg {
+ text-align: right; }
+ .menu.align-right .nested {
+ margin-right: 1rem;
+ margin-left: 0; }
+ .menu.align-center li {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center; }
+ .menu.align-center li .submenu li {
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start; }
+ .menu .menu-text {
+ padding: 0.7rem 1rem;
+ font-weight: bold;
+ line-height: 1;
+ color: inherit; }
+
+.menu-centered > .menu {
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center; }
+ .menu-centered > .menu li {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center; }
+ .menu-centered > .menu li .submenu li {
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start; }
+
+.no-js [data-responsive-menu] ul {
+ display: none; }
+
+.menu-icon {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ width: 20px;
+ height: 16px;
+ cursor: pointer; }
+ .menu-icon::after {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: block;
+ width: 100%;
+ height: 2px;
+ background: #fefefe;
+ -webkit-box-shadow: 0 7px 0 #fefefe, 0 14px 0 #fefefe;
+ box-shadow: 0 7px 0 #fefefe, 0 14px 0 #fefefe;
+ content: ''; }
+ .menu-icon:hover::after {
+ background: #cacaca;
+ -webkit-box-shadow: 0 7px 0 #cacaca, 0 14px 0 #cacaca;
+ box-shadow: 0 7px 0 #cacaca, 0 14px 0 #cacaca; }
+
+.menu-icon.dark {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ width: 20px;
+ height: 16px;
+ cursor: pointer; }
+ .menu-icon.dark::after {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: block;
+ width: 100%;
+ height: 2px;
+ background: #0a0a0a;
+ -webkit-box-shadow: 0 7px 0 #0a0a0a, 0 14px 0 #0a0a0a;
+ box-shadow: 0 7px 0 #0a0a0a, 0 14px 0 #0a0a0a;
+ content: ''; }
+ .menu-icon.dark:hover::after {
+ background: #8a8a8a;
+ -webkit-box-shadow: 0 7px 0 #8a8a8a, 0 14px 0 #8a8a8a;
+ box-shadow: 0 7px 0 #8a8a8a, 0 14px 0 #8a8a8a; }
+
+.accordion-menu li {
+ width: 100%; }
+
+.accordion-menu a {
+ padding: 0.7rem 1rem; }
+
+.accordion-menu .is-accordion-submenu a {
+ padding: 0.7rem 1rem; }
+
+.accordion-menu .nested.is-accordion-submenu {
+ margin-right: 0;
+ margin-left: 1rem; }
+
+.accordion-menu.align-right .nested.is-accordion-submenu {
+ margin-right: 1rem;
+ margin-left: 0; }
+
+.accordion-menu .is-accordion-submenu-parent:not(.has-submenu-toggle) > a {
+ position: relative; }
+ .accordion-menu .is-accordion-submenu-parent:not(.has-submenu-toggle) > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-bottom-width: 0;
+ border-color: #1779ba transparent transparent;
+ position: absolute;
+ top: 50%;
+ margin-top: -3px;
+ right: 1rem; }
+
+.accordion-menu.align-left .is-accordion-submenu-parent > a::after {
+ right: 1rem;
+ left: auto; }
+
+.accordion-menu.align-right .is-accordion-submenu-parent > a::after {
+ right: auto;
+ left: 1rem; }
+
+.accordion-menu .is-accordion-submenu-parent[aria-expanded='true'] > a::after {
+ -webkit-transform: rotate(180deg);
+ -ms-transform: rotate(180deg);
+ transform: rotate(180deg);
+ -webkit-transform-origin: 50% 50%;
+ -ms-transform-origin: 50% 50%;
+ transform-origin: 50% 50%; }
+
+.is-accordion-submenu-parent {
+ position: relative; }
+
+.has-submenu-toggle > a {
+ margin-right: 40px; }
+
+.submenu-toggle {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 40px;
+ height: 40px;
+ cursor: pointer; }
+ .submenu-toggle::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-bottom-width: 0;
+ border-color: #1779ba transparent transparent;
+ top: 0;
+ bottom: 0;
+ margin: auto; }
+
+.submenu-toggle[aria-expanded='true']::after {
+ -webkit-transform: scaleY(-1);
+ -ms-transform: scaleY(-1);
+ transform: scaleY(-1);
+ -webkit-transform-origin: 50% 50%;
+ -ms-transform-origin: 50% 50%;
+ transform-origin: 50% 50%; }
+
+.submenu-toggle-text {
+ position: absolute !important;
+ width: 1px !important;
+ height: 1px !important;
+ padding: 0 !important;
+ overflow: hidden !important;
+ clip: rect(0, 0, 0, 0) !important;
+ white-space: nowrap !important;
+ border: 0 !important; }
+
+.is-drilldown {
+ position: relative;
+ overflow: hidden; }
+ .is-drilldown li {
+ display: block; }
+ .is-drilldown.animate-height {
+ -webkit-transition: height 0.5s;
+ transition: height 0.5s; }
+
+.drilldown a {
+ padding: 0.7rem 1rem;
+ background: #fefefe; }
+
+.drilldown .is-drilldown-submenu {
+ position: absolute;
+ top: 0;
+ left: 100%;
+ z-index: -1;
+ width: 100%;
+ background: #fefefe;
+ -webkit-transition: -webkit-transform 0.15s linear;
+ transition: -webkit-transform 0.15s linear;
+ transition: transform 0.15s linear;
+ transition: transform 0.15s linear, -webkit-transform 0.15s linear; }
+ .drilldown .is-drilldown-submenu.is-active {
+ z-index: 1;
+ display: block;
+ -webkit-transform: translateX(-100%);
+ -ms-transform: translateX(-100%);
+ transform: translateX(-100%); }
+ .drilldown .is-drilldown-submenu.is-closing {
+ -webkit-transform: translateX(100%);
+ -ms-transform: translateX(100%);
+ transform: translateX(100%); }
+ .drilldown .is-drilldown-submenu a {
+ padding: 0.7rem 1rem; }
+
+.drilldown .nested.is-drilldown-submenu {
+ margin-right: 0;
+ margin-left: 0; }
+
+.drilldown .drilldown-submenu-cover-previous {
+ min-height: 100%; }
+
+.drilldown .is-drilldown-submenu-parent > a {
+ position: relative; }
+ .drilldown .is-drilldown-submenu-parent > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-right-width: 0;
+ border-color: transparent transparent transparent #1779ba;
+ position: absolute;
+ top: 50%;
+ margin-top: -6px;
+ right: 1rem; }
+
+.drilldown.align-left .is-drilldown-submenu-parent > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-right-width: 0;
+ border-color: transparent transparent transparent #1779ba;
+ right: 1rem;
+ left: auto; }
+
+.drilldown.align-right .is-drilldown-submenu-parent > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-left-width: 0;
+ border-color: transparent #1779ba transparent transparent;
+ right: auto;
+ left: 1rem; }
+
+.drilldown .js-drilldown-back > a::before {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-left-width: 0;
+ border-color: transparent #1779ba transparent transparent;
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 0.75rem; }
+
+.dropdown.menu > li.opens-left > .is-dropdown-submenu {
+ top: 100%;
+ right: 0;
+ left: auto; }
+
+.dropdown.menu > li.opens-right > .is-dropdown-submenu {
+ top: 100%;
+ right: auto;
+ left: 0; }
+
+.dropdown.menu > li.is-dropdown-submenu-parent > a {
+ position: relative;
+ padding-right: 1.5rem; }
+
+.dropdown.menu > li.is-dropdown-submenu-parent > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-bottom-width: 0;
+ border-color: #1779ba transparent transparent;
+ right: 5px;
+ left: auto;
+ margin-top: -3px; }
+
+[data-whatinput='mouse'] .dropdown.menu a {
+ outline: 0; }
+
+.dropdown.menu > li > a {
+ padding: 0.7rem 1rem; }
+
+.dropdown.menu > li.is-active > a {
+ background: transparent;
+ color: #1779ba; }
+
+.no-js .dropdown.menu ul {
+ display: none; }
+
+.dropdown.menu .nested.is-dropdown-submenu {
+ margin-right: 0;
+ margin-left: 0; }
+
+.dropdown.menu.vertical > li .is-dropdown-submenu {
+ top: 0; }
+
+.dropdown.menu.vertical > li.opens-left > .is-dropdown-submenu {
+ top: 0;
+ right: 100%;
+ left: auto; }
+
+.dropdown.menu.vertical > li.opens-right > .is-dropdown-submenu {
+ right: auto;
+ left: 100%; }
+
+.dropdown.menu.vertical > li > a::after {
+ right: 14px; }
+
+.dropdown.menu.vertical > li.opens-left > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-left-width: 0;
+ border-color: transparent #1779ba transparent transparent;
+ right: auto;
+ left: 5px; }
+
+.dropdown.menu.vertical > li.opens-right > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-right-width: 0;
+ border-color: transparent transparent transparent #1779ba; }
+
+@media print, screen and (min-width: 40em) {
+ .dropdown.menu.medium-horizontal > li.opens-left > .is-dropdown-submenu {
+ top: 100%;
+ right: 0;
+ left: auto; }
+ .dropdown.menu.medium-horizontal > li.opens-right > .is-dropdown-submenu {
+ top: 100%;
+ right: auto;
+ left: 0; }
+ .dropdown.menu.medium-horizontal > li.is-dropdown-submenu-parent > a {
+ position: relative;
+ padding-right: 1.5rem; }
+ .dropdown.menu.medium-horizontal > li.is-dropdown-submenu-parent > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-bottom-width: 0;
+ border-color: #1779ba transparent transparent;
+ right: 5px;
+ left: auto;
+ margin-top: -3px; }
+ .dropdown.menu.medium-vertical > li .is-dropdown-submenu {
+ top: 0; }
+ .dropdown.menu.medium-vertical > li.opens-left > .is-dropdown-submenu {
+ top: 0;
+ right: 100%;
+ left: auto; }
+ .dropdown.menu.medium-vertical > li.opens-right > .is-dropdown-submenu {
+ right: auto;
+ left: 100%; }
+ .dropdown.menu.medium-vertical > li > a::after {
+ right: 14px; }
+ .dropdown.menu.medium-vertical > li.opens-left > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-left-width: 0;
+ border-color: transparent #1779ba transparent transparent;
+ right: auto;
+ left: 5px; }
+ .dropdown.menu.medium-vertical > li.opens-right > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-right-width: 0;
+ border-color: transparent transparent transparent #1779ba; } }
+
+@media print, screen and (min-width: 64em) {
+ .dropdown.menu.large-horizontal > li.opens-left > .is-dropdown-submenu {
+ top: 100%;
+ right: 0;
+ left: auto; }
+ .dropdown.menu.large-horizontal > li.opens-right > .is-dropdown-submenu {
+ top: 100%;
+ right: auto;
+ left: 0; }
+ .dropdown.menu.large-horizontal > li.is-dropdown-submenu-parent > a {
+ position: relative;
+ padding-right: 1.5rem; }
+ .dropdown.menu.large-horizontal > li.is-dropdown-submenu-parent > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-bottom-width: 0;
+ border-color: #1779ba transparent transparent;
+ right: 5px;
+ left: auto;
+ margin-top: -3px; }
+ .dropdown.menu.large-vertical > li .is-dropdown-submenu {
+ top: 0; }
+ .dropdown.menu.large-vertical > li.opens-left > .is-dropdown-submenu {
+ top: 0;
+ right: 100%;
+ left: auto; }
+ .dropdown.menu.large-vertical > li.opens-right > .is-dropdown-submenu {
+ right: auto;
+ left: 100%; }
+ .dropdown.menu.large-vertical > li > a::after {
+ right: 14px; }
+ .dropdown.menu.large-vertical > li.opens-left > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-left-width: 0;
+ border-color: transparent #1779ba transparent transparent;
+ right: auto;
+ left: 5px; }
+ .dropdown.menu.large-vertical > li.opens-right > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-right-width: 0;
+ border-color: transparent transparent transparent #1779ba; } }
+
+.dropdown.menu.align-right .is-dropdown-submenu.first-sub {
+ top: 100%;
+ right: 0;
+ left: auto; }
+
+.is-dropdown-menu.vertical {
+ width: 100px; }
+ .is-dropdown-menu.vertical.align-right {
+ float: right; }
+
+.is-dropdown-submenu-parent {
+ position: relative; }
+ .is-dropdown-submenu-parent a::after {
+ position: absolute;
+ top: 50%;
+ right: 5px;
+ left: auto;
+ margin-top: -6px; }
+ .is-dropdown-submenu-parent.opens-inner > .is-dropdown-submenu {
+ top: 100%;
+ left: auto; }
+ .is-dropdown-submenu-parent.opens-left > .is-dropdown-submenu {
+ right: 100%;
+ left: auto; }
+ .is-dropdown-submenu-parent.opens-right > .is-dropdown-submenu {
+ right: auto;
+ left: 100%; }
+
+.is-dropdown-submenu {
+ position: absolute;
+ top: 0;
+ left: 100%;
+ z-index: 1;
+ display: none;
+ min-width: 200px;
+ border: 1px solid #cacaca;
+ background: #fefefe; }
+ .dropdown .is-dropdown-submenu a {
+ padding: 0.7rem 1rem; }
+ .is-dropdown-submenu .is-dropdown-submenu-parent > a::after {
+ right: 14px; }
+ .is-dropdown-submenu .is-dropdown-submenu-parent.opens-left > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-left-width: 0;
+ border-color: transparent #1779ba transparent transparent;
+ right: auto;
+ left: 5px; }
+ .is-dropdown-submenu .is-dropdown-submenu-parent.opens-right > a::after {
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 6px;
+ content: '';
+ border-right-width: 0;
+ border-color: transparent transparent transparent #1779ba; }
+ .is-dropdown-submenu .is-dropdown-submenu {
+ margin-top: -1px; }
+ .is-dropdown-submenu > li {
+ width: 100%; }
+ .is-dropdown-submenu.js-dropdown-active {
+ display: block; }
+
+.is-off-canvas-open {
+ overflow: hidden; }
+
+.js-off-canvas-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 11;
+ width: 100%;
+ height: 100%;
+ -webkit-transition: opacity 0.5s ease, visibility 0.5s ease;
+ transition: opacity 0.5s ease, visibility 0.5s ease;
+ background: rgba(254, 254, 254, 0.25);
+ opacity: 0;
+ visibility: hidden;
+ overflow: hidden; }
+ .js-off-canvas-overlay.is-visible {
+ opacity: 1;
+ visibility: visible; }
+ .js-off-canvas-overlay.is-closable {
+ cursor: pointer; }
+ .js-off-canvas-overlay.is-overlay-absolute {
+ position: absolute; }
+ .js-off-canvas-overlay.is-overlay-fixed {
+ position: fixed; }
+
+.off-canvas-wrapper {
+ position: relative;
+ overflow: hidden; }
+
+.off-canvas {
+ position: fixed;
+ z-index: 12;
+ -webkit-transition: -webkit-transform 0.5s ease;
+ transition: -webkit-transform 0.5s ease;
+ transition: transform 0.5s ease;
+ transition: transform 0.5s ease, -webkit-transform 0.5s ease;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ background: #e6e6e6; }
+ [data-whatinput='mouse'] .off-canvas {
+ outline: 0; }
+ .off-canvas.is-transition-push {
+ z-index: 12; }
+ .off-canvas.is-closed {
+ visibility: hidden; }
+ .off-canvas.is-transition-overlap {
+ z-index: 13; }
+ .off-canvas.is-transition-overlap.is-open {
+ -webkit-box-shadow: 0 0 10px rgba(10, 10, 10, 0.7);
+ box-shadow: 0 0 10px rgba(10, 10, 10, 0.7); }
+ .off-canvas.is-open {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ transform: translate(0, 0); }
+
+.off-canvas-absolute {
+ position: absolute;
+ z-index: 12;
+ -webkit-transition: -webkit-transform 0.5s ease;
+ transition: -webkit-transform 0.5s ease;
+ transition: transform 0.5s ease;
+ transition: transform 0.5s ease, -webkit-transform 0.5s ease;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ background: #e6e6e6; }
+ [data-whatinput='mouse'] .off-canvas-absolute {
+ outline: 0; }
+ .off-canvas-absolute.is-transition-push {
+ z-index: 12; }
+ .off-canvas-absolute.is-closed {
+ visibility: hidden; }
+ .off-canvas-absolute.is-transition-overlap {
+ z-index: 13; }
+ .off-canvas-absolute.is-transition-overlap.is-open {
+ -webkit-box-shadow: 0 0 10px rgba(10, 10, 10, 0.7);
+ box-shadow: 0 0 10px rgba(10, 10, 10, 0.7); }
+ .off-canvas-absolute.is-open {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ transform: translate(0, 0); }
+
+.position-left {
+ top: 0;
+ left: 0;
+ height: 100%;
+ overflow-y: auto;
+ width: 250px;
+ -webkit-transform: translateX(-250px);
+ -ms-transform: translateX(-250px);
+ transform: translateX(-250px); }
+ .off-canvas-content .off-canvas.position-left {
+ -webkit-transform: translateX(-250px);
+ -ms-transform: translateX(-250px);
+ transform: translateX(-250px); }
+ .off-canvas-content .off-canvas.position-left.is-transition-overlap.is-open {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ transform: translate(0, 0); }
+ .off-canvas-content.is-open-left.has-transition-push {
+ -webkit-transform: translateX(250px);
+ -ms-transform: translateX(250px);
+ transform: translateX(250px); }
+ .position-left.is-transition-push {
+ -webkit-box-shadow: inset -13px 0 20px -13px rgba(10, 10, 10, 0.25);
+ box-shadow: inset -13px 0 20px -13px rgba(10, 10, 10, 0.25); }
+
+.position-right {
+ top: 0;
+ right: 0;
+ height: 100%;
+ overflow-y: auto;
+ width: 250px;
+ -webkit-transform: translateX(250px);
+ -ms-transform: translateX(250px);
+ transform: translateX(250px); }
+ .off-canvas-content .off-canvas.position-right {
+ -webkit-transform: translateX(250px);
+ -ms-transform: translateX(250px);
+ transform: translateX(250px); }
+ .off-canvas-content .off-canvas.position-right.is-transition-overlap.is-open {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ transform: translate(0, 0); }
+ .off-canvas-content.is-open-right.has-transition-push {
+ -webkit-transform: translateX(-250px);
+ -ms-transform: translateX(-250px);
+ transform: translateX(-250px); }
+ .position-right.is-transition-push {
+ -webkit-box-shadow: inset 13px 0 20px -13px rgba(10, 10, 10, 0.25);
+ box-shadow: inset 13px 0 20px -13px rgba(10, 10, 10, 0.25); }
+
+.position-top {
+ top: 0;
+ left: 0;
+ width: 100%;
+ overflow-x: auto;
+ height: 250px;
+ -webkit-transform: translateY(-250px);
+ -ms-transform: translateY(-250px);
+ transform: translateY(-250px); }
+ .off-canvas-content .off-canvas.position-top {
+ -webkit-transform: translateY(-250px);
+ -ms-transform: translateY(-250px);
+ transform: translateY(-250px); }
+ .off-canvas-content .off-canvas.position-top.is-transition-overlap.is-open {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ transform: translate(0, 0); }
+ .off-canvas-content.is-open-top.has-transition-push {
+ -webkit-transform: translateY(250px);
+ -ms-transform: translateY(250px);
+ transform: translateY(250px); }
+ .position-top.is-transition-push {
+ -webkit-box-shadow: inset 0 -13px 20px -13px rgba(10, 10, 10, 0.25);
+ box-shadow: inset 0 -13px 20px -13px rgba(10, 10, 10, 0.25); }
+
+.position-bottom {
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ overflow-x: auto;
+ height: 250px;
+ -webkit-transform: translateY(250px);
+ -ms-transform: translateY(250px);
+ transform: translateY(250px); }
+ .off-canvas-content .off-canvas.position-bottom {
+ -webkit-transform: translateY(250px);
+ -ms-transform: translateY(250px);
+ transform: translateY(250px); }
+ .off-canvas-content .off-canvas.position-bottom.is-transition-overlap.is-open {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ transform: translate(0, 0); }
+ .off-canvas-content.is-open-bottom.has-transition-push {
+ -webkit-transform: translateY(-250px);
+ -ms-transform: translateY(-250px);
+ transform: translateY(-250px); }
+ .position-bottom.is-transition-push {
+ -webkit-box-shadow: inset 0 13px 20px -13px rgba(10, 10, 10, 0.25);
+ box-shadow: inset 0 13px 20px -13px rgba(10, 10, 10, 0.25); }
+
+.off-canvas-content {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden; }
+ .off-canvas-content.has-transition-overlap, .off-canvas-content.has-transition-push {
+ -webkit-transition: -webkit-transform 0.5s ease;
+ transition: -webkit-transform 0.5s ease;
+ transition: transform 0.5s ease;
+ transition: transform 0.5s ease, -webkit-transform 0.5s ease; }
+ .off-canvas-content.has-transition-push {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ transform: translate(0, 0); }
+ .off-canvas-content .off-canvas.is-open {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ transform: translate(0, 0); }
+
+@media print, screen and (min-width: 40em) {
+ .position-left.reveal-for-medium {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ z-index: 12;
+ -webkit-transition: none;
+ transition: none;
+ visibility: visible; }
+ .position-left.reveal-for-medium .close-button {
+ display: none; }
+ .off-canvas-content .position-left.reveal-for-medium {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas-content.has-reveal-left {
+ margin-left: 250px; }
+ .position-left.reveal-for-medium ~ .off-canvas-content {
+ margin-left: 250px; }
+ .position-right.reveal-for-medium {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ z-index: 12;
+ -webkit-transition: none;
+ transition: none;
+ visibility: visible; }
+ .position-right.reveal-for-medium .close-button {
+ display: none; }
+ .off-canvas-content .position-right.reveal-for-medium {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas-content.has-reveal-right {
+ margin-right: 250px; }
+ .position-right.reveal-for-medium ~ .off-canvas-content {
+ margin-right: 250px; }
+ .position-top.reveal-for-medium {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ z-index: 12;
+ -webkit-transition: none;
+ transition: none;
+ visibility: visible; }
+ .position-top.reveal-for-medium .close-button {
+ display: none; }
+ .off-canvas-content .position-top.reveal-for-medium {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas-content.has-reveal-top {
+ margin-top: 250px; }
+ .position-top.reveal-for-medium ~ .off-canvas-content {
+ margin-top: 250px; }
+ .position-bottom.reveal-for-medium {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ z-index: 12;
+ -webkit-transition: none;
+ transition: none;
+ visibility: visible; }
+ .position-bottom.reveal-for-medium .close-button {
+ display: none; }
+ .off-canvas-content .position-bottom.reveal-for-medium {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas-content.has-reveal-bottom {
+ margin-bottom: 250px; }
+ .position-bottom.reveal-for-medium ~ .off-canvas-content {
+ margin-bottom: 250px; } }
+
+@media print, screen and (min-width: 64em) {
+ .position-left.reveal-for-large {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ z-index: 12;
+ -webkit-transition: none;
+ transition: none;
+ visibility: visible; }
+ .position-left.reveal-for-large .close-button {
+ display: none; }
+ .off-canvas-content .position-left.reveal-for-large {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas-content.has-reveal-left {
+ margin-left: 250px; }
+ .position-left.reveal-for-large ~ .off-canvas-content {
+ margin-left: 250px; }
+ .position-right.reveal-for-large {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ z-index: 12;
+ -webkit-transition: none;
+ transition: none;
+ visibility: visible; }
+ .position-right.reveal-for-large .close-button {
+ display: none; }
+ .off-canvas-content .position-right.reveal-for-large {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas-content.has-reveal-right {
+ margin-right: 250px; }
+ .position-right.reveal-for-large ~ .off-canvas-content {
+ margin-right: 250px; }
+ .position-top.reveal-for-large {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ z-index: 12;
+ -webkit-transition: none;
+ transition: none;
+ visibility: visible; }
+ .position-top.reveal-for-large .close-button {
+ display: none; }
+ .off-canvas-content .position-top.reveal-for-large {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas-content.has-reveal-top {
+ margin-top: 250px; }
+ .position-top.reveal-for-large ~ .off-canvas-content {
+ margin-top: 250px; }
+ .position-bottom.reveal-for-large {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ z-index: 12;
+ -webkit-transition: none;
+ transition: none;
+ visibility: visible; }
+ .position-bottom.reveal-for-large .close-button {
+ display: none; }
+ .off-canvas-content .position-bottom.reveal-for-large {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas-content.has-reveal-bottom {
+ margin-bottom: 250px; }
+ .position-bottom.reveal-for-large ~ .off-canvas-content {
+ margin-bottom: 250px; } }
+
+@media print, screen and (min-width: 40em) {
+ .off-canvas.in-canvas-for-medium {
+ visibility: visible;
+ height: auto;
+ position: static;
+ background: none;
+ width: auto;
+ overflow: visible;
+ -webkit-transition: none;
+ transition: none; }
+ .off-canvas.in-canvas-for-medium.position-left, .off-canvas.in-canvas-for-medium.position-right, .off-canvas.in-canvas-for-medium.position-top, .off-canvas.in-canvas-for-medium.position-bottom {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas.in-canvas-for-medium .close-button {
+ display: none; } }
+
+@media print, screen and (min-width: 64em) {
+ .off-canvas.in-canvas-for-large {
+ visibility: visible;
+ height: auto;
+ position: static;
+ background: none;
+ width: auto;
+ overflow: visible;
+ -webkit-transition: none;
+ transition: none; }
+ .off-canvas.in-canvas-for-large.position-left, .off-canvas.in-canvas-for-large.position-right, .off-canvas.in-canvas-for-large.position-top, .off-canvas.in-canvas-for-large.position-bottom {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none; }
+ .off-canvas.in-canvas-for-large .close-button {
+ display: none; } }
+
+html.is-reveal-open {
+ position: fixed;
+ width: 100%;
+ overflow-y: hidden; }
+ html.is-reveal-open.zf-has-scroll {
+ overflow-y: scroll; }
+ html.is-reveal-open body {
+ overflow-y: hidden; }
+
+.reveal-overlay {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1005;
+ display: none;
+ background-color: rgba(10, 10, 10, 0.45);
+ overflow-y: auto; }
+
+.reveal {
+ z-index: 1006;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ display: none;
+ padding: 1rem;
+ border: 1px solid #cacaca;
+ border-radius: 0;
+ background-color: #fefefe;
+ position: relative;
+ top: 100px;
+ margin-right: auto;
+ margin-left: auto;
+ overflow-y: auto; }
+ [data-whatinput='mouse'] .reveal {
+ outline: 0; }
+ @media print, screen and (min-width: 40em) {
+ .reveal {
+ min-height: 0; } }
+ .reveal .column {
+ min-width: 0; }
+ .reveal > :last-child {
+ margin-bottom: 0; }
+ @media print, screen and (min-width: 40em) {
+ .reveal {
+ width: 600px;
+ max-width: 75rem; } }
+ .reveal.collapse {
+ padding: 0; }
+ @media print, screen and (min-width: 40em) {
+ .reveal.tiny {
+ width: 30%;
+ max-width: 75rem; } }
+ @media print, screen and (min-width: 40em) {
+ .reveal.small {
+ width: 50%;
+ max-width: 75rem; } }
+ @media print, screen and (min-width: 40em) {
+ .reveal.large {
+ width: 90%;
+ max-width: 75rem; } }
+ .reveal.full {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ max-width: none;
+ height: 100%;
+ min-height: 100%;
+ margin-left: 0;
+ border: 0;
+ border-radius: 0; }
+ @media print, screen and (max-width: 39.99875em) {
+ .reveal {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ max-width: none;
+ height: 100%;
+ min-height: 100%;
+ margin-left: 0;
+ border: 0;
+ border-radius: 0; } }
+ .reveal.without-overlay {
+ position: fixed; }
+
+.sticky-container {
+ position: relative; }
+
+.sticky {
+ position: relative;
+ z-index: 0;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0); }
+
+.sticky.is-stuck {
+ position: fixed;
+ z-index: 5;
+ width: 100%; }
+ .sticky.is-stuck.is-at-top {
+ top: 0; }
+ .sticky.is-stuck.is-at-bottom {
+ bottom: 0; }
+
+.sticky.is-anchored {
+ position: relative;
+ right: auto;
+ left: auto; }
+ .sticky.is-anchored.is-at-bottom {
+ bottom: 0; }
+
+.title-bar {
+ padding: 0.5rem;
+ background: #0a0a0a;
+ color: #fefefe;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ -webkit-box-align: center;
+ -webkit-align-items: center;
+ -ms-flex-align: center;
+ align-items: center; }
+ .title-bar .menu-icon {
+ margin-left: 0.25rem;
+ margin-right: 0.25rem; }
+
+.title-bar-left,
+.title-bar-right {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 0px;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0px; }
+
+.title-bar-right {
+ text-align: right; }
+
+.title-bar-title {
+ display: inline-block;
+ vertical-align: middle;
+ font-weight: bold; }
+
+.top-bar {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-box-align: center;
+ -webkit-align-items: center;
+ -ms-flex-align: center;
+ align-items: center;
+ padding: 0.5rem;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap; }
+ .top-bar,
+ .top-bar ul {
+ background-color: #e6e6e6; }
+ .top-bar input {
+ max-width: 200px;
+ margin-right: 1rem; }
+ .top-bar .input-group-field {
+ width: 100%;
+ margin-right: 0; }
+ .top-bar input.button {
+ width: auto; }
+ .top-bar .top-bar-left,
+ .top-bar .top-bar-right {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 100%;
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%; }
+ @media print, screen and (min-width: 40em) {
+ .top-bar {
+ -webkit-flex-wrap: nowrap;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap; }
+ .top-bar .top-bar-left {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ margin-right: auto; }
+ .top-bar .top-bar-right {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 1 auto;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto;
+ margin-left: auto; } }
+ @media print, screen and (max-width: 63.99875em) {
+ .top-bar.stacked-for-medium {
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap; }
+ .top-bar.stacked-for-medium .top-bar-left,
+ .top-bar.stacked-for-medium .top-bar-right {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 100%;
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%; } }
+ @media print, screen and (max-width: 74.99875em) {
+ .top-bar.stacked-for-large {
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap; }
+ .top-bar.stacked-for-large .top-bar-left,
+ .top-bar.stacked-for-large .top-bar-right {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 100%;
+ -ms-flex: 0 0 100%;
+ flex: 0 0 100%;
+ max-width: 100%; } }
+
+.top-bar-title {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ margin: 0.5rem 1rem 0.5rem 0; }
+
+.top-bar-left,
+.top-bar-right {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto; }
+
+.float-left {
+ float: left !important; }
+
+.float-right {
+ float: right !important; }
+
+.float-center {
+ display: block;
+ margin-right: auto;
+ margin-left: auto; }
+
+.clearfix::before, .clearfix::after {
+ display: table;
+ content: ' ';
+ -webkit-flex-basis: 0;
+ -ms-flex-preferred-size: 0;
+ flex-basis: 0;
+ -webkit-box-ordinal-group: 2;
+ -webkit-order: 1;
+ -ms-flex-order: 1;
+ order: 1; }
+
+.clearfix::after {
+ clear: both; }
+
+.align-left {
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start; }
+
+.align-right {
+ -webkit-box-pack: end;
+ -webkit-justify-content: flex-end;
+ -ms-flex-pack: end;
+ justify-content: flex-end; }
+
+.align-center {
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center; }
+
+.align-justify {
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ -ms-flex-pack: justify;
+ justify-content: space-between; }
+
+.align-spaced {
+ -webkit-justify-content: space-around;
+ -ms-flex-pack: distribute;
+ justify-content: space-around; }
+
+.align-left.vertical.menu > li > a {
+ -webkit-box-pack: start;
+ -webkit-justify-content: flex-start;
+ -ms-flex-pack: start;
+ justify-content: flex-start; }
+
+.align-right.vertical.menu > li > a {
+ -webkit-box-pack: end;
+ -webkit-justify-content: flex-end;
+ -ms-flex-pack: end;
+ justify-content: flex-end; }
+
+.align-center.vertical.menu > li > a {
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center; }
+
+.align-top {
+ -webkit-box-align: start;
+ -webkit-align-items: flex-start;
+ -ms-flex-align: start;
+ align-items: flex-start; }
+
+.align-self-top {
+ -webkit-align-self: flex-start;
+ -ms-flex-item-align: start;
+ align-self: flex-start; }
+
+.align-bottom {
+ -webkit-box-align: end;
+ -webkit-align-items: flex-end;
+ -ms-flex-align: end;
+ align-items: flex-end; }
+
+.align-self-bottom {
+ -webkit-align-self: flex-end;
+ -ms-flex-item-align: end;
+ align-self: flex-end; }
+
+.align-middle {
+ -webkit-box-align: center;
+ -webkit-align-items: center;
+ -ms-flex-align: center;
+ align-items: center; }
+
+.align-self-middle {
+ -webkit-align-self: center;
+ -ms-flex-item-align: center;
+ align-self: center; }
+
+.align-stretch {
+ -webkit-box-align: stretch;
+ -webkit-align-items: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch; }
+
+.align-self-stretch {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch; }
+
+.align-center-middle {
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -webkit-align-items: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-align-content: center;
+ -ms-flex-line-pack: center;
+ align-content: center; }
+
+.small-order-1 {
+ -webkit-box-ordinal-group: 2;
+ -webkit-order: 1;
+ -ms-flex-order: 1;
+ order: 1; }
+
+.small-order-2 {
+ -webkit-box-ordinal-group: 3;
+ -webkit-order: 2;
+ -ms-flex-order: 2;
+ order: 2; }
+
+.small-order-3 {
+ -webkit-box-ordinal-group: 4;
+ -webkit-order: 3;
+ -ms-flex-order: 3;
+ order: 3; }
+
+.small-order-4 {
+ -webkit-box-ordinal-group: 5;
+ -webkit-order: 4;
+ -ms-flex-order: 4;
+ order: 4; }
+
+.small-order-5 {
+ -webkit-box-ordinal-group: 6;
+ -webkit-order: 5;
+ -ms-flex-order: 5;
+ order: 5; }
+
+.small-order-6 {
+ -webkit-box-ordinal-group: 7;
+ -webkit-order: 6;
+ -ms-flex-order: 6;
+ order: 6; }
+
+@media print, screen and (min-width: 40em) {
+ .medium-order-1 {
+ -webkit-box-ordinal-group: 2;
+ -webkit-order: 1;
+ -ms-flex-order: 1;
+ order: 1; }
+ .medium-order-2 {
+ -webkit-box-ordinal-group: 3;
+ -webkit-order: 2;
+ -ms-flex-order: 2;
+ order: 2; }
+ .medium-order-3 {
+ -webkit-box-ordinal-group: 4;
+ -webkit-order: 3;
+ -ms-flex-order: 3;
+ order: 3; }
+ .medium-order-4 {
+ -webkit-box-ordinal-group: 5;
+ -webkit-order: 4;
+ -ms-flex-order: 4;
+ order: 4; }
+ .medium-order-5 {
+ -webkit-box-ordinal-group: 6;
+ -webkit-order: 5;
+ -ms-flex-order: 5;
+ order: 5; }
+ .medium-order-6 {
+ -webkit-box-ordinal-group: 7;
+ -webkit-order: 6;
+ -ms-flex-order: 6;
+ order: 6; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-order-1 {
+ -webkit-box-ordinal-group: 2;
+ -webkit-order: 1;
+ -ms-flex-order: 1;
+ order: 1; }
+ .large-order-2 {
+ -webkit-box-ordinal-group: 3;
+ -webkit-order: 2;
+ -ms-flex-order: 2;
+ order: 2; }
+ .large-order-3 {
+ -webkit-box-ordinal-group: 4;
+ -webkit-order: 3;
+ -ms-flex-order: 3;
+ order: 3; }
+ .large-order-4 {
+ -webkit-box-ordinal-group: 5;
+ -webkit-order: 4;
+ -ms-flex-order: 4;
+ order: 4; }
+ .large-order-5 {
+ -webkit-box-ordinal-group: 6;
+ -webkit-order: 5;
+ -ms-flex-order: 5;
+ order: 5; }
+ .large-order-6 {
+ -webkit-box-ordinal-group: 7;
+ -webkit-order: 6;
+ -ms-flex-order: 6;
+ order: 6; } }
+
+.flex-container {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex; }
+
+.flex-child-auto {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto; }
+
+.flex-child-grow {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 0 auto;
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto; }
+
+.flex-child-shrink {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 1 auto;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto; }
+
+.flex-dir-row {
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row; }
+
+.flex-dir-row-reverse {
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: reverse;
+ -webkit-flex-direction: row-reverse;
+ -ms-flex-direction: row-reverse;
+ flex-direction: row-reverse; }
+
+.flex-dir-column {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column; }
+
+.flex-dir-column-reverse {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: reverse;
+ -webkit-flex-direction: column-reverse;
+ -ms-flex-direction: column-reverse;
+ flex-direction: column-reverse; }
+
+@media print, screen and (min-width: 40em) {
+ .medium-flex-container {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex; }
+ .medium-flex-child-auto {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto; }
+ .medium-flex-child-grow {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 0 auto;
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto; }
+ .medium-flex-child-shrink {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 1 auto;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto; }
+ .medium-flex-dir-row {
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row; }
+ .medium-flex-dir-row-reverse {
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: reverse;
+ -webkit-flex-direction: row-reverse;
+ -ms-flex-direction: row-reverse;
+ flex-direction: row-reverse; }
+ .medium-flex-dir-column {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column; }
+ .medium-flex-dir-column-reverse {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: reverse;
+ -webkit-flex-direction: column-reverse;
+ -ms-flex-direction: column-reverse;
+ flex-direction: column-reverse; } }
+
+@media print, screen and (min-width: 64em) {
+ .large-flex-container {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex; }
+ .large-flex-child-auto {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto; }
+ .large-flex-child-grow {
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 0 auto;
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto; }
+ .large-flex-child-shrink {
+ -webkit-box-flex: 0;
+ -webkit-flex: 0 1 auto;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto; }
+ .large-flex-dir-row {
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row; }
+ .large-flex-dir-row-reverse {
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: reverse;
+ -webkit-flex-direction: row-reverse;
+ -ms-flex-direction: row-reverse;
+ flex-direction: row-reverse; }
+ .large-flex-dir-column {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column; }
+ .large-flex-dir-column-reverse {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: reverse;
+ -webkit-flex-direction: column-reverse;
+ -ms-flex-direction: column-reverse;
+ flex-direction: column-reverse; } }
+
+.hide {
+ display: none !important; }
+
+.invisible {
+ visibility: hidden; }
+
+.visible {
+ visibility: visible; }
+
+@media print, screen and (max-width: 39.99875em) {
+ .hide-for-small-only {
+ display: none !important; } }
+
+@media screen and (max-width: 0em), screen and (min-width: 40em) {
+ .show-for-small-only {
+ display: none !important; } }
+
+@media print, screen and (min-width: 40em) {
+ .hide-for-medium {
+ display: none !important; } }
+
+@media screen and (max-width: 39.99875em) {
+ .show-for-medium {
+ display: none !important; } }
+
+@media print, screen and (min-width: 40em) and (max-width: 63.99875em) {
+ .hide-for-medium-only {
+ display: none !important; } }
+
+@media screen and (max-width: 39.99875em), screen and (min-width: 64em) {
+ .show-for-medium-only {
+ display: none !important; } }
+
+@media print, screen and (min-width: 64em) {
+ .hide-for-large {
+ display: none !important; } }
+
+@media screen and (max-width: 63.99875em) {
+ .show-for-large {
+ display: none !important; } }
+
+@media print, screen and (min-width: 64em) and (max-width: 74.99875em) {
+ .hide-for-large-only {
+ display: none !important; } }
+
+@media screen and (max-width: 63.99875em), screen and (min-width: 75em) {
+ .show-for-large-only {
+ display: none !important; } }
+
+.show-for-sr,
+.show-on-focus {
+ position: absolute !important;
+ width: 1px !important;
+ height: 1px !important;
+ padding: 0 !important;
+ overflow: hidden !important;
+ clip: rect(0, 0, 0, 0) !important;
+ white-space: nowrap !important;
+ border: 0 !important; }
+
+.show-on-focus:active, .show-on-focus:focus {
+ position: static !important;
+ width: auto !important;
+ height: auto !important;
+ overflow: visible !important;
+ clip: auto !important;
+ white-space: normal !important; }
+
+.show-for-landscape,
+.hide-for-portrait {
+ display: block !important; }
+ @media screen and (orientation: landscape) {
+ .show-for-landscape,
+ .hide-for-portrait {
+ display: block !important; } }
+ @media screen and (orientation: portrait) {
+ .show-for-landscape,
+ .hide-for-portrait {
+ display: none !important; } }
+
+.hide-for-landscape,
+.show-for-portrait {
+ display: none !important; }
+ @media screen and (orientation: landscape) {
+ .hide-for-landscape,
+ .show-for-portrait {
+ display: none !important; } }
+ @media screen and (orientation: portrait) {
+ .hide-for-landscape,
+ .show-for-portrait {
+ display: block !important; } }
+
+/*# sourceMappingURL=foundation.css.map */
diff --git a/pkgs/csslib/third_party/foundation/foundation.min.css b/pkgs/csslib/third_party/foundation/foundation.min.css
new file mode 100644
index 0000000..dec4fbf
--- /dev/null
+++ b/pkgs/csslib/third_party/foundation/foundation.min.css
@@ -0,0 +1,2 @@
+@charset "UTF-8";@media print,screen and (min-width:40em){.reveal,.reveal.large,.reveal.small,.reveal.tiny{right:auto;left:auto;margin:0 auto}}/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}.foundation-mq{font-family:"small=0em&medium=40em&large=64em&xlarge=75em&xxlarge=90em"}html{-webkit-box-sizing:border-box;box-sizing:border-box;font-size:100%}*,::after,::before{-webkit-box-sizing:inherit;box-sizing:inherit}body{margin:0;padding:0;background:#fefefe;font-family:"Helvetica Neue",Helvetica,Roboto,Arial,sans-serif;font-weight:400;line-height:1.5;color:#0a0a0a;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}img{display:inline-block;vertical-align:middle;max-width:100%;height:auto;-ms-interpolation-mode:bicubic}textarea{height:auto;min-height:50px;border-radius:0}select{-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;border-radius:0}.map_canvas embed,.map_canvas img,.map_canvas object,.mqa-display embed,.mqa-display img,.mqa-display object{max-width:none!important}button{padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;border-radius:0;background:0 0;line-height:1;cursor:auto}[data-whatinput=mouse] button{outline:0}pre{overflow:auto}button,input,optgroup,select,textarea{font-family:inherit}.is-visible{display:block!important}.is-hidden{display:none!important}[type=color],[type=date],[type=datetime-local],[type=datetime],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],textarea{display:block;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;height:2.4375rem;margin:0 0 1rem;padding:.5rem;border:1px solid #cacaca;border-radius:0;background-color:#fefefe;-webkit-box-shadow:inset 0 1px 2px rgba(10,10,10,.1);box-shadow:inset 0 1px 2px rgba(10,10,10,.1);font-family:inherit;font-size:1rem;font-weight:400;line-height:1.5;color:#0a0a0a;-webkit-transition:border-color .25s ease-in-out,-webkit-box-shadow .5s;transition:border-color .25s ease-in-out,-webkit-box-shadow .5s;transition:box-shadow .5s,border-color .25s ease-in-out;transition:box-shadow .5s,border-color .25s ease-in-out,-webkit-box-shadow .5s;-webkit-appearance:none;-moz-appearance:none;appearance:none}[type=color]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=datetime]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,textarea:focus{outline:0;border:1px solid #8a8a8a;background-color:#fefefe;-webkit-box-shadow:0 0 5px #cacaca;box-shadow:0 0 5px #cacaca;-webkit-transition:border-color .25s ease-in-out,-webkit-box-shadow .5s;transition:border-color .25s ease-in-out,-webkit-box-shadow .5s;transition:box-shadow .5s,border-color .25s ease-in-out;transition:box-shadow .5s,border-color .25s ease-in-out,-webkit-box-shadow .5s}textarea{max-width:100%}textarea[rows]{height:auto}input:disabled,input[readonly],textarea:disabled,textarea[readonly]{background-color:#e6e6e6;cursor:not-allowed}[type=button],[type=submit]{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:0}input[type=search]{-webkit-box-sizing:border-box;box-sizing:border-box}::-webkit-input-placeholder{color:#cacaca}::-moz-placeholder{color:#cacaca}:-ms-input-placeholder{color:#cacaca}::-ms-input-placeholder{color:#cacaca}::placeholder{color:#cacaca}[type=checkbox],[type=file],[type=radio]{margin:0 0 1rem}[type=checkbox]+label,[type=radio]+label{display:inline-block;vertical-align:baseline;margin-left:.5rem;margin-right:1rem;margin-bottom:0}[type=checkbox]+label[for],[type=radio]+label[for]{cursor:pointer}label>[type=checkbox],label>[type=radio]{margin-right:.5rem}[type=file]{width:100%}label{display:block;margin:0;font-size:.875rem;font-weight:400;line-height:1.8;color:#0a0a0a}label.middle{margin:0 0 1rem;line-height:1.5;padding:.5625rem 0}.help-text{margin-top:-.5rem;font-size:.8125rem;font-style:italic;color:#0a0a0a}.input-group{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;margin-bottom:1rem;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch}.input-group>:first-child,.input-group>:first-child.input-group-button>*{border-radius:0}.input-group>:last-child,.input-group>:last-child.input-group-button>*{border-radius:0}.input-group-button,.input-group-button a,.input-group-button button,.input-group-button input,.input-group-button label,.input-group-field,.input-group-label{margin:0;white-space:nowrap}.input-group-label{padding:0 1rem;border:1px solid #cacaca;background:#e6e6e6;color:#0a0a0a;text-align:center;white-space:nowrap;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.input-group-label:first-child{border-right:0}.input-group-label:last-child{border-left:0}.input-group-field{border-radius:0;-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px;min-width:0}.input-group-button{padding-top:0;padding-bottom:0;text-align:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.input-group-button a,.input-group-button button,.input-group-button input,.input-group-button label{-webkit-align-self:stretch;-ms-flex-item-align:stretch;align-self:stretch;height:auto;padding-top:0;padding-bottom:0;font-size:1rem}fieldset{margin:0;padding:0;border:0}legend{max-width:100%;margin-bottom:.5rem}.fieldset{margin:1.125rem 0;padding:1.25rem;border:1px solid #cacaca}.fieldset legend{margin:0;margin-left:-.1875rem;padding:0 .1875rem}select{height:2.4375rem;margin:0 0 1rem;padding:.5rem;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:1px solid #cacaca;border-radius:0;background-color:#fefefe;font-family:inherit;font-size:1rem;font-weight:400;line-height:1.5;color:#0a0a0a;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='32' height='24' viewBox='0 0 32 24'><polygon points='0,0 32,0 16,24' style='fill: rgb%28138, 138, 138%29'></polygon></svg>");background-origin:content-box;background-position:right -1rem center;background-repeat:no-repeat;background-size:9px 6px;padding-right:1.5rem;-webkit-transition:border-color .25s ease-in-out,-webkit-box-shadow .5s;transition:border-color .25s ease-in-out,-webkit-box-shadow .5s;transition:box-shadow .5s,border-color .25s ease-in-out;transition:box-shadow .5s,border-color .25s ease-in-out,-webkit-box-shadow .5s}@media screen and (min-width:0\0){select{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIpJREFUeNrEkckNgDAMBBfRkEt0ObRBBdsGXUDgmQfK4XhH2m8czQAAy27R3tsw4Qfe2x8uOO6oYLb6GlOor3GF+swURAOmUJ+RwtEJs9WvTGEYxBXqI1MQAZhCfUQKRzDMVj+TwrAIV6jvSUEkYAr1LSkcyTBb/V+KYfX7xAeusq3sLDtGH3kEGACPWIflNZfhRQAAAABJRU5ErkJggg==)}}select:focus{outline:0;border:1px solid #8a8a8a;background-color:#fefefe;-webkit-box-shadow:0 0 5px #cacaca;box-shadow:0 0 5px #cacaca;-webkit-transition:border-color .25s ease-in-out,-webkit-box-shadow .5s;transition:border-color .25s ease-in-out,-webkit-box-shadow .5s;transition:box-shadow .5s,border-color .25s ease-in-out;transition:box-shadow .5s,border-color .25s ease-in-out,-webkit-box-shadow .5s}select:disabled{background-color:#e6e6e6;cursor:not-allowed}select::-ms-expand{display:none}select[multiple]{height:auto;background-image:none}select:not([multiple]){padding-top:0;padding-bottom:0}.is-invalid-input:not(:focus){border-color:#cc4b37;background-color:#f9ecea}.is-invalid-input:not(:focus)::-webkit-input-placeholder{color:#cc4b37}.is-invalid-input:not(:focus)::-moz-placeholder{color:#cc4b37}.is-invalid-input:not(:focus):-ms-input-placeholder{color:#cc4b37}.is-invalid-input:not(:focus)::-ms-input-placeholder{color:#cc4b37}.is-invalid-input:not(:focus)::placeholder{color:#cc4b37}.is-invalid-label{color:#cc4b37}.form-error{display:none;margin-top:-.5rem;margin-bottom:1rem;font-size:.75rem;font-weight:700;color:#cc4b37}.form-error.is-visible{display:block}blockquote,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,li,ol,p,pre,td,th,ul{margin:0;padding:0}p{margin-bottom:1rem;font-size:inherit;line-height:1.6;text-rendering:optimizeLegibility}em,i{font-style:italic;line-height:inherit}b,strong{font-weight:700;line-height:inherit}small{font-size:80%;line-height:inherit}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:"Helvetica Neue",Helvetica,Roboto,Arial,sans-serif;font-style:normal;font-weight:400;color:inherit;text-rendering:optimizeLegibility}.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{line-height:0;color:#cacaca}.h1,h1{font-size:1.5rem;line-height:1.4;margin-top:0;margin-bottom:.5rem}.h2,h2{font-size:1.25rem;line-height:1.4;margin-top:0;margin-bottom:.5rem}.h3,h3{font-size:1.1875rem;line-height:1.4;margin-top:0;margin-bottom:.5rem}.h4,h4{font-size:1.125rem;line-height:1.4;margin-top:0;margin-bottom:.5rem}.h5,h5{font-size:1.0625rem;line-height:1.4;margin-top:0;margin-bottom:.5rem}.h6,h6{font-size:1rem;line-height:1.4;margin-top:0;margin-bottom:.5rem}@media print,screen and (min-width:40em){.h1,h1{font-size:3rem}.h2,h2{font-size:2.5rem}.h3,h3{font-size:1.9375rem}.h4,h4{font-size:1.5625rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}}a{line-height:inherit;color:#1779ba;text-decoration:none;cursor:pointer}a:focus,a:hover{color:#1468a0}a img{border:0}hr{clear:both;max-width:75rem;height:0;margin:1.25rem auto;border-top:0;border-right:0;border-bottom:1px solid #cacaca;border-left:0}dl,ol,ul{margin-bottom:1rem;list-style-position:outside;line-height:1.6}li{font-size:inherit}ul{margin-left:1.25rem;list-style-type:disc}ol{margin-left:1.25rem}ol ol,ol ul,ul ol,ul ul{margin-left:1.25rem;margin-bottom:0}dl{margin-bottom:1rem}dl dt{margin-bottom:.3rem;font-weight:700}blockquote{margin:0 0 1rem;padding:.5625rem 1.25rem 0 1.1875rem;border-left:1px solid #cacaca}blockquote,blockquote p{line-height:1.6;color:#8a8a8a}abbr,abbr[title]{border-bottom:1px dotted #0a0a0a;cursor:help;text-decoration:none}figure{margin:0}kbd{margin:0;padding:.125rem .25rem 0;background-color:#e6e6e6;font-family:Consolas,"Liberation Mono",Courier,monospace;color:#0a0a0a}.subheader{margin-top:.2rem;margin-bottom:.5rem;font-weight:400;line-height:1.4;color:#8a8a8a}.lead{font-size:125%;line-height:1.6}.stat{font-size:2.5rem;line-height:1}p+.stat{margin-top:-1rem}ol.no-bullet,ul.no-bullet{margin-left:0;list-style:none}.cite-block,cite{display:block;color:#8a8a8a;font-size:.8125rem}.cite-block:before,cite:before{content:"— "}.code-inline,code{border:1px solid #cacaca;background-color:#e6e6e6;font-family:Consolas,"Liberation Mono",Courier,monospace;font-weight:400;color:#0a0a0a;display:inline;max-width:100%;word-wrap:break-word;padding:.125rem .3125rem .0625rem}.code-block{border:1px solid #cacaca;background-color:#e6e6e6;font-family:Consolas,"Liberation Mono",Courier,monospace;font-weight:400;color:#0a0a0a;display:block;overflow:auto;white-space:pre;padding:1rem;margin-bottom:1.5rem}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}@media print,screen and (min-width:40em){.medium-text-left{text-align:left}.medium-text-right{text-align:right}.medium-text-center{text-align:center}.medium-text-justify{text-align:justify}}@media print,screen and (min-width:64em){.large-text-left{text-align:left}.large-text-right{text-align:right}.large-text-center{text-align:center}.large-text-justify{text-align:justify}}.show-for-print{display:none!important}@media print{*{background:0 0!important;color:#000!important;-webkit-print-color-adjust:economy;color-adjust:economy;-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}.show-for-print{display:block!important}.hide-for-print{display:none!important}table.show-for-print{display:table!important}thead.show-for-print{display:table-header-group!important}tbody.show-for-print{display:table-row-group!important}tr.show-for-print{display:table-row!important}td.show-for-print{display:table-cell!important}th.show-for-print{display:table-cell!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}.ir a:after,a[href^='#']:after,a[href^='javascript:']:after{content:''}abbr[title]:after{content:" (" attr(title) ")"}blockquote,pre{border:1px solid #8a8a8a;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.print-break-inside{page-break-inside:auto}}.grid-container{padding-right:.625rem;padding-left:.625rem;max-width:75rem;margin-left:auto;margin-right:auto}@media print,screen and (min-width:40em){.grid-container{padding-right:.9375rem;padding-left:.9375rem}}.grid-container.fluid{padding-right:.625rem;padding-left:.625rem;max-width:100%;margin-left:auto;margin-right:auto}@media print,screen and (min-width:40em){.grid-container.fluid{padding-right:.9375rem;padding-left:.9375rem}}.grid-container.full{padding-right:0;padding-left:0;max-width:100%;margin-left:auto;margin-right:auto}.grid-x{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-flow:row wrap;-ms-flex-flow:row wrap;flex-flow:row wrap}.cell{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;min-height:0;min-width:0;width:100%}.cell.auto{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}.cell.shrink{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.grid-x>.auto{width:auto}.grid-x>.shrink{width:auto}.grid-x>.small-1,.grid-x>.small-10,.grid-x>.small-11,.grid-x>.small-12,.grid-x>.small-2,.grid-x>.small-3,.grid-x>.small-4,.grid-x>.small-5,.grid-x>.small-6,.grid-x>.small-7,.grid-x>.small-8,.grid-x>.small-9,.grid-x>.small-full,.grid-x>.small-shrink{-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto}@media print,screen and (min-width:40em){.grid-x>.medium-1,.grid-x>.medium-10,.grid-x>.medium-11,.grid-x>.medium-12,.grid-x>.medium-2,.grid-x>.medium-3,.grid-x>.medium-4,.grid-x>.medium-5,.grid-x>.medium-6,.grid-x>.medium-7,.grid-x>.medium-8,.grid-x>.medium-9,.grid-x>.medium-full,.grid-x>.medium-shrink{-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto}}@media print,screen and (min-width:64em){.grid-x>.large-1,.grid-x>.large-10,.grid-x>.large-11,.grid-x>.large-12,.grid-x>.large-2,.grid-x>.large-3,.grid-x>.large-4,.grid-x>.large-5,.grid-x>.large-6,.grid-x>.large-7,.grid-x>.large-8,.grid-x>.large-9,.grid-x>.large-full,.grid-x>.large-shrink{-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto}}.grid-x>.small-1,.grid-x>.small-10,.grid-x>.small-11,.grid-x>.small-12,.grid-x>.small-2,.grid-x>.small-3,.grid-x>.small-4,.grid-x>.small-5,.grid-x>.small-6,.grid-x>.small-7,.grid-x>.small-8,.grid-x>.small-9{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.grid-x>.small-1{width:8.33333%}.grid-x>.small-2{width:16.66667%}.grid-x>.small-3{width:25%}.grid-x>.small-4{width:33.33333%}.grid-x>.small-5{width:41.66667%}.grid-x>.small-6{width:50%}.grid-x>.small-7{width:58.33333%}.grid-x>.small-8{width:66.66667%}.grid-x>.small-9{width:75%}.grid-x>.small-10{width:83.33333%}.grid-x>.small-11{width:91.66667%}.grid-x>.small-12{width:100%}@media print,screen and (min-width:40em){.grid-x>.medium-auto{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px;width:auto}.grid-x>.medium-1,.grid-x>.medium-10,.grid-x>.medium-11,.grid-x>.medium-12,.grid-x>.medium-2,.grid-x>.medium-3,.grid-x>.medium-4,.grid-x>.medium-5,.grid-x>.medium-6,.grid-x>.medium-7,.grid-x>.medium-8,.grid-x>.medium-9,.grid-x>.medium-shrink{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.grid-x>.medium-shrink{width:auto}.grid-x>.medium-1{width:8.33333%}.grid-x>.medium-2{width:16.66667%}.grid-x>.medium-3{width:25%}.grid-x>.medium-4{width:33.33333%}.grid-x>.medium-5{width:41.66667%}.grid-x>.medium-6{width:50%}.grid-x>.medium-7{width:58.33333%}.grid-x>.medium-8{width:66.66667%}.grid-x>.medium-9{width:75%}.grid-x>.medium-10{width:83.33333%}.grid-x>.medium-11{width:91.66667%}.grid-x>.medium-12{width:100%}}@media print,screen and (min-width:64em){.grid-x>.large-auto{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px;width:auto}.grid-x>.large-1,.grid-x>.large-10,.grid-x>.large-11,.grid-x>.large-12,.grid-x>.large-2,.grid-x>.large-3,.grid-x>.large-4,.grid-x>.large-5,.grid-x>.large-6,.grid-x>.large-7,.grid-x>.large-8,.grid-x>.large-9,.grid-x>.large-shrink{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.grid-x>.large-shrink{width:auto}.grid-x>.large-1{width:8.33333%}.grid-x>.large-2{width:16.66667%}.grid-x>.large-3{width:25%}.grid-x>.large-4{width:33.33333%}.grid-x>.large-5{width:41.66667%}.grid-x>.large-6{width:50%}.grid-x>.large-7{width:58.33333%}.grid-x>.large-8{width:66.66667%}.grid-x>.large-9{width:75%}.grid-x>.large-10{width:83.33333%}.grid-x>.large-11{width:91.66667%}.grid-x>.large-12{width:100%}}.grid-margin-x:not(.grid-x)>.cell{width:auto}.grid-margin-y:not(.grid-y)>.cell{height:auto}.grid-margin-x{margin-left:-.625rem;margin-right:-.625rem}@media print,screen and (min-width:40em){.grid-margin-x{margin-left:-.9375rem;margin-right:-.9375rem}}.grid-margin-x>.cell{width:calc(100% - 1.25rem);margin-left:.625rem;margin-right:.625rem}@media print,screen and (min-width:40em){.grid-margin-x>.cell{width:calc(100% - 1.875rem);margin-left:.9375rem;margin-right:.9375rem}}.grid-margin-x>.auto{width:auto}.grid-margin-x>.shrink{width:auto}.grid-margin-x>.small-1{width:calc(8.33333% - 1.25rem)}.grid-margin-x>.small-2{width:calc(16.66667% - 1.25rem)}.grid-margin-x>.small-3{width:calc(25% - 1.25rem)}.grid-margin-x>.small-4{width:calc(33.33333% - 1.25rem)}.grid-margin-x>.small-5{width:calc(41.66667% - 1.25rem)}.grid-margin-x>.small-6{width:calc(50% - 1.25rem)}.grid-margin-x>.small-7{width:calc(58.33333% - 1.25rem)}.grid-margin-x>.small-8{width:calc(66.66667% - 1.25rem)}.grid-margin-x>.small-9{width:calc(75% - 1.25rem)}.grid-margin-x>.small-10{width:calc(83.33333% - 1.25rem)}.grid-margin-x>.small-11{width:calc(91.66667% - 1.25rem)}.grid-margin-x>.small-12{width:calc(100% - 1.25rem)}@media print,screen and (min-width:40em){.grid-margin-x>.auto{width:auto}.grid-margin-x>.shrink{width:auto}.grid-margin-x>.small-1{width:calc(8.33333% - 1.875rem)}.grid-margin-x>.small-2{width:calc(16.66667% - 1.875rem)}.grid-margin-x>.small-3{width:calc(25% - 1.875rem)}.grid-margin-x>.small-4{width:calc(33.33333% - 1.875rem)}.grid-margin-x>.small-5{width:calc(41.66667% - 1.875rem)}.grid-margin-x>.small-6{width:calc(50% - 1.875rem)}.grid-margin-x>.small-7{width:calc(58.33333% - 1.875rem)}.grid-margin-x>.small-8{width:calc(66.66667% - 1.875rem)}.grid-margin-x>.small-9{width:calc(75% - 1.875rem)}.grid-margin-x>.small-10{width:calc(83.33333% - 1.875rem)}.grid-margin-x>.small-11{width:calc(91.66667% - 1.875rem)}.grid-margin-x>.small-12{width:calc(100% - 1.875rem)}.grid-margin-x>.medium-auto{width:auto}.grid-margin-x>.medium-shrink{width:auto}.grid-margin-x>.medium-1{width:calc(8.33333% - 1.875rem)}.grid-margin-x>.medium-2{width:calc(16.66667% - 1.875rem)}.grid-margin-x>.medium-3{width:calc(25% - 1.875rem)}.grid-margin-x>.medium-4{width:calc(33.33333% - 1.875rem)}.grid-margin-x>.medium-5{width:calc(41.66667% - 1.875rem)}.grid-margin-x>.medium-6{width:calc(50% - 1.875rem)}.grid-margin-x>.medium-7{width:calc(58.33333% - 1.875rem)}.grid-margin-x>.medium-8{width:calc(66.66667% - 1.875rem)}.grid-margin-x>.medium-9{width:calc(75% - 1.875rem)}.grid-margin-x>.medium-10{width:calc(83.33333% - 1.875rem)}.grid-margin-x>.medium-11{width:calc(91.66667% - 1.875rem)}.grid-margin-x>.medium-12{width:calc(100% - 1.875rem)}}@media print,screen and (min-width:64em){.grid-margin-x>.large-auto{width:auto}.grid-margin-x>.large-shrink{width:auto}.grid-margin-x>.large-1{width:calc(8.33333% - 1.875rem)}.grid-margin-x>.large-2{width:calc(16.66667% - 1.875rem)}.grid-margin-x>.large-3{width:calc(25% - 1.875rem)}.grid-margin-x>.large-4{width:calc(33.33333% - 1.875rem)}.grid-margin-x>.large-5{width:calc(41.66667% - 1.875rem)}.grid-margin-x>.large-6{width:calc(50% - 1.875rem)}.grid-margin-x>.large-7{width:calc(58.33333% - 1.875rem)}.grid-margin-x>.large-8{width:calc(66.66667% - 1.875rem)}.grid-margin-x>.large-9{width:calc(75% - 1.875rem)}.grid-margin-x>.large-10{width:calc(83.33333% - 1.875rem)}.grid-margin-x>.large-11{width:calc(91.66667% - 1.875rem)}.grid-margin-x>.large-12{width:calc(100% - 1.875rem)}}.grid-padding-x .grid-padding-x{margin-right:-.625rem;margin-left:-.625rem}@media print,screen and (min-width:40em){.grid-padding-x .grid-padding-x{margin-right:-.9375rem;margin-left:-.9375rem}}.grid-container:not(.full)>.grid-padding-x{margin-right:-.625rem;margin-left:-.625rem}@media print,screen and (min-width:40em){.grid-container:not(.full)>.grid-padding-x{margin-right:-.9375rem;margin-left:-.9375rem}}.grid-padding-x>.cell{padding-right:.625rem;padding-left:.625rem}@media print,screen and (min-width:40em){.grid-padding-x>.cell{padding-right:.9375rem;padding-left:.9375rem}}.small-up-1>.cell{width:100%}.small-up-2>.cell{width:50%}.small-up-3>.cell{width:33.33333%}.small-up-4>.cell{width:25%}.small-up-5>.cell{width:20%}.small-up-6>.cell{width:16.66667%}.small-up-7>.cell{width:14.28571%}.small-up-8>.cell{width:12.5%}@media print,screen and (min-width:40em){.medium-up-1>.cell{width:100%}.medium-up-2>.cell{width:50%}.medium-up-3>.cell{width:33.33333%}.medium-up-4>.cell{width:25%}.medium-up-5>.cell{width:20%}.medium-up-6>.cell{width:16.66667%}.medium-up-7>.cell{width:14.28571%}.medium-up-8>.cell{width:12.5%}}@media print,screen and (min-width:64em){.large-up-1>.cell{width:100%}.large-up-2>.cell{width:50%}.large-up-3>.cell{width:33.33333%}.large-up-4>.cell{width:25%}.large-up-5>.cell{width:20%}.large-up-6>.cell{width:16.66667%}.large-up-7>.cell{width:14.28571%}.large-up-8>.cell{width:12.5%}}.grid-margin-x.small-up-1>.cell{width:calc(100% - 1.25rem)}.grid-margin-x.small-up-2>.cell{width:calc(50% - 1.25rem)}.grid-margin-x.small-up-3>.cell{width:calc(33.33333% - 1.25rem)}.grid-margin-x.small-up-4>.cell{width:calc(25% - 1.25rem)}.grid-margin-x.small-up-5>.cell{width:calc(20% - 1.25rem)}.grid-margin-x.small-up-6>.cell{width:calc(16.66667% - 1.25rem)}.grid-margin-x.small-up-7>.cell{width:calc(14.28571% - 1.25rem)}.grid-margin-x.small-up-8>.cell{width:calc(12.5% - 1.25rem)}@media print,screen and (min-width:40em){.grid-margin-x.small-up-1>.cell{width:calc(100% - 1.875rem)}.grid-margin-x.small-up-2>.cell{width:calc(50% - 1.875rem)}.grid-margin-x.small-up-3>.cell{width:calc(33.33333% - 1.875rem)}.grid-margin-x.small-up-4>.cell{width:calc(25% - 1.875rem)}.grid-margin-x.small-up-5>.cell{width:calc(20% - 1.875rem)}.grid-margin-x.small-up-6>.cell{width:calc(16.66667% - 1.875rem)}.grid-margin-x.small-up-7>.cell{width:calc(14.28571% - 1.875rem)}.grid-margin-x.small-up-8>.cell{width:calc(12.5% - 1.875rem)}.grid-margin-x.medium-up-1>.cell{width:calc(100% - 1.875rem)}.grid-margin-x.medium-up-2>.cell{width:calc(50% - 1.875rem)}.grid-margin-x.medium-up-3>.cell{width:calc(33.33333% - 1.875rem)}.grid-margin-x.medium-up-4>.cell{width:calc(25% - 1.875rem)}.grid-margin-x.medium-up-5>.cell{width:calc(20% - 1.875rem)}.grid-margin-x.medium-up-6>.cell{width:calc(16.66667% - 1.875rem)}.grid-margin-x.medium-up-7>.cell{width:calc(14.28571% - 1.875rem)}.grid-margin-x.medium-up-8>.cell{width:calc(12.5% - 1.875rem)}}@media print,screen and (min-width:64em){.grid-margin-x.large-up-1>.cell{width:calc(100% - 1.875rem)}.grid-margin-x.large-up-2>.cell{width:calc(50% - 1.875rem)}.grid-margin-x.large-up-3>.cell{width:calc(33.33333% - 1.875rem)}.grid-margin-x.large-up-4>.cell{width:calc(25% - 1.875rem)}.grid-margin-x.large-up-5>.cell{width:calc(20% - 1.875rem)}.grid-margin-x.large-up-6>.cell{width:calc(16.66667% - 1.875rem)}.grid-margin-x.large-up-7>.cell{width:calc(14.28571% - 1.875rem)}.grid-margin-x.large-up-8>.cell{width:calc(12.5% - 1.875rem)}}.small-margin-collapse{margin-right:0;margin-left:0}.small-margin-collapse>.cell{margin-right:0;margin-left:0}.small-margin-collapse>.small-1{width:8.33333%}.small-margin-collapse>.small-2{width:16.66667%}.small-margin-collapse>.small-3{width:25%}.small-margin-collapse>.small-4{width:33.33333%}.small-margin-collapse>.small-5{width:41.66667%}.small-margin-collapse>.small-6{width:50%}.small-margin-collapse>.small-7{width:58.33333%}.small-margin-collapse>.small-8{width:66.66667%}.small-margin-collapse>.small-9{width:75%}.small-margin-collapse>.small-10{width:83.33333%}.small-margin-collapse>.small-11{width:91.66667%}.small-margin-collapse>.small-12{width:100%}@media print,screen and (min-width:40em){.small-margin-collapse>.medium-1{width:8.33333%}.small-margin-collapse>.medium-2{width:16.66667%}.small-margin-collapse>.medium-3{width:25%}.small-margin-collapse>.medium-4{width:33.33333%}.small-margin-collapse>.medium-5{width:41.66667%}.small-margin-collapse>.medium-6{width:50%}.small-margin-collapse>.medium-7{width:58.33333%}.small-margin-collapse>.medium-8{width:66.66667%}.small-margin-collapse>.medium-9{width:75%}.small-margin-collapse>.medium-10{width:83.33333%}.small-margin-collapse>.medium-11{width:91.66667%}.small-margin-collapse>.medium-12{width:100%}}@media print,screen and (min-width:64em){.small-margin-collapse>.large-1{width:8.33333%}.small-margin-collapse>.large-2{width:16.66667%}.small-margin-collapse>.large-3{width:25%}.small-margin-collapse>.large-4{width:33.33333%}.small-margin-collapse>.large-5{width:41.66667%}.small-margin-collapse>.large-6{width:50%}.small-margin-collapse>.large-7{width:58.33333%}.small-margin-collapse>.large-8{width:66.66667%}.small-margin-collapse>.large-9{width:75%}.small-margin-collapse>.large-10{width:83.33333%}.small-margin-collapse>.large-11{width:91.66667%}.small-margin-collapse>.large-12{width:100%}}.small-padding-collapse{margin-right:0;margin-left:0}.small-padding-collapse>.cell{padding-right:0;padding-left:0}@media print,screen and (min-width:40em){.medium-margin-collapse{margin-right:0;margin-left:0}.medium-margin-collapse>.cell{margin-right:0;margin-left:0}}@media print,screen and (min-width:40em){.medium-margin-collapse>.small-1{width:8.33333%}.medium-margin-collapse>.small-2{width:16.66667%}.medium-margin-collapse>.small-3{width:25%}.medium-margin-collapse>.small-4{width:33.33333%}.medium-margin-collapse>.small-5{width:41.66667%}.medium-margin-collapse>.small-6{width:50%}.medium-margin-collapse>.small-7{width:58.33333%}.medium-margin-collapse>.small-8{width:66.66667%}.medium-margin-collapse>.small-9{width:75%}.medium-margin-collapse>.small-10{width:83.33333%}.medium-margin-collapse>.small-11{width:91.66667%}.medium-margin-collapse>.small-12{width:100%}}@media print,screen and (min-width:40em){.medium-margin-collapse>.medium-1{width:8.33333%}.medium-margin-collapse>.medium-2{width:16.66667%}.medium-margin-collapse>.medium-3{width:25%}.medium-margin-collapse>.medium-4{width:33.33333%}.medium-margin-collapse>.medium-5{width:41.66667%}.medium-margin-collapse>.medium-6{width:50%}.medium-margin-collapse>.medium-7{width:58.33333%}.medium-margin-collapse>.medium-8{width:66.66667%}.medium-margin-collapse>.medium-9{width:75%}.medium-margin-collapse>.medium-10{width:83.33333%}.medium-margin-collapse>.medium-11{width:91.66667%}.medium-margin-collapse>.medium-12{width:100%}}@media print,screen and (min-width:64em){.medium-margin-collapse>.large-1{width:8.33333%}.medium-margin-collapse>.large-2{width:16.66667%}.medium-margin-collapse>.large-3{width:25%}.medium-margin-collapse>.large-4{width:33.33333%}.medium-margin-collapse>.large-5{width:41.66667%}.medium-margin-collapse>.large-6{width:50%}.medium-margin-collapse>.large-7{width:58.33333%}.medium-margin-collapse>.large-8{width:66.66667%}.medium-margin-collapse>.large-9{width:75%}.medium-margin-collapse>.large-10{width:83.33333%}.medium-margin-collapse>.large-11{width:91.66667%}.medium-margin-collapse>.large-12{width:100%}}@media print,screen and (min-width:40em){.medium-padding-collapse{margin-right:0;margin-left:0}.medium-padding-collapse>.cell{padding-right:0;padding-left:0}}@media print,screen and (min-width:64em){.large-margin-collapse{margin-right:0;margin-left:0}.large-margin-collapse>.cell{margin-right:0;margin-left:0}}@media print,screen and (min-width:64em){.large-margin-collapse>.small-1{width:8.33333%}.large-margin-collapse>.small-2{width:16.66667%}.large-margin-collapse>.small-3{width:25%}.large-margin-collapse>.small-4{width:33.33333%}.large-margin-collapse>.small-5{width:41.66667%}.large-margin-collapse>.small-6{width:50%}.large-margin-collapse>.small-7{width:58.33333%}.large-margin-collapse>.small-8{width:66.66667%}.large-margin-collapse>.small-9{width:75%}.large-margin-collapse>.small-10{width:83.33333%}.large-margin-collapse>.small-11{width:91.66667%}.large-margin-collapse>.small-12{width:100%}}@media print,screen and (min-width:64em){.large-margin-collapse>.medium-1{width:8.33333%}.large-margin-collapse>.medium-2{width:16.66667%}.large-margin-collapse>.medium-3{width:25%}.large-margin-collapse>.medium-4{width:33.33333%}.large-margin-collapse>.medium-5{width:41.66667%}.large-margin-collapse>.medium-6{width:50%}.large-margin-collapse>.medium-7{width:58.33333%}.large-margin-collapse>.medium-8{width:66.66667%}.large-margin-collapse>.medium-9{width:75%}.large-margin-collapse>.medium-10{width:83.33333%}.large-margin-collapse>.medium-11{width:91.66667%}.large-margin-collapse>.medium-12{width:100%}}@media print,screen and (min-width:64em){.large-margin-collapse>.large-1{width:8.33333%}.large-margin-collapse>.large-2{width:16.66667%}.large-margin-collapse>.large-3{width:25%}.large-margin-collapse>.large-4{width:33.33333%}.large-margin-collapse>.large-5{width:41.66667%}.large-margin-collapse>.large-6{width:50%}.large-margin-collapse>.large-7{width:58.33333%}.large-margin-collapse>.large-8{width:66.66667%}.large-margin-collapse>.large-9{width:75%}.large-margin-collapse>.large-10{width:83.33333%}.large-margin-collapse>.large-11{width:91.66667%}.large-margin-collapse>.large-12{width:100%}}@media print,screen and (min-width:64em){.large-padding-collapse{margin-right:0;margin-left:0}.large-padding-collapse>.cell{padding-right:0;padding-left:0}}.small-offset-0{margin-left:0}.grid-margin-x>.small-offset-0{margin-left:calc(0% + 1.25rem / 2)}.small-offset-1{margin-left:8.33333%}.grid-margin-x>.small-offset-1{margin-left:calc(8.33333% + 1.25rem / 2)}.small-offset-2{margin-left:16.66667%}.grid-margin-x>.small-offset-2{margin-left:calc(16.66667% + 1.25rem / 2)}.small-offset-3{margin-left:25%}.grid-margin-x>.small-offset-3{margin-left:calc(25% + 1.25rem / 2)}.small-offset-4{margin-left:33.33333%}.grid-margin-x>.small-offset-4{margin-left:calc(33.33333% + 1.25rem / 2)}.small-offset-5{margin-left:41.66667%}.grid-margin-x>.small-offset-5{margin-left:calc(41.66667% + 1.25rem / 2)}.small-offset-6{margin-left:50%}.grid-margin-x>.small-offset-6{margin-left:calc(50% + 1.25rem / 2)}.small-offset-7{margin-left:58.33333%}.grid-margin-x>.small-offset-7{margin-left:calc(58.33333% + 1.25rem / 2)}.small-offset-8{margin-left:66.66667%}.grid-margin-x>.small-offset-8{margin-left:calc(66.66667% + 1.25rem / 2)}.small-offset-9{margin-left:75%}.grid-margin-x>.small-offset-9{margin-left:calc(75% + 1.25rem / 2)}.small-offset-10{margin-left:83.33333%}.grid-margin-x>.small-offset-10{margin-left:calc(83.33333% + 1.25rem / 2)}.small-offset-11{margin-left:91.66667%}.grid-margin-x>.small-offset-11{margin-left:calc(91.66667% + 1.25rem / 2)}@media print,screen and (min-width:40em){.medium-offset-0{margin-left:0}.grid-margin-x>.medium-offset-0{margin-left:calc(0% + 1.875rem / 2)}.medium-offset-1{margin-left:8.33333%}.grid-margin-x>.medium-offset-1{margin-left:calc(8.33333% + 1.875rem / 2)}.medium-offset-2{margin-left:16.66667%}.grid-margin-x>.medium-offset-2{margin-left:calc(16.66667% + 1.875rem / 2)}.medium-offset-3{margin-left:25%}.grid-margin-x>.medium-offset-3{margin-left:calc(25% + 1.875rem / 2)}.medium-offset-4{margin-left:33.33333%}.grid-margin-x>.medium-offset-4{margin-left:calc(33.33333% + 1.875rem / 2)}.medium-offset-5{margin-left:41.66667%}.grid-margin-x>.medium-offset-5{margin-left:calc(41.66667% + 1.875rem / 2)}.medium-offset-6{margin-left:50%}.grid-margin-x>.medium-offset-6{margin-left:calc(50% + 1.875rem / 2)}.medium-offset-7{margin-left:58.33333%}.grid-margin-x>.medium-offset-7{margin-left:calc(58.33333% + 1.875rem / 2)}.medium-offset-8{margin-left:66.66667%}.grid-margin-x>.medium-offset-8{margin-left:calc(66.66667% + 1.875rem / 2)}.medium-offset-9{margin-left:75%}.grid-margin-x>.medium-offset-9{margin-left:calc(75% + 1.875rem / 2)}.medium-offset-10{margin-left:83.33333%}.grid-margin-x>.medium-offset-10{margin-left:calc(83.33333% + 1.875rem / 2)}.medium-offset-11{margin-left:91.66667%}.grid-margin-x>.medium-offset-11{margin-left:calc(91.66667% + 1.875rem / 2)}}@media print,screen and (min-width:64em){.large-offset-0{margin-left:0}.grid-margin-x>.large-offset-0{margin-left:calc(0% + 1.875rem / 2)}.large-offset-1{margin-left:8.33333%}.grid-margin-x>.large-offset-1{margin-left:calc(8.33333% + 1.875rem / 2)}.large-offset-2{margin-left:16.66667%}.grid-margin-x>.large-offset-2{margin-left:calc(16.66667% + 1.875rem / 2)}.large-offset-3{margin-left:25%}.grid-margin-x>.large-offset-3{margin-left:calc(25% + 1.875rem / 2)}.large-offset-4{margin-left:33.33333%}.grid-margin-x>.large-offset-4{margin-left:calc(33.33333% + 1.875rem / 2)}.large-offset-5{margin-left:41.66667%}.grid-margin-x>.large-offset-5{margin-left:calc(41.66667% + 1.875rem / 2)}.large-offset-6{margin-left:50%}.grid-margin-x>.large-offset-6{margin-left:calc(50% + 1.875rem / 2)}.large-offset-7{margin-left:58.33333%}.grid-margin-x>.large-offset-7{margin-left:calc(58.33333% + 1.875rem / 2)}.large-offset-8{margin-left:66.66667%}.grid-margin-x>.large-offset-8{margin-left:calc(66.66667% + 1.875rem / 2)}.large-offset-9{margin-left:75%}.grid-margin-x>.large-offset-9{margin-left:calc(75% + 1.875rem / 2)}.large-offset-10{margin-left:83.33333%}.grid-margin-x>.large-offset-10{margin-left:calc(83.33333% + 1.875rem / 2)}.large-offset-11{margin-left:91.66667%}.grid-margin-x>.large-offset-11{margin-left:calc(91.66667% + 1.875rem / 2)}}.grid-y{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-flow:column nowrap;-ms-flex-flow:column nowrap;flex-flow:column nowrap}.grid-y>.cell{height:auto;max-height:none}.grid-y>.auto{height:auto}.grid-y>.shrink{height:auto}.grid-y>.small-1,.grid-y>.small-10,.grid-y>.small-11,.grid-y>.small-12,.grid-y>.small-2,.grid-y>.small-3,.grid-y>.small-4,.grid-y>.small-5,.grid-y>.small-6,.grid-y>.small-7,.grid-y>.small-8,.grid-y>.small-9,.grid-y>.small-full,.grid-y>.small-shrink{-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto}@media print,screen and (min-width:40em){.grid-y>.medium-1,.grid-y>.medium-10,.grid-y>.medium-11,.grid-y>.medium-12,.grid-y>.medium-2,.grid-y>.medium-3,.grid-y>.medium-4,.grid-y>.medium-5,.grid-y>.medium-6,.grid-y>.medium-7,.grid-y>.medium-8,.grid-y>.medium-9,.grid-y>.medium-full,.grid-y>.medium-shrink{-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto}}@media print,screen and (min-width:64em){.grid-y>.large-1,.grid-y>.large-10,.grid-y>.large-11,.grid-y>.large-12,.grid-y>.large-2,.grid-y>.large-3,.grid-y>.large-4,.grid-y>.large-5,.grid-y>.large-6,.grid-y>.large-7,.grid-y>.large-8,.grid-y>.large-9,.grid-y>.large-full,.grid-y>.large-shrink{-webkit-flex-basis:auto;-ms-flex-preferred-size:auto;flex-basis:auto}}.grid-y>.small-1,.grid-y>.small-10,.grid-y>.small-11,.grid-y>.small-12,.grid-y>.small-2,.grid-y>.small-3,.grid-y>.small-4,.grid-y>.small-5,.grid-y>.small-6,.grid-y>.small-7,.grid-y>.small-8,.grid-y>.small-9{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.grid-y>.small-1{height:8.33333%}.grid-y>.small-2{height:16.66667%}.grid-y>.small-3{height:25%}.grid-y>.small-4{height:33.33333%}.grid-y>.small-5{height:41.66667%}.grid-y>.small-6{height:50%}.grid-y>.small-7{height:58.33333%}.grid-y>.small-8{height:66.66667%}.grid-y>.small-9{height:75%}.grid-y>.small-10{height:83.33333%}.grid-y>.small-11{height:91.66667%}.grid-y>.small-12{height:100%}@media print,screen and (min-width:40em){.grid-y>.medium-auto{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px;height:auto}.grid-y>.medium-1,.grid-y>.medium-10,.grid-y>.medium-11,.grid-y>.medium-12,.grid-y>.medium-2,.grid-y>.medium-3,.grid-y>.medium-4,.grid-y>.medium-5,.grid-y>.medium-6,.grid-y>.medium-7,.grid-y>.medium-8,.grid-y>.medium-9,.grid-y>.medium-shrink{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.grid-y>.medium-shrink{height:auto}.grid-y>.medium-1{height:8.33333%}.grid-y>.medium-2{height:16.66667%}.grid-y>.medium-3{height:25%}.grid-y>.medium-4{height:33.33333%}.grid-y>.medium-5{height:41.66667%}.grid-y>.medium-6{height:50%}.grid-y>.medium-7{height:58.33333%}.grid-y>.medium-8{height:66.66667%}.grid-y>.medium-9{height:75%}.grid-y>.medium-10{height:83.33333%}.grid-y>.medium-11{height:91.66667%}.grid-y>.medium-12{height:100%}}@media print,screen and (min-width:64em){.grid-y>.large-auto{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px;height:auto}.grid-y>.large-1,.grid-y>.large-10,.grid-y>.large-11,.grid-y>.large-12,.grid-y>.large-2,.grid-y>.large-3,.grid-y>.large-4,.grid-y>.large-5,.grid-y>.large-6,.grid-y>.large-7,.grid-y>.large-8,.grid-y>.large-9,.grid-y>.large-shrink{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.grid-y>.large-shrink{height:auto}.grid-y>.large-1{height:8.33333%}.grid-y>.large-2{height:16.66667%}.grid-y>.large-3{height:25%}.grid-y>.large-4{height:33.33333%}.grid-y>.large-5{height:41.66667%}.grid-y>.large-6{height:50%}.grid-y>.large-7{height:58.33333%}.grid-y>.large-8{height:66.66667%}.grid-y>.large-9{height:75%}.grid-y>.large-10{height:83.33333%}.grid-y>.large-11{height:91.66667%}.grid-y>.large-12{height:100%}}.grid-padding-y .grid-padding-y{margin-top:-.625rem;margin-bottom:-.625rem}@media print,screen and (min-width:40em){.grid-padding-y .grid-padding-y{margin-top:-.9375rem;margin-bottom:-.9375rem}}.grid-padding-y>.cell{padding-top:.625rem;padding-bottom:.625rem}@media print,screen and (min-width:40em){.grid-padding-y>.cell{padding-top:.9375rem;padding-bottom:.9375rem}}.grid-margin-y{margin-top:-.625rem;margin-bottom:-.625rem}@media print,screen and (min-width:40em){.grid-margin-y{margin-top:-.9375rem;margin-bottom:-.9375rem}}.grid-margin-y>.cell{height:calc(100% - 1.25rem);margin-top:.625rem;margin-bottom:.625rem}@media print,screen and (min-width:40em){.grid-margin-y>.cell{height:calc(100% - 1.875rem);margin-top:.9375rem;margin-bottom:.9375rem}}.grid-margin-y>.auto{height:auto}.grid-margin-y>.shrink{height:auto}.grid-margin-y>.small-1{height:calc(8.33333% - 1.25rem)}.grid-margin-y>.small-2{height:calc(16.66667% - 1.25rem)}.grid-margin-y>.small-3{height:calc(25% - 1.25rem)}.grid-margin-y>.small-4{height:calc(33.33333% - 1.25rem)}.grid-margin-y>.small-5{height:calc(41.66667% - 1.25rem)}.grid-margin-y>.small-6{height:calc(50% - 1.25rem)}.grid-margin-y>.small-7{height:calc(58.33333% - 1.25rem)}.grid-margin-y>.small-8{height:calc(66.66667% - 1.25rem)}.grid-margin-y>.small-9{height:calc(75% - 1.25rem)}.grid-margin-y>.small-10{height:calc(83.33333% - 1.25rem)}.grid-margin-y>.small-11{height:calc(91.66667% - 1.25rem)}.grid-margin-y>.small-12{height:calc(100% - 1.25rem)}@media print,screen and (min-width:40em){.grid-margin-y>.auto{height:auto}.grid-margin-y>.shrink{height:auto}.grid-margin-y>.small-1{height:calc(8.33333% - 1.875rem)}.grid-margin-y>.small-2{height:calc(16.66667% - 1.875rem)}.grid-margin-y>.small-3{height:calc(25% - 1.875rem)}.grid-margin-y>.small-4{height:calc(33.33333% - 1.875rem)}.grid-margin-y>.small-5{height:calc(41.66667% - 1.875rem)}.grid-margin-y>.small-6{height:calc(50% - 1.875rem)}.grid-margin-y>.small-7{height:calc(58.33333% - 1.875rem)}.grid-margin-y>.small-8{height:calc(66.66667% - 1.875rem)}.grid-margin-y>.small-9{height:calc(75% - 1.875rem)}.grid-margin-y>.small-10{height:calc(83.33333% - 1.875rem)}.grid-margin-y>.small-11{height:calc(91.66667% - 1.875rem)}.grid-margin-y>.small-12{height:calc(100% - 1.875rem)}.grid-margin-y>.medium-auto{height:auto}.grid-margin-y>.medium-shrink{height:auto}.grid-margin-y>.medium-1{height:calc(8.33333% - 1.875rem)}.grid-margin-y>.medium-2{height:calc(16.66667% - 1.875rem)}.grid-margin-y>.medium-3{height:calc(25% - 1.875rem)}.grid-margin-y>.medium-4{height:calc(33.33333% - 1.875rem)}.grid-margin-y>.medium-5{height:calc(41.66667% - 1.875rem)}.grid-margin-y>.medium-6{height:calc(50% - 1.875rem)}.grid-margin-y>.medium-7{height:calc(58.33333% - 1.875rem)}.grid-margin-y>.medium-8{height:calc(66.66667% - 1.875rem)}.grid-margin-y>.medium-9{height:calc(75% - 1.875rem)}.grid-margin-y>.medium-10{height:calc(83.33333% - 1.875rem)}.grid-margin-y>.medium-11{height:calc(91.66667% - 1.875rem)}.grid-margin-y>.medium-12{height:calc(100% - 1.875rem)}}@media print,screen and (min-width:64em){.grid-margin-y>.large-auto{height:auto}.grid-margin-y>.large-shrink{height:auto}.grid-margin-y>.large-1{height:calc(8.33333% - 1.875rem)}.grid-margin-y>.large-2{height:calc(16.66667% - 1.875rem)}.grid-margin-y>.large-3{height:calc(25% - 1.875rem)}.grid-margin-y>.large-4{height:calc(33.33333% - 1.875rem)}.grid-margin-y>.large-5{height:calc(41.66667% - 1.875rem)}.grid-margin-y>.large-6{height:calc(50% - 1.875rem)}.grid-margin-y>.large-7{height:calc(58.33333% - 1.875rem)}.grid-margin-y>.large-8{height:calc(66.66667% - 1.875rem)}.grid-margin-y>.large-9{height:calc(75% - 1.875rem)}.grid-margin-y>.large-10{height:calc(83.33333% - 1.875rem)}.grid-margin-y>.large-11{height:calc(91.66667% - 1.875rem)}.grid-margin-y>.large-12{height:calc(100% - 1.875rem)}}.grid-frame{overflow:hidden;position:relative;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;width:100vw}.cell .grid-frame{width:100%}.cell-block{overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.cell-block-y{overflow-y:auto;max-height:100%;min-height:100%;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.cell-block-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;max-height:100%}.cell-block-container>.grid-x{max-height:100%;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}@media print,screen and (min-width:40em){.medium-grid-frame{overflow:hidden;position:relative;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;width:100vw}.cell .medium-grid-frame{width:100%}.medium-cell-block{overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.medium-cell-block-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;max-height:100%}.medium-cell-block-container>.grid-x{max-height:100%;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.medium-cell-block-y{overflow-y:auto;max-height:100%;min-height:100%;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}}@media print,screen and (min-width:64em){.large-grid-frame{overflow:hidden;position:relative;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;width:100vw}.cell .large-grid-frame{width:100%}.large-cell-block{overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.large-cell-block-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;max-height:100%}.large-cell-block-container>.grid-x{max-height:100%;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.large-cell-block-y{overflow-y:auto;max-height:100%;min-height:100%;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}}.grid-y.grid-frame{width:auto;overflow:hidden;position:relative;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;height:100vh}@media print,screen and (min-width:40em){.grid-y.medium-grid-frame{width:auto;overflow:hidden;position:relative;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;height:100vh}}@media print,screen and (min-width:64em){.grid-y.large-grid-frame{width:auto;overflow:hidden;position:relative;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;height:100vh}}.cell .grid-y.grid-frame{height:100%}@media print,screen and (min-width:40em){.cell .grid-y.medium-grid-frame{height:100%}}@media print,screen and (min-width:64em){.cell .grid-y.large-grid-frame{height:100%}}.grid-margin-y{margin-top:-.625rem;margin-bottom:-.625rem}@media print,screen and (min-width:40em){.grid-margin-y{margin-top:-.9375rem;margin-bottom:-.9375rem}}.grid-margin-y>.cell{height:calc(100% - 1.25rem);margin-top:.625rem;margin-bottom:.625rem}@media print,screen and (min-width:40em){.grid-margin-y>.cell{height:calc(100% - 1.875rem);margin-top:.9375rem;margin-bottom:.9375rem}}.grid-margin-y>.auto{height:auto}.grid-margin-y>.shrink{height:auto}.grid-margin-y>.small-1{height:calc(8.33333% - 1.25rem)}.grid-margin-y>.small-2{height:calc(16.66667% - 1.25rem)}.grid-margin-y>.small-3{height:calc(25% - 1.25rem)}.grid-margin-y>.small-4{height:calc(33.33333% - 1.25rem)}.grid-margin-y>.small-5{height:calc(41.66667% - 1.25rem)}.grid-margin-y>.small-6{height:calc(50% - 1.25rem)}.grid-margin-y>.small-7{height:calc(58.33333% - 1.25rem)}.grid-margin-y>.small-8{height:calc(66.66667% - 1.25rem)}.grid-margin-y>.small-9{height:calc(75% - 1.25rem)}.grid-margin-y>.small-10{height:calc(83.33333% - 1.25rem)}.grid-margin-y>.small-11{height:calc(91.66667% - 1.25rem)}.grid-margin-y>.small-12{height:calc(100% - 1.25rem)}@media print,screen and (min-width:40em){.grid-margin-y>.auto{height:auto}.grid-margin-y>.shrink{height:auto}.grid-margin-y>.small-1{height:calc(8.33333% - 1.875rem)}.grid-margin-y>.small-2{height:calc(16.66667% - 1.875rem)}.grid-margin-y>.small-3{height:calc(25% - 1.875rem)}.grid-margin-y>.small-4{height:calc(33.33333% - 1.875rem)}.grid-margin-y>.small-5{height:calc(41.66667% - 1.875rem)}.grid-margin-y>.small-6{height:calc(50% - 1.875rem)}.grid-margin-y>.small-7{height:calc(58.33333% - 1.875rem)}.grid-margin-y>.small-8{height:calc(66.66667% - 1.875rem)}.grid-margin-y>.small-9{height:calc(75% - 1.875rem)}.grid-margin-y>.small-10{height:calc(83.33333% - 1.875rem)}.grid-margin-y>.small-11{height:calc(91.66667% - 1.875rem)}.grid-margin-y>.small-12{height:calc(100% - 1.875rem)}.grid-margin-y>.medium-auto{height:auto}.grid-margin-y>.medium-shrink{height:auto}.grid-margin-y>.medium-1{height:calc(8.33333% - 1.875rem)}.grid-margin-y>.medium-2{height:calc(16.66667% - 1.875rem)}.grid-margin-y>.medium-3{height:calc(25% - 1.875rem)}.grid-margin-y>.medium-4{height:calc(33.33333% - 1.875rem)}.grid-margin-y>.medium-5{height:calc(41.66667% - 1.875rem)}.grid-margin-y>.medium-6{height:calc(50% - 1.875rem)}.grid-margin-y>.medium-7{height:calc(58.33333% - 1.875rem)}.grid-margin-y>.medium-8{height:calc(66.66667% - 1.875rem)}.grid-margin-y>.medium-9{height:calc(75% - 1.875rem)}.grid-margin-y>.medium-10{height:calc(83.33333% - 1.875rem)}.grid-margin-y>.medium-11{height:calc(91.66667% - 1.875rem)}.grid-margin-y>.medium-12{height:calc(100% - 1.875rem)}}@media print,screen and (min-width:64em){.grid-margin-y>.large-auto{height:auto}.grid-margin-y>.large-shrink{height:auto}.grid-margin-y>.large-1{height:calc(8.33333% - 1.875rem)}.grid-margin-y>.large-2{height:calc(16.66667% - 1.875rem)}.grid-margin-y>.large-3{height:calc(25% - 1.875rem)}.grid-margin-y>.large-4{height:calc(33.33333% - 1.875rem)}.grid-margin-y>.large-5{height:calc(41.66667% - 1.875rem)}.grid-margin-y>.large-6{height:calc(50% - 1.875rem)}.grid-margin-y>.large-7{height:calc(58.33333% - 1.875rem)}.grid-margin-y>.large-8{height:calc(66.66667% - 1.875rem)}.grid-margin-y>.large-9{height:calc(75% - 1.875rem)}.grid-margin-y>.large-10{height:calc(83.33333% - 1.875rem)}.grid-margin-y>.large-11{height:calc(91.66667% - 1.875rem)}.grid-margin-y>.large-12{height:calc(100% - 1.875rem)}}.grid-frame.grid-margin-y{height:calc(100vh + 1.25rem)}@media print,screen and (min-width:40em){.grid-frame.grid-margin-y{height:calc(100vh + 1.875rem)}}@media print,screen and (min-width:64em){.grid-frame.grid-margin-y{height:calc(100vh + 1.875rem)}}@media print,screen and (min-width:40em){.grid-margin-y.medium-grid-frame{height:calc(100vh + 1.875rem)}}@media print,screen and (min-width:64em){.grid-margin-y.large-grid-frame{height:calc(100vh + 1.875rem)}}.button{display:inline-block;vertical-align:middle;margin:0 0 1rem 0;padding:.85em 1em;border:1px solid transparent;border-radius:0;-webkit-transition:background-color .25s ease-out,color .25s ease-out;transition:background-color .25s ease-out,color .25s ease-out;font-family:inherit;font-size:.9rem;-webkit-appearance:none;line-height:1;text-align:center;cursor:pointer}[data-whatinput=mouse] .button{outline:0}.button.tiny{font-size:.6rem}.button.small{font-size:.75rem}.button.large{font-size:1.25rem}.button.expanded{display:block;width:100%;margin-right:0;margin-left:0}.button,.button.disabled,.button.disabled:focus,.button.disabled:hover,.button[disabled],.button[disabled]:focus,.button[disabled]:hover{background-color:#1779ba;color:#fefefe}.button:focus,.button:hover{background-color:#14679e;color:#fefefe}.button.primary,.button.primary.disabled,.button.primary.disabled:focus,.button.primary.disabled:hover,.button.primary[disabled],.button.primary[disabled]:focus,.button.primary[disabled]:hover{background-color:#1779ba;color:#fefefe}.button.primary:focus,.button.primary:hover{background-color:#126195;color:#fefefe}.button.secondary,.button.secondary.disabled,.button.secondary.disabled:focus,.button.secondary.disabled:hover,.button.secondary[disabled],.button.secondary[disabled]:focus,.button.secondary[disabled]:hover{background-color:#767676;color:#fefefe}.button.secondary:focus,.button.secondary:hover{background-color:#5e5e5e;color:#fefefe}.button.success,.button.success.disabled,.button.success.disabled:focus,.button.success.disabled:hover,.button.success[disabled],.button.success[disabled]:focus,.button.success[disabled]:hover{background-color:#3adb76;color:#0a0a0a}.button.success:focus,.button.success:hover{background-color:#22bb5b;color:#0a0a0a}.button.warning,.button.warning.disabled,.button.warning.disabled:focus,.button.warning.disabled:hover,.button.warning[disabled],.button.warning[disabled]:focus,.button.warning[disabled]:hover{background-color:#ffae00;color:#0a0a0a}.button.warning:focus,.button.warning:hover{background-color:#cc8b00;color:#0a0a0a}.button.alert,.button.alert.disabled,.button.alert.disabled:focus,.button.alert.disabled:hover,.button.alert[disabled],.button.alert[disabled]:focus,.button.alert[disabled]:hover{background-color:#cc4b37;color:#fefefe}.button.alert:focus,.button.alert:hover{background-color:#a53b2a;color:#fefefe}.button.hollow,.button.hollow.disabled,.button.hollow.disabled:focus,.button.hollow.disabled:hover,.button.hollow:focus,.button.hollow:hover,.button.hollow[disabled],.button.hollow[disabled]:focus,.button.hollow[disabled]:hover{background-color:transparent}.button.hollow,.button.hollow.disabled,.button.hollow.disabled:focus,.button.hollow.disabled:hover,.button.hollow[disabled],.button.hollow[disabled]:focus,.button.hollow[disabled]:hover{border:1px solid #1779ba;color:#1779ba}.button.hollow:focus,.button.hollow:hover{border-color:#0c3d5d;color:#0c3d5d}.button.hollow.primary,.button.hollow.primary.disabled,.button.hollow.primary.disabled:focus,.button.hollow.primary.disabled:hover,.button.hollow.primary[disabled],.button.hollow.primary[disabled]:focus,.button.hollow.primary[disabled]:hover{border:1px solid #1779ba;color:#1779ba}.button.hollow.primary:focus,.button.hollow.primary:hover{border-color:#0c3d5d;color:#0c3d5d}.button.hollow.secondary,.button.hollow.secondary.disabled,.button.hollow.secondary.disabled:focus,.button.hollow.secondary.disabled:hover,.button.hollow.secondary[disabled],.button.hollow.secondary[disabled]:focus,.button.hollow.secondary[disabled]:hover{border:1px solid #767676;color:#767676}.button.hollow.secondary:focus,.button.hollow.secondary:hover{border-color:#3b3b3b;color:#3b3b3b}.button.hollow.success,.button.hollow.success.disabled,.button.hollow.success.disabled:focus,.button.hollow.success.disabled:hover,.button.hollow.success[disabled],.button.hollow.success[disabled]:focus,.button.hollow.success[disabled]:hover{border:1px solid #3adb76;color:#3adb76}.button.hollow.success:focus,.button.hollow.success:hover{border-color:#157539;color:#157539}.button.hollow.warning,.button.hollow.warning.disabled,.button.hollow.warning.disabled:focus,.button.hollow.warning.disabled:hover,.button.hollow.warning[disabled],.button.hollow.warning[disabled]:focus,.button.hollow.warning[disabled]:hover{border:1px solid #ffae00;color:#ffae00}.button.hollow.warning:focus,.button.hollow.warning:hover{border-color:#805700;color:#805700}.button.hollow.alert,.button.hollow.alert.disabled,.button.hollow.alert.disabled:focus,.button.hollow.alert.disabled:hover,.button.hollow.alert[disabled],.button.hollow.alert[disabled]:focus,.button.hollow.alert[disabled]:hover{border:1px solid #cc4b37;color:#cc4b37}.button.hollow.alert:focus,.button.hollow.alert:hover{border-color:#67251a;color:#67251a}.button.clear,.button.clear.disabled,.button.clear.disabled:focus,.button.clear.disabled:hover,.button.clear:focus,.button.clear:hover,.button.clear[disabled],.button.clear[disabled]:focus,.button.clear[disabled]:hover{border-color:transparent;background-color:transparent}.button.clear,.button.clear.disabled,.button.clear.disabled:focus,.button.clear.disabled:hover,.button.clear[disabled],.button.clear[disabled]:focus,.button.clear[disabled]:hover{color:#1779ba}.button.clear:focus,.button.clear:hover{color:#0c3d5d}.button.clear.primary,.button.clear.primary.disabled,.button.clear.primary.disabled:focus,.button.clear.primary.disabled:hover,.button.clear.primary[disabled],.button.clear.primary[disabled]:focus,.button.clear.primary[disabled]:hover{color:#1779ba}.button.clear.primary:focus,.button.clear.primary:hover{color:#0c3d5d}.button.clear.secondary,.button.clear.secondary.disabled,.button.clear.secondary.disabled:focus,.button.clear.secondary.disabled:hover,.button.clear.secondary[disabled],.button.clear.secondary[disabled]:focus,.button.clear.secondary[disabled]:hover{color:#767676}.button.clear.secondary:focus,.button.clear.secondary:hover{color:#3b3b3b}.button.clear.success,.button.clear.success.disabled,.button.clear.success.disabled:focus,.button.clear.success.disabled:hover,.button.clear.success[disabled],.button.clear.success[disabled]:focus,.button.clear.success[disabled]:hover{color:#3adb76}.button.clear.success:focus,.button.clear.success:hover{color:#157539}.button.clear.warning,.button.clear.warning.disabled,.button.clear.warning.disabled:focus,.button.clear.warning.disabled:hover,.button.clear.warning[disabled],.button.clear.warning[disabled]:focus,.button.clear.warning[disabled]:hover{color:#ffae00}.button.clear.warning:focus,.button.clear.warning:hover{color:#805700}.button.clear.alert,.button.clear.alert.disabled,.button.clear.alert.disabled:focus,.button.clear.alert.disabled:hover,.button.clear.alert[disabled],.button.clear.alert[disabled]:focus,.button.clear.alert[disabled]:hover{color:#cc4b37}.button.clear.alert:focus,.button.clear.alert:hover{color:#67251a}.button.disabled,.button[disabled]{opacity:.25;cursor:not-allowed}.button.dropdown::after{display:block;width:0;height:0;border-style:solid;border-width:.4em;content:'';border-bottom-width:0;border-color:#fefefe transparent transparent;position:relative;top:.4em;display:inline-block;float:right;margin-left:1em}.button.dropdown.clear::after,.button.dropdown.hollow::after{border-top-color:#1779ba}.button.dropdown.clear.primary::after,.button.dropdown.hollow.primary::after{border-top-color:#1779ba}.button.dropdown.clear.secondary::after,.button.dropdown.hollow.secondary::after{border-top-color:#767676}.button.dropdown.clear.success::after,.button.dropdown.hollow.success::after{border-top-color:#3adb76}.button.dropdown.clear.warning::after,.button.dropdown.hollow.warning::after{border-top-color:#ffae00}.button.dropdown.clear.alert::after,.button.dropdown.hollow.alert::after{border-top-color:#cc4b37}.button.arrow-only::after{top:-.1em;float:none;margin-left:0}a.button:focus,a.button:hover{text-decoration:none}.button-group{margin-bottom:1rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.button-group::after,.button-group::before{display:table;content:' ';-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}.button-group::after{clear:both}.button-group::after,.button-group::before{display:none}.button-group .button{margin:0;margin-right:1px;margin-bottom:1px;font-size:.9rem;-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.button-group .button:last-child{margin-right:0}.button-group.tiny .button{font-size:.6rem}.button-group.small .button{font-size:.75rem}.button-group.large .button{font-size:1.25rem}.button-group.expanded .button{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}.button-group.primary .button,.button-group.primary .button.disabled,.button-group.primary .button.disabled:focus,.button-group.primary .button.disabled:hover,.button-group.primary .button[disabled],.button-group.primary .button[disabled]:focus,.button-group.primary .button[disabled]:hover{background-color:#1779ba;color:#fefefe}.button-group.primary .button:focus,.button-group.primary .button:hover{background-color:#126195;color:#fefefe}.button-group.secondary .button,.button-group.secondary .button.disabled,.button-group.secondary .button.disabled:focus,.button-group.secondary .button.disabled:hover,.button-group.secondary .button[disabled],.button-group.secondary .button[disabled]:focus,.button-group.secondary .button[disabled]:hover{background-color:#767676;color:#fefefe}.button-group.secondary .button:focus,.button-group.secondary .button:hover{background-color:#5e5e5e;color:#fefefe}.button-group.success .button,.button-group.success .button.disabled,.button-group.success .button.disabled:focus,.button-group.success .button.disabled:hover,.button-group.success .button[disabled],.button-group.success .button[disabled]:focus,.button-group.success .button[disabled]:hover{background-color:#3adb76;color:#0a0a0a}.button-group.success .button:focus,.button-group.success .button:hover{background-color:#22bb5b;color:#0a0a0a}.button-group.warning .button,.button-group.warning .button.disabled,.button-group.warning .button.disabled:focus,.button-group.warning .button.disabled:hover,.button-group.warning .button[disabled],.button-group.warning .button[disabled]:focus,.button-group.warning .button[disabled]:hover{background-color:#ffae00;color:#0a0a0a}.button-group.warning .button:focus,.button-group.warning .button:hover{background-color:#cc8b00;color:#0a0a0a}.button-group.alert .button,.button-group.alert .button.disabled,.button-group.alert .button.disabled:focus,.button-group.alert .button.disabled:hover,.button-group.alert .button[disabled],.button-group.alert .button[disabled]:focus,.button-group.alert .button[disabled]:hover{background-color:#cc4b37;color:#fefefe}.button-group.alert .button:focus,.button-group.alert .button:hover{background-color:#a53b2a;color:#fefefe}.button-group.hollow .button,.button-group.hollow .button.disabled,.button-group.hollow .button.disabled:focus,.button-group.hollow .button.disabled:hover,.button-group.hollow .button:focus,.button-group.hollow .button:hover,.button-group.hollow .button[disabled],.button-group.hollow .button[disabled]:focus,.button-group.hollow .button[disabled]:hover{background-color:transparent}.button-group.hollow .button,.button-group.hollow .button.disabled,.button-group.hollow .button.disabled:focus,.button-group.hollow .button.disabled:hover,.button-group.hollow .button[disabled],.button-group.hollow .button[disabled]:focus,.button-group.hollow .button[disabled]:hover{border:1px solid #1779ba;color:#1779ba}.button-group.hollow .button:focus,.button-group.hollow .button:hover{border-color:#0c3d5d;color:#0c3d5d}.button-group.hollow .button.primary,.button-group.hollow .button.primary.disabled,.button-group.hollow .button.primary.disabled:focus,.button-group.hollow .button.primary.disabled:hover,.button-group.hollow .button.primary[disabled],.button-group.hollow .button.primary[disabled]:focus,.button-group.hollow .button.primary[disabled]:hover,.button-group.hollow.primary .button,.button-group.hollow.primary .button.disabled,.button-group.hollow.primary .button.disabled:focus,.button-group.hollow.primary .button.disabled:hover,.button-group.hollow.primary .button[disabled],.button-group.hollow.primary .button[disabled]:focus,.button-group.hollow.primary .button[disabled]:hover{border:1px solid #1779ba;color:#1779ba}.button-group.hollow .button.primary:focus,.button-group.hollow .button.primary:hover,.button-group.hollow.primary .button:focus,.button-group.hollow.primary .button:hover{border-color:#0c3d5d;color:#0c3d5d}.button-group.hollow .button.secondary,.button-group.hollow .button.secondary.disabled,.button-group.hollow .button.secondary.disabled:focus,.button-group.hollow .button.secondary.disabled:hover,.button-group.hollow .button.secondary[disabled],.button-group.hollow .button.secondary[disabled]:focus,.button-group.hollow .button.secondary[disabled]:hover,.button-group.hollow.secondary .button,.button-group.hollow.secondary .button.disabled,.button-group.hollow.secondary .button.disabled:focus,.button-group.hollow.secondary .button.disabled:hover,.button-group.hollow.secondary .button[disabled],.button-group.hollow.secondary .button[disabled]:focus,.button-group.hollow.secondary .button[disabled]:hover{border:1px solid #767676;color:#767676}.button-group.hollow .button.secondary:focus,.button-group.hollow .button.secondary:hover,.button-group.hollow.secondary .button:focus,.button-group.hollow.secondary .button:hover{border-color:#3b3b3b;color:#3b3b3b}.button-group.hollow .button.success,.button-group.hollow .button.success.disabled,.button-group.hollow .button.success.disabled:focus,.button-group.hollow .button.success.disabled:hover,.button-group.hollow .button.success[disabled],.button-group.hollow .button.success[disabled]:focus,.button-group.hollow .button.success[disabled]:hover,.button-group.hollow.success .button,.button-group.hollow.success .button.disabled,.button-group.hollow.success .button.disabled:focus,.button-group.hollow.success .button.disabled:hover,.button-group.hollow.success .button[disabled],.button-group.hollow.success .button[disabled]:focus,.button-group.hollow.success .button[disabled]:hover{border:1px solid #3adb76;color:#3adb76}.button-group.hollow .button.success:focus,.button-group.hollow .button.success:hover,.button-group.hollow.success .button:focus,.button-group.hollow.success .button:hover{border-color:#157539;color:#157539}.button-group.hollow .button.warning,.button-group.hollow .button.warning.disabled,.button-group.hollow .button.warning.disabled:focus,.button-group.hollow .button.warning.disabled:hover,.button-group.hollow .button.warning[disabled],.button-group.hollow .button.warning[disabled]:focus,.button-group.hollow .button.warning[disabled]:hover,.button-group.hollow.warning .button,.button-group.hollow.warning .button.disabled,.button-group.hollow.warning .button.disabled:focus,.button-group.hollow.warning .button.disabled:hover,.button-group.hollow.warning .button[disabled],.button-group.hollow.warning .button[disabled]:focus,.button-group.hollow.warning .button[disabled]:hover{border:1px solid #ffae00;color:#ffae00}.button-group.hollow .button.warning:focus,.button-group.hollow .button.warning:hover,.button-group.hollow.warning .button:focus,.button-group.hollow.warning .button:hover{border-color:#805700;color:#805700}.button-group.hollow .button.alert,.button-group.hollow .button.alert.disabled,.button-group.hollow .button.alert.disabled:focus,.button-group.hollow .button.alert.disabled:hover,.button-group.hollow .button.alert[disabled],.button-group.hollow .button.alert[disabled]:focus,.button-group.hollow .button.alert[disabled]:hover,.button-group.hollow.alert .button,.button-group.hollow.alert .button.disabled,.button-group.hollow.alert .button.disabled:focus,.button-group.hollow.alert .button.disabled:hover,.button-group.hollow.alert .button[disabled],.button-group.hollow.alert .button[disabled]:focus,.button-group.hollow.alert .button[disabled]:hover{border:1px solid #cc4b37;color:#cc4b37}.button-group.hollow .button.alert:focus,.button-group.hollow .button.alert:hover,.button-group.hollow.alert .button:focus,.button-group.hollow.alert .button:hover{border-color:#67251a;color:#67251a}.button-group.clear .button,.button-group.clear .button.disabled,.button-group.clear .button.disabled:focus,.button-group.clear .button.disabled:hover,.button-group.clear .button:focus,.button-group.clear .button:hover,.button-group.clear .button[disabled],.button-group.clear .button[disabled]:focus,.button-group.clear .button[disabled]:hover{border-color:transparent;background-color:transparent}.button-group.clear .button,.button-group.clear .button.disabled,.button-group.clear .button.disabled:focus,.button-group.clear .button.disabled:hover,.button-group.clear .button[disabled],.button-group.clear .button[disabled]:focus,.button-group.clear .button[disabled]:hover{color:#1779ba}.button-group.clear .button:focus,.button-group.clear .button:hover{color:#0c3d5d}.button-group.clear .button.primary,.button-group.clear .button.primary.disabled,.button-group.clear .button.primary.disabled:focus,.button-group.clear .button.primary.disabled:hover,.button-group.clear .button.primary[disabled],.button-group.clear .button.primary[disabled]:focus,.button-group.clear .button.primary[disabled]:hover,.button-group.clear.primary .button,.button-group.clear.primary .button.disabled,.button-group.clear.primary .button.disabled:focus,.button-group.clear.primary .button.disabled:hover,.button-group.clear.primary .button[disabled],.button-group.clear.primary .button[disabled]:focus,.button-group.clear.primary .button[disabled]:hover{color:#1779ba}.button-group.clear .button.primary:focus,.button-group.clear .button.primary:hover,.button-group.clear.primary .button:focus,.button-group.clear.primary .button:hover{color:#0c3d5d}.button-group.clear .button.secondary,.button-group.clear .button.secondary.disabled,.button-group.clear .button.secondary.disabled:focus,.button-group.clear .button.secondary.disabled:hover,.button-group.clear .button.secondary[disabled],.button-group.clear .button.secondary[disabled]:focus,.button-group.clear .button.secondary[disabled]:hover,.button-group.clear.secondary .button,.button-group.clear.secondary .button.disabled,.button-group.clear.secondary .button.disabled:focus,.button-group.clear.secondary .button.disabled:hover,.button-group.clear.secondary .button[disabled],.button-group.clear.secondary .button[disabled]:focus,.button-group.clear.secondary .button[disabled]:hover{color:#767676}.button-group.clear .button.secondary:focus,.button-group.clear .button.secondary:hover,.button-group.clear.secondary .button:focus,.button-group.clear.secondary .button:hover{color:#3b3b3b}.button-group.clear .button.success,.button-group.clear .button.success.disabled,.button-group.clear .button.success.disabled:focus,.button-group.clear .button.success.disabled:hover,.button-group.clear .button.success[disabled],.button-group.clear .button.success[disabled]:focus,.button-group.clear .button.success[disabled]:hover,.button-group.clear.success .button,.button-group.clear.success .button.disabled,.button-group.clear.success .button.disabled:focus,.button-group.clear.success .button.disabled:hover,.button-group.clear.success .button[disabled],.button-group.clear.success .button[disabled]:focus,.button-group.clear.success .button[disabled]:hover{color:#3adb76}.button-group.clear .button.success:focus,.button-group.clear .button.success:hover,.button-group.clear.success .button:focus,.button-group.clear.success .button:hover{color:#157539}.button-group.clear .button.warning,.button-group.clear .button.warning.disabled,.button-group.clear .button.warning.disabled:focus,.button-group.clear .button.warning.disabled:hover,.button-group.clear .button.warning[disabled],.button-group.clear .button.warning[disabled]:focus,.button-group.clear .button.warning[disabled]:hover,.button-group.clear.warning .button,.button-group.clear.warning .button.disabled,.button-group.clear.warning .button.disabled:focus,.button-group.clear.warning .button.disabled:hover,.button-group.clear.warning .button[disabled],.button-group.clear.warning .button[disabled]:focus,.button-group.clear.warning .button[disabled]:hover{color:#ffae00}.button-group.clear .button.warning:focus,.button-group.clear .button.warning:hover,.button-group.clear.warning .button:focus,.button-group.clear.warning .button:hover{color:#805700}.button-group.clear .button.alert,.button-group.clear .button.alert.disabled,.button-group.clear .button.alert.disabled:focus,.button-group.clear .button.alert.disabled:hover,.button-group.clear .button.alert[disabled],.button-group.clear .button.alert[disabled]:focus,.button-group.clear .button.alert[disabled]:hover,.button-group.clear.alert .button,.button-group.clear.alert .button.disabled,.button-group.clear.alert .button.disabled:focus,.button-group.clear.alert .button.disabled:hover,.button-group.clear.alert .button[disabled],.button-group.clear.alert .button[disabled]:focus,.button-group.clear.alert .button[disabled]:hover{color:#cc4b37}.button-group.clear .button.alert:focus,.button-group.clear .button.alert:hover,.button-group.clear.alert .button:focus,.button-group.clear.alert .button:hover{color:#67251a}.button-group.no-gaps .button{margin-right:-.0625rem}.button-group.no-gaps .button+.button{border-left-color:transparent}.button-group.stacked,.button-group.stacked-for-medium,.button-group.stacked-for-small{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.button-group.stacked .button,.button-group.stacked-for-medium .button,.button-group.stacked-for-small .button{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%}.button-group.stacked .button:last-child,.button-group.stacked-for-medium .button:last-child,.button-group.stacked-for-small .button:last-child{margin-bottom:0}.button-group.stacked-for-medium.expanded .button,.button-group.stacked-for-small.expanded .button,.button-group.stacked.expanded .button{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}@media print,screen and (min-width:40em){.button-group.stacked-for-small .button{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;margin-bottom:0}}@media print,screen and (min-width:64em){.button-group.stacked-for-medium .button{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;margin-bottom:0}}@media print,screen and (max-width:39.99875em){.button-group.stacked-for-small.expanded{display:block}.button-group.stacked-for-small.expanded .button{display:block;margin-right:0}}@media print,screen and (max-width:63.99875em){.button-group.stacked-for-medium.expanded{display:block}.button-group.stacked-for-medium.expanded .button{display:block;margin-right:0}}.close-button{position:absolute;z-index:10;color:#8a8a8a;cursor:pointer}[data-whatinput=mouse] .close-button{outline:0}.close-button:focus,.close-button:hover{color:#0a0a0a}.close-button.small{right:.66rem;top:.33em;font-size:1.5em;line-height:1}.close-button,.close-button.medium{right:1rem;top:.5rem;font-size:2em;line-height:1}.label{display:inline-block;padding:.33333rem .5rem;border-radius:0;font-size:.8rem;line-height:1;white-space:nowrap;cursor:default;background:#1779ba;color:#fefefe}.label.primary{background:#1779ba;color:#fefefe}.label.secondary{background:#767676;color:#fefefe}.label.success{background:#3adb76;color:#0a0a0a}.label.warning{background:#ffae00;color:#0a0a0a}.label.alert{background:#cc4b37;color:#fefefe}.progress{height:1rem;margin-bottom:1rem;border-radius:0;background-color:#cacaca}.progress.primary .progress-meter{background-color:#1779ba}.progress.secondary .progress-meter{background-color:#767676}.progress.success .progress-meter{background-color:#3adb76}.progress.warning .progress-meter{background-color:#ffae00}.progress.alert .progress-meter{background-color:#cc4b37}.progress-meter{position:relative;display:block;width:0%;height:100%;background-color:#1779ba}.progress-meter-text{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);margin:0;font-size:.75rem;font-weight:700;color:#fefefe;white-space:nowrap}.slider{position:relative;height:.5rem;margin-top:1.25rem;margin-bottom:2.25rem;background-color:#e6e6e6;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-ms-touch-action:none;touch-action:none}.slider-fill{position:absolute;top:0;left:0;display:inline-block;max-width:100%;height:.5rem;background-color:#cacaca;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.slider-fill.is-dragging{-webkit-transition:all 0s linear;transition:all 0s linear}.slider-handle{position:absolute;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);left:0;z-index:1;display:inline-block;width:1.4rem;height:1.4rem;border-radius:0;background-color:#1779ba;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;-ms-touch-action:manipulation;touch-action:manipulation}[data-whatinput=mouse] .slider-handle{outline:0}.slider-handle:hover{background-color:#14679e}.slider-handle.is-dragging{-webkit-transition:all 0s linear;transition:all 0s linear}.slider.disabled,.slider[disabled]{opacity:.25;cursor:not-allowed}.slider.vertical{display:inline-block;width:.5rem;height:12.5rem;margin:0 1.25rem;-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}.slider.vertical .slider-fill{top:0;width:.5rem;max-height:100%}.slider.vertical .slider-handle{position:absolute;top:0;left:50%;width:1.4rem;height:1.4rem;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%)}.switch{height:2rem;position:relative;margin-bottom:1rem;outline:0;font-size:.875rem;font-weight:700;color:#fefefe;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.switch-input{position:absolute;margin-bottom:0;opacity:0}.switch-paddle{position:relative;display:block;width:4rem;height:2rem;border-radius:0;background:#cacaca;-webkit-transition:all .25s ease-out;transition:all .25s ease-out;font-weight:inherit;color:inherit;cursor:pointer}input+.switch-paddle{margin:0}.switch-paddle::after{position:absolute;top:.25rem;left:.25rem;display:block;width:1.5rem;height:1.5rem;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);border-radius:0;background:#fefefe;-webkit-transition:all .25s ease-out;transition:all .25s ease-out;content:''}input:checked~.switch-paddle{background:#1779ba}input:checked~.switch-paddle::after{left:2.25rem}input:disabled~.switch-paddle{cursor:not-allowed;opacity:.5}[data-whatinput=mouse] input:focus~.switch-paddle{outline:0}.switch-active,.switch-inactive{position:absolute;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%)}.switch-active{left:8%;display:none}input:checked+label>.switch-active{display:block}.switch-inactive{right:15%}input:checked+label>.switch-inactive{display:none}.switch.tiny{height:1.5rem}.switch.tiny .switch-paddle{width:3rem;height:1.5rem;font-size:.625rem}.switch.tiny .switch-paddle::after{top:.25rem;left:.25rem;width:1rem;height:1rem}.switch.tiny input:checked~.switch-paddle::after{left:1.75rem}.switch.small{height:1.75rem}.switch.small .switch-paddle{width:3.5rem;height:1.75rem;font-size:.75rem}.switch.small .switch-paddle::after{top:.25rem;left:.25rem;width:1.25rem;height:1.25rem}.switch.small input:checked~.switch-paddle::after{left:2rem}.switch.large{height:2.5rem}.switch.large .switch-paddle{width:5rem;height:2.5rem;font-size:1rem}.switch.large .switch-paddle::after{top:.25rem;left:.25rem;width:2rem;height:2rem}.switch.large input:checked~.switch-paddle::after{left:2.75rem}table{border-collapse:collapse;width:100%;margin-bottom:1rem;border-radius:0}tbody,tfoot,thead{border:1px solid #f1f1f1;background-color:#fefefe}caption{padding:.5rem .625rem .625rem;font-weight:700}thead{background:#f8f8f8;color:#0a0a0a}tfoot{background:#f1f1f1;color:#0a0a0a}tfoot tr,thead tr{background:0 0}tfoot td,tfoot th,thead td,thead th{padding:.5rem .625rem .625rem;font-weight:700;text-align:left}tbody td,tbody th{padding:.5rem .625rem .625rem}tbody tr:nth-child(even){border-bottom:0;background-color:#f1f1f1}table.unstriped tbody{background-color:#fefefe}table.unstriped tbody tr{border-bottom:0;border-bottom:1px solid #f1f1f1;background-color:#fefefe}@media print,screen and (max-width:63.99875em){table.stack thead{display:none}table.stack tfoot{display:none}table.stack td,table.stack th,table.stack tr{display:block}table.stack td{border-top:0}}table.scroll{display:block;width:100%;overflow-x:auto}table.hover thead tr:hover{background-color:#f3f3f3}table.hover tfoot tr:hover{background-color:#ececec}table.hover tbody tr:hover{background-color:#f9f9f9}table.hover:not(.unstriped) tr:nth-of-type(even):hover{background-color:#ececec}.table-scroll{overflow-x:auto}.badge{display:inline-block;min-width:2.1em;padding:.3em;border-radius:50%;font-size:.6rem;text-align:center;background:#1779ba;color:#fefefe}.badge.primary{background:#1779ba;color:#fefefe}.badge.secondary{background:#767676;color:#fefefe}.badge.success{background:#3adb76;color:#0a0a0a}.badge.warning{background:#ffae00;color:#0a0a0a}.badge.alert{background:#cc4b37;color:#fefefe}.breadcrumbs{margin:0 0 1rem 0;list-style:none}.breadcrumbs::after,.breadcrumbs::before{display:table;content:' ';-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}.breadcrumbs::after{clear:both}.breadcrumbs li{float:left;font-size:.6875rem;color:#0a0a0a;cursor:default;text-transform:uppercase}.breadcrumbs li:not(:last-child)::after{position:relative;margin:0 .75rem;opacity:1;content:"/";color:#cacaca}.breadcrumbs a{color:#1779ba}.breadcrumbs a:hover{text-decoration:underline}.breadcrumbs .disabled{color:#cacaca;cursor:not-allowed}.callout{position:relative;margin:0 0 1rem 0;padding:1rem;border:1px solid rgba(10,10,10,.25);border-radius:0;background-color:#fff;color:#0a0a0a}.callout>:first-child{margin-top:0}.callout>:last-child{margin-bottom:0}.callout.primary{background-color:#d7ecfa;color:#0a0a0a}.callout.secondary{background-color:#eaeaea;color:#0a0a0a}.callout.success{background-color:#e1faea;color:#0a0a0a}.callout.warning{background-color:#fff3d9;color:#0a0a0a}.callout.alert{background-color:#f7e4e1;color:#0a0a0a}.callout.small{padding-top:.5rem;padding-right:.5rem;padding-bottom:.5rem;padding-left:.5rem}.callout.large{padding-top:3rem;padding-right:3rem;padding-bottom:3rem;padding-left:3rem}.card{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-bottom:1rem;border:1px solid #e6e6e6;border-radius:0;background:#fefefe;-webkit-box-shadow:none;box-shadow:none;overflow:hidden;color:#0a0a0a}.card>:last-child{margin-bottom:0}.card-divider{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-webkit-flex:0 1 auto;-ms-flex:0 1 auto;flex:0 1 auto;padding:1rem;background:#e6e6e6}.card-divider>:last-child{margin-bottom:0}.card-section{-webkit-box-flex:1;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;padding:1rem}.card-section>:last-child{margin-bottom:0}.card-image{min-height:1px}.dropdown-pane{position:absolute;z-index:10;display:none;width:300px;padding:1rem;visibility:hidden;border:1px solid #cacaca;border-radius:0;background-color:#fefefe;font-size:1rem}.dropdown-pane.is-opening{display:block}.dropdown-pane.is-open{display:block;visibility:visible}.dropdown-pane.tiny{width:100px}.dropdown-pane.small{width:200px}.dropdown-pane.large{width:400px}.pagination{margin-left:0;margin-bottom:1rem}.pagination::after,.pagination::before{display:table;content:' ';-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}.pagination::after{clear:both}.pagination li{margin-right:.0625rem;border-radius:0;font-size:.875rem;display:none}.pagination li:first-child,.pagination li:last-child{display:inline-block}@media print,screen and (min-width:40em){.pagination li{display:inline-block}}.pagination a,.pagination button{display:block;padding:.1875rem .625rem;border-radius:0;color:#0a0a0a}.pagination a:hover,.pagination button:hover{background:#e6e6e6}.pagination .current{padding:.1875rem .625rem;background:#1779ba;color:#fefefe;cursor:default}.pagination .disabled{padding:.1875rem .625rem;color:#cacaca;cursor:not-allowed}.pagination .disabled:hover{background:0 0}.pagination .ellipsis::after{padding:.1875rem .625rem;content:'\2026';color:#0a0a0a}.pagination-previous a::before,.pagination-previous.disabled::before{display:inline-block;margin-right:.5rem;content:"«"}.pagination-next a::after,.pagination-next.disabled::after{display:inline-block;margin-left:.5rem;content:"»"}.has-tip{position:relative;display:inline-block;border-bottom:dotted 1px #8a8a8a;font-weight:700;cursor:help}.tooltip{position:absolute;top:calc(100% + .6495rem);z-index:1200;max-width:10rem;padding:.75rem;border-radius:0;background-color:#0a0a0a;font-size:80%;color:#fefefe}.tooltip::before{position:absolute}.tooltip.bottom::before{display:block;width:0;height:0;border-style:solid;border-width:.75rem;content:'';border-top-width:0;border-color:transparent transparent #0a0a0a;bottom:100%}.tooltip.bottom.align-center::before{left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%)}.tooltip.top::before{display:block;width:0;height:0;border-style:solid;border-width:.75rem;content:'';border-bottom-width:0;border-color:#0a0a0a transparent transparent;top:100%;bottom:auto}.tooltip.top.align-center::before{left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%)}.tooltip.left::before{display:block;width:0;height:0;border-style:solid;border-width:.75rem;content:'';border-right-width:0;border-color:transparent transparent transparent #0a0a0a;left:100%}.tooltip.left.align-center::before{bottom:auto;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%)}.tooltip.right::before{display:block;width:0;height:0;border-style:solid;border-width:.75rem;content:'';border-left-width:0;border-color:transparent #0a0a0a transparent transparent;right:100%;left:auto}.tooltip.right.align-center::before{bottom:auto;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%)}.tooltip.align-top::before{bottom:auto;top:10%}.tooltip.align-bottom::before{bottom:10%;top:auto}.tooltip.align-left::before{left:10%;right:auto}.tooltip.align-right::before{left:auto;right:10%}.accordion{margin-left:0;background:#fefefe;list-style-type:none}.accordion[disabled] .accordion-title{cursor:not-allowed}.accordion-item:first-child>:first-child{border-radius:0}.accordion-item:last-child>:last-child{border-radius:0}.accordion-title{position:relative;display:block;padding:1.25rem 1rem;border:1px solid #e6e6e6;border-bottom:0;font-size:.75rem;line-height:1;color:#1779ba}:last-child:not(.is-active)>.accordion-title{border-bottom:1px solid #e6e6e6;border-radius:0}.accordion-title:focus,.accordion-title:hover{background-color:#e6e6e6}.accordion-title::before{position:absolute;top:50%;right:1rem;margin-top:-.5rem;content:"+"}.is-active>.accordion-title::before{content:"–"}.accordion-content{display:none;padding:1rem;border:1px solid #e6e6e6;border-bottom:0;background-color:#fefefe;color:#0a0a0a}:last-child>.accordion-content:last-child{border-bottom:1px solid #e6e6e6}.media-object{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:1rem;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.media-object img{max-width:none}@media print,screen and (max-width:39.99875em){.media-object.stack-for-small{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}}.media-object-section{-webkit-box-flex:0;-webkit-flex:0 1 auto;-ms-flex:0 1 auto;flex:0 1 auto}.media-object-section:first-child{padding-right:1rem}.media-object-section:last-child:not(:nth-child(2)){padding-left:1rem}.media-object-section>:last-child{margin-bottom:0}@media print,screen and (max-width:39.99875em){.stack-for-small .media-object-section{padding:0;padding-bottom:1rem;-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%;max-width:100%}.stack-for-small .media-object-section img{width:100%}}.media-object-section.main-section{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}.orbit{position:relative}.orbit-container{position:relative;height:0;margin:0;list-style:none;overflow:hidden}.orbit-slide{width:100%;position:absolute}.orbit-slide.no-motionui.is-active{top:0;left:0}.orbit-figure{margin:0}.orbit-image{width:100%;max-width:100%;margin:0}.orbit-caption{position:absolute;bottom:0;width:100%;margin-bottom:0;padding:1rem;background-color:rgba(10,10,10,.5);color:#fefefe}.orbit-next,.orbit-previous{position:absolute;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);z-index:10;padding:1rem;color:#fefefe}[data-whatinput=mouse] .orbit-next,[data-whatinput=mouse] .orbit-previous{outline:0}.orbit-next:active,.orbit-next:focus,.orbit-next:hover,.orbit-previous:active,.orbit-previous:focus,.orbit-previous:hover{background-color:rgba(10,10,10,.5)}.orbit-previous{left:0}.orbit-next{left:auto;right:0}.orbit-bullets{position:relative;margin-top:.8rem;margin-bottom:.8rem;text-align:center}[data-whatinput=mouse] .orbit-bullets{outline:0}.orbit-bullets button{width:1.2rem;height:1.2rem;margin:.1rem;border-radius:50%;background-color:#cacaca}.orbit-bullets button:hover{background-color:#8a8a8a}.orbit-bullets button.is-active{background-color:#8a8a8a}.flex-video,.responsive-embed{position:relative;height:0;margin-bottom:1rem;padding-bottom:75%;overflow:hidden}.flex-video embed,.flex-video iframe,.flex-video object,.flex-video video,.responsive-embed embed,.responsive-embed iframe,.responsive-embed object,.responsive-embed video{position:absolute;top:0;left:0;width:100%;height:100%}.flex-video.widescreen,.responsive-embed.widescreen{padding-bottom:56.25%}.tabs{margin:0;border:1px solid #e6e6e6;background:#fefefe;list-style-type:none}.tabs::after,.tabs::before{display:table;content:' ';-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}.tabs::after{clear:both}.tabs.vertical>li{display:block;float:none;width:auto}.tabs.simple>li>a{padding:0}.tabs.simple>li>a:hover{background:0 0}.tabs.primary{background:#1779ba}.tabs.primary>li>a{color:#fefefe}.tabs.primary>li>a:focus,.tabs.primary>li>a:hover{background:#1673b1}.tabs-title{float:left}.tabs-title>a{display:block;padding:1.25rem 1.5rem;font-size:.75rem;line-height:1;color:#1779ba}[data-whatinput=mouse] .tabs-title>a{outline:0}.tabs-title>a:hover{background:#fefefe;color:#1468a0}.tabs-title>a:focus,.tabs-title>a[aria-selected=true]{background:#e6e6e6;color:#1779ba}.tabs-content{border:1px solid #e6e6e6;border-top:0;background:#fefefe;color:#0a0a0a;-webkit-transition:all .5s ease;transition:all .5s ease}.tabs-content.vertical{border:1px solid #e6e6e6;border-left:0}.tabs-panel{display:none;padding:1rem}.tabs-panel.is-active{display:block}.thumbnail{display:inline-block;max-width:100%;margin-bottom:1rem;border:4px solid #fefefe;border-radius:0;-webkit-box-shadow:0 0 0 1px rgba(10,10,10,.2);box-shadow:0 0 0 1px rgba(10,10,10,.2);line-height:0}a.thumbnail{-webkit-transition:-webkit-box-shadow .2s ease-out;transition:-webkit-box-shadow .2s ease-out;transition:box-shadow .2s ease-out;transition:box-shadow .2s ease-out,-webkit-box-shadow .2s ease-out}a.thumbnail:focus,a.thumbnail:hover{-webkit-box-shadow:0 0 6px 1px rgba(23,121,186,.5);box-shadow:0 0 6px 1px rgba(23,121,186,.5)}a.thumbnail image{-webkit-box-shadow:none;box-shadow:none}.menu{padding:0;margin:0;list-style:none;position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}[data-whatinput=mouse] .menu li{outline:0}.menu .button,.menu a{line-height:1;text-decoration:none;display:block;padding:.7rem 1rem}.menu a,.menu button,.menu input,.menu select{margin-bottom:0}.menu input{display:inline-block}.menu,.menu.horizontal{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.menu.vertical{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.menu.vertical.icon-bottom li a i,.menu.vertical.icon-bottom li a img,.menu.vertical.icon-bottom li a svg,.menu.vertical.icon-top li a i,.menu.vertical.icon-top li a img,.menu.vertical.icon-top li a svg{text-align:left}.menu.expanded li{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}.menu.expanded.icon-bottom li a i,.menu.expanded.icon-bottom li a img,.menu.expanded.icon-bottom li a svg,.menu.expanded.icon-top li a i,.menu.expanded.icon-top li a img,.menu.expanded.icon-top li a svg{text-align:left}.menu.simple{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.menu.simple li+li{margin-left:1rem}.menu.simple a{padding:0}@media print,screen and (min-width:40em){.menu.medium-horizontal{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.menu.medium-vertical{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.menu.medium-expanded li{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}.menu.medium-simple li{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}}@media print,screen and (min-width:64em){.menu.large-horizontal{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.menu.large-vertical{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.menu.large-expanded li{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}.menu.large-simple li{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}}.menu.nested{margin-right:0;margin-left:1rem}.menu.icons a{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.menu.icon-bottom a,.menu.icon-left a,.menu.icon-right a,.menu.icon-top a{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.menu.icon-left li a,.menu.nested.icon-left li a{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-flow:row nowrap;-ms-flex-flow:row nowrap;flex-flow:row nowrap}.menu.icon-left li a i,.menu.icon-left li a img,.menu.icon-left li a svg,.menu.nested.icon-left li a i,.menu.nested.icon-left li a img,.menu.nested.icon-left li a svg{margin-right:.25rem}.menu.icon-right li a,.menu.nested.icon-right li a{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-flow:row nowrap;-ms-flex-flow:row nowrap;flex-flow:row nowrap}.menu.icon-right li a i,.menu.icon-right li a img,.menu.icon-right li a svg,.menu.nested.icon-right li a i,.menu.nested.icon-right li a img,.menu.nested.icon-right li a svg{margin-left:.25rem}.menu.icon-top li a,.menu.nested.icon-top li a{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-flow:column nowrap;-ms-flex-flow:column nowrap;flex-flow:column nowrap}.menu.icon-top li a i,.menu.icon-top li a img,.menu.icon-top li a svg,.menu.nested.icon-top li a i,.menu.nested.icon-top li a img,.menu.nested.icon-top li a svg{-webkit-align-self:stretch;-ms-flex-item-align:stretch;align-self:stretch;margin-bottom:.25rem;text-align:center}.menu.icon-bottom li a,.menu.nested.icon-bottom li a{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-flow:column nowrap;-ms-flex-flow:column nowrap;flex-flow:column nowrap}.menu.icon-bottom li a i,.menu.icon-bottom li a img,.menu.icon-bottom li a svg,.menu.nested.icon-bottom li a i,.menu.nested.icon-bottom li a img,.menu.nested.icon-bottom li a svg{-webkit-align-self:stretch;-ms-flex-item-align:stretch;align-self:stretch;margin-bottom:.25rem;text-align:center}.menu .is-active>a{background:#1779ba;color:#fefefe}.menu .active>a{background:#1779ba;color:#fefefe}.menu.align-left{-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.menu.align-right li{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}.menu.align-right li .submenu li{-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.menu.align-right.vertical li{display:block;text-align:right}.menu.align-right.vertical li .submenu li{text-align:right}.menu.align-right.icon-bottom li a i,.menu.align-right.icon-bottom li a img,.menu.align-right.icon-bottom li a svg,.menu.align-right.icon-top li a i,.menu.align-right.icon-top li a img,.menu.align-right.icon-top li a svg{text-align:right}.menu.align-right .nested{margin-right:1rem;margin-left:0}.menu.align-center li{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.menu.align-center li .submenu li{-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.menu .menu-text{padding:.7rem 1rem;font-weight:700;line-height:1;color:inherit}.menu-centered>.menu{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.menu-centered>.menu li{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.menu-centered>.menu li .submenu li{-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.no-js [data-responsive-menu] ul{display:none}.menu-icon{position:relative;display:inline-block;vertical-align:middle;width:20px;height:16px;cursor:pointer}.menu-icon::after{position:absolute;top:0;left:0;display:block;width:100%;height:2px;background:#fefefe;-webkit-box-shadow:0 7px 0 #fefefe,0 14px 0 #fefefe;box-shadow:0 7px 0 #fefefe,0 14px 0 #fefefe;content:''}.menu-icon:hover::after{background:#cacaca;-webkit-box-shadow:0 7px 0 #cacaca,0 14px 0 #cacaca;box-shadow:0 7px 0 #cacaca,0 14px 0 #cacaca}.menu-icon.dark{position:relative;display:inline-block;vertical-align:middle;width:20px;height:16px;cursor:pointer}.menu-icon.dark::after{position:absolute;top:0;left:0;display:block;width:100%;height:2px;background:#0a0a0a;-webkit-box-shadow:0 7px 0 #0a0a0a,0 14px 0 #0a0a0a;box-shadow:0 7px 0 #0a0a0a,0 14px 0 #0a0a0a;content:''}.menu-icon.dark:hover::after{background:#8a8a8a;-webkit-box-shadow:0 7px 0 #8a8a8a,0 14px 0 #8a8a8a;box-shadow:0 7px 0 #8a8a8a,0 14px 0 #8a8a8a}.accordion-menu li{width:100%}.accordion-menu a{padding:.7rem 1rem}.accordion-menu .is-accordion-submenu a{padding:.7rem 1rem}.accordion-menu .nested.is-accordion-submenu{margin-right:0;margin-left:1rem}.accordion-menu.align-right .nested.is-accordion-submenu{margin-right:1rem;margin-left:0}.accordion-menu .is-accordion-submenu-parent:not(.has-submenu-toggle)>a{position:relative}.accordion-menu .is-accordion-submenu-parent:not(.has-submenu-toggle)>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-bottom-width:0;border-color:#1779ba transparent transparent;position:absolute;top:50%;margin-top:-3px;right:1rem}.accordion-menu.align-left .is-accordion-submenu-parent>a::after{right:1rem;left:auto}.accordion-menu.align-right .is-accordion-submenu-parent>a::after{right:auto;left:1rem}.accordion-menu .is-accordion-submenu-parent[aria-expanded=true]>a::after{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}.is-accordion-submenu-parent{position:relative}.has-submenu-toggle>a{margin-right:40px}.submenu-toggle{position:absolute;top:0;right:0;width:40px;height:40px;cursor:pointer}.submenu-toggle::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-bottom-width:0;border-color:#1779ba transparent transparent;top:0;bottom:0;margin:auto}.submenu-toggle[aria-expanded=true]::after{-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1);-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%}.submenu-toggle-text{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.is-drilldown{position:relative;overflow:hidden}.is-drilldown li{display:block}.is-drilldown.animate-height{-webkit-transition:height .5s;transition:height .5s}.drilldown a{padding:.7rem 1rem;background:#fefefe}.drilldown .is-drilldown-submenu{position:absolute;top:0;left:100%;z-index:-1;width:100%;background:#fefefe;-webkit-transition:-webkit-transform .15s linear;transition:-webkit-transform .15s linear;transition:transform .15s linear;transition:transform .15s linear,-webkit-transform .15s linear}.drilldown .is-drilldown-submenu.is-active{z-index:1;display:block;-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%)}.drilldown .is-drilldown-submenu.is-closing{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%)}.drilldown .is-drilldown-submenu a{padding:.7rem 1rem}.drilldown .nested.is-drilldown-submenu{margin-right:0;margin-left:0}.drilldown .drilldown-submenu-cover-previous{min-height:100%}.drilldown .is-drilldown-submenu-parent>a{position:relative}.drilldown .is-drilldown-submenu-parent>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-right-width:0;border-color:transparent transparent transparent #1779ba;position:absolute;top:50%;margin-top:-6px;right:1rem}.drilldown.align-left .is-drilldown-submenu-parent>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-right-width:0;border-color:transparent transparent transparent #1779ba;right:1rem;left:auto}.drilldown.align-right .is-drilldown-submenu-parent>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-left-width:0;border-color:transparent #1779ba transparent transparent;right:auto;left:1rem}.drilldown .js-drilldown-back>a::before{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-left-width:0;border-color:transparent #1779ba transparent transparent;display:inline-block;vertical-align:middle;margin-right:.75rem}.dropdown.menu>li.opens-left>.is-dropdown-submenu{top:100%;right:0;left:auto}.dropdown.menu>li.opens-right>.is-dropdown-submenu{top:100%;right:auto;left:0}.dropdown.menu>li.is-dropdown-submenu-parent>a{position:relative;padding-right:1.5rem}.dropdown.menu>li.is-dropdown-submenu-parent>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-bottom-width:0;border-color:#1779ba transparent transparent;right:5px;left:auto;margin-top:-3px}[data-whatinput=mouse] .dropdown.menu a{outline:0}.dropdown.menu>li>a{padding:.7rem 1rem}.dropdown.menu>li.is-active>a{background:0 0;color:#1779ba}.no-js .dropdown.menu ul{display:none}.dropdown.menu .nested.is-dropdown-submenu{margin-right:0;margin-left:0}.dropdown.menu.vertical>li .is-dropdown-submenu{top:0}.dropdown.menu.vertical>li.opens-left>.is-dropdown-submenu{top:0;right:100%;left:auto}.dropdown.menu.vertical>li.opens-right>.is-dropdown-submenu{right:auto;left:100%}.dropdown.menu.vertical>li>a::after{right:14px}.dropdown.menu.vertical>li.opens-left>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-left-width:0;border-color:transparent #1779ba transparent transparent;right:auto;left:5px}.dropdown.menu.vertical>li.opens-right>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-right-width:0;border-color:transparent transparent transparent #1779ba}@media print,screen and (min-width:40em){.dropdown.menu.medium-horizontal>li.opens-left>.is-dropdown-submenu{top:100%;right:0;left:auto}.dropdown.menu.medium-horizontal>li.opens-right>.is-dropdown-submenu{top:100%;right:auto;left:0}.dropdown.menu.medium-horizontal>li.is-dropdown-submenu-parent>a{position:relative;padding-right:1.5rem}.dropdown.menu.medium-horizontal>li.is-dropdown-submenu-parent>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-bottom-width:0;border-color:#1779ba transparent transparent;right:5px;left:auto;margin-top:-3px}.dropdown.menu.medium-vertical>li .is-dropdown-submenu{top:0}.dropdown.menu.medium-vertical>li.opens-left>.is-dropdown-submenu{top:0;right:100%;left:auto}.dropdown.menu.medium-vertical>li.opens-right>.is-dropdown-submenu{right:auto;left:100%}.dropdown.menu.medium-vertical>li>a::after{right:14px}.dropdown.menu.medium-vertical>li.opens-left>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-left-width:0;border-color:transparent #1779ba transparent transparent;right:auto;left:5px}.dropdown.menu.medium-vertical>li.opens-right>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-right-width:0;border-color:transparent transparent transparent #1779ba}}@media print,screen and (min-width:64em){.dropdown.menu.large-horizontal>li.opens-left>.is-dropdown-submenu{top:100%;right:0;left:auto}.dropdown.menu.large-horizontal>li.opens-right>.is-dropdown-submenu{top:100%;right:auto;left:0}.dropdown.menu.large-horizontal>li.is-dropdown-submenu-parent>a{position:relative;padding-right:1.5rem}.dropdown.menu.large-horizontal>li.is-dropdown-submenu-parent>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-bottom-width:0;border-color:#1779ba transparent transparent;right:5px;left:auto;margin-top:-3px}.dropdown.menu.large-vertical>li .is-dropdown-submenu{top:0}.dropdown.menu.large-vertical>li.opens-left>.is-dropdown-submenu{top:0;right:100%;left:auto}.dropdown.menu.large-vertical>li.opens-right>.is-dropdown-submenu{right:auto;left:100%}.dropdown.menu.large-vertical>li>a::after{right:14px}.dropdown.menu.large-vertical>li.opens-left>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-left-width:0;border-color:transparent #1779ba transparent transparent;right:auto;left:5px}.dropdown.menu.large-vertical>li.opens-right>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-right-width:0;border-color:transparent transparent transparent #1779ba}}.dropdown.menu.align-right .is-dropdown-submenu.first-sub{top:100%;right:0;left:auto}.is-dropdown-menu.vertical{width:100px}.is-dropdown-menu.vertical.align-right{float:right}.is-dropdown-submenu-parent{position:relative}.is-dropdown-submenu-parent a::after{position:absolute;top:50%;right:5px;left:auto;margin-top:-6px}.is-dropdown-submenu-parent.opens-inner>.is-dropdown-submenu{top:100%;left:auto}.is-dropdown-submenu-parent.opens-left>.is-dropdown-submenu{right:100%;left:auto}.is-dropdown-submenu-parent.opens-right>.is-dropdown-submenu{right:auto;left:100%}.is-dropdown-submenu{position:absolute;top:0;left:100%;z-index:1;display:none;min-width:200px;border:1px solid #cacaca;background:#fefefe}.dropdown .is-dropdown-submenu a{padding:.7rem 1rem}.is-dropdown-submenu .is-dropdown-submenu-parent>a::after{right:14px}.is-dropdown-submenu .is-dropdown-submenu-parent.opens-left>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-left-width:0;border-color:transparent #1779ba transparent transparent;right:auto;left:5px}.is-dropdown-submenu .is-dropdown-submenu-parent.opens-right>a::after{display:block;width:0;height:0;border-style:solid;border-width:6px;content:'';border-right-width:0;border-color:transparent transparent transparent #1779ba}.is-dropdown-submenu .is-dropdown-submenu{margin-top:-1px}.is-dropdown-submenu>li{width:100%}.is-dropdown-submenu.js-dropdown-active{display:block}.is-off-canvas-open{overflow:hidden}.js-off-canvas-overlay{position:absolute;top:0;left:0;z-index:11;width:100%;height:100%;-webkit-transition:opacity .5s ease,visibility .5s ease;transition:opacity .5s ease,visibility .5s ease;background:rgba(254,254,254,.25);opacity:0;visibility:hidden;overflow:hidden}.js-off-canvas-overlay.is-visible{opacity:1;visibility:visible}.js-off-canvas-overlay.is-closable{cursor:pointer}.js-off-canvas-overlay.is-overlay-absolute{position:absolute}.js-off-canvas-overlay.is-overlay-fixed{position:fixed}.off-canvas-wrapper{position:relative;overflow:hidden}.off-canvas{position:fixed;z-index:12;-webkit-transition:-webkit-transform .5s ease;transition:-webkit-transform .5s ease;transition:transform .5s ease;transition:transform .5s ease,-webkit-transform .5s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:#e6e6e6}[data-whatinput=mouse] .off-canvas{outline:0}.off-canvas.is-transition-push{z-index:12}.off-canvas.is-closed{visibility:hidden}.off-canvas.is-transition-overlap{z-index:13}.off-canvas.is-transition-overlap.is-open{-webkit-box-shadow:0 0 10px rgba(10,10,10,.7);box-shadow:0 0 10px rgba(10,10,10,.7)}.off-canvas.is-open{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.off-canvas-absolute{position:absolute;z-index:12;-webkit-transition:-webkit-transform .5s ease;transition:-webkit-transform .5s ease;transition:transform .5s ease;transition:transform .5s ease,-webkit-transform .5s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;background:#e6e6e6}[data-whatinput=mouse] .off-canvas-absolute{outline:0}.off-canvas-absolute.is-transition-push{z-index:12}.off-canvas-absolute.is-closed{visibility:hidden}.off-canvas-absolute.is-transition-overlap{z-index:13}.off-canvas-absolute.is-transition-overlap.is-open{-webkit-box-shadow:0 0 10px rgba(10,10,10,.7);box-shadow:0 0 10px rgba(10,10,10,.7)}.off-canvas-absolute.is-open{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.position-left{top:0;left:0;height:100%;overflow-y:auto;width:250px;-webkit-transform:translateX(-250px);-ms-transform:translateX(-250px);transform:translateX(-250px)}.off-canvas-content .off-canvas.position-left{-webkit-transform:translateX(-250px);-ms-transform:translateX(-250px);transform:translateX(-250px)}.off-canvas-content .off-canvas.position-left.is-transition-overlap.is-open{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.off-canvas-content.is-open-left.has-transition-push{-webkit-transform:translateX(250px);-ms-transform:translateX(250px);transform:translateX(250px)}.position-left.is-transition-push{-webkit-box-shadow:inset -13px 0 20px -13px rgba(10,10,10,.25);box-shadow:inset -13px 0 20px -13px rgba(10,10,10,.25)}.position-right{top:0;right:0;height:100%;overflow-y:auto;width:250px;-webkit-transform:translateX(250px);-ms-transform:translateX(250px);transform:translateX(250px)}.off-canvas-content .off-canvas.position-right{-webkit-transform:translateX(250px);-ms-transform:translateX(250px);transform:translateX(250px)}.off-canvas-content .off-canvas.position-right.is-transition-overlap.is-open{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.off-canvas-content.is-open-right.has-transition-push{-webkit-transform:translateX(-250px);-ms-transform:translateX(-250px);transform:translateX(-250px)}.position-right.is-transition-push{-webkit-box-shadow:inset 13px 0 20px -13px rgba(10,10,10,.25);box-shadow:inset 13px 0 20px -13px rgba(10,10,10,.25)}.position-top{top:0;left:0;width:100%;overflow-x:auto;height:250px;-webkit-transform:translateY(-250px);-ms-transform:translateY(-250px);transform:translateY(-250px)}.off-canvas-content .off-canvas.position-top{-webkit-transform:translateY(-250px);-ms-transform:translateY(-250px);transform:translateY(-250px)}.off-canvas-content .off-canvas.position-top.is-transition-overlap.is-open{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.off-canvas-content.is-open-top.has-transition-push{-webkit-transform:translateY(250px);-ms-transform:translateY(250px);transform:translateY(250px)}.position-top.is-transition-push{-webkit-box-shadow:inset 0 -13px 20px -13px rgba(10,10,10,.25);box-shadow:inset 0 -13px 20px -13px rgba(10,10,10,.25)}.position-bottom{bottom:0;left:0;width:100%;overflow-x:auto;height:250px;-webkit-transform:translateY(250px);-ms-transform:translateY(250px);transform:translateY(250px)}.off-canvas-content .off-canvas.position-bottom{-webkit-transform:translateY(250px);-ms-transform:translateY(250px);transform:translateY(250px)}.off-canvas-content .off-canvas.position-bottom.is-transition-overlap.is-open{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.off-canvas-content.is-open-bottom.has-transition-push{-webkit-transform:translateY(-250px);-ms-transform:translateY(-250px);transform:translateY(-250px)}.position-bottom.is-transition-push{-webkit-box-shadow:inset 0 13px 20px -13px rgba(10,10,10,.25);box-shadow:inset 0 13px 20px -13px rgba(10,10,10,.25)}.off-canvas-content{-webkit-transform:none;-ms-transform:none;transform:none;-webkit-backface-visibility:hidden;backface-visibility:hidden}.off-canvas-content.has-transition-overlap,.off-canvas-content.has-transition-push{-webkit-transition:-webkit-transform .5s ease;transition:-webkit-transform .5s ease;transition:transform .5s ease;transition:transform .5s ease,-webkit-transform .5s ease}.off-canvas-content.has-transition-push{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.off-canvas-content .off-canvas.is-open{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}@media print,screen and (min-width:40em){.position-left.reveal-for-medium{-webkit-transform:none;-ms-transform:none;transform:none;z-index:12;-webkit-transition:none;transition:none;visibility:visible}.position-left.reveal-for-medium .close-button{display:none}.off-canvas-content .position-left.reveal-for-medium{-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas-content.has-reveal-left{margin-left:250px}.position-left.reveal-for-medium~.off-canvas-content{margin-left:250px}.position-right.reveal-for-medium{-webkit-transform:none;-ms-transform:none;transform:none;z-index:12;-webkit-transition:none;transition:none;visibility:visible}.position-right.reveal-for-medium .close-button{display:none}.off-canvas-content .position-right.reveal-for-medium{-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas-content.has-reveal-right{margin-right:250px}.position-right.reveal-for-medium~.off-canvas-content{margin-right:250px}.position-top.reveal-for-medium{-webkit-transform:none;-ms-transform:none;transform:none;z-index:12;-webkit-transition:none;transition:none;visibility:visible}.position-top.reveal-for-medium .close-button{display:none}.off-canvas-content .position-top.reveal-for-medium{-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas-content.has-reveal-top{margin-top:250px}.position-top.reveal-for-medium~.off-canvas-content{margin-top:250px}.position-bottom.reveal-for-medium{-webkit-transform:none;-ms-transform:none;transform:none;z-index:12;-webkit-transition:none;transition:none;visibility:visible}.position-bottom.reveal-for-medium .close-button{display:none}.off-canvas-content .position-bottom.reveal-for-medium{-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas-content.has-reveal-bottom{margin-bottom:250px}.position-bottom.reveal-for-medium~.off-canvas-content{margin-bottom:250px}}@media print,screen and (min-width:64em){.position-left.reveal-for-large{-webkit-transform:none;-ms-transform:none;transform:none;z-index:12;-webkit-transition:none;transition:none;visibility:visible}.position-left.reveal-for-large .close-button{display:none}.off-canvas-content .position-left.reveal-for-large{-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas-content.has-reveal-left{margin-left:250px}.position-left.reveal-for-large~.off-canvas-content{margin-left:250px}.position-right.reveal-for-large{-webkit-transform:none;-ms-transform:none;transform:none;z-index:12;-webkit-transition:none;transition:none;visibility:visible}.position-right.reveal-for-large .close-button{display:none}.off-canvas-content .position-right.reveal-for-large{-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas-content.has-reveal-right{margin-right:250px}.position-right.reveal-for-large~.off-canvas-content{margin-right:250px}.position-top.reveal-for-large{-webkit-transform:none;-ms-transform:none;transform:none;z-index:12;-webkit-transition:none;transition:none;visibility:visible}.position-top.reveal-for-large .close-button{display:none}.off-canvas-content .position-top.reveal-for-large{-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas-content.has-reveal-top{margin-top:250px}.position-top.reveal-for-large~.off-canvas-content{margin-top:250px}.position-bottom.reveal-for-large{-webkit-transform:none;-ms-transform:none;transform:none;z-index:12;-webkit-transition:none;transition:none;visibility:visible}.position-bottom.reveal-for-large .close-button{display:none}.off-canvas-content .position-bottom.reveal-for-large{-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas-content.has-reveal-bottom{margin-bottom:250px}.position-bottom.reveal-for-large~.off-canvas-content{margin-bottom:250px}}@media print,screen and (min-width:40em){.off-canvas.in-canvas-for-medium{visibility:visible;height:auto;position:static;background:0 0;width:auto;overflow:visible;-webkit-transition:none;transition:none}.off-canvas.in-canvas-for-medium.position-bottom,.off-canvas.in-canvas-for-medium.position-left,.off-canvas.in-canvas-for-medium.position-right,.off-canvas.in-canvas-for-medium.position-top{-webkit-box-shadow:none;box-shadow:none;-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas.in-canvas-for-medium .close-button{display:none}}@media print,screen and (min-width:64em){.off-canvas.in-canvas-for-large{visibility:visible;height:auto;position:static;background:0 0;width:auto;overflow:visible;-webkit-transition:none;transition:none}.off-canvas.in-canvas-for-large.position-bottom,.off-canvas.in-canvas-for-large.position-left,.off-canvas.in-canvas-for-large.position-right,.off-canvas.in-canvas-for-large.position-top{-webkit-box-shadow:none;box-shadow:none;-webkit-transform:none;-ms-transform:none;transform:none}.off-canvas.in-canvas-for-large .close-button{display:none}}html.is-reveal-open{position:fixed;width:100%;overflow-y:hidden}html.is-reveal-open.zf-has-scroll{overflow-y:scroll}html.is-reveal-open body{overflow-y:hidden}.reveal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1005;display:none;background-color:rgba(10,10,10,.45);overflow-y:auto}.reveal{z-index:1006;-webkit-backface-visibility:hidden;backface-visibility:hidden;display:none;padding:1rem;border:1px solid #cacaca;border-radius:0;background-color:#fefefe;position:relative;top:100px;margin-right:auto;margin-left:auto;overflow-y:auto}[data-whatinput=mouse] .reveal{outline:0}@media print,screen and (min-width:40em){.reveal{min-height:0}}.reveal .column{min-width:0}.reveal>:last-child{margin-bottom:0}@media print,screen and (min-width:40em){.reveal{width:600px;max-width:75rem}}.reveal.collapse{padding:0}@media print,screen and (min-width:40em){.reveal.tiny{width:30%;max-width:75rem}}@media print,screen and (min-width:40em){.reveal.small{width:50%;max-width:75rem}}@media print,screen and (min-width:40em){.reveal.large{width:90%;max-width:75rem}}.reveal.full{top:0;right:0;bottom:0;left:0;width:100%;max-width:none;height:100%;min-height:100%;margin-left:0;border:0;border-radius:0}@media print,screen and (max-width:39.99875em){.reveal{top:0;right:0;bottom:0;left:0;width:100%;max-width:none;height:100%;min-height:100%;margin-left:0;border:0;border-radius:0}}.reveal.without-overlay{position:fixed}.sticky-container{position:relative}.sticky{position:relative;z-index:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.sticky.is-stuck{position:fixed;z-index:5;width:100%}.sticky.is-stuck.is-at-top{top:0}.sticky.is-stuck.is-at-bottom{bottom:0}.sticky.is-anchored{position:relative;right:auto;left:auto}.sticky.is-anchored.is-at-bottom{bottom:0}.title-bar{padding:.5rem;background:#0a0a0a;color:#fefefe;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.title-bar .menu-icon{margin-left:.25rem;margin-right:.25rem}.title-bar-left,.title-bar-right{-webkit-box-flex:1;-webkit-flex:1 1 0px;-ms-flex:1 1 0px;flex:1 1 0px}.title-bar-right{text-align:right}.title-bar-title{display:inline-block;vertical-align:middle;font-weight:700}.top-bar{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;padding:.5rem;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.top-bar,.top-bar ul{background-color:#e6e6e6}.top-bar input{max-width:200px;margin-right:1rem}.top-bar .input-group-field{width:100%;margin-right:0}.top-bar input.button{width:auto}.top-bar .top-bar-left,.top-bar .top-bar-right{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}@media print,screen and (min-width:40em){.top-bar{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.top-bar .top-bar-left{-webkit-box-flex:1;-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto;margin-right:auto}.top-bar .top-bar-right{-webkit-box-flex:0;-webkit-flex:0 1 auto;-ms-flex:0 1 auto;flex:0 1 auto;margin-left:auto}}@media print,screen and (max-width:63.99875em){.top-bar.stacked-for-medium{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.top-bar.stacked-for-medium .top-bar-left,.top-bar.stacked-for-medium .top-bar-right{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}@media print,screen and (max-width:74.99875em){.top-bar.stacked-for-large{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.top-bar.stacked-for-large .top-bar-left,.top-bar.stacked-for-large .top-bar-right{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}.top-bar-title{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;margin:.5rem 1rem .5rem 0}.top-bar-left,.top-bar-right{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}.float-left{float:left!important}.float-right{float:right!important}.float-center{display:block;margin-right:auto;margin-left:auto}.clearfix::after,.clearfix::before{display:table;content:' ';-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}.clearfix::after{clear:both}.align-left{-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.align-right{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}.align-center{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.align-justify{-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.align-spaced{-webkit-justify-content:space-around;-ms-flex-pack:distribute;justify-content:space-around}.align-left.vertical.menu>li>a{-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.align-right.vertical.menu>li>a{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}.align-center.vertical.menu>li>a{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.align-top{-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start}.align-self-top{-webkit-align-self:flex-start;-ms-flex-item-align:start;align-self:flex-start}.align-bottom{-webkit-box-align:end;-webkit-align-items:flex-end;-ms-flex-align:end;align-items:flex-end}.align-self-bottom{-webkit-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end}.align-middle{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.align-self-middle{-webkit-align-self:center;-ms-flex-item-align:center;align-self:center}.align-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch}.align-self-stretch{-webkit-align-self:stretch;-ms-flex-item-align:stretch;align-self:stretch}.align-center-middle{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center}.small-order-1{-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}.small-order-2{-webkit-box-ordinal-group:3;-webkit-order:2;-ms-flex-order:2;order:2}.small-order-3{-webkit-box-ordinal-group:4;-webkit-order:3;-ms-flex-order:3;order:3}.small-order-4{-webkit-box-ordinal-group:5;-webkit-order:4;-ms-flex-order:4;order:4}.small-order-5{-webkit-box-ordinal-group:6;-webkit-order:5;-ms-flex-order:5;order:5}.small-order-6{-webkit-box-ordinal-group:7;-webkit-order:6;-ms-flex-order:6;order:6}@media print,screen and (min-width:40em){.medium-order-1{-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}.medium-order-2{-webkit-box-ordinal-group:3;-webkit-order:2;-ms-flex-order:2;order:2}.medium-order-3{-webkit-box-ordinal-group:4;-webkit-order:3;-ms-flex-order:3;order:3}.medium-order-4{-webkit-box-ordinal-group:5;-webkit-order:4;-ms-flex-order:4;order:4}.medium-order-5{-webkit-box-ordinal-group:6;-webkit-order:5;-ms-flex-order:5;order:5}.medium-order-6{-webkit-box-ordinal-group:7;-webkit-order:6;-ms-flex-order:6;order:6}}@media print,screen and (min-width:64em){.large-order-1{-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}.large-order-2{-webkit-box-ordinal-group:3;-webkit-order:2;-ms-flex-order:2;order:2}.large-order-3{-webkit-box-ordinal-group:4;-webkit-order:3;-ms-flex-order:3;order:3}.large-order-4{-webkit-box-ordinal-group:5;-webkit-order:4;-ms-flex-order:4;order:4}.large-order-5{-webkit-box-ordinal-group:6;-webkit-order:5;-ms-flex-order:5;order:5}.large-order-6{-webkit-box-ordinal-group:7;-webkit-order:6;-ms-flex-order:6;order:6}}.flex-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flex-child-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto}.flex-child-grow{-webkit-box-flex:1;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto}.flex-child-shrink{-webkit-box-flex:0;-webkit-flex:0 1 auto;-ms-flex:0 1 auto;flex:0 1 auto}.flex-dir-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.flex-dir-row-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-webkit-flex-direction:row-reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.flex-dir-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.flex-dir-column-reverse{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-webkit-flex-direction:column-reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}@media print,screen and (min-width:40em){.medium-flex-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.medium-flex-child-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto}.medium-flex-child-grow{-webkit-box-flex:1;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto}.medium-flex-child-shrink{-webkit-box-flex:0;-webkit-flex:0 1 auto;-ms-flex:0 1 auto;flex:0 1 auto}.medium-flex-dir-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.medium-flex-dir-row-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-webkit-flex-direction:row-reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.medium-flex-dir-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.medium-flex-dir-column-reverse{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-webkit-flex-direction:column-reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}}@media print,screen and (min-width:64em){.large-flex-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.large-flex-child-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto}.large-flex-child-grow{-webkit-box-flex:1;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto}.large-flex-child-shrink{-webkit-box-flex:0;-webkit-flex:0 1 auto;-ms-flex:0 1 auto;flex:0 1 auto}.large-flex-dir-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.large-flex-dir-row-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-webkit-flex-direction:row-reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.large-flex-dir-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.large-flex-dir-column-reverse{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-webkit-flex-direction:column-reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}}.hide{display:none!important}.invisible{visibility:hidden}.visible{visibility:visible}@media print,screen and (max-width:39.99875em){.hide-for-small-only{display:none!important}}@media screen and (max-width:0em),screen and (min-width:40em){.show-for-small-only{display:none!important}}@media print,screen and (min-width:40em){.hide-for-medium{display:none!important}}@media screen and (max-width:39.99875em){.show-for-medium{display:none!important}}@media print,screen and (min-width:40em) and (max-width:63.99875em){.hide-for-medium-only{display:none!important}}@media screen and (max-width:39.99875em),screen and (min-width:64em){.show-for-medium-only{display:none!important}}@media print,screen and (min-width:64em){.hide-for-large{display:none!important}}@media screen and (max-width:63.99875em){.show-for-large{display:none!important}}@media print,screen and (min-width:64em) and (max-width:74.99875em){.hide-for-large-only{display:none!important}}@media screen and (max-width:63.99875em),screen and (min-width:75em){.show-for-large-only{display:none!important}}.show-for-sr,.show-on-focus{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.show-on-focus:active,.show-on-focus:focus{position:static!important;width:auto!important;height:auto!important;overflow:visible!important;clip:auto!important;white-space:normal!important}.hide-for-portrait,.show-for-landscape{display:block!important}@media screen and (orientation:landscape){.hide-for-portrait,.show-for-landscape{display:block!important}}@media screen and (orientation:portrait){.hide-for-portrait,.show-for-landscape{display:none!important}}.hide-for-landscape,.show-for-portrait{display:none!important}@media screen and (orientation:landscape){.hide-for-landscape,.show-for-portrait{display:none!important}}@media screen and (orientation:portrait){.hide-for-landscape,.show-for-portrait{display:block!important}}
+/*# sourceMappingURL=foundation.min.css.map */
diff --git a/pkgs/csslib/third_party/html5-boilerplate/LICENSE.txt b/pkgs/csslib/third_party/html5-boilerplate/LICENSE.txt
new file mode 100644
index 0000000..294e91d
--- /dev/null
+++ b/pkgs/csslib/third_party/html5-boilerplate/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (c) HTML5 Boilerplate
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/pkgs/csslib/third_party/html5-boilerplate/README.md b/pkgs/csslib/third_party/html5-boilerplate/README.md
new file mode 100644
index 0000000..3ca556d
--- /dev/null
+++ b/pkgs/csslib/third_party/html5-boilerplate/README.md
@@ -0,0 +1,4 @@
+This folder contains sample css files from the open-source project
+https://github.com/h5bp/html5-boilerplate.
+
+This code was included under the terms in the `LICENSE.txt` file.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/html5-boilerplate/normalize.css b/pkgs/csslib/third_party/html5-boilerplate/normalize.css
new file mode 100644
index 0000000..192eb9c
--- /dev/null
+++ b/pkgs/csslib/third_party/html5-boilerplate/normalize.css
@@ -0,0 +1,349 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+ ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+ ========================================================================== */
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+ margin: 0;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+
+main {
+ display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+ border-style: none;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input { /* 1 */
+ overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select { /* 1 */
+ text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+ vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/* Interactive
+ ========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+ display: list-item;
+}
+
+/* Misc
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+ display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+ display: none;
+}
diff --git a/pkgs/csslib/third_party/html5-boilerplate/style.css b/pkgs/csslib/third_party/html5-boilerplate/style.css
new file mode 100644
index 0000000..416a37e
--- /dev/null
+++ b/pkgs/csslib/third_party/html5-boilerplate/style.css
@@ -0,0 +1,263 @@
+/*! HTML5 Boilerplate v8.0.0 | MIT License | https://html5boilerplate.com/ */
+
+/* main.css 2.1.0 | MIT License | https://github.com/h5bp/main.css#readme */
+/*
+ * What follows is the result of much research on cross-browser styling.
+ * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
+ * Kroc Camen, and the H5BP dev community and team.
+ */
+
+/* ==========================================================================
+ Base styles: opinionated defaults
+ ========================================================================== */
+
+html {
+ color: #222;
+ font-size: 1em;
+ line-height: 1.4;
+}
+
+/*
+ * Remove text-shadow in selection highlight:
+ * https://twitter.com/miketaylr/status/12228805301
+ *
+ * Vendor-prefixed and regular ::selection selectors cannot be combined:
+ * https://stackoverflow.com/a/16982510/7133471
+ *
+ * Customize the background color to match your design.
+ */
+
+::-moz-selection {
+ background: #b3d4fc;
+ text-shadow: none;
+}
+
+::selection {
+ background: #b3d4fc;
+ text-shadow: none;
+}
+
+/*
+ * A better looking default horizontal rule
+ */
+
+hr {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin: 1em 0;
+ padding: 0;
+}
+
+/*
+ * Remove the gap between audio, canvas, iframes,
+ * images, videos and the bottom of their containers:
+ * https://github.com/h5bp/html5-boilerplate/issues/440
+ */
+
+audio,
+canvas,
+iframe,
+img,
+svg,
+video {
+ vertical-align: middle;
+}
+
+/*
+ * Remove default fieldset styles.
+ */
+
+fieldset {
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+
+/*
+ * Allow only vertical resizing of textareas.
+ */
+
+textarea {
+ resize: vertical;
+}
+
+/* ==========================================================================
+ Author's custom styles
+ ========================================================================== */
+
+/* ==========================================================================
+ Helper classes
+ ========================================================================== */
+
+/*
+ * Hide visually and from screen readers
+ */
+
+.hidden,
+[hidden] {
+ display: none !important;
+}
+
+/*
+ * Hide only visually, but have it available for screen readers:
+ * https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
+ *
+ * 1. For long content, line feeds are not interpreted as spaces and small width
+ * causes content to wrap 1 word per line:
+ * https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
+ */
+
+.sr-only {
+ border: 0;
+ clip: rect(0, 0, 0, 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ white-space: nowrap;
+ width: 1px;
+ /* 1 */
+}
+
+/*
+ * Extends the .sr-only class to allow the element
+ * to be focusable when navigated to via the keyboard:
+ * https://www.drupal.org/node/897638
+ */
+
+.sr-only.focusable:active,
+.sr-only.focusable:focus {
+ clip: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ position: static;
+ white-space: inherit;
+ width: auto;
+}
+
+/*
+ * Hide visually and from screen readers, but maintain layout
+ */
+
+.invisible {
+ visibility: hidden;
+}
+
+/*
+ * Clearfix: contain floats
+ *
+ * For modern browsers
+ * 1. The space content is one way to avoid an Opera bug when the
+ * `contenteditable` attribute is included anywhere else in the document.
+ * Otherwise it causes space to appear at the top and bottom of elements
+ * that receive the `clearfix` class.
+ * 2. The use of `table` rather than `block` is only necessary if using
+ * `:before` to contain the top-margins of child elements.
+ */
+
+.clearfix::before,
+.clearfix::after {
+ content: " ";
+ display: table;
+}
+
+.clearfix::after {
+ clear: both;
+}
+
+/* ==========================================================================
+ EXAMPLE Media Queries for Responsive Design.
+ These examples override the primary ('mobile first') styles.
+ Modify as content requires.
+ ========================================================================== */
+
+@media only screen and (min-width: 35em) {
+ /* Style adjustments for viewports that meet the condition */
+}
+
+@media print,
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 1.25dppx),
+ (min-resolution: 120dpi) {
+ /* Style adjustments for high resolution devices */
+}
+
+/* ==========================================================================
+ Print styles.
+ Inlined to avoid the additional HTTP request:
+ https://www.phpied.com/delay-loading-your-print-css/
+ ========================================================================== */
+
+@media print {
+ *,
+ *::before,
+ *::after {
+ background: #fff !important;
+ color: #000 !important;
+ /* Black prints faster */
+ box-shadow: none !important;
+ text-shadow: none !important;
+ }
+
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+
+ a[href]::after {
+ content: " (" attr(href) ")";
+ }
+
+ abbr[title]::after {
+ content: " (" attr(title) ")";
+ }
+
+ /*
+ * Don't show links that are fragment identifiers,
+ * or use the `javascript:` pseudo protocol
+ */
+ a[href^="#"]::after,
+ a[href^="javascript:"]::after {
+ content: "";
+ }
+
+ pre {
+ white-space: pre-wrap !important;
+ }
+
+ pre,
+ blockquote {
+ border: 1px solid #999;
+ page-break-inside: avoid;
+ }
+
+ /*
+ * Printing Tables:
+ * https://web.archive.org/web/20180815150934/http://css-discuss.incutio.com/wiki/Printing_Tables
+ */
+ thead {
+ display: table-header-group;
+ }
+
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+}
+
diff --git a/pkgs/csslib/third_party/materialize/LICENSE b/pkgs/csslib/third_party/materialize/LICENSE
new file mode 100644
index 0000000..c790fc2
--- /dev/null
+++ b/pkgs/csslib/third_party/materialize/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2019 Materialize
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/pkgs/csslib/third_party/materialize/README.md b/pkgs/csslib/third_party/materialize/README.md
new file mode 100644
index 0000000..2be2627
--- /dev/null
+++ b/pkgs/csslib/third_party/materialize/README.md
@@ -0,0 +1,4 @@
+This folder contains sample css files from the open-source project
+https://github.com/Dogfalo/materialize.
+
+This code was included under the terms in the `LICENSE` file.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/materialize/materialize.css b/pkgs/csslib/third_party/materialize/materialize.css
new file mode 100644
index 0000000..bc6c1fe
--- /dev/null
+++ b/pkgs/csslib/third_party/materialize/materialize.css
Binary files differ
diff --git a/pkgs/csslib/third_party/materialize/materialize.min.css b/pkgs/csslib/third_party/materialize/materialize.min.css
new file mode 100644
index 0000000..74b1741
--- /dev/null
+++ b/pkgs/csslib/third_party/materialize/materialize.min.css
Binary files differ
diff --git a/pkgs/csslib/third_party/mdc/LICENSE b/pkgs/csslib/third_party/mdc/LICENSE
new file mode 100644
index 0000000..0324838
--- /dev/null
+++ b/pkgs/csslib/third_party/mdc/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2014-2020 Google, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/pkgs/csslib/third_party/mdc/README.md b/pkgs/csslib/third_party/mdc/README.md
new file mode 100644
index 0000000..f388348
--- /dev/null
+++ b/pkgs/csslib/third_party/mdc/README.md
@@ -0,0 +1,7 @@
+This folder contains sample css files from the open-source project
+https://github.com/material-components/material-components-web.
+
+The generated .css files were retrieved from:
+https://unpkg.com/browse/material-components-web@12.0.0/dist/
+
+This code was included under the terms in the `LICENSE` file.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/mdc/material-components-web.css b/pkgs/csslib/third_party/mdc/material-components-web.css
new file mode 100644
index 0000000..2099afe
--- /dev/null
+++ b/pkgs/csslib/third_party/mdc/material-components-web.css
@@ -0,0 +1,16511 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://github.com/material-components/material-components-web/blob/master/LICENSE
+ */
+@charset "UTF-8";
+.mdc-banner__text {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+
+.mdc-banner__graphic {
+ color: #fff;
+ /* @alternate */
+ color: var(--mdc-theme-surface, #fff);
+}
+
+.mdc-banner__graphic {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-theme-primary, #6200ee);
+}
+
+.mdc-banner__graphic {
+ border-radius: 50%;
+}
+
+.mdc-banner__content,
+.mdc-banner__fixed {
+ min-width: 344px;
+}
+@media (max-width: 480px), (max-width: 344px) {
+ .mdc-banner__content,
+.mdc-banner__fixed {
+ min-width: 100%;
+ }
+}
+
+.mdc-banner__content {
+ max-width: 720px;
+}
+
+.mdc-banner {
+ z-index: 1;
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ box-sizing: border-box;
+ display: none;
+ flex-shrink: 0;
+ height: 0;
+ position: relative;
+ width: 100%;
+}
+@media (max-width: 480px) {
+ .mdc-banner .mdc-banner__fixed {
+ left: 0;
+ right: 0;
+ }
+ .mdc-banner .mdc-banner__text {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 36px;
+ }
+ [dir=rtl] .mdc-banner .mdc-banner__text, .mdc-banner .mdc-banner__text[dir=rtl] {
+ /* @noflip */
+ margin-left: 36px;
+ /* @noflip */
+ margin-right: 16px;
+ }
+}
+@media (max-width: 480px) {
+ .mdc-banner.mdc-banner--mobile-stacked .mdc-banner__content {
+ flex-wrap: wrap;
+ }
+ .mdc-banner.mdc-banner--mobile-stacked .mdc-banner__graphic {
+ margin-bottom: 12px;
+ }
+ .mdc-banner.mdc-banner--mobile-stacked .mdc-banner__text {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 8px;
+ padding-bottom: 4px;
+ }
+ [dir=rtl] .mdc-banner.mdc-banner--mobile-stacked .mdc-banner__text, .mdc-banner.mdc-banner--mobile-stacked .mdc-banner__text[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 16px;
+ }
+
+ .mdc-banner.mdc-banner--mobile-stacked .mdc-banner__actions {
+ margin-left: auto;
+ }
+}
+
+.mdc-banner--opening,
+.mdc-banner--open,
+.mdc-banner--closing {
+ display: flex;
+}
+
+.mdc-banner--open {
+ transition: height 300ms ease;
+}
+.mdc-banner--open .mdc-banner__content {
+ transition: -webkit-transform 300ms ease;
+ transition: transform 300ms ease;
+ transition: transform 300ms ease, -webkit-transform 300ms ease;
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+}
+
+.mdc-banner--closing {
+ transition: height 250ms ease;
+}
+.mdc-banner--closing .mdc-banner__content {
+ transition: -webkit-transform 250ms ease;
+ transition: transform 250ms ease;
+ transition: transform 250ms ease, -webkit-transform 250ms ease;
+}
+
+.mdc-banner--centered .mdc-banner__content {
+ left: 0;
+ margin-left: auto;
+ margin-right: auto;
+ right: 0;
+}
+
+.mdc-banner__fixed {
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ box-sizing: border-box;
+ height: inherit;
+ position: fixed;
+ width: 100%;
+}
+
+.mdc-banner__content {
+ display: flex;
+ min-height: 52px;
+ position: absolute;
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ width: 100%;
+}
+
+.mdc-banner__graphic-text-wrapper {
+ display: flex;
+ width: 100%;
+}
+
+.mdc-banner__graphic {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ flex-shrink: 0;
+ height: 40px;
+ margin-top: 16px;
+ margin-bottom: 16px;
+ text-align: center;
+ width: 40px;
+}
+[dir=rtl] .mdc-banner__graphic, .mdc-banner__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-banner__icon {
+ position: relative;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+}
+
+.mdc-banner__text {
+ /* @noflip */
+ margin-left: 24px;
+ /* @noflip */
+ margin-right: 90px;
+ align-self: center;
+ flex-grow: 1;
+ padding-top: 16px;
+ padding-bottom: 16px;
+}
+[dir=rtl] .mdc-banner__text, .mdc-banner__text[dir=rtl] {
+ /* @noflip */
+ margin-left: 90px;
+ /* @noflip */
+ margin-right: 24px;
+}
+
+.mdc-banner__actions {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 8px;
+ align-self: flex-end;
+ display: flex;
+ flex-shrink: 0;
+ padding-bottom: 8px;
+ padding-top: 8px;
+}
+[dir=rtl] .mdc-banner__actions, .mdc-banner__actions[dir=rtl] {
+ /* @noflip */
+ padding-left: 8px;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-banner__secondary-action {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 8px;
+}
+[dir=rtl] .mdc-banner__secondary-action, .mdc-banner__secondary-action[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-banner {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+ border-bottom-color: rgba(0, 0, 0, 0.12);
+}
+.mdc-banner .mdc-banner__fixed {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+}
+.mdc-banner .mdc-banner__fixed {
+ border-bottom-color: rgba(0, 0, 0, 0.12);
+}
+
+.mdc-banner__text {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+}
+
+.mdc-banner__primary-action:not(:disabled) {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-banner__primary-action::before, .mdc-banner__primary-action::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-banner__primary-action:hover::before, .mdc-banner__primary-action.mdc-ripple-surface--hover::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-banner__primary-action.mdc-ripple-upgraded--background-focused::before, .mdc-banner__primary-action:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-banner__primary-action:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-banner__primary-action:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-banner__primary-action.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+
+.mdc-banner__secondary-action {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 8px;
+}
+.mdc-banner__secondary-action:not(:disabled) {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-banner__secondary-action::before, .mdc-banner__secondary-action::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-banner__secondary-action:hover::before, .mdc-banner__secondary-action.mdc-ripple-surface--hover::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-banner__secondary-action.mdc-ripple-upgraded--background-focused::before, .mdc-banner__secondary-action:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-banner__secondary-action:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-banner__secondary-action:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-banner__secondary-action.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+[dir=rtl] .mdc-banner__secondary-action, .mdc-banner__secondary-action[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-touch-target-wrapper {
+ display: inline;
+}
+
+.mdc-elevation-overlay {
+ position: absolute;
+ border-radius: inherit;
+ pointer-events: none;
+ opacity: 0;
+ /* @alternate */
+ opacity: var(--mdc-elevation-overlay-opacity, 0);
+ transition: opacity 280ms cubic-bezier(0.4, 0, 0.2, 1);
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-elevation-overlay-color, #fff);
+}
+
+.mdc-button {
+ /* @alternate */
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ min-width: 64px;
+ border: none;
+ outline: none;
+ /* @alternate */
+ line-height: inherit;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-appearance: none;
+ overflow: visible;
+ vertical-align: middle;
+ background: transparent;
+}
+.mdc-button .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.mdc-button::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+.mdc-button:active {
+ outline: none;
+}
+.mdc-button:hover {
+ cursor: pointer;
+}
+.mdc-button:disabled {
+ cursor: default;
+ pointer-events: none;
+}
+.mdc-button .mdc-button__icon {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 8px;
+ display: inline-block;
+ position: relative;
+ vertical-align: top;
+}
+[dir=rtl] .mdc-button .mdc-button__icon, .mdc-button .mdc-button__icon[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-button .mdc-button__touch {
+ position: absolute;
+ top: 50%;
+ height: 48px;
+ left: 0;
+ right: 0;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+}
+
+.mdc-button__label + .mdc-button__icon {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 0;
+}
+[dir=rtl] .mdc-button__label + .mdc-button__icon, .mdc-button__label + .mdc-button__icon[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 8px;
+}
+
+svg.mdc-button__icon {
+ fill: currentColor;
+}
+
+.mdc-button--raised .mdc-button__icon,
+.mdc-button--unelevated .mdc-button__icon,
+.mdc-button--outlined .mdc-button__icon {
+ /* @noflip */
+ margin-left: -4px;
+ /* @noflip */
+ margin-right: 8px;
+}
+[dir=rtl] .mdc-button--raised .mdc-button__icon, [dir=rtl] .mdc-button--unelevated .mdc-button__icon, [dir=rtl] .mdc-button--outlined .mdc-button__icon, .mdc-button--raised .mdc-button__icon[dir=rtl], .mdc-button--unelevated .mdc-button__icon[dir=rtl], .mdc-button--outlined .mdc-button__icon[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: -4px;
+}
+
+.mdc-button--raised .mdc-button__label + .mdc-button__icon,
+.mdc-button--unelevated .mdc-button__label + .mdc-button__icon,
+.mdc-button--outlined .mdc-button__label + .mdc-button__icon {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: -4px;
+}
+[dir=rtl] .mdc-button--raised .mdc-button__label + .mdc-button__icon, [dir=rtl] .mdc-button--unelevated .mdc-button__label + .mdc-button__icon, [dir=rtl] .mdc-button--outlined .mdc-button__label + .mdc-button__icon, .mdc-button--raised .mdc-button__label + .mdc-button__icon[dir=rtl], .mdc-button--unelevated .mdc-button__label + .mdc-button__icon[dir=rtl], .mdc-button--outlined .mdc-button__label + .mdc-button__icon[dir=rtl] {
+ /* @noflip */
+ margin-left: -4px;
+ /* @noflip */
+ margin-right: 8px;
+}
+
+.mdc-button--touch {
+ margin-top: 6px;
+ margin-bottom: 6px;
+}
+
+.mdc-button {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ text-decoration: none;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-decoration: var(--mdc-typography-button-text-decoration, none);
+}
+
+@-webkit-keyframes mdc-ripple-fg-radius-in {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1);
+ transform: translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1);
+ }
+ to {
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ }
+}
+
+@keyframes mdc-ripple-fg-radius-in {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1);
+ transform: translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1);
+ }
+ to {
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ }
+}
+@-webkit-keyframes mdc-ripple-fg-opacity-in {
+ from {
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+ opacity: 0;
+ }
+ to {
+ opacity: var(--mdc-ripple-fg-opacity, 0);
+ }
+}
+@keyframes mdc-ripple-fg-opacity-in {
+ from {
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+ opacity: 0;
+ }
+ to {
+ opacity: var(--mdc-ripple-fg-opacity, 0);
+ }
+}
+@-webkit-keyframes mdc-ripple-fg-opacity-out {
+ from {
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+ opacity: var(--mdc-ripple-fg-opacity, 0);
+ }
+ to {
+ opacity: 0;
+ }
+}
+@keyframes mdc-ripple-fg-opacity-out {
+ from {
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+ opacity: var(--mdc-ripple-fg-opacity, 0);
+ }
+ to {
+ opacity: 0;
+ }
+}
+.mdc-button {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-button .mdc-button__ripple::before,
+.mdc-button .mdc-button__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-button .mdc-button__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-button .mdc-button__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-button.mdc-ripple-upgraded--unbounded .mdc-button__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-button.mdc-ripple-upgraded--foreground-activation .mdc-button__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-button.mdc-ripple-upgraded--foreground-deactivation .mdc-button__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-button .mdc-button__ripple::before,
+.mdc-button .mdc-button__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-button .mdc-button__ripple {
+ position: absolute;
+ box-sizing: content-box;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+.mdc-button:not(.mdc-button--outlined) .mdc-button__ripple {
+ top: 0;
+ left: 0;
+}
+
+.mdc-button--raised {
+ transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-button--outlined {
+ border-style: solid;
+}
+
+.mdc-button {
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-button-font-size, 0.875rem);
+ letter-spacing: 0.0892857143em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-button-letter-spacing, 0.0892857143em);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-button-font-weight, 500);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-button-text-transform, uppercase);
+ height: 36px;
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+ padding: 0 8px 0 8px;
+}
+.mdc-button:not(:disabled) {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-button:disabled {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-button .mdc-button__icon {
+ font-size: 1.125rem;
+ height: 1.125rem;
+ width: 1.125rem;
+}
+.mdc-button .mdc-button__ripple::before,
+.mdc-button .mdc-button__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-button:hover .mdc-button__ripple::before, .mdc-button.mdc-ripple-surface--hover .mdc-button__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-button.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before, .mdc-button:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-button:not(.mdc-ripple-upgraded) .mdc-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-button:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-button.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-button .mdc-button__ripple {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+
+.mdc-button--unelevated {
+ padding: 0 16px 0 16px;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-button-font-size, 0.875rem);
+ letter-spacing: 0.0892857143em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-button-letter-spacing, 0.0892857143em);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-button-font-weight, 500);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-button-text-transform, uppercase);
+ height: 36px;
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+.mdc-button--unelevated.mdc-button--icon-trailing {
+ padding: 0 12px 0 16px;
+}
+.mdc-button--unelevated.mdc-button--icon-leading {
+ padding: 0 16px 0 12px;
+}
+.mdc-button--unelevated:not(:disabled) {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-button--unelevated:disabled {
+ background-color: rgba(0, 0, 0, 0.12);
+}
+.mdc-button--unelevated:not(:disabled) {
+ color: #fff;
+ /* @alternate */
+ color: var(--mdc-theme-on-primary, #fff);
+}
+.mdc-button--unelevated:disabled {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-button--unelevated .mdc-button__icon {
+ font-size: 1.125rem;
+ height: 1.125rem;
+ width: 1.125rem;
+}
+.mdc-button--unelevated .mdc-button__ripple::before,
+.mdc-button--unelevated .mdc-button__ripple::after {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-on-primary, #fff));
+}
+.mdc-button--unelevated:hover .mdc-button__ripple::before, .mdc-button--unelevated.mdc-ripple-surface--hover .mdc-button__ripple::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.08);
+}
+.mdc-button--unelevated.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before, .mdc-button--unelevated:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+.mdc-button--unelevated:not(.mdc-ripple-upgraded) .mdc-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-button--unelevated:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-button--unelevated.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-button--unelevated .mdc-button__ripple {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+
+.mdc-button--raised {
+ padding: 0 16px 0 16px;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-button-font-size, 0.875rem);
+ letter-spacing: 0.0892857143em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-button-letter-spacing, 0.0892857143em);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-button-font-weight, 500);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-button-text-transform, uppercase);
+ height: 36px;
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+ /* @alternate */
+ box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
+}
+.mdc-button--raised.mdc-button--icon-trailing {
+ padding: 0 12px 0 16px;
+}
+.mdc-button--raised.mdc-button--icon-leading {
+ padding: 0 16px 0 12px;
+}
+.mdc-button--raised:not(:disabled) {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-button--raised:disabled {
+ background-color: rgba(0, 0, 0, 0.12);
+}
+.mdc-button--raised:not(:disabled) {
+ color: #fff;
+ /* @alternate */
+ color: var(--mdc-theme-on-primary, #fff);
+}
+.mdc-button--raised:disabled {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-button--raised .mdc-button__icon {
+ font-size: 1.125rem;
+ height: 1.125rem;
+ width: 1.125rem;
+}
+.mdc-button--raised .mdc-button__ripple::before,
+.mdc-button--raised .mdc-button__ripple::after {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-on-primary, #fff));
+}
+.mdc-button--raised:hover .mdc-button__ripple::before, .mdc-button--raised.mdc-ripple-surface--hover .mdc-button__ripple::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.08);
+}
+.mdc-button--raised.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before, .mdc-button--raised:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+.mdc-button--raised:not(.mdc-ripple-upgraded) .mdc-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-button--raised:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-button--raised.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-button--raised .mdc-button__ripple {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+.mdc-button--raised.mdc-ripple-upgraded--background-focused, .mdc-button--raised:not(.mdc-ripple-upgraded):focus {
+ /* @alternate */
+ box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);
+}
+.mdc-button--raised:hover {
+ /* @alternate */
+ box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);
+}
+.mdc-button--raised:not(:disabled):active {
+ /* @alternate */
+ box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12);
+}
+.mdc-button--raised:disabled {
+ /* @alternate */
+ box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.2), 0px 0px 0px 0px rgba(0, 0, 0, 0.14), 0px 0px 0px 0px rgba(0, 0, 0, 0.12);
+}
+.mdc-button--outlined {
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-button-font-size, 0.875rem);
+ letter-spacing: 0.0892857143em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-button-letter-spacing, 0.0892857143em);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-button-font-weight, 500);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-button-text-transform, uppercase);
+ height: 36px;
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+ padding: 0 15px 0 15px;
+ border-width: 1px;
+}
+.mdc-button--outlined:not(:disabled) {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-button--outlined:disabled {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-button--outlined .mdc-button__icon {
+ font-size: 1.125rem;
+ height: 1.125rem;
+ width: 1.125rem;
+}
+.mdc-button--outlined .mdc-button__ripple::before,
+.mdc-button--outlined .mdc-button__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-button--outlined:hover .mdc-button__ripple::before, .mdc-button--outlined.mdc-ripple-surface--hover .mdc-button__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-button--outlined.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before, .mdc-button--outlined:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-button--outlined:not(.mdc-ripple-upgraded) .mdc-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-button--outlined:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-button--outlined.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-button--outlined .mdc-button__ripple {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+.mdc-button--outlined:not(:disabled) {
+ border-color: rgba(0, 0, 0, 0.12);
+}
+.mdc-button--outlined:disabled {
+ border-color: rgba(0, 0, 0, 0.12);
+}
+.mdc-button--outlined.mdc-button--icon-trailing {
+ padding: 0 11px 0 15px;
+}
+.mdc-button--outlined.mdc-button--icon-leading {
+ padding: 0 15px 0 11px;
+}
+.mdc-button--outlined .mdc-button__ripple {
+ top: -1px;
+ left: -1px;
+ border: 1px solid transparent;
+}
+.mdc-button--outlined .mdc-button__touch {
+ left: -1px;
+ width: calc(100% + 2 * 1px);
+}
+
+.mdc-card {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-medium, 4px);
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+ /* @alternate */
+ position: relative;
+ /* @alternate */
+ box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12);
+ display: flex;
+ flex-direction: column;
+ box-sizing: border-box;
+}
+.mdc-card .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.mdc-card::after {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-medium, 4px);
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 1px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+ pointer-events: none;
+}
+
+.mdc-card--outlined {
+ /* @alternate */
+ box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.2), 0px 0px 0px 0px rgba(0, 0, 0, 0.14), 0px 0px 0px 0px rgba(0, 0, 0, 0.12);
+ border-width: 1px;
+ border-style: solid;
+ border-color: #e0e0e0;
+}
+.mdc-card--outlined::after {
+ border: none;
+}
+
+.mdc-card__content {
+ border-radius: inherit;
+ height: 100%;
+}
+
+.mdc-card__media {
+ position: relative;
+ box-sizing: border-box;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover;
+}
+.mdc-card__media::before {
+ display: block;
+ content: "";
+}
+
+.mdc-card__media:first-child {
+ border-top-left-radius: inherit;
+ border-top-right-radius: inherit;
+}
+
+.mdc-card__media:last-child {
+ border-bottom-left-radius: inherit;
+ border-bottom-right-radius: inherit;
+}
+
+.mdc-card__media--square::before {
+ margin-top: 100%;
+}
+
+.mdc-card__media--16-9::before {
+ margin-top: 56.25%;
+}
+
+.mdc-card__media-content {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ box-sizing: border-box;
+}
+
+.mdc-card__primary-action {
+ display: flex;
+ flex-direction: column;
+ box-sizing: border-box;
+ position: relative;
+ outline: none;
+ color: inherit;
+ text-decoration: none;
+ cursor: pointer;
+ overflow: hidden;
+}
+
+.mdc-card__primary-action:first-child {
+ border-top-left-radius: inherit;
+ border-top-right-radius: inherit;
+}
+
+.mdc-card__primary-action:last-child {
+ border-bottom-left-radius: inherit;
+ border-bottom-right-radius: inherit;
+}
+
+.mdc-card__actions {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ box-sizing: border-box;
+ min-height: 52px;
+ padding: 8px;
+}
+
+.mdc-card__actions--full-bleed {
+ padding: 0;
+}
+
+.mdc-card__action-buttons,
+.mdc-card__action-icons {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ box-sizing: border-box;
+}
+
+.mdc-card__action-icons {
+ color: rgba(0, 0, 0, 0.6);
+ flex-grow: 1;
+ justify-content: flex-end;
+}
+
+.mdc-card__action-buttons + .mdc-card__action-icons {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+}
+[dir=rtl] .mdc-card__action-buttons + .mdc-card__action-icons, .mdc-card__action-buttons + .mdc-card__action-icons[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-card__action {
+ display: inline-flex;
+ flex-direction: row;
+ align-items: center;
+ box-sizing: border-box;
+ justify-content: center;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.mdc-card__action:focus {
+ outline: none;
+}
+
+.mdc-card__action--button {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 8px;
+ padding: 0 8px;
+}
+[dir=rtl] .mdc-card__action--button, .mdc-card__action--button[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-card__action--button:last-child {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0;
+}
+[dir=rtl] .mdc-card__action--button:last-child, .mdc-card__action--button:last-child[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-card__actions--full-bleed .mdc-card__action--button {
+ justify-content: space-between;
+ width: 100%;
+ height: auto;
+ max-height: none;
+ margin: 0;
+ padding: 8px 16px;
+ /* @noflip */
+ text-align: left;
+}
+[dir=rtl] .mdc-card__actions--full-bleed .mdc-card__action--button, .mdc-card__actions--full-bleed .mdc-card__action--button[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-card__action--icon {
+ margin: -6px 0;
+ padding: 12px;
+}
+
+.mdc-card__action--icon:not(:disabled) {
+ color: rgba(0, 0, 0, 0.6);
+}
+
+.mdc-card__primary-action {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-card__primary-action .mdc-card__ripple::before,
+.mdc-card__primary-action .mdc-card__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-card__primary-action .mdc-card__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-card__primary-action .mdc-card__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-card__primary-action.mdc-ripple-upgraded .mdc-card__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-card__primary-action.mdc-ripple-upgraded .mdc-card__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-card__primary-action.mdc-ripple-upgraded--unbounded .mdc-card__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-card__primary-action.mdc-ripple-upgraded--foreground-activation .mdc-card__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-card__primary-action.mdc-ripple-upgraded--foreground-deactivation .mdc-card__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-card__primary-action .mdc-card__ripple::before,
+.mdc-card__primary-action .mdc-card__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-card__primary-action.mdc-ripple-upgraded .mdc-card__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-card__primary-action .mdc-card__ripple::before, .mdc-card__primary-action .mdc-card__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+.mdc-card__primary-action:hover .mdc-card__ripple::before, .mdc-card__primary-action.mdc-ripple-surface--hover .mdc-card__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-card__primary-action.mdc-ripple-upgraded--background-focused .mdc-card__ripple::before, .mdc-card__primary-action:not(.mdc-ripple-upgraded):focus .mdc-card__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-card__primary-action:not(.mdc-ripple-upgraded) .mdc-card__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-card__primary-action:not(.mdc-ripple-upgraded):active .mdc-card__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-card__primary-action.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-card__primary-action .mdc-card__ripple {
+ box-sizing: content-box;
+ height: 100%;
+ overflow: hidden;
+ left: 0;
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.mdc-card__primary-action.mdc-ripple-upgraded--background-focused::after, .mdc-card__primary-action:not(.mdc-ripple-upgraded):focus::after {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 5px double transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+
+.mdc-checkbox {
+ padding: calc((40px - 18px) / 2);
+ /* @alternate */
+ padding: calc((var(--mdc-checkbox-ripple-size, 40px) - 18px) / 2);
+ margin: calc((40px - 40px) / 2);
+ /* @alternate */
+ margin: calc((var(--mdc-checkbox-touch-target-size, 40px) - 40px) / 2);
+}
+.mdc-checkbox .mdc-checkbox__ripple::before, .mdc-checkbox .mdc-checkbox__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+.mdc-checkbox:hover .mdc-checkbox__ripple::before, .mdc-checkbox.mdc-ripple-surface--hover .mdc-checkbox__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-checkbox.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before, .mdc-checkbox:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-checkbox:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-checkbox:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-checkbox.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before, .mdc-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after {
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786));
+}
+.mdc-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before, .mdc-checkbox.mdc-checkbox--selected.mdc-ripple-surface--hover .mdc-checkbox__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before, .mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,
+.mdc-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after {
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786));
+}
+.mdc-checkbox .mdc-checkbox__background {
+ top: calc((40px - 18px) / 2);
+ /* @alternate */
+ top: calc((var(--mdc-checkbox-ripple-size, 40px) - 18px) / 2);
+ left: calc((40px - 18px) / 2);
+ /* @alternate */
+ left: calc((var(--mdc-checkbox-ripple-size, 40px) - 18px) / 2);
+}
+.mdc-checkbox .mdc-checkbox__native-control {
+ top: calc((40px - 40px) / 2);
+ /* @alternate */
+ top: calc((40px - var(--mdc-checkbox-touch-target-size, 40px)) / 2);
+ right: calc((40px - 40px) / 2);
+ /* @alternate */
+ right: calc((40px - var(--mdc-checkbox-touch-target-size, 40px)) / 2);
+ left: calc((40px - 40px) / 2);
+ /* @alternate */
+ left: calc((40px - var(--mdc-checkbox-touch-target-size, 40px)) / 2);
+ width: 40px;
+ /* @alternate */
+ width: var(--mdc-checkbox-touch-target-size, 40px);
+ height: 40px;
+ /* @alternate */
+ height: var(--mdc-checkbox-touch-target-size, 40px);
+}
+.mdc-checkbox .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true]) ~ .mdc-checkbox__background {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+}
+.mdc-checkbox .mdc-checkbox__native-control:enabled:checked ~ .mdc-checkbox__background,
+.mdc-checkbox .mdc-checkbox__native-control:enabled:indeterminate ~ .mdc-checkbox__background,
+.mdc-checkbox .mdc-checkbox__native-control[data-indeterminate=true]:enabled ~ .mdc-checkbox__background {
+ border-color: #018786;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+}
+@-webkit-keyframes mdc-checkbox-fade-in-background-8A000000FF01878600000000FF018786 {
+ 0% {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+ }
+ 50% {
+ border-color: #018786;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ }
+}
+@keyframes mdc-checkbox-fade-in-background-8A000000FF01878600000000FF018786 {
+ 0% {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+ }
+ 50% {
+ border-color: #018786;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ }
+}
+@-webkit-keyframes mdc-checkbox-fade-out-background-8A000000FF01878600000000FF018786 {
+ 0%, 80% {
+ border-color: #018786;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ }
+ 100% {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+ }
+}
+@keyframes mdc-checkbox-fade-out-background-8A000000FF01878600000000FF018786 {
+ 0%, 80% {
+ border-color: #018786;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));
+ }
+ 100% {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+ }
+}
+.mdc-checkbox.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background, .mdc-checkbox.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background {
+ -webkit-animation-name: mdc-checkbox-fade-in-background-8A000000FF01878600000000FF018786;
+ animation-name: mdc-checkbox-fade-in-background-8A000000FF01878600000000FF018786;
+}
+.mdc-checkbox.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background, .mdc-checkbox.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background {
+ -webkit-animation-name: mdc-checkbox-fade-out-background-8A000000FF01878600000000FF018786;
+ animation-name: mdc-checkbox-fade-out-background-8A000000FF01878600000000FF018786;
+}
+.mdc-checkbox .mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate=true]) ~ .mdc-checkbox__background {
+ border-color: rgba(0, 0, 0, 0.38);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-disabled-color, rgba(0, 0, 0, 0.38));
+ background-color: transparent;
+}
+.mdc-checkbox .mdc-checkbox__native-control[disabled]:checked ~ .mdc-checkbox__background,
+.mdc-checkbox .mdc-checkbox__native-control[disabled]:indeterminate ~ .mdc-checkbox__background,
+.mdc-checkbox .mdc-checkbox__native-control[data-indeterminate=true][disabled] ~ .mdc-checkbox__background {
+ border-color: transparent;
+ background-color: rgba(0, 0, 0, 0.38);
+ /* @alternate */
+ background-color: var(--mdc-checkbox-disabled-color, rgba(0, 0, 0, 0.38));
+}
+.mdc-checkbox .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background .mdc-checkbox__checkmark {
+ color: #fff;
+ /* @alternate */
+ color: var(--mdc-checkbox-ink-color, #fff);
+}
+.mdc-checkbox .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background .mdc-checkbox__mixedmark {
+ border-color: #fff;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-ink-color, #fff);
+}
+.mdc-checkbox .mdc-checkbox__native-control:disabled ~ .mdc-checkbox__background .mdc-checkbox__checkmark {
+ color: #fff;
+ /* @alternate */
+ color: var(--mdc-checkbox-ink-color, #fff);
+}
+.mdc-checkbox .mdc-checkbox__native-control:disabled ~ .mdc-checkbox__background .mdc-checkbox__mixedmark {
+ border-color: #fff;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-ink-color, #fff);
+}
+
+@-webkit-keyframes mdc-checkbox-unchecked-checked-checkmark-path {
+ 0%, 50% {
+ stroke-dashoffset: 29.7833385;
+ }
+ 50% {
+ -webkit-animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ }
+ 100% {
+ stroke-dashoffset: 0;
+ }
+}
+
+@keyframes mdc-checkbox-unchecked-checked-checkmark-path {
+ 0%, 50% {
+ stroke-dashoffset: 29.7833385;
+ }
+ 50% {
+ -webkit-animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ }
+ 100% {
+ stroke-dashoffset: 0;
+ }
+}
+@-webkit-keyframes mdc-checkbox-unchecked-indeterminate-mixedmark {
+ 0%, 68.2% {
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+ }
+ 68.2% {
+ -webkit-animation-timing-function: cubic-bezier(0, 0, 0, 1);
+ animation-timing-function: cubic-bezier(0, 0, 0, 1);
+ }
+ 100% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ }
+}
+@keyframes mdc-checkbox-unchecked-indeterminate-mixedmark {
+ 0%, 68.2% {
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+ }
+ 68.2% {
+ -webkit-animation-timing-function: cubic-bezier(0, 0, 0, 1);
+ animation-timing-function: cubic-bezier(0, 0, 0, 1);
+ }
+ 100% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ }
+}
+@-webkit-keyframes mdc-checkbox-checked-unchecked-checkmark-path {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0, 1, 1);
+ animation-timing-function: cubic-bezier(0.4, 0, 1, 1);
+ opacity: 1;
+ stroke-dashoffset: 0;
+ }
+ to {
+ opacity: 0;
+ stroke-dashoffset: -29.7833385;
+ }
+}
+@keyframes mdc-checkbox-checked-unchecked-checkmark-path {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0, 1, 1);
+ animation-timing-function: cubic-bezier(0.4, 0, 1, 1);
+ opacity: 1;
+ stroke-dashoffset: 0;
+ }
+ to {
+ opacity: 0;
+ stroke-dashoffset: -29.7833385;
+ }
+}
+@-webkit-keyframes mdc-checkbox-checked-indeterminate-checkmark {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ opacity: 1;
+ }
+ to {
+ -webkit-transform: rotate(45deg);
+ transform: rotate(45deg);
+ opacity: 0;
+ }
+}
+@keyframes mdc-checkbox-checked-indeterminate-checkmark {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ opacity: 1;
+ }
+ to {
+ -webkit-transform: rotate(45deg);
+ transform: rotate(45deg);
+ opacity: 0;
+ }
+}
+@-webkit-keyframes mdc-checkbox-indeterminate-checked-checkmark {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0.14, 0, 0, 1);
+ animation-timing-function: cubic-bezier(0.14, 0, 0, 1);
+ -webkit-transform: rotate(45deg);
+ transform: rotate(45deg);
+ opacity: 0;
+ }
+ to {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ opacity: 1;
+ }
+}
+@keyframes mdc-checkbox-indeterminate-checked-checkmark {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0.14, 0, 0, 1);
+ animation-timing-function: cubic-bezier(0.14, 0, 0, 1);
+ -webkit-transform: rotate(45deg);
+ transform: rotate(45deg);
+ opacity: 0;
+ }
+ to {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ opacity: 1;
+ }
+}
+@-webkit-keyframes mdc-checkbox-checked-indeterminate-mixedmark {
+ from {
+ -webkit-animation-timing-function: mdc-animation-deceleration-curve-timing-function;
+ animation-timing-function: mdc-animation-deceleration-curve-timing-function;
+ -webkit-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+ opacity: 0;
+ }
+ to {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ opacity: 1;
+ }
+}
+@keyframes mdc-checkbox-checked-indeterminate-mixedmark {
+ from {
+ -webkit-animation-timing-function: mdc-animation-deceleration-curve-timing-function;
+ animation-timing-function: mdc-animation-deceleration-curve-timing-function;
+ -webkit-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+ opacity: 0;
+ }
+ to {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ opacity: 1;
+ }
+}
+@-webkit-keyframes mdc-checkbox-indeterminate-checked-mixedmark {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0.14, 0, 0, 1);
+ animation-timing-function: cubic-bezier(0.14, 0, 0, 1);
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ opacity: 1;
+ }
+ to {
+ -webkit-transform: rotate(315deg);
+ transform: rotate(315deg);
+ opacity: 0;
+ }
+}
+@keyframes mdc-checkbox-indeterminate-checked-mixedmark {
+ from {
+ -webkit-animation-timing-function: cubic-bezier(0.14, 0, 0, 1);
+ animation-timing-function: cubic-bezier(0.14, 0, 0, 1);
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ opacity: 1;
+ }
+ to {
+ -webkit-transform: rotate(315deg);
+ transform: rotate(315deg);
+ opacity: 0;
+ }
+}
+@-webkit-keyframes mdc-checkbox-indeterminate-unchecked-mixedmark {
+ 0% {
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ opacity: 1;
+ }
+ 32.8%, 100% {
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+ opacity: 0;
+ }
+}
+@keyframes mdc-checkbox-indeterminate-unchecked-mixedmark {
+ 0% {
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ opacity: 1;
+ }
+ 32.8%, 100% {
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+ opacity: 0;
+ }
+}
+.mdc-checkbox {
+ display: inline-block;
+ position: relative;
+ flex: 0 0 18px;
+ box-sizing: content-box;
+ width: 18px;
+ height: 18px;
+ line-height: 0;
+ white-space: nowrap;
+ cursor: pointer;
+ vertical-align: bottom;
+}
+
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate=true]) ~ .mdc-checkbox__background {
+ border-color: GrayText;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-disabled-color, GrayText);
+ background-color: transparent;
+ }
+
+ .mdc-checkbox__native-control[disabled]:checked ~ .mdc-checkbox__background,
+.mdc-checkbox__native-control[disabled]:indeterminate ~ .mdc-checkbox__background,
+.mdc-checkbox__native-control[data-indeterminate=true][disabled] ~ .mdc-checkbox__background {
+ border-color: GrayText;
+ background-color: transparent;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-disabled-color, transparent);
+ }
+
+ .mdc-checkbox__native-control:disabled ~ .mdc-checkbox__background .mdc-checkbox__checkmark {
+ color: GrayText;
+ /* @alternate */
+ color: var(--mdc-checkbox-ink-color, GrayText);
+ }
+ .mdc-checkbox__native-control:disabled ~ .mdc-checkbox__background .mdc-checkbox__mixedmark {
+ border-color: GrayText;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-ink-color, GrayText);
+ }
+
+ .mdc-checkbox__mixedmark {
+ margin: 0 1px;
+ }
+}
+.mdc-checkbox--disabled {
+ cursor: default;
+ pointer-events: none;
+}
+
+.mdc-checkbox__background {
+ display: inline-flex;
+ position: absolute;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ width: 18px;
+ height: 18px;
+ border: 2px solid currentColor;
+ border-radius: 2px;
+ background-color: transparent;
+ pointer-events: none;
+ will-change: background-color, border-color;
+ transition: background-color 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), border-color 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+
+.mdc-checkbox__checkmark {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ opacity: 0;
+ transition: opacity 180ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+.mdc-checkbox--upgraded .mdc-checkbox__checkmark {
+ opacity: 1;
+}
+
+.mdc-checkbox__checkmark-path {
+ transition: stroke-dashoffset 180ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ stroke: currentColor;
+ stroke-width: 3.12px;
+ stroke-dashoffset: 29.7833385;
+ stroke-dasharray: 29.7833385;
+}
+
+.mdc-checkbox__mixedmark {
+ width: 100%;
+ height: 0;
+ -webkit-transform: scaleX(0) rotate(0deg);
+ transform: scaleX(0) rotate(0deg);
+ border-width: 1px;
+ border-style: solid;
+ opacity: 0;
+ transition: opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+
+.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__background, .mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__background, .mdc-checkbox--anim-checked-unchecked .mdc-checkbox__background, .mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__background {
+ -webkit-animation-duration: 180ms;
+ animation-duration: 180ms;
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+}
+.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__checkmark-path {
+ -webkit-animation: mdc-checkbox-unchecked-checked-checkmark-path 180ms linear 0s;
+ animation: mdc-checkbox-unchecked-checked-checkmark-path 180ms linear 0s;
+ transition: none;
+}
+.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__mixedmark {
+ -webkit-animation: mdc-checkbox-unchecked-indeterminate-mixedmark 90ms linear 0s;
+ animation: mdc-checkbox-unchecked-indeterminate-mixedmark 90ms linear 0s;
+ transition: none;
+}
+.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__checkmark-path {
+ -webkit-animation: mdc-checkbox-checked-unchecked-checkmark-path 90ms linear 0s;
+ animation: mdc-checkbox-checked-unchecked-checkmark-path 90ms linear 0s;
+ transition: none;
+}
+.mdc-checkbox--anim-checked-indeterminate .mdc-checkbox__checkmark {
+ -webkit-animation: mdc-checkbox-checked-indeterminate-checkmark 90ms linear 0s;
+ animation: mdc-checkbox-checked-indeterminate-checkmark 90ms linear 0s;
+ transition: none;
+}
+.mdc-checkbox--anim-checked-indeterminate .mdc-checkbox__mixedmark {
+ -webkit-animation: mdc-checkbox-checked-indeterminate-mixedmark 90ms linear 0s;
+ animation: mdc-checkbox-checked-indeterminate-mixedmark 90ms linear 0s;
+ transition: none;
+}
+.mdc-checkbox--anim-indeterminate-checked .mdc-checkbox__checkmark {
+ -webkit-animation: mdc-checkbox-indeterminate-checked-checkmark 500ms linear 0s;
+ animation: mdc-checkbox-indeterminate-checked-checkmark 500ms linear 0s;
+ transition: none;
+}
+.mdc-checkbox--anim-indeterminate-checked .mdc-checkbox__mixedmark {
+ -webkit-animation: mdc-checkbox-indeterminate-checked-mixedmark 500ms linear 0s;
+ animation: mdc-checkbox-indeterminate-checked-mixedmark 500ms linear 0s;
+ transition: none;
+}
+.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__mixedmark {
+ -webkit-animation: mdc-checkbox-indeterminate-unchecked-mixedmark 300ms linear 0s;
+ animation: mdc-checkbox-indeterminate-unchecked-mixedmark 300ms linear 0s;
+ transition: none;
+}
+
+.mdc-checkbox__native-control:checked ~ .mdc-checkbox__background,
+.mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background,
+.mdc-checkbox__native-control[data-indeterminate=true] ~ .mdc-checkbox__background {
+ transition: border-color 90ms 0ms cubic-bezier(0, 0, 0.2, 1), background-color 90ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+.mdc-checkbox__native-control:checked ~ .mdc-checkbox__background .mdc-checkbox__checkmark-path,
+.mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background .mdc-checkbox__checkmark-path,
+.mdc-checkbox__native-control[data-indeterminate=true] ~ .mdc-checkbox__background .mdc-checkbox__checkmark-path {
+ stroke-dashoffset: 0;
+}
+
+.mdc-checkbox__native-control {
+ position: absolute;
+ margin: 0;
+ padding: 0;
+ opacity: 0;
+ cursor: inherit;
+}
+.mdc-checkbox__native-control:disabled {
+ cursor: default;
+ pointer-events: none;
+}
+
+.mdc-checkbox--touch {
+ margin: calc((48px - 40px) / 2);
+ /* @alternate */
+ margin: calc((var(--mdc-checkbox-state-layer-size, 48px) - var(--mdc-checkbox-state-layer-size, 40px)) / 2);
+}
+.mdc-checkbox--touch .mdc-checkbox__native-control {
+ top: calc((40px - 48px) / 2);
+ /* @alternate */
+ top: calc((var(--mdc-checkbox-state-layer-size, 40px) - var(--mdc-checkbox-state-layer-size, 48px)) / 2);
+ right: calc((40px - 48px) / 2);
+ /* @alternate */
+ right: calc((var(--mdc-checkbox-state-layer-size, 40px) - var(--mdc-checkbox-state-layer-size, 48px)) / 2);
+ left: calc((40px - 48px) / 2);
+ /* @alternate */
+ left: calc((var(--mdc-checkbox-state-layer-size, 40px) - var(--mdc-checkbox-state-layer-size, 48px)) / 2);
+ width: 48px;
+ /* @alternate */
+ width: var(--mdc-checkbox-state-layer-size, 48px);
+ height: 48px;
+ /* @alternate */
+ height: var(--mdc-checkbox-state-layer-size, 48px);
+}
+
+.mdc-checkbox__native-control:checked ~ .mdc-checkbox__background .mdc-checkbox__checkmark {
+ transition: opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ opacity: 1;
+}
+.mdc-checkbox__native-control:checked ~ .mdc-checkbox__background .mdc-checkbox__mixedmark {
+ -webkit-transform: scaleX(1) rotate(-45deg);
+ transform: scaleX(1) rotate(-45deg);
+}
+
+.mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background .mdc-checkbox__checkmark,
+.mdc-checkbox__native-control[data-indeterminate=true] ~ .mdc-checkbox__background .mdc-checkbox__checkmark {
+ -webkit-transform: rotate(45deg);
+ transform: rotate(45deg);
+ opacity: 0;
+ transition: opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+.mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background .mdc-checkbox__mixedmark,
+.mdc-checkbox__native-control[data-indeterminate=true] ~ .mdc-checkbox__background .mdc-checkbox__mixedmark {
+ -webkit-transform: scaleX(1) rotate(0deg);
+ transform: scaleX(1) rotate(0deg);
+ opacity: 1;
+}
+
+.mdc-checkbox.mdc-checkbox--upgraded .mdc-checkbox__background,
+.mdc-checkbox.mdc-checkbox--upgraded .mdc-checkbox__checkmark,
+.mdc-checkbox.mdc-checkbox--upgraded .mdc-checkbox__checkmark-path,
+.mdc-checkbox.mdc-checkbox--upgraded .mdc-checkbox__mixedmark {
+ transition: none;
+}
+
+.mdc-checkbox {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-checkbox .mdc-checkbox__ripple::before,
+.mdc-checkbox .mdc-checkbox__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-checkbox .mdc-checkbox__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-checkbox .mdc-checkbox__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-checkbox.mdc-ripple-upgraded--unbounded .mdc-checkbox__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-checkbox.mdc-ripple-upgraded--foreground-activation .mdc-checkbox__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-checkbox.mdc-ripple-upgraded--foreground-deactivation .mdc-checkbox__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-checkbox .mdc-checkbox__ripple::before,
+.mdc-checkbox .mdc-checkbox__ripple::after {
+ top: calc(50% - 50%);
+ /* @noflip */
+ left: calc(50% - 50%);
+ width: 100%;
+ height: 100%;
+}
+.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::before,
+.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after {
+ top: var(--mdc-ripple-top, calc(50% - 50%));
+ /* @noflip */
+ left: var(--mdc-ripple-left, calc(50% - 50%));
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-checkbox {
+ z-index: 0;
+}
+.mdc-checkbox .mdc-checkbox__ripple::before,
+.mdc-checkbox .mdc-checkbox__ripple::after {
+ z-index: -1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, -1);
+}
+
+.mdc-checkbox__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+.mdc-deprecated-chip-trailing-action__touch {
+ position: absolute;
+ top: 50%;
+ height: 48px;
+ /* @noflip */
+ left: 50%;
+ width: 48px;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.mdc-deprecated-chip-trailing-action {
+ border: none;
+ display: inline-flex;
+ position: relative;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ padding: 0;
+ outline: none;
+ cursor: pointer;
+ -webkit-appearance: none;
+ background: none;
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__icon {
+ height: 18px;
+ width: 18px;
+ font-size: 18px;
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__touch {
+ width: 26px;
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__icon {
+ fill: currentColor;
+ color: inherit;
+}
+
+.mdc-deprecated-chip-trailing-action {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::before,
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded--unbounded .mdc-deprecated-chip-trailing-action__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded--foreground-activation .mdc-deprecated-chip-trailing-action__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded--foreground-deactivation .mdc-deprecated-chip-trailing-action__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::before,
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::after {
+ top: calc(50% - 50%);
+ /* @noflip */
+ left: calc(50% - 50%);
+ width: 100%;
+ height: 100%;
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::before,
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::after {
+ top: var(--mdc-ripple-top, calc(50% - 50%));
+ /* @noflip */
+ left: var(--mdc-ripple-left, calc(50% - 50%));
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::before, .mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000));
+}
+.mdc-deprecated-chip-trailing-action:hover .mdc-deprecated-chip-trailing-action__ripple::before, .mdc-deprecated-chip-trailing-action.mdc-ripple-surface--hover .mdc-deprecated-chip-trailing-action__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded--background-focused .mdc-deprecated-chip-trailing-action__ripple::before, .mdc-deprecated-chip-trailing-action:not(.mdc-ripple-upgraded):focus .mdc-deprecated-chip-trailing-action__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-deprecated-chip-trailing-action:not(.mdc-ripple-upgraded) .mdc-deprecated-chip-trailing-action__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-deprecated-chip-trailing-action:not(.mdc-ripple-upgraded):active .mdc-deprecated-chip-trailing-action__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple {
+ position: absolute;
+ box-sizing: content-box;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+
+.mdc-chip__icon--leading {
+ color: rgba(0, 0, 0, 0.54);
+}
+
+.mdc-deprecated-chip-trailing-action {
+ color: #000;
+}
+
+.mdc-chip__icon--trailing {
+ color: rgba(0, 0, 0, 0.54);
+}
+.mdc-chip__icon--trailing:hover {
+ color: rgba(0, 0, 0, 0.62);
+}
+.mdc-chip__icon--trailing:focus {
+ color: rgba(0, 0, 0, 0.87);
+}
+
+.mdc-chip__icon.mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden) {
+ width: 20px;
+ height: 20px;
+ font-size: 20px;
+}
+
+.mdc-deprecated-chip-trailing-action__icon {
+ height: 18px;
+ width: 18px;
+ font-size: 18px;
+}
+
+.mdc-chip__icon.mdc-chip__icon--trailing {
+ width: 18px;
+ height: 18px;
+ font-size: 18px;
+}
+
+.mdc-deprecated-chip-trailing-action {
+ /* @noflip */
+ margin-left: 4px;
+ /* @noflip */
+ margin-right: -4px;
+}
+[dir=rtl] .mdc-deprecated-chip-trailing-action, .mdc-deprecated-chip-trailing-action[dir=rtl] {
+ /* @noflip */
+ margin-left: -4px;
+ /* @noflip */
+ margin-right: 4px;
+}
+
+.mdc-chip__icon--trailing {
+ /* @noflip */
+ margin-left: 4px;
+ /* @noflip */
+ margin-right: -4px;
+}
+[dir=rtl] .mdc-chip__icon--trailing, .mdc-chip__icon--trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: -4px;
+ /* @noflip */
+ margin-right: 4px;
+}
+
+.mdc-chip {
+ border-radius: 16px;
+ background-color: #e0e0e0;
+ color: rgba(0, 0, 0, 0.87);
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ height: 32px;
+ /* @alternate */
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ box-sizing: border-box;
+ padding: 0 12px;
+ border-width: 0;
+ outline: none;
+ cursor: pointer;
+ -webkit-appearance: none;
+}
+.mdc-chip .mdc-chip__ripple {
+ border-radius: 16px;
+}
+.mdc-chip:hover {
+ color: rgba(0, 0, 0, 0.87);
+}
+.mdc-chip.mdc-chip--selected .mdc-chip__checkmark,
+.mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden) {
+ /* @noflip */
+ margin-left: -4px;
+ /* @noflip */
+ margin-right: 4px;
+}
+[dir=rtl] .mdc-chip.mdc-chip--selected .mdc-chip__checkmark, [dir=rtl] .mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden), .mdc-chip.mdc-chip--selected .mdc-chip__checkmark[dir=rtl], .mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden)[dir=rtl] {
+ /* @noflip */
+ margin-left: 4px;
+ /* @noflip */
+ margin-right: -4px;
+}
+
+.mdc-chip .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.mdc-chip::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+.mdc-chip:hover {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-chip .mdc-chip__touch {
+ position: absolute;
+ top: 50%;
+ height: 48px;
+ left: 0;
+ right: 0;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+}
+
+.mdc-chip--exit {
+ transition: opacity 75ms cubic-bezier(0.4, 0, 0.2, 1), width 150ms cubic-bezier(0, 0, 0.2, 1), padding 100ms linear, margin 100ms linear;
+ opacity: 0;
+}
+
+.mdc-chip__overflow {
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+.mdc-chip__text {
+ white-space: nowrap;
+}
+
+.mdc-chip__icon {
+ border-radius: 50%;
+ outline: none;
+ vertical-align: middle;
+}
+
+.mdc-chip__checkmark {
+ height: 20px;
+}
+
+.mdc-chip__checkmark-path {
+ transition: stroke-dashoffset 150ms 50ms cubic-bezier(0.4, 0, 0.6, 1);
+ stroke-width: 2px;
+ stroke-dashoffset: 29.7833385;
+ stroke-dasharray: 29.7833385;
+}
+
+.mdc-chip__primary-action:focus {
+ outline: none;
+}
+
+.mdc-chip--selected .mdc-chip__checkmark-path {
+ stroke-dashoffset: 0;
+}
+
+.mdc-chip__icon--leading,
+.mdc-chip__icon--trailing {
+ position: relative;
+}
+
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__icon--leading {
+ color: rgba(98, 0, 238, 0.54);
+}
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:hover {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-chip-set--choice .mdc-chip .mdc-chip__checkmark-path {
+ stroke: #6200ee;
+ /* @alternate */
+ stroke: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-chip-set--choice .mdc-chip--selected {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+}
+
+.mdc-chip__checkmark-svg {
+ width: 0;
+ height: 20px;
+ transition: width 150ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-chip--selected .mdc-chip__checkmark-svg {
+ width: 20px;
+}
+
+.mdc-chip-set--filter .mdc-chip__icon--leading {
+ transition: opacity 75ms linear;
+ transition-delay: -50ms;
+ opacity: 1;
+}
+.mdc-chip-set--filter .mdc-chip__icon--leading + .mdc-chip__checkmark {
+ transition: opacity 75ms linear;
+ transition-delay: 80ms;
+ opacity: 0;
+}
+.mdc-chip-set--filter .mdc-chip__icon--leading + .mdc-chip__checkmark .mdc-chip__checkmark-svg {
+ transition: width 0ms;
+}
+.mdc-chip-set--filter .mdc-chip--selected .mdc-chip__icon--leading {
+ opacity: 0;
+}
+.mdc-chip-set--filter .mdc-chip--selected .mdc-chip__icon--leading + .mdc-chip__checkmark {
+ width: 0;
+ opacity: 1;
+}
+.mdc-chip-set--filter .mdc-chip__icon--leading-hidden.mdc-chip__icon--leading {
+ width: 0;
+ opacity: 0;
+}
+.mdc-chip-set--filter .mdc-chip__icon--leading-hidden.mdc-chip__icon--leading + .mdc-chip__checkmark {
+ width: 20px;
+}
+
+.mdc-chip {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-chip .mdc-chip__ripple::before,
+.mdc-chip .mdc-chip__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-chip .mdc-chip__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-chip .mdc-chip__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-chip.mdc-ripple-upgraded--unbounded .mdc-chip__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-chip.mdc-ripple-upgraded--foreground-activation .mdc-chip__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-chip.mdc-ripple-upgraded--foreground-deactivation .mdc-chip__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-chip .mdc-chip__ripple::before,
+.mdc-chip .mdc-chip__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-chip .mdc-chip__ripple::before, .mdc-chip .mdc-chip__ripple::after {
+ background-color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, rgba(0, 0, 0, 0.87));
+}
+.mdc-chip:hover .mdc-chip__ripple::before, .mdc-chip.mdc-ripple-surface--hover .mdc-chip__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-chip.mdc-ripple-upgraded--background-focused .mdc-chip__ripple::before, .mdc-chip.mdc-ripple-upgraded:focus-within .mdc-chip__ripple::before, .mdc-chip:not(.mdc-ripple-upgraded):focus .mdc-chip__ripple::before, .mdc-chip:not(.mdc-ripple-upgraded):focus-within .mdc-chip__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-chip:not(.mdc-ripple-upgraded) .mdc-chip__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-chip:not(.mdc-ripple-upgraded):active .mdc-chip__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-chip.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-chip .mdc-chip__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ overflow: hidden;
+}
+
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-selected-opacity, 0.08);
+}
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::before, .mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:hover .mdc-chip__ripple::before, .mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-surface--hover .mdc-chip__ripple::before {
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.12);
+}
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded--background-focused .mdc-chip__ripple::before, .mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded:focus-within .mdc-chip__ripple::before, .mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):focus .mdc-chip__ripple::before, .mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):focus-within .mdc-chip__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.2;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.2);
+}
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded) .mdc-chip__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):active .mdc-chip__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.2;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.2);
+}
+.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.2);
+}
+
+@-webkit-keyframes mdc-chip-entry {
+ from {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0.4;
+ }
+ to {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+@keyframes mdc-chip-entry {
+ from {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0.4;
+ }
+ to {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+.mdc-chip-set {
+ padding: 4px;
+ display: flex;
+ flex-wrap: wrap;
+ box-sizing: border-box;
+}
+.mdc-chip-set .mdc-chip {
+ margin: 4px;
+}
+.mdc-chip-set .mdc-chip--touch {
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+
+.mdc-chip-set--input .mdc-chip {
+ -webkit-animation: mdc-chip-entry 100ms cubic-bezier(0, 0, 0.2, 1);
+ animation: mdc-chip-entry 100ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.mdc-circular-progress__determinate-circle,
+.mdc-circular-progress__indeterminate-circle-graphic {
+ stroke: #6200ee;
+ /* @alternate */
+ stroke: var(--mdc-theme-primary, #6200ee);
+}
+
+.mdc-circular-progress__determinate-track {
+ stroke: transparent;
+}
+
+@-webkit-keyframes mdc-circular-progress-container-rotate {
+ to {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes mdc-circular-progress-container-rotate {
+ to {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+@-webkit-keyframes mdc-circular-progress-spinner-layer-rotate {
+ 12.5% {
+ -webkit-transform: rotate(135deg);
+ transform: rotate(135deg);
+ }
+ 25% {
+ -webkit-transform: rotate(270deg);
+ transform: rotate(270deg);
+ }
+ 37.5% {
+ -webkit-transform: rotate(405deg);
+ transform: rotate(405deg);
+ }
+ 50% {
+ -webkit-transform: rotate(540deg);
+ transform: rotate(540deg);
+ }
+ 62.5% {
+ -webkit-transform: rotate(675deg);
+ transform: rotate(675deg);
+ }
+ 75% {
+ -webkit-transform: rotate(810deg);
+ transform: rotate(810deg);
+ }
+ 87.5% {
+ -webkit-transform: rotate(945deg);
+ transform: rotate(945deg);
+ }
+ 100% {
+ -webkit-transform: rotate(1080deg);
+ transform: rotate(1080deg);
+ }
+}
+@keyframes mdc-circular-progress-spinner-layer-rotate {
+ 12.5% {
+ -webkit-transform: rotate(135deg);
+ transform: rotate(135deg);
+ }
+ 25% {
+ -webkit-transform: rotate(270deg);
+ transform: rotate(270deg);
+ }
+ 37.5% {
+ -webkit-transform: rotate(405deg);
+ transform: rotate(405deg);
+ }
+ 50% {
+ -webkit-transform: rotate(540deg);
+ transform: rotate(540deg);
+ }
+ 62.5% {
+ -webkit-transform: rotate(675deg);
+ transform: rotate(675deg);
+ }
+ 75% {
+ -webkit-transform: rotate(810deg);
+ transform: rotate(810deg);
+ }
+ 87.5% {
+ -webkit-transform: rotate(945deg);
+ transform: rotate(945deg);
+ }
+ 100% {
+ -webkit-transform: rotate(1080deg);
+ transform: rotate(1080deg);
+ }
+}
+@-webkit-keyframes mdc-circular-progress-color-1-fade-in-out {
+ from {
+ opacity: 0.99;
+ }
+ 25% {
+ opacity: 0.99;
+ }
+ 26% {
+ opacity: 0;
+ }
+ 89% {
+ opacity: 0;
+ }
+ 90% {
+ opacity: 0.99;
+ }
+ to {
+ opacity: 0.99;
+ }
+}
+@keyframes mdc-circular-progress-color-1-fade-in-out {
+ from {
+ opacity: 0.99;
+ }
+ 25% {
+ opacity: 0.99;
+ }
+ 26% {
+ opacity: 0;
+ }
+ 89% {
+ opacity: 0;
+ }
+ 90% {
+ opacity: 0.99;
+ }
+ to {
+ opacity: 0.99;
+ }
+}
+@-webkit-keyframes mdc-circular-progress-color-2-fade-in-out {
+ from {
+ opacity: 0;
+ }
+ 15% {
+ opacity: 0;
+ }
+ 25% {
+ opacity: 0.99;
+ }
+ 50% {
+ opacity: 0.99;
+ }
+ 51% {
+ opacity: 0;
+ }
+ to {
+ opacity: 0;
+ }
+}
+@keyframes mdc-circular-progress-color-2-fade-in-out {
+ from {
+ opacity: 0;
+ }
+ 15% {
+ opacity: 0;
+ }
+ 25% {
+ opacity: 0.99;
+ }
+ 50% {
+ opacity: 0.99;
+ }
+ 51% {
+ opacity: 0;
+ }
+ to {
+ opacity: 0;
+ }
+}
+@-webkit-keyframes mdc-circular-progress-color-3-fade-in-out {
+ from {
+ opacity: 0;
+ }
+ 40% {
+ opacity: 0;
+ }
+ 50% {
+ opacity: 0.99;
+ }
+ 75% {
+ opacity: 0.99;
+ }
+ 76% {
+ opacity: 0;
+ }
+ to {
+ opacity: 0;
+ }
+}
+@keyframes mdc-circular-progress-color-3-fade-in-out {
+ from {
+ opacity: 0;
+ }
+ 40% {
+ opacity: 0;
+ }
+ 50% {
+ opacity: 0.99;
+ }
+ 75% {
+ opacity: 0.99;
+ }
+ 76% {
+ opacity: 0;
+ }
+ to {
+ opacity: 0;
+ }
+}
+@-webkit-keyframes mdc-circular-progress-color-4-fade-in-out {
+ from {
+ opacity: 0;
+ }
+ 65% {
+ opacity: 0;
+ }
+ 75% {
+ opacity: 0.99;
+ }
+ 90% {
+ opacity: 0.99;
+ }
+ to {
+ opacity: 0;
+ }
+}
+@keyframes mdc-circular-progress-color-4-fade-in-out {
+ from {
+ opacity: 0;
+ }
+ 65% {
+ opacity: 0;
+ }
+ 75% {
+ opacity: 0.99;
+ }
+ 90% {
+ opacity: 0.99;
+ }
+ to {
+ opacity: 0;
+ }
+}
+@-webkit-keyframes mdc-circular-progress-left-spin {
+ from {
+ -webkit-transform: rotate(265deg);
+ transform: rotate(265deg);
+ }
+ 50% {
+ -webkit-transform: rotate(130deg);
+ transform: rotate(130deg);
+ }
+ to {
+ -webkit-transform: rotate(265deg);
+ transform: rotate(265deg);
+ }
+}
+@keyframes mdc-circular-progress-left-spin {
+ from {
+ -webkit-transform: rotate(265deg);
+ transform: rotate(265deg);
+ }
+ 50% {
+ -webkit-transform: rotate(130deg);
+ transform: rotate(130deg);
+ }
+ to {
+ -webkit-transform: rotate(265deg);
+ transform: rotate(265deg);
+ }
+}
+@-webkit-keyframes mdc-circular-progress-right-spin {
+ from {
+ -webkit-transform: rotate(-265deg);
+ transform: rotate(-265deg);
+ }
+ 50% {
+ -webkit-transform: rotate(-130deg);
+ transform: rotate(-130deg);
+ }
+ to {
+ -webkit-transform: rotate(-265deg);
+ transform: rotate(-265deg);
+ }
+}
+@keyframes mdc-circular-progress-right-spin {
+ from {
+ -webkit-transform: rotate(-265deg);
+ transform: rotate(-265deg);
+ }
+ 50% {
+ -webkit-transform: rotate(-130deg);
+ transform: rotate(-130deg);
+ }
+ to {
+ -webkit-transform: rotate(-265deg);
+ transform: rotate(-265deg);
+ }
+}
+.mdc-circular-progress {
+ display: inline-flex;
+ position: relative;
+ /* @noflip */
+ direction: ltr;
+ line-height: 0;
+ transition: opacity 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+
+.mdc-circular-progress__determinate-container,
+.mdc-circular-progress__indeterminate-circle-graphic,
+.mdc-circular-progress__indeterminate-container,
+.mdc-circular-progress__spinner-layer {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.mdc-circular-progress__determinate-container {
+ -webkit-transform: rotate(-90deg);
+ transform: rotate(-90deg);
+}
+
+.mdc-circular-progress__indeterminate-container {
+ font-size: 0;
+ letter-spacing: 0;
+ white-space: nowrap;
+ opacity: 0;
+}
+
+.mdc-circular-progress__determinate-circle-graphic,
+.mdc-circular-progress__indeterminate-circle-graphic {
+ fill: transparent;
+}
+
+.mdc-circular-progress__determinate-circle {
+ transition: stroke-dashoffset 500ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.mdc-circular-progress__gap-patch {
+ position: absolute;
+ top: 0;
+ /* @noflip */
+ left: 47.5%;
+ box-sizing: border-box;
+ width: 5%;
+ height: 100%;
+ overflow: hidden;
+}
+.mdc-circular-progress__gap-patch .mdc-circular-progress__indeterminate-circle-graphic {
+ /* @noflip */
+ left: -900%;
+ width: 2000%;
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+}
+
+.mdc-circular-progress__circle-clipper {
+ display: inline-flex;
+ position: relative;
+ width: 50%;
+ height: 100%;
+ overflow: hidden;
+}
+.mdc-circular-progress__circle-clipper .mdc-circular-progress__indeterminate-circle-graphic {
+ width: 200%;
+}
+
+.mdc-circular-progress__circle-right .mdc-circular-progress__indeterminate-circle-graphic {
+ /* @noflip */
+ left: -100%;
+}
+
+.mdc-circular-progress--indeterminate .mdc-circular-progress__determinate-container {
+ opacity: 0;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__indeterminate-container {
+ opacity: 1;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__indeterminate-container {
+ -webkit-animation: mdc-circular-progress-container-rotate 1568.2352941176ms linear infinite;
+ animation: mdc-circular-progress-container-rotate 1568.2352941176ms linear infinite;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__spinner-layer {
+ -webkit-animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+ animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__color-1 {
+ -webkit-animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdc-circular-progress-color-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+ animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdc-circular-progress-color-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__color-2 {
+ -webkit-animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdc-circular-progress-color-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+ animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdc-circular-progress-color-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__color-3 {
+ -webkit-animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdc-circular-progress-color-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+ animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdc-circular-progress-color-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__color-4 {
+ -webkit-animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdc-circular-progress-color-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+ animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdc-circular-progress-color-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__circle-left .mdc-circular-progress__indeterminate-circle-graphic {
+ /* @noflip */
+ -webkit-animation: mdc-circular-progress-left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+ animation: mdc-circular-progress-left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+}
+.mdc-circular-progress--indeterminate .mdc-circular-progress__circle-right .mdc-circular-progress__indeterminate-circle-graphic {
+ /* @noflip */
+ -webkit-animation: mdc-circular-progress-right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+ animation: mdc-circular-progress-right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
+}
+
+.mdc-circular-progress--closed {
+ opacity: 0;
+}
+
+.mdc-floating-label {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ position: absolute;
+ /* @noflip */
+ left: 0;
+ /* @noflip */
+ -webkit-transform-origin: left top;
+ /* @noflip */
+ transform-origin: left top;
+ line-height: 1.15rem;
+ text-align: left;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ cursor: text;
+ overflow: hidden;
+ /* @alternate */
+ will-change: transform;
+ transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1), color 150ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1), color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+[dir=rtl] .mdc-floating-label, .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ right: 0;
+ /* @noflip */
+ left: auto;
+ /* @noflip */
+ -webkit-transform-origin: right top;
+ /* @noflip */
+ transform-origin: right top;
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-floating-label--float-above {
+ cursor: auto;
+}
+
+.mdc-floating-label--required::after {
+ /* @noflip */
+ margin-left: 1px;
+ /* @noflip */
+ margin-right: 0px;
+ content: "*";
+}
+[dir=rtl] .mdc-floating-label--required::after, .mdc-floating-label--required[dir=rtl]::after {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 1px;
+}
+
+.mdc-floating-label--float-above {
+ -webkit-transform: translateY(-106%) scale(0.75);
+ transform: translateY(-106%) scale(0.75);
+}
+
+.mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-standard 250ms 1;
+ animation: mdc-floating-label-shake-float-above-standard 250ms 1;
+}
+
+@-webkit-keyframes mdc-floating-label-shake-float-above-standard {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-106%) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-106%) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);
+ }
+}
+
+@keyframes mdc-floating-label-shake-float-above-standard {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-106%) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-106%) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);
+ }
+}
+.mdc-line-ripple::before, .mdc-line-ripple::after {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ border-bottom-style: solid;
+ content: "";
+}
+.mdc-line-ripple::before {
+ border-bottom-width: 1px;
+ z-index: 1;
+}
+.mdc-line-ripple::after {
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+ border-bottom-width: 2px;
+ opacity: 0;
+ z-index: 2;
+}
+.mdc-line-ripple::after {
+ transition: opacity 180ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 180ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1), opacity 180ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1), opacity 180ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 180ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-line-ripple--active::after {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ opacity: 1;
+}
+
+.mdc-line-ripple--deactivating::after {
+ opacity: 0;
+}
+
+.mdc-notched-outline {
+ display: flex;
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ box-sizing: border-box;
+ width: 100%;
+ max-width: 100%;
+ height: 100%;
+ /* @noflip */
+ text-align: left;
+ pointer-events: none;
+}
+[dir=rtl] .mdc-notched-outline, .mdc-notched-outline[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing {
+ box-sizing: border-box;
+ height: 100%;
+ border-top: 1px solid;
+ border-bottom: 1px solid;
+ pointer-events: none;
+}
+.mdc-notched-outline__leading {
+ /* @noflip */
+ border-left: 1px solid;
+ /* @noflip */
+ border-right: none;
+ width: 12px;
+}
+[dir=rtl] .mdc-notched-outline__leading, .mdc-notched-outline__leading[dir=rtl] {
+ /* @noflip */
+ border-left: none;
+ /* @noflip */
+ border-right: 1px solid;
+}
+
+.mdc-notched-outline__trailing {
+ /* @noflip */
+ border-left: none;
+ /* @noflip */
+ border-right: 1px solid;
+ flex-grow: 1;
+}
+[dir=rtl] .mdc-notched-outline__trailing, .mdc-notched-outline__trailing[dir=rtl] {
+ /* @noflip */
+ border-left: 1px solid;
+ /* @noflip */
+ border-right: none;
+}
+
+.mdc-notched-outline__notch {
+ flex: 0 0 auto;
+ width: auto;
+ max-width: calc(100% - 12px * 2);
+}
+.mdc-notched-outline .mdc-floating-label {
+ display: inline-block;
+ position: relative;
+ max-width: 100%;
+}
+.mdc-notched-outline .mdc-floating-label--float-above {
+ text-overflow: clip;
+}
+.mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ max-width: calc(100% / 0.75);
+}
+
+.mdc-notched-outline--notched .mdc-notched-outline__notch {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 8px;
+ border-top: none;
+}
+[dir=rtl] .mdc-notched-outline--notched .mdc-notched-outline__notch, .mdc-notched-outline--notched .mdc-notched-outline__notch[dir=rtl] {
+ /* @noflip */
+ padding-left: 8px;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-notched-outline--no-label .mdc-notched-outline__notch {
+ display: none;
+}
+
+.mdc-select {
+ display: inline-flex;
+ position: relative;
+}
+.mdc-select:not(.mdc-select--disabled) .mdc-select__selected-text {
+ color: rgba(0, 0, 0, 0.87);
+}
+.mdc-select.mdc-select--disabled .mdc-select__selected-text {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-select:not(.mdc-select--disabled) .mdc-floating-label {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label {
+ color: rgba(98, 0, 238, 0.87);
+}
+.mdc-select.mdc-select--disabled .mdc-floating-label {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-select:not(.mdc-select--disabled) .mdc-select__dropdown-icon {
+ fill: rgba(0, 0, 0, 0.54);
+}
+.mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-select__dropdown-icon {
+ fill: #6200ee;
+ /* @alternate */
+ fill: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-select.mdc-select--disabled .mdc-select__dropdown-icon {
+ fill: rgba(0, 0, 0, 0.38);
+}
+.mdc-select:not(.mdc-select--disabled) + .mdc-select-helper-text {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-select.mdc-select--disabled + .mdc-select-helper-text {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-select:not(.mdc-select--disabled) .mdc-select__icon {
+ color: rgba(0, 0, 0, 0.54);
+}
+.mdc-select.mdc-select--disabled .mdc-select__icon {
+ color: rgba(0, 0, 0, 0.38);
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-select.mdc-select--disabled .mdc-select__selected-text {
+ color: GrayText;
+ }
+ .mdc-select.mdc-select--disabled .mdc-select__dropdown-icon {
+ fill: red;
+ }
+ .mdc-select.mdc-select--disabled .mdc-floating-label {
+ color: GrayText;
+ }
+ .mdc-select.mdc-select--disabled .mdc-line-ripple::before {
+ border-bottom-color: GrayText;
+ }
+ .mdc-select.mdc-select--disabled .mdc-notched-outline__leading,
+.mdc-select.mdc-select--disabled .mdc-notched-outline__notch,
+.mdc-select.mdc-select--disabled .mdc-notched-outline__trailing {
+ border-color: GrayText;
+ }
+ .mdc-select.mdc-select--disabled .mdc-select__icon {
+ color: GrayText;
+ }
+ .mdc-select.mdc-select--disabled + .mdc-select-helper-text {
+ color: GrayText;
+ }
+}
+.mdc-select .mdc-floating-label {
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+ pointer-events: none;
+}
+.mdc-select .mdc-select__anchor {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-select .mdc-select__anchor, .mdc-select .mdc-select__anchor[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-select.mdc-select--with-leading-icon .mdc-select__anchor {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-select.mdc-select--with-leading-icon .mdc-select__anchor, .mdc-select.mdc-select--with-leading-icon .mdc-select__anchor[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-select .mdc-select__icon {
+ width: 24px;
+ height: 24px;
+ font-size: 24px;
+}
+.mdc-select .mdc-select__dropdown-icon {
+ width: 24px;
+ height: 24px;
+}
+.mdc-select .mdc-select__menu .mdc-deprecated-list-item {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+[dir=rtl] .mdc-select .mdc-select__menu .mdc-deprecated-list-item, .mdc-select .mdc-select__menu .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-select .mdc-select__menu .mdc-deprecated-list-item__graphic {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 12px;
+}
+[dir=rtl] .mdc-select .mdc-select__menu .mdc-deprecated-list-item__graphic, .mdc-select .mdc-select__menu .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 12px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-select__dropdown-icon {
+ /* @noflip */
+ margin-left: 12px;
+ /* @noflip */
+ margin-right: 12px;
+ display: inline-flex;
+ position: relative;
+ align-self: center;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ pointer-events: none;
+}
+.mdc-select__dropdown-icon .mdc-select__dropdown-icon-active,
+.mdc-select__dropdown-icon .mdc-select__dropdown-icon-inactive {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+.mdc-select__dropdown-icon .mdc-select__dropdown-icon-graphic {
+ width: 41.6666666667%;
+ height: 20.8333333333%;
+}
+.mdc-select__dropdown-icon .mdc-select__dropdown-icon-inactive {
+ opacity: 1;
+ transition: opacity 75ms linear 75ms;
+}
+.mdc-select__dropdown-icon .mdc-select__dropdown-icon-active {
+ opacity: 0;
+ transition: opacity 75ms linear;
+}
+[dir=rtl] .mdc-select__dropdown-icon, .mdc-select__dropdown-icon[dir=rtl] {
+ /* @noflip */
+ margin-left: 12px;
+ /* @noflip */
+ margin-right: 12px;
+}
+
+.mdc-select--activated .mdc-select__dropdown-icon .mdc-select__dropdown-icon-inactive {
+ opacity: 0;
+ transition: opacity 49.5ms linear;
+}
+.mdc-select--activated .mdc-select__dropdown-icon .mdc-select__dropdown-icon-active {
+ opacity: 1;
+ transition: opacity 100.5ms linear 49.5ms;
+}
+
+.mdc-select__anchor {
+ width: 200px;
+ min-width: 0;
+ flex: 1 1 auto;
+ position: relative;
+ box-sizing: border-box;
+ overflow: hidden;
+ outline: none;
+ cursor: pointer;
+}
+.mdc-select__anchor .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-106%) scale(0.75);
+ transform: translateY(-106%) scale(0.75);
+}
+
+.mdc-select__selected-text-container {
+ display: flex;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ pointer-events: none;
+ box-sizing: border-box;
+ width: auto;
+ min-width: 0;
+ flex-grow: 1;
+ height: 28px;
+ border: none;
+ outline: none;
+ padding: 0;
+ background-color: transparent;
+ color: inherit;
+}
+
+.mdc-select__selected-text {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ line-height: 1.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle1-line-height, 1.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ display: block;
+ width: 100%;
+ /* @noflip */
+ text-align: left;
+}
+[dir=rtl] .mdc-select__selected-text, .mdc-select__selected-text[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-select--invalid:not(.mdc-select--disabled) .mdc-floating-label {
+ color: #b00020;
+ /* @alternate */
+ color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label {
+ color: #b00020;
+ /* @alternate */
+ color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--invalid + .mdc-select-helper-text--validation-msg {
+ color: #b00020;
+ /* @alternate */
+ color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--invalid:not(.mdc-select--disabled) .mdc-select__dropdown-icon {
+ fill: #b00020;
+ /* @alternate */
+ fill: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-select__dropdown-icon {
+ fill: #b00020;
+ /* @alternate */
+ fill: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--disabled {
+ cursor: default;
+ pointer-events: none;
+}
+
+.mdc-select--with-leading-icon .mdc-select__menu .mdc-deprecated-list-item {
+ /* @noflip */
+ padding-left: 12px;
+ /* @noflip */
+ padding-right: 12px;
+}
+[dir=rtl] .mdc-select--with-leading-icon .mdc-select__menu .mdc-deprecated-list-item, .mdc-select--with-leading-icon .mdc-select__menu .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 12px;
+ /* @noflip */
+ padding-right: 12px;
+}
+
+.mdc-select__menu .mdc-deprecated-list .mdc-select__icon {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0;
+}
+[dir=rtl] .mdc-select__menu .mdc-deprecated-list .mdc-select__icon, .mdc-select__menu .mdc-deprecated-list .mdc-select__icon[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected,
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--activated {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-deprecated-list-item__graphic,
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--activated .mdc-deprecated-list-item__graphic {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+
+.mdc-select--filled .mdc-select__anchor {
+ height: 56px;
+ display: flex;
+ align-items: baseline;
+}
+.mdc-select--filled .mdc-select__anchor::before {
+ display: inline-block;
+ width: 0;
+ height: 40px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-select--filled.mdc-select--no-label .mdc-select__anchor .mdc-select__selected-text::before {
+ content: "";
+}
+.mdc-select--filled.mdc-select--no-label .mdc-select__anchor .mdc-select__selected-text-container {
+ height: 100%;
+ display: inline-flex;
+ align-items: center;
+}
+.mdc-select--filled.mdc-select--no-label .mdc-select__anchor::before {
+ display: none;
+}
+.mdc-select--filled .mdc-select__anchor {
+ border-top-left-radius: 4px;
+ /* @alternate */
+ border-top-left-radius: var(--mdc-shape-small, 4px);
+ border-top-right-radius: 4px;
+ /* @alternate */
+ border-top-right-radius: var(--mdc-shape-small, 4px);
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.mdc-select--filled:not(.mdc-select--disabled) .mdc-select__anchor {
+ background-color: whitesmoke;
+}
+.mdc-select--filled.mdc-select--disabled .mdc-select__anchor {
+ background-color: #fafafa;
+}
+.mdc-select--filled:not(.mdc-select--disabled) .mdc-line-ripple::before {
+ border-bottom-color: rgba(0, 0, 0, 0.42);
+}
+.mdc-select--filled:not(.mdc-select--disabled):hover .mdc-line-ripple::before {
+ border-bottom-color: rgba(0, 0, 0, 0.87);
+}
+.mdc-select--filled:not(.mdc-select--disabled) .mdc-line-ripple::after {
+ border-bottom-color: #6200ee;
+ /* @alternate */
+ border-bottom-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-select--filled.mdc-select--disabled .mdc-line-ripple::before {
+ border-bottom-color: rgba(0, 0, 0, 0.06);
+}
+.mdc-select--filled .mdc-floating-label {
+ max-width: calc(100% - 64px);
+}
+.mdc-select--filled .mdc-floating-label--float-above {
+ max-width: calc(100% / 0.75 - 64px / 0.75);
+}
+.mdc-select--filled .mdc-menu-surface--is-open-below {
+ border-top-left-radius: 0px;
+ border-top-right-radius: 0px;
+}
+.mdc-select--filled.mdc-select--focused.mdc-line-ripple::after {
+ -webkit-transform: scale(1, 2);
+ transform: scale(1, 2);
+ opacity: 1;
+}
+.mdc-select--filled .mdc-floating-label {
+ /* @noflip */
+ left: 16px;
+ /* @noflip */
+ right: initial;
+}
+[dir=rtl] .mdc-select--filled .mdc-floating-label, .mdc-select--filled .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 16px;
+}
+
+.mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label {
+ /* @noflip */
+ left: 48px;
+ /* @noflip */
+ right: initial;
+}
+[dir=rtl] .mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label, .mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 48px;
+}
+
+.mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label {
+ max-width: calc(100% - 96px);
+}
+.mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label--float-above {
+ max-width: calc(100% / 0.75 - 96px / 0.75);
+}
+
+.mdc-select--invalid:not(.mdc-select--disabled) .mdc-line-ripple::before {
+ border-bottom-color: #b00020;
+ /* @alternate */
+ border-bottom-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--invalid:not(.mdc-select--disabled):hover .mdc-line-ripple::before {
+ border-bottom-color: #b00020;
+ /* @alternate */
+ border-bottom-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--invalid:not(.mdc-select--disabled) .mdc-line-ripple::after {
+ border-bottom-color: #b00020;
+ /* @alternate */
+ border-bottom-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--outlined {
+ border: none;
+}
+.mdc-select--outlined .mdc-select__anchor {
+ height: 56px;
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-37.25px) scale(1);
+ transform: translateY(-37.25px) scale(1);
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above {
+ font-size: 0.75rem;
+}
+.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-34.75px) scale(0.75);
+ transform: translateY(-34.75px) scale(0.75);
+}
+.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ font-size: 1rem;
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-select-outlined-56px 250ms 1;
+ animation: mdc-floating-label-shake-float-above-select-outlined-56px 250ms 1;
+}
+@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-56px {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ }
+}
+@keyframes mdc-floating-label-shake-float-above-select-outlined-56px {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ }
+}
+.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading {
+ /* @noflip */
+ border-top-left-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-top-left-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-top-right-radius: 0;
+ /* @noflip */
+ border-bottom-right-radius: 0;
+ /* @noflip */
+ border-bottom-left-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-left-radius: var(--mdc-shape-small, 4px);
+}
+[dir=rtl] .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading, .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading[dir=rtl] {
+ /* @noflip */
+ border-top-left-radius: 0;
+ /* @noflip */
+ border-top-right-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-top-right-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-bottom-right-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-right-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-bottom-left-radius: 0;
+}
+
+@supports (top: max(0%)) {
+ .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading {
+ width: max(12px, var(--mdc-shape-small, 4px));
+ }
+}
+@supports (top: max(0%)) {
+ .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__notch {
+ max-width: calc(100% - max(12px, var(--mdc-shape-small, 4px)) * 2);
+ }
+}
+.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing {
+ /* @noflip */
+ border-top-left-radius: 0;
+ /* @noflip */
+ border-top-right-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-top-right-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-bottom-right-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-right-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-bottom-left-radius: 0;
+}
+[dir=rtl] .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing, .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl] {
+ /* @noflip */
+ border-top-left-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-top-left-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-top-right-radius: 0;
+ /* @noflip */
+ border-bottom-right-radius: 0;
+ /* @noflip */
+ border-bottom-left-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-left-radius: var(--mdc-shape-small, 4px);
+}
+
+@supports (top: max(0%)) {
+ .mdc-select--outlined .mdc-select__anchor {
+ /* @noflip */
+ padding-left: max(16px, calc(var(--mdc-shape-small, 4px) + 4px));
+ }
+}
+[dir=rtl] .mdc-select--outlined .mdc-select__anchor, .mdc-select--outlined .mdc-select__anchor[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+}
+@supports (top: max(0%)) {
+ [dir=rtl] .mdc-select--outlined .mdc-select__anchor, .mdc-select--outlined .mdc-select__anchor[dir=rtl] {
+ /* @noflip */
+ padding-right: max(16px, calc(var(--mdc-shape-small, 4px) + 4px));
+ }
+}
+
+@supports (top: max(0%)) {
+ .mdc-select--outlined + .mdc-select-helper-text {
+ /* @noflip */
+ margin-left: max(16px, calc(var(--mdc-shape-small, 4px) + 4px));
+ }
+}
+[dir=rtl] .mdc-select--outlined + .mdc-select-helper-text, .mdc-select--outlined + .mdc-select-helper-text[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+}
+@supports (top: max(0%)) {
+ [dir=rtl] .mdc-select--outlined + .mdc-select-helper-text, .mdc-select--outlined + .mdc-select-helper-text[dir=rtl] {
+ /* @noflip */
+ margin-right: max(16px, calc(var(--mdc-shape-small, 4px) + 4px));
+ }
+}
+
+.mdc-select--outlined:not(.mdc-select--disabled) .mdc-select__anchor {
+ background-color: transparent;
+}
+.mdc-select--outlined.mdc-select--disabled .mdc-select__anchor {
+ background-color: transparent;
+}
+.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__leading,
+.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__notch,
+.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__trailing {
+ border-color: rgba(0, 0, 0, 0.38);
+}
+.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__leading,
+.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__notch,
+.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__trailing {
+ border-color: rgba(0, 0, 0, 0.87);
+}
+.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,
+.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,
+.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing {
+ border-width: 2px;
+}
+.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,
+.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,
+.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-select--outlined.mdc-select--disabled .mdc-notched-outline__leading,
+.mdc-select--outlined.mdc-select--disabled .mdc-notched-outline__notch,
+.mdc-select--outlined.mdc-select--disabled .mdc-notched-outline__trailing {
+ border-color: rgba(0, 0, 0, 0.06);
+}
+.mdc-select--outlined .mdc-select__anchor :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch {
+ max-width: calc(100% - 60px);
+}
+.mdc-select--outlined .mdc-select__anchor {
+ display: flex;
+ align-items: baseline;
+ overflow: visible;
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-select-outlined 250ms 1;
+ animation: mdc-floating-label-shake-float-above-select-outlined 250ms 1;
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-37.25px) scale(1);
+ transform: translateY(-37.25px) scale(1);
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above {
+ font-size: 0.75rem;
+}
+.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-34.75px) scale(0.75);
+ transform: translateY(-34.75px) scale(0.75);
+}
+.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ font-size: 1rem;
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--notched .mdc-notched-outline__notch {
+ padding-top: 1px;
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-select__selected-text::before {
+ content: "";
+}
+.mdc-select--outlined .mdc-select__anchor .mdc-select__selected-text-container {
+ height: 100%;
+ display: inline-flex;
+ align-items: center;
+}
+.mdc-select--outlined .mdc-select__anchor::before {
+ display: none;
+}
+.mdc-select--outlined .mdc-select__selected-text-container {
+ display: flex;
+ border: none;
+ z-index: 1;
+ background-color: transparent;
+}
+.mdc-select--outlined .mdc-select__icon {
+ z-index: 2;
+}
+.mdc-select--outlined .mdc-floating-label {
+ line-height: 1.15rem;
+ /* @noflip */
+ left: 4px;
+ /* @noflip */
+ right: initial;
+}
+[dir=rtl] .mdc-select--outlined .mdc-floating-label, .mdc-select--outlined .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 4px;
+}
+
+.mdc-select--outlined.mdc-select--focused .mdc-notched-outline--notched .mdc-notched-outline__notch {
+ padding-top: 2px;
+}
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled) .mdc-notched-outline__leading,
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled) .mdc-notched-outline__notch,
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled) .mdc-notched-outline__trailing {
+ border-color: #b00020;
+ /* @alternate */
+ border-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__leading,
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__notch,
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__trailing {
+ border-color: #b00020;
+ /* @alternate */
+ border-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing {
+ border-width: 2px;
+}
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,
+.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing {
+ border-color: #b00020;
+ /* @alternate */
+ border-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label {
+ /* @noflip */
+ left: 36px;
+ /* @noflip */
+ right: initial;
+}
+[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label, .mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 36px;
+}
+
+.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-37.25px) translateX(-32px) scale(1);
+ transform: translateY(-37.25px) translateX(-32px) scale(1);
+}
+[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--float-above, .mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--float-above[dir=rtl] {
+ -webkit-transform: translateY(-37.25px) translateX(32px) scale(1);
+ transform: translateY(-37.25px) translateX(32px) scale(1);
+}
+
+.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--float-above {
+ font-size: 0.75rem;
+}
+.mdc-select--outlined.mdc-select--with-leading-icon.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-select--outlined.mdc-select--with-leading-icon .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-34.75px) translateX(-32px) scale(0.75);
+ transform: translateY(-34.75px) translateX(-32px) scale(0.75);
+}
+[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon.mdc-notched-outline--upgraded .mdc-floating-label--float-above, [dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon .mdc-notched-outline--upgraded .mdc-floating-label--float-above, .mdc-select--outlined.mdc-select--with-leading-icon.mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl], .mdc-select--outlined.mdc-select--with-leading-icon .mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl] {
+ -webkit-transform: translateY(-34.75px) translateX(32px) scale(0.75);
+ transform: translateY(-34.75px) translateX(32px) scale(0.75);
+}
+
+.mdc-select--outlined.mdc-select--with-leading-icon.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-select--outlined.mdc-select--with-leading-icon .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ font-size: 1rem;
+}
+.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px 250ms 1;
+ animation: mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px 250ms 1;
+}
+@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ }
+}
+@keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ }
+}
+[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--shake, .mdc-select--outlined.mdc-select--with-leading-icon[dir=rtl] .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px 250ms 1;
+ animation: mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px 250ms 1;
+}
+
+@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px-rtl {
+ 0% {
+ -webkit-transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ }
+}
+
+@keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px-rtl {
+ 0% {
+ -webkit-transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ }
+}
+.mdc-select--outlined.mdc-select--with-leading-icon .mdc-select__anchor :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch {
+ max-width: calc(100% - 96px);
+}
+.mdc-select--outlined .mdc-menu-surface {
+ margin-bottom: 8px;
+}
+.mdc-select--outlined.mdc-select--no-label .mdc-menu-surface,
+.mdc-select--outlined .mdc-menu-surface--is-open-below {
+ margin-bottom: 0;
+}
+
+.mdc-select__anchor {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-select__anchor .mdc-select__ripple::before,
+.mdc-select__anchor .mdc-select__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-select__anchor .mdc-select__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-select__anchor .mdc-select__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-select__anchor.mdc-ripple-upgraded--unbounded .mdc-select__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-select__anchor.mdc-ripple-upgraded--foreground-activation .mdc-select__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-select__anchor.mdc-ripple-upgraded--foreground-deactivation .mdc-select__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-select__anchor .mdc-select__ripple::before,
+.mdc-select__anchor .mdc-select__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-select__anchor .mdc-select__ripple::before,
+.mdc-select__anchor .mdc-select__ripple::after {
+ background-color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, rgba(0, 0, 0, 0.87));
+}
+.mdc-select__anchor:hover .mdc-select__ripple::before, .mdc-select__anchor.mdc-ripple-surface--hover .mdc-select__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-select__anchor.mdc-ripple-upgraded--background-focused .mdc-select__ripple::before, .mdc-select__anchor:not(.mdc-ripple-upgraded):focus .mdc-select__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-select__anchor .mdc-select__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::before, .mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000));
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:hover .mdc-deprecated-list-item__ripple::before, .mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-surface--hover .mdc-deprecated-list-item__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before, .mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded) .mdc-deprecated-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-deprecated-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-list-item__ripple::before, .mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-list-item__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000));
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:hover .mdc-list-item__ripple::before, .mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-surface--hover .mdc-list-item__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, .mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+
+.mdc-select-helper-text {
+ margin: 0;
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-caption-font-size, 0.75rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-caption-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-caption-font-weight, 400);
+ letter-spacing: 0.0333333333em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-caption-text-transform, inherit);
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+[dir=rtl] .mdc-select-helper-text, .mdc-select-helper-text[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-select-helper-text::before {
+ display: inline-block;
+ width: 0;
+ height: 16px;
+ content: "";
+ vertical-align: 0;
+}
+
+.mdc-select-helper-text--validation-msg {
+ opacity: 0;
+ transition: opacity 180ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-select--invalid + .mdc-select-helper-text--validation-msg,
+.mdc-select-helper-text--validation-msg-persistent {
+ opacity: 1;
+}
+
+.mdc-select--with-leading-icon .mdc-select__icon {
+ display: inline-block;
+ box-sizing: border-box;
+ border: none;
+ text-decoration: none;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ flex-shrink: 0;
+ align-self: center;
+ background-color: transparent;
+ fill: currentColor;
+}
+.mdc-select--with-leading-icon .mdc-select__icon {
+ /* @noflip */
+ margin-left: 12px;
+ /* @noflip */
+ margin-right: 12px;
+}
+[dir=rtl] .mdc-select--with-leading-icon .mdc-select__icon, .mdc-select--with-leading-icon .mdc-select__icon[dir=rtl] {
+ /* @noflip */
+ margin-left: 12px;
+ /* @noflip */
+ margin-right: 12px;
+}
+
+.mdc-select__icon:not([tabindex]),
+.mdc-select__icon[tabindex="-1"] {
+ cursor: default;
+ pointer-events: none;
+}
+
+.mdc-data-table__content {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+}
+
+.mdc-data-table {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-medium, 4px);
+ border-width: 1px;
+ border-style: solid;
+ border-color: rgba(0, 0, 0, 0.12);
+ -webkit-overflow-scrolling: touch;
+ display: inline-flex;
+ flex-direction: column;
+ box-sizing: border-box;
+ position: relative;
+}
+.mdc-data-table .mdc-data-table__header-cell:first-child {
+ border-top-left-radius: 4px;
+ /* @alternate */
+ border-top-left-radius: var(--mdc-shape-medium, 4px);
+}
+[dir=rtl] .mdc-data-table .mdc-data-table__header-cell:first-child, .mdc-data-table .mdc-data-table__header-cell:first-child[dir=rtl] {
+ border-top-right-radius: 4px;
+ /* @alternate */
+ border-top-right-radius: var(--mdc-shape-medium, 4px);
+ border-top-left-radius: 0;
+}
+
+.mdc-data-table .mdc-data-table__header-cell:last-child {
+ border-top-right-radius: 4px;
+ /* @alternate */
+ border-top-right-radius: var(--mdc-shape-medium, 4px);
+}
+[dir=rtl] .mdc-data-table .mdc-data-table__header-cell:last-child, .mdc-data-table .mdc-data-table__header-cell:last-child[dir=rtl] {
+ border-top-left-radius: 4px;
+ /* @alternate */
+ border-top-left-radius: var(--mdc-shape-medium, 4px);
+ border-top-right-radius: 0;
+}
+
+.mdc-data-table__row {
+ background-color: inherit;
+}
+
+.mdc-data-table__header-cell {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+}
+
+.mdc-data-table__row--selected {
+ background-color: rgba(98, 0, 238, 0.04);
+}
+
+.mdc-data-table__pagination-rows-per-page-select:not(.mdc-select--disabled) .mdc-notched-outline__leading,
+.mdc-data-table__pagination-rows-per-page-select:not(.mdc-select--disabled) .mdc-notched-outline__notch,
+.mdc-data-table__pagination-rows-per-page-select:not(.mdc-select--disabled) .mdc-notched-outline__trailing {
+ border-color: rgba(0, 0, 0, 0.12);
+}
+.mdc-data-table__cell,
+.mdc-data-table__header-cell {
+ border-bottom-color: rgba(0, 0, 0, 0.12);
+}
+
+.mdc-data-table__pagination {
+ border-top-color: rgba(0, 0, 0, 0.12);
+}
+
+.mdc-data-table__cell,
+.mdc-data-table__header-cell {
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+.mdc-data-table__pagination {
+ border-top-width: 1px;
+ border-top-style: solid;
+}
+
+.mdc-data-table__row:last-child .mdc-data-table__cell {
+ border-bottom: none;
+}
+
+.mdc-data-table__row:not(.mdc-data-table__row--selected):hover {
+ background-color: rgba(0, 0, 0, 0.04);
+}
+
+.mdc-data-table__header-cell {
+ color: rgba(0, 0, 0, 0.87);
+}
+
+.mdc-data-table__pagination-total,
+.mdc-data-table__pagination-rows-per-page-label,
+.mdc-data-table__cell {
+ color: rgba(0, 0, 0, 0.87);
+}
+
+.mdc-data-table__row {
+ height: 52px;
+}
+
+.mdc-data-table__pagination {
+ min-height: 52px;
+}
+
+.mdc-data-table__header-row {
+ height: 56px;
+}
+
+.mdc-data-table__cell,
+.mdc-data-table__header-cell {
+ padding: 0 16px 0 16px;
+}
+
+.mdc-data-table__header-cell--checkbox,
+.mdc-data-table__cell--checkbox {
+ /* @noflip */
+ padding-left: 4px;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-data-table__header-cell--checkbox, [dir=rtl] .mdc-data-table__cell--checkbox, .mdc-data-table__header-cell--checkbox[dir=rtl], .mdc-data-table__cell--checkbox[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 4px;
+}
+
+.mdc-data-table__sort-icon-button {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-data-table__sort-icon-button .mdc-icon-button__ripple::before, .mdc-data-table__sort-icon-button .mdc-icon-button__ripple::after {
+ background-color: rgba(0, 0, 0, 0.6);
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, rgba(0, 0, 0, 0.6));
+}
+.mdc-data-table__sort-icon-button:hover .mdc-icon-button__ripple::before, .mdc-data-table__sort-icon-button.mdc-ripple-surface--hover .mdc-icon-button__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-data-table__sort-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before, .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-data-table__sort-icon-button.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+
+.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button {
+ color: rgba(0, 0, 0, 0.87);
+}
+.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button .mdc-icon-button__ripple::before, .mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button .mdc-icon-button__ripple::after {
+ background-color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, rgba(0, 0, 0, 0.87));
+}
+.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:hover .mdc-icon-button__ripple::before, .mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button.mdc-ripple-surface--hover .mdc-icon-button__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before, .mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+
+.mdc-data-table__table-container {
+ -webkit-overflow-scrolling: touch;
+ overflow-x: auto;
+ width: 100%;
+}
+
+.mdc-data-table__table {
+ min-width: 100%;
+ border: 0;
+ white-space: nowrap;
+ border-spacing: 0;
+ /**
+ * With table-layout:fixed, table and column widths are defined by the width
+ * of the first row of cells. Cells in subsequent rows do not affect column
+ * widths. This results in a predictable table layout and may also speed up
+ * rendering.
+ */
+ table-layout: fixed;
+}
+
+.mdc-data-table__cell {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ box-sizing: border-box;
+ overflow: hidden;
+ text-align: left;
+ text-overflow: ellipsis;
+}
+[dir=rtl] .mdc-data-table__cell, .mdc-data-table__cell[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-data-table__cell--numeric {
+ text-align: right;
+}
+[dir=rtl] .mdc-data-table__cell--numeric, .mdc-data-table__cell--numeric[dir=rtl] {
+ /* @noflip */
+ text-align: left;
+}
+
+.mdc-data-table__cell--checkbox {
+ width: 1px;
+}
+
+.mdc-data-table__header-cell {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle2-font-size, 0.875rem);
+ line-height: 1.375rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle2-line-height, 1.375rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle2-font-weight, 500);
+ letter-spacing: 0.0071428571em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle2-text-transform, inherit);
+ box-sizing: border-box;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ outline: none;
+ /* @noflip */
+ text-align: left;
+}
+[dir=rtl] .mdc-data-table__header-cell, .mdc-data-table__header-cell[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-data-table__header-cell--checkbox {
+ width: 1px;
+}
+
+.mdc-data-table__header-cell--numeric {
+ text-align: right;
+}
+[dir=rtl] .mdc-data-table__header-cell--numeric, .mdc-data-table__header-cell--numeric[dir=rtl] {
+ /* @noflip */
+ text-align: left;
+}
+
+.mdc-data-table__sort-icon-button {
+ width: 28px;
+ height: 28px;
+ padding: 2px;
+ -webkit-transform: rotate(0.0001deg);
+ transform: rotate(0.0001deg);
+ /* @noflip */
+ margin-left: 4px;
+ /* @noflip */
+ margin-right: 0;
+ transition: -webkit-transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ opacity: 0;
+}
+.mdc-data-table__sort-icon-button.mdc-icon-button--touch {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.mdc-data-table__sort-icon-button.mdc-icon-button--touch .mdc-icon-button__touch {
+ display: none;
+}
+[dir=rtl] .mdc-data-table__sort-icon-button, .mdc-data-table__sort-icon-button[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 4px;
+}
+
+.mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 4px;
+}
+[dir=rtl] .mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button, .mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button[dir=rtl] {
+ /* @noflip */
+ margin-left: 4px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-data-table__header-cell--sorted-descending .mdc-data-table__sort-icon-button {
+ -webkit-transform: rotate(-180deg);
+ transform: rotate(-180deg);
+}
+.mdc-data-table__sort-icon-button:focus, .mdc-data-table__header-cell:hover .mdc-data-table__sort-icon-button, .mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button {
+ opacity: 1;
+}
+
+.mdc-data-table__header-cell-wrapper {
+ align-items: center;
+ display: inline-flex;
+ vertical-align: middle;
+}
+
+.mdc-data-table__header-cell--with-sort {
+ cursor: pointer;
+}
+
+.mdc-data-table__sort-status-label {
+ clip: rect(1px, 1px, 1px, 1px);
+ height: 1px;
+ overflow: hidden;
+ position: absolute;
+ white-space: nowrap;
+ /* added line */
+ width: 1px;
+}
+
+.mdc-data-table__progress-indicator {
+ display: none;
+ position: absolute;
+ width: 100%;
+}
+.mdc-data-table--in-progress .mdc-data-table__progress-indicator {
+ display: block;
+}
+
+.mdc-data-table__scrim {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+ height: 100%;
+ opacity: 0.32;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+
+.mdc-data-table--sticky-header .mdc-data-table__header-cell {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1;
+}
+
+.mdc-data-table__pagination {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ box-sizing: border-box;
+ display: flex;
+ justify-content: flex-end;
+}
+
+.mdc-data-table__pagination-trailing {
+ /* @noflip */
+ margin-left: 4px;
+ /* @noflip */
+ margin-right: 0;
+ align-items: center;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+}
+[dir=rtl] .mdc-data-table__pagination-trailing, .mdc-data-table__pagination-trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 4px;
+}
+
+.mdc-data-table__pagination-navigation {
+ align-items: center;
+ display: flex;
+}
+
+.mdc-data-table__pagination-button {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 4px;
+}
+[dir=rtl] .mdc-data-table__pagination-button .mdc-button__icon, .mdc-data-table__pagination-button .mdc-button__icon[dir=rtl] {
+ /* @noflip */
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+}
+
+[dir=rtl] .mdc-data-table__pagination-button, .mdc-data-table__pagination-button[dir=rtl] {
+ /* @noflip */
+ margin-left: 4px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-data-table__pagination-total {
+ /* @noflip */
+ margin-left: 14px;
+ /* @noflip */
+ margin-right: 36px;
+ white-space: nowrap;
+}
+[dir=rtl] .mdc-data-table__pagination-total, .mdc-data-table__pagination-total[dir=rtl] {
+ /* @noflip */
+ margin-left: 36px;
+ /* @noflip */
+ margin-right: 14px;
+}
+
+.mdc-data-table__pagination-rows-per-page {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 22px;
+ align-items: center;
+ display: inline-flex;
+}
+[dir=rtl] .mdc-data-table__pagination-rows-per-page, .mdc-data-table__pagination-rows-per-page[dir=rtl] {
+ /* @noflip */
+ margin-left: 22px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-data-table__pagination-rows-per-page-label {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 12px;
+ white-space: nowrap;
+}
+[dir=rtl] .mdc-data-table__pagination-rows-per-page-label, .mdc-data-table__pagination-rows-per-page-label[dir=rtl] {
+ /* @noflip */
+ margin-left: 12px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-data-table__pagination-rows-per-page-select {
+ min-width: 80px;
+ /* @alternate */
+ min-width: var(--mdc-menu-min-width, 80px);
+ margin: 8px 0;
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor {
+ width: 100%;
+ min-width: 80px;
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor {
+ height: 36px;
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-27.25px) scale(1);
+ transform: translateY(-27.25px) scale(1);
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-floating-label--float-above {
+ font-size: 0.75rem;
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-24.75px) scale(0.75);
+ transform: translateY(-24.75px) scale(0.75);
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ font-size: 1rem;
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-select-outlined-36px 250ms 1;
+ animation: mdc-floating-label-shake-float-above-select-outlined-36px 250ms 1;
+}
+@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-36px {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ }
+}
+@keyframes mdc-floating-label-shake-float-above-select-outlined-36px {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ }
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-select__dropdown-icon {
+ width: 20px;
+ height: 20px;
+}
+.mdc-data-table__pagination-rows-per-page-select.mdc-select--outlined .mdc-select__anchor :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch {
+ max-width: calc(100% - 56px);
+}
+.mdc-data-table__pagination-rows-per-page-select .mdc-deprecated-list-item {
+ height: 36px;
+}
+
+.mdc-data-table__header-row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before, .mdc-data-table__header-row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before, .mdc-data-table__header-row-checkbox.mdc-checkbox--selected.mdc-ripple-surface--hover .mdc-checkbox__ripple::before,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected.mdc-ripple-surface--hover .mdc-checkbox__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-data-table__header-row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before, .mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-data-table__header-row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded,
+.mdc-data-table__row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-data-table__header-row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,
+.mdc-data-table__header-row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after,
+.mdc-data-table__row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,
+.mdc-data-table__row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true]) ~ .mdc-checkbox__background,
+.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true]) ~ .mdc-checkbox__background {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+}
+.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:checked ~ .mdc-checkbox__background,
+.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:indeterminate ~ .mdc-checkbox__background,
+.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control[data-indeterminate=true]:enabled ~ .mdc-checkbox__background,
+.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:checked ~ .mdc-checkbox__background,
+.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:indeterminate ~ .mdc-checkbox__background,
+.mdc-data-table__row-checkbox .mdc-checkbox__native-control[data-indeterminate=true]:enabled ~ .mdc-checkbox__background {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+}
+@-webkit-keyframes mdc-checkbox-fade-in-background-8A000000FF6200EE00000000FF6200EE {
+ 0% {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+ }
+ 50% {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ }
+}
+@keyframes mdc-checkbox-fade-in-background-8A000000FF6200EE00000000FF6200EE {
+ 0% {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+ }
+ 50% {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ }
+}
+@-webkit-keyframes mdc-checkbox-fade-out-background-8A000000FF6200EE00000000FF6200EE {
+ 0%, 80% {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ }
+ 100% {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+ }
+}
+@keyframes mdc-checkbox-fade-out-background-8A000000FF6200EE00000000FF6200EE {
+ 0%, 80% {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));
+ }
+ 100% {
+ border-color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ border-color: var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));
+ background-color: transparent;
+ }
+}
+.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background, .mdc-data-table__header-row-checkbox.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background,
+.mdc-data-table__row-checkbox.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background,
+.mdc-data-table__row-checkbox.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background {
+ -webkit-animation-name: mdc-checkbox-fade-in-background-8A000000FF6200EE00000000FF6200EE;
+ animation-name: mdc-checkbox-fade-in-background-8A000000FF6200EE00000000FF6200EE;
+}
+.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background, .mdc-data-table__header-row-checkbox.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background,
+.mdc-data-table__row-checkbox.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background,
+.mdc-data-table__row-checkbox.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background {
+ -webkit-animation-name: mdc-checkbox-fade-out-background-8A000000FF6200EE00000000FF6200EE;
+ animation-name: mdc-checkbox-fade-out-background-8A000000FF6200EE00000000FF6200EE;
+}
+
+.mdc-dialog,
+.mdc-dialog__scrim {
+ position: fixed;
+ top: 0;
+ left: 0;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+}
+
+.mdc-dialog {
+ display: none;
+ z-index: 7;
+ /* @alternate */
+ z-index: var(--mdc-dialog-z-index, 7);
+}
+.mdc-dialog .mdc-dialog__surface {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+}
+.mdc-dialog .mdc-dialog__scrim {
+ background-color: rgba(0, 0, 0, 0.32);
+}
+.mdc-dialog .mdc-dialog__surface-scrim {
+ background-color: rgba(0, 0, 0, 0.32);
+}
+.mdc-dialog .mdc-dialog__title {
+ color: rgba(0, 0, 0, 0.87);
+}
+.mdc-dialog .mdc-dialog__content {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-dialog .mdc-dialog__close {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-dialog .mdc-dialog__close .mdc-icon-button__ripple::before, .mdc-dialog .mdc-dialog__close .mdc-icon-button__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000));
+}
+.mdc-dialog .mdc-dialog__close:hover .mdc-icon-button__ripple::before, .mdc-dialog .mdc-dialog__close.mdc-ripple-surface--hover .mdc-icon-button__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-dialog .mdc-dialog__close.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before, .mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-dialog .mdc-dialog__close.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__title, .mdc-dialog.mdc-dialog--scrollable .mdc-dialog__actions, .mdc-dialog.mdc-dialog--scrollable.mdc-dialog-scroll-divider-footer .mdc-dialog__actions {
+ border-color: rgba(0, 0, 0, 0.12);
+}
+.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__title {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.12);
+ margin-bottom: 0;
+}
+.mdc-dialog.mdc-dialog-scroll-divider-header.mdc-dialog--fullscreen .mdc-dialog__header {
+ /* @alternate */
+ box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
+}
+.mdc-dialog .mdc-dialog__content {
+ padding: 20px 24px 20px 24px;
+}
+.mdc-dialog .mdc-dialog__surface {
+ min-width: 280px;
+}
+@media (max-width: 592px) {
+ .mdc-dialog .mdc-dialog__surface {
+ max-width: calc(100vw - 32px);
+ }
+}
+@media (min-width: 592px) {
+ .mdc-dialog .mdc-dialog__surface {
+ max-width: 560px;
+ }
+}
+.mdc-dialog .mdc-dialog__surface {
+ max-height: calc(100% - 32px);
+}
+@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
+ .mdc-dialog .mdc-dialog__container {
+ /* stylelint-disable */
+ /* stylelint-enable*/
+ }
+}
+.mdc-dialog .mdc-dialog__surface {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-medium, 4px);
+}
+@media (max-width: 960px) and (max-height: 1440px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface {
+ max-height: 560px;
+ max-width: 560px;
+ }
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close {
+ right: -12px;
+ }
+}
+@media (max-width: 720px) and (max-height: 1023px) and (max-width: 672px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface {
+ max-width: calc(100vw - 112px);
+ }
+}
+@media (max-width: 720px) and (max-height: 1023px) and (min-width: 672px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface {
+ max-width: 560px;
+ }
+}
+@media (max-width: 720px) and (max-height: 1023px) and (max-height: 720px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface {
+ max-height: calc(100vh - 160px);
+ }
+}
+@media (max-width: 720px) and (max-height: 1023px) and (min-height: 720px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface {
+ max-height: 560px;
+ }
+}
+@media (max-width: 720px) and (max-height: 1023px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close {
+ right: -12px;
+ }
+}
+@media (max-width: 720px) and (max-height: 400px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface {
+ height: 100%;
+ max-height: 100vh;
+ max-width: 100vw;
+ width: 100%;
+ border-radius: 0;
+ }
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close {
+ order: -1;
+ left: -12px;
+ }
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__header {
+ padding: 0 16px 9px;
+ justify-content: flex-start;
+ }
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__title {
+ margin-left: calc(16px - 2 * 12px);
+ }
+}
+@media (max-width: 600px) and (max-height: 960px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface {
+ height: 100%;
+ max-height: 100vh;
+ max-width: 100vw;
+ width: 100vw;
+ border-radius: 0;
+ }
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close {
+ order: -1;
+ left: -12px;
+ }
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__header {
+ padding: 0 16px 9px;
+ justify-content: flex-start;
+ }
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__title {
+ margin-left: calc(16px - 2 * 12px);
+ }
+}
+@media (min-width: 960px) and (min-height: 1440px) {
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface {
+ max-width: calc(100vw - 400px);
+ }
+ .mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close {
+ right: -12px;
+ }
+}
+.mdc-dialog.mdc-dialog__scrim--hidden .mdc-dialog__scrim {
+ opacity: 0;
+}
+
+.mdc-dialog__scrim {
+ opacity: 0;
+ z-index: -1;
+}
+
+.mdc-dialog__container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ box-sizing: border-box;
+ height: 100%;
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0;
+ pointer-events: none;
+}
+
+.mdc-dialog__surface {
+ /* @alternate */
+ position: relative;
+ /* @alternate */
+ box-shadow: 0px 11px 15px -7px rgba(0, 0, 0, 0.2), 0px 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 9px 46px 8px rgba(0, 0, 0, 0.12);
+ display: flex;
+ flex-direction: column;
+ flex-grow: 0;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ max-width: 100%;
+ max-height: 100%;
+ pointer-events: auto;
+ overflow-y: auto;
+}
+.mdc-dialog__surface .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+[dir=rtl] .mdc-dialog__surface, .mdc-dialog__surface[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-dialog__surface {
+ outline: 2px solid windowText;
+ }
+}
+.mdc-dialog__surface::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 2px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+@media screen and (-ms-high-contrast: active), screen and (-ms-high-contrast: none) {
+ .mdc-dialog__surface::before {
+ content: none;
+ }
+}
+
+.mdc-dialog__title {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1.25rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline6-font-size, 1.25rem);
+ line-height: 2rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline6-line-height, 2rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline6-font-weight, 500);
+ letter-spacing: 0.0125em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline6-letter-spacing, 0.0125em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline6-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline6-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline6-text-transform, inherit);
+ position: relative;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ margin: 0 0 1px;
+ padding: 0 24px 9px;
+}
+.mdc-dialog__title::before {
+ display: inline-block;
+ width: 0;
+ height: 40px;
+ content: "";
+ vertical-align: 0;
+}
+[dir=rtl] .mdc-dialog__title, .mdc-dialog__title[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-dialog--scrollable .mdc-dialog__title {
+ margin-bottom: 1px;
+ padding-bottom: 15px;
+}
+
+.mdc-dialog--fullscreen .mdc-dialog__header {
+ align-items: baseline;
+ border-bottom: 1px solid transparent;
+ display: inline-flex;
+ justify-content: space-between;
+ padding: 0 24px 9px;
+ z-index: 1;
+}
+.mdc-dialog--fullscreen .mdc-dialog__header .mdc-dialog__close {
+ right: -12px;
+}
+.mdc-dialog--fullscreen .mdc-dialog__title {
+ margin-bottom: 0;
+ padding: 0;
+ border-bottom: 0;
+}
+.mdc-dialog--fullscreen.mdc-dialog--scrollable .mdc-dialog__title {
+ border-bottom: 0;
+ margin-bottom: 0;
+}
+.mdc-dialog--fullscreen .mdc-dialog__close {
+ top: 5px;
+}
+.mdc-dialog--fullscreen.mdc-dialog--scrollable .mdc-dialog__actions {
+ border-top: 1px solid transparent;
+}
+
+.mdc-dialog__content {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body1-font-size, 1rem);
+ line-height: 1.5rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body1-line-height, 1.5rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body1-font-weight, 400);
+ letter-spacing: 0.03125em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body1-letter-spacing, 0.03125em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body1-text-transform, inherit);
+ flex-grow: 1;
+ box-sizing: border-box;
+ margin: 0;
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+}
+.mdc-dialog__content > :first-child {
+ margin-top: 0;
+}
+.mdc-dialog__content > :last-child {
+ margin-bottom: 0;
+}
+
+.mdc-dialog__title + .mdc-dialog__content,
+.mdc-dialog__header + .mdc-dialog__content {
+ padding-top: 0;
+}
+
+.mdc-dialog--scrollable .mdc-dialog__title + .mdc-dialog__content {
+ padding-top: 8px;
+ padding-bottom: 8px;
+}
+
+.mdc-dialog__content .mdc-deprecated-list:first-child:last-child {
+ padding: 6px 0 0;
+}
+
+.mdc-dialog--scrollable .mdc-dialog__content .mdc-deprecated-list:first-child:last-child {
+ padding: 0;
+}
+
+.mdc-dialog__actions {
+ display: flex;
+ position: relative;
+ flex-shrink: 0;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: flex-end;
+ box-sizing: border-box;
+ min-height: 52px;
+ margin: 0;
+ padding: 8px;
+ border-top: 1px solid transparent;
+}
+.mdc-dialog--stacked .mdc-dialog__actions {
+ flex-direction: column;
+ align-items: flex-end;
+}
+
+.mdc-dialog__button {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 0;
+ max-width: 100%;
+ /* @noflip */
+ text-align: right;
+}
+[dir=rtl] .mdc-dialog__button, .mdc-dialog__button[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 8px;
+}
+
+.mdc-dialog__button:first-child {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0;
+}
+[dir=rtl] .mdc-dialog__button:first-child, .mdc-dialog__button:first-child[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0;
+}
+
+[dir=rtl] .mdc-dialog__button, .mdc-dialog__button[dir=rtl] {
+ /* @noflip */
+ text-align: left;
+}
+
+.mdc-dialog--stacked .mdc-dialog__button:not(:first-child) {
+ margin-top: 12px;
+}
+
+.mdc-dialog--open,
+.mdc-dialog--opening,
+.mdc-dialog--closing {
+ display: flex;
+}
+
+.mdc-dialog--opening .mdc-dialog__scrim {
+ transition: opacity 150ms linear;
+}
+.mdc-dialog--opening .mdc-dialog__container {
+ transition: opacity 75ms linear, -webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 75ms linear, transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 75ms linear, transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.mdc-dialog--closing .mdc-dialog__scrim,
+.mdc-dialog--closing .mdc-dialog__container {
+ transition: opacity 75ms linear;
+}
+.mdc-dialog--closing .mdc-dialog__container {
+ -webkit-transform: none;
+ transform: none;
+}
+
+.mdc-dialog--open .mdc-dialog__scrim {
+ opacity: 1;
+}
+.mdc-dialog--open .mdc-dialog__container {
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+}
+.mdc-dialog--open.mdc-dialog__surface-scrim--shown .mdc-dialog__surface-scrim {
+ opacity: 1;
+ z-index: 1;
+}
+.mdc-dialog--open.mdc-dialog__surface-scrim--hiding .mdc-dialog__surface-scrim {
+ transition: opacity 75ms linear;
+}
+.mdc-dialog--open.mdc-dialog__surface-scrim--showing .mdc-dialog__surface-scrim {
+ transition: opacity 150ms linear;
+}
+
+.mdc-dialog__surface-scrim {
+ display: none;
+ opacity: 0;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+.mdc-dialog__surface-scrim--shown .mdc-dialog__surface-scrim, .mdc-dialog__surface-scrim--showing .mdc-dialog__surface-scrim, .mdc-dialog__surface-scrim--hiding .mdc-dialog__surface-scrim {
+ display: block;
+}
+
+.mdc-dialog-scroll-lock {
+ overflow: hidden;
+}
+
+.mdc-drawer {
+ border-color: rgba(0, 0, 0, 0.12);
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+ /* @noflip */
+ border-top-left-radius: 0;
+ /* @noflip */
+ border-top-right-radius: 0;
+ /* @alternate */
+ /* @noflip */
+ border-top-right-radius: var(--mdc-shape-large, 0);
+ /* @noflip */
+ border-bottom-right-radius: 0;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-right-radius: var(--mdc-shape-large, 0);
+ /* @noflip */
+ border-bottom-left-radius: 0;
+ z-index: 6;
+ width: 256px;
+ display: flex;
+ flex-direction: column;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ height: 100%;
+ /* @noflip */
+ border-right-width: 1px;
+ /* @noflip */
+ border-right-style: solid;
+ overflow: hidden;
+ transition-property: -webkit-transform;
+ transition-property: transform;
+ transition-property: transform, -webkit-transform;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+}
+.mdc-drawer .mdc-drawer__title {
+ color: rgba(0, 0, 0, 0.87);
+}
+.mdc-drawer .mdc-deprecated-list-group__subheader {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-drawer .mdc-drawer__subtitle {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-drawer .mdc-deprecated-list-item__graphic {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-drawer .mdc-deprecated-list-item {
+ color: rgba(0, 0, 0, 0.87);
+}
+.mdc-drawer .mdc-deprecated-list-item--activated .mdc-deprecated-list-item__graphic {
+ color: #6200ee;
+}
+.mdc-drawer .mdc-deprecated-list-item--activated {
+ color: rgba(98, 0, 238, 0.87);
+}
+[dir=rtl] .mdc-drawer, .mdc-drawer[dir=rtl] {
+ /* @noflip */
+ border-top-left-radius: 0;
+ /* @alternate */
+ /* @noflip */
+ border-top-left-radius: var(--mdc-shape-large, 0);
+ /* @noflip */
+ border-top-right-radius: 0;
+ /* @noflip */
+ border-bottom-right-radius: 0;
+ /* @noflip */
+ border-bottom-left-radius: 0;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-left-radius: var(--mdc-shape-large, 0);
+}
+
+.mdc-drawer .mdc-deprecated-list-item {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+.mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing) + .mdc-drawer-app-content {
+ /* @noflip */
+ margin-left: 256px;
+ /* @noflip */
+ margin-right: 0;
+}
+[dir=rtl] .mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing) + .mdc-drawer-app-content, .mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing) + .mdc-drawer-app-content[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 256px;
+}
+
+[dir=rtl] .mdc-drawer, .mdc-drawer[dir=rtl] {
+ /* @noflip */
+ border-right-width: 0;
+ /* @noflip */
+ border-left-width: 1px;
+ /* @noflip */
+ border-right-style: none;
+ /* @noflip */
+ border-left-style: solid;
+}
+
+.mdc-drawer .mdc-deprecated-list-item {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle2-font-size, 0.875rem);
+ line-height: 1.375rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle2-line-height, 1.375rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle2-font-weight, 500);
+ letter-spacing: 0.0071428571em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle2-text-transform, inherit);
+ height: calc(48px - 2 * 4px);
+ margin: 8px 8px;
+ padding: 0 8px;
+}
+.mdc-drawer .mdc-deprecated-list-item:nth-child(1) {
+ margin-top: 2px;
+}
+.mdc-drawer .mdc-deprecated-list-item:nth-last-child(1) {
+ margin-bottom: 0;
+}
+.mdc-drawer .mdc-deprecated-list-group__subheader {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin: 0;
+ padding: 0 16px;
+}
+.mdc-drawer .mdc-deprecated-list-group__subheader::before {
+ display: inline-block;
+ width: 0;
+ height: 24px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-drawer .mdc-deprecated-list-divider {
+ margin: 3px 0 4px;
+}
+.mdc-drawer .mdc-deprecated-list-item__text,
+.mdc-drawer .mdc-deprecated-list-item__graphic {
+ pointer-events: none;
+}
+
+.mdc-drawer--animate {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+}
+[dir=rtl] .mdc-drawer--animate, .mdc-drawer--animate[dir=rtl] {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+}
+
+.mdc-drawer--opening {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ transition-duration: 250ms;
+}
+[dir=rtl] .mdc-drawer--opening, .mdc-drawer--opening[dir=rtl] {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+}
+
+.mdc-drawer--closing {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ transition-duration: 200ms;
+}
+[dir=rtl] .mdc-drawer--closing, .mdc-drawer--closing[dir=rtl] {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+}
+
+.mdc-drawer__header {
+ flex-shrink: 0;
+ box-sizing: border-box;
+ min-height: 64px;
+ padding: 0 16px 4px;
+}
+
+.mdc-drawer__title {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1.25rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline6-font-size, 1.25rem);
+ line-height: 2rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline6-line-height, 2rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline6-font-weight, 500);
+ letter-spacing: 0.0125em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline6-letter-spacing, 0.0125em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline6-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline6-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline6-text-transform, inherit);
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-drawer__title::before {
+ display: inline-block;
+ width: 0;
+ height: 36px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-drawer__title::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+
+.mdc-drawer__subtitle {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: 0;
+}
+.mdc-drawer__subtitle::before {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: 0;
+}
+
+.mdc-drawer__content {
+ height: 100%;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.mdc-drawer--dismissible {
+ /* @noflip */
+ left: 0;
+ /* @noflip */
+ right: initial;
+ display: none;
+ position: absolute;
+}
+[dir=rtl] .mdc-drawer--dismissible, .mdc-drawer--dismissible[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 0;
+}
+
+.mdc-drawer--dismissible.mdc-drawer--open {
+ display: flex;
+}
+
+.mdc-drawer-app-content {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0;
+ position: relative;
+}
+[dir=rtl] .mdc-drawer-app-content, .mdc-drawer-app-content[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-drawer--modal {
+ /* @alternate */
+ box-shadow: 0px 8px 10px -5px rgba(0, 0, 0, 0.2), 0px 16px 24px 2px rgba(0, 0, 0, 0.14), 0px 6px 30px 5px rgba(0, 0, 0, 0.12);
+ /* @noflip */
+ left: 0;
+ /* @noflip */
+ right: initial;
+ display: none;
+ position: fixed;
+}
+.mdc-drawer--modal + .mdc-drawer-scrim {
+ background-color: rgba(0, 0, 0, 0.32);
+}
+[dir=rtl] .mdc-drawer--modal, .mdc-drawer--modal[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 0;
+}
+
+.mdc-drawer--modal.mdc-drawer--open {
+ display: flex;
+}
+
+.mdc-drawer-scrim {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 5;
+ transition-property: opacity;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+}
+.mdc-drawer--open + .mdc-drawer-scrim {
+ display: block;
+}
+.mdc-drawer--animate + .mdc-drawer-scrim {
+ opacity: 0;
+}
+.mdc-drawer--opening + .mdc-drawer-scrim {
+ transition-duration: 250ms;
+ opacity: 1;
+}
+.mdc-drawer--closing + .mdc-drawer-scrim {
+ transition-duration: 200ms;
+ opacity: 0;
+}
+
+.mdc-elevation--z0 {
+ /* @alternate */
+ box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0.2), 0px 0px 0px 0px rgba(0, 0, 0, 0.14), 0px 0px 0px 0px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z1 {
+ /* @alternate */
+ box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z2 {
+ /* @alternate */
+ box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z3 {
+ /* @alternate */
+ box-shadow: 0px 3px 3px -2px rgba(0, 0, 0, 0.2), 0px 3px 4px 0px rgba(0, 0, 0, 0.14), 0px 1px 8px 0px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z4 {
+ /* @alternate */
+ box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z5 {
+ /* @alternate */
+ box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 5px 8px 0px rgba(0, 0, 0, 0.14), 0px 1px 14px 0px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z6 {
+ /* @alternate */
+ box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z7 {
+ /* @alternate */
+ box-shadow: 0px 4px 5px -2px rgba(0, 0, 0, 0.2), 0px 7px 10px 1px rgba(0, 0, 0, 0.14), 0px 2px 16px 1px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z8 {
+ /* @alternate */
+ box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z9 {
+ /* @alternate */
+ box-shadow: 0px 5px 6px -3px rgba(0, 0, 0, 0.2), 0px 9px 12px 1px rgba(0, 0, 0, 0.14), 0px 3px 16px 2px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z10 {
+ /* @alternate */
+ box-shadow: 0px 6px 6px -3px rgba(0, 0, 0, 0.2), 0px 10px 14px 1px rgba(0, 0, 0, 0.14), 0px 4px 18px 3px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z11 {
+ /* @alternate */
+ box-shadow: 0px 6px 7px -4px rgba(0, 0, 0, 0.2), 0px 11px 15px 1px rgba(0, 0, 0, 0.14), 0px 4px 20px 3px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z12 {
+ /* @alternate */
+ box-shadow: 0px 7px 8px -4px rgba(0, 0, 0, 0.2), 0px 12px 17px 2px rgba(0, 0, 0, 0.14), 0px 5px 22px 4px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z13 {
+ /* @alternate */
+ box-shadow: 0px 7px 8px -4px rgba(0, 0, 0, 0.2), 0px 13px 19px 2px rgba(0, 0, 0, 0.14), 0px 5px 24px 4px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z14 {
+ /* @alternate */
+ box-shadow: 0px 7px 9px -4px rgba(0, 0, 0, 0.2), 0px 14px 21px 2px rgba(0, 0, 0, 0.14), 0px 5px 26px 4px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z15 {
+ /* @alternate */
+ box-shadow: 0px 8px 9px -5px rgba(0, 0, 0, 0.2), 0px 15px 22px 2px rgba(0, 0, 0, 0.14), 0px 6px 28px 5px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z16 {
+ /* @alternate */
+ box-shadow: 0px 8px 10px -5px rgba(0, 0, 0, 0.2), 0px 16px 24px 2px rgba(0, 0, 0, 0.14), 0px 6px 30px 5px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z17 {
+ /* @alternate */
+ box-shadow: 0px 8px 11px -5px rgba(0, 0, 0, 0.2), 0px 17px 26px 2px rgba(0, 0, 0, 0.14), 0px 6px 32px 5px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z18 {
+ /* @alternate */
+ box-shadow: 0px 9px 11px -5px rgba(0, 0, 0, 0.2), 0px 18px 28px 2px rgba(0, 0, 0, 0.14), 0px 7px 34px 6px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z19 {
+ /* @alternate */
+ box-shadow: 0px 9px 12px -6px rgba(0, 0, 0, 0.2), 0px 19px 29px 2px rgba(0, 0, 0, 0.14), 0px 7px 36px 6px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z20 {
+ /* @alternate */
+ box-shadow: 0px 10px 13px -6px rgba(0, 0, 0, 0.2), 0px 20px 31px 3px rgba(0, 0, 0, 0.14), 0px 8px 38px 7px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z21 {
+ /* @alternate */
+ box-shadow: 0px 10px 13px -6px rgba(0, 0, 0, 0.2), 0px 21px 33px 3px rgba(0, 0, 0, 0.14), 0px 8px 40px 7px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z22 {
+ /* @alternate */
+ box-shadow: 0px 10px 14px -6px rgba(0, 0, 0, 0.2), 0px 22px 35px 3px rgba(0, 0, 0, 0.14), 0px 8px 42px 7px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z23 {
+ /* @alternate */
+ box-shadow: 0px 11px 14px -7px rgba(0, 0, 0, 0.2), 0px 23px 36px 3px rgba(0, 0, 0, 0.14), 0px 9px 44px 8px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation--z24 {
+ /* @alternate */
+ box-shadow: 0px 11px 15px -7px rgba(0, 0, 0, 0.2), 0px 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 9px 46px 8px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-elevation-transition {
+ transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
+ will-change: box-shadow;
+}
+
+.mdc-fab {
+ /* @alternate */
+ position: relative;
+ display: inline-flex;
+ position: relative;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ width: 56px;
+ height: 56px;
+ padding: 0;
+ border: none;
+ fill: currentColor;
+ text-decoration: none;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -moz-appearance: none;
+ -webkit-appearance: none;
+ overflow: visible;
+ transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1), opacity 15ms linear 30ms, -webkit-transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1), opacity 15ms linear 30ms, transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1), opacity 15ms linear 30ms, transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+.mdc-fab .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.mdc-fab::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+.mdc-fab:hover {
+ /* @alternate */
+ box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12);
+}
+.mdc-fab.mdc-ripple-upgraded--background-focused, .mdc-fab:not(.mdc-ripple-upgraded):focus {
+ /* @alternate */
+ box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12);
+}
+.mdc-fab:active, .mdc-fab:focus:active {
+ /* @alternate */
+ box-shadow: 0px 7px 8px -4px rgba(0, 0, 0, 0.2), 0px 12px 17px 2px rgba(0, 0, 0, 0.14), 0px 5px 22px 4px rgba(0, 0, 0, 0.12);
+}
+.mdc-fab:active, .mdc-fab:focus {
+ outline: none;
+}
+.mdc-fab:hover {
+ cursor: pointer;
+}
+.mdc-fab > svg {
+ width: 100%;
+}
+
+.mdc-fab--mini {
+ width: 40px;
+ height: 40px;
+}
+
+.mdc-fab--extended {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-button-font-size, 0.875rem);
+ line-height: 2.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-button-line-height, 2.25rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-button-font-weight, 500);
+ letter-spacing: 0.0892857143em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-button-letter-spacing, 0.0892857143em);
+ text-decoration: none;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-button-text-transform, uppercase);
+ border-radius: 24px;
+ /* @noflip */
+ padding-left: 20px;
+ /* @noflip */
+ padding-right: 20px;
+ width: auto;
+ max-width: 100%;
+ height: 48px;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-fab--extended .mdc-fab__ripple {
+ border-radius: 24px;
+}
+.mdc-fab--extended .mdc-fab__icon {
+ /* @noflip */
+ margin-left: calc(12px - 20px);
+ /* @noflip */
+ margin-right: 12px;
+}
+[dir=rtl] .mdc-fab--extended .mdc-fab__icon, .mdc-fab--extended .mdc-fab__icon[dir=rtl] {
+ /* @noflip */
+ margin-left: 12px;
+ /* @noflip */
+ margin-right: calc(12px - 20px);
+}
+
+.mdc-fab--extended .mdc-fab__label + .mdc-fab__icon {
+ /* @noflip */
+ margin-left: 12px;
+ /* @noflip */
+ margin-right: calc(12px - 20px);
+}
+[dir=rtl] .mdc-fab--extended .mdc-fab__label + .mdc-fab__icon, .mdc-fab--extended .mdc-fab__label + .mdc-fab__icon[dir=rtl] {
+ /* @noflip */
+ margin-left: calc(12px - 20px);
+ /* @noflip */
+ margin-right: 12px;
+}
+
+.mdc-fab--touch {
+ margin-top: 4px;
+ margin-bottom: 4px;
+ margin-right: 4px;
+ margin-left: 4px;
+}
+.mdc-fab--touch .mdc-fab__touch {
+ position: absolute;
+ top: 50%;
+ height: 48px;
+ /* @noflip */
+ left: 50%;
+ width: 48px;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.mdc-fab::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 1px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+
+.mdc-fab__label {
+ justify-content: flex-start;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow-x: hidden;
+ overflow-y: visible;
+}
+
+.mdc-fab__icon {
+ transition: -webkit-transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);
+ transition: transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);
+ transition: transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);
+ fill: currentColor;
+ will-change: transform;
+}
+
+.mdc-fab .mdc-fab__icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.mdc-fab--exited {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ opacity: 0;
+ transition: opacity 15ms linear 150ms, -webkit-transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1);
+ transition: opacity 15ms linear 150ms, transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1);
+ transition: opacity 15ms linear 150ms, transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1), -webkit-transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1);
+}
+.mdc-fab--exited .mdc-fab__icon {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ transition: -webkit-transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1);
+ transition: transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1);
+ transition: transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1), -webkit-transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1);
+}
+
+.mdc-fab {
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-theme-secondary, #018786);
+ /* @alternate */
+ box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12);
+}
+.mdc-fab .mdc-fab__icon {
+ width: 24px;
+ height: 24px;
+ font-size: 24px;
+}
+.mdc-fab, .mdc-fab:not(:disabled) .mdc-fab__icon, .mdc-fab:not(:disabled) .mdc-fab__label, .mdc-fab:disabled .mdc-fab__icon, .mdc-fab:disabled .mdc-fab__label {
+ color: #fff;
+ /* @alternate */
+ color: var(--mdc-theme-on-secondary, #fff);
+}
+.mdc-fab:not(.mdc-fab--extended) {
+ border-radius: 50%;
+}
+.mdc-fab:not(.mdc-fab--extended) .mdc-fab__ripple {
+ border-radius: 50%;
+}
+
+.mdc-fab {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-fab .mdc-fab__ripple::before,
+.mdc-fab .mdc-fab__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-fab .mdc-fab__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-fab .mdc-fab__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-fab.mdc-ripple-upgraded--unbounded .mdc-fab__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-fab.mdc-ripple-upgraded--foreground-activation .mdc-fab__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-fab.mdc-ripple-upgraded--foreground-deactivation .mdc-fab__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-fab .mdc-fab__ripple::before,
+.mdc-fab .mdc-fab__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-fab .mdc-fab__ripple::before, .mdc-fab .mdc-fab__ripple::after {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-on-secondary, #fff));
+}
+.mdc-fab:hover .mdc-fab__ripple::before, .mdc-fab.mdc-ripple-surface--hover .mdc-fab__ripple::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.08);
+}
+.mdc-fab.mdc-ripple-upgraded--background-focused .mdc-fab__ripple::before, .mdc-fab:not(.mdc-ripple-upgraded):focus .mdc-fab__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+.mdc-fab:not(.mdc-ripple-upgraded) .mdc-fab__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-fab:not(.mdc-ripple-upgraded):active .mdc-fab__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-fab.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-fab .mdc-fab__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ overflow: hidden;
+}
+.mdc-fab {
+ z-index: 0;
+}
+.mdc-fab .mdc-fab__ripple::before,
+.mdc-fab .mdc-fab__ripple::after {
+ z-index: -1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, -1);
+}
+
+.mdc-form-field {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));
+ display: inline-flex;
+ align-items: center;
+ vertical-align: middle;
+}
+.mdc-form-field > label {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: auto;
+ /* @noflip */
+ padding-left: 4px;
+ /* @noflip */
+ padding-right: 0;
+ order: 0;
+}
+[dir=rtl] .mdc-form-field > label, .mdc-form-field > label[dir=rtl] {
+ /* @noflip */
+ margin-left: auto;
+ /* @noflip */
+ margin-right: 0;
+}
+
+[dir=rtl] .mdc-form-field > label, .mdc-form-field > label[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 4px;
+}
+
+.mdc-form-field--nowrap > label {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+.mdc-form-field--align-end > label {
+ /* @noflip */
+ margin-left: auto;
+ /* @noflip */
+ margin-right: 0;
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 4px;
+ order: -1;
+}
+[dir=rtl] .mdc-form-field--align-end > label, .mdc-form-field--align-end > label[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: auto;
+}
+
+[dir=rtl] .mdc-form-field--align-end > label, .mdc-form-field--align-end > label[dir=rtl] {
+ /* @noflip */
+ padding-left: 4px;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-form-field--space-between {
+ justify-content: space-between;
+}
+.mdc-form-field--space-between > label {
+ margin: 0;
+}
+[dir=rtl] .mdc-form-field--space-between > label, .mdc-form-field--space-between > label[dir=rtl] {
+ margin: 0;
+}
+
+.mdc-icon-button {
+ display: inline-block;
+ position: relative;
+ box-sizing: border-box;
+ border: none;
+ outline: none;
+ background-color: transparent;
+ fill: currentColor;
+ color: inherit;
+ font-size: 24px;
+ text-decoration: none;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ width: 48px;
+ height: 48px;
+ padding: 12px;
+}
+.mdc-icon-button svg,
+.mdc-icon-button img {
+ width: 24px;
+ height: 24px;
+}
+.mdc-icon-button:disabled {
+ color: rgba(0, 0, 0, 0.38);
+ /* @alternate */
+ color: var(--mdc-theme-text-disabled-on-light, rgba(0, 0, 0, 0.38));
+}
+.mdc-icon-button:disabled {
+ cursor: default;
+ pointer-events: none;
+}
+.mdc-icon-button .mdc-icon-button__touch {
+ position: absolute;
+ top: 50%;
+ height: 48px;
+ /* @noflip */
+ left: 50%;
+ width: 48px;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.mdc-icon-button__icon {
+ display: inline-block;
+}
+.mdc-icon-button__icon.mdc-icon-button__icon--on {
+ display: none;
+}
+
+.mdc-icon-button--on .mdc-icon-button__icon {
+ display: none;
+}
+.mdc-icon-button--on .mdc-icon-button__icon.mdc-icon-button__icon--on {
+ display: inline-block;
+}
+
+.mdc-icon-button--touch {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+.mdc-icon-button {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-icon-button .mdc-icon-button__ripple::before,
+.mdc-icon-button .mdc-icon-button__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-icon-button .mdc-icon-button__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-icon-button .mdc-icon-button__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-icon-button.mdc-ripple-upgraded--unbounded .mdc-icon-button__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-icon-button.mdc-ripple-upgraded--foreground-activation .mdc-icon-button__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-icon-button.mdc-ripple-upgraded--foreground-deactivation .mdc-icon-button__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-icon-button .mdc-icon-button__ripple::before,
+.mdc-icon-button .mdc-icon-button__ripple::after {
+ top: calc(50% - 50%);
+ /* @noflip */
+ left: calc(50% - 50%);
+ width: 100%;
+ height: 100%;
+}
+.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::before,
+.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::after {
+ top: var(--mdc-ripple-top, calc(50% - 50%));
+ /* @noflip */
+ left: var(--mdc-ripple-left, calc(50% - 50%));
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-icon-button .mdc-icon-button__ripple::before, .mdc-icon-button .mdc-icon-button__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+.mdc-icon-button:hover .mdc-icon-button__ripple::before, .mdc-icon-button.mdc-ripple-surface--hover .mdc-icon-button__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before, .mdc-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-icon-button:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-icon-button:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-icon-button.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-icon-button .mdc-icon-button__ripple {
+ pointer-events: none;
+ z-index: 1;
+}
+
+.mdc-image-list {
+ display: flex;
+ flex-wrap: wrap;
+ margin: 0 auto;
+ padding: 0;
+}
+
+.mdc-image-list__item,
+.mdc-image-list__image-aspect-container {
+ position: relative;
+ box-sizing: border-box;
+}
+
+.mdc-image-list__item {
+ list-style-type: none;
+}
+
+.mdc-image-list__image {
+ width: 100%;
+}
+
+.mdc-image-list__image-aspect-container .mdc-image-list__image {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: 100%;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover;
+}
+
+.mdc-image-list__image-aspect-container {
+ padding-bottom: calc(100% / 1);
+}
+
+.mdc-image-list__image {
+ border-radius: 0;
+}
+
+.mdc-image-list--with-text-protection .mdc-image-list__supporting {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.mdc-image-list__supporting {
+ color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ box-sizing: border-box;
+ padding: 8px 0;
+ line-height: 24px;
+}
+
+.mdc-image-list__label {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ line-height: 1.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle1-line-height, 1.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.mdc-image-list--with-text-protection .mdc-image-list__supporting {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ height: 48px;
+ padding: 0 16px;
+ background: rgba(0, 0, 0, 0.6);
+ color: #fff;
+}
+
+.mdc-image-list--masonry {
+ display: block;
+}
+.mdc-image-list--masonry .mdc-image-list__item {
+ -webkit-column-break-inside: avoid;
+ break-inside: avoid-column;
+}
+.mdc-image-list--masonry .mdc-image-list__image {
+ display: block;
+ height: auto;
+}
+
+:root {
+ --mdc-layout-grid-margin-desktop: 24px;
+ --mdc-layout-grid-gutter-desktop: 24px;
+ --mdc-layout-grid-column-width-desktop: 72px;
+ --mdc-layout-grid-margin-tablet: 16px;
+ --mdc-layout-grid-gutter-tablet: 16px;
+ --mdc-layout-grid-column-width-tablet: 72px;
+ --mdc-layout-grid-margin-phone: 16px;
+ --mdc-layout-grid-gutter-phone: 16px;
+ --mdc-layout-grid-column-width-phone: 72px;
+}
+
+@media (min-width: 840px) {
+ .mdc-layout-grid {
+ box-sizing: border-box;
+ margin: 0 auto;
+ padding: 24px;
+ padding: var(--mdc-layout-grid-margin-desktop, 24px);
+ }
+}
+@media (min-width: 600px) and (max-width: 839px) {
+ .mdc-layout-grid {
+ box-sizing: border-box;
+ margin: 0 auto;
+ padding: 16px;
+ padding: var(--mdc-layout-grid-margin-tablet, 16px);
+ }
+}
+@media (max-width: 599px) {
+ .mdc-layout-grid {
+ box-sizing: border-box;
+ margin: 0 auto;
+ padding: 16px;
+ padding: var(--mdc-layout-grid-margin-phone, 16px);
+ }
+}
+
+@media (min-width: 840px) {
+ .mdc-layout-grid__inner {
+ display: flex;
+ flex-flow: row wrap;
+ align-items: stretch;
+ margin: -12px;
+ margin: calc(var(--mdc-layout-grid-gutter-desktop, 24px) / 2 * -1);
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__inner {
+ display: grid;
+ margin: 0;
+ grid-gap: 24px;
+ grid-gap: var(--mdc-layout-grid-gutter-desktop, 24px);
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+ }
+}
+@media (min-width: 600px) and (max-width: 839px) {
+ .mdc-layout-grid__inner {
+ display: flex;
+ flex-flow: row wrap;
+ align-items: stretch;
+ margin: -8px;
+ margin: calc(var(--mdc-layout-grid-gutter-tablet, 16px) / 2 * -1);
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__inner {
+ display: grid;
+ margin: 0;
+ grid-gap: 16px;
+ grid-gap: var(--mdc-layout-grid-gutter-tablet, 16px);
+ grid-template-columns: repeat(8, minmax(0, 1fr));
+ }
+ }
+}
+@media (max-width: 599px) {
+ .mdc-layout-grid__inner {
+ display: flex;
+ flex-flow: row wrap;
+ align-items: stretch;
+ margin: -8px;
+ margin: calc(var(--mdc-layout-grid-gutter-phone, 16px) / 2 * -1);
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__inner {
+ display: grid;
+ margin: 0;
+ grid-gap: 16px;
+ grid-gap: var(--mdc-layout-grid-gutter-phone, 16px);
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+ }
+}
+
+@media (min-width: 840px) {
+ .mdc-layout-grid__cell {
+ width: calc(33.3333333333% - 24px);
+ width: calc(33.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ box-sizing: border-box;
+ margin: 12px;
+ margin: calc(var(--mdc-layout-grid-gutter-desktop, 24px) / 2);
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell {
+ margin: 0;
+ }
+ }
+ .mdc-layout-grid__cell--span-1,
+.mdc-layout-grid__cell--span-1-desktop {
+ width: calc(8.3333333333% - 24px);
+ width: calc(8.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-1,
+.mdc-layout-grid__cell--span-1-desktop {
+ width: auto;
+ grid-column-end: span 1;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-2,
+.mdc-layout-grid__cell--span-2-desktop {
+ width: calc(16.6666666667% - 24px);
+ width: calc(16.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-2,
+.mdc-layout-grid__cell--span-2-desktop {
+ width: auto;
+ grid-column-end: span 2;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-3,
+.mdc-layout-grid__cell--span-3-desktop {
+ width: calc(25% - 24px);
+ width: calc(25% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-3,
+.mdc-layout-grid__cell--span-3-desktop {
+ width: auto;
+ grid-column-end: span 3;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-4,
+.mdc-layout-grid__cell--span-4-desktop {
+ width: calc(33.3333333333% - 24px);
+ width: calc(33.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-4,
+.mdc-layout-grid__cell--span-4-desktop {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-5,
+.mdc-layout-grid__cell--span-5-desktop {
+ width: calc(41.6666666667% - 24px);
+ width: calc(41.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-5,
+.mdc-layout-grid__cell--span-5-desktop {
+ width: auto;
+ grid-column-end: span 5;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-6,
+.mdc-layout-grid__cell--span-6-desktop {
+ width: calc(50% - 24px);
+ width: calc(50% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-6,
+.mdc-layout-grid__cell--span-6-desktop {
+ width: auto;
+ grid-column-end: span 6;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-7,
+.mdc-layout-grid__cell--span-7-desktop {
+ width: calc(58.3333333333% - 24px);
+ width: calc(58.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-7,
+.mdc-layout-grid__cell--span-7-desktop {
+ width: auto;
+ grid-column-end: span 7;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-8,
+.mdc-layout-grid__cell--span-8-desktop {
+ width: calc(66.6666666667% - 24px);
+ width: calc(66.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-8,
+.mdc-layout-grid__cell--span-8-desktop {
+ width: auto;
+ grid-column-end: span 8;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-9,
+.mdc-layout-grid__cell--span-9-desktop {
+ width: calc(75% - 24px);
+ width: calc(75% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-9,
+.mdc-layout-grid__cell--span-9-desktop {
+ width: auto;
+ grid-column-end: span 9;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-10,
+.mdc-layout-grid__cell--span-10-desktop {
+ width: calc(83.3333333333% - 24px);
+ width: calc(83.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-10,
+.mdc-layout-grid__cell--span-10-desktop {
+ width: auto;
+ grid-column-end: span 10;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-11,
+.mdc-layout-grid__cell--span-11-desktop {
+ width: calc(91.6666666667% - 24px);
+ width: calc(91.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-11,
+.mdc-layout-grid__cell--span-11-desktop {
+ width: auto;
+ grid-column-end: span 11;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-12,
+.mdc-layout-grid__cell--span-12-desktop {
+ width: calc(100% - 24px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-desktop, 24px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-12,
+.mdc-layout-grid__cell--span-12-desktop {
+ width: auto;
+ grid-column-end: span 12;
+ }
+ }
+}
+@media (min-width: 600px) and (max-width: 839px) {
+ .mdc-layout-grid__cell {
+ width: calc(50% - 16px);
+ width: calc(50% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ box-sizing: border-box;
+ margin: 8px;
+ margin: calc(var(--mdc-layout-grid-gutter-tablet, 16px) / 2);
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell {
+ margin: 0;
+ }
+ }
+ .mdc-layout-grid__cell--span-1,
+.mdc-layout-grid__cell--span-1-tablet {
+ width: calc(12.5% - 16px);
+ width: calc(12.5% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-1,
+.mdc-layout-grid__cell--span-1-tablet {
+ width: auto;
+ grid-column-end: span 1;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-2,
+.mdc-layout-grid__cell--span-2-tablet {
+ width: calc(25% - 16px);
+ width: calc(25% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-2,
+.mdc-layout-grid__cell--span-2-tablet {
+ width: auto;
+ grid-column-end: span 2;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-3,
+.mdc-layout-grid__cell--span-3-tablet {
+ width: calc(37.5% - 16px);
+ width: calc(37.5% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-3,
+.mdc-layout-grid__cell--span-3-tablet {
+ width: auto;
+ grid-column-end: span 3;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-4,
+.mdc-layout-grid__cell--span-4-tablet {
+ width: calc(50% - 16px);
+ width: calc(50% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-4,
+.mdc-layout-grid__cell--span-4-tablet {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-5,
+.mdc-layout-grid__cell--span-5-tablet {
+ width: calc(62.5% - 16px);
+ width: calc(62.5% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-5,
+.mdc-layout-grid__cell--span-5-tablet {
+ width: auto;
+ grid-column-end: span 5;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-6,
+.mdc-layout-grid__cell--span-6-tablet {
+ width: calc(75% - 16px);
+ width: calc(75% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-6,
+.mdc-layout-grid__cell--span-6-tablet {
+ width: auto;
+ grid-column-end: span 6;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-7,
+.mdc-layout-grid__cell--span-7-tablet {
+ width: calc(87.5% - 16px);
+ width: calc(87.5% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-7,
+.mdc-layout-grid__cell--span-7-tablet {
+ width: auto;
+ grid-column-end: span 7;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-8,
+.mdc-layout-grid__cell--span-8-tablet {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-8,
+.mdc-layout-grid__cell--span-8-tablet {
+ width: auto;
+ grid-column-end: span 8;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-9,
+.mdc-layout-grid__cell--span-9-tablet {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-9,
+.mdc-layout-grid__cell--span-9-tablet {
+ width: auto;
+ grid-column-end: span 8;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-10,
+.mdc-layout-grid__cell--span-10-tablet {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-10,
+.mdc-layout-grid__cell--span-10-tablet {
+ width: auto;
+ grid-column-end: span 8;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-11,
+.mdc-layout-grid__cell--span-11-tablet {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-11,
+.mdc-layout-grid__cell--span-11-tablet {
+ width: auto;
+ grid-column-end: span 8;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-12,
+.mdc-layout-grid__cell--span-12-tablet {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-12,
+.mdc-layout-grid__cell--span-12-tablet {
+ width: auto;
+ grid-column-end: span 8;
+ }
+ }
+}
+@media (max-width: 599px) {
+ .mdc-layout-grid__cell {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ box-sizing: border-box;
+ margin: 8px;
+ margin: calc(var(--mdc-layout-grid-gutter-phone, 16px) / 2);
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell {
+ margin: 0;
+ }
+ }
+ .mdc-layout-grid__cell--span-1,
+.mdc-layout-grid__cell--span-1-phone {
+ width: calc(25% - 16px);
+ width: calc(25% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-1,
+.mdc-layout-grid__cell--span-1-phone {
+ width: auto;
+ grid-column-end: span 1;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-2,
+.mdc-layout-grid__cell--span-2-phone {
+ width: calc(50% - 16px);
+ width: calc(50% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-2,
+.mdc-layout-grid__cell--span-2-phone {
+ width: auto;
+ grid-column-end: span 2;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-3,
+.mdc-layout-grid__cell--span-3-phone {
+ width: calc(75% - 16px);
+ width: calc(75% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-3,
+.mdc-layout-grid__cell--span-3-phone {
+ width: auto;
+ grid-column-end: span 3;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-4,
+.mdc-layout-grid__cell--span-4-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-4,
+.mdc-layout-grid__cell--span-4-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-5,
+.mdc-layout-grid__cell--span-5-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-5,
+.mdc-layout-grid__cell--span-5-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-6,
+.mdc-layout-grid__cell--span-6-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-6,
+.mdc-layout-grid__cell--span-6-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-7,
+.mdc-layout-grid__cell--span-7-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-7,
+.mdc-layout-grid__cell--span-7-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-8,
+.mdc-layout-grid__cell--span-8-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-8,
+.mdc-layout-grid__cell--span-8-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-9,
+.mdc-layout-grid__cell--span-9-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-9,
+.mdc-layout-grid__cell--span-9-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-10,
+.mdc-layout-grid__cell--span-10-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-10,
+.mdc-layout-grid__cell--span-10-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-11,
+.mdc-layout-grid__cell--span-11-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-11,
+.mdc-layout-grid__cell--span-11-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+
+ .mdc-layout-grid__cell--span-12,
+.mdc-layout-grid__cell--span-12-phone {
+ width: calc(100% - 16px);
+ width: calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));
+ }
+ @supports (display: grid) {
+ .mdc-layout-grid__cell--span-12,
+.mdc-layout-grid__cell--span-12-phone {
+ width: auto;
+ grid-column-end: span 4;
+ }
+ }
+}
+.mdc-layout-grid__cell--order-1 {
+ order: 1;
+}
+.mdc-layout-grid__cell--order-2 {
+ order: 2;
+}
+.mdc-layout-grid__cell--order-3 {
+ order: 3;
+}
+.mdc-layout-grid__cell--order-4 {
+ order: 4;
+}
+.mdc-layout-grid__cell--order-5 {
+ order: 5;
+}
+.mdc-layout-grid__cell--order-6 {
+ order: 6;
+}
+.mdc-layout-grid__cell--order-7 {
+ order: 7;
+}
+.mdc-layout-grid__cell--order-8 {
+ order: 8;
+}
+.mdc-layout-grid__cell--order-9 {
+ order: 9;
+}
+.mdc-layout-grid__cell--order-10 {
+ order: 10;
+}
+.mdc-layout-grid__cell--order-11 {
+ order: 11;
+}
+.mdc-layout-grid__cell--order-12 {
+ order: 12;
+}
+.mdc-layout-grid__cell--align-top {
+ align-self: flex-start;
+}
+@supports (display: grid) {
+ .mdc-layout-grid__cell--align-top {
+ align-self: start;
+ }
+}
+.mdc-layout-grid__cell--align-middle {
+ align-self: center;
+}
+.mdc-layout-grid__cell--align-bottom {
+ align-self: flex-end;
+}
+@supports (display: grid) {
+ .mdc-layout-grid__cell--align-bottom {
+ align-self: end;
+ }
+}
+
+@media (min-width: 840px) {
+ .mdc-layout-grid--fixed-column-width {
+ width: 1176px;
+ width: calc( var(--mdc-layout-grid-column-width-desktop, 72px) * 12 + var(--mdc-layout-grid-gutter-desktop, 24px) * 11 + var(--mdc-layout-grid-margin-desktop, 24px) * 2 );
+ }
+}
+@media (min-width: 600px) and (max-width: 839px) {
+ .mdc-layout-grid--fixed-column-width {
+ width: 720px;
+ width: calc( var(--mdc-layout-grid-column-width-tablet, 72px) * 8 + var(--mdc-layout-grid-gutter-tablet, 16px) * 7 + var(--mdc-layout-grid-margin-tablet, 16px) * 2 );
+ }
+}
+@media (max-width: 599px) {
+ .mdc-layout-grid--fixed-column-width {
+ width: 368px;
+ width: calc( var(--mdc-layout-grid-column-width-phone, 72px) * 4 + var(--mdc-layout-grid-gutter-phone, 16px) * 3 + var(--mdc-layout-grid-margin-phone, 16px) * 2 );
+ }
+}
+
+.mdc-layout-grid--align-left {
+ margin-right: auto;
+ margin-left: 0;
+}
+
+.mdc-layout-grid--align-right {
+ margin-right: 0;
+ margin-left: auto;
+}
+
+@-webkit-keyframes mdc-linear-progress-primary-indeterminate-translate {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 20% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 59.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(83.67142%);
+ transform: translateX(83.67142%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-primary-half, 83.67142%));
+ transform: translateX(var(--mdc-linear-progress-primary-half, 83.67142%));
+ }
+ 100% {
+ -webkit-transform: translateX(200.611057%);
+ transform: translateX(200.611057%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-primary-full, 200.611057%));
+ transform: translateX(var(--mdc-linear-progress-primary-full, 200.611057%));
+ }
+}
+
+@keyframes mdc-linear-progress-primary-indeterminate-translate {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 20% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 59.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(83.67142%);
+ transform: translateX(83.67142%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-primary-half, 83.67142%));
+ transform: translateX(var(--mdc-linear-progress-primary-half, 83.67142%));
+ }
+ 100% {
+ -webkit-transform: translateX(200.611057%);
+ transform: translateX(200.611057%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-primary-full, 200.611057%));
+ transform: translateX(var(--mdc-linear-progress-primary-full, 200.611057%));
+ }
+}
+@-webkit-keyframes mdc-linear-progress-primary-indeterminate-scale {
+ 0% {
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+ 36.65% {
+ -webkit-animation-timing-function: cubic-bezier(0.334731, 0.12482, 0.785844, 1);
+ animation-timing-function: cubic-bezier(0.334731, 0.12482, 0.785844, 1);
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+ 69.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.06, 0.11, 0.6, 1);
+ animation-timing-function: cubic-bezier(0.06, 0.11, 0.6, 1);
+ -webkit-transform: scaleX(0.661479);
+ transform: scaleX(0.661479);
+ }
+ 100% {
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+}
+@keyframes mdc-linear-progress-primary-indeterminate-scale {
+ 0% {
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+ 36.65% {
+ -webkit-animation-timing-function: cubic-bezier(0.334731, 0.12482, 0.785844, 1);
+ animation-timing-function: cubic-bezier(0.334731, 0.12482, 0.785844, 1);
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+ 69.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.06, 0.11, 0.6, 1);
+ animation-timing-function: cubic-bezier(0.06, 0.11, 0.6, 1);
+ -webkit-transform: scaleX(0.661479);
+ transform: scaleX(0.661479);
+ }
+ 100% {
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+}
+@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-translate {
+ 0% {
+ -webkit-animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685);
+ animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685);
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 25% {
+ -webkit-animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);
+ animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);
+ -webkit-transform: translateX(37.651913%);
+ transform: translateX(37.651913%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%));
+ transform: translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%));
+ }
+ 48.35% {
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026);
+ animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026);
+ -webkit-transform: translateX(84.386165%);
+ transform: translateX(84.386165%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-half, 84.386165%));
+ transform: translateX(var(--mdc-linear-progress-secondary-half, 84.386165%));
+ }
+ 100% {
+ -webkit-transform: translateX(160.277782%);
+ transform: translateX(160.277782%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-full, 160.277782%));
+ transform: translateX(var(--mdc-linear-progress-secondary-full, 160.277782%));
+ }
+}
+@keyframes mdc-linear-progress-secondary-indeterminate-translate {
+ 0% {
+ -webkit-animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685);
+ animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685);
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 25% {
+ -webkit-animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);
+ animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);
+ -webkit-transform: translateX(37.651913%);
+ transform: translateX(37.651913%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%));
+ transform: translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%));
+ }
+ 48.35% {
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026);
+ animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026);
+ -webkit-transform: translateX(84.386165%);
+ transform: translateX(84.386165%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-half, 84.386165%));
+ transform: translateX(var(--mdc-linear-progress-secondary-half, 84.386165%));
+ }
+ 100% {
+ -webkit-transform: translateX(160.277782%);
+ transform: translateX(160.277782%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-full, 160.277782%));
+ transform: translateX(var(--mdc-linear-progress-secondary-full, 160.277782%));
+ }
+}
+@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-scale {
+ 0% {
+ -webkit-animation-timing-function: cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);
+ animation-timing-function: cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+ 19.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);
+ animation-timing-function: cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);
+ -webkit-transform: scaleX(0.457104);
+ transform: scaleX(0.457104);
+ }
+ 44.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);
+ animation-timing-function: cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);
+ -webkit-transform: scaleX(0.72796);
+ transform: scaleX(0.72796);
+ }
+ 100% {
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+}
+@keyframes mdc-linear-progress-secondary-indeterminate-scale {
+ 0% {
+ -webkit-animation-timing-function: cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);
+ animation-timing-function: cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+ 19.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);
+ animation-timing-function: cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);
+ -webkit-transform: scaleX(0.457104);
+ transform: scaleX(0.457104);
+ }
+ 44.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);
+ animation-timing-function: cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);
+ -webkit-transform: scaleX(0.72796);
+ transform: scaleX(0.72796);
+ }
+ 100% {
+ -webkit-transform: scaleX(0.08);
+ transform: scaleX(0.08);
+ }
+}
+@-webkit-keyframes mdc-linear-progress-buffering {
+ from {
+ -webkit-transform: rotate(180deg) translateX(-10px);
+ transform: rotate(180deg) translateX(-10px);
+ }
+}
+@keyframes mdc-linear-progress-buffering {
+ from {
+ -webkit-transform: rotate(180deg) translateX(-10px);
+ transform: rotate(180deg) translateX(-10px);
+ }
+}
+@-webkit-keyframes mdc-linear-progress-primary-indeterminate-translate-reverse {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 20% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 59.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(-83.67142%);
+ transform: translateX(-83.67142%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%));
+ transform: translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%));
+ }
+ 100% {
+ -webkit-transform: translateX(-200.611057%);
+ transform: translateX(-200.611057%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%));
+ transform: translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%));
+ }
+}
+@keyframes mdc-linear-progress-primary-indeterminate-translate-reverse {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 20% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 59.15% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(-83.67142%);
+ transform: translateX(-83.67142%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%));
+ transform: translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%));
+ }
+ 100% {
+ -webkit-transform: translateX(-200.611057%);
+ transform: translateX(-200.611057%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%));
+ transform: translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%));
+ }
+}
+@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-translate-reverse {
+ 0% {
+ -webkit-animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685);
+ animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685);
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 25% {
+ -webkit-animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);
+ animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);
+ -webkit-transform: translateX(-37.651913%);
+ transform: translateX(-37.651913%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%));
+ transform: translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%));
+ }
+ 48.35% {
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026);
+ animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026);
+ -webkit-transform: translateX(-84.386165%);
+ transform: translateX(-84.386165%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%));
+ transform: translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%));
+ }
+ 100% {
+ -webkit-transform: translateX(-160.277782%);
+ transform: translateX(-160.277782%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%));
+ transform: translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%));
+ }
+}
+@keyframes mdc-linear-progress-secondary-indeterminate-translate-reverse {
+ 0% {
+ -webkit-animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685);
+ animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685);
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+ 25% {
+ -webkit-animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);
+ animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);
+ -webkit-transform: translateX(-37.651913%);
+ transform: translateX(-37.651913%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%));
+ transform: translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%));
+ }
+ 48.35% {
+ -webkit-animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026);
+ animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026);
+ -webkit-transform: translateX(-84.386165%);
+ transform: translateX(-84.386165%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%));
+ transform: translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%));
+ }
+ 100% {
+ -webkit-transform: translateX(-160.277782%);
+ transform: translateX(-160.277782%);
+ /* @alternate */
+ -webkit-transform: translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%));
+ transform: translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%));
+ }
+}
+@-webkit-keyframes mdc-linear-progress-buffering-reverse {
+ from {
+ -webkit-transform: translateX(-10px);
+ transform: translateX(-10px);
+ }
+}
+@keyframes mdc-linear-progress-buffering-reverse {
+ from {
+ -webkit-transform: translateX(-10px);
+ transform: translateX(-10px);
+ }
+}
+.mdc-linear-progress {
+ position: relative;
+ width: 100%;
+ height: 4px;
+ -webkit-transform: translateZ(0);
+ transform: translateZ(0);
+ outline: 1px solid transparent;
+ overflow: hidden;
+ transition: opacity 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+.mdc-linear-progress__bar {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ -webkit-animation: none;
+ animation: none;
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ transition: -webkit-transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+.mdc-linear-progress__bar-inner {
+ display: inline-block;
+ position: absolute;
+ width: 100%;
+ -webkit-animation: none;
+ animation: none;
+ border-top: 4px solid;
+}
+.mdc-linear-progress__buffer {
+ display: flex;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+.mdc-linear-progress__buffer-dots {
+ background-repeat: repeat-x;
+ background-size: 10px 4px;
+ flex: auto;
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+ -webkit-animation: mdc-linear-progress-buffering 250ms infinite linear;
+ animation: mdc-linear-progress-buffering 250ms infinite linear;
+}
+.mdc-linear-progress__buffer-bar {
+ flex: 0 1 100%;
+ transition: flex-basis 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+.mdc-linear-progress__primary-bar {
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+}
+.mdc-linear-progress__secondary-bar {
+ display: none;
+}
+.mdc-linear-progress--indeterminate .mdc-linear-progress__bar {
+ transition: none;
+}
+.mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar {
+ left: -145.166611%;
+}
+.mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar {
+ left: -54.888891%;
+ display: block;
+}
+.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar {
+ -webkit-animation: mdc-linear-progress-primary-indeterminate-translate 2s infinite linear;
+ animation: mdc-linear-progress-primary-indeterminate-translate 2s infinite linear;
+}
+.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar > .mdc-linear-progress__bar-inner {
+ -webkit-animation: mdc-linear-progress-primary-indeterminate-scale 2s infinite linear;
+ animation: mdc-linear-progress-primary-indeterminate-scale 2s infinite linear;
+}
+.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar {
+ -webkit-animation: mdc-linear-progress-secondary-indeterminate-translate 2s infinite linear;
+ animation: mdc-linear-progress-secondary-indeterminate-translate 2s infinite linear;
+}
+.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar > .mdc-linear-progress__bar-inner {
+ -webkit-animation: mdc-linear-progress-secondary-indeterminate-scale 2s infinite linear;
+ animation: mdc-linear-progress-secondary-indeterminate-scale 2s infinite linear;
+}
+[dir=rtl] .mdc-linear-progress:not([dir=ltr]) .mdc-linear-progress__bar, .mdc-linear-progress[dir=rtl]:not([dir=ltr]) .mdc-linear-progress__bar {
+ /* @noflip */
+ right: 0;
+ /* @noflip */
+ -webkit-transform-origin: center right;
+ /* @noflip */
+ transform-origin: center right;
+}
+[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar, .mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar {
+ -webkit-animation-name: mdc-linear-progress-primary-indeterminate-translate-reverse;
+ animation-name: mdc-linear-progress-primary-indeterminate-translate-reverse;
+}
+[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar, .mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar {
+ -webkit-animation-name: mdc-linear-progress-secondary-indeterminate-translate-reverse;
+ animation-name: mdc-linear-progress-secondary-indeterminate-translate-reverse;
+}
+[dir=rtl] .mdc-linear-progress:not([dir=ltr]) .mdc-linear-progress__buffer-dots, .mdc-linear-progress[dir=rtl]:not([dir=ltr]) .mdc-linear-progress__buffer-dots {
+ -webkit-animation: mdc-linear-progress-buffering-reverse 250ms infinite linear;
+ animation: mdc-linear-progress-buffering-reverse 250ms infinite linear;
+ -webkit-transform: rotate(0);
+ transform: rotate(0);
+}
+[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar, .mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar {
+ /* @noflip */
+ right: -145.166611%;
+ /* @noflip */
+ left: auto;
+}
+[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar, .mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar {
+ /* @noflip */
+ right: -54.888891%;
+ /* @noflip */
+ left: auto;
+}
+
+.mdc-linear-progress--closed {
+ opacity: 0;
+}
+.mdc-linear-progress--closed-animation-off .mdc-linear-progress__buffer-dots {
+ -webkit-animation: none;
+ animation: none;
+}
+.mdc-linear-progress--closed-animation-off.mdc-linear-progress--indeterminate .mdc-linear-progress__bar,
+.mdc-linear-progress--closed-animation-off.mdc-linear-progress--indeterminate .mdc-linear-progress__bar .mdc-linear-progress__bar-inner {
+ -webkit-animation: none;
+ animation: none;
+}
+
+.mdc-linear-progress__bar-inner {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-theme-primary, #6200ee);
+}
+
+.mdc-linear-progress__buffer-dots {
+ background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' enable-background='new 0 0 5 2' xml:space='preserve' viewBox='0 0 5 2' preserveAspectRatio='none slice'%3E%3Ccircle cx='1' cy='1' r='1' fill='%23e6e6e6'/%3E%3C/svg%3E");
+}
+
+.mdc-linear-progress__buffer-bar {
+ background-color: #e6e6e6;
+}
+
+.mdc-deprecated-list {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ line-height: 1.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle1-line-height, 1.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ /* @alternate */
+ line-height: 1.5rem;
+ margin: 0;
+ padding: 8px 0;
+ list-style-type: none;
+ color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));
+}
+.mdc-deprecated-list:focus {
+ outline: none;
+}
+
+.mdc-deprecated-list-item {
+ height: 48px;
+}
+
+.mdc-deprecated-list-item__secondary-text {
+ color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ color: var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54));
+}
+
+.mdc-deprecated-list-item__graphic {
+ background-color: transparent;
+}
+
+.mdc-deprecated-list-item__graphic {
+ color: rgba(0, 0, 0, 0.38);
+ /* @alternate */
+ color: var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38));
+}
+
+.mdc-deprecated-list-item__meta {
+ color: rgba(0, 0, 0, 0.38);
+ /* @alternate */
+ color: var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38));
+}
+
+.mdc-deprecated-list-group__subheader {
+ color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));
+}
+
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__text {
+ opacity: 0.38;
+}
+
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__text,
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__primary-text,
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__secondary-text {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+
+.mdc-deprecated-list-item--selected,
+.mdc-deprecated-list-item--activated {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-deprecated-list-item--selected .mdc-deprecated-list-item__graphic,
+.mdc-deprecated-list-item--activated .mdc-deprecated-list-item__graphic {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+
+.mdc-deprecated-list--dense {
+ padding-top: 4px;
+ padding-bottom: 4px;
+ font-size: 0.812rem;
+}
+
+.mdc-deprecated-list-item {
+ display: flex;
+ position: relative;
+ align-items: center;
+ justify-content: flex-start;
+ overflow: hidden;
+ padding: 0;
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+ height: 48px;
+}
+.mdc-deprecated-list-item:focus {
+ outline: none;
+}
+.mdc-deprecated-list-item:not(.mdc-deprecated-list-item--selected):focus::before, .mdc-deprecated-list-item.mdc-ripple-upgraded--background-focused::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 1px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+.mdc-deprecated-list-item.mdc-deprecated-list-item--selected::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 3px double transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+[dir=rtl] .mdc-deprecated-list-item, .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-deprecated-list--icon-list .mdc-deprecated-list-item {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+ height: 56px;
+}
+[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-item, .mdc-deprecated-list--icon-list .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+ height: 56px;
+}
+[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+ height: 56px;
+}
+[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-deprecated-list--image-list .mdc-deprecated-list-item {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+ height: 72px;
+}
+[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-item, .mdc-deprecated-list--image-list .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-deprecated-list--video-list .mdc-deprecated-list-item {
+ /* @noflip */
+ padding-left: 0px;
+ /* @noflip */
+ padding-right: 16px;
+ height: 72px;
+}
+[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-item, .mdc-deprecated-list--video-list .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 0px;
+}
+
+.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+ width: 20px;
+ height: 20px;
+}
+[dir=rtl] .mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic, .mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-deprecated-list-item__graphic {
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+ fill: currentColor;
+ -o-object-fit: cover;
+ object-fit: cover;
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 32px;
+ width: 24px;
+ height: 24px;
+}
+[dir=rtl] .mdc-deprecated-list-item__graphic, .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 32px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-deprecated-list--icon-list .mdc-deprecated-list-item__graphic {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 32px;
+ width: 24px;
+ height: 24px;
+}
+[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-item__graphic, .mdc-deprecated-list--icon-list .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 32px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__graphic {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+}
+[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__graphic, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__graphic {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+ width: 40px;
+ height: 40px;
+}
+[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__graphic, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-deprecated-list--image-list .mdc-deprecated-list-item__graphic {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+ width: 56px;
+ height: 56px;
+}
+[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-item__graphic, .mdc-deprecated-list--image-list .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-deprecated-list--video-list .mdc-deprecated-list-item__graphic {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+ width: 100px;
+ height: 56px;
+}
+[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-item__graphic, .mdc-deprecated-list--video-list .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-deprecated-list .mdc-deprecated-list-item__graphic {
+ display: inline-flex;
+}
+
+.mdc-deprecated-list-item__meta {
+ /* @noflip */
+ margin-left: auto;
+ /* @noflip */
+ margin-right: 0;
+}
+.mdc-deprecated-list-item__meta:not(.material-icons) {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-caption-font-size, 0.75rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-caption-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-caption-font-weight, 400);
+ letter-spacing: 0.0333333333em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-caption-text-transform, inherit);
+}
+.mdc-deprecated-list-item[dir=rtl] .mdc-deprecated-list-item__meta, [dir=rtl] .mdc-deprecated-list-item .mdc-deprecated-list-item__meta {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: auto;
+}
+
+.mdc-deprecated-list-item__text {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.mdc-deprecated-list-item__text[for] {
+ pointer-events: none;
+}
+
+.mdc-deprecated-list-item__primary-text {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-deprecated-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-deprecated-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-deprecated-list--video-list .mdc-deprecated-list-item__primary-text, .mdc-deprecated-list--image-list .mdc-deprecated-list-item__primary-text, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__primary-text, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__primary-text, .mdc-deprecated-list--icon-list .mdc-deprecated-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-deprecated-list--video-list .mdc-deprecated-list-item__primary-text::before, .mdc-deprecated-list--image-list .mdc-deprecated-list-item__primary-text::before, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__primary-text::before, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__primary-text::before, .mdc-deprecated-list--icon-list .mdc-deprecated-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-deprecated-list--video-list .mdc-deprecated-list-item__primary-text::after, .mdc-deprecated-list--image-list .mdc-deprecated-list-item__primary-text::after, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__primary-text::after, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__primary-text::after, .mdc-deprecated-list--icon-list .mdc-deprecated-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-deprecated-list--dense .mdc-deprecated-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-deprecated-list--dense .mdc-deprecated-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 24px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-deprecated-list--dense .mdc-deprecated-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+
+.mdc-deprecated-list-item__secondary-text {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-deprecated-list-item__secondary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-deprecated-list--dense .mdc-deprecated-list-item__secondary-text {
+ font-size: inherit;
+}
+
+.mdc-deprecated-list--dense .mdc-deprecated-list-item {
+ height: 40px;
+}
+
+.mdc-deprecated-list--two-line .mdc-deprecated-list-item__text {
+ align-self: flex-start;
+}
+
+.mdc-deprecated-list--two-line .mdc-deprecated-list-item {
+ height: 64px;
+}
+.mdc-deprecated-list--two-line.mdc-deprecated-list--video-list .mdc-deprecated-list-item, .mdc-deprecated-list--two-line.mdc-deprecated-list--image-list .mdc-deprecated-list-item, .mdc-deprecated-list--two-line.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item, .mdc-deprecated-list--two-line.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item, .mdc-deprecated-list--two-line.mdc-deprecated-list--icon-list .mdc-deprecated-list-item {
+ height: 72px;
+}
+.mdc-deprecated-list--two-line.mdc-deprecated-list--icon-list .mdc-deprecated-list-item__graphic {
+ align-self: flex-start;
+ margin-top: 16px;
+}
+
+.mdc-deprecated-list--two-line.mdc-deprecated-list--dense .mdc-deprecated-list-item,
+.mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense .mdc-deprecated-list-item {
+ height: 60px;
+}
+
+.mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+ width: 36px;
+ height: 36px;
+}
+[dir=rtl] .mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic, .mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item {
+ cursor: pointer;
+}
+
+a.mdc-deprecated-list-item {
+ color: inherit;
+ text-decoration: none;
+}
+
+.mdc-deprecated-list-divider {
+ height: 0;
+ margin: 0;
+ border: none;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+.mdc-deprecated-list-divider {
+ border-bottom-color: rgba(0, 0, 0, 0.12);
+}
+
+.mdc-deprecated-list-divider--padded {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 32px);
+}
+[dir=rtl] .mdc-deprecated-list-divider--padded, .mdc-deprecated-list-divider--padded[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list-divider--inset {
+ /* @noflip */
+ margin-left: 72px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 72px);
+}
+[dir=rtl] .mdc-deprecated-list-divider--inset, .mdc-deprecated-list-divider--inset[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 72px;
+}
+
+.mdc-deprecated-list-divider--inset.mdc-deprecated-list-divider--padded {
+ /* @noflip */
+ margin-left: 72px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 88px);
+}
+[dir=rtl] .mdc-deprecated-list-divider--inset.mdc-deprecated-list-divider--padded, .mdc-deprecated-list-divider--inset.mdc-deprecated-list-divider--padded[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 72px;
+}
+
+.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 16px);
+}
+[dir=rtl] .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading, .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list .mdc-deprecated-list-divider--inset-trailing {
+ width: calc(100% - 16px);
+}
+.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 32px);
+}
+[dir=rtl] .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing, .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 16px);
+}
+[dir=rtl] .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding, .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 32px);
+}
+[dir=rtl] .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding, .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading {
+ /* @noflip */
+ margin-left: 72px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 72px);
+}
+[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading, .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 72px;
+}
+
+.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-trailing {
+ width: calc(100% - 16px);
+}
+.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing {
+ /* @noflip */
+ margin-left: 72px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 88px);
+}
+[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing, .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 72px;
+}
+
+.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 16px);
+}
+[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding, .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 32px);
+}
+[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding, .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading {
+ /* @noflip */
+ margin-left: 72px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 72px);
+}
+[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 72px;
+}
+
+.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-trailing {
+ width: calc(100% - 16px);
+}
+.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing {
+ /* @noflip */
+ margin-left: 72px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 88px);
+}
+[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 72px;
+}
+
+.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 16px);
+}
+[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 32px);
+}
+[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding, .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading {
+ /* @noflip */
+ margin-left: 72px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 72px);
+}
+[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 72px;
+}
+
+.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-trailing {
+ width: calc(100% - 16px);
+}
+.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing {
+ /* @noflip */
+ margin-left: 72px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 88px);
+}
+[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 72px;
+}
+
+.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 16px);
+}
+[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 32px);
+}
+[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding, .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading {
+ /* @noflip */
+ margin-left: 88px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 88px);
+}
+[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading, .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 88px;
+}
+
+.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-trailing {
+ width: calc(100% - 16px);
+}
+.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing {
+ /* @noflip */
+ margin-left: 88px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 104px);
+}
+[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing, .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 88px;
+}
+
+.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 16px);
+}
+[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding, .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 32px);
+}
+[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding, .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading {
+ /* @noflip */
+ margin-left: 116px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 116px);
+}
+[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading, .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 116px;
+}
+
+.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-trailing {
+ width: calc(100% - 16px);
+}
+.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing {
+ /* @noflip */
+ margin-left: 116px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 132px);
+}
+[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing, .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 116px;
+}
+
+.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding {
+ /* @noflip */
+ margin-left: 0px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 0px);
+}
+[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding, .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0px;
+}
+
+.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding {
+ /* @noflip */
+ margin-left: 0px;
+ /* @noflip */
+ margin-right: 0;
+ width: calc(100% - 16px);
+}
+[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding, .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 0px;
+}
+
+.mdc-deprecated-list-group .mdc-deprecated-list {
+ padding: 0;
+}
+
+.mdc-deprecated-list-group__subheader {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ line-height: 1.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle1-line-height, 1.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ margin: calc( (3rem - 1.5rem) / 2 ) 16px;
+}
+
+.mdc-list-item__primary-text {
+ color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));
+}
+
+.mdc-list-item__secondary-text {
+ color: rgba(0, 0, 0, 0.54);
+ /* @alternate */
+ color: var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54));
+}
+
+.mdc-list-item__overline-text {
+ color: rgba(0, 0, 0, 0.38);
+ /* @alternate */
+ color: var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38));
+}
+
+.mdc-list-item--with-leading-icon .mdc-list-item__start,
+.mdc-list-item--with-trailing-icon .mdc-list-item__end {
+ background-color: transparent;
+}
+
+.mdc-list-item--with-leading-icon .mdc-list-item__start,
+.mdc-list-item--with-trailing-icon .mdc-list-item__end {
+ color: rgba(0, 0, 0, 0.38);
+ /* @alternate */
+ color: var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38));
+}
+
+.mdc-list-item__end {
+ color: rgba(0, 0, 0, 0.38);
+ /* @alternate */
+ color: var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38));
+}
+
+.mdc-list-item--disabled .mdc-list-item__start,
+.mdc-list-item--disabled .mdc-list-item__content,
+.mdc-list-item--disabled .mdc-list-item__end {
+ opacity: 0.38;
+}
+
+.mdc-list-item--disabled .mdc-list-item__primary-text {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-list-item--disabled .mdc-list-item__secondary-text {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-list-item--disabled .mdc-list-item__overline-text {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-list-item--disabled.mdc-list-item--with-leading-icon .mdc-list-item__start {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-list-item--disabled.mdc-list-item--with-trailing-icon .mdc-list-item__end {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-list-item--disabled.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+}
+
+.mdc-list-item--selected .mdc-list-item__primary-text,
+.mdc-list-item--activated .mdc-list-item__primary-text {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-list-item--selected.mdc-list-item--with-leading-icon .mdc-list-item__start,
+.mdc-list-item--activated.mdc-list-item--with-leading-icon .mdc-list-item__start {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+
+.mdc-deprecated-list-group__subheader {
+ color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));
+}
+
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-list-divider::after {
+ content: "";
+ display: block;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ border-bottom-color: white;
+ }
+}
+.mdc-list {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ line-height: 1.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle1-line-height, 1.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ /* @alternate */
+ line-height: 1.5rem;
+ margin: 0;
+ padding: 8px 0;
+ list-style-type: none;
+}
+.mdc-list:focus {
+ outline: none;
+}
+
+.mdc-list-item {
+ display: flex;
+ position: relative;
+ align-items: center;
+ justify-content: flex-start;
+ overflow: hidden;
+ padding: 0;
+ align-items: stretch;
+ cursor: pointer;
+}
+.mdc-list-item:focus {
+ outline: none;
+}
+.mdc-list-item.mdc-list-item--with-one-line {
+ height: 48px;
+}
+.mdc-list-item.mdc-list-item--with-two-lines {
+ height: 64px;
+}
+.mdc-list-item.mdc-list-item--with-three-lines {
+ height: 88px;
+}
+.mdc-list-item.mdc-list-item--with-one-line .mdc-list-item__start {
+ align-self: center;
+ margin-top: 0;
+}
+.mdc-list-item.mdc-list-item--with-two-lines .mdc-list-item__start {
+ align-self: flex-start;
+ margin-top: 16px;
+}
+.mdc-list-item.mdc-list-item--with-three-lines .mdc-list-item__start {
+ align-self: flex-start;
+ margin-top: 16px;
+}
+.mdc-list-item.mdc-list-item--with-one-line .mdc-list-item__end {
+ align-self: center;
+ margin-top: 0;
+}
+.mdc-list-item.mdc-list-item--with-two-lines .mdc-list-item__end {
+ align-self: center;
+ margin-top: 0;
+}
+.mdc-list-item.mdc-list-item--with-three-lines .mdc-list-item__end {
+ align-self: flex-start;
+ margin-top: 16px;
+}
+.mdc-list-item.mdc-list-item--disabled, .mdc-list-item.mdc-list-item--non-interactive {
+ cursor: auto;
+}
+.mdc-list-item:not(.mdc-list-item--selected):focus::before, .mdc-list-item.mdc-ripple-upgraded--background-focused::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 1px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+.mdc-list-item.mdc-list-item--selected::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 3px double transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+.mdc-list-item.mdc-list-item--selected:focus::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 3px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+
+a.mdc-list-item {
+ color: inherit;
+ text-decoration: none;
+}
+
+.mdc-list-item__start {
+ fill: currentColor;
+ flex-shrink: 0;
+ pointer-events: none;
+}
+
+.mdc-list-item__end {
+ flex-shrink: 0;
+ pointer-events: none;
+}
+
+.mdc-list-item__content {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ align-self: center;
+ flex: 1;
+ pointer-events: none;
+}
+.mdc-list-item--with-two-lines .mdc-list-item__content, .mdc-list-item--with-three-lines .mdc-list-item__content {
+ align-self: stretch;
+}
+.mdc-list-item__content[for] {
+ pointer-events: none;
+}
+
+.mdc-list-item__primary-text {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ line-height: 1.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle1-line-height, 1.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+.mdc-list-item--with-two-lines .mdc-list-item__primary-text, .mdc-list-item--with-three-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before, .mdc-list-item--with-three-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after, .mdc-list-item--with-three-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+
+.mdc-list-item__secondary-text {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item__secondary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-three-lines .mdc-list-item__secondary-text {
+ white-space: normal;
+ line-height: 20px;
+}
+.mdc-list-item--with-overline .mdc-list-item__secondary-text {
+ white-space: nowrap;
+ line-height: auto;
+}
+
+.mdc-list-item__overline-text {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-overline-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-overline-font-size, 0.75rem);
+ line-height: 2rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-overline-line-height, 2rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-overline-font-weight, 500);
+ letter-spacing: 0.1666666667em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-overline-letter-spacing, 0.1666666667em);
+ text-decoration: none;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-overline-text-decoration, none);
+ text-decoration: var(--mdc-typography-overline-text-decoration, none);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-overline-text-transform, uppercase);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 24px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-three-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-three-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-three-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+
+.mdc-list-item--with-leading-avatar.mdc-list-item {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-item--with-leading-avatar.mdc-list-item, .mdc-list-item--with-leading-avatar.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-list-item--with-leading-avatar .mdc-list-item__start {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+[dir=rtl] .mdc-list-item--with-leading-avatar .mdc-list-item__start, .mdc-list-item--with-leading-avatar .mdc-list-item__start[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-list-item--with-leading-avatar .mdc-list-item__start {
+ width: 40px;
+ height: 40px;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-one-line {
+ height: 56px;
+}
+.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines {
+ height: 72px;
+}
+.mdc-list-item--with-leading-avatar .mdc-list-item__start {
+ border-radius: 50%;
+}
+
+.mdc-list-item--with-leading-icon .mdc-list-item__start {
+ width: 24px;
+ height: 24px;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-item--with-leading-icon.mdc-list-item, .mdc-list-item--with-leading-icon.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-list-item--with-leading-icon .mdc-list-item__start {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 32px;
+}
+[dir=rtl] .mdc-list-item--with-leading-icon .mdc-list-item__start, .mdc-list-item--with-leading-icon .mdc-list-item__start[dir=rtl] {
+ /* @noflip */
+ margin-left: 32px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-one-line {
+ height: 56px;
+}
+.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines {
+ height: 72px;
+}
+
+.mdc-list-item--with-leading-thumbnail.mdc-list-item {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-item--with-leading-thumbnail.mdc-list-item, .mdc-list-item--with-leading-thumbnail.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-list-item--with-leading-thumbnail .mdc-list-item__start {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+[dir=rtl] .mdc-list-item--with-leading-thumbnail .mdc-list-item__start, .mdc-list-item--with-leading-thumbnail .mdc-list-item__start[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-list-item--with-leading-thumbnail .mdc-list-item__start {
+ width: 40px;
+ height: 40px;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-one-line {
+ height: 56px;
+}
+.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines {
+ height: 72px;
+}
+
+.mdc-list-item--with-leading-image.mdc-list-item {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-item--with-leading-image.mdc-list-item, .mdc-list-item--with-leading-image.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-list-item--with-leading-image .mdc-list-item__start {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+[dir=rtl] .mdc-list-item--with-leading-image .mdc-list-item__start, .mdc-list-item--with-leading-image .mdc-list-item__start[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-list-item--with-leading-image .mdc-list-item__start {
+ width: 56px;
+ height: 56px;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-one-line {
+ height: 72px;
+}
+.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines {
+ height: 72px;
+}
+
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__start {
+ align-self: flex-start;
+ margin-top: 8px;
+}
+.mdc-list-item--with-leading-video.mdc-list-item {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-item--with-leading-video.mdc-list-item, .mdc-list-item--with-leading-video.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-list-item--with-leading-video .mdc-list-item__start {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 16px;
+}
+[dir=rtl] .mdc-list-item--with-leading-video .mdc-list-item__start, .mdc-list-item--with-leading-video .mdc-list-item__start[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 0;
+}
+
+.mdc-list-item--with-leading-video .mdc-list-item__start {
+ width: 100px;
+ height: 56px;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-one-line {
+ height: 72px;
+}
+.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines {
+ height: 72px;
+}
+
+.mdc-list-item--with-leading-checkbox.mdc-list-item {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-item--with-leading-checkbox.mdc-list-item, .mdc-list-item--with-leading-checkbox.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-list-item--with-leading-checkbox .mdc-list-item__start {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 24px;
+}
+[dir=rtl] .mdc-list-item--with-leading-checkbox .mdc-list-item__start, .mdc-list-item--with-leading-checkbox .mdc-list-item__start[dir=rtl] {
+ /* @noflip */
+ margin-left: 24px;
+ /* @noflip */
+ margin-right: 8px;
+}
+
+.mdc-list-item--with-leading-checkbox .mdc-list-item__start {
+ width: 40px;
+ height: 40px;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__start {
+ align-self: flex-start;
+ margin-top: 8px;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-one-line {
+ height: 56px;
+}
+.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines {
+ height: 72px;
+}
+
+.mdc-list-item--with-leading-radio.mdc-list-item {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-item--with-leading-radio.mdc-list-item, .mdc-list-item--with-leading-radio.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-list-item--with-leading-radio .mdc-list-item__start {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 24px;
+}
+[dir=rtl] .mdc-list-item--with-leading-radio .mdc-list-item__start, .mdc-list-item--with-leading-radio .mdc-list-item__start[dir=rtl] {
+ /* @noflip */
+ margin-left: 24px;
+ /* @noflip */
+ margin-right: 8px;
+}
+
+.mdc-list-item--with-leading-radio .mdc-list-item__start {
+ width: 40px;
+ height: 40px;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__start {
+ align-self: flex-start;
+ margin-top: 8px;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-one-line {
+ height: 56px;
+}
+.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines {
+ height: 72px;
+}
+
+.mdc-list-item--with-leading-switch.mdc-list-item {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-item--with-leading-switch.mdc-list-item, .mdc-list-item--with-leading-switch.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-list-item--with-leading-switch .mdc-list-item__start {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+[dir=rtl] .mdc-list-item--with-leading-switch .mdc-list-item__start, .mdc-list-item--with-leading-switch .mdc-list-item__start[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-list-item--with-leading-switch .mdc-list-item__start {
+ width: 36px;
+ height: 20px;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__start {
+ align-self: flex-start;
+ margin-top: 16px;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__overline-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin-bottom: -20px;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: -20px;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 32px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-one-line {
+ height: 56px;
+}
+.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines {
+ height: 72px;
+}
+
+.mdc-list-item--with-trailing-icon.mdc-list-item {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-list-item--with-trailing-icon.mdc-list-item, .mdc-list-item--with-trailing-icon.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+
+.mdc-list-item--with-trailing-icon .mdc-list-item__end {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+[dir=rtl] .mdc-list-item--with-trailing-icon .mdc-list-item__end, .mdc-list-item--with-trailing-icon .mdc-list-item__end[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-list-item--with-trailing-icon .mdc-list-item__end {
+ width: 24px;
+ height: 24px;
+}
+
+.mdc-list-item--with-trailing-meta.mdc-list-item--with-two-lines .mdc-list-item__end {
+ align-self: flex-start;
+ margin-top: 0;
+}
+.mdc-list-item--with-trailing-meta.mdc-list-item--with-three-lines .mdc-list-item__end {
+ align-self: flex-start;
+ margin-top: 0;
+}
+.mdc-list-item--with-trailing-meta.mdc-list-item {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-list-item--with-trailing-meta.mdc-list-item, .mdc-list-item--with-trailing-meta.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+
+.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ /* @noflip */
+ margin-left: 28px;
+ /* @noflip */
+ margin-right: 16px;
+}
+[dir=rtl] .mdc-list-item--with-trailing-meta .mdc-list-item__end, .mdc-list-item--with-trailing-meta .mdc-list-item__end[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 28px;
+}
+
+.mdc-list-item--with-trailing-meta.mdc-list-item--with-two-lines .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-trailing-meta.mdc-list-item--with-two-lines .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-trailing-meta.mdc-list-item--with-three-lines .mdc-list-item__end {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-trailing-meta.mdc-list-item--with-three-lines .mdc-list-item__end::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-trailing-meta .mdc-list-item__end {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-caption-font-size, 0.75rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-caption-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-caption-font-weight, 400);
+ letter-spacing: 0.0333333333em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-caption-text-transform, inherit);
+}
+
+.mdc-list-item--with-trailing-checkbox.mdc-list-item {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-list-item--with-trailing-checkbox.mdc-list-item, .mdc-list-item--with-trailing-checkbox.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+
+.mdc-list-item--with-trailing-checkbox .mdc-list-item__end {
+ /* @noflip */
+ margin-left: 24px;
+ /* @noflip */
+ margin-right: 8px;
+}
+[dir=rtl] .mdc-list-item--with-trailing-checkbox .mdc-list-item__end, .mdc-list-item--with-trailing-checkbox .mdc-list-item__end[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 24px;
+}
+
+.mdc-list-item--with-trailing-checkbox .mdc-list-item__end {
+ width: 40px;
+ height: 40px;
+}
+.mdc-list-item--with-trailing-checkbox.mdc-list-item--with-three-lines .mdc-list-item__end {
+ align-self: flex-start;
+ margin-top: 8px;
+}
+
+.mdc-list-item--with-trailing-radio.mdc-list-item {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-list-item--with-trailing-radio.mdc-list-item, .mdc-list-item--with-trailing-radio.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+
+.mdc-list-item--with-trailing-radio .mdc-list-item__end {
+ /* @noflip */
+ margin-left: 24px;
+ /* @noflip */
+ margin-right: 8px;
+}
+[dir=rtl] .mdc-list-item--with-trailing-radio .mdc-list-item__end, .mdc-list-item--with-trailing-radio .mdc-list-item__end[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 24px;
+}
+
+.mdc-list-item--with-trailing-radio .mdc-list-item__end {
+ width: 40px;
+ height: 40px;
+}
+.mdc-list-item--with-trailing-radio.mdc-list-item--with-three-lines .mdc-list-item__end {
+ align-self: flex-start;
+ margin-top: 8px;
+}
+
+.mdc-list-item--with-trailing-switch.mdc-list-item {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-list-item--with-trailing-switch.mdc-list-item, .mdc-list-item--with-trailing-switch.mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: auto;
+}
+
+.mdc-list-item--with-trailing-switch .mdc-list-item__end {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+[dir=rtl] .mdc-list-item--with-trailing-switch .mdc-list-item__end, .mdc-list-item--with-trailing-switch .mdc-list-item__end[dir=rtl] {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-list-item--with-trailing-switch .mdc-list-item__end {
+ width: 36px;
+ height: 20px;
+}
+.mdc-list-item--with-trailing-switch.mdc-list-item--with-three-lines .mdc-list-item__end {
+ align-self: flex-start;
+ margin-top: 16px;
+}
+
+.mdc-list-item--with-overline.mdc-list-item--with-two-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-overline.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-list-item--with-overline.mdc-list-item--with-three-lines .mdc-list-item__primary-text {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+}
+.mdc-list-item--with-overline.mdc-list-item--with-three-lines .mdc-list-item__primary-text::before {
+ display: inline-block;
+ width: 0;
+ height: 20px;
+ content: "";
+ vertical-align: 0;
+}
+
+.mdc-list-item {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+[dir=rtl] .mdc-list-item, .mdc-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-list-group .mdc-deprecated-list {
+ padding: 0;
+}
+
+.mdc-list-group__subheader {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ line-height: 1.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle1-line-height, 1.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ margin: calc( (3rem - 1.5rem) / 2 ) 16px;
+}
+
+.mdc-list-divider {
+ background-color: rgba(0, 0, 0, 0.12);
+}
+
+.mdc-list-divider {
+ height: 1px;
+ padding: 0;
+ background-clip: content-box;
+}
+
+.mdc-list-divider.mdc-list-divider--with-leading-inset,
+.mdc-list-divider--with-leading-text.mdc-list-divider--with-leading-inset,
+.mdc-list-divider--with-leading-icon.mdc-list-divider--with-leading-inset,
+.mdc-list-divider--with-leading-image.mdc-list-divider--with-leading-inset,
+.mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-leading-inset,
+.mdc-list-divider--with-leading-avatar.mdc-list-divider--with-leading-inset,
+.mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-leading-inset,
+.mdc-list-divider--with-leading-switch.mdc-list-divider--with-leading-inset,
+.mdc-list-divider--with-leading-radio.mdc-list-divider--with-leading-inset {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-divider.mdc-list-divider--with-leading-inset, [dir=rtl] .mdc-list-divider--with-leading-text.mdc-list-divider--with-leading-inset, [dir=rtl] .mdc-list-divider--with-leading-icon.mdc-list-divider--with-leading-inset, [dir=rtl] .mdc-list-divider--with-leading-image.mdc-list-divider--with-leading-inset, [dir=rtl] .mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-leading-inset, [dir=rtl] .mdc-list-divider--with-leading-avatar.mdc-list-divider--with-leading-inset, [dir=rtl] .mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-leading-inset, [dir=rtl] .mdc-list-divider--with-leading-switch.mdc-list-divider--with-leading-inset, [dir=rtl] .mdc-list-divider--with-leading-radio.mdc-list-divider--with-leading-inset, .mdc-list-divider.mdc-list-divider--with-leading-inset[dir=rtl], .mdc-list-divider--with-leading-text.mdc-list-divider--with-leading-inset[dir=rtl], .mdc-list-divider--with-leading-icon.mdc-list-divider--with-leading-inset[dir=rtl], .mdc-list-divider--with-leading-image.mdc-list-divider--with-leading-inset[dir=rtl], .mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-leading-inset[dir=rtl], .mdc-list-divider--with-leading-avatar.mdc-list-divider--with-leading-inset[dir=rtl], .mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-leading-inset[dir=rtl], .mdc-list-divider--with-leading-switch.mdc-list-divider--with-leading-inset[dir=rtl], .mdc-list-divider--with-leading-radio.mdc-list-divider--with-leading-inset[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-list-divider.mdc-list-divider--with-trailing-inset,
+.mdc-list-divider--with-leading-text.mdc-list-divider--with-trailing-inset,
+.mdc-list-divider--with-leading-icon.mdc-list-divider--with-trailing-inset,
+.mdc-list-divider--with-leading-image.mdc-list-divider--with-trailing-inset,
+.mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-trailing-inset,
+.mdc-list-divider--with-leading-avatar.mdc-list-divider--with-trailing-inset,
+.mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-trailing-inset,
+.mdc-list-divider--with-leading-switch.mdc-list-divider--with-trailing-inset,
+.mdc-list-divider--with-leading-radio.mdc-list-divider--with-trailing-inset {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 16px;
+}
+[dir=rtl] .mdc-list-divider.mdc-list-divider--with-trailing-inset, [dir=rtl] .mdc-list-divider--with-leading-text.mdc-list-divider--with-trailing-inset, [dir=rtl] .mdc-list-divider--with-leading-icon.mdc-list-divider--with-trailing-inset, [dir=rtl] .mdc-list-divider--with-leading-image.mdc-list-divider--with-trailing-inset, [dir=rtl] .mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-trailing-inset, [dir=rtl] .mdc-list-divider--with-leading-avatar.mdc-list-divider--with-trailing-inset, [dir=rtl] .mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-trailing-inset, [dir=rtl] .mdc-list-divider--with-leading-switch.mdc-list-divider--with-trailing-inset, [dir=rtl] .mdc-list-divider--with-leading-radio.mdc-list-divider--with-trailing-inset, .mdc-list-divider.mdc-list-divider--with-trailing-inset[dir=rtl], .mdc-list-divider--with-leading-text.mdc-list-divider--with-trailing-inset[dir=rtl], .mdc-list-divider--with-leading-icon.mdc-list-divider--with-trailing-inset[dir=rtl], .mdc-list-divider--with-leading-image.mdc-list-divider--with-trailing-inset[dir=rtl], .mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-trailing-inset[dir=rtl], .mdc-list-divider--with-leading-avatar.mdc-list-divider--with-trailing-inset[dir=rtl], .mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-trailing-inset[dir=rtl], .mdc-list-divider--with-leading-switch.mdc-list-divider--with-trailing-inset[dir=rtl], .mdc-list-divider--with-leading-radio.mdc-list-divider--with-trailing-inset[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: auto;
+}
+
+.mdc-list-divider--with-leading-video.mdc-list-divider--with-leading-inset {
+ /* @noflip */
+ padding-left: 0px;
+ /* @noflip */
+ padding-right: auto;
+}
+[dir=rtl] .mdc-list-divider--with-leading-video.mdc-list-divider--with-leading-inset, .mdc-list-divider--with-leading-video.mdc-list-divider--with-leading-inset[dir=rtl] {
+ /* @noflip */
+ padding-left: auto;
+ /* @noflip */
+ padding-right: 0px;
+}
+
+[dir=rtl] .mdc-list-divider, .mdc-list-divider[dir=rtl] {
+ padding: 0;
+}
+
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::before,
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--unbounded .mdc-deprecated-list-item__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--foreground-activation .mdc-deprecated-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--foreground-deactivation .mdc-deprecated-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::before,
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--unbounded .mdc-list-item__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--foreground-activation .mdc-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--foreground-deactivation .mdc-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::before,
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::before,
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:hover .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-surface--hover .mdc-deprecated-list-item__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded) .mdc-deprecated-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded):active .mdc-deprecated-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:hover .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-surface--hover .mdc-list-item__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-deprecated-list-item__ripple::before {
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-activated-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-deprecated-list-item__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:hover .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-surface--hover .mdc-deprecated-list-item__ripple::before {
+ opacity: 0.16;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.16);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded) .mdc-deprecated-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded):active .mdc-deprecated-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-list-item__ripple::before {
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-activated-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-list-item__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:hover .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-surface--hover .mdc-list-item__ripple::before {
+ opacity: 0.16;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.16);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-selected-opacity, 0.08);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:hover .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-surface--hover .mdc-deprecated-list-item__ripple::before {
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.2;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.2);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded) .mdc-deprecated-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-deprecated-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.2;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.2);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.2);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-list-item__ripple::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-selected-opacity, 0.08);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-list-item__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:hover .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-surface--hover .mdc-list-item__ripple::before {
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.12);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, :not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.2;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.2);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.2;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.2);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.2);
+}
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple,
+:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+.mdc-deprecated-list-item--disabled {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::before,
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--unbounded .mdc-deprecated-list-item__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--foreground-activation .mdc-deprecated-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--foreground-deactivation .mdc-deprecated-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::before,
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--unbounded .mdc-list-item__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--foreground-activation .mdc-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--foreground-deactivation .mdc-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::before,
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::before,
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::before,
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::before,
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before, .mdc-deprecated-list-item--disabled:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, .mdc-deprecated-list-item--disabled:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple,
+.mdc-deprecated-list-item--disabled .mdc-list-item__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+:not(.mdc-list-item--disabled).mdc-list-item {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::before,
+:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--unbounded .mdc-list-item__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--foreground-activation .mdc-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--foreground-deactivation .mdc-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::before,
+:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+:not(.mdc-list-item--disabled).mdc-list-item:hover .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-surface--hover .mdc-list-item__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+:not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--activated .mdc-list-item__ripple::before {
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-activated-opacity, 0.12);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--activated .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item--activated .mdc-list-item__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+:not(.mdc-list-item--disabled).mdc-list-item--activated:hover .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item--activated.mdc-ripple-surface--hover .mdc-list-item__ripple::before {
+ opacity: 0.16;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.16);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--activated.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--activated.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--selected .mdc-list-item__ripple::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-selected-opacity, 0.08);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--selected .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item--selected .mdc-list-item__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+:not(.mdc-list-item--disabled).mdc-list-item--selected:hover .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item--selected.mdc-ripple-surface--hover .mdc-list-item__ripple::before {
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.12);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, :not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.2;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.2);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after {
+ transition: opacity 150ms linear;
+}
+:not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.2;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.2);
+}
+:not(.mdc-list-item--disabled).mdc-list-item--selected.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.2);
+}
+:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+.mdc-list-item--disabled {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-list-item--disabled .mdc-list-item__ripple::before,
+.mdc-list-item--disabled .mdc-list-item__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-list-item--disabled .mdc-list-item__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-list-item--disabled .mdc-list-item__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-list-item--disabled.mdc-ripple-upgraded--unbounded .mdc-list-item__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-list-item--disabled.mdc-ripple-upgraded--foreground-activation .mdc-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-list-item--disabled.mdc-ripple-upgraded--foreground-deactivation .mdc-list-item__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-list-item--disabled .mdc-list-item__ripple::before,
+.mdc-list-item--disabled .mdc-list-item__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-list-item--disabled .mdc-list-item__ripple::before,
+.mdc-list-item--disabled .mdc-list-item__ripple::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+.mdc-list-item--disabled.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before, .mdc-list-item--disabled:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-list-item--disabled .mdc-list-item__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+.mdc-menu {
+ min-width: 112px;
+ /* @alternate */
+ min-width: var(--mdc-menu-min-width, 112px);
+}
+.mdc-menu .mdc-deprecated-list-item__meta {
+ color: rgba(0, 0, 0, 0.87);
+}
+.mdc-menu .mdc-deprecated-list-item__graphic {
+ color: rgba(0, 0, 0, 0.87);
+}
+.mdc-menu .mdc-deprecated-list {
+ color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ position: relative;
+}
+.mdc-menu .mdc-deprecated-list .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.mdc-menu .mdc-deprecated-list-divider {
+ margin: 8px 0;
+}
+.mdc-menu .mdc-deprecated-list-item {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.mdc-menu .mdc-deprecated-list-item--disabled {
+ cursor: auto;
+}
+.mdc-menu a.mdc-deprecated-list-item .mdc-deprecated-list-item__text,
+.mdc-menu a.mdc-deprecated-list-item .mdc-deprecated-list-item__graphic {
+ pointer-events: none;
+}
+
+.mdc-menu__selection-group {
+ padding: 0;
+ fill: currentColor;
+}
+.mdc-menu__selection-group .mdc-deprecated-list-item {
+ /* @noflip */
+ padding-left: 56px;
+ /* @noflip */
+ padding-right: 16px;
+}
+[dir=rtl] .mdc-menu__selection-group .mdc-deprecated-list-item, .mdc-menu__selection-group .mdc-deprecated-list-item[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 56px;
+}
+
+.mdc-menu__selection-group .mdc-menu__selection-group-icon {
+ /* @noflip */
+ left: 16px;
+ /* @noflip */
+ right: initial;
+ display: none;
+ position: absolute;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+}
+[dir=rtl] .mdc-menu__selection-group .mdc-menu__selection-group-icon, .mdc-menu__selection-group .mdc-menu__selection-group-icon[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 16px;
+}
+
+.mdc-menu-item--selected .mdc-menu__selection-group-icon {
+ display: inline;
+}
+
+.mdc-menu-surface {
+ display: none;
+ position: absolute;
+ box-sizing: border-box;
+ max-width: calc(100vw - 32px);
+ /* @alternate */
+ max-width: var(--mdc-menu-max-width, calc(100vw - 32px));
+ max-height: calc(100vh - 32px);
+ /* @alternate */
+ max-height: var(--mdc-menu-max-height, calc(100vh - 32px));
+ margin: 0;
+ padding: 0;
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ opacity: 0;
+ overflow: auto;
+ will-change: transform, opacity;
+ z-index: 8;
+ transition: opacity 0.03s linear, height 250ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 0.12s cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 0.03s linear, transform 0.12s cubic-bezier(0, 0, 0.2, 1), height 250ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 0.03s linear, transform 0.12s cubic-bezier(0, 0, 0.2, 1), height 250ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 0.12s cubic-bezier(0, 0, 0.2, 1);
+ /* @alternate */
+ box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12);
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+ color: #000;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000);
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-medium, 4px);
+ /* @noflip */
+ transform-origin-left: top left;
+ /* @noflip */
+ transform-origin-right: top right;
+}
+.mdc-menu-surface:focus {
+ outline: none;
+}
+.mdc-menu-surface--animating-open {
+ display: inline-block;
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0;
+}
+.mdc-menu-surface--open {
+ display: inline-block;
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+}
+.mdc-menu-surface--animating-closed {
+ display: inline-block;
+ opacity: 0;
+ transition: opacity 0.075s linear;
+}
+[dir=rtl] .mdc-menu-surface, .mdc-menu-surface[dir=rtl] {
+ /* @noflip */
+ transform-origin-left: top right;
+ /* @noflip */
+ transform-origin-right: top left;
+}
+
+.mdc-menu-surface--anchor {
+ position: relative;
+ overflow: visible;
+}
+
+.mdc-menu-surface--fixed {
+ position: fixed;
+}
+
+.mdc-menu-surface--fullwidth {
+ width: 100%;
+}
+
+.mdc-radio {
+ padding: calc((40px - 20px) / 2);
+}
+.mdc-radio .mdc-radio__native-control:enabled:not(:checked) + .mdc-radio__background .mdc-radio__outer-circle {
+ border-color: rgba(0, 0, 0, 0.54);
+}
+.mdc-radio .mdc-radio__native-control:enabled:checked + .mdc-radio__background .mdc-radio__outer-circle {
+ border-color: #018786;
+ /* @alternate */
+ border-color: var(--mdc-theme-secondary, #018786);
+}
+.mdc-radio .mdc-radio__native-control:enabled + .mdc-radio__background .mdc-radio__inner-circle {
+ border-color: #018786;
+ /* @alternate */
+ border-color: var(--mdc-theme-secondary, #018786);
+}
+.mdc-radio [aria-disabled=true] .mdc-radio__native-control:not(:checked) + .mdc-radio__background .mdc-radio__outer-circle,
+.mdc-radio .mdc-radio__native-control:disabled:not(:checked) + .mdc-radio__background .mdc-radio__outer-circle {
+ border-color: rgba(0, 0, 0, 0.38);
+}
+.mdc-radio [aria-disabled=true] .mdc-radio__native-control:checked + .mdc-radio__background .mdc-radio__outer-circle,
+.mdc-radio .mdc-radio__native-control:disabled:checked + .mdc-radio__background .mdc-radio__outer-circle {
+ border-color: rgba(0, 0, 0, 0.38);
+}
+.mdc-radio [aria-disabled=true] .mdc-radio__native-control + .mdc-radio__background .mdc-radio__inner-circle,
+.mdc-radio .mdc-radio__native-control:disabled + .mdc-radio__background .mdc-radio__inner-circle {
+ border-color: rgba(0, 0, 0, 0.38);
+}
+.mdc-radio .mdc-radio__background::before {
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-theme-secondary, #018786);
+}
+.mdc-radio .mdc-radio__background::before {
+ top: calc(-1 * (40px - 20px) / 2);
+ left: calc(-1 * (40px - 20px) / 2);
+ width: 40px;
+ height: 40px;
+}
+.mdc-radio .mdc-radio__native-control {
+ top: calc((40px - 40px) / 2);
+ right: calc((40px - 40px) / 2);
+ left: calc((40px - 40px) / 2);
+ width: 40px;
+ height: 40px;
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-radio [aria-disabled=true] .mdc-radio__native-control:not(:checked) + .mdc-radio__background .mdc-radio__outer-circle,
+.mdc-radio .mdc-radio__native-control:disabled:not(:checked) + .mdc-radio__background .mdc-radio__outer-circle {
+ border-color: GrayText;
+ }
+ .mdc-radio [aria-disabled=true] .mdc-radio__native-control:checked + .mdc-radio__background .mdc-radio__outer-circle,
+.mdc-radio .mdc-radio__native-control:disabled:checked + .mdc-radio__background .mdc-radio__outer-circle {
+ border-color: GrayText;
+ }
+ .mdc-radio [aria-disabled=true] .mdc-radio__native-control + .mdc-radio__background .mdc-radio__inner-circle,
+.mdc-radio .mdc-radio__native-control:disabled + .mdc-radio__background .mdc-radio__inner-circle {
+ border-color: GrayText;
+ }
+}
+
+.mdc-radio {
+ display: inline-block;
+ position: relative;
+ flex: 0 0 auto;
+ box-sizing: content-box;
+ width: 20px;
+ height: 20px;
+ cursor: pointer;
+ /* @alternate */
+ will-change: opacity, transform, border-color, color;
+}
+.mdc-radio__background {
+ display: inline-block;
+ position: relative;
+ box-sizing: border-box;
+ width: 20px;
+ height: 20px;
+}
+.mdc-radio__background::before {
+ position: absolute;
+ -webkit-transform: scale(0, 0);
+ transform: scale(0, 0);
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+ transition: opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1), transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1), transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+.mdc-radio__outer-circle {
+ position: absolute;
+ top: 0;
+ left: 0;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ border-width: 2px;
+ border-style: solid;
+ border-radius: 50%;
+ transition: border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+.mdc-radio__inner-circle {
+ position: absolute;
+ top: 0;
+ left: 0;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ -webkit-transform: scale(0, 0);
+ transform: scale(0, 0);
+ border-width: 10px;
+ border-style: solid;
+ border-radius: 50%;
+ transition: border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1), border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+ transition: transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1), border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);
+}
+.mdc-radio__native-control {
+ position: absolute;
+ margin: 0;
+ padding: 0;
+ opacity: 0;
+ cursor: inherit;
+ z-index: 1;
+}
+.mdc-radio--touch {
+ margin-top: 4px;
+ margin-bottom: 4px;
+ margin-right: 4px;
+ margin-left: 4px;
+}
+.mdc-radio--touch .mdc-radio__native-control {
+ top: calc((40px - 48px) / 2);
+ right: calc((40px - 48px) / 2);
+ left: calc((40px - 48px) / 2);
+ width: 48px;
+ height: 48px;
+}
+
+.mdc-radio__native-control:checked + .mdc-radio__background,
+.mdc-radio__native-control:disabled + .mdc-radio__background {
+ transition: opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+.mdc-radio__native-control:checked + .mdc-radio__background .mdc-radio__outer-circle,
+.mdc-radio__native-control:disabled + .mdc-radio__background .mdc-radio__outer-circle {
+ transition: border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+.mdc-radio__native-control:checked + .mdc-radio__background .mdc-radio__inner-circle,
+.mdc-radio__native-control:disabled + .mdc-radio__background .mdc-radio__inner-circle {
+ transition: border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1), border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1), border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.mdc-radio--disabled {
+ cursor: default;
+ pointer-events: none;
+}
+
+.mdc-radio__native-control:checked + .mdc-radio__background .mdc-radio__inner-circle {
+ -webkit-transform: scale(0.5);
+ transform: scale(0.5);
+ transition: border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1), border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1), border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.mdc-radio__native-control:disabled + .mdc-radio__background,
+[aria-disabled=true] .mdc-radio__native-control + .mdc-radio__background {
+ cursor: default;
+}
+
+.mdc-radio__native-control:focus + .mdc-radio__background::before {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 0.12;
+ transition: opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.mdc-radio {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-radio .mdc-radio__ripple::before,
+.mdc-radio .mdc-radio__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-radio .mdc-radio__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-radio .mdc-radio__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-radio.mdc-ripple-upgraded--unbounded .mdc-radio__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-radio.mdc-ripple-upgraded--foreground-activation .mdc-radio__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-radio.mdc-ripple-upgraded--foreground-deactivation .mdc-radio__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-radio .mdc-radio__ripple::before,
+.mdc-radio .mdc-radio__ripple::after {
+ top: calc(50% - 50%);
+ /* @noflip */
+ left: calc(50% - 50%);
+ width: 100%;
+ height: 100%;
+}
+.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::before,
+.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after {
+ top: var(--mdc-ripple-top, calc(50% - 50%));
+ /* @noflip */
+ left: var(--mdc-ripple-left, calc(50% - 50%));
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-radio .mdc-radio__ripple::before, .mdc-radio .mdc-radio__ripple::after {
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786));
+}
+.mdc-radio:hover .mdc-radio__ripple::before, .mdc-radio.mdc-ripple-surface--hover .mdc-radio__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-radio.mdc-ripple-upgraded--background-focused .mdc-radio__ripple::before, .mdc-radio:not(.mdc-ripple-upgraded):focus .mdc-radio__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-radio:not(.mdc-ripple-upgraded) .mdc-radio__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-radio:not(.mdc-ripple-upgraded):active .mdc-radio__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-radio.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-radio.mdc-ripple-upgraded .mdc-radio__background::before, .mdc-radio.mdc-ripple-upgraded--background-focused .mdc-radio__background::before {
+ content: none;
+}
+
+.mdc-radio__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+.mdc-ripple-surface {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+ position: relative;
+ outline: none;
+ overflow: hidden;
+}
+.mdc-ripple-surface::before, .mdc-ripple-surface::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-ripple-surface::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-ripple-surface::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-ripple-surface.mdc-ripple-upgraded::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-ripple-surface.mdc-ripple-upgraded::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-ripple-surface.mdc-ripple-upgraded--unbounded::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-ripple-surface.mdc-ripple-upgraded--foreground-activation::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-ripple-surface.mdc-ripple-upgraded--foreground-deactivation::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-ripple-surface::before, .mdc-ripple-surface::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-ripple-surface.mdc-ripple-upgraded::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+
+.mdc-ripple-surface[data-mdc-ripple-is-unbounded],
+.mdc-ripple-upgraded--unbounded {
+ overflow: visible;
+}
+.mdc-ripple-surface[data-mdc-ripple-is-unbounded]::before, .mdc-ripple-surface[data-mdc-ripple-is-unbounded]::after,
+.mdc-ripple-upgraded--unbounded::before,
+.mdc-ripple-upgraded--unbounded::after {
+ top: calc(50% - 50%);
+ /* @noflip */
+ left: calc(50% - 50%);
+ width: 100%;
+ height: 100%;
+}
+.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::before, .mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::after,
+.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::before,
+.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::after {
+ top: var(--mdc-ripple-top, calc(50% - 50%));
+ /* @noflip */
+ left: var(--mdc-ripple-left, calc(50% - 50%));
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::after,
+.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+
+.mdc-ripple-surface::before, .mdc-ripple-surface::after {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #000);
+}
+.mdc-ripple-surface:hover::before, .mdc-ripple-surface.mdc-ripple-surface--hover::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-ripple-surface.mdc-ripple-upgraded--background-focused::before, .mdc-ripple-surface:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-ripple-surface:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-ripple-surface:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-ripple-surface.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+
+.mdc-segmented-button {
+ display: inline-block;
+ font-size: 0;
+}
+
+.mdc-segmented-button__segment {
+ border-color: rgba(0, 0, 0, 0.12);
+ /* @alternate */
+ border-color: var(--mdc-segmented-button-outline-color, rgba(0, 0, 0, 0.12));
+}
+
+.mdc-segmented-button__segment {
+ color: rgba(0, 0, 0, 0.6);
+ /* @alternate */
+ color: var(--mdc-segmented-button-unselected-ink-color, rgba(0, 0, 0, 0.6));
+}
+
+.mdc-segmented-button__segment {
+ background-color: white;
+ /* @alternate */
+ background-color: var(--mdc-segmented-button-unselected-container-fill-color, white);
+}
+
+.mdc-segmented-button__segment--selected {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-segmented-button-selected-ink-color, #6200ee);
+}
+
+.mdc-segmented-button__segment--selected {
+ background-color: rgba(98, 0, 238, 0.08);
+ /* @alternate */
+ background-color: var(--mdc-segmented-button-selected-container-fill-color, rgba(98, 0, 238, 0.08));
+}
+
+.mdc-segmented-button__segment {
+ /* @alternate */
+ position: relative;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-button-font-size, 0.875rem);
+ line-height: 2.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-button-line-height, 2.25rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-button-font-weight, 500);
+ letter-spacing: 0.0892857143em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-button-letter-spacing, 0.0892857143em);
+ text-decoration: none;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-button-text-transform, uppercase);
+ display: inline-flex;
+ vertical-align: top;
+ align-items: center;
+ height: 36px;
+ min-width: 48px;
+ padding: 0 12px;
+ border-width: 1px 0 1px 1px;
+}
+.mdc-segmented-button__segment .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.mdc-segmented-button__segment:hover {
+ cursor: pointer;
+}
+.mdc-segmented-button__segment:focus {
+ outline-width: 0;
+}
+.mdc-segmented-button__segment:first-child {
+ border-radius: 4px 0 0 4px;
+}
+.mdc-segmented-button__segment:last-child {
+ border-right-width: 1px;
+ border-radius: 0 4px 4px 0;
+}
+.mdc-segmented-button__segment .mdc-segmented-button__segment__touch {
+ position: absolute;
+ top: 50%;
+ height: 48px;
+ left: 0;
+ right: 0;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+}
+.mdc-segmented-button__segment .mdc-segmented-button__segment--touch {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+.mdc-touch-target-wrapper .mdc-segmented-button__segment {
+ border-radius: 0;
+ border-right-width: 0;
+}
+.mdc-touch-target-wrapper:first-child .mdc-segmented-button__segment {
+ border-radius: 4px 0 0 4px;
+}
+.mdc-touch-target-wrapper:last-child .mdc-segmented-button__segment {
+ border-right-width: 1px;
+ border-radius: 0 4px 4px 0;
+}
+
+.mdc-segmented-button__icon {
+ width: 24px;
+ font-size: 18px;
+}
+
+.mdc-segmented-button__icon + .mdc-segmented-button__label {
+ padding-left: 6px;
+}
+
+.mdc-segmented-button__segment {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+ overflow: hidden;
+}
+.mdc-segmented-button__segment .mdc-segmented-button__ripple::before,
+.mdc-segmented-button__segment .mdc-segmented-button__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-segmented-button__segment .mdc-segmented-button__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-segmented-button__segment .mdc-segmented-button__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-segmented-button__segment.mdc-ripple-upgraded .mdc-segmented-button__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-segmented-button__segment.mdc-ripple-upgraded .mdc-segmented-button__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-segmented-button__segment.mdc-ripple-upgraded--unbounded .mdc-segmented-button__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-segmented-button__segment.mdc-ripple-upgraded--foreground-activation .mdc-segmented-button__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-segmented-button__segment.mdc-ripple-upgraded--foreground-deactivation .mdc-segmented-button__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-segmented-button__segment .mdc-segmented-button__ripple::before,
+.mdc-segmented-button__segment .mdc-segmented-button__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-segmented-button__segment.mdc-ripple-upgraded .mdc-segmented-button__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-segmented-button__segment .mdc-segmented-button__ripple::before, .mdc-segmented-button__segment .mdc-segmented-button__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #6200ee);
+}
+.mdc-segmented-button__segment:hover .mdc-segmented-button__ripple::before, .mdc-segmented-button__segment.mdc-ripple-surface--hover .mdc-segmented-button__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-segmented-button__segment.mdc-ripple-upgraded--background-focused .mdc-segmented-button__ripple::before, .mdc-segmented-button__segment.mdc-ripple-upgraded:focus-within .mdc-segmented-button__ripple::before, .mdc-segmented-button__segment:not(.mdc-ripple-upgraded):focus .mdc-segmented-button__ripple::before, .mdc-segmented-button__segment:not(.mdc-ripple-upgraded):focus-within .mdc-segmented-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-segmented-button__segment:not(.mdc-ripple-upgraded) .mdc-segmented-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-segmented-button__segment:not(.mdc-ripple-upgraded):active .mdc-segmented-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-segmented-button__segment.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-segmented-button__segment .mdc-segmented-button__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+.mdc-slider__thumb {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-slider__thumb::before, .mdc-slider__thumb::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-slider__thumb::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-slider__thumb::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-slider__thumb.mdc-ripple-upgraded::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-slider__thumb.mdc-ripple-upgraded::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-slider__thumb.mdc-ripple-upgraded--unbounded::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-slider__thumb.mdc-ripple-upgraded--foreground-activation::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-slider__thumb.mdc-ripple-upgraded--foreground-deactivation::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-slider__thumb::before, .mdc-slider__thumb::after {
+ top: calc(50% - 50%);
+ /* @noflip */
+ left: calc(50% - 50%);
+ width: 100%;
+ height: 100%;
+}
+.mdc-slider__thumb.mdc-ripple-upgraded::before, .mdc-slider__thumb.mdc-ripple-upgraded::after {
+ top: var(--mdc-ripple-top, calc(50% - 50%));
+ /* @noflip */
+ left: var(--mdc-ripple-left, calc(50% - 50%));
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-slider__thumb.mdc-ripple-upgraded::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-slider__thumb::before, .mdc-slider__thumb::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-slider__thumb:hover::before, .mdc-slider__thumb.mdc-ripple-surface--hover::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-slider__thumb.mdc-ripple-upgraded--background-focused::before, .mdc-slider__thumb:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-slider__thumb:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-slider__thumb:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-slider__thumb.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+
+.mdc-slider {
+ cursor: pointer;
+ height: 48px;
+ margin: 0 24px;
+ position: relative;
+ touch-action: pan-y;
+}
+.mdc-slider .mdc-slider__track {
+ height: 4px;
+ position: absolute;
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+ width: 100%;
+}
+.mdc-slider .mdc-slider__track--active,
+.mdc-slider .mdc-slider__track--inactive {
+ display: flex;
+ height: 100%;
+ position: absolute;
+ width: 100%;
+}
+.mdc-slider .mdc-slider__track--active {
+ border-radius: 3px;
+ height: 6px;
+ overflow: hidden;
+ top: -1px;
+}
+.mdc-slider .mdc-slider__track--active_fill {
+ border-top: 6px solid;
+ box-sizing: border-box;
+ height: 100%;
+ width: 100%;
+ position: relative;
+ /* @noflip */
+ -webkit-transform-origin: left;
+ /* @noflip */
+ transform-origin: left;
+}
+[dir=rtl] .mdc-slider .mdc-slider__track--active_fill, .mdc-slider .mdc-slider__track--active_fill[dir=rtl] {
+ /* @noflip */
+ -webkit-transform-origin: right;
+ /* @noflip */
+ transform-origin: right;
+}
+
+.mdc-slider .mdc-slider__track--inactive {
+ border-radius: 2px;
+ height: 4px;
+ left: 0;
+ top: 0;
+}
+.mdc-slider .mdc-slider__track--inactive::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 1px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+.mdc-slider .mdc-slider__track--active_fill {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-slider.mdc-slider--disabled .mdc-slider__track--active_fill {
+ border-color: #000;
+ /* @alternate */
+ border-color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-slider .mdc-slider__track--inactive {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-theme-primary, #6200ee);
+ opacity: 0.24;
+}
+.mdc-slider.mdc-slider--disabled .mdc-slider__track--inactive {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-theme-on-surface, #000);
+ opacity: 0.24;
+}
+.mdc-slider .mdc-slider__value-indicator-container {
+ bottom: 44px;
+ /* @noflip */
+ left: 50%;
+ pointer-events: none;
+ position: absolute;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+}
+.mdc-slider .mdc-slider__value-indicator {
+ transition: -webkit-transform 100ms 0ms cubic-bezier(0.4, 0, 1, 1);
+ transition: transform 100ms 0ms cubic-bezier(0.4, 0, 1, 1);
+ transition: transform 100ms 0ms cubic-bezier(0.4, 0, 1, 1), -webkit-transform 100ms 0ms cubic-bezier(0.4, 0, 1, 1);
+ align-items: center;
+ border-radius: 4px;
+ display: flex;
+ height: 32px;
+ padding: 0 12px;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: bottom;
+ transform-origin: bottom;
+}
+.mdc-slider .mdc-slider__value-indicator::before {
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-top: 6px solid;
+ bottom: -5px;
+ content: "";
+ height: 0;
+ /* @noflip */
+ left: 50%;
+ position: absolute;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+ width: 0;
+}
+.mdc-slider .mdc-slider__value-indicator::after {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 1px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+.mdc-slider .mdc-slider__thumb--with-indicator .mdc-slider__value-indicator-container {
+ pointer-events: auto;
+}
+.mdc-slider .mdc-slider__thumb--with-indicator .mdc-slider__value-indicator {
+ transition: -webkit-transform 100ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: transform 100ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: transform 100ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 100ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ -webkit-transform: scale(1);
+ transform: scale(1);
+}
+@media (prefers-reduced-motion) {
+ .mdc-slider .mdc-slider__value-indicator,
+.mdc-slider .mdc-slider__thumb--with-indicator .mdc-slider__value-indicator {
+ transition: none;
+ }
+}
+.mdc-slider .mdc-slider__value-indicator-text {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle2-font-size, 0.875rem);
+ line-height: 1.375rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle2-line-height, 1.375rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle2-font-weight, 500);
+ letter-spacing: 0.0071428571em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle2-text-transform, inherit);
+}
+.mdc-slider .mdc-slider__value-indicator {
+ background-color: #000;
+ opacity: 0.6;
+}
+.mdc-slider .mdc-slider__value-indicator::before {
+ border-top-color: #000;
+}
+.mdc-slider .mdc-slider__value-indicator {
+ color: #fff;
+ /* @alternate */
+ color: var(--mdc-theme-on-primary, #fff);
+}
+.mdc-slider .mdc-slider__thumb {
+ display: flex;
+ height: 48px;
+ /* @noflip */
+ left: -24px;
+ outline: none;
+ position: absolute;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ width: 48px;
+}
+.mdc-slider .mdc-slider__thumb--top {
+ z-index: 1;
+}
+.mdc-slider .mdc-slider__thumb--top .mdc-slider__thumb-knob, .mdc-slider .mdc-slider__thumb--top.mdc-slider__thumb:hover .mdc-slider__thumb-knob, .mdc-slider .mdc-slider__thumb--top.mdc-slider__thumb--focused .mdc-slider__thumb-knob {
+ border-style: solid;
+ border-width: 1px;
+ box-sizing: content-box;
+}
+.mdc-slider .mdc-slider__thumb-knob {
+ /* @alternate */
+ box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12);
+ border: 10px solid;
+ border-radius: 50%;
+ box-sizing: border-box;
+ height: 20px;
+ /* @noflip */
+ left: 50%;
+ position: absolute;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ width: 20px;
+}
+.mdc-slider .mdc-slider__thumb-knob {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-theme-primary, #6200ee);
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-slider .mdc-slider__thumb--top .mdc-slider__thumb-knob, .mdc-slider .mdc-slider__thumb--top.mdc-slider__thumb:hover .mdc-slider__thumb-knob, .mdc-slider .mdc-slider__thumb--top.mdc-slider__thumb--focused .mdc-slider__thumb-knob {
+ border-color: #fff;
+}
+.mdc-slider.mdc-slider--disabled .mdc-slider__thumb-knob {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-theme-on-surface, #000);
+ border-color: #000;
+ /* @alternate */
+ border-color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-slider.mdc-slider--disabled .mdc-slider__thumb--top .mdc-slider__thumb-knob, .mdc-slider.mdc-slider--disabled .mdc-slider__thumb--top.mdc-slider__thumb:hover .mdc-slider__thumb-knob, .mdc-slider.mdc-slider--disabled .mdc-slider__thumb--top.mdc-slider__thumb--focused .mdc-slider__thumb-knob {
+ border-color: #fff;
+}
+.mdc-slider .mdc-slider__thumb::before, .mdc-slider .mdc-slider__thumb::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-slider .mdc-slider__thumb:hover::before, .mdc-slider .mdc-slider__thumb.mdc-ripple-surface--hover::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-slider .mdc-slider__thumb.mdc-ripple-upgraded--background-focused::before, .mdc-slider .mdc-slider__thumb:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-slider .mdc-slider__thumb:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-slider .mdc-slider__thumb:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-slider .mdc-slider__thumb.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-slider .mdc-slider__tick-marks {
+ align-items: center;
+ box-sizing: border-box;
+ display: flex;
+ height: 100%;
+ justify-content: space-between;
+ padding: 0 1px;
+ position: absolute;
+ width: 100%;
+}
+.mdc-slider .mdc-slider__tick-mark--active,
+.mdc-slider .mdc-slider__tick-mark--inactive {
+ border-radius: 50%;
+ height: 2px;
+ width: 2px;
+}
+.mdc-slider .mdc-slider__tick-mark--active {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-on-primary, #fff);
+ opacity: 0.6;
+}
+.mdc-slider.mdc-slider--disabled .mdc-slider__tick-mark--active {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-on-primary, #fff);
+ opacity: 0.6;
+}
+.mdc-slider .mdc-slider__tick-mark--inactive {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-theme-primary, #6200ee);
+ opacity: 0.6;
+}
+.mdc-slider.mdc-slider--disabled .mdc-slider__tick-mark--inactive {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-theme-on-surface, #000);
+ opacity: 0.6;
+}
+.mdc-slider.mdc-slider--disabled {
+ opacity: 0.38;
+ cursor: auto;
+}
+.mdc-slider.mdc-slider--disabled .mdc-slider__thumb {
+ pointer-events: none;
+}
+.mdc-slider--discrete .mdc-slider__thumb,
+.mdc-slider--discrete .mdc-slider__track--active_fill {
+ transition: -webkit-transform 80ms ease;
+ transition: transform 80ms ease;
+ transition: transform 80ms ease, -webkit-transform 80ms ease;
+}
+@media (prefers-reduced-motion) {
+ .mdc-slider--discrete .mdc-slider__thumb,
+.mdc-slider--discrete .mdc-slider__track--active_fill {
+ transition: none;
+ }
+}
+
+.mdc-slider__input {
+ cursor: pointer;
+ left: 0;
+ margin: 0;
+ height: 100%;
+ opacity: 0;
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+
+.mdc-snackbar {
+ z-index: 8;
+ margin: 8px;
+ display: none;
+ position: fixed;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ pointer-events: none;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+.mdc-snackbar__surface {
+ background-color: #333333;
+}
+
+.mdc-snackbar__label {
+ color: rgba(255, 255, 255, 0.87);
+}
+
+.mdc-snackbar__surface {
+ min-width: 344px;
+}
+@media (max-width: 480px), (max-width: 344px) {
+ .mdc-snackbar__surface {
+ min-width: 100%;
+ }
+}
+
+.mdc-snackbar__surface {
+ max-width: 672px;
+}
+
+.mdc-snackbar__surface {
+ /* @alternate */
+ box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12);
+}
+
+.mdc-snackbar__surface {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+
+.mdc-snackbar--opening,
+.mdc-snackbar--open,
+.mdc-snackbar--closing {
+ display: flex;
+}
+
+.mdc-snackbar--open .mdc-snackbar__label,
+.mdc-snackbar--open .mdc-snackbar__actions {
+ visibility: visible;
+}
+
+.mdc-snackbar--leading {
+ justify-content: flex-start;
+}
+
+.mdc-snackbar--stacked .mdc-snackbar__label {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 8px;
+ padding-bottom: 12px;
+}
+[dir=rtl] .mdc-snackbar--stacked .mdc-snackbar__label, .mdc-snackbar--stacked .mdc-snackbar__label[dir=rtl] {
+ /* @noflip */
+ padding-left: 8px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-snackbar--stacked .mdc-snackbar__surface {
+ flex-direction: column;
+ align-items: flex-start;
+}
+.mdc-snackbar--stacked .mdc-snackbar__actions {
+ align-self: flex-end;
+ margin-bottom: 8px;
+}
+
+.mdc-snackbar__surface {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ box-sizing: border-box;
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0;
+}
+.mdc-snackbar__surface::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 1px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+[dir=rtl] .mdc-snackbar__surface, .mdc-snackbar__surface[dir=rtl] {
+ /* @noflip */
+ padding-left: 8px;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-snackbar--open .mdc-snackbar__surface {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+ pointer-events: auto;
+ transition: opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+.mdc-snackbar--closing .mdc-snackbar__surface {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ transition: opacity 75ms 0ms cubic-bezier(0.4, 0, 1, 1);
+}
+
+.mdc-snackbar__label {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 8px;
+ width: 100%;
+ flex-grow: 1;
+ box-sizing: border-box;
+ margin: 0;
+ visibility: hidden;
+ padding-top: 14px;
+ padding-bottom: 14px;
+}
+[dir=rtl] .mdc-snackbar__label, .mdc-snackbar__label[dir=rtl] {
+ /* @noflip */
+ padding-left: 8px;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-snackbar__label::before {
+ display: inline;
+ content: attr(data-mdc-snackbar-label-text);
+}
+
+.mdc-snackbar__actions {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ box-sizing: border-box;
+ visibility: hidden;
+}
+
+.mdc-snackbar__action:not(:disabled) {
+ color: #bb86fc;
+}
+.mdc-snackbar__action::before, .mdc-snackbar__action::after {
+ background-color: #bb86fc;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #bb86fc);
+}
+.mdc-snackbar__action:hover::before, .mdc-snackbar__action.mdc-ripple-surface--hover::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.08);
+}
+.mdc-snackbar__action.mdc-ripple-upgraded--background-focused::before, .mdc-snackbar__action:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+.mdc-snackbar__action:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-snackbar__action:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-snackbar__action.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+
+.mdc-snackbar__dismiss {
+ color: rgba(255, 255, 255, 0.87);
+}
+.mdc-snackbar__dismiss .mdc-icon-button__ripple::before, .mdc-snackbar__dismiss .mdc-icon-button__ripple::after {
+ background-color: rgba(255, 255, 255, 0.87);
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, rgba(255, 255, 255, 0.87));
+}
+.mdc-snackbar__dismiss:hover .mdc-icon-button__ripple::before, .mdc-snackbar__dismiss.mdc-ripple-surface--hover .mdc-icon-button__ripple::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.08);
+}
+.mdc-snackbar__dismiss.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before, .mdc-snackbar__dismiss:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+.mdc-snackbar__dismiss:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-snackbar__dismiss:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-snackbar__dismiss.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+
+.mdc-snackbar__dismiss.mdc-snackbar__dismiss {
+ width: 36px;
+ height: 36px;
+ padding: 6px;
+ font-size: 18px;
+}
+
+.mdc-snackbar__action + .mdc-snackbar__dismiss {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 0;
+}
+[dir=rtl] .mdc-snackbar__action + .mdc-snackbar__dismiss, .mdc-snackbar__action + .mdc-snackbar__dismiss[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: 8px;
+}
+
+.mdc-switch__thumb-underlay {
+ /* @noflip */
+ left: -14px;
+ /* @noflip */
+ right: initial;
+ top: -17px;
+ width: 48px;
+ height: 48px;
+}
+[dir=rtl] .mdc-switch__thumb-underlay, .mdc-switch__thumb-underlay[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: -14px;
+}
+
+.mdc-switch__native-control {
+ width: 64px;
+ height: 48px;
+}
+
+.mdc-switch {
+ display: inline-block;
+ position: relative;
+ outline: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.mdc-switch.mdc-switch--checked .mdc-switch__track {
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-theme-secondary, #018786);
+}
+.mdc-switch.mdc-switch--checked .mdc-switch__thumb {
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-theme-secondary, #018786);
+ border-color: #018786;
+ /* @alternate */
+ border-color: var(--mdc-theme-secondary, #018786);
+}
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__track {
+ background-color: #000;
+ /* @alternate */
+ background-color: var(--mdc-theme-on-surface, #000);
+}
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+ border-color: #fff;
+ /* @alternate */
+ border-color: var(--mdc-theme-surface, #fff);
+}
+
+.mdc-switch__native-control {
+ /* @noflip */
+ left: 0;
+ /* @noflip */
+ right: initial;
+ position: absolute;
+ top: 0;
+ margin: 0;
+ opacity: 0;
+ cursor: pointer;
+ pointer-events: auto;
+ transition: -webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 90ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 90ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+[dir=rtl] .mdc-switch__native-control, .mdc-switch__native-control[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 0;
+}
+
+.mdc-switch__track {
+ box-sizing: border-box;
+ width: 36px;
+ height: 14px;
+ border: 1px solid transparent;
+ border-radius: 7px;
+ opacity: 0.38;
+ transition: opacity 90ms cubic-bezier(0.4, 0, 0.2, 1), background-color 90ms cubic-bezier(0.4, 0, 0.2, 1), border-color 90ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-switch__thumb-underlay {
+ display: flex;
+ position: absolute;
+ align-items: center;
+ justify-content: center;
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ transition: background-color 90ms cubic-bezier(0.4, 0, 0.2, 1), border-color 90ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 90ms cubic-bezier(0.4, 0, 0.2, 1), background-color 90ms cubic-bezier(0.4, 0, 0.2, 1), border-color 90ms cubic-bezier(0.4, 0, 0.2, 1);
+ transition: transform 90ms cubic-bezier(0.4, 0, 0.2, 1), background-color 90ms cubic-bezier(0.4, 0, 0.2, 1), border-color 90ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-switch__thumb {
+ /* @alternate */
+ box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
+ box-sizing: border-box;
+ width: 20px;
+ height: 20px;
+ border: 10px solid;
+ border-radius: 50%;
+ pointer-events: none;
+ z-index: 1;
+}
+
+.mdc-switch--checked .mdc-switch__track {
+ opacity: 0.54;
+}
+.mdc-switch--checked .mdc-switch__thumb-underlay {
+ -webkit-transform: translateX(16px);
+ transform: translateX(16px);
+}
+[dir=rtl] .mdc-switch--checked .mdc-switch__thumb-underlay, .mdc-switch--checked .mdc-switch__thumb-underlay[dir=rtl] {
+ -webkit-transform: translateX(-16px);
+ transform: translateX(-16px);
+}
+
+.mdc-switch--checked .mdc-switch__native-control {
+ -webkit-transform: translateX(-16px);
+ transform: translateX(-16px);
+}
+[dir=rtl] .mdc-switch--checked .mdc-switch__native-control, .mdc-switch--checked .mdc-switch__native-control[dir=rtl] {
+ -webkit-transform: translateX(16px);
+ transform: translateX(16px);
+}
+
+.mdc-switch--disabled {
+ opacity: 0.38;
+ pointer-events: none;
+}
+.mdc-switch--disabled .mdc-switch__thumb {
+ border-width: 1px;
+}
+.mdc-switch--disabled .mdc-switch__native-control {
+ cursor: default;
+ pointer-events: none;
+}
+
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay::before, .mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay::after {
+ background-color: #9e9e9e;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, #9e9e9e);
+}
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:hover::before, .mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay.mdc-ripple-surface--hover::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.08);
+}
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay.mdc-ripple-upgraded--background-focused::before, .mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+
+.mdc-switch__thumb-underlay {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-switch__thumb-underlay::before, .mdc-switch__thumb-underlay::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-switch__thumb-underlay::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-switch__thumb-underlay::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded--unbounded::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded--foreground-activation::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded--foreground-deactivation::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-switch__thumb-underlay::before, .mdc-switch__thumb-underlay::after {
+ top: calc(50% - 50%);
+ /* @noflip */
+ left: calc(50% - 50%);
+ width: 100%;
+ height: 100%;
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded::before, .mdc-switch__thumb-underlay.mdc-ripple-upgraded::after {
+ top: var(--mdc-ripple-top, calc(50% - 50%));
+ /* @noflip */
+ left: var(--mdc-ripple-left, calc(50% - 50%));
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-switch__thumb-underlay::before, .mdc-switch__thumb-underlay::after {
+ background-color: #018786;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786));
+}
+.mdc-switch__thumb-underlay:hover::before, .mdc-switch__thumb-underlay.mdc-ripple-surface--hover::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded--background-focused::before, .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-switch__thumb-underlay.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+
+.mdc-tab {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-button-font-size, 0.875rem);
+ line-height: 2.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-button-line-height, 2.25rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-button-font-weight, 500);
+ letter-spacing: 0.0892857143em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-button-letter-spacing, 0.0892857143em);
+ text-decoration: none;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-button-text-transform, uppercase);
+ position: relative;
+}
+.mdc-tab .mdc-tab__text-label {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-tab .mdc-tab__icon {
+ color: rgba(0, 0, 0, 0.54);
+ fill: currentColor;
+}
+
+.mdc-tab__content {
+ position: relative;
+}
+
+.mdc-tab__icon {
+ width: 24px;
+ height: 24px;
+ font-size: 24px;
+}
+
+.mdc-tab--active .mdc-tab__text-label {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-tab--active .mdc-tab__icon {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+ fill: currentColor;
+}
+
+.mdc-tab {
+ background: none;
+}
+
+.mdc-tab {
+ min-width: 90px;
+ padding-right: 24px;
+ padding-left: 24px;
+ display: flex;
+ flex: 1 0 auto;
+ justify-content: center;
+ box-sizing: border-box;
+ margin: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ border: none;
+ outline: none;
+ text-align: center;
+ white-space: nowrap;
+ cursor: pointer;
+ -webkit-appearance: none;
+ z-index: 1;
+}
+.mdc-tab::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+
+.mdc-tab--min-width {
+ flex: 0 1 auto;
+}
+
+.mdc-tab__content {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: inherit;
+ pointer-events: none;
+}
+
+.mdc-tab__text-label {
+ transition: 150ms color linear;
+ display: inline-block;
+ line-height: 1;
+ z-index: 2;
+}
+
+.mdc-tab__icon {
+ transition: 150ms color linear;
+ z-index: 2;
+}
+
+.mdc-tab--stacked .mdc-tab__content {
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+.mdc-tab--stacked .mdc-tab__text-label {
+ padding-top: 6px;
+ padding-bottom: 4px;
+}
+
+.mdc-tab--active .mdc-tab__text-label,
+.mdc-tab--active .mdc-tab__icon {
+ transition-delay: 100ms;
+}
+
+.mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon + .mdc-tab__text-label {
+ /* @noflip */
+ padding-left: 8px;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon + .mdc-tab__text-label, .mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon + .mdc-tab__text-label[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 8px;
+}
+
+.mdc-tab {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+.mdc-tab .mdc-tab__ripple::before,
+.mdc-tab .mdc-tab__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-tab .mdc-tab__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-tab .mdc-tab__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-tab.mdc-ripple-upgraded--unbounded .mdc-tab__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-tab.mdc-ripple-upgraded--foreground-activation .mdc-tab__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-tab.mdc-ripple-upgraded--foreground-deactivation .mdc-tab__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-tab .mdc-tab__ripple::before,
+.mdc-tab .mdc-tab__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+.mdc-tab .mdc-tab__ripple::before, .mdc-tab .mdc-tab__ripple::after {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee));
+}
+.mdc-tab:hover .mdc-tab__ripple::before, .mdc-tab.mdc-ripple-surface--hover .mdc-tab__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-tab.mdc-ripple-upgraded--background-focused .mdc-tab__ripple::before, .mdc-tab:not(.mdc-ripple-upgraded):focus .mdc-tab__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-tab:not(.mdc-ripple-upgraded) .mdc-tab__ripple::after {
+ transition: opacity 150ms linear;
+}
+.mdc-tab:not(.mdc-ripple-upgraded):active .mdc-tab__ripple::after {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+.mdc-tab.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.12);
+}
+
+.mdc-tab__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ will-change: transform, opacity;
+}
+
+/**
+ * @license
+ * Copyright 2018 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+.mdc-tab-bar {
+ width: 100%;
+}
+
+.mdc-tab {
+ height: 48px;
+}
+
+.mdc-tab--stacked {
+ height: 72px;
+}
+
+/**
+ * @license
+ * Copyright 2018 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+.mdc-tab-indicator .mdc-tab-indicator__content--underline {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-tab-indicator .mdc-tab-indicator__content--icon {
+ color: #018786;
+ /* @alternate */
+ color: var(--mdc-theme-secondary, #018786);
+}
+.mdc-tab-indicator .mdc-tab-indicator__content--underline {
+ border-top-width: 2px;
+}
+.mdc-tab-indicator .mdc-tab-indicator__content--icon {
+ height: 34px;
+ font-size: 34px;
+}
+
+.mdc-tab-indicator {
+ display: flex;
+ position: absolute;
+ top: 0;
+ left: 0;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ z-index: 1;
+}
+
+.mdc-tab-indicator__content {
+ -webkit-transform-origin: left;
+ transform-origin: left;
+ opacity: 0;
+}
+
+.mdc-tab-indicator__content--underline {
+ align-self: flex-end;
+ box-sizing: border-box;
+ width: 100%;
+ border-top-style: solid;
+}
+
+.mdc-tab-indicator__content--icon {
+ align-self: center;
+ margin: 0 auto;
+}
+
+.mdc-tab-indicator--active .mdc-tab-indicator__content {
+ opacity: 1;
+}
+
+.mdc-tab-indicator .mdc-tab-indicator__content {
+ transition: 250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1);
+ transition: 250ms transform cubic-bezier(0.4, 0, 0.2, 1);
+ transition: 250ms transform cubic-bezier(0.4, 0, 0.2, 1), 250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-tab-indicator--no-transition .mdc-tab-indicator__content {
+ transition: none;
+}
+
+.mdc-tab-indicator--fade .mdc-tab-indicator__content {
+ transition: 150ms opacity linear;
+}
+
+.mdc-tab-indicator--active.mdc-tab-indicator--fade .mdc-tab-indicator__content {
+ transition-delay: 100ms;
+}
+
+/**
+ * @license
+ * Copyright 2018 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+.mdc-tab-scroller {
+ overflow-y: hidden;
+}
+.mdc-tab-scroller.mdc-tab-scroller--animating .mdc-tab-scroller__scroll-content {
+ transition: 250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1);
+ transition: 250ms transform cubic-bezier(0.4, 0, 0.2, 1);
+ transition: 250ms transform cubic-bezier(0.4, 0, 0.2, 1), 250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-tab-scroller__test {
+ position: absolute;
+ top: -9999px;
+ width: 100px;
+ height: 100px;
+ overflow-x: scroll;
+}
+
+.mdc-tab-scroller__scroll-area {
+ -webkit-overflow-scrolling: touch;
+ display: flex;
+ overflow-x: hidden;
+}
+
+.mdc-tab-scroller__scroll-area::-webkit-scrollbar,
+.mdc-tab-scroller__test::-webkit-scrollbar {
+ display: none;
+}
+
+.mdc-tab-scroller__scroll-area--scroll {
+ overflow-x: scroll;
+}
+
+.mdc-tab-scroller__scroll-content {
+ position: relative;
+ display: flex;
+ flex: 1 0 auto;
+ -webkit-transform: none;
+ transform: none;
+ will-change: transform;
+}
+
+.mdc-tab-scroller--align-start .mdc-tab-scroller__scroll-content {
+ justify-content: flex-start;
+}
+
+.mdc-tab-scroller--align-end .mdc-tab-scroller__scroll-content {
+ justify-content: flex-end;
+}
+
+.mdc-tab-scroller--align-center .mdc-tab-scroller__scroll-content {
+ justify-content: center;
+}
+
+.mdc-tab-scroller--animating .mdc-tab-scroller__scroll-area {
+ -webkit-overflow-scrolling: auto;
+}
+
+.mdc-text-field--filled {
+ --mdc-ripple-fg-size: 0;
+ --mdc-ripple-left: 0;
+ --mdc-ripple-top: 0;
+ --mdc-ripple-fg-scale: 1;
+ --mdc-ripple-fg-translate-end: 0;
+ --mdc-ripple-fg-translate-start: 0;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ will-change: transform, opacity;
+}
+.mdc-text-field--filled .mdc-text-field__ripple::before,
+.mdc-text-field--filled .mdc-text-field__ripple::after {
+ position: absolute;
+ border-radius: 50%;
+ opacity: 0;
+ pointer-events: none;
+ content: "";
+}
+.mdc-text-field--filled .mdc-text-field__ripple::before {
+ transition: opacity 15ms linear, background-color 15ms linear;
+ z-index: 1;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 1);
+}
+.mdc-text-field--filled .mdc-text-field__ripple::after {
+ z-index: 0;
+ /* @alternate */
+ z-index: var(--mdc-ripple-z-index, 0);
+}
+.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::before {
+ -webkit-transform: scale(var(--mdc-ripple-fg-scale, 1));
+ transform: scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::after {
+ top: 0;
+ /* @noflip */
+ left: 0;
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+}
+.mdc-text-field--filled.mdc-ripple-upgraded--unbounded .mdc-text-field__ripple::after {
+ top: var(--mdc-ripple-top, 0);
+ /* @noflip */
+ left: var(--mdc-ripple-left, 0);
+}
+.mdc-text-field--filled.mdc-ripple-upgraded--foreground-activation .mdc-text-field__ripple::after {
+ -webkit-animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+ animation: mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards;
+}
+.mdc-text-field--filled.mdc-ripple-upgraded--foreground-deactivation .mdc-text-field__ripple::after {
+ -webkit-animation: mdc-ripple-fg-opacity-out 150ms;
+ animation: mdc-ripple-fg-opacity-out 150ms;
+ -webkit-transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+ transform: translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));
+}
+.mdc-text-field--filled .mdc-text-field__ripple::before,
+.mdc-text-field--filled .mdc-text-field__ripple::after {
+ top: calc(50% - 100%);
+ /* @noflip */
+ left: calc(50% - 100%);
+ width: 200%;
+ height: 200%;
+}
+.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::after {
+ width: var(--mdc-ripple-fg-size, 100%);
+ height: var(--mdc-ripple-fg-size, 100%);
+}
+
+.mdc-text-field__ripple {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+}
+
+.mdc-text-field {
+ border-top-left-radius: 4px;
+ /* @alternate */
+ border-top-left-radius: var(--mdc-shape-small, 4px);
+ border-top-right-radius: 4px;
+ /* @alternate */
+ border-top-right-radius: var(--mdc-shape-small, 4px);
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+ display: inline-flex;
+ align-items: baseline;
+ padding: 0 16px;
+ position: relative;
+ box-sizing: border-box;
+ overflow: hidden;
+ /* @alternate */
+ will-change: opacity, transform, color;
+}
+.mdc-text-field:not(.mdc-text-field--disabled) .mdc-floating-label {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input {
+ color: rgba(0, 0, 0, 0.87);
+}
+@media all {
+ .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::-webkit-input-placeholder {
+ color: rgba(0, 0, 0, 0.54);
+ }
+ .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input:-ms-input-placeholder {
+ color: rgba(0, 0, 0, 0.54);
+ }
+ .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::-ms-input-placeholder {
+ color: rgba(0, 0, 0, 0.54);
+ }
+ .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::placeholder {
+ color: rgba(0, 0, 0, 0.54);
+ }
+}
+@media all {
+ .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input:-ms-input-placeholder {
+ color: rgba(0, 0, 0, 0.54);
+ }
+}
+.mdc-text-field .mdc-text-field__input {
+ caret-color: #6200ee;
+ /* @alternate */
+ caret-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-text-field:not(.mdc-text-field--disabled) + .mdc-text-field-helper-line .mdc-text-field-helper-text {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field-character-counter,
+.mdc-text-field:not(.mdc-text-field--disabled) + .mdc-text-field-helper-line .mdc-text-field-character-counter {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__icon--leading {
+ color: rgba(0, 0, 0, 0.54);
+}
+.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__icon--trailing {
+ color: rgba(0, 0, 0, 0.54);
+}
+.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--prefix {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--suffix {
+ color: rgba(0, 0, 0, 0.6);
+}
+.mdc-text-field .mdc-floating-label {
+ top: 50%;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+ pointer-events: none;
+}
+
+.mdc-text-field__input {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ height: 28px;
+ transition: opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ width: 100%;
+ min-width: 0;
+ border: none;
+ border-radius: 0;
+ background: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ padding: 0;
+}
+.mdc-text-field__input::-ms-clear {
+ display: none;
+}
+.mdc-text-field__input::-webkit-calendar-picker-indicator {
+ display: none;
+}
+.mdc-text-field__input:focus {
+ outline: none;
+}
+.mdc-text-field__input:invalid {
+ box-shadow: none;
+}
+@media all {
+ .mdc-text-field__input::-webkit-input-placeholder {
+ transition: opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ opacity: 0;
+ }
+ .mdc-text-field__input:-ms-input-placeholder {
+ transition: opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ opacity: 0;
+ }
+ .mdc-text-field__input::-ms-input-placeholder {
+ transition: opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ opacity: 0;
+ }
+ .mdc-text-field__input::placeholder {
+ transition: opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ opacity: 0;
+ }
+}
+@media all {
+ .mdc-text-field__input:-ms-input-placeholder {
+ transition: opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ opacity: 0;
+ }
+}
+@media all {
+ .mdc-text-field--no-label .mdc-text-field__input::-webkit-input-placeholder, .mdc-text-field--focused .mdc-text-field__input::-webkit-input-placeholder {
+ transition-delay: 40ms;
+ transition-duration: 110ms;
+ opacity: 1;
+ }
+ .mdc-text-field--no-label .mdc-text-field__input:-ms-input-placeholder, .mdc-text-field--focused .mdc-text-field__input:-ms-input-placeholder {
+ transition-delay: 40ms;
+ transition-duration: 110ms;
+ opacity: 1;
+ }
+ .mdc-text-field--no-label .mdc-text-field__input::-ms-input-placeholder, .mdc-text-field--focused .mdc-text-field__input::-ms-input-placeholder {
+ transition-delay: 40ms;
+ transition-duration: 110ms;
+ opacity: 1;
+ }
+ .mdc-text-field--no-label .mdc-text-field__input::placeholder, .mdc-text-field--focused .mdc-text-field__input::placeholder {
+ transition-delay: 40ms;
+ transition-duration: 110ms;
+ opacity: 1;
+ }
+}
+@media all {
+ .mdc-text-field--no-label .mdc-text-field__input:-ms-input-placeholder, .mdc-text-field--focused .mdc-text-field__input:-ms-input-placeholder {
+ transition-delay: 40ms;
+ transition-duration: 110ms;
+ opacity: 1;
+ }
+}
+
+.mdc-text-field__affix {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+ height: 28px;
+ transition: opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+ opacity: 0;
+ white-space: nowrap;
+}
+.mdc-text-field--label-floating .mdc-text-field__affix, .mdc-text-field--no-label .mdc-text-field__affix {
+ opacity: 1;
+}
+@supports (-webkit-hyphens: none) {
+ .mdc-text-field--outlined .mdc-text-field__affix {
+ align-items: center;
+ align-self: center;
+ display: inline-flex;
+ height: 100%;
+ }
+}
+
+.mdc-text-field__affix--prefix {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 2px;
+}
+[dir=rtl] .mdc-text-field__affix--prefix, .mdc-text-field__affix--prefix[dir=rtl] {
+ /* @noflip */
+ padding-left: 2px;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-text-field--end-aligned .mdc-text-field__affix--prefix {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 12px;
+}
+[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__affix--prefix, .mdc-text-field--end-aligned .mdc-text-field__affix--prefix[dir=rtl] {
+ /* @noflip */
+ padding-left: 12px;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-text-field__affix--suffix {
+ /* @noflip */
+ padding-left: 12px;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-text-field__affix--suffix, .mdc-text-field__affix--suffix[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 12px;
+}
+
+.mdc-text-field--end-aligned .mdc-text-field__affix--suffix {
+ /* @noflip */
+ padding-left: 2px;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__affix--suffix, .mdc-text-field--end-aligned .mdc-text-field__affix--suffix[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 2px;
+}
+
+.mdc-text-field--filled {
+ height: 56px;
+}
+.mdc-text-field--filled .mdc-text-field__ripple::before,
+.mdc-text-field--filled .mdc-text-field__ripple::after {
+ background-color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, rgba(0, 0, 0, 0.87));
+}
+.mdc-text-field--filled:hover .mdc-text-field__ripple::before, .mdc-text-field--filled.mdc-ripple-surface--hover .mdc-text-field__ripple::before {
+ opacity: 0.04;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.04);
+}
+.mdc-text-field--filled.mdc-ripple-upgraded--background-focused .mdc-text-field__ripple::before, .mdc-text-field--filled:not(.mdc-ripple-upgraded):focus .mdc-text-field__ripple::before {
+ transition-duration: 75ms;
+ opacity: 0.12;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.12);
+}
+.mdc-text-field--filled::before {
+ display: inline-block;
+ width: 0;
+ height: 40px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-text-field--filled:not(.mdc-text-field--disabled) {
+ background-color: whitesmoke;
+}
+.mdc-text-field--filled:not(.mdc-text-field--disabled) .mdc-line-ripple::before {
+ border-bottom-color: rgba(0, 0, 0, 0.42);
+}
+.mdc-text-field--filled:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before {
+ border-bottom-color: rgba(0, 0, 0, 0.87);
+}
+.mdc-text-field--filled .mdc-line-ripple::after {
+ border-bottom-color: #6200ee;
+ /* @alternate */
+ border-bottom-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-text-field--filled .mdc-floating-label {
+ /* @noflip */
+ left: 16px;
+ /* @noflip */
+ right: initial;
+}
+[dir=rtl] .mdc-text-field--filled .mdc-floating-label, .mdc-text-field--filled .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 16px;
+}
+
+.mdc-text-field--filled .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-106%) scale(0.75);
+ transform: translateY(-106%) scale(0.75);
+}
+.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__input {
+ height: 100%;
+}
+.mdc-text-field--filled.mdc-text-field--no-label .mdc-floating-label {
+ display: none;
+}
+.mdc-text-field--filled.mdc-text-field--no-label::before {
+ display: none;
+}
+@supports (-webkit-hyphens: none) {
+ .mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__affix {
+ align-items: center;
+ align-self: center;
+ display: inline-flex;
+ height: 100%;
+ }
+}
+
+.mdc-text-field--outlined {
+ height: 56px;
+ overflow: visible;
+}
+.mdc-text-field--outlined .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-37.25px) scale(1);
+ transform: translateY(-37.25px) scale(1);
+}
+.mdc-text-field--outlined .mdc-floating-label--float-above {
+ font-size: 0.75rem;
+}
+.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-34.75px) scale(0.75);
+ transform: translateY(-34.75px) scale(0.75);
+}
+.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ font-size: 1rem;
+}
+.mdc-text-field--outlined .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-text-field-outlined 250ms 1;
+ animation: mdc-floating-label-shake-float-above-text-field-outlined 250ms 1;
+}
+@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ }
+}
+@keyframes mdc-floating-label-shake-float-above-text-field-outlined {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);
+ }
+}
+.mdc-text-field--outlined .mdc-text-field__input {
+ height: 100%;
+}
+.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,
+.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,
+.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing {
+ border-color: rgba(0, 0, 0, 0.38);
+}
+.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,
+.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,
+.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing {
+ border-color: rgba(0, 0, 0, 0.87);
+}
+.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,
+.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,
+.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing {
+ border-color: #6200ee;
+ /* @alternate */
+ border-color: var(--mdc-theme-primary, #6200ee);
+}
+.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading {
+ /* @noflip */
+ border-top-left-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-top-left-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-top-right-radius: 0;
+ /* @noflip */
+ border-bottom-right-radius: 0;
+ /* @noflip */
+ border-bottom-left-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-left-radius: var(--mdc-shape-small, 4px);
+}
+[dir=rtl] .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading, .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading[dir=rtl] {
+ /* @noflip */
+ border-top-left-radius: 0;
+ /* @noflip */
+ border-top-right-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-top-right-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-bottom-right-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-right-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-bottom-left-radius: 0;
+}
+
+@supports (top: max(0%)) {
+ .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading {
+ width: max(12px, var(--mdc-shape-small, 4px));
+ }
+}
+@supports (top: max(0%)) {
+ .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__notch {
+ max-width: calc(100% - max(12px, var(--mdc-shape-small, 4px)) * 2);
+ }
+}
+.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing {
+ /* @noflip */
+ border-top-left-radius: 0;
+ /* @noflip */
+ border-top-right-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-top-right-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-bottom-right-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-right-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-bottom-left-radius: 0;
+}
+[dir=rtl] .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing, .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl] {
+ /* @noflip */
+ border-top-left-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-top-left-radius: var(--mdc-shape-small, 4px);
+ /* @noflip */
+ border-top-right-radius: 0;
+ /* @noflip */
+ border-bottom-right-radius: 0;
+ /* @noflip */
+ border-bottom-left-radius: 4px;
+ /* @alternate */
+ /* @noflip */
+ border-bottom-left-radius: var(--mdc-shape-small, 4px);
+}
+
+@supports (top: max(0%)) {
+ .mdc-text-field--outlined {
+ /* @noflip */
+ padding-left: max(16px, calc(var(--mdc-shape-small, 4px) + 4px));
+ }
+}
+@supports (top: max(0%)) {
+ .mdc-text-field--outlined {
+ /* @noflip */
+ padding-right: max(16px, var(--mdc-shape-small, 4px));
+ }
+}
+@supports (top: max(0%)) {
+ .mdc-text-field--outlined + .mdc-text-field-helper-line {
+ /* @noflip */
+ padding-left: max(16px, calc(var(--mdc-shape-small, 4px) + 4px));
+ }
+}
+@supports (top: max(0%)) {
+ .mdc-text-field--outlined + .mdc-text-field-helper-line {
+ /* @noflip */
+ padding-right: max(16px, var(--mdc-shape-small, 4px));
+ }
+}
+.mdc-text-field--outlined.mdc-text-field--with-leading-icon {
+ /* @noflip */
+ padding-left: 0;
+}
+@supports (top: max(0%)) {
+ .mdc-text-field--outlined.mdc-text-field--with-leading-icon {
+ /* @noflip */
+ padding-right: max(16px, var(--mdc-shape-small, 4px));
+ }
+}
+[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-leading-icon, .mdc-text-field--outlined.mdc-text-field--with-leading-icon[dir=rtl] {
+ /* @noflip */
+ padding-right: 0;
+}
+@supports (top: max(0%)) {
+ [dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-leading-icon, .mdc-text-field--outlined.mdc-text-field--with-leading-icon[dir=rtl] {
+ /* @noflip */
+ padding-left: max(16px, var(--mdc-shape-small, 4px));
+ }
+}
+
+.mdc-text-field--outlined.mdc-text-field--with-trailing-icon {
+ /* @noflip */
+ padding-right: 0;
+}
+@supports (top: max(0%)) {
+ .mdc-text-field--outlined.mdc-text-field--with-trailing-icon {
+ /* @noflip */
+ padding-left: max(16px, calc(var(--mdc-shape-small, 4px) + 4px));
+ }
+}
+[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-trailing-icon, .mdc-text-field--outlined.mdc-text-field--with-trailing-icon[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+}
+@supports (top: max(0%)) {
+ [dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-trailing-icon, .mdc-text-field--outlined.mdc-text-field--with-trailing-icon[dir=rtl] {
+ /* @noflip */
+ padding-right: max(16px, calc(var(--mdc-shape-small, 4px) + 4px));
+ }
+}
+
+.mdc-text-field--outlined.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 0;
+}
+.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch {
+ padding-top: 1px;
+}
+.mdc-text-field--outlined .mdc-text-field__ripple::before,
+.mdc-text-field--outlined .mdc-text-field__ripple::after {
+ content: none;
+}
+.mdc-text-field--outlined .mdc-floating-label {
+ /* @noflip */
+ left: 4px;
+ /* @noflip */
+ right: initial;
+}
+[dir=rtl] .mdc-text-field--outlined .mdc-floating-label, .mdc-text-field--outlined .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 4px;
+}
+
+.mdc-text-field--outlined .mdc-text-field__input {
+ display: flex;
+ border: none !important;
+ background-color: transparent;
+}
+.mdc-text-field--outlined .mdc-notched-outline {
+ z-index: 1;
+}
+
+.mdc-text-field--textarea {
+ flex-direction: column;
+ align-items: center;
+ width: auto;
+ height: auto;
+ padding: 0;
+ transition: none;
+}
+.mdc-text-field--textarea .mdc-floating-label {
+ top: 19px;
+}
+.mdc-text-field--textarea .mdc-floating-label:not(.mdc-floating-label--float-above) {
+ -webkit-transform: none;
+ transform: none;
+}
+.mdc-text-field--textarea .mdc-text-field__input {
+ flex-grow: 1;
+ height: auto;
+ min-height: 1.5rem;
+ overflow-x: hidden;
+ overflow-y: auto;
+ box-sizing: border-box;
+ resize: none;
+ padding: 0 16px;
+ line-height: 1.5rem;
+}
+.mdc-text-field--textarea.mdc-text-field--filled::before {
+ display: none;
+}
+.mdc-text-field--textarea.mdc-text-field--filled .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-10.25px) scale(0.75);
+ transform: translateY(-10.25px) scale(0.75);
+}
+.mdc-text-field--textarea.mdc-text-field--filled .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-textarea-filled 250ms 1;
+ animation: mdc-floating-label-shake-float-above-textarea-filled 250ms 1;
+}
+@-webkit-keyframes mdc-floating-label-shake-float-above-textarea-filled {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);
+ }
+}
+@keyframes mdc-floating-label-shake-float-above-textarea-filled {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);
+ }
+}
+.mdc-text-field--textarea.mdc-text-field--filled .mdc-text-field__input {
+ margin-top: 23px;
+ margin-bottom: 9px;
+}
+.mdc-text-field--textarea.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__input {
+ margin-top: 16px;
+ margin-bottom: 16px;
+}
+.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch {
+ padding-top: 0;
+}
+.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-27.25px) scale(1);
+ transform: translateY(-27.25px) scale(1);
+}
+.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--float-above {
+ font-size: 0.75rem;
+}
+.mdc-text-field--textarea.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-24.75px) scale(0.75);
+ transform: translateY(-24.75px) scale(0.75);
+}
+.mdc-text-field--textarea.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ font-size: 1rem;
+}
+.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-textarea-outlined 250ms 1;
+ animation: mdc-floating-label-shake-float-above-textarea-outlined 250ms 1;
+}
+@-webkit-keyframes mdc-floating-label-shake-float-above-textarea-outlined {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ }
+}
+@keyframes mdc-floating-label-shake-float-above-textarea-outlined {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ transform: translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);
+ }
+}
+.mdc-text-field--textarea.mdc-text-field--outlined .mdc-text-field__input {
+ margin-top: 16px;
+ margin-bottom: 16px;
+}
+.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label {
+ top: 18px;
+}
+.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field__input {
+ margin-bottom: 2px;
+}
+.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter {
+ align-self: flex-end;
+ padding: 0 16px;
+}
+.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter::after {
+ display: inline-block;
+ width: 0;
+ height: 16px;
+ content: "";
+ vertical-align: -16px;
+}
+.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter::before {
+ display: none;
+}
+
+.mdc-text-field__resizer {
+ align-self: stretch;
+ display: inline-flex;
+ flex-direction: column;
+ flex-grow: 1;
+ max-height: 100%;
+ max-width: 100%;
+ min-height: 56px;
+ min-width: -webkit-fit-content;
+ min-width: -moz-fit-content;
+ min-width: fit-content;
+ /* @alternate */
+ min-width: -moz-available;
+ /* @alternate */
+ min-width: -webkit-fill-available;
+ overflow: hidden;
+ resize: both;
+}
+.mdc-text-field--filled .mdc-text-field__resizer {
+ -webkit-transform: translateY(-1px);
+ transform: translateY(-1px);
+}
+.mdc-text-field--filled .mdc-text-field__resizer .mdc-text-field__input,
+.mdc-text-field--filled .mdc-text-field__resizer .mdc-text-field-character-counter {
+ -webkit-transform: translateY(1px);
+ transform: translateY(1px);
+}
+.mdc-text-field--outlined .mdc-text-field__resizer {
+ -webkit-transform: translateX(-1px) translateY(-1px);
+ transform: translateX(-1px) translateY(-1px);
+}
+[dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer, .mdc-text-field--outlined .mdc-text-field__resizer[dir=rtl] {
+ -webkit-transform: translateX(1px) translateY(-1px);
+ transform: translateX(1px) translateY(-1px);
+}
+
+.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input,
+.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter {
+ -webkit-transform: translateX(1px) translateY(1px);
+ transform: translateX(1px) translateY(1px);
+}
+[dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input, [dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter, .mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input[dir=rtl], .mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter[dir=rtl] {
+ -webkit-transform: translateX(-1px) translateY(1px);
+ transform: translateX(-1px) translateY(1px);
+}
+
+.mdc-text-field--with-leading-icon {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 16px;
+}
+[dir=rtl] .mdc-text-field--with-leading-icon, .mdc-text-field--with-leading-icon[dir=rtl] {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label {
+ max-width: calc(100% - 48px);
+ /* @noflip */
+ left: 48px;
+ /* @noflip */
+ right: initial;
+}
+[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label, .mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 48px;
+}
+
+.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label--float-above {
+ max-width: calc(100% / 0.75 - 64px / 0.75);
+}
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label {
+ /* @noflip */
+ left: 36px;
+ /* @noflip */
+ right: initial;
+}
+[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label, .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label[dir=rtl] {
+ /* @noflip */
+ left: initial;
+ /* @noflip */
+ right: 36px;
+}
+
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch {
+ max-width: calc(100% - 60px);
+}
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-37.25px) translateX(-32px) scale(1);
+ transform: translateY(-37.25px) translateX(-32px) scale(1);
+}
+[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above, .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above[dir=rtl] {
+ -webkit-transform: translateY(-37.25px) translateX(32px) scale(1);
+ transform: translateY(-37.25px) translateX(32px) scale(1);
+}
+
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above {
+ font-size: 0.75rem;
+}
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ -webkit-transform: translateY(-34.75px) translateX(-32px) scale(0.75);
+ transform: translateY(-34.75px) translateX(-32px) scale(0.75);
+}
+[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above, [dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above, .mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl], .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl] {
+ -webkit-transform: translateY(-34.75px) translateX(32px) scale(0.75);
+ transform: translateY(-34.75px) translateX(32px) scale(0.75);
+}
+
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above {
+ font-size: 1rem;
+}
+.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1;
+ animation: mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1;
+}
+@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ }
+}
+@keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon {
+ 0% {
+ -webkit-transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);
+ }
+}
+[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--shake, .mdc-text-field--with-leading-icon.mdc-text-field--outlined[dir=rtl] .mdc-floating-label--shake {
+ -webkit-animation: mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1;
+ animation: mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1;
+}
+
+@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon-rtl {
+ 0% {
+ -webkit-transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ }
+}
+
+@keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon-rtl {
+ 0% {
+ -webkit-transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 33% {
+ -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819);
+ -webkit-transform: translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 66% {
+ -webkit-animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);
+ -webkit-transform: translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);
+ }
+ 100% {
+ -webkit-transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ transform: translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);
+ }
+}
+
+.mdc-text-field--with-trailing-icon {
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-text-field--with-trailing-icon, .mdc-text-field--with-trailing-icon[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label {
+ max-width: calc(100% - 64px);
+}
+.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label--float-above {
+ max-width: calc(100% / 0.75 - 64px / 0.75);
+}
+.mdc-text-field--with-trailing-icon.mdc-text-field--outlined :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch {
+ max-width: calc(100% - 60px);
+}
+
+.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 0;
+}
+.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label {
+ max-width: calc(100% - 96px);
+}
+.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label--float-above {
+ max-width: calc(100% / 0.75 - 96px / 0.75);
+}
+
+.mdc-text-field-helper-line {
+ display: flex;
+ justify-content: space-between;
+ box-sizing: border-box;
+}
+.mdc-text-field + .mdc-text-field-helper-line {
+ padding-right: 16px;
+ padding-left: 16px;
+}
+
+.mdc-form-field > .mdc-text-field + label {
+ align-self: flex-start;
+}
+
+.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label {
+ color: rgba(98, 0, 238, 0.87);
+}
+.mdc-text-field--focused .mdc-notched-outline__leading,
+.mdc-text-field--focused .mdc-notched-outline__notch,
+.mdc-text-field--focused .mdc-notched-outline__trailing {
+ border-width: 2px;
+}
+.mdc-text-field--focused + .mdc-text-field-helper-line .mdc-text-field-helper-text:not(.mdc-text-field-helper-text--validation-msg) {
+ opacity: 1;
+}
+.mdc-text-field--focused.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch {
+ padding-top: 2px;
+}
+.mdc-text-field--focused.mdc-text-field--outlined.mdc-text-field--textarea .mdc-notched-outline--notched .mdc-notched-outline__notch {
+ padding-top: 0;
+}
+
+.mdc-text-field--invalid:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before {
+ border-bottom-color: #b00020;
+ /* @alternate */
+ border-bottom-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::after {
+ border-bottom-color: #b00020;
+ /* @alternate */
+ border-bottom-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-floating-label {
+ color: #b00020;
+ /* @alternate */
+ color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--invalid + .mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg {
+ color: #b00020;
+ /* @alternate */
+ color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid .mdc-text-field__input {
+ caret-color: #b00020;
+ /* @alternate */
+ caret-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-text-field__icon--trailing {
+ color: #b00020;
+ /* @alternate */
+ color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::before {
+ border-bottom-color: #b00020;
+ /* @alternate */
+ border-bottom-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,
+.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,
+.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing {
+ border-color: #b00020;
+ /* @alternate */
+ border-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,
+.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,
+.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing {
+ border-color: #b00020;
+ /* @alternate */
+ border-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,
+.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,
+.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing {
+ border-color: #b00020;
+ /* @alternate */
+ border-color: var(--mdc-theme-error, #b00020);
+}
+.mdc-text-field--invalid + .mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg {
+ opacity: 1;
+}
+
+.mdc-text-field--disabled {
+ pointer-events: none;
+}
+.mdc-text-field--disabled .mdc-text-field__input {
+ color: rgba(0, 0, 0, 0.38);
+}
+@media all {
+ .mdc-text-field--disabled .mdc-text-field__input::-webkit-input-placeholder {
+ color: rgba(0, 0, 0, 0.38);
+ }
+ .mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder {
+ color: rgba(0, 0, 0, 0.38);
+ }
+ .mdc-text-field--disabled .mdc-text-field__input::-ms-input-placeholder {
+ color: rgba(0, 0, 0, 0.38);
+ }
+ .mdc-text-field--disabled .mdc-text-field__input::placeholder {
+ color: rgba(0, 0, 0, 0.38);
+ }
+}
+@media all {
+ .mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder {
+ color: rgba(0, 0, 0, 0.38);
+ }
+}
+.mdc-text-field--disabled .mdc-floating-label {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-text-field--disabled + .mdc-text-field-helper-line .mdc-text-field-helper-text {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-text-field--disabled .mdc-text-field-character-counter,
+.mdc-text-field--disabled + .mdc-text-field-helper-line .mdc-text-field-character-counter {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-text-field--disabled .mdc-text-field__icon--leading {
+ color: rgba(0, 0, 0, 0.3);
+}
+.mdc-text-field--disabled .mdc-text-field__icon--trailing {
+ color: rgba(0, 0, 0, 0.3);
+}
+.mdc-text-field--disabled .mdc-text-field__affix--prefix {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-text-field--disabled .mdc-text-field__affix--suffix {
+ color: rgba(0, 0, 0, 0.38);
+}
+.mdc-text-field--disabled .mdc-line-ripple::before {
+ border-bottom-color: rgba(0, 0, 0, 0.06);
+}
+.mdc-text-field--disabled .mdc-notched-outline__leading,
+.mdc-text-field--disabled .mdc-notched-outline__notch,
+.mdc-text-field--disabled .mdc-notched-outline__trailing {
+ border-color: rgba(0, 0, 0, 0.06);
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-text-field__input::-webkit-input-placeholder {
+ color: GrayText;
+ }
+ .mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder {
+ color: GrayText;
+ }
+ .mdc-text-field--disabled .mdc-text-field__input::-ms-input-placeholder {
+ color: GrayText;
+ }
+ .mdc-text-field--disabled .mdc-text-field__input::placeholder {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-floating-label {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled + .mdc-text-field-helper-line .mdc-text-field-helper-text {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-text-field-character-counter,
+.mdc-text-field--disabled + .mdc-text-field-helper-line .mdc-text-field-character-counter {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-text-field__icon--leading {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-text-field__icon--trailing {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-text-field__affix--prefix {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-text-field__affix--suffix {
+ color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-line-ripple::before {
+ border-bottom-color: GrayText;
+ }
+}
+@media screen and (forced-colors: active), (-ms-high-contrast: active) {
+ .mdc-text-field--disabled .mdc-notched-outline__leading,
+.mdc-text-field--disabled .mdc-notched-outline__notch,
+.mdc-text-field--disabled .mdc-notched-outline__trailing {
+ border-color: GrayText;
+ }
+}
+@media screen and (forced-colors: active) {
+ .mdc-text-field--disabled .mdc-text-field__input {
+ background-color: Window;
+ }
+ .mdc-text-field--disabled .mdc-floating-label {
+ z-index: 1;
+ }
+}
+.mdc-text-field--disabled .mdc-floating-label {
+ cursor: default;
+}
+.mdc-text-field--disabled.mdc-text-field--filled {
+ background-color: #fafafa;
+}
+.mdc-text-field--disabled.mdc-text-field--filled .mdc-text-field__ripple {
+ display: none;
+}
+.mdc-text-field--disabled .mdc-text-field__input {
+ pointer-events: auto;
+}
+
+.mdc-text-field--end-aligned .mdc-text-field__input {
+ /* @noflip */
+ text-align: right;
+}
+[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__input, .mdc-text-field--end-aligned .mdc-text-field__input[dir=rtl] {
+ /* @noflip */
+ text-align: left;
+}
+
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__input,
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix, .mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__input,
+.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix {
+ /* @noflip */
+ direction: ltr;
+}
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--prefix, .mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--prefix {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 2px;
+}
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--suffix, .mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--suffix {
+ /* @noflip */
+ padding-left: 12px;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__icon--leading, .mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__icon--leading {
+ order: 1;
+}
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--suffix, .mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--suffix {
+ order: 2;
+}
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__input, .mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__input {
+ order: 3;
+}
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--prefix, .mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--prefix {
+ order: 4;
+}
+[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__icon--trailing, .mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__icon--trailing {
+ order: 5;
+}
+
+[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__input, .mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__input {
+ /* @noflip */
+ text-align: right;
+}
+[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__affix--prefix, .mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__affix--prefix {
+ /* @noflip */
+ padding-right: 12px;
+}
+[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__affix--suffix, .mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__affix--suffix {
+ /* @noflip */
+ padding-left: 2px;
+}
+
+.mdc-text-field-helper-text {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-caption-font-size, 0.75rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-caption-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-caption-font-weight, 400);
+ letter-spacing: 0.0333333333em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-caption-text-transform, inherit);
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ margin: 0;
+ opacity: 0;
+ will-change: opacity;
+ transition: opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+.mdc-text-field-helper-text::before {
+ display: inline-block;
+ width: 0;
+ height: 16px;
+ content: "";
+ vertical-align: 0;
+}
+
+.mdc-text-field-helper-text--persistent {
+ transition: none;
+ opacity: 1;
+ will-change: initial;
+}
+
+.mdc-text-field-character-counter {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-caption-font-size, 0.75rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-caption-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-caption-font-weight, 400);
+ letter-spacing: 0.0333333333em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-caption-text-transform, inherit);
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ /* @noflip */
+ margin-left: auto;
+ /* @noflip */
+ margin-right: 0;
+ /* @noflip */
+ padding-left: 16px;
+ /* @noflip */
+ padding-right: 0;
+ white-space: nowrap;
+}
+.mdc-text-field-character-counter::before {
+ display: inline-block;
+ width: 0;
+ height: 16px;
+ content: "";
+ vertical-align: 0;
+}
+[dir=rtl] .mdc-text-field-character-counter, .mdc-text-field-character-counter[dir=rtl] {
+ /* @noflip */
+ margin-left: 0;
+ /* @noflip */
+ margin-right: auto;
+}
+
+[dir=rtl] .mdc-text-field-character-counter, .mdc-text-field-character-counter[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 16px;
+}
+
+.mdc-text-field__icon {
+ align-self: center;
+ cursor: pointer;
+}
+.mdc-text-field__icon:not([tabindex]), .mdc-text-field__icon[tabindex="-1"] {
+ cursor: default;
+ pointer-events: none;
+}
+.mdc-text-field__icon svg {
+ display: block;
+}
+
+.mdc-text-field__icon--leading {
+ /* @noflip */
+ margin-left: 16px;
+ /* @noflip */
+ margin-right: 8px;
+}
+[dir=rtl] .mdc-text-field__icon--leading, .mdc-text-field__icon--leading[dir=rtl] {
+ /* @noflip */
+ margin-left: 8px;
+ /* @noflip */
+ margin-right: 16px;
+}
+
+.mdc-text-field__icon--trailing {
+ padding: 12px;
+ /* @noflip */
+ margin-left: 0px;
+ /* @noflip */
+ margin-right: 0px;
+}
+[dir=rtl] .mdc-text-field__icon--trailing, .mdc-text-field__icon--trailing[dir=rtl] {
+ /* @noflip */
+ margin-left: 0px;
+ /* @noflip */
+ margin-right: 0px;
+}
+
+:root {
+ --mdc-theme-primary: #6200ee;
+ --mdc-theme-secondary: #018786;
+ --mdc-theme-background: #fff;
+ --mdc-theme-surface: #fff;
+ --mdc-theme-error: #b00020;
+ --mdc-theme-on-primary: #fff;
+ --mdc-theme-on-secondary: #fff;
+ --mdc-theme-on-surface: #000;
+ --mdc-theme-on-error: #fff;
+ --mdc-theme-text-primary-on-background: rgba(0, 0, 0, 0.87);
+ --mdc-theme-text-secondary-on-background: rgba(0, 0, 0, 0.54);
+ --mdc-theme-text-hint-on-background: rgba(0, 0, 0, 0.38);
+ --mdc-theme-text-disabled-on-background: rgba(0, 0, 0, 0.38);
+ --mdc-theme-text-icon-on-background: rgba(0, 0, 0, 0.38);
+ --mdc-theme-text-primary-on-light: rgba(0, 0, 0, 0.87);
+ --mdc-theme-text-secondary-on-light: rgba(0, 0, 0, 0.54);
+ --mdc-theme-text-hint-on-light: rgba(0, 0, 0, 0.38);
+ --mdc-theme-text-disabled-on-light: rgba(0, 0, 0, 0.38);
+ --mdc-theme-text-icon-on-light: rgba(0, 0, 0, 0.38);
+ --mdc-theme-text-primary-on-dark: white;
+ --mdc-theme-text-secondary-on-dark: rgba(255, 255, 255, 0.7);
+ --mdc-theme-text-hint-on-dark: rgba(255, 255, 255, 0.5);
+ --mdc-theme-text-disabled-on-dark: rgba(255, 255, 255, 0.5);
+ --mdc-theme-text-icon-on-dark: rgba(255, 255, 255, 0.5);
+}
+
+.mdc-theme--primary {
+ color: #6200ee !important;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee) !important;
+}
+
+.mdc-theme--secondary {
+ color: #018786 !important;
+ /* @alternate */
+ color: var(--mdc-theme-secondary, #018786) !important;
+}
+
+.mdc-theme--background {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-background, #fff);
+}
+
+.mdc-theme--surface {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-theme-surface, #fff);
+}
+
+.mdc-theme--error {
+ color: #b00020 !important;
+ /* @alternate */
+ color: var(--mdc-theme-error, #b00020) !important;
+}
+
+.mdc-theme--on-primary {
+ color: #fff !important;
+ /* @alternate */
+ color: var(--mdc-theme-on-primary, #fff) !important;
+}
+
+.mdc-theme--on-secondary {
+ color: #fff !important;
+ /* @alternate */
+ color: var(--mdc-theme-on-secondary, #fff) !important;
+}
+
+.mdc-theme--on-surface {
+ color: #000 !important;
+ /* @alternate */
+ color: var(--mdc-theme-on-surface, #000) !important;
+}
+
+.mdc-theme--on-error {
+ color: #fff !important;
+ /* @alternate */
+ color: var(--mdc-theme-on-error, #fff) !important;
+}
+
+.mdc-theme--text-primary-on-background {
+ color: rgba(0, 0, 0, 0.87) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87)) !important;
+}
+
+.mdc-theme--text-secondary-on-background {
+ color: rgba(0, 0, 0, 0.54) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54)) !important;
+}
+
+.mdc-theme--text-hint-on-background {
+ color: rgba(0, 0, 0, 0.38) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38)) !important;
+}
+
+.mdc-theme--text-disabled-on-background {
+ color: rgba(0, 0, 0, 0.38) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-disabled-on-background, rgba(0, 0, 0, 0.38)) !important;
+}
+
+.mdc-theme--text-icon-on-background {
+ color: rgba(0, 0, 0, 0.38) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38)) !important;
+}
+
+.mdc-theme--text-primary-on-light {
+ color: rgba(0, 0, 0, 0.87) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-light, rgba(0, 0, 0, 0.87)) !important;
+}
+
+.mdc-theme--text-secondary-on-light {
+ color: rgba(0, 0, 0, 0.54) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-secondary-on-light, rgba(0, 0, 0, 0.54)) !important;
+}
+
+.mdc-theme--text-hint-on-light {
+ color: rgba(0, 0, 0, 0.38) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-hint-on-light, rgba(0, 0, 0, 0.38)) !important;
+}
+
+.mdc-theme--text-disabled-on-light {
+ color: rgba(0, 0, 0, 0.38) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-disabled-on-light, rgba(0, 0, 0, 0.38)) !important;
+}
+
+.mdc-theme--text-icon-on-light {
+ color: rgba(0, 0, 0, 0.38) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-icon-on-light, rgba(0, 0, 0, 0.38)) !important;
+}
+
+.mdc-theme--text-primary-on-dark {
+ color: white !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-dark, white) !important;
+}
+
+.mdc-theme--text-secondary-on-dark {
+ color: rgba(255, 255, 255, 0.7) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-secondary-on-dark, rgba(255, 255, 255, 0.7)) !important;
+}
+
+.mdc-theme--text-hint-on-dark {
+ color: rgba(255, 255, 255, 0.5) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-hint-on-dark, rgba(255, 255, 255, 0.5)) !important;
+}
+
+.mdc-theme--text-disabled-on-dark {
+ color: rgba(255, 255, 255, 0.5) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-disabled-on-dark, rgba(255, 255, 255, 0.5)) !important;
+}
+
+.mdc-theme--text-icon-on-dark {
+ color: rgba(255, 255, 255, 0.5) !important;
+ /* @alternate */
+ color: var(--mdc-theme-text-icon-on-dark, rgba(255, 255, 255, 0.5)) !important;
+}
+
+.mdc-theme--primary-bg {
+ background-color: #6200ee !important;
+ /* @alternate */
+ background-color: var(--mdc-theme-primary, #6200ee) !important;
+}
+
+.mdc-theme--secondary-bg {
+ background-color: #018786 !important;
+ /* @alternate */
+ background-color: var(--mdc-theme-secondary, #018786) !important;
+}
+
+.mdc-tooltip__surface {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+
+.mdc-tooltip__caret-surface-top,
+.mdc-tooltip__caret-surface-bottom {
+ border-radius: 4px;
+ /* @alternate */
+ border-radius: var(--mdc-shape-small, 4px);
+}
+
+.mdc-tooltip__surface {
+ color: white;
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-dark, white);
+}
+
+.mdc-tooltip__surface {
+ background-color: rgba(0, 0, 0, 0.6);
+}
+
+.mdc-tooltip__surface {
+ word-break: break-all;
+ /* @alternate */
+ word-break: var(--mdc-tooltip-word-break, normal);
+ overflow-wrap: anywhere;
+}
+
+.mdc-tooltip {
+ z-index: 9;
+}
+
+.mdc-tooltip--showing-transition .mdc-tooltip__surface-animation {
+ transition: opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+ transition: opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1), transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.mdc-tooltip--hide-transition .mdc-tooltip__surface-animation {
+ transition: opacity 75ms 0ms cubic-bezier(0.4, 0, 1, 1);
+}
+
+.mdc-tooltip__title {
+ color: rgba(0, 0, 0, 0.87);
+ /* @alternate */
+ color: var(--mdc-theme-text-primary-on-light, rgba(0, 0, 0, 0.87));
+}
+
+.mdc-tooltip__content {
+ color: rgba(0, 0, 0, 0.6);
+}
+
+.mdc-tooltip__content-link {
+ color: #6200ee;
+ /* @alternate */
+ color: var(--mdc-theme-primary, #6200ee);
+}
+
+.mdc-tooltip {
+ position: fixed;
+ display: none;
+}
+.mdc-tooltip.mdc-tooltip--rich .mdc-tooltip__surface {
+ background-color: #fff;
+}
+.mdc-tooltip.mdc-tooltip--rich .mdc-tooltip__caret-surface-top,
+.mdc-tooltip.mdc-tooltip--rich .mdc-tooltip__caret-surface-bottom {
+ background-color: #fff;
+}
+
+.mdc-tooltip-wrapper--rich {
+ position: relative;
+}
+
+.mdc-tooltip--shown,
+.mdc-tooltip--showing,
+.mdc-tooltip--hide {
+ display: inline-flex;
+}
+.mdc-tooltip--shown.mdc-tooltip--rich,
+.mdc-tooltip--showing.mdc-tooltip--rich,
+.mdc-tooltip--hide.mdc-tooltip--rich {
+ display: inline-block;
+ /* @noflip */
+ left: -320px;
+ position: absolute;
+}
+
+.mdc-tooltip__surface {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-caption-font-size, 0.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-caption-font-weight, 400);
+ letter-spacing: 0.0333333333em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-caption-text-transform, inherit);
+ line-height: 16px;
+ padding: 4px 8px;
+ min-width: 40px;
+ max-width: 200px;
+ min-height: 24px;
+ max-height: 40vh;
+ box-sizing: border-box;
+ overflow: hidden;
+ text-align: center;
+}
+.mdc-tooltip__surface::before {
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ border: 1px solid transparent;
+ border-radius: inherit;
+ content: "";
+ pointer-events: none;
+}
+.mdc-tooltip--rich .mdc-tooltip__surface {
+ /* @alternate */
+ box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
+ align-items: flex-start;
+ border-radius: 4px;
+ display: flex;
+ flex-direction: column;
+ line-height: 20px;
+ min-height: 24px;
+ min-width: 40px;
+ max-width: 320px;
+ position: relative;
+}
+.mdc-tooltip--rich .mdc-tooltip__surface .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.mdc-tooltip--multiline .mdc-tooltip__surface {
+ /* @noflip */
+ text-align: left;
+}
+[dir=rtl] .mdc-tooltip--multiline .mdc-tooltip__surface, .mdc-tooltip--multiline .mdc-tooltip__surface[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-tooltip__surface .mdc-tooltip__title {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle2-font-size, 0.875rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle2-font-weight, 500);
+ letter-spacing: 0.0071428571em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle2-text-transform, inherit);
+ margin: 0 8px;
+}
+.mdc-tooltip__surface .mdc-tooltip__title::before {
+ display: inline-block;
+ width: 0;
+ height: 28px;
+ content: "";
+ vertical-align: 0;
+}
+.mdc-tooltip__surface .mdc-tooltip__content {
+ display: block;
+ margin-top: 0;
+ /* @alternate */
+ line-height: normal;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+ max-width: calc(100% - 2 * 8px);
+ margin: 0 8px 16px 8px;
+ /* @noflip */
+ text-align: left;
+}
+.mdc-tooltip__surface .mdc-tooltip__content::before {
+ display: inline-block;
+ width: 0;
+ height: 24px;
+ content: "";
+ vertical-align: 0;
+}
+[dir=rtl] .mdc-tooltip__surface .mdc-tooltip__content, .mdc-tooltip__surface .mdc-tooltip__content[dir=rtl] {
+ /* @noflip */
+ text-align: right;
+}
+
+.mdc-tooltip__surface .mdc-tooltip__content-link {
+ text-decoration: none;
+}
+
+.mdc-tooltip__surface-animation {
+ opacity: 0;
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ will-change: transform, opacity;
+}
+.mdc-tooltip--shown .mdc-tooltip__surface-animation {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+}
+.mdc-tooltip--hide .mdc-tooltip__surface-animation {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+}
+
+.mdc-tooltip__caret-surface-top,
+.mdc-tooltip__caret-surface-bottom {
+ position: absolute;
+ height: 24px;
+ width: 24px;
+ -webkit-transform: rotate(35deg) skewY(20deg) scaleX(0.9396926208);
+ transform: rotate(35deg) skewY(20deg) scaleX(0.9396926208);
+}
+.mdc-tooltip__caret-surface-top .mdc-elevation-overlay,
+.mdc-tooltip__caret-surface-bottom .mdc-elevation-overlay {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+
+.mdc-tooltip__caret-surface-bottom {
+ /* @alternate */
+ box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
+ outline: 1px solid transparent;
+ z-index: -1;
+}
+
+.mdc-top-app-bar {
+ background-color: #6200ee;
+ /* @alternate */
+ background-color: var(--mdc-theme-primary, #6200ee);
+ color: white;
+ display: flex;
+ position: fixed;
+ flex-direction: column;
+ justify-content: space-between;
+ box-sizing: border-box;
+ width: 100%;
+ z-index: 4;
+}
+.mdc-top-app-bar .mdc-top-app-bar__action-item,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon {
+ color: #fff;
+ /* @alternate */
+ color: var(--mdc-theme-on-primary, #fff);
+}
+.mdc-top-app-bar .mdc-top-app-bar__action-item::before, .mdc-top-app-bar .mdc-top-app-bar__action-item::after,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon::before,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon::after {
+ background-color: #fff;
+ /* @alternate */
+ background-color: var(--mdc-ripple-color, var(--mdc-theme-on-primary, #fff));
+}
+.mdc-top-app-bar .mdc-top-app-bar__action-item:hover::before, .mdc-top-app-bar .mdc-top-app-bar__action-item.mdc-ripple-surface--hover::before,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:hover::before,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon.mdc-ripple-surface--hover::before {
+ opacity: 0.08;
+ /* @alternate */
+ opacity: var(--mdc-ripple-hover-opacity, 0.08);
+}
+.mdc-top-app-bar .mdc-top-app-bar__action-item.mdc-ripple-upgraded--background-focused::before, .mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded):focus::before,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon.mdc-ripple-upgraded--background-focused::before,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded):focus::before {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-focus-opacity, 0.24);
+}
+.mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded)::after,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded)::after {
+ transition: opacity 150ms linear;
+}
+.mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded):active::after,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded):active::after {
+ transition-duration: 75ms;
+ opacity: 0.24;
+ /* @alternate */
+ opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-top-app-bar .mdc-top-app-bar__action-item.mdc-ripple-upgraded,
+.mdc-top-app-bar .mdc-top-app-bar__navigation-icon.mdc-ripple-upgraded {
+ --mdc-ripple-fg-opacity: var(--mdc-ripple-press-opacity, 0.24);
+}
+.mdc-top-app-bar__row {
+ display: flex;
+ position: relative;
+ box-sizing: border-box;
+ width: 100%;
+ height: 64px;
+}
+.mdc-top-app-bar__section {
+ display: inline-flex;
+ flex: 1 1 auto;
+ align-items: center;
+ min-width: 0;
+ padding: 8px 12px;
+ z-index: 1;
+}
+.mdc-top-app-bar__section--align-start {
+ justify-content: flex-start;
+ order: -1;
+}
+.mdc-top-app-bar__section--align-end {
+ justify-content: flex-end;
+ order: 1;
+}
+.mdc-top-app-bar__title {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1.25rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline6-font-size, 1.25rem);
+ line-height: 2rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline6-line-height, 2rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline6-font-weight, 500);
+ letter-spacing: 0.0125em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline6-letter-spacing, 0.0125em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline6-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline6-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline6-text-transform, inherit);
+ /* @noflip */
+ padding-left: 20px;
+ /* @noflip */
+ padding-right: 0;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ z-index: 1;
+}
+[dir=rtl] .mdc-top-app-bar__title, .mdc-top-app-bar__title[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 20px;
+}
+
+.mdc-top-app-bar--short-collapsed {
+ /* @noflip */
+ border-top-left-radius: 0;
+ /* @noflip */
+ border-top-right-radius: 0;
+ /* @noflip */
+ border-bottom-right-radius: 24px;
+ /* @noflip */
+ border-bottom-left-radius: 0;
+}
+[dir=rtl] .mdc-top-app-bar--short-collapsed, .mdc-top-app-bar--short-collapsed[dir=rtl] {
+ /* @noflip */
+ border-top-left-radius: 0;
+ /* @noflip */
+ border-top-right-radius: 0;
+ /* @noflip */
+ border-bottom-right-radius: 0;
+ /* @noflip */
+ border-bottom-left-radius: 24px;
+}
+
+.mdc-top-app-bar--short {
+ top: 0;
+ /* @noflip */
+ right: auto;
+ /* @noflip */
+ left: 0;
+ width: 100%;
+ transition: width 250ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+[dir=rtl] .mdc-top-app-bar--short, .mdc-top-app-bar--short[dir=rtl] {
+ /* @noflip */
+ right: 0;
+ /* @noflip */
+ left: auto;
+}
+
+.mdc-top-app-bar--short .mdc-top-app-bar__row {
+ height: 56px;
+}
+.mdc-top-app-bar--short .mdc-top-app-bar__section {
+ padding: 4px;
+}
+.mdc-top-app-bar--short .mdc-top-app-bar__title {
+ transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);
+ opacity: 1;
+}
+
+.mdc-top-app-bar--short-collapsed {
+ /* @alternate */
+ box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);
+ width: 56px;
+ transition: width 300ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__title {
+ display: none;
+}
+.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__action-item {
+ transition: padding 150ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item {
+ width: 112px;
+}
+.mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 12px;
+}
+[dir=rtl] .mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end, .mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end[dir=rtl] {
+ /* @noflip */
+ padding-left: 12px;
+ /* @noflip */
+ padding-right: 0;
+}
+
+.mdc-top-app-bar--dense .mdc-top-app-bar__row {
+ height: 48px;
+}
+.mdc-top-app-bar--dense .mdc-top-app-bar__section {
+ padding: 0 4px;
+}
+.mdc-top-app-bar--dense .mdc-top-app-bar__title {
+ /* @noflip */
+ padding-left: 12px;
+ /* @noflip */
+ padding-right: 0;
+}
+[dir=rtl] .mdc-top-app-bar--dense .mdc-top-app-bar__title, .mdc-top-app-bar--dense .mdc-top-app-bar__title[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 12px;
+}
+
+.mdc-top-app-bar--prominent .mdc-top-app-bar__row {
+ height: 128px;
+}
+.mdc-top-app-bar--prominent .mdc-top-app-bar__title {
+ align-self: flex-end;
+ padding-bottom: 2px;
+}
+.mdc-top-app-bar--prominent .mdc-top-app-bar__action-item,
+.mdc-top-app-bar--prominent .mdc-top-app-bar__navigation-icon {
+ align-self: flex-start;
+}
+
+.mdc-top-app-bar--fixed {
+ transition: box-shadow 200ms linear;
+}
+
+.mdc-top-app-bar--fixed-scrolled {
+ /* @alternate */
+ box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);
+ transition: box-shadow 200ms linear;
+}
+
+.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__row {
+ height: 96px;
+}
+.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__section {
+ padding: 0 12px;
+}
+.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title {
+ /* @noflip */
+ padding-left: 20px;
+ /* @noflip */
+ padding-right: 0;
+ padding-bottom: 9px;
+}
+[dir=rtl] .mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title, .mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title[dir=rtl] {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 20px;
+}
+
+.mdc-top-app-bar--fixed-adjust {
+ padding-top: 64px;
+}
+
+.mdc-top-app-bar--dense-fixed-adjust {
+ padding-top: 48px;
+}
+
+.mdc-top-app-bar--short-fixed-adjust {
+ padding-top: 56px;
+}
+
+.mdc-top-app-bar--prominent-fixed-adjust {
+ padding-top: 128px;
+}
+
+.mdc-top-app-bar--dense-prominent-fixed-adjust {
+ padding-top: 96px;
+}
+
+@media (max-width: 599px) {
+ .mdc-top-app-bar__row {
+ height: 56px;
+ }
+
+ .mdc-top-app-bar__section {
+ padding: 4px;
+ }
+
+ .mdc-top-app-bar--short {
+ transition: width 200ms cubic-bezier(0.4, 0, 0.2, 1);
+ }
+
+ .mdc-top-app-bar--short-collapsed {
+ transition: width 250ms cubic-bezier(0.4, 0, 0.2, 1);
+ }
+ .mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end {
+ /* @noflip */
+ padding-left: 0;
+ /* @noflip */
+ padding-right: 12px;
+ }
+ [dir=rtl] .mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end, .mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end[dir=rtl] {
+ /* @noflip */
+ padding-left: 12px;
+ /* @noflip */
+ padding-right: 0;
+ }
+
+ .mdc-top-app-bar--prominent .mdc-top-app-bar__title {
+ padding-bottom: 6px;
+ }
+
+ .mdc-top-app-bar--fixed-adjust {
+ padding-top: 56px;
+ }
+}
+.mdc-typography {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-font-family, Roboto, sans-serif);
+}
+
+.mdc-typography--headline1 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 6rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline1-font-size, 6rem);
+ line-height: 6rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline1-line-height, 6rem);
+ font-weight: 300;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline1-font-weight, 300);
+ letter-spacing: -0.015625em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline1-letter-spacing, -0.015625em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline1-text-transform, inherit);
+}
+
+.mdc-typography--headline2 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 3.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline2-font-size, 3.75rem);
+ line-height: 3.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline2-line-height, 3.75rem);
+ font-weight: 300;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline2-font-weight, 300);
+ letter-spacing: -0.0083333333em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline2-letter-spacing, -0.0083333333em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline2-text-transform, inherit);
+}
+
+.mdc-typography--headline3 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline3-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 3rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline3-font-size, 3rem);
+ line-height: 3.125rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline3-line-height, 3.125rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline3-font-weight, 400);
+ letter-spacing: normal;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline3-letter-spacing, normal);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline3-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline3-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline3-text-transform, inherit);
+}
+
+.mdc-typography--headline4 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline4-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 2.125rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline4-font-size, 2.125rem);
+ line-height: 2.5rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline4-line-height, 2.5rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline4-font-weight, 400);
+ letter-spacing: 0.0073529412em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline4-letter-spacing, 0.0073529412em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline4-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline4-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline4-text-transform, inherit);
+}
+
+.mdc-typography--headline5 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline5-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1.5rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline5-font-size, 1.5rem);
+ line-height: 2rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline5-line-height, 2rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline5-font-weight, 400);
+ letter-spacing: normal;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline5-letter-spacing, normal);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline5-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline5-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline5-text-transform, inherit);
+}
+
+.mdc-typography--headline6 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1.25rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-headline6-font-size, 1.25rem);
+ line-height: 2rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-headline6-line-height, 2rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-headline6-font-weight, 500);
+ letter-spacing: 0.0125em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-headline6-letter-spacing, 0.0125em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-headline6-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-headline6-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-headline6-text-transform, inherit);
+}
+
+.mdc-typography--subtitle1 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle1-font-size, 1rem);
+ line-height: 1.75rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle1-line-height, 1.75rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle1-font-weight, 400);
+ letter-spacing: 0.009375em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle1-text-transform, inherit);
+}
+
+.mdc-typography--subtitle2 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-subtitle2-font-size, 0.875rem);
+ line-height: 1.375rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-subtitle2-line-height, 1.375rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-subtitle2-font-weight, 500);
+ letter-spacing: 0.0071428571em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-subtitle2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-subtitle2-text-transform, inherit);
+}
+
+.mdc-typography--body1 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 1rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body1-font-size, 1rem);
+ line-height: 1.5rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body1-line-height, 1.5rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body1-font-weight, 400);
+ letter-spacing: 0.03125em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body1-letter-spacing, 0.03125em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body1-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body1-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body1-text-transform, inherit);
+}
+
+.mdc-typography--body2 {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-body2-font-size, 0.875rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-body2-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-body2-font-weight, 400);
+ letter-spacing: 0.0178571429em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-body2-letter-spacing, 0.0178571429em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-body2-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-body2-text-transform, inherit);
+}
+
+.mdc-typography--caption {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-caption-font-size, 0.75rem);
+ line-height: 1.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-caption-line-height, 1.25rem);
+ font-weight: 400;
+ /* @alternate */
+ font-weight: var(--mdc-typography-caption-font-weight, 400);
+ letter-spacing: 0.0333333333em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em);
+ text-decoration: inherit;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-decoration: var(--mdc-typography-caption-text-decoration, inherit);
+ text-transform: inherit;
+ /* @alternate */
+ text-transform: var(--mdc-typography-caption-text-transform, inherit);
+}
+
+.mdc-typography--button {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.875rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-button-font-size, 0.875rem);
+ line-height: 2.25rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-button-line-height, 2.25rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-button-font-weight, 500);
+ letter-spacing: 0.0892857143em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-button-letter-spacing, 0.0892857143em);
+ text-decoration: none;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-decoration: var(--mdc-typography-button-text-decoration, none);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-button-text-transform, uppercase);
+}
+
+.mdc-typography--overline {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ font-family: Roboto, sans-serif;
+ /* @alternate */
+ font-family: var(--mdc-typography-overline-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));
+ font-size: 0.75rem;
+ /* @alternate */
+ font-size: var(--mdc-typography-overline-font-size, 0.75rem);
+ line-height: 2rem;
+ /* @alternate */
+ line-height: var(--mdc-typography-overline-line-height, 2rem);
+ font-weight: 500;
+ /* @alternate */
+ font-weight: var(--mdc-typography-overline-font-weight, 500);
+ letter-spacing: 0.1666666667em;
+ /* @alternate */
+ letter-spacing: var(--mdc-typography-overline-letter-spacing, 0.1666666667em);
+ text-decoration: none;
+ /* @alternate */
+ -webkit-text-decoration: var(--mdc-typography-overline-text-decoration, none);
+ text-decoration: var(--mdc-typography-overline-text-decoration, none);
+ text-transform: uppercase;
+ /* @alternate */
+ text-transform: var(--mdc-typography-overline-text-transform, uppercase);
+}
+
+/*# sourceMappingURL=material-components-web.css.map*/
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/mdc/material-components-web.min.css b/pkgs/csslib/third_party/mdc/material-components-web.min.css
new file mode 100644
index 0000000..7194839
--- /dev/null
+++ b/pkgs/csslib/third_party/mdc/material-components-web.min.css
@@ -0,0 +1,10 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://github.com/material-components/material-components-web/blob/master/LICENSE
+ */
+ .mdc-banner__text{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-banner__graphic{color:#fff;color:var(--mdc-theme-surface, #fff)}.mdc-banner__graphic{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-banner__graphic{border-radius:50%}.mdc-banner__content,.mdc-banner__fixed{min-width:344px}@media(max-width: 480px),(max-width: 344px){.mdc-banner__content,.mdc-banner__fixed{min-width:100%}}.mdc-banner__content{max-width:720px}.mdc-banner{z-index:1;border-bottom-style:solid;border-bottom-width:1px;box-sizing:border-box;display:none;flex-shrink:0;height:0;position:relative;width:100%}@media(max-width: 480px){.mdc-banner .mdc-banner__fixed{left:0;right:0}.mdc-banner .mdc-banner__text{margin-left:16px;margin-right:36px}[dir=rtl] .mdc-banner .mdc-banner__text,.mdc-banner .mdc-banner__text[dir=rtl]{margin-left:36px;margin-right:16px}}@media(max-width: 480px){.mdc-banner.mdc-banner--mobile-stacked .mdc-banner__content{flex-wrap:wrap}.mdc-banner.mdc-banner--mobile-stacked .mdc-banner__graphic{margin-bottom:12px}.mdc-banner.mdc-banner--mobile-stacked .mdc-banner__text{margin-left:16px;margin-right:8px;padding-bottom:4px}[dir=rtl] .mdc-banner.mdc-banner--mobile-stacked .mdc-banner__text,.mdc-banner.mdc-banner--mobile-stacked .mdc-banner__text[dir=rtl]{margin-left:8px;margin-right:16px}.mdc-banner.mdc-banner--mobile-stacked .mdc-banner__actions{margin-left:auto}}.mdc-banner--opening,.mdc-banner--open,.mdc-banner--closing{display:flex}.mdc-banner--open{transition:height 300ms ease}.mdc-banner--open .mdc-banner__content{transition:-webkit-transform 300ms ease;transition:transform 300ms ease;transition:transform 300ms ease, -webkit-transform 300ms ease;-webkit-transform:translateY(0);transform:translateY(0)}.mdc-banner--closing{transition:height 250ms ease}.mdc-banner--closing .mdc-banner__content{transition:-webkit-transform 250ms ease;transition:transform 250ms ease;transition:transform 250ms ease, -webkit-transform 250ms ease}.mdc-banner--centered .mdc-banner__content{left:0;margin-left:auto;margin-right:auto;right:0}.mdc-banner__fixed{border-bottom-style:solid;border-bottom-width:1px;box-sizing:border-box;height:inherit;position:fixed;width:100%}.mdc-banner__content{display:flex;min-height:52px;position:absolute;-webkit-transform:translateY(-100%);transform:translateY(-100%);width:100%}.mdc-banner__graphic-text-wrapper{display:flex;width:100%}.mdc-banner__graphic{margin-left:16px;margin-right:0;flex-shrink:0;height:40px;margin-top:16px;margin-bottom:16px;text-align:center;width:40px}[dir=rtl] .mdc-banner__graphic,.mdc-banner__graphic[dir=rtl]{margin-left:0;margin-right:16px}.mdc-banner__icon{position:relative;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.mdc-banner__text{margin-left:24px;margin-right:90px;align-self:center;flex-grow:1;padding-top:16px;padding-bottom:16px}[dir=rtl] .mdc-banner__text,.mdc-banner__text[dir=rtl]{margin-left:90px;margin-right:24px}.mdc-banner__actions{padding-left:0;padding-right:8px;align-self:flex-end;display:flex;flex-shrink:0;padding-bottom:8px;padding-top:8px}[dir=rtl] .mdc-banner__actions,.mdc-banner__actions[dir=rtl]{padding-left:8px;padding-right:0}.mdc-banner__secondary-action{margin-left:0;margin-right:8px}[dir=rtl] .mdc-banner__secondary-action,.mdc-banner__secondary-action[dir=rtl]{margin-left:8px;margin-right:0}.mdc-banner{background-color:#fff;background-color:var(--mdc-theme-surface, #fff);border-bottom-color:rgba(0, 0, 0, 0.12)}.mdc-banner .mdc-banner__fixed{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-banner .mdc-banner__fixed{border-bottom-color:rgba(0, 0, 0, 0.12)}.mdc-banner__text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit)}.mdc-banner__primary-action:not(:disabled){color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-banner__primary-action::before,.mdc-banner__primary-action::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-banner__primary-action:hover::before,.mdc-banner__primary-action.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-banner__primary-action.mdc-ripple-upgraded--background-focused::before,.mdc-banner__primary-action:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-banner__primary-action:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-banner__primary-action:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-banner__primary-action.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-banner__secondary-action{margin-left:0;margin-right:8px}.mdc-banner__secondary-action:not(:disabled){color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-banner__secondary-action::before,.mdc-banner__secondary-action::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-banner__secondary-action:hover::before,.mdc-banner__secondary-action.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-banner__secondary-action.mdc-ripple-upgraded--background-focused::before,.mdc-banner__secondary-action:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-banner__secondary-action:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-banner__secondary-action:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-banner__secondary-action.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}[dir=rtl] .mdc-banner__secondary-action,.mdc-banner__secondary-action[dir=rtl]{margin-left:8px;margin-right:0}.mdc-touch-target-wrapper{display:inline}.mdc-elevation-overlay{position:absolute;border-radius:inherit;pointer-events:none;opacity:0;opacity:var(--mdc-elevation-overlay-opacity, 0);transition:opacity 280ms cubic-bezier(0.4, 0, 0.2, 1);background-color:#fff;background-color:var(--mdc-elevation-overlay-color, #fff)}.mdc-button{position:relative;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;min-width:64px;border:none;outline:none;line-height:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-appearance:none;overflow:visible;vertical-align:middle;background:transparent}.mdc-button .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-button::-moz-focus-inner{padding:0;border:0}.mdc-button:active{outline:none}.mdc-button:hover{cursor:pointer}.mdc-button:disabled{cursor:default;pointer-events:none}.mdc-button .mdc-button__icon{margin-left:0;margin-right:8px;display:inline-block;position:relative;vertical-align:top}[dir=rtl] .mdc-button .mdc-button__icon,.mdc-button .mdc-button__icon[dir=rtl]{margin-left:8px;margin-right:0}.mdc-button .mdc-button__touch{position:absolute;top:50%;height:48px;left:0;right:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.mdc-button__label+.mdc-button__icon{margin-left:8px;margin-right:0}[dir=rtl] .mdc-button__label+.mdc-button__icon,.mdc-button__label+.mdc-button__icon[dir=rtl]{margin-left:0;margin-right:8px}svg.mdc-button__icon{fill:currentColor}.mdc-button--raised .mdc-button__icon,.mdc-button--unelevated .mdc-button__icon,.mdc-button--outlined .mdc-button__icon{margin-left:-4px;margin-right:8px}[dir=rtl] .mdc-button--raised .mdc-button__icon,[dir=rtl] .mdc-button--unelevated .mdc-button__icon,[dir=rtl] .mdc-button--outlined .mdc-button__icon,.mdc-button--raised .mdc-button__icon[dir=rtl],.mdc-button--unelevated .mdc-button__icon[dir=rtl],.mdc-button--outlined .mdc-button__icon[dir=rtl]{margin-left:8px;margin-right:-4px}.mdc-button--raised .mdc-button__label+.mdc-button__icon,.mdc-button--unelevated .mdc-button__label+.mdc-button__icon,.mdc-button--outlined .mdc-button__label+.mdc-button__icon{margin-left:8px;margin-right:-4px}[dir=rtl] .mdc-button--raised .mdc-button__label+.mdc-button__icon,[dir=rtl] .mdc-button--unelevated .mdc-button__label+.mdc-button__icon,[dir=rtl] .mdc-button--outlined .mdc-button__label+.mdc-button__icon,.mdc-button--raised .mdc-button__label+.mdc-button__icon[dir=rtl],.mdc-button--unelevated .mdc-button__label+.mdc-button__icon[dir=rtl],.mdc-button--outlined .mdc-button__label+.mdc-button__icon[dir=rtl]{margin-left:-4px;margin-right:8px}.mdc-button--touch{margin-top:6px;margin-bottom:6px}.mdc-button{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none)}@-webkit-keyframes mdc-ripple-fg-radius-in{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);-webkit-transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@keyframes mdc-ripple-fg-radius-in{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);-webkit-transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@-webkit-keyframes mdc-ripple-fg-opacity-in{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@keyframes mdc-ripple-fg-opacity-in{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@-webkit-keyframes mdc-ripple-fg-opacity-out{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}@keyframes mdc-ripple-fg-opacity-out{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}.mdc-button{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-button .mdc-button__ripple::before,.mdc-button .mdc-button__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-button .mdc-button__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-button .mdc-button__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-button.mdc-ripple-upgraded--unbounded .mdc-button__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-button.mdc-ripple-upgraded--foreground-activation .mdc-button__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-button.mdc-ripple-upgraded--foreground-deactivation .mdc-button__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-button .mdc-button__ripple::before,.mdc-button .mdc-button__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-button.mdc-ripple-upgraded .mdc-button__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-button .mdc-button__ripple{position:absolute;box-sizing:content-box;width:100%;height:100%;overflow:hidden}.mdc-button:not(.mdc-button--outlined) .mdc-button__ripple{top:0;left:0}.mdc-button--raised{transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-button--outlined{border-style:solid}.mdc-button{font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);height:36px;border-radius:4px;border-radius:var(--mdc-shape-small, 4px);padding:0 8px 0 8px}.mdc-button:not(:disabled){color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-button:disabled{color:rgba(0, 0, 0, 0.38)}.mdc-button .mdc-button__icon{font-size:1.125rem;height:1.125rem;width:1.125rem}.mdc-button .mdc-button__ripple::before,.mdc-button .mdc-button__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-button:hover .mdc-button__ripple::before,.mdc-button.mdc-ripple-surface--hover .mdc-button__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-button.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before,.mdc-button:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-button:not(.mdc-ripple-upgraded) .mdc-button__ripple::after{transition:opacity 150ms linear}.mdc-button:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-button .mdc-button__ripple{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--unelevated{padding:0 16px 0 16px;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);height:36px;border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--unelevated.mdc-button--icon-trailing{padding:0 12px 0 16px}.mdc-button--unelevated.mdc-button--icon-leading{padding:0 16px 0 12px}.mdc-button--unelevated:not(:disabled){background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-button--unelevated:disabled{background-color:rgba(0, 0, 0, 0.12)}.mdc-button--unelevated:not(:disabled){color:#fff;color:var(--mdc-theme-on-primary, #fff)}.mdc-button--unelevated:disabled{color:rgba(0, 0, 0, 0.38)}.mdc-button--unelevated .mdc-button__icon{font-size:1.125rem;height:1.125rem;width:1.125rem}.mdc-button--unelevated .mdc-button__ripple::before,.mdc-button--unelevated .mdc-button__ripple::after{background-color:#fff;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-primary, #fff))}.mdc-button--unelevated:hover .mdc-button__ripple::before,.mdc-button--unelevated.mdc-ripple-surface--hover .mdc-button__ripple::before{opacity:0.08;opacity:var(--mdc-ripple-hover-opacity, 0.08)}.mdc-button--unelevated.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before,.mdc-button--unelevated:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-button--unelevated:not(.mdc-ripple-upgraded) .mdc-button__ripple::after{transition:opacity 150ms linear}.mdc-button--unelevated:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-button--unelevated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-button--unelevated .mdc-button__ripple{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--raised{padding:0 16px 0 16px;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);height:36px;border-radius:4px;border-radius:var(--mdc-shape-small, 4px);box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12)}.mdc-button--raised.mdc-button--icon-trailing{padding:0 12px 0 16px}.mdc-button--raised.mdc-button--icon-leading{padding:0 16px 0 12px}.mdc-button--raised:not(:disabled){background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee)}.mdc-button--raised:disabled{background-color:rgba(0, 0, 0, 0.12)}.mdc-button--raised:not(:disabled){color:#fff;color:var(--mdc-theme-on-primary, #fff)}.mdc-button--raised:disabled{color:rgba(0, 0, 0, 0.38)}.mdc-button--raised .mdc-button__icon{font-size:1.125rem;height:1.125rem;width:1.125rem}.mdc-button--raised .mdc-button__ripple::before,.mdc-button--raised .mdc-button__ripple::after{background-color:#fff;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-primary, #fff))}.mdc-button--raised:hover .mdc-button__ripple::before,.mdc-button--raised.mdc-ripple-surface--hover .mdc-button__ripple::before{opacity:0.08;opacity:var(--mdc-ripple-hover-opacity, 0.08)}.mdc-button--raised.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before,.mdc-button--raised:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-button--raised:not(.mdc-ripple-upgraded) .mdc-button__ripple::after{transition:opacity 150ms linear}.mdc-button--raised:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-button--raised.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-button--raised .mdc-button__ripple{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--raised.mdc-ripple-upgraded--background-focused,.mdc-button--raised:not(.mdc-ripple-upgraded):focus{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12)}.mdc-button--raised:hover{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12)}.mdc-button--raised:not(:disabled):active{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-button--raised:disabled{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2),0px 0px 0px 0px rgba(0, 0, 0, 0.14),0px 0px 0px 0px rgba(0,0,0,.12)}.mdc-button--outlined{font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);height:36px;border-radius:4px;border-radius:var(--mdc-shape-small, 4px);padding:0 15px 0 15px;border-width:1px}.mdc-button--outlined:not(:disabled){color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-button--outlined:disabled{color:rgba(0, 0, 0, 0.38)}.mdc-button--outlined .mdc-button__icon{font-size:1.125rem;height:1.125rem;width:1.125rem}.mdc-button--outlined .mdc-button__ripple::before,.mdc-button--outlined .mdc-button__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-button--outlined:hover .mdc-button__ripple::before,.mdc-button--outlined.mdc-ripple-surface--hover .mdc-button__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-button--outlined.mdc-ripple-upgraded--background-focused .mdc-button__ripple::before,.mdc-button--outlined:not(.mdc-ripple-upgraded):focus .mdc-button__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-button--outlined:not(.mdc-ripple-upgraded) .mdc-button__ripple::after{transition:opacity 150ms linear}.mdc-button--outlined:not(.mdc-ripple-upgraded):active .mdc-button__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-button--outlined.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-button--outlined .mdc-button__ripple{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-button--outlined:not(:disabled){border-color:rgba(0, 0, 0, 0.12)}.mdc-button--outlined:disabled{border-color:rgba(0, 0, 0, 0.12)}.mdc-button--outlined.mdc-button--icon-trailing{padding:0 11px 0 15px}.mdc-button--outlined.mdc-button--icon-leading{padding:0 15px 0 11px}.mdc-button--outlined .mdc-button__ripple{top:-1px;left:-1px;border:1px solid transparent}.mdc-button--outlined .mdc-button__touch{left:-1px;width:calc(100% + 2 * 1px)}.mdc-card{border-radius:4px;border-radius:var(--mdc-shape-medium, 4px);background-color:#fff;background-color:var(--mdc-theme-surface, #fff);position:relative;box-shadow:0px 2px 1px -1px rgba(0, 0, 0, 0.2),0px 1px 1px 0px rgba(0, 0, 0, 0.14),0px 1px 3px 0px rgba(0,0,0,.12);display:flex;flex-direction:column;box-sizing:border-box}.mdc-card .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-card::after{border-radius:4px;border-radius:var(--mdc-shape-medium, 4px);position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:"";pointer-events:none;pointer-events:none}.mdc-card--outlined{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2),0px 0px 0px 0px rgba(0, 0, 0, 0.14),0px 0px 0px 0px rgba(0,0,0,.12);border-width:1px;border-style:solid;border-color:#e0e0e0}.mdc-card--outlined::after{border:none}.mdc-card__content{border-radius:inherit;height:100%}.mdc-card__media{position:relative;box-sizing:border-box;background-repeat:no-repeat;background-position:center;background-size:cover}.mdc-card__media::before{display:block;content:""}.mdc-card__media:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.mdc-card__media:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.mdc-card__media--square::before{margin-top:100%}.mdc-card__media--16-9::before{margin-top:56.25%}.mdc-card__media-content{position:absolute;top:0;right:0;bottom:0;left:0;box-sizing:border-box}.mdc-card__primary-action{display:flex;flex-direction:column;box-sizing:border-box;position:relative;outline:none;color:inherit;text-decoration:none;cursor:pointer;overflow:hidden}.mdc-card__primary-action:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.mdc-card__primary-action:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.mdc-card__actions{display:flex;flex-direction:row;align-items:center;box-sizing:border-box;min-height:52px;padding:8px}.mdc-card__actions--full-bleed{padding:0}.mdc-card__action-buttons,.mdc-card__action-icons{display:flex;flex-direction:row;align-items:center;box-sizing:border-box}.mdc-card__action-icons{color:rgba(0, 0, 0, 0.6);flex-grow:1;justify-content:flex-end}.mdc-card__action-buttons+.mdc-card__action-icons{margin-left:16px;margin-right:0}[dir=rtl] .mdc-card__action-buttons+.mdc-card__action-icons,.mdc-card__action-buttons+.mdc-card__action-icons[dir=rtl]{margin-left:0;margin-right:16px}.mdc-card__action{display:inline-flex;flex-direction:row;align-items:center;box-sizing:border-box;justify-content:center;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdc-card__action:focus{outline:none}.mdc-card__action--button{margin-left:0;margin-right:8px;padding:0 8px}[dir=rtl] .mdc-card__action--button,.mdc-card__action--button[dir=rtl]{margin-left:8px;margin-right:0}.mdc-card__action--button:last-child{margin-left:0;margin-right:0}[dir=rtl] .mdc-card__action--button:last-child,.mdc-card__action--button:last-child[dir=rtl]{margin-left:0;margin-right:0}.mdc-card__actions--full-bleed .mdc-card__action--button{justify-content:space-between;width:100%;height:auto;max-height:none;margin:0;padding:8px 16px;text-align:left}[dir=rtl] .mdc-card__actions--full-bleed .mdc-card__action--button,.mdc-card__actions--full-bleed .mdc-card__action--button[dir=rtl]{text-align:right}.mdc-card__action--icon{margin:-6px 0;padding:12px}.mdc-card__action--icon:not(:disabled){color:rgba(0, 0, 0, 0.6)}.mdc-card__primary-action{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-card__primary-action .mdc-card__ripple::before,.mdc-card__primary-action .mdc-card__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-card__primary-action .mdc-card__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-card__primary-action .mdc-card__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-card__primary-action.mdc-ripple-upgraded .mdc-card__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-card__primary-action.mdc-ripple-upgraded .mdc-card__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-card__primary-action.mdc-ripple-upgraded--unbounded .mdc-card__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-card__primary-action.mdc-ripple-upgraded--foreground-activation .mdc-card__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-card__primary-action.mdc-ripple-upgraded--foreground-deactivation .mdc-card__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-card__primary-action .mdc-card__ripple::before,.mdc-card__primary-action .mdc-card__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-card__primary-action.mdc-ripple-upgraded .mdc-card__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-card__primary-action .mdc-card__ripple::before,.mdc-card__primary-action .mdc-card__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}.mdc-card__primary-action:hover .mdc-card__ripple::before,.mdc-card__primary-action.mdc-ripple-surface--hover .mdc-card__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-card__primary-action.mdc-ripple-upgraded--background-focused .mdc-card__ripple::before,.mdc-card__primary-action:not(.mdc-ripple-upgraded):focus .mdc-card__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-card__primary-action:not(.mdc-ripple-upgraded) .mdc-card__ripple::after{transition:opacity 150ms linear}.mdc-card__primary-action:not(.mdc-ripple-upgraded):active .mdc-card__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-card__primary-action.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-card__primary-action .mdc-card__ripple{box-sizing:content-box;height:100%;overflow:hidden;left:0;pointer-events:none;position:absolute;top:0;width:100%}.mdc-card__primary-action.mdc-ripple-upgraded--background-focused::after,.mdc-card__primary-action:not(.mdc-ripple-upgraded):focus::after{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:5px double transparent;border-radius:inherit;content:"";pointer-events:none}.mdc-checkbox{padding:calc((40px - 18px) / 2);padding:calc((var(--mdc-checkbox-ripple-size, 40px) - 18px) / 2);margin:calc((40px - 40px) / 2);margin:calc((var(--mdc-checkbox-touch-target-size, 40px) - 40px) / 2)}.mdc-checkbox .mdc-checkbox__ripple::before,.mdc-checkbox .mdc-checkbox__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}.mdc-checkbox:hover .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-ripple-surface--hover .mdc-checkbox__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-checkbox.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,.mdc-checkbox:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-checkbox:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after{transition:opacity 150ms linear}.mdc-checkbox:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-checkbox.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after{background-color:#018786;background-color:var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786))}.mdc-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-checkbox--selected.mdc-ripple-surface--hover .mdc-checkbox__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after{transition:opacity 150ms linear}.mdc-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after{background-color:#018786;background-color:var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786))}.mdc-checkbox .mdc-checkbox__background{top:calc((40px - 18px) / 2);top:calc((var(--mdc-checkbox-ripple-size, 40px) - 18px) / 2);left:calc((40px - 18px) / 2);left:calc((var(--mdc-checkbox-ripple-size, 40px) - 18px) / 2)}.mdc-checkbox .mdc-checkbox__native-control{top:calc((40px - 40px) / 2);top:calc((40px - var(--mdc-checkbox-touch-target-size, 40px)) / 2);right:calc((40px - 40px) / 2);right:calc((40px - var(--mdc-checkbox-touch-target-size, 40px)) / 2);left:calc((40px - 40px) / 2);left:calc((40px - var(--mdc-checkbox-touch-target-size, 40px)) / 2);width:40px;width:var(--mdc-checkbox-touch-target-size, 40px);height:40px;height:var(--mdc-checkbox-touch-target-size, 40px)}.mdc-checkbox .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}.mdc-checkbox .mdc-checkbox__native-control:enabled:checked~.mdc-checkbox__background,.mdc-checkbox .mdc-checkbox__native-control:enabled:indeterminate~.mdc-checkbox__background,.mdc-checkbox .mdc-checkbox__native-control[data-indeterminate=true]:enabled~.mdc-checkbox__background{border-color:#018786;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));background-color:#018786;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786))}@-webkit-keyframes mdc-checkbox-fade-in-background-8A000000FF01878600000000FF018786{0%{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}50%{border-color:#018786;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));background-color:#018786;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786))}}@keyframes mdc-checkbox-fade-in-background-8A000000FF01878600000000FF018786{0%{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}50%{border-color:#018786;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));background-color:#018786;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786))}}@-webkit-keyframes mdc-checkbox-fade-out-background-8A000000FF01878600000000FF018786{0%,80%{border-color:#018786;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));background-color:#018786;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786))}100%{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}}@keyframes mdc-checkbox-fade-out-background-8A000000FF01878600000000FF018786{0%,80%{border-color:#018786;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786));background-color:#018786;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #018786))}100%{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}}.mdc-checkbox.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-checkbox.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled~.mdc-checkbox__background{-webkit-animation-name:mdc-checkbox-fade-in-background-8A000000FF01878600000000FF018786;animation-name:mdc-checkbox-fade-in-background-8A000000FF01878600000000FF018786}.mdc-checkbox.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-checkbox.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background{-webkit-animation-name:mdc-checkbox-fade-out-background-8A000000FF01878600000000FF018786;animation-name:mdc-checkbox-fade-out-background-8A000000FF01878600000000FF018786}.mdc-checkbox .mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:rgba(0, 0, 0, 0.38);border-color:var(--mdc-checkbox-disabled-color, rgba(0, 0, 0, 0.38));background-color:transparent}.mdc-checkbox .mdc-checkbox__native-control[disabled]:checked~.mdc-checkbox__background,.mdc-checkbox .mdc-checkbox__native-control[disabled]:indeterminate~.mdc-checkbox__background,.mdc-checkbox .mdc-checkbox__native-control[data-indeterminate=true][disabled]~.mdc-checkbox__background{border-color:transparent;background-color:rgba(0, 0, 0, 0.38);background-color:var(--mdc-checkbox-disabled-color, rgba(0, 0, 0, 0.38))}.mdc-checkbox .mdc-checkbox__native-control:enabled~.mdc-checkbox__background .mdc-checkbox__checkmark{color:#fff;color:var(--mdc-checkbox-ink-color, #fff)}.mdc-checkbox .mdc-checkbox__native-control:enabled~.mdc-checkbox__background .mdc-checkbox__mixedmark{border-color:#fff;border-color:var(--mdc-checkbox-ink-color, #fff)}.mdc-checkbox .mdc-checkbox__native-control:disabled~.mdc-checkbox__background .mdc-checkbox__checkmark{color:#fff;color:var(--mdc-checkbox-ink-color, #fff)}.mdc-checkbox .mdc-checkbox__native-control:disabled~.mdc-checkbox__background .mdc-checkbox__mixedmark{border-color:#fff;border-color:var(--mdc-checkbox-ink-color, #fff)}@-webkit-keyframes mdc-checkbox-unchecked-checked-checkmark-path{0%,50%{stroke-dashoffset:29.7833385}50%{-webkit-animation-timing-function:cubic-bezier(0, 0, 0.2, 1);animation-timing-function:cubic-bezier(0, 0, 0.2, 1)}100%{stroke-dashoffset:0}}@keyframes mdc-checkbox-unchecked-checked-checkmark-path{0%,50%{stroke-dashoffset:29.7833385}50%{-webkit-animation-timing-function:cubic-bezier(0, 0, 0.2, 1);animation-timing-function:cubic-bezier(0, 0, 0.2, 1)}100%{stroke-dashoffset:0}}@-webkit-keyframes mdc-checkbox-unchecked-indeterminate-mixedmark{0%,68.2%{-webkit-transform:scaleX(0);transform:scaleX(0)}68.2%{-webkit-animation-timing-function:cubic-bezier(0, 0, 0, 1);animation-timing-function:cubic-bezier(0, 0, 0, 1)}100%{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes mdc-checkbox-unchecked-indeterminate-mixedmark{0%,68.2%{-webkit-transform:scaleX(0);transform:scaleX(0)}68.2%{-webkit-animation-timing-function:cubic-bezier(0, 0, 0, 1);animation-timing-function:cubic-bezier(0, 0, 0, 1)}100%{-webkit-transform:scaleX(1);transform:scaleX(1)}}@-webkit-keyframes mdc-checkbox-checked-unchecked-checkmark-path{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 1, 1);animation-timing-function:cubic-bezier(0.4, 0, 1, 1);opacity:1;stroke-dashoffset:0}to{opacity:0;stroke-dashoffset:-29.7833385}}@keyframes mdc-checkbox-checked-unchecked-checkmark-path{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 1, 1);animation-timing-function:cubic-bezier(0.4, 0, 1, 1);opacity:1;stroke-dashoffset:0}to{opacity:0;stroke-dashoffset:-29.7833385}}@-webkit-keyframes mdc-checkbox-checked-indeterminate-checkmark{from{-webkit-animation-timing-function:cubic-bezier(0, 0, 0.2, 1);animation-timing-function:cubic-bezier(0, 0, 0.2, 1);-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}to{-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}@keyframes mdc-checkbox-checked-indeterminate-checkmark{from{-webkit-animation-timing-function:cubic-bezier(0, 0, 0.2, 1);animation-timing-function:cubic-bezier(0, 0, 0.2, 1);-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}to{-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}@-webkit-keyframes mdc-checkbox-indeterminate-checked-checkmark{from{-webkit-animation-timing-function:cubic-bezier(0.14, 0, 0, 1);animation-timing-function:cubic-bezier(0.14, 0, 0, 1);-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}to{-webkit-transform:rotate(360deg);transform:rotate(360deg);opacity:1}}@keyframes mdc-checkbox-indeterminate-checked-checkmark{from{-webkit-animation-timing-function:cubic-bezier(0.14, 0, 0, 1);animation-timing-function:cubic-bezier(0.14, 0, 0, 1);-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}to{-webkit-transform:rotate(360deg);transform:rotate(360deg);opacity:1}}@-webkit-keyframes mdc-checkbox-checked-indeterminate-mixedmark{from{-webkit-animation-timing-function:mdc-animation-deceleration-curve-timing-function;animation-timing-function:mdc-animation-deceleration-curve-timing-function;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}to{-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}}@keyframes mdc-checkbox-checked-indeterminate-mixedmark{from{-webkit-animation-timing-function:mdc-animation-deceleration-curve-timing-function;animation-timing-function:mdc-animation-deceleration-curve-timing-function;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}to{-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}}@-webkit-keyframes mdc-checkbox-indeterminate-checked-mixedmark{from{-webkit-animation-timing-function:cubic-bezier(0.14, 0, 0, 1);animation-timing-function:cubic-bezier(0.14, 0, 0, 1);-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}to{-webkit-transform:rotate(315deg);transform:rotate(315deg);opacity:0}}@keyframes mdc-checkbox-indeterminate-checked-mixedmark{from{-webkit-animation-timing-function:cubic-bezier(0.14, 0, 0, 1);animation-timing-function:cubic-bezier(0.14, 0, 0, 1);-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}to{-webkit-transform:rotate(315deg);transform:rotate(315deg);opacity:0}}@-webkit-keyframes mdc-checkbox-indeterminate-unchecked-mixedmark{0%{-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform:scaleX(1);transform:scaleX(1);opacity:1}32.8%,100%{-webkit-transform:scaleX(0);transform:scaleX(0);opacity:0}}@keyframes mdc-checkbox-indeterminate-unchecked-mixedmark{0%{-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform:scaleX(1);transform:scaleX(1);opacity:1}32.8%,100%{-webkit-transform:scaleX(0);transform:scaleX(0);opacity:0}}.mdc-checkbox{display:inline-block;position:relative;flex:0 0 18px;box-sizing:content-box;width:18px;height:18px;line-height:0;white-space:nowrap;cursor:pointer;vertical-align:bottom}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:GrayText;border-color:var(--mdc-checkbox-disabled-color, GrayText);background-color:transparent}.mdc-checkbox__native-control[disabled]:checked~.mdc-checkbox__background,.mdc-checkbox__native-control[disabled]:indeterminate~.mdc-checkbox__background,.mdc-checkbox__native-control[data-indeterminate=true][disabled]~.mdc-checkbox__background{border-color:GrayText;background-color:transparent;background-color:var(--mdc-checkbox-disabled-color, transparent)}.mdc-checkbox__native-control:disabled~.mdc-checkbox__background .mdc-checkbox__checkmark{color:GrayText;color:var(--mdc-checkbox-ink-color, GrayText)}.mdc-checkbox__native-control:disabled~.mdc-checkbox__background .mdc-checkbox__mixedmark{border-color:GrayText;border-color:var(--mdc-checkbox-ink-color, GrayText)}.mdc-checkbox__mixedmark{margin:0 1px}}.mdc-checkbox--disabled{cursor:default;pointer-events:none}.mdc-checkbox__background{display:inline-flex;position:absolute;align-items:center;justify-content:center;box-sizing:border-box;width:18px;height:18px;border:2px solid currentColor;border-radius:2px;background-color:transparent;pointer-events:none;will-change:background-color,border-color;transition:background-color 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),border-color 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox__checkmark{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;opacity:0;transition:opacity 180ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox--upgraded .mdc-checkbox__checkmark{opacity:1}.mdc-checkbox__checkmark-path{transition:stroke-dashoffset 180ms 0ms cubic-bezier(0.4, 0, 0.6, 1);stroke:currentColor;stroke-width:3.12px;stroke-dashoffset:29.7833385;stroke-dasharray:29.7833385}.mdc-checkbox__mixedmark{width:100%;height:0;-webkit-transform:scaleX(0) rotate(0deg);transform:scaleX(0) rotate(0deg);border-width:1px;border-style:solid;opacity:0;transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__background,.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__background,.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__background,.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__background{-webkit-animation-duration:180ms;animation-duration:180ms;-webkit-animation-timing-function:linear;animation-timing-function:linear}.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__checkmark-path{-webkit-animation:mdc-checkbox-unchecked-checked-checkmark-path 180ms linear 0s;animation:mdc-checkbox-unchecked-checked-checkmark-path 180ms linear 0s;transition:none}.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__mixedmark{-webkit-animation:mdc-checkbox-unchecked-indeterminate-mixedmark 90ms linear 0s;animation:mdc-checkbox-unchecked-indeterminate-mixedmark 90ms linear 0s;transition:none}.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__checkmark-path{-webkit-animation:mdc-checkbox-checked-unchecked-checkmark-path 90ms linear 0s;animation:mdc-checkbox-checked-unchecked-checkmark-path 90ms linear 0s;transition:none}.mdc-checkbox--anim-checked-indeterminate .mdc-checkbox__checkmark{-webkit-animation:mdc-checkbox-checked-indeterminate-checkmark 90ms linear 0s;animation:mdc-checkbox-checked-indeterminate-checkmark 90ms linear 0s;transition:none}.mdc-checkbox--anim-checked-indeterminate .mdc-checkbox__mixedmark{-webkit-animation:mdc-checkbox-checked-indeterminate-mixedmark 90ms linear 0s;animation:mdc-checkbox-checked-indeterminate-mixedmark 90ms linear 0s;transition:none}.mdc-checkbox--anim-indeterminate-checked .mdc-checkbox__checkmark{-webkit-animation:mdc-checkbox-indeterminate-checked-checkmark 500ms linear 0s;animation:mdc-checkbox-indeterminate-checked-checkmark 500ms linear 0s;transition:none}.mdc-checkbox--anim-indeterminate-checked .mdc-checkbox__mixedmark{-webkit-animation:mdc-checkbox-indeterminate-checked-mixedmark 500ms linear 0s;animation:mdc-checkbox-indeterminate-checked-mixedmark 500ms linear 0s;transition:none}.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__mixedmark{-webkit-animation:mdc-checkbox-indeterminate-unchecked-mixedmark 300ms linear 0s;animation:mdc-checkbox-indeterminate-unchecked-mixedmark 300ms linear 0s;transition:none}.mdc-checkbox__native-control:checked~.mdc-checkbox__background,.mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background,.mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background{transition:border-color 90ms 0ms cubic-bezier(0, 0, 0.2, 1),background-color 90ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-checkbox__native-control:checked~.mdc-checkbox__background .mdc-checkbox__checkmark-path,.mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background .mdc-checkbox__checkmark-path,.mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background .mdc-checkbox__checkmark-path{stroke-dashoffset:0}.mdc-checkbox__native-control{position:absolute;margin:0;padding:0;opacity:0;cursor:inherit}.mdc-checkbox__native-control:disabled{cursor:default;pointer-events:none}.mdc-checkbox--touch{margin:calc((48px - 40px) / 2);margin:calc((var(--mdc-checkbox-state-layer-size, 48px) - var(--mdc-checkbox-state-layer-size, 40px)) / 2)}.mdc-checkbox--touch .mdc-checkbox__native-control{top:calc((40px - 48px) / 2);top:calc((var(--mdc-checkbox-state-layer-size, 40px) - var(--mdc-checkbox-state-layer-size, 48px)) / 2);right:calc((40px - 48px) / 2);right:calc((var(--mdc-checkbox-state-layer-size, 40px) - var(--mdc-checkbox-state-layer-size, 48px)) / 2);left:calc((40px - 48px) / 2);left:calc((var(--mdc-checkbox-state-layer-size, 40px) - var(--mdc-checkbox-state-layer-size, 48px)) / 2);width:48px;width:var(--mdc-checkbox-state-layer-size, 48px);height:48px;height:var(--mdc-checkbox-state-layer-size, 48px)}.mdc-checkbox__native-control:checked~.mdc-checkbox__background .mdc-checkbox__checkmark{transition:opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 180ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 180ms 0ms cubic-bezier(0, 0, 0.2, 1);opacity:1}.mdc-checkbox__native-control:checked~.mdc-checkbox__background .mdc-checkbox__mixedmark{-webkit-transform:scaleX(1) rotate(-45deg);transform:scaleX(1) rotate(-45deg)}.mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background .mdc-checkbox__checkmark,.mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background .mdc-checkbox__checkmark{-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0;transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 90ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-checkbox__native-control:indeterminate~.mdc-checkbox__background .mdc-checkbox__mixedmark,.mdc-checkbox__native-control[data-indeterminate=true]~.mdc-checkbox__background .mdc-checkbox__mixedmark{-webkit-transform:scaleX(1) rotate(0deg);transform:scaleX(1) rotate(0deg);opacity:1}.mdc-checkbox.mdc-checkbox--upgraded .mdc-checkbox__background,.mdc-checkbox.mdc-checkbox--upgraded .mdc-checkbox__checkmark,.mdc-checkbox.mdc-checkbox--upgraded .mdc-checkbox__checkmark-path,.mdc-checkbox.mdc-checkbox--upgraded .mdc-checkbox__mixedmark{transition:none}.mdc-checkbox{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-checkbox .mdc-checkbox__ripple::before,.mdc-checkbox .mdc-checkbox__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-checkbox .mdc-checkbox__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-checkbox .mdc-checkbox__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-checkbox.mdc-ripple-upgraded--unbounded .mdc-checkbox__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-checkbox.mdc-ripple-upgraded--foreground-activation .mdc-checkbox__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-checkbox.mdc-ripple-upgraded--foreground-deactivation .mdc-checkbox__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-checkbox .mdc-checkbox__ripple::before,.mdc-checkbox .mdc-checkbox__ripple::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::before,.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-checkbox.mdc-ripple-upgraded .mdc-checkbox__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-checkbox{z-index:0}.mdc-checkbox .mdc-checkbox__ripple::before,.mdc-checkbox .mdc-checkbox__ripple::after{z-index:-1;z-index:var(--mdc-ripple-z-index, -1)}.mdc-checkbox__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-deprecated-chip-trailing-action__touch{position:absolute;top:50%;height:48px;left:50%;width:48px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.mdc-deprecated-chip-trailing-action{border:none;display:inline-flex;position:relative;align-items:center;justify-content:center;box-sizing:border-box;padding:0;outline:none;cursor:pointer;-webkit-appearance:none;background:none}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__icon{height:18px;width:18px;font-size:18px}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__touch{width:26px}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__icon{fill:currentColor;color:inherit}.mdc-deprecated-chip-trailing-action{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::before,.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded--unbounded .mdc-deprecated-chip-trailing-action__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded--foreground-activation .mdc-deprecated-chip-trailing-action__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded--foreground-deactivation .mdc-deprecated-chip-trailing-action__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::before,.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::before,.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded .mdc-deprecated-chip-trailing-action__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::before,.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000))}.mdc-deprecated-chip-trailing-action:hover .mdc-deprecated-chip-trailing-action__ripple::before,.mdc-deprecated-chip-trailing-action.mdc-ripple-surface--hover .mdc-deprecated-chip-trailing-action__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded--background-focused .mdc-deprecated-chip-trailing-action__ripple::before,.mdc-deprecated-chip-trailing-action:not(.mdc-ripple-upgraded):focus .mdc-deprecated-chip-trailing-action__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-deprecated-chip-trailing-action:not(.mdc-ripple-upgraded) .mdc-deprecated-chip-trailing-action__ripple::after{transition:opacity 150ms linear}.mdc-deprecated-chip-trailing-action:not(.mdc-ripple-upgraded):active .mdc-deprecated-chip-trailing-action__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-deprecated-chip-trailing-action.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-deprecated-chip-trailing-action .mdc-deprecated-chip-trailing-action__ripple{position:absolute;box-sizing:content-box;width:100%;height:100%;overflow:hidden}.mdc-chip__icon--leading{color:rgba(0,0,0,.54)}.mdc-deprecated-chip-trailing-action{color:#000}.mdc-chip__icon--trailing{color:rgba(0,0,0,.54)}.mdc-chip__icon--trailing:hover{color:rgba(0,0,0,.62)}.mdc-chip__icon--trailing:focus{color:rgba(0,0,0,.87)}.mdc-chip__icon.mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden){width:20px;height:20px;font-size:20px}.mdc-deprecated-chip-trailing-action__icon{height:18px;width:18px;font-size:18px}.mdc-chip__icon.mdc-chip__icon--trailing{width:18px;height:18px;font-size:18px}.mdc-deprecated-chip-trailing-action{margin-left:4px;margin-right:-4px}[dir=rtl] .mdc-deprecated-chip-trailing-action,.mdc-deprecated-chip-trailing-action[dir=rtl]{margin-left:-4px;margin-right:4px}.mdc-chip__icon--trailing{margin-left:4px;margin-right:-4px}[dir=rtl] .mdc-chip__icon--trailing,.mdc-chip__icon--trailing[dir=rtl]{margin-left:-4px;margin-right:4px}.mdc-chip{border-radius:16px;background-color:#e0e0e0;color:rgba(0, 0, 0, 0.87);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);height:32px;position:relative;display:inline-flex;align-items:center;box-sizing:border-box;padding:0 12px;border-width:0;outline:none;cursor:pointer;-webkit-appearance:none}.mdc-chip .mdc-chip__ripple{border-radius:16px}.mdc-chip:hover{color:rgba(0, 0, 0, 0.87)}.mdc-chip.mdc-chip--selected .mdc-chip__checkmark,.mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden){margin-left:-4px;margin-right:4px}[dir=rtl] .mdc-chip.mdc-chip--selected .mdc-chip__checkmark,[dir=rtl] .mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden),.mdc-chip.mdc-chip--selected .mdc-chip__checkmark[dir=rtl],.mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden)[dir=rtl]{margin-left:4px;margin-right:-4px}.mdc-chip .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-chip::-moz-focus-inner{padding:0;border:0}.mdc-chip:hover{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-chip .mdc-chip__touch{position:absolute;top:50%;height:48px;left:0;right:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.mdc-chip--exit{transition:opacity 75ms cubic-bezier(0.4, 0, 0.2, 1),width 150ms cubic-bezier(0, 0, 0.2, 1),padding 100ms linear,margin 100ms linear;opacity:0}.mdc-chip__overflow{text-overflow:ellipsis;overflow:hidden}.mdc-chip__text{white-space:nowrap}.mdc-chip__icon{border-radius:50%;outline:none;vertical-align:middle}.mdc-chip__checkmark{height:20px}.mdc-chip__checkmark-path{transition:stroke-dashoffset 150ms 50ms cubic-bezier(0.4, 0, 0.6, 1);stroke-width:2px;stroke-dashoffset:29.7833385;stroke-dasharray:29.7833385}.mdc-chip__primary-action:focus{outline:none}.mdc-chip--selected .mdc-chip__checkmark-path{stroke-dashoffset:0}.mdc-chip__icon--leading,.mdc-chip__icon--trailing{position:relative}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__icon--leading{color:rgba(98,0,238,.54)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:hover{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-chip-set--choice .mdc-chip .mdc-chip__checkmark-path{stroke:#6200ee;stroke:var(--mdc-theme-primary, #6200ee)}.mdc-chip-set--choice .mdc-chip--selected{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-chip__checkmark-svg{width:0;height:20px;transition:width 150ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-chip--selected .mdc-chip__checkmark-svg{width:20px}.mdc-chip-set--filter .mdc-chip__icon--leading{transition:opacity 75ms linear;transition-delay:-50ms;opacity:1}.mdc-chip-set--filter .mdc-chip__icon--leading+.mdc-chip__checkmark{transition:opacity 75ms linear;transition-delay:80ms;opacity:0}.mdc-chip-set--filter .mdc-chip__icon--leading+.mdc-chip__checkmark .mdc-chip__checkmark-svg{transition:width 0ms}.mdc-chip-set--filter .mdc-chip--selected .mdc-chip__icon--leading{opacity:0}.mdc-chip-set--filter .mdc-chip--selected .mdc-chip__icon--leading+.mdc-chip__checkmark{width:0;opacity:1}.mdc-chip-set--filter .mdc-chip__icon--leading-hidden.mdc-chip__icon--leading{width:0;opacity:0}.mdc-chip-set--filter .mdc-chip__icon--leading-hidden.mdc-chip__icon--leading+.mdc-chip__checkmark{width:20px}.mdc-chip{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-chip .mdc-chip__ripple::before,.mdc-chip .mdc-chip__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-chip .mdc-chip__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-chip .mdc-chip__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-chip.mdc-ripple-upgraded--unbounded .mdc-chip__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-chip.mdc-ripple-upgraded--foreground-activation .mdc-chip__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-chip.mdc-ripple-upgraded--foreground-deactivation .mdc-chip__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-chip .mdc-chip__ripple::before,.mdc-chip .mdc-chip__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-chip.mdc-ripple-upgraded .mdc-chip__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-chip .mdc-chip__ripple::before,.mdc-chip .mdc-chip__ripple::after{background-color:rgba(0, 0, 0, 0.87);background-color:var(--mdc-ripple-color, rgba(0, 0, 0, 0.87))}.mdc-chip:hover .mdc-chip__ripple::before,.mdc-chip.mdc-ripple-surface--hover .mdc-chip__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-chip.mdc-ripple-upgraded--background-focused .mdc-chip__ripple::before,.mdc-chip.mdc-ripple-upgraded:focus-within .mdc-chip__ripple::before,.mdc-chip:not(.mdc-ripple-upgraded):focus .mdc-chip__ripple::before,.mdc-chip:not(.mdc-ripple-upgraded):focus-within .mdc-chip__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-chip:not(.mdc-ripple-upgraded) .mdc-chip__ripple::after{transition:opacity 150ms linear}.mdc-chip:not(.mdc-ripple-upgraded):active .mdc-chip__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-chip.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-chip .mdc-chip__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;overflow:hidden}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::before{opacity:0.08;opacity:var(--mdc-ripple-selected-opacity, 0.08)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected .mdc-chip__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:hover .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-surface--hover .mdc-chip__ripple::before{opacity:0.12;opacity:var(--mdc-ripple-hover-opacity, 0.12)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded--background-focused .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded:focus-within .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):focus .mdc-chip__ripple::before,.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):focus-within .mdc-chip__ripple::before{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-focus-opacity, 0.2)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded) .mdc-chip__ripple::after{transition:opacity 150ms linear}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected:not(.mdc-ripple-upgraded):active .mdc-chip__ripple::after{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-press-opacity, 0.2)}.mdc-chip-set--choice .mdc-chip.mdc-chip--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.2)}@-webkit-keyframes mdc-chip-entry{from{-webkit-transform:scale(0.8);transform:scale(0.8);opacity:.4}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes mdc-chip-entry{from{-webkit-transform:scale(0.8);transform:scale(0.8);opacity:.4}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.mdc-chip-set{padding:4px;display:flex;flex-wrap:wrap;box-sizing:border-box}.mdc-chip-set .mdc-chip{margin:4px}.mdc-chip-set .mdc-chip--touch{margin-top:8px;margin-bottom:8px}.mdc-chip-set--input .mdc-chip{-webkit-animation:mdc-chip-entry 100ms cubic-bezier(0, 0, 0.2, 1);animation:mdc-chip-entry 100ms cubic-bezier(0, 0, 0.2, 1)}.mdc-circular-progress__determinate-circle,.mdc-circular-progress__indeterminate-circle-graphic{stroke:#6200ee;stroke:var(--mdc-theme-primary, #6200ee)}.mdc-circular-progress__determinate-track{stroke:transparent}@-webkit-keyframes mdc-circular-progress-container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes mdc-circular-progress-container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes mdc-circular-progress-spinner-layer-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}100%{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@keyframes mdc-circular-progress-spinner-layer-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}100%{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@-webkit-keyframes mdc-circular-progress-color-1-fade-in-out{from{opacity:.99}25%{opacity:.99}26%{opacity:0}89%{opacity:0}90%{opacity:.99}to{opacity:.99}}@keyframes mdc-circular-progress-color-1-fade-in-out{from{opacity:.99}25%{opacity:.99}26%{opacity:0}89%{opacity:0}90%{opacity:.99}to{opacity:.99}}@-webkit-keyframes mdc-circular-progress-color-2-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:.99}50%{opacity:.99}51%{opacity:0}to{opacity:0}}@keyframes mdc-circular-progress-color-2-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:.99}50%{opacity:.99}51%{opacity:0}to{opacity:0}}@-webkit-keyframes mdc-circular-progress-color-3-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:.99}75%{opacity:.99}76%{opacity:0}to{opacity:0}}@keyframes mdc-circular-progress-color-3-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:.99}75%{opacity:.99}76%{opacity:0}to{opacity:0}}@-webkit-keyframes mdc-circular-progress-color-4-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:.99}90%{opacity:.99}to{opacity:0}}@keyframes mdc-circular-progress-color-4-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:.99}90%{opacity:.99}to{opacity:0}}@-webkit-keyframes mdc-circular-progress-left-spin{from{-webkit-transform:rotate(265deg);transform:rotate(265deg)}50%{-webkit-transform:rotate(130deg);transform:rotate(130deg)}to{-webkit-transform:rotate(265deg);transform:rotate(265deg)}}@keyframes mdc-circular-progress-left-spin{from{-webkit-transform:rotate(265deg);transform:rotate(265deg)}50%{-webkit-transform:rotate(130deg);transform:rotate(130deg)}to{-webkit-transform:rotate(265deg);transform:rotate(265deg)}}@-webkit-keyframes mdc-circular-progress-right-spin{from{-webkit-transform:rotate(-265deg);transform:rotate(-265deg)}50%{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}to{-webkit-transform:rotate(-265deg);transform:rotate(-265deg)}}@keyframes mdc-circular-progress-right-spin{from{-webkit-transform:rotate(-265deg);transform:rotate(-265deg)}50%{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}to{-webkit-transform:rotate(-265deg);transform:rotate(-265deg)}}.mdc-circular-progress{display:inline-flex;position:relative;direction:ltr;line-height:0;transition:opacity 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-circular-progress__determinate-container,.mdc-circular-progress__indeterminate-circle-graphic,.mdc-circular-progress__indeterminate-container,.mdc-circular-progress__spinner-layer{position:absolute;width:100%;height:100%}.mdc-circular-progress__determinate-container{-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}.mdc-circular-progress__indeterminate-container{font-size:0;letter-spacing:0;white-space:nowrap;opacity:0}.mdc-circular-progress__determinate-circle-graphic,.mdc-circular-progress__indeterminate-circle-graphic{fill:transparent}.mdc-circular-progress__determinate-circle{transition:stroke-dashoffset 500ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-circular-progress__gap-patch{position:absolute;top:0;left:47.5%;box-sizing:border-box;width:5%;height:100%;overflow:hidden}.mdc-circular-progress__gap-patch .mdc-circular-progress__indeterminate-circle-graphic{left:-900%;width:2000%;-webkit-transform:rotate(180deg);transform:rotate(180deg)}.mdc-circular-progress__circle-clipper{display:inline-flex;position:relative;width:50%;height:100%;overflow:hidden}.mdc-circular-progress__circle-clipper .mdc-circular-progress__indeterminate-circle-graphic{width:200%}.mdc-circular-progress__circle-right .mdc-circular-progress__indeterminate-circle-graphic{left:-100%}.mdc-circular-progress--indeterminate .mdc-circular-progress__determinate-container{opacity:0}.mdc-circular-progress--indeterminate .mdc-circular-progress__indeterminate-container{opacity:1}.mdc-circular-progress--indeterminate .mdc-circular-progress__indeterminate-container{-webkit-animation:mdc-circular-progress-container-rotate 1568.2352941176ms linear infinite;animation:mdc-circular-progress-container-rotate 1568.2352941176ms linear infinite}.mdc-circular-progress--indeterminate .mdc-circular-progress__spinner-layer{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__color-1{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__color-2{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__color-3{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__color-4{-webkit-animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,mdc-circular-progress-color-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__circle-left .mdc-circular-progress__indeterminate-circle-graphic{-webkit-animation:mdc-circular-progress-left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--indeterminate .mdc-circular-progress__circle-right .mdc-circular-progress__indeterminate-circle-graphic{-webkit-animation:mdc-circular-progress-right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:mdc-circular-progress-right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.mdc-circular-progress--closed{opacity:0}.mdc-floating-label{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);position:absolute;left:0;-webkit-transform-origin:left top;transform-origin:left top;line-height:1.15rem;text-align:left;text-overflow:ellipsis;white-space:nowrap;cursor:text;overflow:hidden;will-change:transform;transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1),color 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms cubic-bezier(0.4, 0, 0.2, 1),color 150ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-floating-label,.mdc-floating-label[dir=rtl]{right:0;left:auto;-webkit-transform-origin:right top;transform-origin:right top;text-align:right}.mdc-floating-label--float-above{cursor:auto}.mdc-floating-label--required::after{margin-left:1px;margin-right:0px;content:"*"}[dir=rtl] .mdc-floating-label--required::after,.mdc-floating-label--required[dir=rtl]::after{margin-left:0;margin-right:1px}.mdc-floating-label--float-above{-webkit-transform:translateY(-106%) scale(0.75);transform:translateY(-106%) scale(0.75)}.mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-standard 250ms 1;animation:mdc-floating-label-shake-float-above-standard 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-standard{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-standard{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-106%) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-106%) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-106%) scale(0.75)}}.mdc-line-ripple::before,.mdc-line-ripple::after{position:absolute;bottom:0;left:0;width:100%;border-bottom-style:solid;content:""}.mdc-line-ripple::before{border-bottom-width:1px;z-index:1}.mdc-line-ripple::after{-webkit-transform:scaleX(0);transform:scaleX(0);border-bottom-width:2px;opacity:0;z-index:2}.mdc-line-ripple::after{transition:opacity 180ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 180ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 180ms cubic-bezier(0.4, 0, 0.2, 1),opacity 180ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 180ms cubic-bezier(0.4, 0, 0.2, 1),opacity 180ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 180ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-line-ripple--active::after{-webkit-transform:scaleX(1);transform:scaleX(1);opacity:1}.mdc-line-ripple--deactivating::after{opacity:0}.mdc-notched-outline{display:flex;position:absolute;top:0;right:0;left:0;box-sizing:border-box;width:100%;max-width:100%;height:100%;text-align:left;pointer-events:none}[dir=rtl] .mdc-notched-outline,.mdc-notched-outline[dir=rtl]{text-align:right}.mdc-notched-outline__leading,.mdc-notched-outline__notch,.mdc-notched-outline__trailing{box-sizing:border-box;height:100%;border-top:1px solid;border-bottom:1px solid;pointer-events:none}.mdc-notched-outline__leading{border-left:1px solid;border-right:none;width:12px}[dir=rtl] .mdc-notched-outline__leading,.mdc-notched-outline__leading[dir=rtl]{border-left:none;border-right:1px solid}.mdc-notched-outline__trailing{border-left:none;border-right:1px solid;flex-grow:1}[dir=rtl] .mdc-notched-outline__trailing,.mdc-notched-outline__trailing[dir=rtl]{border-left:1px solid;border-right:none}.mdc-notched-outline__notch{flex:0 0 auto;width:auto;max-width:calc(100% - 12px * 2)}.mdc-notched-outline .mdc-floating-label{display:inline-block;position:relative;max-width:100%}.mdc-notched-outline .mdc-floating-label--float-above{text-overflow:clip}.mdc-notched-outline--upgraded .mdc-floating-label--float-above{max-width:calc(100% / 0.75)}.mdc-notched-outline--notched .mdc-notched-outline__notch{padding-left:0;padding-right:8px;border-top:none}[dir=rtl] .mdc-notched-outline--notched .mdc-notched-outline__notch,.mdc-notched-outline--notched .mdc-notched-outline__notch[dir=rtl]{padding-left:8px;padding-right:0}.mdc-notched-outline--no-label .mdc-notched-outline__notch{display:none}.mdc-select{display:inline-flex;position:relative}.mdc-select:not(.mdc-select--disabled) .mdc-select__selected-text{color:rgba(0, 0, 0, 0.87)}.mdc-select.mdc-select--disabled .mdc-select__selected-text{color:rgba(0, 0, 0, 0.38)}.mdc-select:not(.mdc-select--disabled) .mdc-floating-label{color:rgba(0, 0, 0, 0.6)}.mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label{color:rgba(98, 0, 238, 0.87)}.mdc-select.mdc-select--disabled .mdc-floating-label{color:rgba(0, 0, 0, 0.38)}.mdc-select:not(.mdc-select--disabled) .mdc-select__dropdown-icon{fill:rgba(0, 0, 0, 0.54)}.mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-select__dropdown-icon{fill:#6200ee;fill:var(--mdc-theme-primary, #6200ee)}.mdc-select.mdc-select--disabled .mdc-select__dropdown-icon{fill:rgba(0, 0, 0, 0.38)}.mdc-select:not(.mdc-select--disabled)+.mdc-select-helper-text{color:rgba(0, 0, 0, 0.6)}.mdc-select.mdc-select--disabled+.mdc-select-helper-text{color:rgba(0, 0, 0, 0.38)}.mdc-select:not(.mdc-select--disabled) .mdc-select__icon{color:rgba(0, 0, 0, 0.54)}.mdc-select.mdc-select--disabled .mdc-select__icon{color:rgba(0, 0, 0, 0.38)}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-select.mdc-select--disabled .mdc-select__selected-text{color:GrayText}.mdc-select.mdc-select--disabled .mdc-select__dropdown-icon{fill:red}.mdc-select.mdc-select--disabled .mdc-floating-label{color:GrayText}.mdc-select.mdc-select--disabled .mdc-line-ripple::before{border-bottom-color:GrayText}.mdc-select.mdc-select--disabled .mdc-notched-outline__leading,.mdc-select.mdc-select--disabled .mdc-notched-outline__notch,.mdc-select.mdc-select--disabled .mdc-notched-outline__trailing{border-color:GrayText}.mdc-select.mdc-select--disabled .mdc-select__icon{color:GrayText}.mdc-select.mdc-select--disabled+.mdc-select-helper-text{color:GrayText}}.mdc-select .mdc-floating-label{top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);pointer-events:none}.mdc-select .mdc-select__anchor{padding-left:16px;padding-right:0}[dir=rtl] .mdc-select .mdc-select__anchor,.mdc-select .mdc-select__anchor[dir=rtl]{padding-left:0;padding-right:16px}.mdc-select.mdc-select--with-leading-icon .mdc-select__anchor{padding-left:0;padding-right:0}[dir=rtl] .mdc-select.mdc-select--with-leading-icon .mdc-select__anchor,.mdc-select.mdc-select--with-leading-icon .mdc-select__anchor[dir=rtl]{padding-left:0;padding-right:0}.mdc-select .mdc-select__icon{width:24px;height:24px;font-size:24px}.mdc-select .mdc-select__dropdown-icon{width:24px;height:24px}.mdc-select .mdc-select__menu .mdc-deprecated-list-item{padding-left:16px;padding-right:16px}[dir=rtl] .mdc-select .mdc-select__menu .mdc-deprecated-list-item,.mdc-select .mdc-select__menu .mdc-deprecated-list-item[dir=rtl]{padding-left:16px;padding-right:16px}.mdc-select .mdc-select__menu .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:12px}[dir=rtl] .mdc-select .mdc-select__menu .mdc-deprecated-list-item__graphic,.mdc-select .mdc-select__menu .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:12px;margin-right:0}.mdc-select__dropdown-icon{margin-left:12px;margin-right:12px;display:inline-flex;position:relative;align-self:center;align-items:center;justify-content:center;flex-shrink:0;pointer-events:none}.mdc-select__dropdown-icon .mdc-select__dropdown-icon-active,.mdc-select__dropdown-icon .mdc-select__dropdown-icon-inactive{position:absolute;top:0;left:0}.mdc-select__dropdown-icon .mdc-select__dropdown-icon-graphic{width:41.6666666667%;height:20.8333333333%}.mdc-select__dropdown-icon .mdc-select__dropdown-icon-inactive{opacity:1;transition:opacity 75ms linear 75ms}.mdc-select__dropdown-icon .mdc-select__dropdown-icon-active{opacity:0;transition:opacity 75ms linear}[dir=rtl] .mdc-select__dropdown-icon,.mdc-select__dropdown-icon[dir=rtl]{margin-left:12px;margin-right:12px}.mdc-select--activated .mdc-select__dropdown-icon .mdc-select__dropdown-icon-inactive{opacity:0;transition:opacity 49.5ms linear}.mdc-select--activated .mdc-select__dropdown-icon .mdc-select__dropdown-icon-active{opacity:1;transition:opacity 100.5ms linear 49.5ms}.mdc-select__anchor{width:200px;min-width:0;flex:1 1 auto;position:relative;box-sizing:border-box;overflow:hidden;outline:none;cursor:pointer}.mdc-select__anchor .mdc-floating-label--float-above{-webkit-transform:translateY(-106%) scale(0.75);transform:translateY(-106%) scale(0.75)}.mdc-select__selected-text-container{display:flex;-webkit-appearance:none;-moz-appearance:none;appearance:none;pointer-events:none;box-sizing:border-box;width:auto;min-width:0;flex-grow:1;height:28px;border:none;outline:none;padding:0;background-color:transparent;color:inherit}.mdc-select__selected-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block;width:100%;text-align:left}[dir=rtl] .mdc-select__selected-text,.mdc-select__selected-text[dir=rtl]{text-align:right}.mdc-select--invalid:not(.mdc-select--disabled) .mdc-floating-label{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--invalid+.mdc-select-helper-text--validation-msg{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled) .mdc-select__dropdown-icon{fill:#b00020;fill:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-select__dropdown-icon{fill:#b00020;fill:var(--mdc-theme-error, #b00020)}.mdc-select--disabled{cursor:default;pointer-events:none}.mdc-select--with-leading-icon .mdc-select__menu .mdc-deprecated-list-item{padding-left:12px;padding-right:12px}[dir=rtl] .mdc-select--with-leading-icon .mdc-select__menu .mdc-deprecated-list-item,.mdc-select--with-leading-icon .mdc-select__menu .mdc-deprecated-list-item[dir=rtl]{padding-left:12px;padding-right:12px}.mdc-select__menu .mdc-deprecated-list .mdc-select__icon{margin-left:0;margin-right:0}[dir=rtl] .mdc-select__menu .mdc-deprecated-list .mdc-select__icon,.mdc-select__menu .mdc-deprecated-list .mdc-select__icon[dir=rtl]{margin-left:0;margin-right:0}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected,.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--activated{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-deprecated-list-item__graphic,.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--activated .mdc-deprecated-list-item__graphic{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-select--filled .mdc-select__anchor{height:56px;display:flex;align-items:baseline}.mdc-select--filled .mdc-select__anchor::before{display:inline-block;width:0;height:40px;content:"";vertical-align:0}.mdc-select--filled.mdc-select--no-label .mdc-select__anchor .mdc-select__selected-text::before{content:""}.mdc-select--filled.mdc-select--no-label .mdc-select__anchor .mdc-select__selected-text-container{height:100%;display:inline-flex;align-items:center}.mdc-select--filled.mdc-select--no-label .mdc-select__anchor::before{display:none}.mdc-select--filled .mdc-select__anchor{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:0;border-bottom-left-radius:0}.mdc-select--filled:not(.mdc-select--disabled) .mdc-select__anchor{background-color:whitesmoke}.mdc-select--filled.mdc-select--disabled .mdc-select__anchor{background-color:#fafafa}.mdc-select--filled:not(.mdc-select--disabled) .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.42)}.mdc-select--filled:not(.mdc-select--disabled):hover .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.87)}.mdc-select--filled:not(.mdc-select--disabled) .mdc-line-ripple::after{border-bottom-color:#6200ee;border-bottom-color:var(--mdc-theme-primary, #6200ee)}.mdc-select--filled.mdc-select--disabled .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.06)}.mdc-select--filled .mdc-floating-label{max-width:calc(100% - 64px)}.mdc-select--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 64px / 0.75)}.mdc-select--filled .mdc-menu-surface--is-open-below{border-top-left-radius:0px;border-top-right-radius:0px}.mdc-select--filled.mdc-select--focused.mdc-line-ripple::after{-webkit-transform:scale(1, 2);transform:scale(1, 2);opacity:1}.mdc-select--filled .mdc-floating-label{left:16px;right:initial}[dir=rtl] .mdc-select--filled .mdc-floating-label,.mdc-select--filled .mdc-floating-label[dir=rtl]{left:initial;right:16px}.mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label{left:48px;right:initial}[dir=rtl] .mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label,.mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label[dir=rtl]{left:initial;right:48px}.mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label{max-width:calc(100% - 96px)}.mdc-select--filled.mdc-select--with-leading-icon .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 96px / 0.75)}.mdc-select--invalid:not(.mdc-select--disabled) .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled):hover .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-select--invalid:not(.mdc-select--disabled) .mdc-line-ripple::after{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-select--outlined{border:none}.mdc-select--outlined .mdc-select__anchor{height:56px}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) scale(1);transform:translateY(-37.25px) scale(1)}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above{font-size:.75rem}.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) scale(0.75);transform:translateY(-34.75px) scale(0.75)}.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-select-outlined-56px 250ms 1;animation:mdc-floating-label-shake-float-above-select-outlined-56px 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-56px{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-select-outlined-56px{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}}.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:4px;border-bottom-left-radius:var(--mdc-shape-small, 4px)}[dir=rtl] .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading[dir=rtl]{border-top-left-radius:0;border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:4px;border-bottom-right-radius:var(--mdc-shape-small, 4px);border-bottom-left-radius:0}@supports(top: max(0%)){.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__leading{width:max(12px, var(--mdc-shape-small, 4px))}}@supports(top: max(0%)){.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__notch{max-width:calc(100% - max(12px, var(--mdc-shape-small, 4px)) * 2)}}.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing{border-top-left-radius:0;border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:4px;border-bottom-right-radius:var(--mdc-shape-small, 4px);border-bottom-left-radius:0}[dir=rtl] .mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing,.mdc-select--outlined .mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl]{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:4px;border-bottom-left-radius:var(--mdc-shape-small, 4px)}@supports(top: max(0%)){.mdc-select--outlined .mdc-select__anchor{padding-left:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}[dir=rtl] .mdc-select--outlined .mdc-select__anchor,.mdc-select--outlined .mdc-select__anchor[dir=rtl]{padding-left:0}@supports(top: max(0%)){[dir=rtl] .mdc-select--outlined .mdc-select__anchor,.mdc-select--outlined .mdc-select__anchor[dir=rtl]{padding-right:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}@supports(top: max(0%)){.mdc-select--outlined+.mdc-select-helper-text{margin-left:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}[dir=rtl] .mdc-select--outlined+.mdc-select-helper-text,.mdc-select--outlined+.mdc-select-helper-text[dir=rtl]{margin-left:0}@supports(top: max(0%)){[dir=rtl] .mdc-select--outlined+.mdc-select-helper-text,.mdc-select--outlined+.mdc-select-helper-text[dir=rtl]{margin-right:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}.mdc-select--outlined:not(.mdc-select--disabled) .mdc-select__anchor{background-color:transparent}.mdc-select--outlined.mdc-select--disabled .mdc-select__anchor{background-color:transparent}.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__leading,.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__notch,.mdc-select--outlined:not(.mdc-select--disabled) .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.38)}.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.87)}.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing{border-width:2px}.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-select--outlined.mdc-select--disabled .mdc-notched-outline__leading,.mdc-select--outlined.mdc-select--disabled .mdc-notched-outline__notch,.mdc-select--outlined.mdc-select--disabled .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.06)}.mdc-select--outlined .mdc-select__anchor :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mdc-select--outlined .mdc-select__anchor{display:flex;align-items:baseline;overflow:visible}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-select-outlined 250ms 1;animation:mdc-floating-label-shake-float-above-select-outlined 250ms 1}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) scale(1);transform:translateY(-37.25px) scale(1)}.mdc-select--outlined .mdc-select__anchor .mdc-floating-label--float-above{font-size:.75rem}.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) scale(0.75);transform:translateY(-34.75px) scale(0.75)}.mdc-select--outlined .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-select--outlined .mdc-select__anchor .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:1px}.mdc-select--outlined .mdc-select__anchor .mdc-select__selected-text::before{content:""}.mdc-select--outlined .mdc-select__anchor .mdc-select__selected-text-container{height:100%;display:inline-flex;align-items:center}.mdc-select--outlined .mdc-select__anchor::before{display:none}.mdc-select--outlined .mdc-select__selected-text-container{display:flex;border:none;z-index:1;background-color:transparent}.mdc-select--outlined .mdc-select__icon{z-index:2}.mdc-select--outlined .mdc-floating-label{line-height:1.15rem;left:4px;right:initial}[dir=rtl] .mdc-select--outlined .mdc-floating-label,.mdc-select--outlined .mdc-floating-label[dir=rtl]{left:initial;right:4px}.mdc-select--outlined.mdc-select--focused .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:2px}.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled) .mdc-notched-outline__leading,.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled) .mdc-notched-outline__notch,.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled) .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled):not(.mdc-select--focused) .mdc-select__anchor:hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing{border-width:2px}.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__leading,.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__notch,.mdc-select--outlined.mdc-select--invalid:not(.mdc-select--disabled).mdc-select--focused .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label{left:36px;right:initial}[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label,.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label[dir=rtl]{left:initial;right:36px}.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) translateX(-32px) scale(1);transform:translateY(-37.25px) translateX(-32px) scale(1)}[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--float-above,.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--float-above[dir=rtl]{-webkit-transform:translateY(-37.25px) translateX(32px) scale(1);transform:translateY(-37.25px) translateX(32px) scale(1)}.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--float-above{font-size:.75rem}.mdc-select--outlined.mdc-select--with-leading-icon.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined.mdc-select--with-leading-icon .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) translateX(-32px) scale(0.75);transform:translateY(-34.75px) translateX(-32px) scale(0.75)}[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon.mdc-notched-outline--upgraded .mdc-floating-label--float-above,[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon .mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined.mdc-select--with-leading-icon.mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl],.mdc-select--outlined.mdc-select--with-leading-icon .mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl]{-webkit-transform:translateY(-34.75px) translateX(32px) scale(0.75);transform:translateY(-34.75px) translateX(32px) scale(0.75)}.mdc-select--outlined.mdc-select--with-leading-icon.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-select--outlined.mdc-select--with-leading-icon .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px 250ms 1;animation:mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px{0%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px{0%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}[dir=rtl] .mdc-select--outlined.mdc-select--with-leading-icon .mdc-floating-label--shake,.mdc-select--outlined.mdc-select--with-leading-icon[dir=rtl] .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px 250ms 1;animation:mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px-rtl{0%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-select-outlined-leading-icon-56px-rtl{0%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}.mdc-select--outlined.mdc-select--with-leading-icon .mdc-select__anchor :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 96px)}.mdc-select--outlined .mdc-menu-surface{margin-bottom:8px}.mdc-select--outlined.mdc-select--no-label .mdc-menu-surface,.mdc-select--outlined .mdc-menu-surface--is-open-below{margin-bottom:0}.mdc-select__anchor{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-select__anchor .mdc-select__ripple::before,.mdc-select__anchor .mdc-select__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-select__anchor .mdc-select__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-select__anchor .mdc-select__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-select__anchor.mdc-ripple-upgraded--unbounded .mdc-select__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-select__anchor.mdc-ripple-upgraded--foreground-activation .mdc-select__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-select__anchor.mdc-ripple-upgraded--foreground-deactivation .mdc-select__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-select__anchor .mdc-select__ripple::before,.mdc-select__anchor .mdc-select__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-select__anchor.mdc-ripple-upgraded .mdc-select__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-select__anchor .mdc-select__ripple::before,.mdc-select__anchor .mdc-select__ripple::after{background-color:rgba(0, 0, 0, 0.87);background-color:var(--mdc-ripple-color, rgba(0, 0, 0, 0.87))}.mdc-select__anchor:hover .mdc-select__ripple::before,.mdc-select__anchor.mdc-ripple-surface--hover .mdc-select__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-select__anchor.mdc-ripple-upgraded--background-focused .mdc-select__ripple::before,.mdc-select__anchor:not(.mdc-ripple-upgraded):focus .mdc-select__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-select__anchor .mdc-select__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::before,.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000))}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:hover .mdc-deprecated-list-item__ripple::before,.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-surface--hover .mdc-deprecated-list-item__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before,.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded) .mdc-deprecated-list-item__ripple::after{transition:opacity 150ms linear}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-deprecated-list-item__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-list-item__ripple::before,.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected .mdc-list-item__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000))}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:hover .mdc-list-item__ripple::before,.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-surface--hover .mdc-list-item__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after{transition:opacity 150ms linear}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-select__menu .mdc-deprecated-list .mdc-deprecated-list-item--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-select-helper-text{margin:0;margin-left:16px;margin-right:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);display:block;margin-top:0;line-height:normal}[dir=rtl] .mdc-select-helper-text,.mdc-select-helper-text[dir=rtl]{margin-left:16px;margin-right:16px}.mdc-select-helper-text::before{display:inline-block;width:0;height:16px;content:"";vertical-align:0}.mdc-select-helper-text--validation-msg{opacity:0;transition:opacity 180ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-select--invalid+.mdc-select-helper-text--validation-msg,.mdc-select-helper-text--validation-msg-persistent{opacity:1}.mdc-select--with-leading-icon .mdc-select__icon{display:inline-block;box-sizing:border-box;border:none;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;flex-shrink:0;align-self:center;background-color:transparent;fill:currentColor}.mdc-select--with-leading-icon .mdc-select__icon{margin-left:12px;margin-right:12px}[dir=rtl] .mdc-select--with-leading-icon .mdc-select__icon,.mdc-select--with-leading-icon .mdc-select__icon[dir=rtl]{margin-left:12px;margin-right:12px}.mdc-select__icon:not([tabindex]),.mdc-select__icon[tabindex="-1"]{cursor:default;pointer-events:none}.mdc-data-table__content{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit)}.mdc-data-table{background-color:#fff;background-color:var(--mdc-theme-surface, #fff);border-radius:4px;border-radius:var(--mdc-shape-medium, 4px);border-width:1px;border-style:solid;border-color:rgba(0,0,0,.12);-webkit-overflow-scrolling:touch;display:inline-flex;flex-direction:column;box-sizing:border-box;position:relative}.mdc-data-table .mdc-data-table__header-cell:first-child{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-medium, 4px)}[dir=rtl] .mdc-data-table .mdc-data-table__header-cell:first-child,.mdc-data-table .mdc-data-table__header-cell:first-child[dir=rtl]{border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-medium, 4px);border-top-left-radius:0}.mdc-data-table .mdc-data-table__header-cell:last-child{border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-medium, 4px)}[dir=rtl] .mdc-data-table .mdc-data-table__header-cell:last-child,.mdc-data-table .mdc-data-table__header-cell:last-child[dir=rtl]{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-medium, 4px);border-top-right-radius:0}.mdc-data-table__row{background-color:inherit}.mdc-data-table__header-cell{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-data-table__row--selected{background-color:rgba(98, 0, 238, 0.04)}.mdc-data-table__pagination-rows-per-page-select:not(.mdc-select--disabled) .mdc-notched-outline__leading,.mdc-data-table__pagination-rows-per-page-select:not(.mdc-select--disabled) .mdc-notched-outline__notch,.mdc-data-table__pagination-rows-per-page-select:not(.mdc-select--disabled) .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.12)}.mdc-data-table__cell,.mdc-data-table__header-cell{border-bottom-color:rgba(0,0,0,.12)}.mdc-data-table__pagination{border-top-color:rgba(0,0,0,.12)}.mdc-data-table__cell,.mdc-data-table__header-cell{border-bottom-width:1px;border-bottom-style:solid}.mdc-data-table__pagination{border-top-width:1px;border-top-style:solid}.mdc-data-table__row:last-child .mdc-data-table__cell{border-bottom:none}.mdc-data-table__row:not(.mdc-data-table__row--selected):hover{background-color:rgba(0, 0, 0, 0.04)}.mdc-data-table__header-cell{color:rgba(0, 0, 0, 0.87)}.mdc-data-table__pagination-total,.mdc-data-table__pagination-rows-per-page-label,.mdc-data-table__cell{color:rgba(0, 0, 0, 0.87)}.mdc-data-table__row{height:52px}.mdc-data-table__pagination{min-height:52px}.mdc-data-table__header-row{height:56px}.mdc-data-table__cell,.mdc-data-table__header-cell{padding:0 16px 0 16px}.mdc-data-table__header-cell--checkbox,.mdc-data-table__cell--checkbox{padding-left:4px;padding-right:0}[dir=rtl] .mdc-data-table__header-cell--checkbox,[dir=rtl] .mdc-data-table__cell--checkbox,.mdc-data-table__header-cell--checkbox[dir=rtl],.mdc-data-table__cell--checkbox[dir=rtl]{padding-left:0;padding-right:4px}.mdc-data-table__sort-icon-button{color:rgba(0, 0, 0, 0.6)}.mdc-data-table__sort-icon-button .mdc-icon-button__ripple::before,.mdc-data-table__sort-icon-button .mdc-icon-button__ripple::after{background-color:rgba(0, 0, 0, 0.6);background-color:var(--mdc-ripple-color, rgba(0, 0, 0, 0.6))}.mdc-data-table__sort-icon-button:hover .mdc-icon-button__ripple::before,.mdc-data-table__sort-icon-button.mdc-ripple-surface--hover .mdc-icon-button__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-data-table__sort-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before,.mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after{transition:opacity 150ms linear}.mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-data-table__sort-icon-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button{color:rgba(0, 0, 0, 0.87)}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button .mdc-icon-button__ripple::before,.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button .mdc-icon-button__ripple::after{background-color:rgba(0, 0, 0, 0.87);background-color:var(--mdc-ripple-color, rgba(0, 0, 0, 0.87))}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:hover .mdc-icon-button__ripple::before,.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button.mdc-ripple-surface--hover .mdc-icon-button__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before,.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after{transition:opacity 150ms linear}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-data-table__table-container{-webkit-overflow-scrolling:touch;overflow-x:auto;width:100%}.mdc-data-table__table{min-width:100%;border:0;white-space:nowrap;border-spacing:0;table-layout:fixed}.mdc-data-table__cell{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);box-sizing:border-box;overflow:hidden;text-align:left;text-overflow:ellipsis}[dir=rtl] .mdc-data-table__cell,.mdc-data-table__cell[dir=rtl]{text-align:right}.mdc-data-table__cell--numeric{text-align:right}[dir=rtl] .mdc-data-table__cell--numeric,.mdc-data-table__cell--numeric[dir=rtl]{text-align:left}.mdc-data-table__cell--checkbox{width:1px}.mdc-data-table__header-cell{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-subtitle2-font-size, 0.875rem);line-height:1.375rem;line-height:var(--mdc-typography-subtitle2-line-height, 1.375rem);font-weight:500;font-weight:var(--mdc-typography-subtitle2-font-weight, 500);letter-spacing:0.0071428571em;letter-spacing:var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle2-text-transform, inherit);box-sizing:border-box;text-overflow:ellipsis;overflow:hidden;outline:none;text-align:left}[dir=rtl] .mdc-data-table__header-cell,.mdc-data-table__header-cell[dir=rtl]{text-align:right}.mdc-data-table__header-cell--checkbox{width:1px}.mdc-data-table__header-cell--numeric{text-align:right}[dir=rtl] .mdc-data-table__header-cell--numeric,.mdc-data-table__header-cell--numeric[dir=rtl]{text-align:left}.mdc-data-table__sort-icon-button{width:28px;height:28px;padding:2px;-webkit-transform:rotate(0.0001deg);transform:rotate(0.0001deg);margin-left:4px;margin-right:0;transition:-webkit-transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}.mdc-data-table__sort-icon-button.mdc-icon-button--touch{margin-top:0;margin-bottom:0}.mdc-data-table__sort-icon-button.mdc-icon-button--touch .mdc-icon-button__touch{display:none}[dir=rtl] .mdc-data-table__sort-icon-button,.mdc-data-table__sort-icon-button[dir=rtl]{margin-left:0;margin-right:4px}.mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button{margin-left:0;margin-right:4px}[dir=rtl] .mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button,.mdc-data-table__header-cell--numeric .mdc-data-table__sort-icon-button[dir=rtl]{margin-left:4px;margin-right:0}.mdc-data-table__header-cell--sorted-descending .mdc-data-table__sort-icon-button{-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.mdc-data-table__sort-icon-button:focus,.mdc-data-table__header-cell:hover .mdc-data-table__sort-icon-button,.mdc-data-table__header-cell--sorted .mdc-data-table__sort-icon-button{opacity:1}.mdc-data-table__header-cell-wrapper{align-items:center;display:inline-flex;vertical-align:middle}.mdc-data-table__header-cell--with-sort{cursor:pointer}.mdc-data-table__sort-status-label{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}.mdc-data-table__progress-indicator{display:none;position:absolute;width:100%}.mdc-data-table--in-progress .mdc-data-table__progress-indicator{display:block}.mdc-data-table__scrim{background-color:#fff;background-color:var(--mdc-theme-surface, #fff);height:100%;opacity:.32;position:absolute;top:0;width:100%}.mdc-data-table--sticky-header .mdc-data-table__header-cell{position:-webkit-sticky;position:sticky;top:0;z-index:1}.mdc-data-table__pagination{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);box-sizing:border-box;display:flex;justify-content:flex-end}.mdc-data-table__pagination-trailing{margin-left:4px;margin-right:0;align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-end}[dir=rtl] .mdc-data-table__pagination-trailing,.mdc-data-table__pagination-trailing[dir=rtl]{margin-left:0;margin-right:4px}.mdc-data-table__pagination-navigation{align-items:center;display:flex}.mdc-data-table__pagination-button{margin-left:0;margin-right:4px}[dir=rtl] .mdc-data-table__pagination-button .mdc-button__icon,.mdc-data-table__pagination-button .mdc-button__icon[dir=rtl]{-webkit-transform:rotate(180deg);transform:rotate(180deg)}[dir=rtl] .mdc-data-table__pagination-button,.mdc-data-table__pagination-button[dir=rtl]{margin-left:4px;margin-right:0}.mdc-data-table__pagination-total{margin-left:14px;margin-right:36px;white-space:nowrap}[dir=rtl] .mdc-data-table__pagination-total,.mdc-data-table__pagination-total[dir=rtl]{margin-left:36px;margin-right:14px}.mdc-data-table__pagination-rows-per-page{margin-left:0;margin-right:22px;align-items:center;display:inline-flex}[dir=rtl] .mdc-data-table__pagination-rows-per-page,.mdc-data-table__pagination-rows-per-page[dir=rtl]{margin-left:22px;margin-right:0}.mdc-data-table__pagination-rows-per-page-label{margin-left:0;margin-right:12px;white-space:nowrap}[dir=rtl] .mdc-data-table__pagination-rows-per-page-label,.mdc-data-table__pagination-rows-per-page-label[dir=rtl]{margin-left:12px;margin-right:0}.mdc-data-table__pagination-rows-per-page-select{min-width:80px;min-width:var(--mdc-menu-min-width, 80px);margin:8px 0}.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor{width:100%;min-width:80px}.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor{height:36px}.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-floating-label--float-above{-webkit-transform:translateY(-27.25px) scale(1);transform:translateY(-27.25px) scale(1)}.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-floating-label--float-above{font-size:.75rem}.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-24.75px) scale(0.75);transform:translateY(-24.75px) scale(0.75)}.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-data-table__pagination-rows-per-page-select .mdc-select__anchor .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-select-outlined-36px 250ms 1;animation:mdc-floating-label-shake-float-above-select-outlined-36px 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-select-outlined-36px{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-select-outlined-36px{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}}.mdc-data-table__pagination-rows-per-page-select .mdc-select__dropdown-icon{width:20px;height:20px}.mdc-data-table__pagination-rows-per-page-select.mdc-select--outlined .mdc-select__anchor :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 56px)}.mdc-data-table__pagination-rows-per-page-select .mdc-deprecated-list-item{height:36px}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-data-table__header-row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after,.mdc-data-table__row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected .mdc-checkbox__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before,.mdc-data-table__header-row-checkbox.mdc-checkbox--selected.mdc-ripple-surface--hover .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected:hover .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected.mdc-ripple-surface--hover .mdc-checkbox__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded--background-focused .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):focus .mdc-checkbox__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after,.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded) .mdc-checkbox__ripple::after{transition:opacity 150ms linear}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after,.mdc-data-table__row-checkbox.mdc-checkbox--selected:not(.mdc-ripple-upgraded):active .mdc-checkbox__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-data-table__header-row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded,.mdc-data-table__row-checkbox.mdc-checkbox--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-data-table__header-row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-data-table__header-row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after,.mdc-data-table__row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::before,.mdc-data-table__row-checkbox.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected .mdc-checkbox__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background,.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:checked~.mdc-checkbox__background,.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control:enabled:indeterminate~.mdc-checkbox__background,.mdc-data-table__header-row-checkbox .mdc-checkbox__native-control[data-indeterminate=true]:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:checked~.mdc-checkbox__background,.mdc-data-table__row-checkbox .mdc-checkbox__native-control:enabled:indeterminate~.mdc-checkbox__background,.mdc-data-table__row-checkbox .mdc-checkbox__native-control[data-indeterminate=true]:enabled~.mdc-checkbox__background{border-color:#6200ee;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));background-color:#6200ee;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee))}@-webkit-keyframes mdc-checkbox-fade-in-background-8A000000FF6200EE00000000FF6200EE{0%{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}50%{border-color:#6200ee;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));background-color:#6200ee;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee))}}@keyframes mdc-checkbox-fade-in-background-8A000000FF6200EE00000000FF6200EE{0%{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}50%{border-color:#6200ee;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));background-color:#6200ee;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee))}}@-webkit-keyframes mdc-checkbox-fade-out-background-8A000000FF6200EE00000000FF6200EE{0%,80%{border-color:#6200ee;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));background-color:#6200ee;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee))}100%{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}}@keyframes mdc-checkbox-fade-out-background-8A000000FF6200EE00000000FF6200EE{0%,80%{border-color:#6200ee;border-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee));background-color:#6200ee;background-color:var(--mdc-checkbox-checked-color, var(--mdc-theme-secondary, #6200ee))}100%{border-color:rgba(0, 0, 0, 0.54);border-color:var(--mdc-checkbox-unchecked-color, rgba(0, 0, 0, 0.54));background-color:transparent}}.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox.mdc-checkbox--anim-unchecked-checked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox.mdc-checkbox--anim-unchecked-indeterminate .mdc-checkbox__native-control:enabled~.mdc-checkbox__background{-webkit-animation-name:mdc-checkbox-fade-in-background-8A000000FF6200EE00000000FF6200EE;animation-name:mdc-checkbox-fade-in-background-8A000000FF6200EE00000000FF6200EE}.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__header-row-checkbox.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox.mdc-checkbox--anim-checked-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background,.mdc-data-table__row-checkbox.mdc-checkbox--anim-indeterminate-unchecked .mdc-checkbox__native-control:enabled~.mdc-checkbox__background{-webkit-animation-name:mdc-checkbox-fade-out-background-8A000000FF6200EE00000000FF6200EE;animation-name:mdc-checkbox-fade-out-background-8A000000FF6200EE00000000FF6200EE}.mdc-dialog,.mdc-dialog__scrim{position:fixed;top:0;left:0;align-items:center;justify-content:center;box-sizing:border-box;width:100%;height:100%}.mdc-dialog{display:none;z-index:7;z-index:var(--mdc-dialog-z-index, 7)}.mdc-dialog .mdc-dialog__surface{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-dialog .mdc-dialog__scrim{background-color:rgba(0,0,0,.32)}.mdc-dialog .mdc-dialog__surface-scrim{background-color:rgba(0,0,0,.32)}.mdc-dialog .mdc-dialog__title{color:rgba(0,0,0,.87)}.mdc-dialog .mdc-dialog__content{color:rgba(0,0,0,.6)}.mdc-dialog .mdc-dialog__close{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-dialog .mdc-dialog__close .mdc-icon-button__ripple::before,.mdc-dialog .mdc-dialog__close .mdc-icon-button__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-surface, #000))}.mdc-dialog .mdc-dialog__close:hover .mdc-icon-button__ripple::before,.mdc-dialog .mdc-dialog__close.mdc-ripple-surface--hover .mdc-icon-button__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-dialog .mdc-dialog__close.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before,.mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after{transition:opacity 150ms linear}.mdc-dialog .mdc-dialog__close:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-dialog .mdc-dialog__close.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__title,.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__actions,.mdc-dialog.mdc-dialog--scrollable.mdc-dialog-scroll-divider-footer .mdc-dialog__actions{border-color:rgba(0,0,0,.12)}.mdc-dialog.mdc-dialog--scrollable .mdc-dialog__title{border-bottom:1px solid rgba(0,0,0,.12);margin-bottom:0}.mdc-dialog.mdc-dialog-scroll-divider-header.mdc-dialog--fullscreen .mdc-dialog__header{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12)}.mdc-dialog .mdc-dialog__content{padding:20px 24px 20px 24px}.mdc-dialog .mdc-dialog__surface{min-width:280px}@media(max-width: 592px){.mdc-dialog .mdc-dialog__surface{max-width:calc(100vw - 32px)}}@media(min-width: 592px){.mdc-dialog .mdc-dialog__surface{max-width:560px}}.mdc-dialog .mdc-dialog__surface{max-height:calc(100% - 32px)}.mdc-dialog .mdc-dialog__surface{border-radius:4px;border-radius:var(--mdc-shape-medium, 4px)}@media(max-width: 960px)and (max-height: 1440px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-height:560px;max-width:560px}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{right:-12px}}@media(max-width: 720px)and (max-height: 1023px)and (max-width: 672px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-width:calc(100vw - 112px)}}@media(max-width: 720px)and (max-height: 1023px)and (min-width: 672px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-width:560px}}@media(max-width: 720px)and (max-height: 1023px)and (max-height: 720px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-height:calc(100vh - 160px)}}@media(max-width: 720px)and (max-height: 1023px)and (min-height: 720px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-height:560px}}@media(max-width: 720px)and (max-height: 1023px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{right:-12px}}@media(max-width: 720px)and (max-height: 400px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{height:100%;max-height:100vh;max-width:100vw;width:100%;border-radius:0}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{order:-1;left:-12px}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__header{padding:0 16px 9px;justify-content:flex-start}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__title{margin-left:calc(16px - 2 * 12px)}}@media(max-width: 600px)and (max-height: 960px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{height:100%;max-height:100vh;max-width:100vw;width:100vw;border-radius:0}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{order:-1;left:-12px}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__header{padding:0 16px 9px;justify-content:flex-start}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__title{margin-left:calc(16px - 2 * 12px)}}@media(min-width: 960px)and (min-height: 1440px){.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface{max-width:calc(100vw - 400px)}.mdc-dialog.mdc-dialog--fullscreen .mdc-dialog__surface .mdc-dialog__close{right:-12px}}.mdc-dialog.mdc-dialog__scrim--hidden .mdc-dialog__scrim{opacity:0}.mdc-dialog__scrim{opacity:0;z-index:-1}.mdc-dialog__container{display:flex;flex-direction:row;align-items:center;justify-content:space-around;box-sizing:border-box;height:100%;-webkit-transform:scale(0.8);transform:scale(0.8);opacity:0;pointer-events:none}.mdc-dialog__surface{position:relative;box-shadow:0px 11px 15px -7px rgba(0, 0, 0, 0.2),0px 24px 38px 3px rgba(0, 0, 0, 0.14),0px 9px 46px 8px rgba(0,0,0,.12);display:flex;flex-direction:column;flex-grow:0;flex-shrink:0;box-sizing:border-box;max-width:100%;max-height:100%;pointer-events:auto;overflow-y:auto}.mdc-dialog__surface .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}[dir=rtl] .mdc-dialog__surface,.mdc-dialog__surface[dir=rtl]{text-align:right}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-dialog__surface{outline:2px solid windowText}}.mdc-dialog__surface::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:2px solid transparent;border-radius:inherit;content:"";pointer-events:none}@media screen and (-ms-high-contrast: active),screen and (-ms-high-contrast: none){.mdc-dialog__surface::before{content:none}}.mdc-dialog__title{display:block;margin-top:0;line-height:normal;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:0.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit);position:relative;flex-shrink:0;box-sizing:border-box;margin:0 0 1px;padding:0 24px 9px}.mdc-dialog__title::before{display:inline-block;width:0;height:40px;content:"";vertical-align:0}[dir=rtl] .mdc-dialog__title,.mdc-dialog__title[dir=rtl]{text-align:right}.mdc-dialog--scrollable .mdc-dialog__title{margin-bottom:1px;padding-bottom:15px}.mdc-dialog--fullscreen .mdc-dialog__header{align-items:baseline;border-bottom:1px solid transparent;display:inline-flex;justify-content:space-between;padding:0 24px 9px;z-index:1}.mdc-dialog--fullscreen .mdc-dialog__header .mdc-dialog__close{right:-12px}.mdc-dialog--fullscreen .mdc-dialog__title{margin-bottom:0;padding:0;border-bottom:0}.mdc-dialog--fullscreen.mdc-dialog--scrollable .mdc-dialog__title{border-bottom:0;margin-bottom:0}.mdc-dialog--fullscreen .mdc-dialog__close{top:5px}.mdc-dialog--fullscreen.mdc-dialog--scrollable .mdc-dialog__actions{border-top:1px solid transparent}.mdc-dialog__content{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-body1-font-size, 1rem);line-height:1.5rem;line-height:var(--mdc-typography-body1-line-height, 1.5rem);font-weight:400;font-weight:var(--mdc-typography-body1-font-weight, 400);letter-spacing:0.03125em;letter-spacing:var(--mdc-typography-body1-letter-spacing, 0.03125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body1-text-transform, inherit);flex-grow:1;box-sizing:border-box;margin:0;overflow:auto;-webkit-overflow-scrolling:touch}.mdc-dialog__content>:first-child{margin-top:0}.mdc-dialog__content>:last-child{margin-bottom:0}.mdc-dialog__title+.mdc-dialog__content,.mdc-dialog__header+.mdc-dialog__content{padding-top:0}.mdc-dialog--scrollable .mdc-dialog__title+.mdc-dialog__content{padding-top:8px;padding-bottom:8px}.mdc-dialog__content .mdc-deprecated-list:first-child:last-child{padding:6px 0 0}.mdc-dialog--scrollable .mdc-dialog__content .mdc-deprecated-list:first-child:last-child{padding:0}.mdc-dialog__actions{display:flex;position:relative;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;box-sizing:border-box;min-height:52px;margin:0;padding:8px;border-top:1px solid transparent}.mdc-dialog--stacked .mdc-dialog__actions{flex-direction:column;align-items:flex-end}.mdc-dialog__button{margin-left:8px;margin-right:0;max-width:100%;text-align:right}[dir=rtl] .mdc-dialog__button,.mdc-dialog__button[dir=rtl]{margin-left:0;margin-right:8px}.mdc-dialog__button:first-child{margin-left:0;margin-right:0}[dir=rtl] .mdc-dialog__button:first-child,.mdc-dialog__button:first-child[dir=rtl]{margin-left:0;margin-right:0}[dir=rtl] .mdc-dialog__button,.mdc-dialog__button[dir=rtl]{text-align:left}.mdc-dialog--stacked .mdc-dialog__button:not(:first-child){margin-top:12px}.mdc-dialog--open,.mdc-dialog--opening,.mdc-dialog--closing{display:flex}.mdc-dialog--opening .mdc-dialog__scrim{transition:opacity 150ms linear}.mdc-dialog--opening .mdc-dialog__container{transition:opacity 75ms linear,-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 75ms linear,transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 75ms linear,transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-dialog--closing .mdc-dialog__scrim,.mdc-dialog--closing .mdc-dialog__container{transition:opacity 75ms linear}.mdc-dialog--closing .mdc-dialog__container{-webkit-transform:none;transform:none}.mdc-dialog--open .mdc-dialog__scrim{opacity:1}.mdc-dialog--open .mdc-dialog__container{-webkit-transform:none;transform:none;opacity:1}.mdc-dialog--open.mdc-dialog__surface-scrim--shown .mdc-dialog__surface-scrim{opacity:1;z-index:1}.mdc-dialog--open.mdc-dialog__surface-scrim--hiding .mdc-dialog__surface-scrim{transition:opacity 75ms linear}.mdc-dialog--open.mdc-dialog__surface-scrim--showing .mdc-dialog__surface-scrim{transition:opacity 150ms linear}.mdc-dialog__surface-scrim{display:none;opacity:0;position:absolute;width:100%;height:100%}.mdc-dialog__surface-scrim--shown .mdc-dialog__surface-scrim,.mdc-dialog__surface-scrim--showing .mdc-dialog__surface-scrim,.mdc-dialog__surface-scrim--hiding .mdc-dialog__surface-scrim{display:block}.mdc-dialog-scroll-lock{overflow:hidden}.mdc-drawer{border-color:rgba(0, 0, 0, 0.12);background-color:#fff;background-color:var(--mdc-theme-surface, #fff);border-top-left-radius:0;border-top-right-radius:0;border-top-right-radius:var(--mdc-shape-large, 0);border-bottom-right-radius:0;border-bottom-right-radius:var(--mdc-shape-large, 0);border-bottom-left-radius:0;z-index:6;width:256px;display:flex;flex-direction:column;flex-shrink:0;box-sizing:border-box;height:100%;border-right-width:1px;border-right-style:solid;overflow:hidden;transition-property:-webkit-transform;transition-property:transform;transition-property:transform, -webkit-transform;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1)}.mdc-drawer .mdc-drawer__title{color:rgba(0, 0, 0, 0.87)}.mdc-drawer .mdc-deprecated-list-group__subheader{color:rgba(0, 0, 0, 0.6)}.mdc-drawer .mdc-drawer__subtitle{color:rgba(0, 0, 0, 0.6)}.mdc-drawer .mdc-deprecated-list-item__graphic{color:rgba(0, 0, 0, 0.6)}.mdc-drawer .mdc-deprecated-list-item{color:rgba(0, 0, 0, 0.87)}.mdc-drawer .mdc-deprecated-list-item--activated .mdc-deprecated-list-item__graphic{color:#6200ee}.mdc-drawer .mdc-deprecated-list-item--activated{color:rgba(98, 0, 238, 0.87)}[dir=rtl] .mdc-drawer,.mdc-drawer[dir=rtl]{border-top-left-radius:0;border-top-left-radius:var(--mdc-shape-large, 0);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0;border-bottom-left-radius:var(--mdc-shape-large, 0)}.mdc-drawer .mdc-deprecated-list-item{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing)+.mdc-drawer-app-content{margin-left:256px;margin-right:0}[dir=rtl] .mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing)+.mdc-drawer-app-content,.mdc-drawer.mdc-drawer--open:not(.mdc-drawer--closing)+.mdc-drawer-app-content[dir=rtl]{margin-left:0;margin-right:256px}[dir=rtl] .mdc-drawer,.mdc-drawer[dir=rtl]{border-right-width:0;border-left-width:1px;border-right-style:none;border-left-style:solid}.mdc-drawer .mdc-deprecated-list-item{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-subtitle2-font-size, 0.875rem);line-height:1.375rem;line-height:var(--mdc-typography-subtitle2-line-height, 1.375rem);font-weight:500;font-weight:var(--mdc-typography-subtitle2-font-weight, 500);letter-spacing:0.0071428571em;letter-spacing:var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle2-text-transform, inherit);height:calc(48px - 2 * 4px);margin:8px 8px;padding:0 8px}.mdc-drawer .mdc-deprecated-list-item:nth-child(1){margin-top:2px}.mdc-drawer .mdc-deprecated-list-item:nth-last-child(1){margin-bottom:0}.mdc-drawer .mdc-deprecated-list-group__subheader{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin:0;padding:0 16px}.mdc-drawer .mdc-deprecated-list-group__subheader::before{display:inline-block;width:0;height:24px;content:"";vertical-align:0}.mdc-drawer .mdc-deprecated-list-divider{margin:3px 0 4px}.mdc-drawer .mdc-deprecated-list-item__text,.mdc-drawer .mdc-deprecated-list-item__graphic{pointer-events:none}.mdc-drawer--animate{-webkit-transform:translateX(-100%);transform:translateX(-100%)}[dir=rtl] .mdc-drawer--animate,.mdc-drawer--animate[dir=rtl]{-webkit-transform:translateX(100%);transform:translateX(100%)}.mdc-drawer--opening{-webkit-transform:translateX(0);transform:translateX(0);transition-duration:250ms}[dir=rtl] .mdc-drawer--opening,.mdc-drawer--opening[dir=rtl]{-webkit-transform:translateX(0);transform:translateX(0)}.mdc-drawer--closing{-webkit-transform:translateX(-100%);transform:translateX(-100%);transition-duration:200ms}[dir=rtl] .mdc-drawer--closing,.mdc-drawer--closing[dir=rtl]{-webkit-transform:translateX(100%);transform:translateX(100%)}.mdc-drawer__header{flex-shrink:0;box-sizing:border-box;min-height:64px;padding:0 16px 4px}.mdc-drawer__title{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:0.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-drawer__title::before{display:inline-block;width:0;height:36px;content:"";vertical-align:0}.mdc-drawer__title::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-drawer__subtitle{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin-bottom:0}.mdc-drawer__subtitle::before{display:inline-block;width:0;height:20px;content:"";vertical-align:0}.mdc-drawer__content{height:100%;overflow-y:auto;-webkit-overflow-scrolling:touch}.mdc-drawer--dismissible{left:0;right:initial;display:none;position:absolute}[dir=rtl] .mdc-drawer--dismissible,.mdc-drawer--dismissible[dir=rtl]{left:initial;right:0}.mdc-drawer--dismissible.mdc-drawer--open{display:flex}.mdc-drawer-app-content{margin-left:0;margin-right:0;position:relative}[dir=rtl] .mdc-drawer-app-content,.mdc-drawer-app-content[dir=rtl]{margin-left:0;margin-right:0}.mdc-drawer--modal{box-shadow:0px 8px 10px -5px rgba(0, 0, 0, 0.2),0px 16px 24px 2px rgba(0, 0, 0, 0.14),0px 6px 30px 5px rgba(0,0,0,.12);left:0;right:initial;display:none;position:fixed}.mdc-drawer--modal+.mdc-drawer-scrim{background-color:rgba(0, 0, 0, 0.32)}[dir=rtl] .mdc-drawer--modal,.mdc-drawer--modal[dir=rtl]{left:initial;right:0}.mdc-drawer--modal.mdc-drawer--open{display:flex}.mdc-drawer-scrim{display:none;position:fixed;top:0;left:0;width:100%;height:100%;z-index:5;transition-property:opacity;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1)}.mdc-drawer--open+.mdc-drawer-scrim{display:block}.mdc-drawer--animate+.mdc-drawer-scrim{opacity:0}.mdc-drawer--opening+.mdc-drawer-scrim{transition-duration:250ms;opacity:1}.mdc-drawer--closing+.mdc-drawer-scrim{transition-duration:200ms;opacity:0}.mdc-elevation--z0{box-shadow:0px 0px 0px 0px rgba(0, 0, 0, 0.2),0px 0px 0px 0px rgba(0, 0, 0, 0.14),0px 0px 0px 0px rgba(0,0,0,.12)}.mdc-elevation--z1{box-shadow:0px 2px 1px -1px rgba(0, 0, 0, 0.2),0px 1px 1px 0px rgba(0, 0, 0, 0.14),0px 1px 3px 0px rgba(0,0,0,.12)}.mdc-elevation--z2{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12)}.mdc-elevation--z3{box-shadow:0px 3px 3px -2px rgba(0, 0, 0, 0.2),0px 3px 4px 0px rgba(0, 0, 0, 0.14),0px 1px 8px 0px rgba(0,0,0,.12)}.mdc-elevation--z4{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12)}.mdc-elevation--z5{box-shadow:0px 3px 5px -1px rgba(0, 0, 0, 0.2),0px 5px 8px 0px rgba(0, 0, 0, 0.14),0px 1px 14px 0px rgba(0,0,0,.12)}.mdc-elevation--z6{box-shadow:0px 3px 5px -1px rgba(0, 0, 0, 0.2),0px 6px 10px 0px rgba(0, 0, 0, 0.14),0px 1px 18px 0px rgba(0,0,0,.12)}.mdc-elevation--z7{box-shadow:0px 4px 5px -2px rgba(0, 0, 0, 0.2),0px 7px 10px 1px rgba(0, 0, 0, 0.14),0px 2px 16px 1px rgba(0,0,0,.12)}.mdc-elevation--z8{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-elevation--z9{box-shadow:0px 5px 6px -3px rgba(0, 0, 0, 0.2),0px 9px 12px 1px rgba(0, 0, 0, 0.14),0px 3px 16px 2px rgba(0,0,0,.12)}.mdc-elevation--z10{box-shadow:0px 6px 6px -3px rgba(0, 0, 0, 0.2),0px 10px 14px 1px rgba(0, 0, 0, 0.14),0px 4px 18px 3px rgba(0,0,0,.12)}.mdc-elevation--z11{box-shadow:0px 6px 7px -4px rgba(0, 0, 0, 0.2),0px 11px 15px 1px rgba(0, 0, 0, 0.14),0px 4px 20px 3px rgba(0,0,0,.12)}.mdc-elevation--z12{box-shadow:0px 7px 8px -4px rgba(0, 0, 0, 0.2),0px 12px 17px 2px rgba(0, 0, 0, 0.14),0px 5px 22px 4px rgba(0,0,0,.12)}.mdc-elevation--z13{box-shadow:0px 7px 8px -4px rgba(0, 0, 0, 0.2),0px 13px 19px 2px rgba(0, 0, 0, 0.14),0px 5px 24px 4px rgba(0,0,0,.12)}.mdc-elevation--z14{box-shadow:0px 7px 9px -4px rgba(0, 0, 0, 0.2),0px 14px 21px 2px rgba(0, 0, 0, 0.14),0px 5px 26px 4px rgba(0,0,0,.12)}.mdc-elevation--z15{box-shadow:0px 8px 9px -5px rgba(0, 0, 0, 0.2),0px 15px 22px 2px rgba(0, 0, 0, 0.14),0px 6px 28px 5px rgba(0,0,0,.12)}.mdc-elevation--z16{box-shadow:0px 8px 10px -5px rgba(0, 0, 0, 0.2),0px 16px 24px 2px rgba(0, 0, 0, 0.14),0px 6px 30px 5px rgba(0,0,0,.12)}.mdc-elevation--z17{box-shadow:0px 8px 11px -5px rgba(0, 0, 0, 0.2),0px 17px 26px 2px rgba(0, 0, 0, 0.14),0px 6px 32px 5px rgba(0,0,0,.12)}.mdc-elevation--z18{box-shadow:0px 9px 11px -5px rgba(0, 0, 0, 0.2),0px 18px 28px 2px rgba(0, 0, 0, 0.14),0px 7px 34px 6px rgba(0,0,0,.12)}.mdc-elevation--z19{box-shadow:0px 9px 12px -6px rgba(0, 0, 0, 0.2),0px 19px 29px 2px rgba(0, 0, 0, 0.14),0px 7px 36px 6px rgba(0,0,0,.12)}.mdc-elevation--z20{box-shadow:0px 10px 13px -6px rgba(0, 0, 0, 0.2),0px 20px 31px 3px rgba(0, 0, 0, 0.14),0px 8px 38px 7px rgba(0,0,0,.12)}.mdc-elevation--z21{box-shadow:0px 10px 13px -6px rgba(0, 0, 0, 0.2),0px 21px 33px 3px rgba(0, 0, 0, 0.14),0px 8px 40px 7px rgba(0,0,0,.12)}.mdc-elevation--z22{box-shadow:0px 10px 14px -6px rgba(0, 0, 0, 0.2),0px 22px 35px 3px rgba(0, 0, 0, 0.14),0px 8px 42px 7px rgba(0,0,0,.12)}.mdc-elevation--z23{box-shadow:0px 11px 14px -7px rgba(0, 0, 0, 0.2),0px 23px 36px 3px rgba(0, 0, 0, 0.14),0px 9px 44px 8px rgba(0,0,0,.12)}.mdc-elevation--z24{box-shadow:0px 11px 15px -7px rgba(0, 0, 0, 0.2),0px 24px 38px 3px rgba(0, 0, 0, 0.14),0px 9px 46px 8px rgba(0,0,0,.12)}.mdc-elevation-transition{transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);will-change:box-shadow}.mdc-fab{position:relative;display:inline-flex;position:relative;align-items:center;justify-content:center;box-sizing:border-box;width:56px;height:56px;padding:0;border:none;fill:currentColor;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;overflow:visible;transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1),opacity 15ms linear 30ms,-webkit-transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1),opacity 15ms linear 30ms,transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1),opacity 15ms linear 30ms,transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-fab .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-fab::-moz-focus-inner{padding:0;border:0}.mdc-fab:hover{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-fab.mdc-ripple-upgraded--background-focused,.mdc-fab:not(.mdc-ripple-upgraded):focus{box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12)}.mdc-fab:active,.mdc-fab:focus:active{box-shadow:0px 7px 8px -4px rgba(0, 0, 0, 0.2),0px 12px 17px 2px rgba(0, 0, 0, 0.14),0px 5px 22px 4px rgba(0,0,0,.12)}.mdc-fab:active,.mdc-fab:focus{outline:none}.mdc-fab:hover{cursor:pointer}.mdc-fab>svg{width:100%}.mdc-fab--mini{width:40px;height:40px}.mdc-fab--extended{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);border-radius:24px;padding-left:20px;padding-right:20px;width:auto;max-width:100%;height:48px;line-height:normal}.mdc-fab--extended .mdc-fab__ripple{border-radius:24px}.mdc-fab--extended .mdc-fab__icon{margin-left:calc(12px - 20px);margin-right:12px}[dir=rtl] .mdc-fab--extended .mdc-fab__icon,.mdc-fab--extended .mdc-fab__icon[dir=rtl]{margin-left:12px;margin-right:calc(12px - 20px)}.mdc-fab--extended .mdc-fab__label+.mdc-fab__icon{margin-left:12px;margin-right:calc(12px - 20px)}[dir=rtl] .mdc-fab--extended .mdc-fab__label+.mdc-fab__icon,.mdc-fab--extended .mdc-fab__label+.mdc-fab__icon[dir=rtl]{margin-left:calc(12px - 20px);margin-right:12px}.mdc-fab--touch{margin-top:4px;margin-bottom:4px;margin-right:4px;margin-left:4px}.mdc-fab--touch .mdc-fab__touch{position:absolute;top:50%;height:48px;left:50%;width:48px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.mdc-fab::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:"";pointer-events:none}.mdc-fab__label{justify-content:flex-start;text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden;overflow-y:visible}.mdc-fab__icon{transition:-webkit-transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);transition:transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);transition:transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1);fill:currentColor;will-change:transform}.mdc-fab .mdc-fab__icon{display:inline-flex;align-items:center;justify-content:center}.mdc-fab--exited{-webkit-transform:scale(0);transform:scale(0);opacity:0;transition:opacity 15ms linear 150ms,-webkit-transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:opacity 15ms linear 150ms,transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:opacity 15ms linear 150ms,transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1),-webkit-transform 180ms 0ms cubic-bezier(0.4, 0, 1, 1)}.mdc-fab--exited .mdc-fab__icon{-webkit-transform:scale(0);transform:scale(0);transition:-webkit-transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1), -webkit-transform 135ms 0ms cubic-bezier(0.4, 0, 1, 1)}.mdc-fab{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786);box-shadow:0px 3px 5px -1px rgba(0, 0, 0, 0.2),0px 6px 10px 0px rgba(0, 0, 0, 0.14),0px 1px 18px 0px rgba(0,0,0,.12)}.mdc-fab .mdc-fab__icon{width:24px;height:24px;font-size:24px}.mdc-fab,.mdc-fab:not(:disabled) .mdc-fab__icon,.mdc-fab:not(:disabled) .mdc-fab__label,.mdc-fab:disabled .mdc-fab__icon,.mdc-fab:disabled .mdc-fab__label{color:#fff;color:var(--mdc-theme-on-secondary, #fff)}.mdc-fab:not(.mdc-fab--extended){border-radius:50%}.mdc-fab:not(.mdc-fab--extended) .mdc-fab__ripple{border-radius:50%}.mdc-fab{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-fab .mdc-fab__ripple::before,.mdc-fab .mdc-fab__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-fab .mdc-fab__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-fab .mdc-fab__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-fab.mdc-ripple-upgraded--unbounded .mdc-fab__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-fab.mdc-ripple-upgraded--foreground-activation .mdc-fab__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-fab.mdc-ripple-upgraded--foreground-deactivation .mdc-fab__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-fab .mdc-fab__ripple::before,.mdc-fab .mdc-fab__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-fab.mdc-ripple-upgraded .mdc-fab__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-fab .mdc-fab__ripple::before,.mdc-fab .mdc-fab__ripple::after{background-color:#fff;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-secondary, #fff))}.mdc-fab:hover .mdc-fab__ripple::before,.mdc-fab.mdc-ripple-surface--hover .mdc-fab__ripple::before{opacity:0.08;opacity:var(--mdc-ripple-hover-opacity, 0.08)}.mdc-fab.mdc-ripple-upgraded--background-focused .mdc-fab__ripple::before,.mdc-fab:not(.mdc-ripple-upgraded):focus .mdc-fab__ripple::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-fab:not(.mdc-ripple-upgraded) .mdc-fab__ripple::after{transition:opacity 150ms linear}.mdc-fab:not(.mdc-ripple-upgraded):active .mdc-fab__ripple::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-fab.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-fab .mdc-fab__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;overflow:hidden}.mdc-fab{z-index:0}.mdc-fab .mdc-fab__ripple::before,.mdc-fab .mdc-fab__ripple::after{z-index:-1;z-index:var(--mdc-ripple-z-index, -1)}.mdc-form-field{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));display:inline-flex;align-items:center;vertical-align:middle}.mdc-form-field>label{margin-left:0;margin-right:auto;padding-left:4px;padding-right:0;order:0}[dir=rtl] .mdc-form-field>label,.mdc-form-field>label[dir=rtl]{margin-left:auto;margin-right:0}[dir=rtl] .mdc-form-field>label,.mdc-form-field>label[dir=rtl]{padding-left:0;padding-right:4px}.mdc-form-field--nowrap>label{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.mdc-form-field--align-end>label{margin-left:auto;margin-right:0;padding-left:0;padding-right:4px;order:-1}[dir=rtl] .mdc-form-field--align-end>label,.mdc-form-field--align-end>label[dir=rtl]{margin-left:0;margin-right:auto}[dir=rtl] .mdc-form-field--align-end>label,.mdc-form-field--align-end>label[dir=rtl]{padding-left:4px;padding-right:0}.mdc-form-field--space-between{justify-content:space-between}.mdc-form-field--space-between>label{margin:0}[dir=rtl] .mdc-form-field--space-between>label,.mdc-form-field--space-between>label[dir=rtl]{margin:0}.mdc-icon-button{display:inline-block;position:relative;box-sizing:border-box;border:none;outline:none;background-color:transparent;fill:currentColor;color:inherit;font-size:24px;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:48px;height:48px;padding:12px}.mdc-icon-button svg,.mdc-icon-button img{width:24px;height:24px}.mdc-icon-button:disabled{color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-disabled-on-light, rgba(0, 0, 0, 0.38))}.mdc-icon-button:disabled{cursor:default;pointer-events:none}.mdc-icon-button .mdc-icon-button__touch{position:absolute;top:50%;height:48px;left:50%;width:48px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.mdc-icon-button__icon{display:inline-block}.mdc-icon-button__icon.mdc-icon-button__icon--on{display:none}.mdc-icon-button--on .mdc-icon-button__icon{display:none}.mdc-icon-button--on .mdc-icon-button__icon.mdc-icon-button__icon--on{display:inline-block}.mdc-icon-button--touch{margin-top:0px;margin-bottom:0px}.mdc-icon-button{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-icon-button .mdc-icon-button__ripple::before,.mdc-icon-button .mdc-icon-button__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-icon-button .mdc-icon-button__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-icon-button .mdc-icon-button__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-icon-button.mdc-ripple-upgraded--unbounded .mdc-icon-button__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-icon-button.mdc-ripple-upgraded--foreground-activation .mdc-icon-button__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-icon-button.mdc-ripple-upgraded--foreground-deactivation .mdc-icon-button__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-icon-button .mdc-icon-button__ripple::before,.mdc-icon-button .mdc-icon-button__ripple::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::before,.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-icon-button.mdc-ripple-upgraded .mdc-icon-button__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-icon-button .mdc-icon-button__ripple::before,.mdc-icon-button .mdc-icon-button__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}.mdc-icon-button:hover .mdc-icon-button__ripple::before,.mdc-icon-button.mdc-ripple-surface--hover .mdc-icon-button__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-icon-button.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before,.mdc-icon-button:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-icon-button:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after{transition:opacity 150ms linear}.mdc-icon-button:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-icon-button.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-icon-button .mdc-icon-button__ripple{pointer-events:none;z-index:1}.mdc-image-list{display:flex;flex-wrap:wrap;margin:0 auto;padding:0}.mdc-image-list__item,.mdc-image-list__image-aspect-container{position:relative;box-sizing:border-box}.mdc-image-list__item{list-style-type:none}.mdc-image-list__image{width:100%}.mdc-image-list__image-aspect-container .mdc-image-list__image{position:absolute;top:0;right:0;bottom:0;left:0;height:100%;background-repeat:no-repeat;background-position:center;background-size:cover}.mdc-image-list__image-aspect-container{padding-bottom:calc(100% / 1)}.mdc-image-list__image{border-radius:0}.mdc-image-list--with-text-protection .mdc-image-list__supporting{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.mdc-image-list__supporting{color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;padding:8px 0;line-height:24px}.mdc-image-list__label{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mdc-image-list--with-text-protection .mdc-image-list__supporting{position:absolute;bottom:0;width:100%;height:48px;padding:0 16px;background:rgba(0,0,0,.6);color:#fff}.mdc-image-list--masonry{display:block}.mdc-image-list--masonry .mdc-image-list__item{-webkit-column-break-inside:avoid;break-inside:avoid-column}.mdc-image-list--masonry .mdc-image-list__image{display:block;height:auto}:root{--mdc-layout-grid-margin-desktop: 24px;--mdc-layout-grid-gutter-desktop: 24px;--mdc-layout-grid-column-width-desktop: 72px;--mdc-layout-grid-margin-tablet: 16px;--mdc-layout-grid-gutter-tablet: 16px;--mdc-layout-grid-column-width-tablet: 72px;--mdc-layout-grid-margin-phone: 16px;--mdc-layout-grid-gutter-phone: 16px;--mdc-layout-grid-column-width-phone: 72px}@media(min-width: 840px){.mdc-layout-grid{box-sizing:border-box;margin:0 auto;padding:24px;padding:var(--mdc-layout-grid-margin-desktop, 24px)}}@media(min-width: 600px)and (max-width: 839px){.mdc-layout-grid{box-sizing:border-box;margin:0 auto;padding:16px;padding:var(--mdc-layout-grid-margin-tablet, 16px)}}@media(max-width: 599px){.mdc-layout-grid{box-sizing:border-box;margin:0 auto;padding:16px;padding:var(--mdc-layout-grid-margin-phone, 16px)}}@media(min-width: 840px){.mdc-layout-grid__inner{display:flex;flex-flow:row wrap;align-items:stretch;margin:-12px;margin:calc(var(--mdc-layout-grid-gutter-desktop, 24px) / 2 * -1)}@supports(display: grid){.mdc-layout-grid__inner{display:grid;margin:0;grid-gap:24px;grid-gap:var(--mdc-layout-grid-gutter-desktop, 24px);grid-template-columns:repeat(12, minmax(0, 1fr))}}}@media(min-width: 600px)and (max-width: 839px){.mdc-layout-grid__inner{display:flex;flex-flow:row wrap;align-items:stretch;margin:-8px;margin:calc(var(--mdc-layout-grid-gutter-tablet, 16px) / 2 * -1)}@supports(display: grid){.mdc-layout-grid__inner{display:grid;margin:0;grid-gap:16px;grid-gap:var(--mdc-layout-grid-gutter-tablet, 16px);grid-template-columns:repeat(8, minmax(0, 1fr))}}}@media(max-width: 599px){.mdc-layout-grid__inner{display:flex;flex-flow:row wrap;align-items:stretch;margin:-8px;margin:calc(var(--mdc-layout-grid-gutter-phone, 16px) / 2 * -1)}@supports(display: grid){.mdc-layout-grid__inner{display:grid;margin:0;grid-gap:16px;grid-gap:var(--mdc-layout-grid-gutter-phone, 16px);grid-template-columns:repeat(4, minmax(0, 1fr))}}}@media(min-width: 840px){.mdc-layout-grid__cell{width:calc(33.3333333333% - 24px);width:calc(33.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px));box-sizing:border-box;margin:12px;margin:calc(var(--mdc-layout-grid-gutter-desktop, 24px) / 2)}@supports(display: grid){.mdc-layout-grid__cell{width:auto;grid-column-end:span 4}}@supports(display: grid){.mdc-layout-grid__cell{margin:0}}.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-desktop{width:calc(8.3333333333% - 24px);width:calc(8.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-desktop{width:auto;grid-column-end:span 1}}.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-desktop{width:calc(16.6666666667% - 24px);width:calc(16.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-desktop{width:auto;grid-column-end:span 2}}.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-desktop{width:calc(25% - 24px);width:calc(25% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-desktop{width:auto;grid-column-end:span 3}}.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-desktop{width:calc(33.3333333333% - 24px);width:calc(33.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-desktop{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-desktop{width:calc(41.6666666667% - 24px);width:calc(41.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-desktop{width:auto;grid-column-end:span 5}}.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-desktop{width:calc(50% - 24px);width:calc(50% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-desktop{width:auto;grid-column-end:span 6}}.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-desktop{width:calc(58.3333333333% - 24px);width:calc(58.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-desktop{width:auto;grid-column-end:span 7}}.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-desktop{width:calc(66.6666666667% - 24px);width:calc(66.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-desktop{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-desktop{width:calc(75% - 24px);width:calc(75% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-desktop{width:auto;grid-column-end:span 9}}.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-desktop{width:calc(83.3333333333% - 24px);width:calc(83.3333333333% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-desktop{width:auto;grid-column-end:span 10}}.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-desktop{width:calc(91.6666666667% - 24px);width:calc(91.6666666667% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-desktop{width:auto;grid-column-end:span 11}}.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-desktop{width:calc(100% - 24px);width:calc(100% - var(--mdc-layout-grid-gutter-desktop, 24px))}@supports(display: grid){.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-desktop{width:auto;grid-column-end:span 12}}}@media(min-width: 600px)and (max-width: 839px){.mdc-layout-grid__cell{width:calc(50% - 16px);width:calc(50% - var(--mdc-layout-grid-gutter-tablet, 16px));box-sizing:border-box;margin:8px;margin:calc(var(--mdc-layout-grid-gutter-tablet, 16px) / 2)}@supports(display: grid){.mdc-layout-grid__cell{width:auto;grid-column-end:span 4}}@supports(display: grid){.mdc-layout-grid__cell{margin:0}}.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-tablet{width:calc(12.5% - 16px);width:calc(12.5% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-tablet{width:auto;grid-column-end:span 1}}.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-tablet{width:calc(25% - 16px);width:calc(25% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-tablet{width:auto;grid-column-end:span 2}}.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-tablet{width:calc(37.5% - 16px);width:calc(37.5% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-tablet{width:auto;grid-column-end:span 3}}.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-tablet{width:calc(50% - 16px);width:calc(50% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-tablet{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-tablet{width:calc(62.5% - 16px);width:calc(62.5% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-tablet{width:auto;grid-column-end:span 5}}.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-tablet{width:calc(75% - 16px);width:calc(75% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-tablet{width:auto;grid-column-end:span 6}}.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-tablet{width:calc(87.5% - 16px);width:calc(87.5% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-tablet{width:auto;grid-column-end:span 7}}.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-tablet{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-tablet{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-tablet{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-tablet{width:auto;grid-column-end:span 8}}.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-tablet{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-tablet, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-tablet{width:auto;grid-column-end:span 8}}}@media(max-width: 599px){.mdc-layout-grid__cell{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px));box-sizing:border-box;margin:8px;margin:calc(var(--mdc-layout-grid-gutter-phone, 16px) / 2)}@supports(display: grid){.mdc-layout-grid__cell{width:auto;grid-column-end:span 4}}@supports(display: grid){.mdc-layout-grid__cell{margin:0}}.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-phone{width:calc(25% - 16px);width:calc(25% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-1,.mdc-layout-grid__cell--span-1-phone{width:auto;grid-column-end:span 1}}.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-phone{width:calc(50% - 16px);width:calc(50% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-2,.mdc-layout-grid__cell--span-2-phone{width:auto;grid-column-end:span 2}}.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-phone{width:calc(75% - 16px);width:calc(75% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-3,.mdc-layout-grid__cell--span-3-phone{width:auto;grid-column-end:span 3}}.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-4,.mdc-layout-grid__cell--span-4-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-5,.mdc-layout-grid__cell--span-5-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-6,.mdc-layout-grid__cell--span-6-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-7,.mdc-layout-grid__cell--span-7-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-8,.mdc-layout-grid__cell--span-8-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-9,.mdc-layout-grid__cell--span-9-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-10,.mdc-layout-grid__cell--span-10-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-11,.mdc-layout-grid__cell--span-11-phone{width:auto;grid-column-end:span 4}}.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-phone{width:calc(100% - 16px);width:calc(100% - var(--mdc-layout-grid-gutter-phone, 16px))}@supports(display: grid){.mdc-layout-grid__cell--span-12,.mdc-layout-grid__cell--span-12-phone{width:auto;grid-column-end:span 4}}}.mdc-layout-grid__cell--order-1{order:1}.mdc-layout-grid__cell--order-2{order:2}.mdc-layout-grid__cell--order-3{order:3}.mdc-layout-grid__cell--order-4{order:4}.mdc-layout-grid__cell--order-5{order:5}.mdc-layout-grid__cell--order-6{order:6}.mdc-layout-grid__cell--order-7{order:7}.mdc-layout-grid__cell--order-8{order:8}.mdc-layout-grid__cell--order-9{order:9}.mdc-layout-grid__cell--order-10{order:10}.mdc-layout-grid__cell--order-11{order:11}.mdc-layout-grid__cell--order-12{order:12}.mdc-layout-grid__cell--align-top{align-self:flex-start}@supports(display: grid){.mdc-layout-grid__cell--align-top{align-self:start}}.mdc-layout-grid__cell--align-middle{align-self:center}.mdc-layout-grid__cell--align-bottom{align-self:flex-end}@supports(display: grid){.mdc-layout-grid__cell--align-bottom{align-self:end}}@media(min-width: 840px){.mdc-layout-grid--fixed-column-width{width:1176px;width:calc( var(--mdc-layout-grid-column-width-desktop, 72px) * 12 + var(--mdc-layout-grid-gutter-desktop, 24px) * 11 + var(--mdc-layout-grid-margin-desktop, 24px) * 2 )}}@media(min-width: 600px)and (max-width: 839px){.mdc-layout-grid--fixed-column-width{width:720px;width:calc( var(--mdc-layout-grid-column-width-tablet, 72px) * 8 + var(--mdc-layout-grid-gutter-tablet, 16px) * 7 + var(--mdc-layout-grid-margin-tablet, 16px) * 2 )}}@media(max-width: 599px){.mdc-layout-grid--fixed-column-width{width:368px;width:calc( var(--mdc-layout-grid-column-width-phone, 72px) * 4 + var(--mdc-layout-grid-gutter-phone, 16px) * 3 + var(--mdc-layout-grid-margin-phone, 16px) * 2 )}}.mdc-layout-grid--align-left{margin-right:auto;margin-left:0}.mdc-layout-grid--align-right{margin-right:0;margin-left:auto}@-webkit-keyframes mdc-linear-progress-primary-indeterminate-translate{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(83.67142%);transform:translateX(83.67142%);-webkit-transform:translateX(var(--mdc-linear-progress-primary-half, 83.67142%));transform:translateX(var(--mdc-linear-progress-primary-half, 83.67142%))}100%{-webkit-transform:translateX(200.611057%);transform:translateX(200.611057%);-webkit-transform:translateX(var(--mdc-linear-progress-primary-full, 200.611057%));transform:translateX(var(--mdc-linear-progress-primary-full, 200.611057%))}}@keyframes mdc-linear-progress-primary-indeterminate-translate{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(83.67142%);transform:translateX(83.67142%);-webkit-transform:translateX(var(--mdc-linear-progress-primary-half, 83.67142%));transform:translateX(var(--mdc-linear-progress-primary-half, 83.67142%))}100%{-webkit-transform:translateX(200.611057%);transform:translateX(200.611057%);-webkit-transform:translateX(var(--mdc-linear-progress-primary-full, 200.611057%));transform:translateX(var(--mdc-linear-progress-primary-full, 200.611057%))}}@-webkit-keyframes mdc-linear-progress-primary-indeterminate-scale{0%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}36.65%{-webkit-animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}69.15%{-webkit-animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);-webkit-transform:scaleX(0.661479);transform:scaleX(0.661479)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@keyframes mdc-linear-progress-primary-indeterminate-scale{0%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}36.65%{-webkit-animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}69.15%{-webkit-animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);-webkit-transform:scaleX(0.661479);transform:scaleX(0.661479)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-translate{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(37.651913%);transform:translateX(37.651913%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%));transform:translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%))}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(84.386165%);transform:translateX(84.386165%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-half, 84.386165%));transform:translateX(var(--mdc-linear-progress-secondary-half, 84.386165%))}100%{-webkit-transform:translateX(160.277782%);transform:translateX(160.277782%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-full, 160.277782%));transform:translateX(var(--mdc-linear-progress-secondary-full, 160.277782%))}}@keyframes mdc-linear-progress-secondary-indeterminate-translate{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(37.651913%);transform:translateX(37.651913%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%));transform:translateX(var(--mdc-linear-progress-secondary-quarter, 37.651913%))}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(84.386165%);transform:translateX(84.386165%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-half, 84.386165%));transform:translateX(var(--mdc-linear-progress-secondary-half, 84.386165%))}100%{-webkit-transform:translateX(160.277782%);transform:translateX(160.277782%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-full, 160.277782%));transform:translateX(var(--mdc-linear-progress-secondary-full, 160.277782%))}}@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-scale{0%{-webkit-animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}19.15%{-webkit-animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);-webkit-transform:scaleX(0.457104);transform:scaleX(0.457104)}44.15%{-webkit-animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);-webkit-transform:scaleX(0.72796);transform:scaleX(0.72796)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@keyframes mdc-linear-progress-secondary-indeterminate-scale{0%{-webkit-animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}19.15%{-webkit-animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);-webkit-transform:scaleX(0.457104);transform:scaleX(0.457104)}44.15%{-webkit-animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);-webkit-transform:scaleX(0.72796);transform:scaleX(0.72796)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@-webkit-keyframes mdc-linear-progress-buffering{from{-webkit-transform:rotate(180deg) translateX(-10px);transform:rotate(180deg) translateX(-10px)}}@keyframes mdc-linear-progress-buffering{from{-webkit-transform:rotate(180deg) translateX(-10px);transform:rotate(180deg) translateX(-10px)}}@-webkit-keyframes mdc-linear-progress-primary-indeterminate-translate-reverse{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(-83.67142%);transform:translateX(-83.67142%);-webkit-transform:translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%));transform:translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%))}100%{-webkit-transform:translateX(-200.611057%);transform:translateX(-200.611057%);-webkit-transform:translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%));transform:translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%))}}@keyframes mdc-linear-progress-primary-indeterminate-translate-reverse{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(-83.67142%);transform:translateX(-83.67142%);-webkit-transform:translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%));transform:translateX(var(--mdc-linear-progress-primary-half-neg, -83.67142%))}100%{-webkit-transform:translateX(-200.611057%);transform:translateX(-200.611057%);-webkit-transform:translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%));transform:translateX(var(--mdc-linear-progress-primary-full-neg, -200.611057%))}}@-webkit-keyframes mdc-linear-progress-secondary-indeterminate-translate-reverse{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(-37.651913%);transform:translateX(-37.651913%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%));transform:translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%))}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(-84.386165%);transform:translateX(-84.386165%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%));transform:translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%))}100%{-webkit-transform:translateX(-160.277782%);transform:translateX(-160.277782%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%));transform:translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%))}}@keyframes mdc-linear-progress-secondary-indeterminate-translate-reverse{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(-37.651913%);transform:translateX(-37.651913%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%));transform:translateX(var(--mdc-linear-progress-secondary-quarter-neg, -37.651913%))}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(-84.386165%);transform:translateX(-84.386165%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%));transform:translateX(var(--mdc-linear-progress-secondary-half-neg, -84.386165%))}100%{-webkit-transform:translateX(-160.277782%);transform:translateX(-160.277782%);-webkit-transform:translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%));transform:translateX(var(--mdc-linear-progress-secondary-full-neg, -160.277782%))}}@-webkit-keyframes mdc-linear-progress-buffering-reverse{from{-webkit-transform:translateX(-10px);transform:translateX(-10px)}}@keyframes mdc-linear-progress-buffering-reverse{from{-webkit-transform:translateX(-10px);transform:translateX(-10px)}}.mdc-linear-progress{position:relative;width:100%;height:4px;-webkit-transform:translateZ(0);transform:translateZ(0);outline:1px solid transparent;overflow:hidden;transition:opacity 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-linear-progress__bar{position:absolute;width:100%;height:100%;-webkit-animation:none;animation:none;-webkit-transform-origin:top left;transform-origin:top left;transition:-webkit-transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1), -webkit-transform 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-linear-progress__bar-inner{display:inline-block;position:absolute;width:100%;-webkit-animation:none;animation:none;border-top:4px solid}.mdc-linear-progress__buffer{display:flex;position:absolute;width:100%;height:100%}.mdc-linear-progress__buffer-dots{background-repeat:repeat-x;background-size:10px 4px;flex:auto;-webkit-transform:rotate(180deg);transform:rotate(180deg);-webkit-animation:mdc-linear-progress-buffering 250ms infinite linear;animation:mdc-linear-progress-buffering 250ms infinite linear}.mdc-linear-progress__buffer-bar{flex:0 1 100%;transition:flex-basis 250ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-linear-progress__primary-bar{-webkit-transform:scaleX(0);transform:scaleX(0)}.mdc-linear-progress__secondary-bar{display:none}.mdc-linear-progress--indeterminate .mdc-linear-progress__bar{transition:none}.mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar{left:-145.166611%}.mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar{left:-54.888891%;display:block}.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar{-webkit-animation:mdc-linear-progress-primary-indeterminate-translate 2s infinite linear;animation:mdc-linear-progress-primary-indeterminate-translate 2s infinite linear}.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar>.mdc-linear-progress__bar-inner{-webkit-animation:mdc-linear-progress-primary-indeterminate-scale 2s infinite linear;animation:mdc-linear-progress-primary-indeterminate-scale 2s infinite linear}.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar{-webkit-animation:mdc-linear-progress-secondary-indeterminate-translate 2s infinite linear;animation:mdc-linear-progress-secondary-indeterminate-translate 2s infinite linear}.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar>.mdc-linear-progress__bar-inner{-webkit-animation:mdc-linear-progress-secondary-indeterminate-scale 2s infinite linear;animation:mdc-linear-progress-secondary-indeterminate-scale 2s infinite linear}[dir=rtl] .mdc-linear-progress:not([dir=ltr]) .mdc-linear-progress__bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]) .mdc-linear-progress__bar{right:0;-webkit-transform-origin:center right;transform-origin:center right}[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__primary-bar{-webkit-animation-name:mdc-linear-progress-primary-indeterminate-translate-reverse;animation-name:mdc-linear-progress-primary-indeterminate-translate-reverse}[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--animation-ready .mdc-linear-progress__secondary-bar{-webkit-animation-name:mdc-linear-progress-secondary-indeterminate-translate-reverse;animation-name:mdc-linear-progress-secondary-indeterminate-translate-reverse}[dir=rtl] .mdc-linear-progress:not([dir=ltr]) .mdc-linear-progress__buffer-dots,.mdc-linear-progress[dir=rtl]:not([dir=ltr]) .mdc-linear-progress__buffer-dots{-webkit-animation:mdc-linear-progress-buffering-reverse 250ms infinite linear;animation:mdc-linear-progress-buffering-reverse 250ms infinite linear;-webkit-transform:rotate(0);transform:rotate(0)}[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__primary-bar{right:-145.166611%;left:auto}[dir=rtl] .mdc-linear-progress:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar,.mdc-linear-progress[dir=rtl]:not([dir=ltr]).mdc-linear-progress--indeterminate .mdc-linear-progress__secondary-bar{right:-54.888891%;left:auto}.mdc-linear-progress--closed{opacity:0}.mdc-linear-progress--closed-animation-off .mdc-linear-progress__buffer-dots{-webkit-animation:none;animation:none}.mdc-linear-progress--closed-animation-off.mdc-linear-progress--indeterminate .mdc-linear-progress__bar,.mdc-linear-progress--closed-animation-off.mdc-linear-progress--indeterminate .mdc-linear-progress__bar .mdc-linear-progress__bar-inner{-webkit-animation:none;animation:none}.mdc-linear-progress__bar-inner{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-linear-progress__buffer-dots{background-image:url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' enable-background='new 0 0 5 2' xml:space='preserve' viewBox='0 0 5 2' preserveAspectRatio='none slice'%3E%3Ccircle cx='1' cy='1' r='1' fill='%23e6e6e6'/%3E%3C/svg%3E")}.mdc-linear-progress__buffer-bar{background-color:#e6e6e6}.mdc-deprecated-list{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);line-height:1.5rem;margin:0;padding:8px 0;list-style-type:none;color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87))}.mdc-deprecated-list:focus{outline:none}.mdc-deprecated-list-item{height:48px}.mdc-deprecated-list-item__secondary-text{color:rgba(0, 0, 0, 0.54);color:var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54))}.mdc-deprecated-list-item__graphic{background-color:transparent}.mdc-deprecated-list-item__graphic{color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38))}.mdc-deprecated-list-item__meta{color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38))}.mdc-deprecated-list-group__subheader{color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87))}.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__text{opacity:.38}.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__text,.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__primary-text,.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__secondary-text{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-deprecated-list-item--selected,.mdc-deprecated-list-item--activated{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-deprecated-list-item--selected .mdc-deprecated-list-item__graphic,.mdc-deprecated-list-item--activated .mdc-deprecated-list-item__graphic{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-deprecated-list--dense{padding-top:4px;padding-bottom:4px;font-size:.812rem}.mdc-deprecated-list-item{display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;padding:0;padding-left:16px;padding-right:16px;height:48px}.mdc-deprecated-list-item:focus{outline:none}.mdc-deprecated-list-item:not(.mdc-deprecated-list-item--selected):focus::before,.mdc-deprecated-list-item.mdc-ripple-upgraded--background-focused::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:"";pointer-events:none}.mdc-deprecated-list-item.mdc-deprecated-list-item--selected::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:3px double transparent;border-radius:inherit;content:"";pointer-events:none}[dir=rtl] .mdc-deprecated-list-item,.mdc-deprecated-list-item[dir=rtl]{padding-left:16px;padding-right:16px}.mdc-deprecated-list--icon-list .mdc-deprecated-list-item{padding-left:16px;padding-right:16px;height:56px}[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-item,.mdc-deprecated-list--icon-list .mdc-deprecated-list-item[dir=rtl]{padding-left:16px;padding-right:16px}.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item{padding-left:16px;padding-right:16px;height:56px}[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item[dir=rtl]{padding-left:16px;padding-right:16px}.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item{padding-left:16px;padding-right:16px;height:56px}[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item[dir=rtl]{padding-left:16px;padding-right:16px}.mdc-deprecated-list--image-list .mdc-deprecated-list-item{padding-left:16px;padding-right:16px;height:72px}[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-item,.mdc-deprecated-list--image-list .mdc-deprecated-list-item[dir=rtl]{padding-left:16px;padding-right:16px}.mdc-deprecated-list--video-list .mdc-deprecated-list-item{padding-left:0px;padding-right:16px;height:72px}[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-item,.mdc-deprecated-list--video-list .mdc-deprecated-list-item[dir=rtl]{padding-left:16px;padding-right:0px}.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:16px;width:20px;height:20px}[dir=rtl] .mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic,.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:16px;margin-right:0}.mdc-deprecated-list-item__graphic{flex-shrink:0;align-items:center;justify-content:center;fill:currentColor;-o-object-fit:cover;object-fit:cover;margin-left:0;margin-right:32px;width:24px;height:24px}[dir=rtl] .mdc-deprecated-list-item__graphic,.mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:32px;margin-right:0}.mdc-deprecated-list--icon-list .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:32px;width:24px;height:24px}[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-item__graphic,.mdc-deprecated-list--icon-list .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:32px;margin-right:0}.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:16px;width:40px;height:40px;border-radius:50%}[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__graphic,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:16px;margin-right:0}.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:16px;width:40px;height:40px}[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__graphic,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:16px;margin-right:0}.mdc-deprecated-list--image-list .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:16px;width:56px;height:56px}[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-item__graphic,.mdc-deprecated-list--image-list .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:16px;margin-right:0}.mdc-deprecated-list--video-list .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:16px;width:100px;height:56px}[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-item__graphic,.mdc-deprecated-list--video-list .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:16px;margin-right:0}.mdc-deprecated-list .mdc-deprecated-list-item__graphic{display:inline-flex}.mdc-deprecated-list-item__meta{margin-left:auto;margin-right:0}.mdc-deprecated-list-item__meta:not(.material-icons){-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit)}.mdc-deprecated-list-item[dir=rtl] .mdc-deprecated-list-item__meta,[dir=rtl] .mdc-deprecated-list-item .mdc-deprecated-list-item__meta{margin-left:0;margin-right:auto}.mdc-deprecated-list-item__text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mdc-deprecated-list-item__text[for]{pointer-events:none}.mdc-deprecated-list-item__primary-text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-deprecated-list-item__primary-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-deprecated-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-deprecated-list--video-list .mdc-deprecated-list-item__primary-text,.mdc-deprecated-list--image-list .mdc-deprecated-list-item__primary-text,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__primary-text,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__primary-text,.mdc-deprecated-list--icon-list .mdc-deprecated-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-deprecated-list--video-list .mdc-deprecated-list-item__primary-text::before,.mdc-deprecated-list--image-list .mdc-deprecated-list-item__primary-text::before,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__primary-text::before,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__primary-text::before,.mdc-deprecated-list--icon-list .mdc-deprecated-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-deprecated-list--video-list .mdc-deprecated-list-item__primary-text::after,.mdc-deprecated-list--image-list .mdc-deprecated-list-item__primary-text::after,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item__primary-text::after,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item__primary-text::after,.mdc-deprecated-list--icon-list .mdc-deprecated-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-deprecated-list--dense .mdc-deprecated-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-deprecated-list--dense .mdc-deprecated-list-item__primary-text::before{display:inline-block;width:0;height:24px;content:"";vertical-align:0}.mdc-deprecated-list--dense .mdc-deprecated-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-deprecated-list-item__secondary-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block;margin-top:0;line-height:normal}.mdc-deprecated-list-item__secondary-text::before{display:inline-block;width:0;height:20px;content:"";vertical-align:0}.mdc-deprecated-list--dense .mdc-deprecated-list-item__secondary-text{font-size:inherit}.mdc-deprecated-list--dense .mdc-deprecated-list-item{height:40px}.mdc-deprecated-list--two-line .mdc-deprecated-list-item__text{align-self:flex-start}.mdc-deprecated-list--two-line .mdc-deprecated-list-item{height:64px}.mdc-deprecated-list--two-line.mdc-deprecated-list--video-list .mdc-deprecated-list-item,.mdc-deprecated-list--two-line.mdc-deprecated-list--image-list .mdc-deprecated-list-item,.mdc-deprecated-list--two-line.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-item,.mdc-deprecated-list--two-line.mdc-deprecated-list--avatar-list .mdc-deprecated-list-item,.mdc-deprecated-list--two-line.mdc-deprecated-list--icon-list .mdc-deprecated-list-item{height:72px}.mdc-deprecated-list--two-line.mdc-deprecated-list--icon-list .mdc-deprecated-list-item__graphic{align-self:flex-start;margin-top:16px}.mdc-deprecated-list--two-line.mdc-deprecated-list--dense .mdc-deprecated-list-item,.mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense .mdc-deprecated-list-item{height:60px}.mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic{margin-left:0;margin-right:16px;width:36px;height:36px}[dir=rtl] .mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic,.mdc-deprecated-list--avatar-list.mdc-deprecated-list--dense .mdc-deprecated-list-item__graphic[dir=rtl]{margin-left:16px;margin-right:0}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item{cursor:pointer}a.mdc-deprecated-list-item{color:inherit;text-decoration:none}.mdc-deprecated-list-divider{height:0;margin:0;border:none;border-bottom-width:1px;border-bottom-style:solid}.mdc-deprecated-list-divider{border-bottom-color:rgba(0, 0, 0, 0.12)}.mdc-deprecated-list-divider--padded{margin-left:16px;margin-right:0;width:calc(100% - 32px)}[dir=rtl] .mdc-deprecated-list-divider--padded,.mdc-deprecated-list-divider--padded[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list-divider--inset{margin-left:72px;margin-right:0;width:calc(100% - 72px)}[dir=rtl] .mdc-deprecated-list-divider--inset,.mdc-deprecated-list-divider--inset[dir=rtl]{margin-left:0;margin-right:72px}.mdc-deprecated-list-divider--inset.mdc-deprecated-list-divider--padded{margin-left:72px;margin-right:0;width:calc(100% - 88px)}[dir=rtl] .mdc-deprecated-list-divider--inset.mdc-deprecated-list-divider--padded,.mdc-deprecated-list-divider--inset.mdc-deprecated-list-divider--padded[dir=rtl]{margin-left:0;margin-right:72px}.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading{margin-left:16px;margin-right:0;width:calc(100% - 16px)}[dir=rtl] .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading,.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list .mdc-deprecated-list-divider--inset-trailing{width:calc(100% - 16px)}.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing{margin-left:16px;margin-right:0;width:calc(100% - 32px)}[dir=rtl] .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing,.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding{margin-left:16px;margin-right:0;width:calc(100% - 16px)}[dir=rtl] .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding,.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding{margin-left:16px;margin-right:0;width:calc(100% - 32px)}[dir=rtl] .mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding,.mdc-deprecated-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading{margin-left:72px;margin-right:0;width:calc(100% - 72px)}[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading,.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading[dir=rtl]{margin-left:0;margin-right:72px}.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-trailing{width:calc(100% - 16px)}.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing{margin-left:72px;margin-right:0;width:calc(100% - 88px)}[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing,.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl]{margin-left:0;margin-right:72px}.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding{margin-left:16px;margin-right:0;width:calc(100% - 16px)}[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding,.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding{margin-left:16px;margin-right:0;width:calc(100% - 32px)}[dir=rtl] .mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding,.mdc-deprecated-list--icon-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading{margin-left:72px;margin-right:0;width:calc(100% - 72px)}[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading[dir=rtl]{margin-left:0;margin-right:72px}.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-trailing{width:calc(100% - 16px)}.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing{margin-left:72px;margin-right:0;width:calc(100% - 88px)}[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl]{margin-left:0;margin-right:72px}.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding{margin-left:16px;margin-right:0;width:calc(100% - 16px)}[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding{margin-left:16px;margin-right:0;width:calc(100% - 32px)}[dir=rtl] .mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding,.mdc-deprecated-list--avatar-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading{margin-left:72px;margin-right:0;width:calc(100% - 72px)}[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading[dir=rtl]{margin-left:0;margin-right:72px}.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-trailing{width:calc(100% - 16px)}.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing{margin-left:72px;margin-right:0;width:calc(100% - 88px)}[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl]{margin-left:0;margin-right:72px}.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding{margin-left:16px;margin-right:0;width:calc(100% - 16px)}[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding{margin-left:16px;margin-right:0;width:calc(100% - 32px)}[dir=rtl] .mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding,.mdc-deprecated-list--thumbnail-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading{margin-left:88px;margin-right:0;width:calc(100% - 88px)}[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading,.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading[dir=rtl]{margin-left:0;margin-right:88px}.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-trailing{width:calc(100% - 16px)}.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing{margin-left:88px;margin-right:0;width:calc(100% - 104px)}[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing,.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl]{margin-left:0;margin-right:88px}.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding{margin-left:16px;margin-right:0;width:calc(100% - 16px)}[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding,.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding{margin-left:16px;margin-right:0;width:calc(100% - 32px)}[dir=rtl] .mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding,.mdc-deprecated-list--image-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl]{margin-left:0;margin-right:16px}.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading{margin-left:116px;margin-right:0;width:calc(100% - 116px)}[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading,.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading[dir=rtl]{margin-left:0;margin-right:116px}.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-trailing{width:calc(100% - 16px)}.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing{margin-left:116px;margin-right:0;width:calc(100% - 132px)}[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing,.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing[dir=rtl]{margin-left:0;margin-right:116px}.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding{margin-left:0px;margin-right:0;width:calc(100% - 0px)}[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding,.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--padding[dir=rtl]{margin-left:0;margin-right:0px}.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding{margin-left:0px;margin-right:0;width:calc(100% - 16px)}[dir=rtl] .mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding,.mdc-deprecated-list--video-list .mdc-deprecated-list-divider--inset-leading.mdc-deprecated-list-divider--inset-trailing.mdc-deprecated-list-divider--inset-padding[dir=rtl]{margin-left:0;margin-right:0px}.mdc-deprecated-list-group .mdc-deprecated-list{padding:0}.mdc-deprecated-list-group__subheader{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);margin:calc( (3rem - 1.5rem) / 2 ) 16px}.mdc-list-item__primary-text{color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87))}.mdc-list-item__secondary-text{color:rgba(0, 0, 0, 0.54);color:var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54))}.mdc-list-item__overline-text{color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38))}.mdc-list-item--with-leading-icon .mdc-list-item__start,.mdc-list-item--with-trailing-icon .mdc-list-item__end{background-color:transparent}.mdc-list-item--with-leading-icon .mdc-list-item__start,.mdc-list-item--with-trailing-icon .mdc-list-item__end{color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38))}.mdc-list-item__end{color:rgba(0, 0, 0, 0.38);color:var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38))}.mdc-list-item--disabled .mdc-list-item__start,.mdc-list-item--disabled .mdc-list-item__content,.mdc-list-item--disabled .mdc-list-item__end{opacity:.38}.mdc-list-item--disabled .mdc-list-item__primary-text{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-list-item--disabled .mdc-list-item__secondary-text{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-list-item--disabled .mdc-list-item__overline-text{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-list-item--disabled.mdc-list-item--with-leading-icon .mdc-list-item__start{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-list-item--disabled.mdc-list-item--with-trailing-icon .mdc-list-item__end{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-list-item--disabled.mdc-list-item--with-trailing-meta .mdc-list-item__end{color:#000;color:var(--mdc-theme-on-surface, #000)}.mdc-list-item--selected .mdc-list-item__primary-text,.mdc-list-item--activated .mdc-list-item__primary-text{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-list-item--selected.mdc-list-item--with-leading-icon .mdc-list-item__start,.mdc-list-item--activated.mdc-list-item--with-leading-icon .mdc-list-item__start{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-deprecated-list-group__subheader{color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87))}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-list-divider::after{content:"";display:block;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:white}}.mdc-list{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);line-height:1.5rem;margin:0;padding:8px 0;list-style-type:none}.mdc-list:focus{outline:none}.mdc-list-item{display:flex;position:relative;align-items:center;justify-content:flex-start;overflow:hidden;padding:0;align-items:stretch;cursor:pointer}.mdc-list-item:focus{outline:none}.mdc-list-item.mdc-list-item--with-one-line{height:48px}.mdc-list-item.mdc-list-item--with-two-lines{height:64px}.mdc-list-item.mdc-list-item--with-three-lines{height:88px}.mdc-list-item.mdc-list-item--with-one-line .mdc-list-item__start{align-self:center;margin-top:0}.mdc-list-item.mdc-list-item--with-two-lines .mdc-list-item__start{align-self:flex-start;margin-top:16px}.mdc-list-item.mdc-list-item--with-three-lines .mdc-list-item__start{align-self:flex-start;margin-top:16px}.mdc-list-item.mdc-list-item--with-one-line .mdc-list-item__end{align-self:center;margin-top:0}.mdc-list-item.mdc-list-item--with-two-lines .mdc-list-item__end{align-self:center;margin-top:0}.mdc-list-item.mdc-list-item--with-three-lines .mdc-list-item__end{align-self:flex-start;margin-top:16px}.mdc-list-item.mdc-list-item--disabled,.mdc-list-item.mdc-list-item--non-interactive{cursor:auto}.mdc-list-item:not(.mdc-list-item--selected):focus::before,.mdc-list-item.mdc-ripple-upgraded--background-focused::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:"";pointer-events:none}.mdc-list-item.mdc-list-item--selected::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:3px double transparent;border-radius:inherit;content:"";pointer-events:none}.mdc-list-item.mdc-list-item--selected:focus::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:3px solid transparent;border-radius:inherit;content:"";pointer-events:none}a.mdc-list-item{color:inherit;text-decoration:none}.mdc-list-item__start{fill:currentColor;flex-shrink:0;pointer-events:none}.mdc-list-item__end{flex-shrink:0;pointer-events:none}.mdc-list-item__content{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;align-self:center;flex:1;pointer-events:none}.mdc-list-item--with-two-lines .mdc-list-item__content,.mdc-list-item--with-three-lines .mdc-list-item__content{align-self:stretch}.mdc-list-item__content[for]{pointer-events:none}.mdc-list-item__primary-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mdc-list-item--with-two-lines .mdc-list-item__primary-text,.mdc-list-item--with-three-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before,.mdc-list-item--with-three-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after,.mdc-list-item--with-three-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item__secondary-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;display:block;margin-top:0;line-height:normal}.mdc-list-item__secondary-text::before{display:inline-block;width:0;height:20px;content:"";vertical-align:0}.mdc-list-item--with-three-lines .mdc-list-item__secondary-text{white-space:normal;line-height:20px}.mdc-list-item--with-overline .mdc-list-item__secondary-text{white-space:nowrap;line-height:auto}.mdc-list-item__overline-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-overline-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-overline-font-size, 0.75rem);line-height:2rem;line-height:var(--mdc-typography-overline-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-overline-font-weight, 500);letter-spacing:0.1666666667em;letter-spacing:var(--mdc-typography-overline-letter-spacing, 0.1666666667em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-overline-text-decoration, none);text-decoration:var(--mdc-typography-overline-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-overline-text-transform, uppercase);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:24px;content:"";vertical-align:0}.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-three-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-three-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-three-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-avatar.mdc-list-item{padding-left:0;padding-right:auto}[dir=rtl] .mdc-list-item--with-leading-avatar.mdc-list-item,.mdc-list-item--with-leading-avatar.mdc-list-item[dir=rtl]{padding-left:auto;padding-right:0}.mdc-list-item--with-leading-avatar .mdc-list-item__start{margin-left:16px;margin-right:16px}[dir=rtl] .mdc-list-item--with-leading-avatar .mdc-list-item__start,.mdc-list-item--with-leading-avatar .mdc-list-item__start[dir=rtl]{margin-left:16px;margin-right:16px}.mdc-list-item--with-leading-avatar .mdc-list-item__start{width:40px;height:40px}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-avatar.mdc-list-item--with-one-line{height:56px}.mdc-list-item--with-leading-avatar.mdc-list-item--with-two-lines{height:72px}.mdc-list-item--with-leading-avatar .mdc-list-item__start{border-radius:50%}.mdc-list-item--with-leading-icon .mdc-list-item__start{width:24px;height:24px}.mdc-list-item--with-leading-icon.mdc-list-item{padding-left:0;padding-right:auto}[dir=rtl] .mdc-list-item--with-leading-icon.mdc-list-item,.mdc-list-item--with-leading-icon.mdc-list-item[dir=rtl]{padding-left:auto;padding-right:0}.mdc-list-item--with-leading-icon .mdc-list-item__start{margin-left:16px;margin-right:32px}[dir=rtl] .mdc-list-item--with-leading-icon .mdc-list-item__start,.mdc-list-item--with-leading-icon .mdc-list-item__start[dir=rtl]{margin-left:32px;margin-right:16px}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-icon.mdc-list-item--with-one-line{height:56px}.mdc-list-item--with-leading-icon.mdc-list-item--with-two-lines{height:72px}.mdc-list-item--with-leading-thumbnail.mdc-list-item{padding-left:0;padding-right:auto}[dir=rtl] .mdc-list-item--with-leading-thumbnail.mdc-list-item,.mdc-list-item--with-leading-thumbnail.mdc-list-item[dir=rtl]{padding-left:auto;padding-right:0}.mdc-list-item--with-leading-thumbnail .mdc-list-item__start{margin-left:16px;margin-right:16px}[dir=rtl] .mdc-list-item--with-leading-thumbnail .mdc-list-item__start,.mdc-list-item--with-leading-thumbnail .mdc-list-item__start[dir=rtl]{margin-left:16px;margin-right:16px}.mdc-list-item--with-leading-thumbnail .mdc-list-item__start{width:40px;height:40px}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-one-line{height:56px}.mdc-list-item--with-leading-thumbnail.mdc-list-item--with-two-lines{height:72px}.mdc-list-item--with-leading-image.mdc-list-item{padding-left:0;padding-right:auto}[dir=rtl] .mdc-list-item--with-leading-image.mdc-list-item,.mdc-list-item--with-leading-image.mdc-list-item[dir=rtl]{padding-left:auto;padding-right:0}.mdc-list-item--with-leading-image .mdc-list-item__start{margin-left:16px;margin-right:16px}[dir=rtl] .mdc-list-item--with-leading-image .mdc-list-item__start,.mdc-list-item--with-leading-image .mdc-list-item__start[dir=rtl]{margin-left:16px;margin-right:16px}.mdc-list-item--with-leading-image .mdc-list-item__start{width:56px;height:56px}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-image.mdc-list-item--with-one-line{height:72px}.mdc-list-item--with-leading-image.mdc-list-item--with-two-lines{height:72px}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__start{align-self:flex-start;margin-top:8px}.mdc-list-item--with-leading-video.mdc-list-item{padding-left:0;padding-right:auto}[dir=rtl] .mdc-list-item--with-leading-video.mdc-list-item,.mdc-list-item--with-leading-video.mdc-list-item[dir=rtl]{padding-left:auto;padding-right:0}.mdc-list-item--with-leading-video .mdc-list-item__start{margin-left:0;margin-right:16px}[dir=rtl] .mdc-list-item--with-leading-video .mdc-list-item__start,.mdc-list-item--with-leading-video .mdc-list-item__start[dir=rtl]{margin-left:16px;margin-right:0}.mdc-list-item--with-leading-video .mdc-list-item__start{width:100px;height:56px}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-video.mdc-list-item--with-one-line{height:72px}.mdc-list-item--with-leading-video.mdc-list-item--with-two-lines{height:72px}.mdc-list-item--with-leading-checkbox.mdc-list-item{padding-left:0;padding-right:auto}[dir=rtl] .mdc-list-item--with-leading-checkbox.mdc-list-item,.mdc-list-item--with-leading-checkbox.mdc-list-item[dir=rtl]{padding-left:auto;padding-right:0}.mdc-list-item--with-leading-checkbox .mdc-list-item__start{margin-left:8px;margin-right:24px}[dir=rtl] .mdc-list-item--with-leading-checkbox .mdc-list-item__start,.mdc-list-item--with-leading-checkbox .mdc-list-item__start[dir=rtl]{margin-left:24px;margin-right:8px}.mdc-list-item--with-leading-checkbox .mdc-list-item__start{width:40px;height:40px}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__start{align-self:flex-start;margin-top:8px}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-one-line{height:56px}.mdc-list-item--with-leading-checkbox.mdc-list-item--with-two-lines{height:72px}.mdc-list-item--with-leading-radio.mdc-list-item{padding-left:0;padding-right:auto}[dir=rtl] .mdc-list-item--with-leading-radio.mdc-list-item,.mdc-list-item--with-leading-radio.mdc-list-item[dir=rtl]{padding-left:auto;padding-right:0}.mdc-list-item--with-leading-radio .mdc-list-item__start{margin-left:8px;margin-right:24px}[dir=rtl] .mdc-list-item--with-leading-radio .mdc-list-item__start,.mdc-list-item--with-leading-radio .mdc-list-item__start[dir=rtl]{margin-left:24px;margin-right:8px}.mdc-list-item--with-leading-radio .mdc-list-item__start{width:40px;height:40px}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__start{align-self:flex-start;margin-top:8px}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-radio.mdc-list-item--with-one-line{height:56px}.mdc-list-item--with-leading-radio.mdc-list-item--with-two-lines{height:72px}.mdc-list-item--with-leading-switch.mdc-list-item{padding-left:0;padding-right:auto}[dir=rtl] .mdc-list-item--with-leading-switch.mdc-list-item,.mdc-list-item--with-leading-switch.mdc-list-item[dir=rtl]{padding-left:auto;padding-right:0}.mdc-list-item--with-leading-switch .mdc-list-item__start{margin-left:16px;margin-right:16px}[dir=rtl] .mdc-list-item--with-leading-switch .mdc-list-item__start,.mdc-list-item--with-leading-switch .mdc-list-item__start[dir=rtl]{margin-left:16px;margin-right:16px}.mdc-list-item--with-leading-switch .mdc-list-item__start{width:36px;height:20px}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__start{align-self:flex-start;margin-top:16px}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__primary-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__overline-text{display:block;margin-top:0;line-height:normal;margin-bottom:-20px}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__overline-text::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines .mdc-list-item__overline-text::after{display:inline-block;width:0;height:20px;content:"";vertical-align:-20px}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines.mdc-list-item--with-trailing-meta .mdc-list-item__end::before{display:inline-block;width:0;height:32px;content:"";vertical-align:0}.mdc-list-item--with-leading-switch.mdc-list-item--with-one-line{height:56px}.mdc-list-item--with-leading-switch.mdc-list-item--with-two-lines{height:72px}.mdc-list-item--with-trailing-icon.mdc-list-item{padding-left:auto;padding-right:0}[dir=rtl] .mdc-list-item--with-trailing-icon.mdc-list-item,.mdc-list-item--with-trailing-icon.mdc-list-item[dir=rtl]{padding-left:0;padding-right:auto}.mdc-list-item--with-trailing-icon .mdc-list-item__end{margin-left:16px;margin-right:16px}[dir=rtl] .mdc-list-item--with-trailing-icon .mdc-list-item__end,.mdc-list-item--with-trailing-icon .mdc-list-item__end[dir=rtl]{margin-left:16px;margin-right:16px}.mdc-list-item--with-trailing-icon .mdc-list-item__end{width:24px;height:24px}.mdc-list-item--with-trailing-meta.mdc-list-item--with-two-lines .mdc-list-item__end{align-self:flex-start;margin-top:0}.mdc-list-item--with-trailing-meta.mdc-list-item--with-three-lines .mdc-list-item__end{align-self:flex-start;margin-top:0}.mdc-list-item--with-trailing-meta.mdc-list-item{padding-left:auto;padding-right:0}[dir=rtl] .mdc-list-item--with-trailing-meta.mdc-list-item,.mdc-list-item--with-trailing-meta.mdc-list-item[dir=rtl]{padding-left:0;padding-right:auto}.mdc-list-item--with-trailing-meta .mdc-list-item__end{margin-left:28px;margin-right:16px}[dir=rtl] .mdc-list-item--with-trailing-meta .mdc-list-item__end,.mdc-list-item--with-trailing-meta .mdc-list-item__end[dir=rtl]{margin-left:16px;margin-right:28px}.mdc-list-item--with-trailing-meta.mdc-list-item--with-two-lines .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-trailing-meta.mdc-list-item--with-two-lines .mdc-list-item__end::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-trailing-meta.mdc-list-item--with-three-lines .mdc-list-item__end{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-trailing-meta.mdc-list-item--with-three-lines .mdc-list-item__end::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-list-item--with-trailing-meta .mdc-list-item__end{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit)}.mdc-list-item--with-trailing-checkbox.mdc-list-item{padding-left:auto;padding-right:0}[dir=rtl] .mdc-list-item--with-trailing-checkbox.mdc-list-item,.mdc-list-item--with-trailing-checkbox.mdc-list-item[dir=rtl]{padding-left:0;padding-right:auto}.mdc-list-item--with-trailing-checkbox .mdc-list-item__end{margin-left:24px;margin-right:8px}[dir=rtl] .mdc-list-item--with-trailing-checkbox .mdc-list-item__end,.mdc-list-item--with-trailing-checkbox .mdc-list-item__end[dir=rtl]{margin-left:8px;margin-right:24px}.mdc-list-item--with-trailing-checkbox .mdc-list-item__end{width:40px;height:40px}.mdc-list-item--with-trailing-checkbox.mdc-list-item--with-three-lines .mdc-list-item__end{align-self:flex-start;margin-top:8px}.mdc-list-item--with-trailing-radio.mdc-list-item{padding-left:auto;padding-right:0}[dir=rtl] .mdc-list-item--with-trailing-radio.mdc-list-item,.mdc-list-item--with-trailing-radio.mdc-list-item[dir=rtl]{padding-left:0;padding-right:auto}.mdc-list-item--with-trailing-radio .mdc-list-item__end{margin-left:24px;margin-right:8px}[dir=rtl] .mdc-list-item--with-trailing-radio .mdc-list-item__end,.mdc-list-item--with-trailing-radio .mdc-list-item__end[dir=rtl]{margin-left:8px;margin-right:24px}.mdc-list-item--with-trailing-radio .mdc-list-item__end{width:40px;height:40px}.mdc-list-item--with-trailing-radio.mdc-list-item--with-three-lines .mdc-list-item__end{align-self:flex-start;margin-top:8px}.mdc-list-item--with-trailing-switch.mdc-list-item{padding-left:auto;padding-right:0}[dir=rtl] .mdc-list-item--with-trailing-switch.mdc-list-item,.mdc-list-item--with-trailing-switch.mdc-list-item[dir=rtl]{padding-left:0;padding-right:auto}.mdc-list-item--with-trailing-switch .mdc-list-item__end{margin-left:16px;margin-right:16px}[dir=rtl] .mdc-list-item--with-trailing-switch .mdc-list-item__end,.mdc-list-item--with-trailing-switch .mdc-list-item__end[dir=rtl]{margin-left:16px;margin-right:16px}.mdc-list-item--with-trailing-switch .mdc-list-item__end{width:36px;height:20px}.mdc-list-item--with-trailing-switch.mdc-list-item--with-three-lines .mdc-list-item__end{align-self:flex-start;margin-top:16px}.mdc-list-item--with-overline.mdc-list-item--with-two-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-overline.mdc-list-item--with-two-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:20px;content:"";vertical-align:0}.mdc-list-item--with-overline.mdc-list-item--with-three-lines .mdc-list-item__primary-text{display:block;margin-top:0;line-height:normal}.mdc-list-item--with-overline.mdc-list-item--with-three-lines .mdc-list-item__primary-text::before{display:inline-block;width:0;height:20px;content:"";vertical-align:0}.mdc-list-item{padding-left:16px;padding-right:16px}[dir=rtl] .mdc-list-item,.mdc-list-item[dir=rtl]{padding-left:16px;padding-right:16px}.mdc-list-group .mdc-deprecated-list{padding:0}.mdc-list-group__subheader{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);margin:calc( (3rem - 1.5rem) / 2 ) 16px}.mdc-list-divider{background-color:rgba(0, 0, 0, 0.12)}.mdc-list-divider{height:1px;padding:0;background-clip:content-box}.mdc-list-divider.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-text.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-icon.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-image.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-avatar.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-switch.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-radio.mdc-list-divider--with-leading-inset{padding-left:16px;padding-right:auto}[dir=rtl] .mdc-list-divider.mdc-list-divider--with-leading-inset,[dir=rtl] .mdc-list-divider--with-leading-text.mdc-list-divider--with-leading-inset,[dir=rtl] .mdc-list-divider--with-leading-icon.mdc-list-divider--with-leading-inset,[dir=rtl] .mdc-list-divider--with-leading-image.mdc-list-divider--with-leading-inset,[dir=rtl] .mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-leading-inset,[dir=rtl] .mdc-list-divider--with-leading-avatar.mdc-list-divider--with-leading-inset,[dir=rtl] .mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-leading-inset,[dir=rtl] .mdc-list-divider--with-leading-switch.mdc-list-divider--with-leading-inset,[dir=rtl] .mdc-list-divider--with-leading-radio.mdc-list-divider--with-leading-inset,.mdc-list-divider.mdc-list-divider--with-leading-inset[dir=rtl],.mdc-list-divider--with-leading-text.mdc-list-divider--with-leading-inset[dir=rtl],.mdc-list-divider--with-leading-icon.mdc-list-divider--with-leading-inset[dir=rtl],.mdc-list-divider--with-leading-image.mdc-list-divider--with-leading-inset[dir=rtl],.mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-leading-inset[dir=rtl],.mdc-list-divider--with-leading-avatar.mdc-list-divider--with-leading-inset[dir=rtl],.mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-leading-inset[dir=rtl],.mdc-list-divider--with-leading-switch.mdc-list-divider--with-leading-inset[dir=rtl],.mdc-list-divider--with-leading-radio.mdc-list-divider--with-leading-inset[dir=rtl]{padding-left:auto;padding-right:16px}.mdc-list-divider.mdc-list-divider--with-trailing-inset,.mdc-list-divider--with-leading-text.mdc-list-divider--with-trailing-inset,.mdc-list-divider--with-leading-icon.mdc-list-divider--with-trailing-inset,.mdc-list-divider--with-leading-image.mdc-list-divider--with-trailing-inset,.mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-trailing-inset,.mdc-list-divider--with-leading-avatar.mdc-list-divider--with-trailing-inset,.mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-trailing-inset,.mdc-list-divider--with-leading-switch.mdc-list-divider--with-trailing-inset,.mdc-list-divider--with-leading-radio.mdc-list-divider--with-trailing-inset{padding-left:auto;padding-right:16px}[dir=rtl] .mdc-list-divider.mdc-list-divider--with-trailing-inset,[dir=rtl] .mdc-list-divider--with-leading-text.mdc-list-divider--with-trailing-inset,[dir=rtl] .mdc-list-divider--with-leading-icon.mdc-list-divider--with-trailing-inset,[dir=rtl] .mdc-list-divider--with-leading-image.mdc-list-divider--with-trailing-inset,[dir=rtl] .mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-trailing-inset,[dir=rtl] .mdc-list-divider--with-leading-avatar.mdc-list-divider--with-trailing-inset,[dir=rtl] .mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-trailing-inset,[dir=rtl] .mdc-list-divider--with-leading-switch.mdc-list-divider--with-trailing-inset,[dir=rtl] .mdc-list-divider--with-leading-radio.mdc-list-divider--with-trailing-inset,.mdc-list-divider.mdc-list-divider--with-trailing-inset[dir=rtl],.mdc-list-divider--with-leading-text.mdc-list-divider--with-trailing-inset[dir=rtl],.mdc-list-divider--with-leading-icon.mdc-list-divider--with-trailing-inset[dir=rtl],.mdc-list-divider--with-leading-image.mdc-list-divider--with-trailing-inset[dir=rtl],.mdc-list-divider--with-leading-thumbnail.mdc-list-divider--with-trailing-inset[dir=rtl],.mdc-list-divider--with-leading-avatar.mdc-list-divider--with-trailing-inset[dir=rtl],.mdc-list-divider--with-leading-checkbox.mdc-list-divider--with-trailing-inset[dir=rtl],.mdc-list-divider--with-leading-switch.mdc-list-divider--with-trailing-inset[dir=rtl],.mdc-list-divider--with-leading-radio.mdc-list-divider--with-trailing-inset[dir=rtl]{padding-left:16px;padding-right:auto}.mdc-list-divider--with-leading-video.mdc-list-divider--with-leading-inset{padding-left:0px;padding-right:auto}[dir=rtl] .mdc-list-divider--with-leading-video.mdc-list-divider--with-leading-inset,.mdc-list-divider--with-leading-video.mdc-list-divider--with-leading-inset[dir=rtl]{padding-left:auto;padding-right:0px}[dir=rtl] .mdc-list-divider,.mdc-list-divider[dir=rtl]{padding:0}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity;--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--unbounded .mdc-deprecated-list-item__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--foreground-activation .mdc-deprecated-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--foreground-deactivation .mdc-deprecated-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--unbounded .mdc-list-item__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--foreground-activation .mdc-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--foreground-deactivation .mdc-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:hover .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-surface--hover .mdc-deprecated-list-item__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded) .mdc-deprecated-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded):active .mdc-deprecated-list-item__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:hover .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-surface--hover .mdc-list-item__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-deprecated-list-item__ripple::before{opacity:0.12;opacity:var(--mdc-ripple-activated-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-deprecated-list-item__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:hover .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-surface--hover .mdc-deprecated-list-item__ripple::before{opacity:0.16;opacity:var(--mdc-ripple-hover-opacity, 0.16)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded) .mdc-deprecated-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded):active .mdc-deprecated-list-item__ripple::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-list-item__ripple::before{opacity:0.12;opacity:var(--mdc-ripple-activated-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated .mdc-list-item__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:hover .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-surface--hover .mdc-list-item__ripple::before{opacity:0.16;opacity:var(--mdc-ripple-hover-opacity, 0.16)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--activated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::before{opacity:0.08;opacity:var(--mdc-ripple-selected-opacity, 0.08)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-deprecated-list-item__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:hover .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-surface--hover .mdc-deprecated-list-item__ripple::before{opacity:0.12;opacity:var(--mdc-ripple-hover-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-focus-opacity, 0.2)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded) .mdc-deprecated-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-deprecated-list-item__ripple::after{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-press-opacity, 0.2)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.2)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-list-item__ripple::before{opacity:0.08;opacity:var(--mdc-ripple-selected-opacity, 0.08)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected .mdc-list-item__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:hover .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-surface--hover .mdc-list-item__ripple::before{opacity:0.12;opacity:var(--mdc-ripple-hover-opacity, 0.12)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-focus-opacity, 0.2)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-press-opacity, 0.2)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.2)}:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-deprecated-list-item__ripple,:not(.mdc-deprecated-list-item--disabled).mdc-deprecated-list-item .mdc-list-item__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-deprecated-list-item--disabled{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity;--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::before,.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--unbounded .mdc-deprecated-list-item__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--foreground-activation .mdc-deprecated-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--foreground-deactivation .mdc-deprecated-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::before,.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--unbounded .mdc-list-item__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--foreground-activation .mdc-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--foreground-deactivation .mdc-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::before,.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-deprecated-list-item__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::before,.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::before,.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::before,.mdc-deprecated-list-item--disabled .mdc-list-item__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--background-focused .mdc-deprecated-list-item__ripple::before,.mdc-deprecated-list-item--disabled:not(.mdc-ripple-upgraded):focus .mdc-deprecated-list-item__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-deprecated-list-item--disabled.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,.mdc-deprecated-list-item--disabled:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-deprecated-list-item--disabled .mdc-deprecated-list-item__ripple,.mdc-deprecated-list-item--disabled .mdc-list-item__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}:not(.mdc-list-item--disabled).mdc-list-item{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--unbounded .mdc-list-item__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--foreground-activation .mdc-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--foreground-deactivation .mdc-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded .mdc-list-item__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}:not(.mdc-list-item--disabled).mdc-list-item:hover .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-surface--hover .mdc-list-item__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}:not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-list-item--disabled).mdc-list-item:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}:not(.mdc-list-item--disabled).mdc-list-item.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}:not(.mdc-list-item--disabled).mdc-list-item--activated .mdc-list-item__ripple::before{opacity:0.12;opacity:var(--mdc-ripple-activated-opacity, 0.12)}:not(.mdc-list-item--disabled).mdc-list-item--activated .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item--activated .mdc-list-item__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}:not(.mdc-list-item--disabled).mdc-list-item--activated:hover .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item--activated.mdc-ripple-surface--hover .mdc-list-item__ripple::before{opacity:0.16;opacity:var(--mdc-ripple-hover-opacity, 0.16)}:not(.mdc-list-item--disabled).mdc-list-item--activated.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}:not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-list-item--disabled).mdc-list-item--activated:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}:not(.mdc-list-item--disabled).mdc-list-item--activated.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}:not(.mdc-list-item--disabled).mdc-list-item--selected .mdc-list-item__ripple::before{opacity:0.08;opacity:var(--mdc-ripple-selected-opacity, 0.08)}:not(.mdc-list-item--disabled).mdc-list-item--selected .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item--selected .mdc-list-item__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}:not(.mdc-list-item--disabled).mdc-list-item--selected:hover .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item--selected.mdc-ripple-surface--hover .mdc-list-item__ripple::before{opacity:0.12;opacity:var(--mdc-ripple-hover-opacity, 0.12)}:not(.mdc-list-item--disabled).mdc-list-item--selected.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,:not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-focus-opacity, 0.2)}:not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded) .mdc-list-item__ripple::after{transition:opacity 150ms linear}:not(.mdc-list-item--disabled).mdc-list-item--selected:not(.mdc-ripple-upgraded):active .mdc-list-item__ripple::after{transition-duration:75ms;opacity:0.2;opacity:var(--mdc-ripple-press-opacity, 0.2)}:not(.mdc-list-item--disabled).mdc-list-item--selected.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.2)}:not(.mdc-list-item--disabled).mdc-list-item .mdc-list-item__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-list-item--disabled{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-list-item--disabled .mdc-list-item__ripple::before,.mdc-list-item--disabled .mdc-list-item__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-list-item--disabled .mdc-list-item__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-list-item--disabled .mdc-list-item__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-list-item--disabled.mdc-ripple-upgraded--unbounded .mdc-list-item__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-list-item--disabled.mdc-ripple-upgraded--foreground-activation .mdc-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-list-item--disabled.mdc-ripple-upgraded--foreground-deactivation .mdc-list-item__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-list-item--disabled .mdc-list-item__ripple::before,.mdc-list-item--disabled .mdc-list-item__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-list-item--disabled.mdc-ripple-upgraded .mdc-list-item__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-list-item--disabled .mdc-list-item__ripple::before,.mdc-list-item--disabled .mdc-list-item__ripple::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}.mdc-list-item--disabled.mdc-ripple-upgraded--background-focused .mdc-list-item__ripple::before,.mdc-list-item--disabled:not(.mdc-ripple-upgraded):focus .mdc-list-item__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-list-item--disabled .mdc-list-item__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-menu{min-width:112px;min-width:var(--mdc-menu-min-width, 112px)}.mdc-menu .mdc-deprecated-list-item__meta{color:rgba(0, 0, 0, 0.87)}.mdc-menu .mdc-deprecated-list-item__graphic{color:rgba(0, 0, 0, 0.87)}.mdc-menu .mdc-deprecated-list{color:rgba(0, 0, 0, 0.87);position:relative}.mdc-menu .mdc-deprecated-list .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-menu .mdc-deprecated-list-divider{margin:8px 0}.mdc-menu .mdc-deprecated-list-item{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdc-menu .mdc-deprecated-list-item--disabled{cursor:auto}.mdc-menu a.mdc-deprecated-list-item .mdc-deprecated-list-item__text,.mdc-menu a.mdc-deprecated-list-item .mdc-deprecated-list-item__graphic{pointer-events:none}.mdc-menu__selection-group{padding:0;fill:currentColor}.mdc-menu__selection-group .mdc-deprecated-list-item{padding-left:56px;padding-right:16px}[dir=rtl] .mdc-menu__selection-group .mdc-deprecated-list-item,.mdc-menu__selection-group .mdc-deprecated-list-item[dir=rtl]{padding-left:16px;padding-right:56px}.mdc-menu__selection-group .mdc-menu__selection-group-icon{left:16px;right:initial;display:none;position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}[dir=rtl] .mdc-menu__selection-group .mdc-menu__selection-group-icon,.mdc-menu__selection-group .mdc-menu__selection-group-icon[dir=rtl]{left:initial;right:16px}.mdc-menu-item--selected .mdc-menu__selection-group-icon{display:inline}.mdc-menu-surface{display:none;position:absolute;box-sizing:border-box;max-width:calc(100vw - 32px);max-width:var(--mdc-menu-max-width, calc(100vw - 32px));max-height:calc(100vh - 32px);max-height:var(--mdc-menu-max-height, calc(100vh - 32px));margin:0;padding:0;-webkit-transform:scale(1);transform:scale(1);-webkit-transform-origin:top left;transform-origin:top left;opacity:0;overflow:auto;will-change:transform,opacity;z-index:8;transition:opacity .03s linear,height 250ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform .12s cubic-bezier(0, 0, 0.2, 1);transition:opacity .03s linear,transform .12s cubic-bezier(0, 0, 0.2, 1),height 250ms cubic-bezier(0, 0, 0.2, 1);transition:opacity .03s linear,transform .12s cubic-bezier(0, 0, 0.2, 1),height 250ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform .12s cubic-bezier(0, 0, 0.2, 1);box-shadow:0px 5px 5px -3px rgba(0, 0, 0, 0.2),0px 8px 10px 1px rgba(0, 0, 0, 0.14),0px 3px 14px 2px rgba(0,0,0,.12);background-color:#fff;background-color:var(--mdc-theme-surface, #fff);color:#000;color:var(--mdc-theme-on-surface, #000);border-radius:4px;border-radius:var(--mdc-shape-medium, 4px);transform-origin-left:top left;transform-origin-right:top right}.mdc-menu-surface:focus{outline:none}.mdc-menu-surface--animating-open{display:inline-block;-webkit-transform:scale(0.8);transform:scale(0.8);opacity:0}.mdc-menu-surface--open{display:inline-block;-webkit-transform:scale(1);transform:scale(1);opacity:1}.mdc-menu-surface--animating-closed{display:inline-block;opacity:0;transition:opacity .075s linear}[dir=rtl] .mdc-menu-surface,.mdc-menu-surface[dir=rtl]{transform-origin-left:top right;transform-origin-right:top left}.mdc-menu-surface--anchor{position:relative;overflow:visible}.mdc-menu-surface--fixed{position:fixed}.mdc-menu-surface--fullwidth{width:100%}.mdc-radio{padding:calc((40px - 20px) / 2)}.mdc-radio .mdc-radio__native-control:enabled:not(:checked)+.mdc-radio__background .mdc-radio__outer-circle{border-color:rgba(0, 0, 0, 0.54)}.mdc-radio .mdc-radio__native-control:enabled:checked+.mdc-radio__background .mdc-radio__outer-circle{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786)}.mdc-radio .mdc-radio__native-control:enabled+.mdc-radio__background .mdc-radio__inner-circle{border-color:#018786;border-color:var(--mdc-theme-secondary, #018786)}.mdc-radio [aria-disabled=true] .mdc-radio__native-control:not(:checked)+.mdc-radio__background .mdc-radio__outer-circle,.mdc-radio .mdc-radio__native-control:disabled:not(:checked)+.mdc-radio__background .mdc-radio__outer-circle{border-color:rgba(0, 0, 0, 0.38)}.mdc-radio [aria-disabled=true] .mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__outer-circle,.mdc-radio .mdc-radio__native-control:disabled:checked+.mdc-radio__background .mdc-radio__outer-circle{border-color:rgba(0, 0, 0, 0.38)}.mdc-radio [aria-disabled=true] .mdc-radio__native-control+.mdc-radio__background .mdc-radio__inner-circle,.mdc-radio .mdc-radio__native-control:disabled+.mdc-radio__background .mdc-radio__inner-circle{border-color:rgba(0, 0, 0, 0.38)}.mdc-radio .mdc-radio__background::before{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-radio .mdc-radio__background::before{top:calc(-1 * (40px - 20px) / 2);left:calc(-1 * (40px - 20px) / 2);width:40px;height:40px}.mdc-radio .mdc-radio__native-control{top:calc((40px - 40px) / 2);right:calc((40px - 40px) / 2);left:calc((40px - 40px) / 2);width:40px;height:40px}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-radio [aria-disabled=true] .mdc-radio__native-control:not(:checked)+.mdc-radio__background .mdc-radio__outer-circle,.mdc-radio .mdc-radio__native-control:disabled:not(:checked)+.mdc-radio__background .mdc-radio__outer-circle{border-color:GrayText}.mdc-radio [aria-disabled=true] .mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__outer-circle,.mdc-radio .mdc-radio__native-control:disabled:checked+.mdc-radio__background .mdc-radio__outer-circle{border-color:GrayText}.mdc-radio [aria-disabled=true] .mdc-radio__native-control+.mdc-radio__background .mdc-radio__inner-circle,.mdc-radio .mdc-radio__native-control:disabled+.mdc-radio__background .mdc-radio__inner-circle{border-color:GrayText}}.mdc-radio{display:inline-block;position:relative;flex:0 0 auto;box-sizing:content-box;width:20px;height:20px;cursor:pointer;will-change:opacity,transform,border-color,color}.mdc-radio__background{display:inline-block;position:relative;box-sizing:border-box;width:20px;height:20px}.mdc-radio__background::before{position:absolute;-webkit-transform:scale(0, 0);transform:scale(0, 0);border-radius:50%;opacity:0;pointer-events:none;content:"";transition:opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:opacity 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-radio__outer-circle{position:absolute;top:0;left:0;box-sizing:border-box;width:100%;height:100%;border-width:2px;border-style:solid;border-radius:50%;transition:border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-radio__inner-circle{position:absolute;top:0;left:0;box-sizing:border-box;width:100%;height:100%;-webkit-transform:scale(0, 0);transform:scale(0, 0);border-width:10px;border-style:solid;border-radius:50%;transition:border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1);transition:transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),border-color 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1),-webkit-transform 120ms 0ms cubic-bezier(0.4, 0, 0.6, 1)}.mdc-radio__native-control{position:absolute;margin:0;padding:0;opacity:0;cursor:inherit;z-index:1}.mdc-radio--touch{margin-top:4px;margin-bottom:4px;margin-right:4px;margin-left:4px}.mdc-radio--touch .mdc-radio__native-control{top:calc((40px - 48px) / 2);right:calc((40px - 48px) / 2);left:calc((40px - 48px) / 2);width:48px;height:48px}.mdc-radio__native-control:checked+.mdc-radio__background,.mdc-radio__native-control:disabled+.mdc-radio__background{transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__outer-circle,.mdc-radio__native-control:disabled+.mdc-radio__background .mdc-radio__outer-circle{transition:border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__inner-circle,.mdc-radio__native-control:disabled+.mdc-radio__background .mdc-radio__inner-circle{transition:border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio--disabled{cursor:default;pointer-events:none}.mdc-radio__native-control:checked+.mdc-radio__background .mdc-radio__inner-circle{-webkit-transform:scale(0.5);transform:scale(0.5);transition:border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),border-color 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio__native-control:disabled+.mdc-radio__background,[aria-disabled=true] .mdc-radio__native-control+.mdc-radio__background{cursor:default}.mdc-radio__native-control:focus+.mdc-radio__background::before{-webkit-transform:scale(1);transform:scale(1);opacity:.12;transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 120ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 120ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-radio{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-radio .mdc-radio__ripple::before,.mdc-radio .mdc-radio__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-radio .mdc-radio__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-radio .mdc-radio__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-radio.mdc-ripple-upgraded--unbounded .mdc-radio__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-radio.mdc-ripple-upgraded--foreground-activation .mdc-radio__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-radio.mdc-ripple-upgraded--foreground-deactivation .mdc-radio__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-radio .mdc-radio__ripple::before,.mdc-radio .mdc-radio__ripple::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::before,.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-radio.mdc-ripple-upgraded .mdc-radio__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-radio .mdc-radio__ripple::before,.mdc-radio .mdc-radio__ripple::after{background-color:#018786;background-color:var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786))}.mdc-radio:hover .mdc-radio__ripple::before,.mdc-radio.mdc-ripple-surface--hover .mdc-radio__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-radio.mdc-ripple-upgraded--background-focused .mdc-radio__ripple::before,.mdc-radio:not(.mdc-ripple-upgraded):focus .mdc-radio__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-radio:not(.mdc-ripple-upgraded) .mdc-radio__ripple::after{transition:opacity 150ms linear}.mdc-radio:not(.mdc-ripple-upgraded):active .mdc-radio__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-radio.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-radio.mdc-ripple-upgraded .mdc-radio__background::before,.mdc-radio.mdc-ripple-upgraded--background-focused .mdc-radio__background::before{content:none}.mdc-radio__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-ripple-surface{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity;position:relative;outline:none;overflow:hidden}.mdc-ripple-surface::before,.mdc-ripple-surface::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-ripple-surface::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-ripple-surface::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-ripple-surface.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-ripple-surface.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-ripple-surface.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-ripple-surface.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-ripple-surface.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-ripple-surface::before,.mdc-ripple-surface::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-ripple-surface.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface[data-mdc-ripple-is-unbounded],.mdc-ripple-upgraded--unbounded{overflow:visible}.mdc-ripple-surface[data-mdc-ripple-is-unbounded]::before,.mdc-ripple-surface[data-mdc-ripple-is-unbounded]::after,.mdc-ripple-upgraded--unbounded::before,.mdc-ripple-upgraded--unbounded::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::before,.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::after,.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::before,.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface[data-mdc-ripple-is-unbounded].mdc-ripple-upgraded::after,.mdc-ripple-upgraded--unbounded.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-ripple-surface::before,.mdc-ripple-surface::after{background-color:#000;background-color:var(--mdc-ripple-color, #000)}.mdc-ripple-surface:hover::before,.mdc-ripple-surface.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-ripple-surface.mdc-ripple-upgraded--background-focused::before,.mdc-ripple-surface:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-ripple-surface:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-ripple-surface:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-ripple-surface.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-segmented-button{display:inline-block;font-size:0}.mdc-segmented-button__segment{border-color:rgba(0, 0, 0, 0.12);border-color:var(--mdc-segmented-button-outline-color, rgba(0, 0, 0, 0.12))}.mdc-segmented-button__segment{color:rgba(0, 0, 0, 0.6);color:var(--mdc-segmented-button-unselected-ink-color, rgba(0, 0, 0, 0.6))}.mdc-segmented-button__segment{background-color:white;background-color:var(--mdc-segmented-button-unselected-container-fill-color, white)}.mdc-segmented-button__segment--selected{color:#6200ee;color:var(--mdc-segmented-button-selected-ink-color, #6200ee)}.mdc-segmented-button__segment--selected{background-color:rgba(98, 0, 238, 0.08);background-color:var(--mdc-segmented-button-selected-container-fill-color, rgba(98, 0, 238, 0.08))}.mdc-segmented-button__segment{position:relative;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);display:inline-flex;vertical-align:top;align-items:center;height:36px;min-width:48px;padding:0 12px;border-width:1px 0 1px 1px}.mdc-segmented-button__segment .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-segmented-button__segment:hover{cursor:pointer}.mdc-segmented-button__segment:focus{outline-width:0}.mdc-segmented-button__segment:first-child{border-radius:4px 0 0 4px}.mdc-segmented-button__segment:last-child{border-right-width:1px;border-radius:0 4px 4px 0}.mdc-segmented-button__segment .mdc-segmented-button__segment__touch{position:absolute;top:50%;height:48px;left:0;right:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.mdc-segmented-button__segment .mdc-segmented-button__segment--touch{margin-top:0px;margin-bottom:0px}.mdc-touch-target-wrapper .mdc-segmented-button__segment{border-radius:0;border-right-width:0}.mdc-touch-target-wrapper:first-child .mdc-segmented-button__segment{border-radius:4px 0 0 4px}.mdc-touch-target-wrapper:last-child .mdc-segmented-button__segment{border-right-width:1px;border-radius:0 4px 4px 0}.mdc-segmented-button__icon{width:24px;font-size:18px}.mdc-segmented-button__icon+.mdc-segmented-button__label{padding-left:6px}.mdc-segmented-button__segment{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity;overflow:hidden}.mdc-segmented-button__segment .mdc-segmented-button__ripple::before,.mdc-segmented-button__segment .mdc-segmented-button__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-segmented-button__segment .mdc-segmented-button__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-segmented-button__segment .mdc-segmented-button__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-segmented-button__segment.mdc-ripple-upgraded .mdc-segmented-button__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-segmented-button__segment.mdc-ripple-upgraded .mdc-segmented-button__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-segmented-button__segment.mdc-ripple-upgraded--unbounded .mdc-segmented-button__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-segmented-button__segment.mdc-ripple-upgraded--foreground-activation .mdc-segmented-button__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-segmented-button__segment.mdc-ripple-upgraded--foreground-deactivation .mdc-segmented-button__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-segmented-button__segment .mdc-segmented-button__ripple::before,.mdc-segmented-button__segment .mdc-segmented-button__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-segmented-button__segment.mdc-ripple-upgraded .mdc-segmented-button__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-segmented-button__segment .mdc-segmented-button__ripple::before,.mdc-segmented-button__segment .mdc-segmented-button__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, #6200ee)}.mdc-segmented-button__segment:hover .mdc-segmented-button__ripple::before,.mdc-segmented-button__segment.mdc-ripple-surface--hover .mdc-segmented-button__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-segmented-button__segment.mdc-ripple-upgraded--background-focused .mdc-segmented-button__ripple::before,.mdc-segmented-button__segment.mdc-ripple-upgraded:focus-within .mdc-segmented-button__ripple::before,.mdc-segmented-button__segment:not(.mdc-ripple-upgraded):focus .mdc-segmented-button__ripple::before,.mdc-segmented-button__segment:not(.mdc-ripple-upgraded):focus-within .mdc-segmented-button__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-segmented-button__segment:not(.mdc-ripple-upgraded) .mdc-segmented-button__ripple::after{transition:opacity 150ms linear}.mdc-segmented-button__segment:not(.mdc-ripple-upgraded):active .mdc-segmented-button__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-segmented-button__segment.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-segmented-button__segment .mdc-segmented-button__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-slider__thumb{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-slider__thumb::before,.mdc-slider__thumb::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-slider__thumb::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-slider__thumb::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-slider__thumb.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-slider__thumb.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-slider__thumb.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-slider__thumb.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-slider__thumb.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-slider__thumb::before,.mdc-slider__thumb::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-slider__thumb.mdc-ripple-upgraded::before,.mdc-slider__thumb.mdc-ripple-upgraded::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-slider__thumb.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-slider__thumb::before,.mdc-slider__thumb::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-slider__thumb:hover::before,.mdc-slider__thumb.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-slider__thumb.mdc-ripple-upgraded--background-focused::before,.mdc-slider__thumb:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-slider__thumb:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-slider__thumb:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-slider__thumb.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-slider{cursor:pointer;height:48px;margin:0 24px;position:relative;touch-action:pan-y}.mdc-slider .mdc-slider__track{height:4px;position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);width:100%}.mdc-slider .mdc-slider__track--active,.mdc-slider .mdc-slider__track--inactive{display:flex;height:100%;position:absolute;width:100%}.mdc-slider .mdc-slider__track--active{border-radius:3px;height:6px;overflow:hidden;top:-1px}.mdc-slider .mdc-slider__track--active_fill{border-top:6px solid;box-sizing:border-box;height:100%;width:100%;position:relative;-webkit-transform-origin:left;transform-origin:left}[dir=rtl] .mdc-slider .mdc-slider__track--active_fill,.mdc-slider .mdc-slider__track--active_fill[dir=rtl]{-webkit-transform-origin:right;transform-origin:right}.mdc-slider .mdc-slider__track--inactive{border-radius:2px;height:4px;left:0;top:0}.mdc-slider .mdc-slider__track--inactive::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:"";pointer-events:none}.mdc-slider .mdc-slider__track--active_fill{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-slider.mdc-slider--disabled .mdc-slider__track--active_fill{border-color:#000;border-color:var(--mdc-theme-on-surface, #000)}.mdc-slider .mdc-slider__track--inactive{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee);opacity:.24}.mdc-slider.mdc-slider--disabled .mdc-slider__track--inactive{background-color:#000;background-color:var(--mdc-theme-on-surface, #000);opacity:.24}.mdc-slider .mdc-slider__value-indicator-container{bottom:44px;left:50%;pointer-events:none;position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.mdc-slider .mdc-slider__value-indicator{transition:-webkit-transform 100ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:transform 100ms 0ms cubic-bezier(0.4, 0, 1, 1);transition:transform 100ms 0ms cubic-bezier(0.4, 0, 1, 1), -webkit-transform 100ms 0ms cubic-bezier(0.4, 0, 1, 1);align-items:center;border-radius:4px;display:flex;height:32px;padding:0 12px;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:bottom;transform-origin:bottom}.mdc-slider .mdc-slider__value-indicator::before{border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid;bottom:-5px;content:"";height:0;left:50%;position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:0}.mdc-slider .mdc-slider__value-indicator::after{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:"";pointer-events:none}.mdc-slider .mdc-slider__thumb--with-indicator .mdc-slider__value-indicator-container{pointer-events:auto}.mdc-slider .mdc-slider__thumb--with-indicator .mdc-slider__value-indicator{transition:-webkit-transform 100ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 100ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:transform 100ms 0ms cubic-bezier(0, 0, 0.2, 1), -webkit-transform 100ms 0ms cubic-bezier(0, 0, 0.2, 1);-webkit-transform:scale(1);transform:scale(1)}@media(prefers-reduced-motion){.mdc-slider .mdc-slider__value-indicator,.mdc-slider .mdc-slider__thumb--with-indicator .mdc-slider__value-indicator{transition:none}}.mdc-slider .mdc-slider__value-indicator-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-subtitle2-font-size, 0.875rem);line-height:1.375rem;line-height:var(--mdc-typography-subtitle2-line-height, 1.375rem);font-weight:500;font-weight:var(--mdc-typography-subtitle2-font-weight, 500);letter-spacing:0.0071428571em;letter-spacing:var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle2-text-transform, inherit)}.mdc-slider .mdc-slider__value-indicator{background-color:#000;opacity:.6}.mdc-slider .mdc-slider__value-indicator::before{border-top-color:#000}.mdc-slider .mdc-slider__value-indicator{color:#fff;color:var(--mdc-theme-on-primary, #fff)}.mdc-slider .mdc-slider__thumb{display:flex;height:48px;left:-24px;outline:none;position:absolute;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:48px}.mdc-slider .mdc-slider__thumb--top{z-index:1}.mdc-slider .mdc-slider__thumb--top .mdc-slider__thumb-knob,.mdc-slider .mdc-slider__thumb--top.mdc-slider__thumb:hover .mdc-slider__thumb-knob,.mdc-slider .mdc-slider__thumb--top.mdc-slider__thumb--focused .mdc-slider__thumb-knob{border-style:solid;border-width:1px;box-sizing:content-box}.mdc-slider .mdc-slider__thumb-knob{box-shadow:0px 2px 1px -1px rgba(0, 0, 0, 0.2),0px 1px 1px 0px rgba(0, 0, 0, 0.14),0px 1px 3px 0px rgba(0,0,0,.12);border:10px solid;border-radius:50%;box-sizing:border-box;height:20px;left:50%;position:absolute;top:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);width:20px}.mdc-slider .mdc-slider__thumb-knob{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee);border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-slider .mdc-slider__thumb--top .mdc-slider__thumb-knob,.mdc-slider .mdc-slider__thumb--top.mdc-slider__thumb:hover .mdc-slider__thumb-knob,.mdc-slider .mdc-slider__thumb--top.mdc-slider__thumb--focused .mdc-slider__thumb-knob{border-color:#fff}.mdc-slider.mdc-slider--disabled .mdc-slider__thumb-knob{background-color:#000;background-color:var(--mdc-theme-on-surface, #000);border-color:#000;border-color:var(--mdc-theme-on-surface, #000)}.mdc-slider.mdc-slider--disabled .mdc-slider__thumb--top .mdc-slider__thumb-knob,.mdc-slider.mdc-slider--disabled .mdc-slider__thumb--top.mdc-slider__thumb:hover .mdc-slider__thumb-knob,.mdc-slider.mdc-slider--disabled .mdc-slider__thumb--top.mdc-slider__thumb--focused .mdc-slider__thumb-knob{border-color:#fff}.mdc-slider .mdc-slider__thumb::before,.mdc-slider .mdc-slider__thumb::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-slider .mdc-slider__thumb:hover::before,.mdc-slider .mdc-slider__thumb.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-slider .mdc-slider__thumb.mdc-ripple-upgraded--background-focused::before,.mdc-slider .mdc-slider__thumb:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-slider .mdc-slider__thumb:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-slider .mdc-slider__thumb:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-slider .mdc-slider__thumb.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-slider .mdc-slider__tick-marks{align-items:center;box-sizing:border-box;display:flex;height:100%;justify-content:space-between;padding:0 1px;position:absolute;width:100%}.mdc-slider .mdc-slider__tick-mark--active,.mdc-slider .mdc-slider__tick-mark--inactive{border-radius:50%;height:2px;width:2px}.mdc-slider .mdc-slider__tick-mark--active{background-color:#fff;background-color:var(--mdc-theme-on-primary, #fff);opacity:.6}.mdc-slider.mdc-slider--disabled .mdc-slider__tick-mark--active{background-color:#fff;background-color:var(--mdc-theme-on-primary, #fff);opacity:.6}.mdc-slider .mdc-slider__tick-mark--inactive{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee);opacity:.6}.mdc-slider.mdc-slider--disabled .mdc-slider__tick-mark--inactive{background-color:#000;background-color:var(--mdc-theme-on-surface, #000);opacity:.6}.mdc-slider.mdc-slider--disabled{opacity:.38;cursor:auto}.mdc-slider.mdc-slider--disabled .mdc-slider__thumb{pointer-events:none}.mdc-slider--discrete .mdc-slider__thumb,.mdc-slider--discrete .mdc-slider__track--active_fill{transition:-webkit-transform 80ms ease;transition:transform 80ms ease;transition:transform 80ms ease, -webkit-transform 80ms ease}@media(prefers-reduced-motion){.mdc-slider--discrete .mdc-slider__thumb,.mdc-slider--discrete .mdc-slider__track--active_fill{transition:none}}.mdc-slider__input{cursor:pointer;left:0;margin:0;height:100%;opacity:0;pointer-events:none;position:absolute;top:0;width:100%}.mdc-snackbar{z-index:8;margin:8px;display:none;position:fixed;right:0;bottom:0;left:0;align-items:center;justify-content:center;box-sizing:border-box;pointer-events:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-snackbar__surface{background-color:#333333}.mdc-snackbar__label{color:rgba(255, 255, 255, 0.87)}.mdc-snackbar__surface{min-width:344px}@media(max-width: 480px),(max-width: 344px){.mdc-snackbar__surface{min-width:100%}}.mdc-snackbar__surface{max-width:672px}.mdc-snackbar__surface{box-shadow:0px 3px 5px -1px rgba(0, 0, 0, 0.2),0px 6px 10px 0px rgba(0, 0, 0, 0.14),0px 1px 18px 0px rgba(0,0,0,.12)}.mdc-snackbar__surface{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-snackbar--opening,.mdc-snackbar--open,.mdc-snackbar--closing{display:flex}.mdc-snackbar--open .mdc-snackbar__label,.mdc-snackbar--open .mdc-snackbar__actions{visibility:visible}.mdc-snackbar--leading{justify-content:flex-start}.mdc-snackbar--stacked .mdc-snackbar__label{padding-left:16px;padding-right:8px;padding-bottom:12px}[dir=rtl] .mdc-snackbar--stacked .mdc-snackbar__label,.mdc-snackbar--stacked .mdc-snackbar__label[dir=rtl]{padding-left:8px;padding-right:16px}.mdc-snackbar--stacked .mdc-snackbar__surface{flex-direction:column;align-items:flex-start}.mdc-snackbar--stacked .mdc-snackbar__actions{align-self:flex-end;margin-bottom:8px}.mdc-snackbar__surface{padding-left:0;padding-right:8px;display:flex;align-items:center;justify-content:flex-start;box-sizing:border-box;-webkit-transform:scale(0.8);transform:scale(0.8);opacity:0}.mdc-snackbar__surface::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:"";pointer-events:none}[dir=rtl] .mdc-snackbar__surface,.mdc-snackbar__surface[dir=rtl]{padding-left:8px;padding-right:0}.mdc-snackbar--open .mdc-snackbar__surface{-webkit-transform:scale(1);transform:scale(1);opacity:1;pointer-events:auto;transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-snackbar--closing .mdc-snackbar__surface{-webkit-transform:scale(1);transform:scale(1);transition:opacity 75ms 0ms cubic-bezier(0.4, 0, 1, 1)}.mdc-snackbar__label{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);padding-left:16px;padding-right:8px;width:100%;flex-grow:1;box-sizing:border-box;margin:0;visibility:hidden;padding-top:14px;padding-bottom:14px}[dir=rtl] .mdc-snackbar__label,.mdc-snackbar__label[dir=rtl]{padding-left:8px;padding-right:16px}.mdc-snackbar__label::before{display:inline;content:attr(data-mdc-snackbar-label-text)}.mdc-snackbar__actions{display:flex;flex-shrink:0;align-items:center;box-sizing:border-box;visibility:hidden}.mdc-snackbar__action:not(:disabled){color:#bb86fc}.mdc-snackbar__action::before,.mdc-snackbar__action::after{background-color:#bb86fc;background-color:var(--mdc-ripple-color, #bb86fc)}.mdc-snackbar__action:hover::before,.mdc-snackbar__action.mdc-ripple-surface--hover::before{opacity:0.08;opacity:var(--mdc-ripple-hover-opacity, 0.08)}.mdc-snackbar__action.mdc-ripple-upgraded--background-focused::before,.mdc-snackbar__action:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-snackbar__action:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-snackbar__action:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-snackbar__action.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-snackbar__dismiss{color:rgba(255, 255, 255, 0.87)}.mdc-snackbar__dismiss .mdc-icon-button__ripple::before,.mdc-snackbar__dismiss .mdc-icon-button__ripple::after{background-color:rgba(255, 255, 255, 0.87);background-color:var(--mdc-ripple-color, rgba(255, 255, 255, 0.87))}.mdc-snackbar__dismiss:hover .mdc-icon-button__ripple::before,.mdc-snackbar__dismiss.mdc-ripple-surface--hover .mdc-icon-button__ripple::before{opacity:0.08;opacity:var(--mdc-ripple-hover-opacity, 0.08)}.mdc-snackbar__dismiss.mdc-ripple-upgraded--background-focused .mdc-icon-button__ripple::before,.mdc-snackbar__dismiss:not(.mdc-ripple-upgraded):focus .mdc-icon-button__ripple::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-snackbar__dismiss:not(.mdc-ripple-upgraded) .mdc-icon-button__ripple::after{transition:opacity 150ms linear}.mdc-snackbar__dismiss:not(.mdc-ripple-upgraded):active .mdc-icon-button__ripple::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-snackbar__dismiss.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-snackbar__dismiss.mdc-snackbar__dismiss{width:36px;height:36px;padding:6px;font-size:18px}.mdc-snackbar__action+.mdc-snackbar__dismiss{margin-left:8px;margin-right:0}[dir=rtl] .mdc-snackbar__action+.mdc-snackbar__dismiss,.mdc-snackbar__action+.mdc-snackbar__dismiss[dir=rtl]{margin-left:0;margin-right:8px}.mdc-switch__thumb-underlay{left:-14px;right:initial;top:-17px;width:48px;height:48px}[dir=rtl] .mdc-switch__thumb-underlay,.mdc-switch__thumb-underlay[dir=rtl]{left:initial;right:-14px}.mdc-switch__native-control{width:64px;height:48px}.mdc-switch{display:inline-block;position:relative;outline:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdc-switch.mdc-switch--checked .mdc-switch__track{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-switch.mdc-switch--checked .mdc-switch__thumb{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786);border-color:#018786;border-color:var(--mdc-theme-secondary, #018786)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__track{background-color:#000;background-color:var(--mdc-theme-on-surface, #000)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb{background-color:#fff;background-color:var(--mdc-theme-surface, #fff);border-color:#fff;border-color:var(--mdc-theme-surface, #fff)}.mdc-switch__native-control{left:0;right:initial;position:absolute;top:0;margin:0;opacity:0;cursor:pointer;pointer-events:auto;transition:-webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-switch__native-control,.mdc-switch__native-control[dir=rtl]{left:initial;right:0}.mdc-switch__track{box-sizing:border-box;width:36px;height:14px;border:1px solid transparent;border-radius:7px;opacity:.38;transition:opacity 90ms cubic-bezier(0.4, 0, 0.2, 1),background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-switch__thumb-underlay{display:flex;position:absolute;align-items:center;justify-content:center;-webkit-transform:translateX(0);transform:translateX(0);transition:background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1),background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1),background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1),-webkit-transform 90ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-switch__thumb{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12);box-sizing:border-box;width:20px;height:20px;border:10px solid;border-radius:50%;pointer-events:none;z-index:1}.mdc-switch--checked .mdc-switch__track{opacity:.54}.mdc-switch--checked .mdc-switch__thumb-underlay{-webkit-transform:translateX(16px);transform:translateX(16px)}[dir=rtl] .mdc-switch--checked .mdc-switch__thumb-underlay,.mdc-switch--checked .mdc-switch__thumb-underlay[dir=rtl]{-webkit-transform:translateX(-16px);transform:translateX(-16px)}.mdc-switch--checked .mdc-switch__native-control{-webkit-transform:translateX(-16px);transform:translateX(-16px)}[dir=rtl] .mdc-switch--checked .mdc-switch__native-control,.mdc-switch--checked .mdc-switch__native-control[dir=rtl]{-webkit-transform:translateX(16px);transform:translateX(16px)}.mdc-switch--disabled{opacity:.38;pointer-events:none}.mdc-switch--disabled .mdc-switch__thumb{border-width:1px}.mdc-switch--disabled .mdc-switch__native-control{cursor:default;pointer-events:none}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay::before,.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay::after{background-color:#9e9e9e;background-color:var(--mdc-ripple-color, #9e9e9e)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:hover::before,.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay.mdc-ripple-surface--hover::before{opacity:0.08;opacity:var(--mdc-ripple-hover-opacity, 0.08)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay.mdc-ripple-upgraded--background-focused::before,.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb-underlay.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-switch__thumb-underlay{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-switch__thumb-underlay::before,.mdc-switch__thumb-underlay::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-switch__thumb-underlay::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-switch__thumb-underlay::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-switch__thumb-underlay.mdc-ripple-upgraded::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-switch__thumb-underlay.mdc-ripple-upgraded::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-switch__thumb-underlay.mdc-ripple-upgraded--unbounded::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-switch__thumb-underlay.mdc-ripple-upgraded--foreground-activation::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-switch__thumb-underlay.mdc-ripple-upgraded--foreground-deactivation::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-switch__thumb-underlay::before,.mdc-switch__thumb-underlay::after{top:calc(50% - 50%);left:calc(50% - 50%);width:100%;height:100%}.mdc-switch__thumb-underlay.mdc-ripple-upgraded::before,.mdc-switch__thumb-underlay.mdc-ripple-upgraded::after{top:var(--mdc-ripple-top, calc(50% - 50%));left:var(--mdc-ripple-left, calc(50% - 50%));width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-switch__thumb-underlay.mdc-ripple-upgraded::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-switch__thumb-underlay::before,.mdc-switch__thumb-underlay::after{background-color:#018786;background-color:var(--mdc-ripple-color, var(--mdc-theme-secondary, #018786))}.mdc-switch__thumb-underlay:hover::before,.mdc-switch__thumb-underlay.mdc-ripple-surface--hover::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-switch__thumb-underlay.mdc-ripple-upgraded--background-focused::before,.mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-switch__thumb-underlay:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-switch__thumb-underlay.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-tab{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase);position:relative}.mdc-tab .mdc-tab__text-label{color:rgba(0, 0, 0, 0.6)}.mdc-tab .mdc-tab__icon{color:rgba(0, 0, 0, 0.54);fill:currentColor}.mdc-tab__content{position:relative}.mdc-tab__icon{width:24px;height:24px;font-size:24px}.mdc-tab--active .mdc-tab__text-label{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-tab--active .mdc-tab__icon{color:#6200ee;color:var(--mdc-theme-primary, #6200ee);fill:currentColor}.mdc-tab{background:none}.mdc-tab{min-width:90px;padding-right:24px;padding-left:24px;display:flex;flex:1 0 auto;justify-content:center;box-sizing:border-box;margin:0;padding-top:0;padding-bottom:0;border:none;outline:none;text-align:center;white-space:nowrap;cursor:pointer;-webkit-appearance:none;z-index:1}.mdc-tab::-moz-focus-inner{padding:0;border:0}.mdc-tab--min-width{flex:0 1 auto}.mdc-tab__content{display:flex;align-items:center;justify-content:center;height:inherit;pointer-events:none}.mdc-tab__text-label{transition:150ms color linear;display:inline-block;line-height:1;z-index:2}.mdc-tab__icon{transition:150ms color linear;z-index:2}.mdc-tab--stacked .mdc-tab__content{flex-direction:column;align-items:center;justify-content:center}.mdc-tab--stacked .mdc-tab__text-label{padding-top:6px;padding-bottom:4px}.mdc-tab--active .mdc-tab__text-label,.mdc-tab--active .mdc-tab__icon{transition-delay:100ms}.mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label{padding-left:8px;padding-right:0}[dir=rtl] .mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label,.mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label[dir=rtl]{padding-left:0;padding-right:8px}.mdc-tab{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mdc-tab .mdc-tab__ripple::before,.mdc-tab .mdc-tab__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-tab .mdc-tab__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-tab .mdc-tab__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-tab.mdc-ripple-upgraded--unbounded .mdc-tab__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-tab.mdc-ripple-upgraded--foreground-activation .mdc-tab__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-tab.mdc-ripple-upgraded--foreground-deactivation .mdc-tab__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-tab .mdc-tab__ripple::before,.mdc-tab .mdc-tab__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-tab .mdc-tab__ripple::before,.mdc-tab .mdc-tab__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-tab:hover .mdc-tab__ripple::before,.mdc-tab.mdc-ripple-surface--hover .mdc-tab__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-tab.mdc-ripple-upgraded--background-focused .mdc-tab__ripple::before,.mdc-tab:not(.mdc-ripple-upgraded):focus .mdc-tab__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-tab:not(.mdc-ripple-upgraded) .mdc-tab__ripple::after{transition:opacity 150ms linear}.mdc-tab:not(.mdc-ripple-upgraded):active .mdc-tab__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-tab.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-tab__ripple{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;will-change:transform,opacity}.mdc-tab-bar{width:100%}.mdc-tab{height:48px}.mdc-tab--stacked{height:72px}.mdc-tab-indicator .mdc-tab-indicator__content--underline{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-tab-indicator .mdc-tab-indicator__content--icon{color:#018786;color:var(--mdc-theme-secondary, #018786)}.mdc-tab-indicator .mdc-tab-indicator__content--underline{border-top-width:2px}.mdc-tab-indicator .mdc-tab-indicator__content--icon{height:34px;font-size:34px}.mdc-tab-indicator{display:flex;position:absolute;top:0;left:0;justify-content:center;width:100%;height:100%;pointer-events:none;z-index:1}.mdc-tab-indicator__content{-webkit-transform-origin:left;transform-origin:left;opacity:0}.mdc-tab-indicator__content--underline{align-self:flex-end;box-sizing:border-box;width:100%;border-top-style:solid}.mdc-tab-indicator__content--icon{align-self:center;margin:0 auto}.mdc-tab-indicator--active .mdc-tab-indicator__content{opacity:1}.mdc-tab-indicator .mdc-tab-indicator__content{transition:250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1);transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1);transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1), 250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1)}.mdc-tab-indicator--no-transition .mdc-tab-indicator__content{transition:none}.mdc-tab-indicator--fade .mdc-tab-indicator__content{transition:150ms opacity linear}.mdc-tab-indicator--active.mdc-tab-indicator--fade .mdc-tab-indicator__content{transition-delay:100ms}.mdc-tab-scroller{overflow-y:hidden}.mdc-tab-scroller.mdc-tab-scroller--animating .mdc-tab-scroller__scroll-content{transition:250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1);transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1);transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1), 250ms -webkit-transform cubic-bezier(0.4, 0, 0.2, 1)}.mdc-tab-scroller__test{position:absolute;top:-9999px;width:100px;height:100px;overflow-x:scroll}.mdc-tab-scroller__scroll-area{-webkit-overflow-scrolling:touch;display:flex;overflow-x:hidden}.mdc-tab-scroller__scroll-area::-webkit-scrollbar,.mdc-tab-scroller__test::-webkit-scrollbar{display:none}.mdc-tab-scroller__scroll-area--scroll{overflow-x:scroll}.mdc-tab-scroller__scroll-content{position:relative;display:flex;flex:1 0 auto;-webkit-transform:none;transform:none;will-change:transform}.mdc-tab-scroller--align-start .mdc-tab-scroller__scroll-content{justify-content:flex-start}.mdc-tab-scroller--align-end .mdc-tab-scroller__scroll-content{justify-content:flex-end}.mdc-tab-scroller--align-center .mdc-tab-scroller__scroll-content{justify-content:center}.mdc-tab-scroller--animating .mdc-tab-scroller__scroll-area{-webkit-overflow-scrolling:auto}.mdc-text-field--filled{--mdc-ripple-fg-size: 0;--mdc-ripple-left: 0;--mdc-ripple-top: 0;--mdc-ripple-fg-scale: 1;--mdc-ripple-fg-translate-end: 0;--mdc-ripple-fg-translate-start: 0;-webkit-tap-highlight-color:rgba(0,0,0,0);will-change:transform,opacity}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-text-field--filled .mdc-text-field__ripple::before{transition:opacity 15ms linear,background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-text-field--filled .mdc-text-field__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::before{-webkit-transform:scale(var(--mdc-ripple-fg-scale, 1));transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::after{top:0;left:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:center center;transform-origin:center center}.mdc-text-field--filled.mdc-ripple-upgraded--unbounded .mdc-text-field__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-text-field--filled.mdc-ripple-upgraded--foreground-activation .mdc-text-field__ripple::after{-webkit-animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards;animation:mdc-ripple-fg-radius-in 225ms forwards,mdc-ripple-fg-opacity-in 75ms forwards}.mdc-text-field--filled.mdc-ripple-upgraded--foreground-deactivation .mdc-text-field__ripple::after{-webkit-animation:mdc-ripple-fg-opacity-out 150ms;animation:mdc-ripple-fg-opacity-out 150ms;-webkit-transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1));transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-text-field--filled.mdc-ripple-upgraded .mdc-text-field__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-text-field__ripple{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.mdc-text-field{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:0;border-bottom-left-radius:0;display:inline-flex;align-items:baseline;padding:0 16px;position:relative;box-sizing:border-box;overflow:hidden;will-change:opacity,transform,color}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-floating-label{color:rgba(0, 0, 0, 0.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input{color:rgba(0, 0, 0, 0.87)}@media all{.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::-webkit-input-placeholder{color:rgba(0, 0, 0, 0.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input:-ms-input-placeholder{color:rgba(0, 0, 0, 0.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::-ms-input-placeholder{color:rgba(0, 0, 0, 0.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input::placeholder{color:rgba(0, 0, 0, 0.54)}}@media all{.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input:-ms-input-placeholder{color:rgba(0, 0, 0, 0.54)}}.mdc-text-field .mdc-text-field__input{caret-color:#6200ee;caret-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field:not(.mdc-text-field--disabled)+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:rgba(0, 0, 0, 0.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field-character-counter,.mdc-text-field:not(.mdc-text-field--disabled)+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:rgba(0, 0, 0, 0.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__icon--leading{color:rgba(0, 0, 0, 0.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__icon--trailing{color:rgba(0, 0, 0, 0.54)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--prefix{color:rgba(0, 0, 0, 0.6)}.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--suffix{color:rgba(0, 0, 0, 0.6)}.mdc-text-field .mdc-floating-label{top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);pointer-events:none}.mdc-text-field__input{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);height:28px;transition:opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);width:100%;min-width:0;border:none;border-radius:0;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0}.mdc-text-field__input::-ms-clear{display:none}.mdc-text-field__input::-webkit-calendar-picker-indicator{display:none}.mdc-text-field__input:focus{outline:none}.mdc-text-field__input:invalid{box-shadow:none}@media all{.mdc-text-field__input::-webkit-input-placeholder{transition:opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}.mdc-text-field__input:-ms-input-placeholder{transition:opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}.mdc-text-field__input::-ms-input-placeholder{transition:opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}.mdc-text-field__input::placeholder{transition:opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}}@media all{.mdc-text-field__input:-ms-input-placeholder{transition:opacity 67ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0}}@media all{.mdc-text-field--no-label .mdc-text-field__input::-webkit-input-placeholder,.mdc-text-field--focused .mdc-text-field__input::-webkit-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}.mdc-text-field--no-label .mdc-text-field__input:-ms-input-placeholder,.mdc-text-field--focused .mdc-text-field__input:-ms-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}.mdc-text-field--no-label .mdc-text-field__input::-ms-input-placeholder,.mdc-text-field--focused .mdc-text-field__input::-ms-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}.mdc-text-field--no-label .mdc-text-field__input::placeholder,.mdc-text-field--focused .mdc-text-field__input::placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}}@media all{.mdc-text-field--no-label .mdc-text-field__input:-ms-input-placeholder,.mdc-text-field--focused .mdc-text-field__input:-ms-input-placeholder{transition-delay:40ms;transition-duration:110ms;opacity:1}}.mdc-text-field__affix{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit);height:28px;transition:opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1);opacity:0;white-space:nowrap}.mdc-text-field--label-floating .mdc-text-field__affix,.mdc-text-field--no-label .mdc-text-field__affix{opacity:1}@supports(-webkit-hyphens: none){.mdc-text-field--outlined .mdc-text-field__affix{align-items:center;align-self:center;display:inline-flex;height:100%}}.mdc-text-field__affix--prefix{padding-left:0;padding-right:2px}[dir=rtl] .mdc-text-field__affix--prefix,.mdc-text-field__affix--prefix[dir=rtl]{padding-left:2px;padding-right:0}.mdc-text-field--end-aligned .mdc-text-field__affix--prefix{padding-left:0;padding-right:12px}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__affix--prefix,.mdc-text-field--end-aligned .mdc-text-field__affix--prefix[dir=rtl]{padding-left:12px;padding-right:0}.mdc-text-field__affix--suffix{padding-left:12px;padding-right:0}[dir=rtl] .mdc-text-field__affix--suffix,.mdc-text-field__affix--suffix[dir=rtl]{padding-left:0;padding-right:12px}.mdc-text-field--end-aligned .mdc-text-field__affix--suffix{padding-left:2px;padding-right:0}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__affix--suffix,.mdc-text-field--end-aligned .mdc-text-field__affix--suffix[dir=rtl]{padding-left:0;padding-right:2px}.mdc-text-field--filled{height:56px}.mdc-text-field--filled .mdc-text-field__ripple::before,.mdc-text-field--filled .mdc-text-field__ripple::after{background-color:rgba(0, 0, 0, 0.87);background-color:var(--mdc-ripple-color, rgba(0, 0, 0, 0.87))}.mdc-text-field--filled:hover .mdc-text-field__ripple::before,.mdc-text-field--filled.mdc-ripple-surface--hover .mdc-text-field__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-text-field--filled.mdc-ripple-upgraded--background-focused .mdc-text-field__ripple::before,.mdc-text-field--filled:not(.mdc-ripple-upgraded):focus .mdc-text-field__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-text-field--filled::before{display:inline-block;width:0;height:40px;content:"";vertical-align:0}.mdc-text-field--filled:not(.mdc-text-field--disabled){background-color:whitesmoke}.mdc-text-field--filled:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.42)}.mdc-text-field--filled:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.87)}.mdc-text-field--filled .mdc-line-ripple::after{border-bottom-color:#6200ee;border-bottom-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field--filled .mdc-floating-label{left:16px;right:initial}[dir=rtl] .mdc-text-field--filled .mdc-floating-label,.mdc-text-field--filled .mdc-floating-label[dir=rtl]{left:initial;right:16px}.mdc-text-field--filled .mdc-floating-label--float-above{-webkit-transform:translateY(-106%) scale(0.75);transform:translateY(-106%) scale(0.75)}.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__input{height:100%}.mdc-text-field--filled.mdc-text-field--no-label .mdc-floating-label{display:none}.mdc-text-field--filled.mdc-text-field--no-label::before{display:none}@supports(-webkit-hyphens: none){.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__affix{align-items:center;align-self:center;display:inline-flex;height:100%}}.mdc-text-field--outlined{height:56px;overflow:visible}.mdc-text-field--outlined .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) scale(1);transform:translateY(-37.25px) scale(1)}.mdc-text-field--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) scale(0.75);transform:translateY(-34.75px) scale(0.75)}.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--outlined .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-text-field-outlined 250ms 1;animation:mdc-floating-label-shake-float-above-text-field-outlined 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-text-field-outlined{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-34.75px) scale(0.75)}}.mdc-text-field--outlined .mdc-text-field__input{height:100%}.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.38)}.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.87)}.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--outlined:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:4px;border-bottom-left-radius:var(--mdc-shape-small, 4px)}[dir=rtl] .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading[dir=rtl]{border-top-left-radius:0;border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:4px;border-bottom-right-radius:var(--mdc-shape-small, 4px);border-bottom-left-radius:0}@supports(top: max(0%)){.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading{width:max(12px, var(--mdc-shape-small, 4px))}}@supports(top: max(0%)){.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__notch{max-width:calc(100% - max(12px, var(--mdc-shape-small, 4px)) * 2)}}.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing{border-top-left-radius:0;border-top-right-radius:4px;border-top-right-radius:var(--mdc-shape-small, 4px);border-bottom-right-radius:4px;border-bottom-right-radius:var(--mdc-shape-small, 4px);border-bottom-left-radius:0}[dir=rtl] .mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing,.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing[dir=rtl]{border-top-left-radius:4px;border-top-left-radius:var(--mdc-shape-small, 4px);border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:4px;border-bottom-left-radius:var(--mdc-shape-small, 4px)}@supports(top: max(0%)){.mdc-text-field--outlined{padding-left:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}@supports(top: max(0%)){.mdc-text-field--outlined{padding-right:max(16px, var(--mdc-shape-small, 4px))}}@supports(top: max(0%)){.mdc-text-field--outlined+.mdc-text-field-helper-line{padding-left:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}@supports(top: max(0%)){.mdc-text-field--outlined+.mdc-text-field-helper-line{padding-right:max(16px, var(--mdc-shape-small, 4px))}}.mdc-text-field--outlined.mdc-text-field--with-leading-icon{padding-left:0}@supports(top: max(0%)){.mdc-text-field--outlined.mdc-text-field--with-leading-icon{padding-right:max(16px, var(--mdc-shape-small, 4px))}}[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-leading-icon,.mdc-text-field--outlined.mdc-text-field--with-leading-icon[dir=rtl]{padding-right:0}@supports(top: max(0%)){[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-leading-icon,.mdc-text-field--outlined.mdc-text-field--with-leading-icon[dir=rtl]{padding-left:max(16px, var(--mdc-shape-small, 4px))}}.mdc-text-field--outlined.mdc-text-field--with-trailing-icon{padding-right:0}@supports(top: max(0%)){.mdc-text-field--outlined.mdc-text-field--with-trailing-icon{padding-left:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-trailing-icon,.mdc-text-field--outlined.mdc-text-field--with-trailing-icon[dir=rtl]{padding-left:0}@supports(top: max(0%)){[dir=rtl] .mdc-text-field--outlined.mdc-text-field--with-trailing-icon,.mdc-text-field--outlined.mdc-text-field--with-trailing-icon[dir=rtl]{padding-right:max(16px, calc(var(--mdc-shape-small, 4px) + 4px))}}.mdc-text-field--outlined.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon{padding-left:0;padding-right:0}.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:1px}.mdc-text-field--outlined .mdc-text-field__ripple::before,.mdc-text-field--outlined .mdc-text-field__ripple::after{content:none}.mdc-text-field--outlined .mdc-floating-label{left:4px;right:initial}[dir=rtl] .mdc-text-field--outlined .mdc-floating-label,.mdc-text-field--outlined .mdc-floating-label[dir=rtl]{left:initial;right:4px}.mdc-text-field--outlined .mdc-text-field__input{display:flex;border:none !important;background-color:transparent}.mdc-text-field--outlined .mdc-notched-outline{z-index:1}.mdc-text-field--textarea{flex-direction:column;align-items:center;width:auto;height:auto;padding:0;transition:none}.mdc-text-field--textarea .mdc-floating-label{top:19px}.mdc-text-field--textarea .mdc-floating-label:not(.mdc-floating-label--float-above){-webkit-transform:none;transform:none}.mdc-text-field--textarea .mdc-text-field__input{flex-grow:1;height:auto;min-height:1.5rem;overflow-x:hidden;overflow-y:auto;box-sizing:border-box;resize:none;padding:0 16px;line-height:1.5rem}.mdc-text-field--textarea.mdc-text-field--filled::before{display:none}.mdc-text-field--textarea.mdc-text-field--filled .mdc-floating-label--float-above{-webkit-transform:translateY(-10.25px) scale(0.75);transform:translateY(-10.25px) scale(0.75)}.mdc-text-field--textarea.mdc-text-field--filled .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-textarea-filled 250ms 1;animation:mdc-floating-label-shake-float-above-textarea-filled 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-textarea-filled{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-textarea-filled{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-10.25px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-10.25px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-10.25px) scale(0.75)}}.mdc-text-field--textarea.mdc-text-field--filled .mdc-text-field__input{margin-top:23px;margin-bottom:9px}.mdc-text-field--textarea.mdc-text-field--filled.mdc-text-field--no-label .mdc-text-field__input{margin-top:16px;margin-bottom:16px}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:0}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--float-above{-webkit-transform:translateY(-27.25px) scale(1);transform:translateY(-27.25px) scale(1)}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--textarea.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-24.75px) scale(0.75);transform:translateY(-24.75px) scale(0.75)}.mdc-text-field--textarea.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--textarea.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-textarea-outlined 250ms 1;animation:mdc-floating-label-shake-float-above-textarea-outlined 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-textarea-outlined{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-textarea-outlined{0%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(4% - 0%)) translateY(-24.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(-4% - 0%)) translateY(-24.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75);transform:translateX(calc(0 - 0%)) translateY(-24.75px) scale(0.75)}}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-text-field__input{margin-top:16px;margin-bottom:16px}.mdc-text-field--textarea.mdc-text-field--outlined .mdc-floating-label{top:18px}.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field__input{margin-bottom:2px}.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter{align-self:flex-end;padding:0 16px}.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter::after{display:inline-block;width:0;height:16px;content:"";vertical-align:-16px}.mdc-text-field--textarea.mdc-text-field--with-internal-counter .mdc-text-field-character-counter::before{display:none}.mdc-text-field__resizer{align-self:stretch;display:inline-flex;flex-direction:column;flex-grow:1;max-height:100%;max-width:100%;min-height:56px;min-width:-webkit-fit-content;min-width:-moz-fit-content;min-width:fit-content;min-width:-moz-available;min-width:-webkit-fill-available;overflow:hidden;resize:both}.mdc-text-field--filled .mdc-text-field__resizer{-webkit-transform:translateY(-1px);transform:translateY(-1px)}.mdc-text-field--filled .mdc-text-field__resizer .mdc-text-field__input,.mdc-text-field--filled .mdc-text-field__resizer .mdc-text-field-character-counter{-webkit-transform:translateY(1px);transform:translateY(1px)}.mdc-text-field--outlined .mdc-text-field__resizer{-webkit-transform:translateX(-1px) translateY(-1px);transform:translateX(-1px) translateY(-1px)}[dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer,.mdc-text-field--outlined .mdc-text-field__resizer[dir=rtl]{-webkit-transform:translateX(1px) translateY(-1px);transform:translateX(1px) translateY(-1px)}.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input,.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter{-webkit-transform:translateX(1px) translateY(1px);transform:translateX(1px) translateY(1px)}[dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input,[dir=rtl] .mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter,.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field__input[dir=rtl],.mdc-text-field--outlined .mdc-text-field__resizer .mdc-text-field-character-counter[dir=rtl]{-webkit-transform:translateX(-1px) translateY(1px);transform:translateX(-1px) translateY(1px)}.mdc-text-field--with-leading-icon{padding-left:0;padding-right:16px}[dir=rtl] .mdc-text-field--with-leading-icon,.mdc-text-field--with-leading-icon[dir=rtl]{padding-left:16px;padding-right:0}.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 48px);left:48px;right:initial}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label,.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label[dir=rtl]{left:initial;right:48px}.mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 64px / 0.75)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label{left:36px;right:initial}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label[dir=rtl]{left:initial;right:36px}.mdc-text-field--with-leading-icon.mdc-text-field--outlined :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above{-webkit-transform:translateY(-37.25px) translateX(-32px) scale(1);transform:translateY(-37.25px) translateX(-32px) scale(1)}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above[dir=rtl]{-webkit-transform:translateY(-37.25px) translateX(32px) scale(1);transform:translateY(-37.25px) translateX(32px) scale(1)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--float-above{font-size:.75rem}.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{-webkit-transform:translateY(-34.75px) translateX(-32px) scale(0.75);transform:translateY(-34.75px) translateX(-32px) scale(0.75)}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl],.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above[dir=rtl]{-webkit-transform:translateY(-34.75px) translateX(32px) scale(0.75);transform:translateY(-34.75px) translateX(32px) scale(0.75)}.mdc-text-field--with-leading-icon.mdc-text-field--outlined.mdc-notched-outline--upgraded .mdc-floating-label--float-above,.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-notched-outline--upgraded .mdc-floating-label--float-above{font-size:1rem}.mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1;animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon{0%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon{0%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - 32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - 32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - 32px)) translateY(-34.75px) scale(0.75)}}[dir=rtl] .mdc-text-field--with-leading-icon.mdc-text-field--outlined .mdc-floating-label--shake,.mdc-text-field--with-leading-icon.mdc-text-field--outlined[dir=rtl] .mdc-floating-label--shake{-webkit-animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1;animation:mdc-floating-label-shake-float-above-text-field-outlined-leading-icon 250ms 1}@-webkit-keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon-rtl{0%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}@keyframes mdc-floating-label-shake-float-above-text-field-outlined-leading-icon-rtl{0%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}33%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(4% - -32px)) translateY(-34.75px) scale(0.75)}66%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(-4% - -32px)) translateY(-34.75px) scale(0.75)}100%{-webkit-transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75);transform:translateX(calc(0 - -32px)) translateY(-34.75px) scale(0.75)}}.mdc-text-field--with-trailing-icon{padding-left:16px;padding-right:0}[dir=rtl] .mdc-text-field--with-trailing-icon,.mdc-text-field--with-trailing-icon[dir=rtl]{padding-left:0;padding-right:16px}.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 64px)}.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 64px / 0.75)}.mdc-text-field--with-trailing-icon.mdc-text-field--outlined :not(.mdc-notched-outline--notched) .mdc-notched-outline__notch{max-width:calc(100% - 60px)}.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon{padding-left:0;padding-right:0}.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label{max-width:calc(100% - 96px)}.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon.mdc-text-field--filled .mdc-floating-label--float-above{max-width:calc(100% / 0.75 - 96px / 0.75)}.mdc-text-field-helper-line{display:flex;justify-content:space-between;box-sizing:border-box}.mdc-text-field+.mdc-text-field-helper-line{padding-right:16px;padding-left:16px}.mdc-form-field>.mdc-text-field+label{align-self:flex-start}.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label{color:rgba(98, 0, 238, 0.87)}.mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--focused .mdc-notched-outline__trailing{border-width:2px}.mdc-text-field--focused+.mdc-text-field-helper-line .mdc-text-field-helper-text:not(.mdc-text-field-helper-text--validation-msg){opacity:1}.mdc-text-field--focused.mdc-text-field--outlined .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:2px}.mdc-text-field--focused.mdc-text-field--outlined.mdc-text-field--textarea .mdc-notched-outline--notched .mdc-notched-outline__notch{padding-top:0}.mdc-text-field--invalid:not(.mdc-text-field--disabled):hover .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::after{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-floating-label{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--invalid+.mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid .mdc-text-field__input{caret-color:#b00020;caret-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-text-field__icon--trailing{color:#b00020;color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-line-ripple::before{border-bottom-color:#b00020;border-bottom-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled) .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled):not(.mdc-text-field--focused):hover .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__leading,.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__notch,.mdc-text-field--invalid:not(.mdc-text-field--disabled).mdc-text-field--focused .mdc-notched-outline__trailing{border-color:#b00020;border-color:var(--mdc-theme-error, #b00020)}.mdc-text-field--invalid+.mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg{opacity:1}.mdc-text-field--disabled{pointer-events:none}.mdc-text-field--disabled .mdc-text-field__input{color:rgba(0, 0, 0, 0.38)}@media all{.mdc-text-field--disabled .mdc-text-field__input::-webkit-input-placeholder{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field__input::-ms-input-placeholder{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field__input::placeholder{color:rgba(0, 0, 0, 0.38)}}@media all{.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:rgba(0, 0, 0, 0.38)}}.mdc-text-field--disabled .mdc-floating-label{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field-character-counter,.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field__icon--leading{color:rgba(0, 0, 0, 0.3)}.mdc-text-field--disabled .mdc-text-field__icon--trailing{color:rgba(0, 0, 0, 0.3)}.mdc-text-field--disabled .mdc-text-field__affix--prefix{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-text-field__affix--suffix{color:rgba(0, 0, 0, 0.38)}.mdc-text-field--disabled .mdc-line-ripple::before{border-bottom-color:rgba(0, 0, 0, 0.06)}.mdc-text-field--disabled .mdc-notched-outline__leading,.mdc-text-field--disabled .mdc-notched-outline__notch,.mdc-text-field--disabled .mdc-notched-outline__trailing{border-color:rgba(0, 0, 0, 0.06)}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__input::-webkit-input-placeholder{color:GrayText}.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:GrayText}.mdc-text-field--disabled .mdc-text-field__input::-ms-input-placeholder{color:GrayText}.mdc-text-field--disabled .mdc-text-field__input::placeholder{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__input:-ms-input-placeholder{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-floating-label{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-helper-text{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field-character-counter,.mdc-text-field--disabled+.mdc-text-field-helper-line .mdc-text-field-character-counter{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__icon--leading{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__icon--trailing{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__affix--prefix{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-text-field__affix--suffix{color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-line-ripple::before{border-bottom-color:GrayText}}@media screen and (forced-colors: active),(-ms-high-contrast: active){.mdc-text-field--disabled .mdc-notched-outline__leading,.mdc-text-field--disabled .mdc-notched-outline__notch,.mdc-text-field--disabled .mdc-notched-outline__trailing{border-color:GrayText}}@media screen and (forced-colors: active){.mdc-text-field--disabled .mdc-text-field__input{background-color:Window}.mdc-text-field--disabled .mdc-floating-label{z-index:1}}.mdc-text-field--disabled .mdc-floating-label{cursor:default}.mdc-text-field--disabled.mdc-text-field--filled{background-color:#fafafa}.mdc-text-field--disabled.mdc-text-field--filled .mdc-text-field__ripple{display:none}.mdc-text-field--disabled .mdc-text-field__input{pointer-events:auto}.mdc-text-field--end-aligned .mdc-text-field__input{text-align:right}[dir=rtl] .mdc-text-field--end-aligned .mdc-text-field__input,.mdc-text-field--end-aligned .mdc-text-field__input[dir=rtl]{text-align:left}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__input,[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__input,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix{direction:ltr}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--prefix{padding-left:0;padding-right:2px}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--suffix{padding-left:12px;padding-right:0}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__icon--leading,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__icon--leading{order:1}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--suffix{order:2}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__input,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__input{order:3}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__affix--prefix{order:4}[dir=rtl] .mdc-text-field--ltr-text .mdc-text-field__icon--trailing,.mdc-text-field--ltr-text[dir=rtl] .mdc-text-field__icon--trailing{order:5}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__input,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__input{text-align:right}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__affix--prefix,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__affix--prefix{padding-right:12px}[dir=rtl] .mdc-text-field--ltr-text.mdc-text-field--end-aligned .mdc-text-field__affix--suffix,.mdc-text-field--ltr-text.mdc-text-field--end-aligned[dir=rtl] .mdc-text-field__affix--suffix{padding-left:2px}.mdc-text-field-helper-text{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin:0;opacity:0;will-change:opacity;transition:opacity 150ms 0ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-text-field-helper-text::before{display:inline-block;width:0;height:16px;content:"";vertical-align:0}.mdc-text-field-helper-text--persistent{transition:none;opacity:1;will-change:initial}.mdc-text-field-character-counter{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);display:block;margin-top:0;line-height:normal;margin-left:auto;margin-right:0;padding-left:16px;padding-right:0;white-space:nowrap}.mdc-text-field-character-counter::before{display:inline-block;width:0;height:16px;content:"";vertical-align:0}[dir=rtl] .mdc-text-field-character-counter,.mdc-text-field-character-counter[dir=rtl]{margin-left:0;margin-right:auto}[dir=rtl] .mdc-text-field-character-counter,.mdc-text-field-character-counter[dir=rtl]{padding-left:0;padding-right:16px}.mdc-text-field__icon{align-self:center;cursor:pointer}.mdc-text-field__icon:not([tabindex]),.mdc-text-field__icon[tabindex="-1"]{cursor:default;pointer-events:none}.mdc-text-field__icon svg{display:block}.mdc-text-field__icon--leading{margin-left:16px;margin-right:8px}[dir=rtl] .mdc-text-field__icon--leading,.mdc-text-field__icon--leading[dir=rtl]{margin-left:8px;margin-right:16px}.mdc-text-field__icon--trailing{padding:12px;margin-left:0px;margin-right:0px}[dir=rtl] .mdc-text-field__icon--trailing,.mdc-text-field__icon--trailing[dir=rtl]{margin-left:0px;margin-right:0px}:root{--mdc-theme-primary:#6200ee;--mdc-theme-secondary:#018786;--mdc-theme-background:#fff;--mdc-theme-surface:#fff;--mdc-theme-error:#b00020;--mdc-theme-on-primary:#fff;--mdc-theme-on-secondary:#fff;--mdc-theme-on-surface:#000;--mdc-theme-on-error:#fff;--mdc-theme-text-primary-on-background:rgba(0, 0, 0, 0.87);--mdc-theme-text-secondary-on-background:rgba(0, 0, 0, 0.54);--mdc-theme-text-hint-on-background:rgba(0, 0, 0, 0.38);--mdc-theme-text-disabled-on-background:rgba(0, 0, 0, 0.38);--mdc-theme-text-icon-on-background:rgba(0, 0, 0, 0.38);--mdc-theme-text-primary-on-light:rgba(0, 0, 0, 0.87);--mdc-theme-text-secondary-on-light:rgba(0, 0, 0, 0.54);--mdc-theme-text-hint-on-light:rgba(0, 0, 0, 0.38);--mdc-theme-text-disabled-on-light:rgba(0, 0, 0, 0.38);--mdc-theme-text-icon-on-light:rgba(0, 0, 0, 0.38);--mdc-theme-text-primary-on-dark:white;--mdc-theme-text-secondary-on-dark:rgba(255, 255, 255, 0.7);--mdc-theme-text-hint-on-dark:rgba(255, 255, 255, 0.5);--mdc-theme-text-disabled-on-dark:rgba(255, 255, 255, 0.5);--mdc-theme-text-icon-on-dark:rgba(255, 255, 255, 0.5)}.mdc-theme--primary{color:#6200ee !important;color:var(--mdc-theme-primary, #6200ee) !important}.mdc-theme--secondary{color:#018786 !important;color:var(--mdc-theme-secondary, #018786) !important}.mdc-theme--background{background-color:#fff;background-color:var(--mdc-theme-background, #fff)}.mdc-theme--surface{background-color:#fff;background-color:var(--mdc-theme-surface, #fff)}.mdc-theme--error{color:#b00020 !important;color:var(--mdc-theme-error, #b00020) !important}.mdc-theme--on-primary{color:#fff !important;color:var(--mdc-theme-on-primary, #fff) !important}.mdc-theme--on-secondary{color:#fff !important;color:var(--mdc-theme-on-secondary, #fff) !important}.mdc-theme--on-surface{color:#000 !important;color:var(--mdc-theme-on-surface, #000) !important}.mdc-theme--on-error{color:#fff !important;color:var(--mdc-theme-on-error, #fff) !important}.mdc-theme--text-primary-on-background{color:rgba(0, 0, 0, 0.87) !important;color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87)) !important}.mdc-theme--text-secondary-on-background{color:rgba(0, 0, 0, 0.54) !important;color:var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54)) !important}.mdc-theme--text-hint-on-background{color:rgba(0, 0, 0, 0.38) !important;color:var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-disabled-on-background{color:rgba(0, 0, 0, 0.38) !important;color:var(--mdc-theme-text-disabled-on-background, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-icon-on-background{color:rgba(0, 0, 0, 0.38) !important;color:var(--mdc-theme-text-icon-on-background, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-primary-on-light{color:rgba(0, 0, 0, 0.87) !important;color:var(--mdc-theme-text-primary-on-light, rgba(0, 0, 0, 0.87)) !important}.mdc-theme--text-secondary-on-light{color:rgba(0, 0, 0, 0.54) !important;color:var(--mdc-theme-text-secondary-on-light, rgba(0, 0, 0, 0.54)) !important}.mdc-theme--text-hint-on-light{color:rgba(0, 0, 0, 0.38) !important;color:var(--mdc-theme-text-hint-on-light, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-disabled-on-light{color:rgba(0, 0, 0, 0.38) !important;color:var(--mdc-theme-text-disabled-on-light, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-icon-on-light{color:rgba(0, 0, 0, 0.38) !important;color:var(--mdc-theme-text-icon-on-light, rgba(0, 0, 0, 0.38)) !important}.mdc-theme--text-primary-on-dark{color:white !important;color:var(--mdc-theme-text-primary-on-dark, white) !important}.mdc-theme--text-secondary-on-dark{color:rgba(255, 255, 255, 0.7) !important;color:var(--mdc-theme-text-secondary-on-dark, rgba(255, 255, 255, 0.7)) !important}.mdc-theme--text-hint-on-dark{color:rgba(255, 255, 255, 0.5) !important;color:var(--mdc-theme-text-hint-on-dark, rgba(255, 255, 255, 0.5)) !important}.mdc-theme--text-disabled-on-dark{color:rgba(255, 255, 255, 0.5) !important;color:var(--mdc-theme-text-disabled-on-dark, rgba(255, 255, 255, 0.5)) !important}.mdc-theme--text-icon-on-dark{color:rgba(255, 255, 255, 0.5) !important;color:var(--mdc-theme-text-icon-on-dark, rgba(255, 255, 255, 0.5)) !important}.mdc-theme--primary-bg{background-color:#6200ee !important;background-color:var(--mdc-theme-primary, #6200ee) !important}.mdc-theme--secondary-bg{background-color:#018786 !important;background-color:var(--mdc-theme-secondary, #018786) !important}.mdc-tooltip__surface{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-tooltip__caret-surface-top,.mdc-tooltip__caret-surface-bottom{border-radius:4px;border-radius:var(--mdc-shape-small, 4px)}.mdc-tooltip__surface{color:white;color:var(--mdc-theme-text-primary-on-dark, white)}.mdc-tooltip__surface{background-color:rgba(0, 0, 0, 0.6)}.mdc-tooltip__surface{word-break:break-all;word-break:var(--mdc-tooltip-word-break, normal);overflow-wrap:anywhere}.mdc-tooltip{z-index:9}.mdc-tooltip--showing-transition .mdc-tooltip__surface-animation{transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1);transition:opacity 150ms 0ms cubic-bezier(0, 0, 0.2, 1),transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1),-webkit-transform 150ms 0ms cubic-bezier(0, 0, 0.2, 1)}.mdc-tooltip--hide-transition .mdc-tooltip__surface-animation{transition:opacity 75ms 0ms cubic-bezier(0.4, 0, 1, 1)}.mdc-tooltip__title{color:rgba(0, 0, 0, 0.87);color:var(--mdc-theme-text-primary-on-light, rgba(0, 0, 0, 0.87))}.mdc-tooltip__content{color:rgba(0, 0, 0, 0.6)}.mdc-tooltip__content-link{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-tooltip{position:fixed;display:none}.mdc-tooltip.mdc-tooltip--rich .mdc-tooltip__surface{background-color:#fff}.mdc-tooltip.mdc-tooltip--rich .mdc-tooltip__caret-surface-top,.mdc-tooltip.mdc-tooltip--rich .mdc-tooltip__caret-surface-bottom{background-color:#fff}.mdc-tooltip-wrapper--rich{position:relative}.mdc-tooltip--shown,.mdc-tooltip--showing,.mdc-tooltip--hide{display:inline-flex}.mdc-tooltip--shown.mdc-tooltip--rich,.mdc-tooltip--showing.mdc-tooltip--rich,.mdc-tooltip--hide.mdc-tooltip--rich{display:inline-block;left:-320px;position:absolute}.mdc-tooltip__surface{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit);line-height:16px;padding:4px 8px;min-width:40px;max-width:200px;min-height:24px;max-height:40vh;box-sizing:border-box;overflow:hidden;text-align:center}.mdc-tooltip__surface::before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:"";pointer-events:none}.mdc-tooltip--rich .mdc-tooltip__surface{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12);align-items:flex-start;border-radius:4px;display:flex;flex-direction:column;line-height:20px;min-height:24px;min-width:40px;max-width:320px;position:relative}.mdc-tooltip--rich .mdc-tooltip__surface .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-tooltip--multiline .mdc-tooltip__surface{text-align:left}[dir=rtl] .mdc-tooltip--multiline .mdc-tooltip__surface,.mdc-tooltip--multiline .mdc-tooltip__surface[dir=rtl]{text-align:right}.mdc-tooltip__surface .mdc-tooltip__title{display:block;margin-top:0;line-height:normal;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-subtitle2-font-size, 0.875rem);font-weight:500;font-weight:var(--mdc-typography-subtitle2-font-weight, 500);letter-spacing:0.0071428571em;letter-spacing:var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle2-text-transform, inherit);margin:0 8px}.mdc-tooltip__surface .mdc-tooltip__title::before{display:inline-block;width:0;height:28px;content:"";vertical-align:0}.mdc-tooltip__surface .mdc-tooltip__content{display:block;margin-top:0;line-height:normal;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit);max-width:calc(100% - 2 * 8px);margin:0 8px 16px 8px;text-align:left}.mdc-tooltip__surface .mdc-tooltip__content::before{display:inline-block;width:0;height:24px;content:"";vertical-align:0}[dir=rtl] .mdc-tooltip__surface .mdc-tooltip__content,.mdc-tooltip__surface .mdc-tooltip__content[dir=rtl]{text-align:right}.mdc-tooltip__surface .mdc-tooltip__content-link{text-decoration:none}.mdc-tooltip__surface-animation{opacity:0;-webkit-transform:scale(0.8);transform:scale(0.8);will-change:transform,opacity}.mdc-tooltip--shown .mdc-tooltip__surface-animation{-webkit-transform:scale(1);transform:scale(1);opacity:1}.mdc-tooltip--hide .mdc-tooltip__surface-animation{-webkit-transform:scale(1);transform:scale(1)}.mdc-tooltip__caret-surface-top,.mdc-tooltip__caret-surface-bottom{position:absolute;height:24px;width:24px;-webkit-transform:rotate(35deg) skewY(20deg) scaleX(0.9396926208);transform:rotate(35deg) skewY(20deg) scaleX(0.9396926208)}.mdc-tooltip__caret-surface-top .mdc-elevation-overlay,.mdc-tooltip__caret-surface-bottom .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-tooltip__caret-surface-bottom{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12);outline:1px solid transparent;z-index:-1}.mdc-top-app-bar{background-color:#6200ee;background-color:var(--mdc-theme-primary, #6200ee);color:white;display:flex;position:fixed;flex-direction:column;justify-content:space-between;box-sizing:border-box;width:100%;z-index:4}.mdc-top-app-bar .mdc-top-app-bar__action-item,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon{color:#fff;color:var(--mdc-theme-on-primary, #fff)}.mdc-top-app-bar .mdc-top-app-bar__action-item::before,.mdc-top-app-bar .mdc-top-app-bar__action-item::after,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon::after{background-color:#fff;background-color:var(--mdc-ripple-color, var(--mdc-theme-on-primary, #fff))}.mdc-top-app-bar .mdc-top-app-bar__action-item:hover::before,.mdc-top-app-bar .mdc-top-app-bar__action-item.mdc-ripple-surface--hover::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:hover::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon.mdc-ripple-surface--hover::before{opacity:0.08;opacity:var(--mdc-ripple-hover-opacity, 0.08)}.mdc-top-app-bar .mdc-top-app-bar__action-item.mdc-ripple-upgraded--background-focused::before,.mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded):focus::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon.mdc-ripple-upgraded--background-focused::before,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded):focus::before{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-focus-opacity, 0.24)}.mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded)::after,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded)::after{transition:opacity 150ms linear}.mdc-top-app-bar .mdc-top-app-bar__action-item:not(.mdc-ripple-upgraded):active::after,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon:not(.mdc-ripple-upgraded):active::after{transition-duration:75ms;opacity:0.24;opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-top-app-bar .mdc-top-app-bar__action-item.mdc-ripple-upgraded,.mdc-top-app-bar .mdc-top-app-bar__navigation-icon.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.24)}.mdc-top-app-bar__row{display:flex;position:relative;box-sizing:border-box;width:100%;height:64px}.mdc-top-app-bar__section{display:inline-flex;flex:1 1 auto;align-items:center;min-width:0;padding:8px 12px;z-index:1}.mdc-top-app-bar__section--align-start{justify-content:flex-start;order:-1}.mdc-top-app-bar__section--align-end{justify-content:flex-end;order:1}.mdc-top-app-bar__title{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:0.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit);padding-left:20px;padding-right:0;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;z-index:1}[dir=rtl] .mdc-top-app-bar__title,.mdc-top-app-bar__title[dir=rtl]{padding-left:0;padding-right:20px}.mdc-top-app-bar--short-collapsed{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:24px;border-bottom-left-radius:0}[dir=rtl] .mdc-top-app-bar--short-collapsed,.mdc-top-app-bar--short-collapsed[dir=rtl]{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:24px}.mdc-top-app-bar--short{top:0;right:auto;left:0;width:100%;transition:width 250ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-top-app-bar--short,.mdc-top-app-bar--short[dir=rtl]{right:0;left:auto}.mdc-top-app-bar--short .mdc-top-app-bar__row{height:56px}.mdc-top-app-bar--short .mdc-top-app-bar__section{padding:4px}.mdc-top-app-bar--short .mdc-top-app-bar__title{transition:opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);opacity:1}.mdc-top-app-bar--short-collapsed{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12);width:56px;transition:width 300ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__title{display:none}.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__action-item{transition:padding 150ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item{width:112px}.mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end{padding-left:0;padding-right:12px}[dir=rtl] .mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end,.mdc-top-app-bar--short-collapsed.mdc-top-app-bar--short-has-action-item .mdc-top-app-bar__section--align-end[dir=rtl]{padding-left:12px;padding-right:0}.mdc-top-app-bar--dense .mdc-top-app-bar__row{height:48px}.mdc-top-app-bar--dense .mdc-top-app-bar__section{padding:0 4px}.mdc-top-app-bar--dense .mdc-top-app-bar__title{padding-left:12px;padding-right:0}[dir=rtl] .mdc-top-app-bar--dense .mdc-top-app-bar__title,.mdc-top-app-bar--dense .mdc-top-app-bar__title[dir=rtl]{padding-left:0;padding-right:12px}.mdc-top-app-bar--prominent .mdc-top-app-bar__row{height:128px}.mdc-top-app-bar--prominent .mdc-top-app-bar__title{align-self:flex-end;padding-bottom:2px}.mdc-top-app-bar--prominent .mdc-top-app-bar__action-item,.mdc-top-app-bar--prominent .mdc-top-app-bar__navigation-icon{align-self:flex-start}.mdc-top-app-bar--fixed{transition:box-shadow 200ms linear}.mdc-top-app-bar--fixed-scrolled{box-shadow:0px 2px 4px -1px rgba(0, 0, 0, 0.2),0px 4px 5px 0px rgba(0, 0, 0, 0.14),0px 1px 10px 0px rgba(0,0,0,.12);transition:box-shadow 200ms linear}.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__row{height:96px}.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__section{padding:0 12px}.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title{padding-left:20px;padding-right:0;padding-bottom:9px}[dir=rtl] .mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title,.mdc-top-app-bar--dense.mdc-top-app-bar--prominent .mdc-top-app-bar__title[dir=rtl]{padding-left:0;padding-right:20px}.mdc-top-app-bar--fixed-adjust{padding-top:64px}.mdc-top-app-bar--dense-fixed-adjust{padding-top:48px}.mdc-top-app-bar--short-fixed-adjust{padding-top:56px}.mdc-top-app-bar--prominent-fixed-adjust{padding-top:128px}.mdc-top-app-bar--dense-prominent-fixed-adjust{padding-top:96px}@media(max-width: 599px){.mdc-top-app-bar__row{height:56px}.mdc-top-app-bar__section{padding:4px}.mdc-top-app-bar--short{transition:width 200ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-top-app-bar--short-collapsed{transition:width 250ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end{padding-left:0;padding-right:12px}[dir=rtl] .mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end,.mdc-top-app-bar--short-collapsed .mdc-top-app-bar__section--align-end[dir=rtl]{padding-left:12px;padding-right:0}.mdc-top-app-bar--prominent .mdc-top-app-bar__title{padding-bottom:6px}.mdc-top-app-bar--fixed-adjust{padding-top:56px}}.mdc-typography{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-font-family, Roboto, sans-serif)}.mdc-typography--headline1{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:6rem;font-size:var(--mdc-typography-headline1-font-size, 6rem);line-height:6rem;line-height:var(--mdc-typography-headline1-line-height, 6rem);font-weight:300;font-weight:var(--mdc-typography-headline1-font-weight, 300);letter-spacing:-0.015625em;letter-spacing:var(--mdc-typography-headline1-letter-spacing, -0.015625em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline1-text-decoration, inherit);text-decoration:var(--mdc-typography-headline1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline1-text-transform, inherit)}.mdc-typography--headline2{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:3.75rem;font-size:var(--mdc-typography-headline2-font-size, 3.75rem);line-height:3.75rem;line-height:var(--mdc-typography-headline2-line-height, 3.75rem);font-weight:300;font-weight:var(--mdc-typography-headline2-font-weight, 300);letter-spacing:-0.0083333333em;letter-spacing:var(--mdc-typography-headline2-letter-spacing, -0.0083333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline2-text-decoration, inherit);text-decoration:var(--mdc-typography-headline2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline2-text-transform, inherit)}.mdc-typography--headline3{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline3-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:3rem;font-size:var(--mdc-typography-headline3-font-size, 3rem);line-height:3.125rem;line-height:var(--mdc-typography-headline3-line-height, 3.125rem);font-weight:400;font-weight:var(--mdc-typography-headline3-font-weight, 400);letter-spacing:normal;letter-spacing:var(--mdc-typography-headline3-letter-spacing, normal);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline3-text-decoration, inherit);text-decoration:var(--mdc-typography-headline3-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline3-text-transform, inherit)}.mdc-typography--headline4{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline4-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:2.125rem;font-size:var(--mdc-typography-headline4-font-size, 2.125rem);line-height:2.5rem;line-height:var(--mdc-typography-headline4-line-height, 2.5rem);font-weight:400;font-weight:var(--mdc-typography-headline4-font-weight, 400);letter-spacing:0.0073529412em;letter-spacing:var(--mdc-typography-headline4-letter-spacing, 0.0073529412em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline4-text-decoration, inherit);text-decoration:var(--mdc-typography-headline4-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline4-text-transform, inherit)}.mdc-typography--headline5{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline5-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.5rem;font-size:var(--mdc-typography-headline5-font-size, 1.5rem);line-height:2rem;line-height:var(--mdc-typography-headline5-line-height, 2rem);font-weight:400;font-weight:var(--mdc-typography-headline5-font-weight, 400);letter-spacing:normal;letter-spacing:var(--mdc-typography-headline5-letter-spacing, normal);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline5-text-decoration, inherit);text-decoration:var(--mdc-typography-headline5-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline5-text-transform, inherit)}.mdc-typography--headline6{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-headline6-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1.25rem;font-size:var(--mdc-typography-headline6-font-size, 1.25rem);line-height:2rem;line-height:var(--mdc-typography-headline6-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-headline6-font-weight, 500);letter-spacing:0.0125em;letter-spacing:var(--mdc-typography-headline6-letter-spacing, 0.0125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-decoration:var(--mdc-typography-headline6-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-headline6-text-transform, inherit)}.mdc-typography--subtitle1{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-subtitle1-font-size, 1rem);line-height:1.75rem;line-height:var(--mdc-typography-subtitle1-line-height, 1.75rem);font-weight:400;font-weight:var(--mdc-typography-subtitle1-font-weight, 400);letter-spacing:0.009375em;letter-spacing:var(--mdc-typography-subtitle1-letter-spacing, 0.009375em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle1-text-transform, inherit)}.mdc-typography--subtitle2{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-subtitle2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-subtitle2-font-size, 0.875rem);line-height:1.375rem;line-height:var(--mdc-typography-subtitle2-line-height, 1.375rem);font-weight:500;font-weight:var(--mdc-typography-subtitle2-font-weight, 500);letter-spacing:0.0071428571em;letter-spacing:var(--mdc-typography-subtitle2-letter-spacing, 0.0071428571em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-decoration:var(--mdc-typography-subtitle2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-subtitle2-text-transform, inherit)}.mdc-typography--body1{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body1-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:1rem;font-size:var(--mdc-typography-body1-font-size, 1rem);line-height:1.5rem;line-height:var(--mdc-typography-body1-line-height, 1.5rem);font-weight:400;font-weight:var(--mdc-typography-body1-font-weight, 400);letter-spacing:0.03125em;letter-spacing:var(--mdc-typography-body1-letter-spacing, 0.03125em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-decoration:var(--mdc-typography-body1-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body1-text-transform, inherit)}.mdc-typography--body2{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-body2-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-body2-font-size, 0.875rem);line-height:1.25rem;line-height:var(--mdc-typography-body2-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-body2-font-weight, 400);letter-spacing:0.0178571429em;letter-spacing:var(--mdc-typography-body2-letter-spacing, 0.0178571429em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-decoration:var(--mdc-typography-body2-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-body2-text-transform, inherit)}.mdc-typography--caption{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-caption-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-caption-font-size, 0.75rem);line-height:1.25rem;line-height:var(--mdc-typography-caption-line-height, 1.25rem);font-weight:400;font-weight:var(--mdc-typography-caption-font-weight, 400);letter-spacing:0.0333333333em;letter-spacing:var(--mdc-typography-caption-letter-spacing, 0.0333333333em);text-decoration:inherit;-webkit-text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-decoration:var(--mdc-typography-caption-text-decoration, inherit);text-transform:inherit;text-transform:var(--mdc-typography-caption-text-transform, inherit)}.mdc-typography--button{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-button-text-decoration, none);text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase)}.mdc-typography--overline{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-overline-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.75rem;font-size:var(--mdc-typography-overline-font-size, 0.75rem);line-height:2rem;line-height:var(--mdc-typography-overline-line-height, 2rem);font-weight:500;font-weight:var(--mdc-typography-overline-font-weight, 500);letter-spacing:0.1666666667em;letter-spacing:var(--mdc-typography-overline-letter-spacing, 0.1666666667em);text-decoration:none;-webkit-text-decoration:var(--mdc-typography-overline-text-decoration, none);text-decoration:var(--mdc-typography-overline-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-overline-text-transform, uppercase)}
+
+ /*# sourceMappingURL=material-components-web.min.css.map*/
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/pure/LICENSE b/pkgs/csslib/third_party/pure/LICENSE
new file mode 100644
index 0000000..aae45d8
--- /dev/null
+++ b/pkgs/csslib/third_party/pure/LICENSE
@@ -0,0 +1,29 @@
+Software License Agreement (BSD License)
+========================================
+
+Copyright 2013 Yahoo! Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the Yahoo! Inc. nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/csslib/third_party/pure/README.md b/pkgs/csslib/third_party/pure/README.md
new file mode 100644
index 0000000..7c005a6
--- /dev/null
+++ b/pkgs/csslib/third_party/pure/README.md
@@ -0,0 +1,4 @@
+This folder contains sample css files from the open-source project
+https://github.com/pure-css/pure/
+
+This code was included under the terms in the `LICENSE` file.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/pure/main-grid.css b/pkgs/csslib/third_party/pure/main-grid.css
new file mode 100644
index 0000000..0598dfe
--- /dev/null
+++ b/pkgs/csslib/third_party/pure/main-grid.css
@@ -0,0 +1,855 @@
+@media screen and (min-width: 35.5em) {
+ .u-sm-1,
+ .u-sm-1-1,
+ .u-sm-1-2,
+ .u-sm-1-3,
+ .u-sm-2-3,
+ .u-sm-1-4,
+ .u-sm-3-4,
+ .u-sm-1-5,
+ .u-sm-2-5,
+ .u-sm-3-5,
+ .u-sm-4-5,
+ .u-sm-5-5,
+ .u-sm-1-6,
+ .u-sm-5-6,
+ .u-sm-1-8,
+ .u-sm-3-8,
+ .u-sm-5-8,
+ .u-sm-7-8,
+ .u-sm-1-12,
+ .u-sm-5-12,
+ .u-sm-7-12,
+ .u-sm-11-12,
+ .u-sm-1-24,
+ .u-sm-2-24,
+ .u-sm-3-24,
+ .u-sm-4-24,
+ .u-sm-5-24,
+ .u-sm-6-24,
+ .u-sm-7-24,
+ .u-sm-8-24,
+ .u-sm-9-24,
+ .u-sm-10-24,
+ .u-sm-11-24,
+ .u-sm-12-24,
+ .u-sm-13-24,
+ .u-sm-14-24,
+ .u-sm-15-24,
+ .u-sm-16-24,
+ .u-sm-17-24,
+ .u-sm-18-24,
+ .u-sm-19-24,
+ .u-sm-20-24,
+ .u-sm-21-24,
+ .u-sm-22-24,
+ .u-sm-23-24,
+ .u-sm-24-24 {
+ display: inline-block;
+ *display: inline;
+ zoom: 1;
+ letter-spacing: normal;
+ word-spacing: normal;
+ vertical-align: top;
+ text-rendering: auto;
+ }
+
+ .u-sm-1-24 {
+ width: 4.1667%;
+ *width: 4.1357%;
+ }
+
+ .u-sm-1-12,
+ .u-sm-2-24 {
+ width: 8.3333%;
+ *width: 8.3023%;
+ }
+
+ .u-sm-1-8,
+ .u-sm-3-24 {
+ width: 12.5000%;
+ *width: 12.4690%;
+ }
+
+ .u-sm-1-6,
+ .u-sm-4-24 {
+ width: 16.6667%;
+ *width: 16.6357%;
+ }
+
+ .u-sm-1-5 {
+ width: 20%;
+ *width: 19.9690%;
+ }
+
+ .u-sm-5-24 {
+ width: 20.8333%;
+ *width: 20.8023%;
+ }
+
+ .u-sm-1-4,
+ .u-sm-6-24 {
+ width: 25%;
+ *width: 24.9690%;
+ }
+
+ .u-sm-7-24 {
+ width: 29.1667%;
+ *width: 29.1357%;
+ }
+
+ .u-sm-1-3,
+ .u-sm-8-24 {
+ width: 33.3333%;
+ *width: 33.3023%;
+ }
+
+ .u-sm-3-8,
+ .u-sm-9-24 {
+ width: 37.5000%;
+ *width: 37.4690%;
+ }
+
+ .u-sm-2-5 {
+ width: 40%;
+ *width: 39.9690%;
+ }
+
+ .u-sm-5-12,
+ .u-sm-10-24 {
+ width: 41.6667%;
+ *width: 41.6357%;
+ }
+
+ .u-sm-11-24 {
+ width: 45.8333%;
+ *width: 45.8023%;
+ }
+
+ .u-sm-1-2,
+ .u-sm-12-24 {
+ width: 50%;
+ *width: 49.9690%;
+ }
+
+ .u-sm-13-24 {
+ width: 54.1667%;
+ *width: 54.1357%;
+ }
+
+ .u-sm-7-12,
+ .u-sm-14-24 {
+ width: 58.3333%;
+ *width: 58.3023%;
+ }
+
+ .u-sm-3-5 {
+ width: 60%;
+ *width: 59.9690%;
+ }
+
+ .u-sm-5-8,
+ .u-sm-15-24 {
+ width: 62.5000%;
+ *width: 62.4690%;
+ }
+
+ .u-sm-2-3,
+ .u-sm-16-24 {
+ width: 66.6667%;
+ *width: 66.6357%;
+ }
+
+ .u-sm-17-24 {
+ width: 70.8333%;
+ *width: 70.8023%;
+ }
+
+ .u-sm-3-4,
+ .u-sm-18-24 {
+ width: 75%;
+ *width: 74.9690%;
+ }
+
+ .u-sm-19-24 {
+ width: 79.1667%;
+ *width: 79.1357%;
+ }
+
+ .u-sm-4-5 {
+ width: 80%;
+ *width: 79.9690%;
+ }
+
+ .u-sm-5-6,
+ .u-sm-20-24 {
+ width: 83.3333%;
+ *width: 83.3023%;
+ }
+
+ .u-sm-7-8,
+ .u-sm-21-24 {
+ width: 87.5000%;
+ *width: 87.4690%;
+ }
+
+ .u-sm-11-12,
+ .u-sm-22-24 {
+ width: 91.6667%;
+ *width: 91.6357%;
+ }
+
+ .u-sm-23-24 {
+ width: 95.8333%;
+ *width: 95.8023%;
+ }
+
+ .u-sm-1,
+ .u-sm-1-1,
+ .u-sm-5-5,
+ .u-sm-24-24 {
+ width: 100%;
+ }
+}
+
+@media screen and (min-width: 48em) {
+ .u-md-1,
+ .u-md-1-1,
+ .u-md-1-2,
+ .u-md-1-3,
+ .u-md-2-3,
+ .u-md-1-4,
+ .u-md-3-4,
+ .u-md-1-5,
+ .u-md-2-5,
+ .u-md-3-5,
+ .u-md-4-5,
+ .u-md-5-5,
+ .u-md-1-6,
+ .u-md-5-6,
+ .u-md-1-8,
+ .u-md-3-8,
+ .u-md-5-8,
+ .u-md-7-8,
+ .u-md-1-12,
+ .u-md-5-12,
+ .u-md-7-12,
+ .u-md-11-12,
+ .u-md-1-24,
+ .u-md-2-24,
+ .u-md-3-24,
+ .u-md-4-24,
+ .u-md-5-24,
+ .u-md-6-24,
+ .u-md-7-24,
+ .u-md-8-24,
+ .u-md-9-24,
+ .u-md-10-24,
+ .u-md-11-24,
+ .u-md-12-24,
+ .u-md-13-24,
+ .u-md-14-24,
+ .u-md-15-24,
+ .u-md-16-24,
+ .u-md-17-24,
+ .u-md-18-24,
+ .u-md-19-24,
+ .u-md-20-24,
+ .u-md-21-24,
+ .u-md-22-24,
+ .u-md-23-24,
+ .u-md-24-24 {
+ display: inline-block;
+ *display: inline;
+ zoom: 1;
+ letter-spacing: normal;
+ word-spacing: normal;
+ vertical-align: top;
+ text-rendering: auto;
+ }
+
+ .u-md-1-24 {
+ width: 4.1667%;
+ *width: 4.1357%;
+ }
+
+ .u-md-1-12,
+ .u-md-2-24 {
+ width: 8.3333%;
+ *width: 8.3023%;
+ }
+
+ .u-md-1-8,
+ .u-md-3-24 {
+ width: 12.5000%;
+ *width: 12.4690%;
+ }
+
+ .u-md-1-6,
+ .u-md-4-24 {
+ width: 16.6667%;
+ *width: 16.6357%;
+ }
+
+ .u-md-1-5 {
+ width: 20%;
+ *width: 19.9690%;
+ }
+
+ .u-md-5-24 {
+ width: 20.8333%;
+ *width: 20.8023%;
+ }
+
+ .u-md-1-4,
+ .u-md-6-24 {
+ width: 25%;
+ *width: 24.9690%;
+ }
+
+ .u-md-7-24 {
+ width: 29.1667%;
+ *width: 29.1357%;
+ }
+
+ .u-md-1-3,
+ .u-md-8-24 {
+ width: 33.3333%;
+ *width: 33.3023%;
+ }
+
+ .u-md-3-8,
+ .u-md-9-24 {
+ width: 37.5000%;
+ *width: 37.4690%;
+ }
+
+ .u-md-2-5 {
+ width: 40%;
+ *width: 39.9690%;
+ }
+
+ .u-md-5-12,
+ .u-md-10-24 {
+ width: 41.6667%;
+ *width: 41.6357%;
+ }
+
+ .u-md-11-24 {
+ width: 45.8333%;
+ *width: 45.8023%;
+ }
+
+ .u-md-1-2,
+ .u-md-12-24 {
+ width: 50%;
+ *width: 49.9690%;
+ }
+
+ .u-md-13-24 {
+ width: 54.1667%;
+ *width: 54.1357%;
+ }
+
+ .u-md-7-12,
+ .u-md-14-24 {
+ width: 58.3333%;
+ *width: 58.3023%;
+ }
+
+ .u-md-3-5 {
+ width: 60%;
+ *width: 59.9690%;
+ }
+
+ .u-md-5-8,
+ .u-md-15-24 {
+ width: 62.5000%;
+ *width: 62.4690%;
+ }
+
+ .u-md-2-3,
+ .u-md-16-24 {
+ width: 66.6667%;
+ *width: 66.6357%;
+ }
+
+ .u-md-17-24 {
+ width: 70.8333%;
+ *width: 70.8023%;
+ }
+
+ .u-md-3-4,
+ .u-md-18-24 {
+ width: 75%;
+ *width: 74.9690%;
+ }
+
+ .u-md-19-24 {
+ width: 79.1667%;
+ *width: 79.1357%;
+ }
+
+ .u-md-4-5 {
+ width: 80%;
+ *width: 79.9690%;
+ }
+
+ .u-md-5-6,
+ .u-md-20-24 {
+ width: 83.3333%;
+ *width: 83.3023%;
+ }
+
+ .u-md-7-8,
+ .u-md-21-24 {
+ width: 87.5000%;
+ *width: 87.4690%;
+ }
+
+ .u-md-11-12,
+ .u-md-22-24 {
+ width: 91.6667%;
+ *width: 91.6357%;
+ }
+
+ .u-md-23-24 {
+ width: 95.8333%;
+ *width: 95.8023%;
+ }
+
+ .u-md-1,
+ .u-md-1-1,
+ .u-md-5-5,
+ .u-md-24-24 {
+ width: 100%;
+ }
+}
+
+@media screen and (min-width: 58em) {
+ .u-lg-1,
+ .u-lg-1-1,
+ .u-lg-1-2,
+ .u-lg-1-3,
+ .u-lg-2-3,
+ .u-lg-1-4,
+ .u-lg-3-4,
+ .u-lg-1-5,
+ .u-lg-2-5,
+ .u-lg-3-5,
+ .u-lg-4-5,
+ .u-lg-5-5,
+ .u-lg-1-6,
+ .u-lg-5-6,
+ .u-lg-1-8,
+ .u-lg-3-8,
+ .u-lg-5-8,
+ .u-lg-7-8,
+ .u-lg-1-12,
+ .u-lg-5-12,
+ .u-lg-7-12,
+ .u-lg-11-12,
+ .u-lg-1-24,
+ .u-lg-2-24,
+ .u-lg-3-24,
+ .u-lg-4-24,
+ .u-lg-5-24,
+ .u-lg-6-24,
+ .u-lg-7-24,
+ .u-lg-8-24,
+ .u-lg-9-24,
+ .u-lg-10-24,
+ .u-lg-11-24,
+ .u-lg-12-24,
+ .u-lg-13-24,
+ .u-lg-14-24,
+ .u-lg-15-24,
+ .u-lg-16-24,
+ .u-lg-17-24,
+ .u-lg-18-24,
+ .u-lg-19-24,
+ .u-lg-20-24,
+ .u-lg-21-24,
+ .u-lg-22-24,
+ .u-lg-23-24,
+ .u-lg-24-24 {
+ display: inline-block;
+ *display: inline;
+ zoom: 1;
+ letter-spacing: normal;
+ word-spacing: normal;
+ vertical-align: top;
+ text-rendering: auto;
+ }
+
+ .u-lg-1-24 {
+ width: 4.1667%;
+ *width: 4.1357%;
+ }
+
+ .u-lg-1-12,
+ .u-lg-2-24 {
+ width: 8.3333%;
+ *width: 8.3023%;
+ }
+
+ .u-lg-1-8,
+ .u-lg-3-24 {
+ width: 12.5000%;
+ *width: 12.4690%;
+ }
+
+ .u-lg-1-6,
+ .u-lg-4-24 {
+ width: 16.6667%;
+ *width: 16.6357%;
+ }
+
+ .u-lg-1-5 {
+ width: 20%;
+ *width: 19.9690%;
+ }
+
+ .u-lg-5-24 {
+ width: 20.8333%;
+ *width: 20.8023%;
+ }
+
+ .u-lg-1-4,
+ .u-lg-6-24 {
+ width: 25%;
+ *width: 24.9690%;
+ }
+
+ .u-lg-7-24 {
+ width: 29.1667%;
+ *width: 29.1357%;
+ }
+
+ .u-lg-1-3,
+ .u-lg-8-24 {
+ width: 33.3333%;
+ *width: 33.3023%;
+ }
+
+ .u-lg-3-8,
+ .u-lg-9-24 {
+ width: 37.5000%;
+ *width: 37.4690%;
+ }
+
+ .u-lg-2-5 {
+ width: 40%;
+ *width: 39.9690%;
+ }
+
+ .u-lg-5-12,
+ .u-lg-10-24 {
+ width: 41.6667%;
+ *width: 41.6357%;
+ }
+
+ .u-lg-11-24 {
+ width: 45.8333%;
+ *width: 45.8023%;
+ }
+
+ .u-lg-1-2,
+ .u-lg-12-24 {
+ width: 50%;
+ *width: 49.9690%;
+ }
+
+ .u-lg-13-24 {
+ width: 54.1667%;
+ *width: 54.1357%;
+ }
+
+ .u-lg-7-12,
+ .u-lg-14-24 {
+ width: 58.3333%;
+ *width: 58.3023%;
+ }
+
+ .u-lg-3-5 {
+ width: 60%;
+ *width: 59.9690%;
+ }
+
+ .u-lg-5-8,
+ .u-lg-15-24 {
+ width: 62.5000%;
+ *width: 62.4690%;
+ }
+
+ .u-lg-2-3,
+ .u-lg-16-24 {
+ width: 66.6667%;
+ *width: 66.6357%;
+ }
+
+ .u-lg-17-24 {
+ width: 70.8333%;
+ *width: 70.8023%;
+ }
+
+ .u-lg-3-4,
+ .u-lg-18-24 {
+ width: 75%;
+ *width: 74.9690%;
+ }
+
+ .u-lg-19-24 {
+ width: 79.1667%;
+ *width: 79.1357%;
+ }
+
+ .u-lg-4-5 {
+ width: 80%;
+ *width: 79.9690%;
+ }
+
+ .u-lg-5-6,
+ .u-lg-20-24 {
+ width: 83.3333%;
+ *width: 83.3023%;
+ }
+
+ .u-lg-7-8,
+ .u-lg-21-24 {
+ width: 87.5000%;
+ *width: 87.4690%;
+ }
+
+ .u-lg-11-12,
+ .u-lg-22-24 {
+ width: 91.6667%;
+ *width: 91.6357%;
+ }
+
+ .u-lg-23-24 {
+ width: 95.8333%;
+ *width: 95.8023%;
+ }
+
+ .u-lg-1,
+ .u-lg-1-1,
+ .u-lg-5-5,
+ .u-lg-24-24 {
+ width: 100%;
+ }
+}
+
+@media screen and (min-width: 75em) {
+ .u-xl-1,
+ .u-xl-1-1,
+ .u-xl-1-2,
+ .u-xl-1-3,
+ .u-xl-2-3,
+ .u-xl-1-4,
+ .u-xl-3-4,
+ .u-xl-1-5,
+ .u-xl-2-5,
+ .u-xl-3-5,
+ .u-xl-4-5,
+ .u-xl-5-5,
+ .u-xl-1-6,
+ .u-xl-5-6,
+ .u-xl-1-8,
+ .u-xl-3-8,
+ .u-xl-5-8,
+ .u-xl-7-8,
+ .u-xl-1-12,
+ .u-xl-5-12,
+ .u-xl-7-12,
+ .u-xl-11-12,
+ .u-xl-1-24,
+ .u-xl-2-24,
+ .u-xl-3-24,
+ .u-xl-4-24,
+ .u-xl-5-24,
+ .u-xl-6-24,
+ .u-xl-7-24,
+ .u-xl-8-24,
+ .u-xl-9-24,
+ .u-xl-10-24,
+ .u-xl-11-24,
+ .u-xl-12-24,
+ .u-xl-13-24,
+ .u-xl-14-24,
+ .u-xl-15-24,
+ .u-xl-16-24,
+ .u-xl-17-24,
+ .u-xl-18-24,
+ .u-xl-19-24,
+ .u-xl-20-24,
+ .u-xl-21-24,
+ .u-xl-22-24,
+ .u-xl-23-24,
+ .u-xl-24-24 {
+ display: inline-block;
+ *display: inline;
+ zoom: 1;
+ letter-spacing: normal;
+ word-spacing: normal;
+ vertical-align: top;
+ text-rendering: auto;
+ }
+
+ .u-xl-1-24 {
+ width: 4.1667%;
+ *width: 4.1357%;
+ }
+
+ .u-xl-1-12,
+ .u-xl-2-24 {
+ width: 8.3333%;
+ *width: 8.3023%;
+ }
+
+ .u-xl-1-8,
+ .u-xl-3-24 {
+ width: 12.5000%;
+ *width: 12.4690%;
+ }
+
+ .u-xl-1-6,
+ .u-xl-4-24 {
+ width: 16.6667%;
+ *width: 16.6357%;
+ }
+
+ .u-xl-1-5 {
+ width: 20%;
+ *width: 19.9690%;
+ }
+
+ .u-xl-5-24 {
+ width: 20.8333%;
+ *width: 20.8023%;
+ }
+
+ .u-xl-1-4,
+ .u-xl-6-24 {
+ width: 25%;
+ *width: 24.9690%;
+ }
+
+ .u-xl-7-24 {
+ width: 29.1667%;
+ *width: 29.1357%;
+ }
+
+ .u-xl-1-3,
+ .u-xl-8-24 {
+ width: 33.3333%;
+ *width: 33.3023%;
+ }
+
+ .u-xl-3-8,
+ .u-xl-9-24 {
+ width: 37.5000%;
+ *width: 37.4690%;
+ }
+
+ .u-xl-2-5 {
+ width: 40%;
+ *width: 39.9690%;
+ }
+
+ .u-xl-5-12,
+ .u-xl-10-24 {
+ width: 41.6667%;
+ *width: 41.6357%;
+ }
+
+ .u-xl-11-24 {
+ width: 45.8333%;
+ *width: 45.8023%;
+ }
+
+ .u-xl-1-2,
+ .u-xl-12-24 {
+ width: 50%;
+ *width: 49.9690%;
+ }
+
+ .u-xl-13-24 {
+ width: 54.1667%;
+ *width: 54.1357%;
+ }
+
+ .u-xl-7-12,
+ .u-xl-14-24 {
+ width: 58.3333%;
+ *width: 58.3023%;
+ }
+
+ .u-xl-3-5 {
+ width: 60%;
+ *width: 59.9690%;
+ }
+
+ .u-xl-5-8,
+ .u-xl-15-24 {
+ width: 62.5000%;
+ *width: 62.4690%;
+ }
+
+ .u-xl-2-3,
+ .u-xl-16-24 {
+ width: 66.6667%;
+ *width: 66.6357%;
+ }
+
+ .u-xl-17-24 {
+ width: 70.8333%;
+ *width: 70.8023%;
+ }
+
+ .u-xl-3-4,
+ .u-xl-18-24 {
+ width: 75%;
+ *width: 74.9690%;
+ }
+
+ .u-xl-19-24 {
+ width: 79.1667%;
+ *width: 79.1357%;
+ }
+
+ .u-xl-4-5 {
+ width: 80%;
+ *width: 79.9690%;
+ }
+
+ .u-xl-5-6,
+ .u-xl-20-24 {
+ width: 83.3333%;
+ *width: 83.3023%;
+ }
+
+ .u-xl-7-8,
+ .u-xl-21-24 {
+ width: 87.5000%;
+ *width: 87.4690%;
+ }
+
+ .u-xl-11-12,
+ .u-xl-22-24 {
+ width: 91.6667%;
+ *width: 91.6357%;
+ }
+
+ .u-xl-23-24 {
+ width: 95.8333%;
+ *width: 95.8023%;
+ }
+
+ .u-xl-1,
+ .u-xl-1-1,
+ .u-xl-5-5,
+ .u-xl-24-24 {
+ width: 100%;
+ }
+}
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/pure/main.css b/pkgs/csslib/third_party/pure/main.css
new file mode 100644
index 0000000..ed5f613
--- /dev/null
+++ b/pkgs/csslib/third_party/pure/main.css
@@ -0,0 +1,624 @@
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+*:before,
+*:after {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+html, button, input, select, textarea,
+.pure-g [class *= "pure-u"] {
+ font-family: Helvetica, Arial, sans-serif;
+ letter-spacing: 0.01em;
+}
+
+
+/* --------------------------
+ * Element Styles
+ * --------------------------
+*/
+
+body {
+ min-width: 320px;
+ background-color: #fff;
+ color: #777;
+ line-height: 1.6;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: bold;
+ color: rgb(75, 75, 75);
+}
+h3 {
+ font-size: 1.25em;
+}
+h4 {
+ font-size: 1.125em;
+}
+
+a {
+ color: #3b8bba; /* block-background-text-normal */
+ text-decoration: none;
+}
+
+a:visited {
+ color: #265778; /* block-normal-text-normal */
+}
+
+dt {
+ font-weight: bold;
+}
+dd {
+ margin: 0 0 10px 0;
+}
+
+aside {
+ background: #1f8dd6; /* same color as selected state on site menu */
+ margin: 1em 0;
+ padding: 0.3em 1em;
+ border-radius: 3px;
+ color: #fff;
+}
+ aside a, aside a:visited {
+ color: rgb(169, 226, 255);
+ }
+
+
+/* --------------------------
+ * Layout Styles
+ * --------------------------
+*/
+
+/* Navigation Push Styles */
+#layout {
+ position: relative;
+ padding-left: 0;
+}
+ #layout.active #menu {
+ left: 160px;
+ width: 160px;
+ }
+
+/* Apply the .box class on the immediate parent of any grid element (pure-u-*) to apply some padding. */
+.l-box {
+ padding: 1em;
+}
+
+.l-wrap {
+ margin-left: auto;
+ margin-right: auto;
+}
+.content .l-wrap {
+ margin-left: -1em;
+ margin-right: -1em;
+}
+
+
+/* --------------------------
+ * Header Module Styles
+ * --------------------------
+*/
+
+.header {
+ font-family: "Raleway", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ max-width: 768px;
+ margin: 0 auto;
+ padding: 1em;
+ text-align: center;
+ border-bottom: 1px solid #eee;
+ background: #fff;
+ letter-spacing: 0.05em;
+}
+ .header h1 {
+ font-size: 300%;
+ font-weight: 100;
+ margin: 0;
+ }
+ .header h2 {
+ font-size: 125%;
+ font-weight: 100;
+ line-height: 1.5;
+ margin: 0;
+ color: #666;
+ letter-spacing: -0.02em;
+ }
+
+
+ /* --------------------------
+ * Content Module Styles
+ * --------------------------
+ */
+
+/* The content div is placed as a wrapper around all the docs */
+.content {
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 1em;
+ padding-right: 1em;
+ max-width: 768px;
+}
+
+ .content .content-subhead {
+ margin: 2em 0 1em 0;
+ font-weight: 300;
+ color: #888;
+ position: relative;
+ }
+
+ .content .content-spaced {
+ line-height: 1.8;
+ }
+
+ .content .content-quote {
+ font-family: "Georgia", serif;
+ color: #666;
+ font-style: italic;
+ line-height: 1.8;
+ border-left: 5px solid #ddd;
+ padding-left: 1.5em;
+ }
+
+ .content-link {
+ position: absolute;
+ top: 0;
+ right: 0;
+ display: block;
+ height: 100%;
+ width: 20px;
+ background: transparent url('/img/link-icon.png') no-repeat center center;
+ background-size: 20px 20px;
+ }
+
+ @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
+ .content-link {
+ background-image: url('/img/link-icon@2x.png');
+ }
+ }
+
+
+/* --------------------------
+ * Code Styles
+ * --------------------------
+*/
+
+pre,
+code {
+ font-family: Consolas, Courier, monospace;
+ color: #333;
+ background: rgb(250, 250, 250);
+}
+
+code {
+ padding: 0.2em 0.4em;
+ white-space: nowrap;
+}
+.content p code {
+ font-size: 90%;
+}
+
+.code {
+ margin-left: -1em;
+ margin-right: -1em;
+ border: 1px solid #eee;
+ border-left-width: 0;
+ border-right-width: 0;
+ overflow-x: auto;
+}
+.code pre {
+ margin: 0;
+}
+.code code {
+ font-size: 95%;
+ white-space: pre;
+ word-wrap: normal;
+ padding: 0;
+ background: none;
+}
+.code-wrap code {
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+.example .code {
+ margin-top: 1em;
+}
+
+/* --------------------------
+ * Footer Module Styles
+ * --------------------------
+*/
+
+.footer {
+ font-size: 87.5%;
+ border-top: 1px solid #eee;
+ margin-top: 3.4286em;
+ padding: 1.1429em;
+ background: rgb(250, 250, 250);
+}
+
+.legal {
+ line-height: 1.6;
+ text-align: center;
+ margin: 0 auto;
+}
+
+ .legal-license {
+ margin-top: 0;
+ }
+ .legal-links {
+ list-style: none;
+ padding: 0;
+ margin-bottom: 0;
+ }
+ .legal-copyright {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+
+/* --------------------------
+ * Main Navigation Bar Styles
+ * --------------------------
+*/
+
+/* Add transition to containers so they can push in and out */
+#layout,
+#menu,
+.menu-link {
+ -webkit-transition: all 0.2s ease-out;
+ -moz-transition: all 0.2s ease-out;
+ -ms-transition: all 0.2s ease-out;
+ -o-transition: all 0.2s ease-out;
+ transition: all 0.2s ease-out;
+}
+
+#layout.active .menu-link {
+ left: 160px;
+}
+
+#menu {
+ margin-left: -160px; /* "#menu" width */
+ width: 160px;
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ z-index: 1000; /* so the menu or its navicon stays above all content */
+ background: #191818;
+ overflow-y: auto;
+}
+ #menu a {
+ color: #999;
+ border: none;
+ white-space: normal;
+ padding: 0.625em 1em;
+ }
+
+ #menu .pure-menu-open {
+ background: transparent;
+ border: 0;
+ }
+
+ #menu .pure-menu ul {
+ border: none;
+ background: transparent;
+ display: block;
+ }
+
+ #menu .pure-menu ul,
+ #menu .pure-menu .menu-item-divided {
+ border-top: 1px solid #333;
+ }
+
+ #menu .pure-menu-list li .pure-menu-link:hover,
+ #menu .pure-menu-list li .pure-menu-link:focus {
+ background: #333;
+ }
+
+ .menu-link {
+ position: fixed;
+ display: block; /* show this only on small screens */
+ top: 0;
+ left: 0; /* "#menu width" */
+ background: #000;
+ background: rgba(0,0,0,0.7);
+ font-size: 11px; /* change this value to increase/decrease button size */
+ z-index: 10;
+ width: 4em;
+ height: 4em;
+ padding: 1em;
+ }
+
+ .menu-link:hover,
+ .menu-link:focus {
+ background: #000;
+ }
+
+ .menu-link span {
+ position: relative;
+ display: block;
+ margin-top: 0.9em;
+ }
+
+ .menu-link span,
+ .menu-link span:before,
+ .menu-link span:after {
+ background-color: #fff;
+ pointer-events: none;
+ width: 100%;
+ height: .2em;
+ -webkit-transition: all 0.4s;
+ -moz-transition: all 0.4s;
+ -ms-transition: all 0.4s;
+ -o-transition: all 0.4s;
+ transition: all 0.4s;
+ }
+
+ .menu-link span:before,
+ .menu-link span:after {
+ position: absolute;
+ top: -.55em;
+ content: " ";
+ }
+
+ .menu-link span:after {
+ top: .55em;
+ }
+
+ .menu-link.active span {
+ background: transparent;
+ }
+
+ .menu-link.active span:before {
+ -webkit-transform: rotate(45deg) translate(.5em, .4em);
+ -moz-transform: rotate(45deg) translate(.5em, .4em);
+ -ms-transform: rotate(45deg) translate(.5em, .4em);
+ -o-transform: rotate(45deg) translate(.5em, .4em);
+ transform: rotate(45deg) translate(.5em, .4em);
+ }
+
+ .menu-link.active span:after {
+ -webkit-transform: rotate(-45deg) translate(.4em, -.3em);
+ -moz-transform: rotate(-45deg) translate(.4em, -.3em);
+ -ms-transform: rotate(-45deg) translate(.4em, -.3em);
+ -o-transform: rotate(-45deg) translate(.4em, -.3em);
+ transform: rotate(-45deg) translate(.4em, -.3em);
+ }
+
+ #menu .pure-menu-heading {
+ font-size: 125%;
+ font-weight: 300;
+ letter-spacing: 0.1em;
+ color: #fff;
+ margin-top: 0;
+ padding: 0.5em 0.8em;
+ text-transform: uppercase;
+ }
+ #menu .pure-menu-heading:hover,
+ #menu .pure-menu-heading:focus {
+ color: #999;
+ }
+
+ #menu .pure-menu-item .active {
+ background: #1f8dd6;
+ color: #fff;
+ }
+
+ #menu li.pure-menu-item .active:hover,
+ #menu li.pure-menu-item .active:focus {
+ background: #1f8dd6;
+ }
+
+
+/* ---------------------
+ * Smaller Module Styles
+ * ---------------------
+*/
+
+.pure-img-responsive {
+ max-width: 100%;
+ height: auto;
+}
+
+.pure-paginator .pure-button {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+.pure-button {
+ font-family: inherit;
+}
+a.pure-button-primary {
+ color: white;
+}
+
+
+/* green call to action button class */
+.notice {
+ background-color: #61B842;
+ color: white;
+}
+
+.muted {
+ color: #ccc;
+}
+
+
+
+/* -------------
+ * Table Styles
+ * -------------
+*/
+.pure-table th,
+.pure-table td {
+ padding: 0.5em 1em;
+}
+
+.table-responsive {
+ margin-left: -1em;
+ margin-right: -1em;
+ overflow-x: auto;
+ margin-bottom: 1em;
+}
+.table-responsive table {
+ width: 100%;
+ min-width: 35.5em;
+ border-left-width: 0;
+ border-right-width: 0;
+}
+
+.table-responsive .mq-table {
+ width: 100%;
+ min-width: 44em;
+}
+.mq-table th.highlight {
+ background-color: rgb(255, 234, 133);
+}
+.mq-table td.highlight {
+ background-color: rgb(255, 250, 229);
+}
+.mq-table th.highlight code,
+.mq-table td.highlight code {
+ background: rgb(255, 255, 243);
+}
+.mq-table-mq code {
+ font-size: 0.875em;
+}
+
+/* ----------------------------
+ * Example for full-width Grids
+ * ----------------------------
+*/
+
+.grids-example {
+ background: rgb(250, 250, 250);
+ margin: 2em auto;
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+}
+
+/* --------------------------
+ * State Rules
+ * --------------------------
+*/
+
+
+.is-code-full {
+ text-align: center;
+}
+.is-code-full .code {
+ margin-left: auto;
+ margin-right: auto;
+}
+.is-code-full code {
+ display: inline-block;
+ max-width: 768px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+
+/* --------------------------
+ * Responsive Styles
+ * --------------------------
+*/
+
+@media screen and (min-width: 35.5em) {
+
+ .legal-license {
+ text-align: left;
+ margin: 0;
+ }
+ .legal-copyright,
+ .legal-links,
+ .legal-links li {
+ text-align: right;
+ margin: 0;
+ }
+
+}
+
+@media screen and (min-width: 48em) {
+
+ .l-wrap,
+ .l-wrap .content {
+ padding-left: 1em;
+ padding-right: 1em;
+ }
+ .content .l-wrap {
+ margin-left: -2em;
+ margin-right: -2em;
+ }
+
+ .header,
+ .content {
+ padding-left: 2em;
+ padding-right: 2em;
+ }
+
+ .header h1 {
+ font-size: 320%;
+ }
+ .header h2 {
+ font-size: 128%;
+ }
+
+ .content p {
+ font-size: 1.125em;
+ }
+
+ .code {
+ margin-left: auto;
+ margin-right: auto;
+ border-left-width: 1px;
+ border-right-width: 1px;
+ }
+
+ .table-responsive {
+ margin-left: auto;
+ margin-right: auto;
+ }
+ .table-responsive table {
+ border-left-width: 1px;
+ border-right-width: 1px;
+ }
+
+}
+
+@media (max-width: 58em) {
+ /* Only apply this when the window is smaller. Otherwise, the following
+ case results in extra padding on the left:
+ * Make the window small. (Rotate to portrait on a mobile.)
+ * Tap the menu to trigger the active state.
+ * Make the window large again. (Rotate to landscape on mobile.)
+ */
+ #layout.active {
+ position: relative;
+ left: 160px;
+ }
+}
+
+@media (min-width: 58em) {
+
+ #layout {
+ padding-left: 160px; /* left col width "#menu" */
+ left: 0;
+ }
+ #menu {
+ left: 160px;
+ }
+ .menu-link {
+ position: fixed;
+ left: 160px;
+ display: none;
+ }
+ #layout.active .menu-link {
+ left: 160px;
+ }
+
+}
diff --git a/pkgs/csslib/third_party/skeleton/LICENSE.md b/pkgs/csslib/third_party/skeleton/LICENSE.md
new file mode 100644
index 0000000..32a62b3
--- /dev/null
+++ b/pkgs/csslib/third_party/skeleton/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2014 Dave Gamache
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/skeleton/README.me b/pkgs/csslib/third_party/skeleton/README.me
new file mode 100644
index 0000000..aa8c136
--- /dev/null
+++ b/pkgs/csslib/third_party/skeleton/README.me
@@ -0,0 +1,4 @@
+This folder contains sample css files from the open-source project
+https://github.com/dhg/Skeleton.
+
+This code was included under the terms in the `LICENSE.md file.
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/skeleton/normalize.css b/pkgs/csslib/third_party/skeleton/normalize.css
new file mode 100644
index 0000000..81c6f31
--- /dev/null
+++ b/pkgs/csslib/third_party/skeleton/normalize.css
@@ -0,0 +1,427 @@
+/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -ms-text-size-adjust: 100%; /* 2 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio,
+canvas,
+progress,
+video {
+ display: inline-block; /* 1 */
+ vertical-align: baseline; /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+ display: none;
+}
+
+/* Links
+ ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * Improve readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9/10.
+ */
+
+img {
+ border: 0;
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+
+figure {
+ margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+ overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ * Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ color: inherit; /* 1 */
+ font: inherit; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+
+button {
+ overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+ line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* 2 */
+ box-sizing: content-box;
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+ font-weight: bold;
+}
+
+/* Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+td,
+th {
+ padding: 0;
+}
\ No newline at end of file
diff --git a/pkgs/csslib/third_party/skeleton/skeleton.css b/pkgs/csslib/third_party/skeleton/skeleton.css
new file mode 100644
index 0000000..f28bf6c
--- /dev/null
+++ b/pkgs/csslib/third_party/skeleton/skeleton.css
@@ -0,0 +1,418 @@
+/*
+* Skeleton V2.0.4
+* Copyright 2014, Dave Gamache
+* www.getskeleton.com
+* Free to use under the MIT license.
+* http://www.opensource.org/licenses/mit-license.php
+* 12/29/2014
+*/
+
+
+/* Table of contents
+––––––––––––––––––––––––––––––––––––––––––––––––––
+- Grid
+- Base Styles
+- Typography
+- Links
+- Buttons
+- Forms
+- Lists
+- Code
+- Tables
+- Spacing
+- Utilities
+- Clearing
+- Media Queries
+*/
+
+
+/* Grid
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.container {
+ position: relative;
+ width: 100%;
+ max-width: 960px;
+ margin: 0 auto;
+ padding: 0 20px;
+ box-sizing: border-box; }
+.column,
+.columns {
+ width: 100%;
+ float: left;
+ box-sizing: border-box; }
+
+/* For devices larger than 400px */
+@media (min-width: 400px) {
+ .container {
+ width: 85%;
+ padding: 0; }
+}
+
+/* For devices larger than 550px */
+@media (min-width: 550px) {
+ .container {
+ width: 80%; }
+ .column,
+ .columns {
+ margin-left: 4%; }
+ .column:first-child,
+ .columns:first-child {
+ margin-left: 0; }
+
+ .one.column,
+ .one.columns { width: 4.66666666667%; }
+ .two.columns { width: 13.3333333333%; }
+ .three.columns { width: 22%; }
+ .four.columns { width: 30.6666666667%; }
+ .five.columns { width: 39.3333333333%; }
+ .six.columns { width: 48%; }
+ .seven.columns { width: 56.6666666667%; }
+ .eight.columns { width: 65.3333333333%; }
+ .nine.columns { width: 74.0%; }
+ .ten.columns { width: 82.6666666667%; }
+ .eleven.columns { width: 91.3333333333%; }
+ .twelve.columns { width: 100%; margin-left: 0; }
+
+ .one-third.column { width: 30.6666666667%; }
+ .two-thirds.column { width: 65.3333333333%; }
+
+ .one-half.column { width: 48%; }
+
+ /* Offsets */
+ .offset-by-one.column,
+ .offset-by-one.columns { margin-left: 8.66666666667%; }
+ .offset-by-two.column,
+ .offset-by-two.columns { margin-left: 17.3333333333%; }
+ .offset-by-three.column,
+ .offset-by-three.columns { margin-left: 26%; }
+ .offset-by-four.column,
+ .offset-by-four.columns { margin-left: 34.6666666667%; }
+ .offset-by-five.column,
+ .offset-by-five.columns { margin-left: 43.3333333333%; }
+ .offset-by-six.column,
+ .offset-by-six.columns { margin-left: 52%; }
+ .offset-by-seven.column,
+ .offset-by-seven.columns { margin-left: 60.6666666667%; }
+ .offset-by-eight.column,
+ .offset-by-eight.columns { margin-left: 69.3333333333%; }
+ .offset-by-nine.column,
+ .offset-by-nine.columns { margin-left: 78.0%; }
+ .offset-by-ten.column,
+ .offset-by-ten.columns { margin-left: 86.6666666667%; }
+ .offset-by-eleven.column,
+ .offset-by-eleven.columns { margin-left: 95.3333333333%; }
+
+ .offset-by-one-third.column,
+ .offset-by-one-third.columns { margin-left: 34.6666666667%; }
+ .offset-by-two-thirds.column,
+ .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
+
+ .offset-by-one-half.column,
+ .offset-by-one-half.columns { margin-left: 52%; }
+
+}
+
+
+/* Base Styles
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+/* NOTE
+html is set to 62.5% so that all the REM measurements throughout Skeleton
+are based on 10px sizing. So basically 1.5rem = 15px :) */
+html {
+ font-size: 62.5%; }
+body {
+ font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
+ line-height: 1.6;
+ font-weight: 400;
+ font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ color: #222; }
+
+
+/* Typography
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+h1, h2, h3, h4, h5, h6 {
+ margin-top: 0;
+ margin-bottom: 2rem;
+ font-weight: 300; }
+h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
+h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
+h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
+h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
+h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
+h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
+
+/* Larger than phablet */
+@media (min-width: 550px) {
+ h1 { font-size: 5.0rem; }
+ h2 { font-size: 4.2rem; }
+ h3 { font-size: 3.6rem; }
+ h4 { font-size: 3.0rem; }
+ h5 { font-size: 2.4rem; }
+ h6 { font-size: 1.5rem; }
+}
+
+p {
+ margin-top: 0; }
+
+
+/* Links
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+a {
+ color: #1EAEDB; }
+a:hover {
+ color: #0FA0CE; }
+
+
+/* Buttons
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+ display: inline-block;
+ height: 38px;
+ padding: 0 30px;
+ color: #555;
+ text-align: center;
+ font-size: 11px;
+ font-weight: 600;
+ line-height: 38px;
+ letter-spacing: .1rem;
+ text-transform: uppercase;
+ text-decoration: none;
+ white-space: nowrap;
+ background-color: transparent;
+ border-radius: 4px;
+ border: 1px solid #bbb;
+ cursor: pointer;
+ box-sizing: border-box; }
+.button:hover,
+button:hover,
+input[type="submit"]:hover,
+input[type="reset"]:hover,
+input[type="button"]:hover,
+.button:focus,
+button:focus,
+input[type="submit"]:focus,
+input[type="reset"]:focus,
+input[type="button"]:focus {
+ color: #333;
+ border-color: #888;
+ outline: 0; }
+.button.button-primary,
+button.button-primary,
+input[type="submit"].button-primary,
+input[type="reset"].button-primary,
+input[type="button"].button-primary {
+ color: #FFF;
+ background-color: #33C3F0;
+ border-color: #33C3F0; }
+.button.button-primary:hover,
+button.button-primary:hover,
+input[type="submit"].button-primary:hover,
+input[type="reset"].button-primary:hover,
+input[type="button"].button-primary:hover,
+.button.button-primary:focus,
+button.button-primary:focus,
+input[type="submit"].button-primary:focus,
+input[type="reset"].button-primary:focus,
+input[type="button"].button-primary:focus {
+ color: #FFF;
+ background-color: #1EAEDB;
+ border-color: #1EAEDB; }
+
+
+/* Forms
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="text"],
+input[type="tel"],
+input[type="url"],
+input[type="password"],
+textarea,
+select {
+ height: 38px;
+ padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
+ background-color: #fff;
+ border: 1px solid #D1D1D1;
+ border-radius: 4px;
+ box-shadow: none;
+ box-sizing: border-box; }
+/* Removes awkward default styles on some inputs for iOS */
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="text"],
+input[type="tel"],
+input[type="url"],
+input[type="password"],
+textarea {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none; }
+textarea {
+ min-height: 65px;
+ padding-top: 6px;
+ padding-bottom: 6px; }
+input[type="email"]:focus,
+input[type="number"]:focus,
+input[type="search"]:focus,
+input[type="text"]:focus,
+input[type="tel"]:focus,
+input[type="url"]:focus,
+input[type="password"]:focus,
+textarea:focus,
+select:focus {
+ border: 1px solid #33C3F0;
+ outline: 0; }
+label,
+legend {
+ display: block;
+ margin-bottom: .5rem;
+ font-weight: 600; }
+fieldset {
+ padding: 0;
+ border-width: 0; }
+input[type="checkbox"],
+input[type="radio"] {
+ display: inline; }
+label > .label-body {
+ display: inline-block;
+ margin-left: .5rem;
+ font-weight: normal; }
+
+
+/* Lists
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+ul {
+ list-style: circle inside; }
+ol {
+ list-style: decimal inside; }
+ol, ul {
+ padding-left: 0;
+ margin-top: 0; }
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ margin: 1.5rem 0 1.5rem 3rem;
+ font-size: 90%; }
+li {
+ margin-bottom: 1rem; }
+
+
+/* Code
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+code {
+ padding: .2rem .5rem;
+ margin: 0 .2rem;
+ font-size: 90%;
+ white-space: nowrap;
+ background: #F1F1F1;
+ border: 1px solid #E1E1E1;
+ border-radius: 4px; }
+pre > code {
+ display: block;
+ padding: 1rem 1.5rem;
+ white-space: pre; }
+
+
+/* Tables
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+th,
+td {
+ padding: 12px 15px;
+ text-align: left;
+ border-bottom: 1px solid #E1E1E1; }
+th:first-child,
+td:first-child {
+ padding-left: 0; }
+th:last-child,
+td:last-child {
+ padding-right: 0; }
+
+
+/* Spacing
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+button,
+.button {
+ margin-bottom: 1rem; }
+input,
+textarea,
+select,
+fieldset {
+ margin-bottom: 1.5rem; }
+pre,
+blockquote,
+dl,
+figure,
+table,
+p,
+ul,
+ol,
+form {
+ margin-bottom: 2.5rem; }
+
+
+/* Utilities
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.u-full-width {
+ width: 100%;
+ box-sizing: border-box; }
+.u-max-full-width {
+ max-width: 100%;
+ box-sizing: border-box; }
+.u-pull-right {
+ float: right; }
+.u-pull-left {
+ float: left; }
+
+
+/* Misc
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+hr {
+ margin-top: 3rem;
+ margin-bottom: 3.5rem;
+ border-width: 0;
+ border-top: 1px solid #E1E1E1; }
+
+
+/* Clearing
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+
+/* Self Clearing Goodness */
+.container:after,
+.row:after,
+.u-cf {
+ content: "";
+ display: table;
+ clear: both; }
+
+
+/* Media Queries
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+/*
+Note: The best way to structure the use of media queries is to create the queries
+near the relevant code. For example, if you wanted to change the styles for buttons
+on small devices, paste the mobile query code up in the buttons section and style it
+there.
+*/
+
+
+/* Larger than mobile */
+@media (min-width: 400px) {}
+
+/* Larger than phablet (also point when grid becomes active) */
+@media (min-width: 550px) {}
+
+/* Larger than tablet */
+@media (min-width: 750px) {}
+
+/* Larger than desktop */
+@media (min-width: 1000px) {}
+
+/* Larger than Desktop HD */
+@media (min-width: 1200px) {}
diff --git a/pkgs/extension_discovery/.gitignore b/pkgs/extension_discovery/.gitignore
new file mode 100644
index 0000000..ddfdca1
--- /dev/null
+++ b/pkgs/extension_discovery/.gitignore
@@ -0,0 +1,5 @@
+.dart_tool/
+.packages
+.pub/
+build/
+pubspec.lock
diff --git a/pkgs/extension_discovery/CHANGELOG.md b/pkgs/extension_discovery/CHANGELOG.md
new file mode 100644
index 0000000..f35371e
--- /dev/null
+++ b/pkgs/extension_discovery/CHANGELOG.md
@@ -0,0 +1,24 @@
+## 2.1.0
+
+- Require Dart 3.4.
+- Update to the latest version of `package:dart_flutter_team_lints`.
+- Add `findPackageConfig()` allowing for automatic discovery of the
+ packageConfig based on a package directory.
+
+## 2.0.0
+
+- Use `extension/<package>/config.yaml` instead of
+ `extension/<package>/config.json` for better consistency with other tooling.
+- Require that the top-level value in `extension/<package>/config.yaml` is
+ always a `Map`, and that the structure can be converted to a JSON equivalent
+ structure.
+
+## 1.0.1
+
+- Support optional `packageUri`.
+- Improve error messaging for `package_config.json` parsing.
+- Update the package description.
+
+## 1.0.0
+
+- Initial version.
diff --git a/pkgs/extension_discovery/LICENSE b/pkgs/extension_discovery/LICENSE
new file mode 100644
index 0000000..ac90031
--- /dev/null
+++ b/pkgs/extension_discovery/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2023, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/pkgs/extension_discovery/README.md b/pkgs/extension_discovery/README.md
new file mode 100644
index 0000000..0214ae9
--- /dev/null
+++ b/pkgs/extension_discovery/README.md
@@ -0,0 +1,237 @@
+[](https://github.com/dart-lang/tools/actions/workflows/extension_discovery.yml)
+[](https://pub.dev/packages/extension_discovery)
+[](https://pub.dev/packages/extension_discovery/publisher)
+
+A convention and utilities for package extension discovery.
+
+## What's this?
+
+A convention to allow other packages to provide extensions for your package
+(or tool). Including logic for finding extensions that honor this convention.
+
+The convention implemented in this package is that if `foo` provides an
+extension for `<targetPackage>`.
+Then `foo` must contain a config file `extension/<targetPackage>/config.yaml`.
+This file indicates that `foo` provides an extension for `<targetPackage>`.
+
+If `<targetPackage>` accepts extensions from other packages it must:
+ * Find extensions using `findExtensions('<targetPackage>')` from this package.
+ * Document how extensions are implemented:
+ * What should the contents of the `extension/<targetPackage>/config.yaml` file be?
+ * Should packages providing extensions have a dependency constraint on `<targetPackage>`?
+ * What libraries/assets should packages that provide extensions include?
+ * Should packages providing extensions specify a [topic in `pubspec.yaml`][1]
+ for easy discovery on pub.dev.
+
+The `findExtensions(targetPackage, packageConfig: ...)` function will:
+ * Load `.dart_tool/package_config.json` and find all packages that contain a
+ valid YAML file: `extension/<targetPackage>/config.yaml`.
+ * Provide the package name, location and contents of the `config.yaml` file,
+ for all detected extensions (aimed at `targetPackage`).
+ * Cache the results for fast loading, comparing modification timestamps to
+ ensure consistent results.
+
+It is the responsibility package that can be extended to validate extensions,
+decide when they should be enabled, and documenting how such extensions are
+created.
+
+
+## Packages that extend tools
+
+You can also use this package (and associated convention), if you are developing
+a tool that can be extended by packages. In this case, you would call
+`findExtensions(<my_tool_package_name>, packageConfig: ...)` where
+`packageConfig` points to the `.dart_tool/package_config.json` in the workspace
+the tool is operating on.
+
+If you tool is not distributed through pub.dev, you might consider publishing
+a placeholder package in order to reserve a unique name (and avoid collisions).
+Using a placeholder package to reserve a unique is also recommended for tools
+that wish to cache files in `.dart_tool/<my_tool_package_name>/`.
+See [package layout documentation][2] for details.
+
+
+## Example: Hello World
+
+Imagine that we have a `hello_world` package that defines a single method
+`sayHello(String language)`, along the lines of:
+
+```dart
+void sayHello(String language) {
+ if (language == 'danish') {
+ print('Hej verden');
+ } else {
+ print('Hello world!');
+ }
+}
+```
+
+### Enabling packages to extend `hello_world`
+
+If we wanted to allow other packages to provide additional languages by
+extending the `hello_world` package. Then we could do:
+
+```dart
+import 'package:extension_discovery/extension_discovery.dart';
+
+Future<void> sayHello(String language) async {
+ // Find extensions for the "hello_world" package.
+ // WARNING: This only works when running in JIT-mode, if running in AOT-mode
+ // you must supply the `packageConfig` argument, and have a local
+ // `.dart_tool/package_config.json` and `$PUB_CACHE`.
+ // See "Runtime limitations" section further down.
+ final extensions = await findExtensions('hello_world');
+
+ // Search extensions to see if one provides a message for language
+ for (final ext in extensions) {
+ final config = ext.config;
+ if (config is! Map<String, Object?>) {
+ continue; // ignore extensions with invalid configation
+ }
+ if (config['language'] == language) {
+ print(config['message']);
+ return; // Don't print more messages!
+ }
+ }
+
+ if (language == 'danish') {
+ print('Hej verden');
+ } else {
+ print('Hello world!');
+ }
+}
+```
+
+The `findExtensions` function will search other packages for
+`extension/hello_world/config.yaml`, and provide the contents of this file as
+well as provide the location of the extending packages.
+As authors of the `hello_world` package we should also document how other
+packages can extend `hello_world`. This is typically done by adding a segment
+to the `README.md`.
+
+
+### Extending `hello_world` from another package
+
+If in another package `hello_world_german` we wanted to extend `hello_world`
+and provide a translation for German, then we would create a
+`hello_world_german` package containing an
+**`extension/hello_world/config.yaml`**:
+
+```yaml
+language: german
+message: "Hello Welt!"
+```
+
+Obviously, this is a contrived example. The authors of the `hello_world` package
+could specify all sorts configuration options that extension authors can
+specify in `extension/hello_world/config.yaml`.
+
+The authors of `hello_world` could also specify that extensions must provide
+certain assets in `extension/hello_world/` or that they must provide certain
+Dart libraries implementing a specified interface somewhere in `lib/src/...`.
+
+It is up to the authors of `hello_world` to specify what extension authors must
+provide. The `extension_discovery` package only provides a utility for finding
+extensions.
+
+
+### Using `hello_world` and `hello_world_german`
+
+If writing `my_hello_world_app` I can now take advantage of `hello_world` and
+`hello_world_german`. Simply write a `pubspec.yaml` as follows:
+
+```yaml
+# pubspec.yaml
+name: my_hello_world_app
+dependencies:
+ hello_world: ^1.0.0
+ hello_world_german: ^1.0.0
+environment:
+ sdk: ^3.4.0
+```
+
+Then I can write a `bin/hello.dart` as follows:
+
+```dart
+// bin/hello.dart
+import 'package:hello_world/hello_world.dart';
+
+Future<void> main() async {
+ await sayHello('german');
+}
+```
+
+
+## What can an extension provide?
+
+As far as the `extension_discovery` package is concerned an extension can
+provide anything. Naturally, it is the authors of the extendable package that
+decides what extensions can be provide.
+
+In the example above it is the authors of the `hello_world` package that decides
+what extension packages can provide. For this reason it is important that the
+authors of `hello_world` very explicitly document how an extension is written.
+
+Obviously, authors of `hello_world` should document what should be specified in
+`extension/hello_world/config.yaml`. They could also specify that other files
+should be provided in `extension/hello_world/`, or that certain Dart libraries
+should be provided in `lib/src/hello_world/...` or something like that.
+
+When authors of `hello_world` consumes the extensions discovered through
+`findExtensions` they would naturally also be wise to validate that the
+extension provides the required configuration and files.
+
+
+## Compatibility considerations
+
+When writing an extension it is strongly encouraged to have a dependency
+constraint on the package being extended. This ensures that the extending
+package will be incompatibility with new major versions of the extended package.
+
+In the example above, it is strongly encouraged for `hello_world_german` to
+have a dependency constraint `hello_world: ^1.0.0`. Even if `hello_world_german`
+doesn't import libraries from `package:hello_world`.
+
+Because the next major version of `hello_world` (version `2.0.0`) might change
+what is required of an extension. Thus, it's fair to assume that
+`hello_world_german` might not be compatible with newer versions of
+`hello_world`. Hence, adding a dependency constraint `hello_world: ^1.0.0` saves
+users from resolving dependencies that aren't compatible.
+
+Naturally, after a new major version of `hello_world` is published a new
+version of `hello_world_german` can then also be published, addressing any
+breaking changes and bumping the dependency constraint.
+
+**Tip:** Authors of packages that can be extended might want to force extension
+authors take dependency on their package, to ensure that they have the ability
+to do breaking changes in the future.
+
+
+## Runtime limitations
+
+The `findExtensions` function only works when running in JIT-mode, otherwise the
+`packageConfig` parameter must be used to provide the location of
+`.dart_tool/package_config.json`. Obviously, the `package_config.json` must be
+present, as must the pub-cache locations referenced here.
+
+Hence, `findExtensions` effectively **only works from project workspace!**.
+
+You can't use `findExtensions` in a compiled Flutter application or an
+AOT-compiled executable distributed to end-users. Because in these environments
+you don't have a `package_config.json` nor do you have a pub-cache. You don't
+even have access to your own source files.
+
+If your deployment target a compiled Flutter application or AOT-compiled
+executable, then you will have to create some code/asset-generation.
+You code/asset-generation scripts can use `findExtensions` to find extensions,
+and then use the assets or Dart libraries from here to generate assets or code
+that is embedded in the final Flutter application (or AOT-compiled executable).
+
+This makes `findExtensions` immediately useful, if you are writing development
+tools that users will install into their project workspace. But if you're
+writing a package for use in deployed applications, you'll likely need to figure
+out how to embed the extensions, `findExtensions` only helps
+you find the extensions during code-gen.
+
+[1]: https://dart.dev/tools/pub/pubspec#topics
+[2]: https://dart.dev/tools/pub/package-layout#project-specific-caching-for-tools
diff --git a/pkgs/extension_discovery/analysis_options.yaml b/pkgs/extension_discovery/analysis_options.yaml
new file mode 100644
index 0000000..aadd26e
--- /dev/null
+++ b/pkgs/extension_discovery/analysis_options.yaml
@@ -0,0 +1,5 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+linter:
+ rules:
+ - avoid_catches_without_on_clauses
diff --git a/pkgs/extension_discovery/example/hello_world/README.md b/pkgs/extension_discovery/example/hello_world/README.md
new file mode 100644
index 0000000..39ec96d
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world/README.md
@@ -0,0 +1,26 @@
+# `hello_world` package
+
+Example of a package that can be extended, and uses `extension_discovery` to
+find extensions.
+
+## Limitations
+
+The `sayHello` function in this package can only be used in a project workspace,
+where dependencies are resolved and you're running in JIT-mode.
+
+The `sayHello` function uses `findExtensions` and, thus, cannot be called in a
+compiled Flutter application or AOT-compiled executable. For this to work, we'd
+need to augment this package with code-generation, such that the code-generation
+uses `findExtensions` and compiles a `sayHello` function into your application.
+
+## Extending the `hello_world` package
+
+Other packages can extend this package by providing an `extension/hello_world/config.json` file the following form:
+
+```js
+// extension/hello_world/config.json
+{
+ "language": "<language>",
+ "message": "<message>"
+}
+```
diff --git a/pkgs/extension_discovery/example/hello_world/lib/hello_world.dart b/pkgs/extension_discovery/example/hello_world/lib/hello_world.dart
new file mode 100644
index 0000000..9e4a848
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world/lib/hello_world.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:extension_discovery/extension_discovery.dart';
+
+Future<void> sayHello(String language) async {
+ // Find extensions for the "hello_world" package.
+ // WARNING: This only works when running in JIT-mode, if running in AOT-mode
+ // you must supply the `packageConfig` argument, and have a local
+ // `.dart_tool/package_config.json` and `$PUB_CACHE`.
+ final extensions = await findExtensions('hello_world');
+
+ // Search extensions to see if one provides a message for language
+ for (final ext in extensions) {
+ final config = ext.config;
+ if (config['language'] == language) {
+ print(config['message']);
+ return; // Don't print more messages!
+ }
+ }
+
+ if (language == 'danish') {
+ print('Hej verden');
+ } else {
+ print('Hello world!');
+ }
+}
diff --git a/pkgs/extension_discovery/example/hello_world/pubspec.yaml b/pkgs/extension_discovery/example/hello_world/pubspec.yaml
new file mode 100644
index 0000000..40c68a3
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world/pubspec.yaml
@@ -0,0 +1,10 @@
+name: hello_world
+version: 1.0.0
+publish_to: none # This is an example, don't publish!
+
+dependencies:
+ extension_discovery: # ^1.0.0
+ path: ../../
+
+environment:
+ sdk: ^3.4.0
diff --git a/pkgs/extension_discovery/example/hello_world_app/README.md b/pkgs/extension_discovery/example/hello_world_app/README.md
new file mode 100644
index 0000000..1d45229
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world_app/README.md
@@ -0,0 +1,8 @@
+# `hello_world_app`
+
+An application that uses the `hello_world` package and has a dependency on
+`hello_world_german` such that when `hello_world` calls `findExtensions` it will
+find the extension in `hello_world_german`.
+
+**Notice**: This application only works when running from a project workspace.
+See "runtime limitation" in the README for `package:extension_discovery`.
diff --git a/pkgs/extension_discovery/example/hello_world_app/bin/hello.dart b/pkgs/extension_discovery/example/hello_world_app/bin/hello.dart
new file mode 100644
index 0000000..a4715ef
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world_app/bin/hello.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:hello_world/hello_world.dart';
+
+Future<void> main() async {
+ await sayHello('german');
+}
diff --git a/pkgs/extension_discovery/example/hello_world_app/pubspec.yaml b/pkgs/extension_discovery/example/hello_world_app/pubspec.yaml
new file mode 100644
index 0000000..30338d2
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world_app/pubspec.yaml
@@ -0,0 +1,11 @@
+name: my_hello_world_app
+publish_to: none # applications should never be published!
+
+dependencies:
+ hello_world: # ^1.0.0
+ path: ../hello_world
+ hello_world_german: # ^1.0.0
+ path: ../hello_world_german
+
+environment:
+ sdk: ^3.4.0
diff --git a/pkgs/extension_discovery/example/hello_world_german/README.md b/pkgs/extension_discovery/example/hello_world_german/README.md
new file mode 100644
index 0000000..4a58703
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world_german/README.md
@@ -0,0 +1,4 @@
+# `hello_world_german`
+
+Example of a simple package that provides an extension for the `hello_world`
+package.
diff --git a/pkgs/extension_discovery/example/hello_world_german/extension/hello_world/config.yaml b/pkgs/extension_discovery/example/hello_world_german/extension/hello_world/config.yaml
new file mode 100644
index 0000000..ef57087
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world_german/extension/hello_world/config.yaml
@@ -0,0 +1,9 @@
+# This config file let's `package:extension_discovery` find out that
+# `package:hello_world_german` has an extension for `package:hello_world`.
+#
+# The root object must be a map, and the data structure must be representable
+# as JSON, but those are the only constraints. Beyond that it is the
+# responsibility of `package:hello_world` to define what this file should
+# contain, to validate the contents, and do something useful with it.
+language: german
+message: "Hello Welt!"
diff --git a/pkgs/extension_discovery/example/hello_world_german/pubspec.yaml b/pkgs/extension_discovery/example/hello_world_german/pubspec.yaml
new file mode 100644
index 0000000..39e80be
--- /dev/null
+++ b/pkgs/extension_discovery/example/hello_world_german/pubspec.yaml
@@ -0,0 +1,15 @@
+name: hello_world_german
+version: 1.0.0
+publish_to: none # This is an example, don't publish!
+
+dependencies:
+ # We keep a dependency on package `hello_world` because this package provides
+ # an extension for this package. Hence, a newer major version of hello_world
+ # might be incompatible with the extension options we've provided in
+ # extension/hello_world/config.json
+ # It is `hello_world` that specifies what is required in `config.json`.
+ hello_world: # ^1.0.0
+ path: ../hello_world
+
+environment:
+ sdk: ^3.4.0
diff --git a/pkgs/extension_discovery/lib/extension_discovery.dart b/pkgs/extension_discovery/lib/extension_discovery.dart
new file mode 100644
index 0000000..662435a
--- /dev/null
+++ b/pkgs/extension_discovery/lib/extension_discovery.dart
@@ -0,0 +1,285 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Find extensions with [findExtensions].
+library;
+
+import 'dart:collection' show UnmodifiableListView;
+import 'dart:io' show File, IOException;
+import 'dart:isolate' show Isolate;
+
+import 'src/io.dart';
+import 'src/package_config.dart';
+import 'src/registry.dart';
+import 'src/yaml_config_format.dart';
+
+export 'src/package_config.dart' show PackageConfigException, findPackageConfig;
+
+/// Information about an extension for target package.
+final class Extension {
+ /// Name of the package providing an extension.
+ final String package;
+
+ /// Absolute path to the package root.
+ ///
+ /// This folder usually contains a `lib/` folder and a `pubspec.yaml`
+ /// (assuming dependencies are fetched using the pub package manager).
+ ///
+ /// **Examples:** If `foo` is installed in pub-cache this would be:
+ /// * `/home/my_user/.pub-cache/hosted/pub.dev/foo-1.0.0/`
+ ///
+ /// See `rootUri` in the [specification for `package_config.json`][1],
+ /// for details.
+ ///
+ /// [1]: https://github.com/dart-lang/language/blob/main/accepted/2.8/language-versioning/package-config-file-v2.md
+ final Uri rootUri;
+
+ /// Path to the library import path relative to [rootUri].
+ ///
+ /// In Dart code the `package:<package>/<path>` will be resolved as
+ /// `<rootUri>/<packageUri>/<path>`.
+ ///
+ /// If dependencies are installed using `dart pub`, then this is
+ /// **always** `lib/`.
+ ///
+ /// See `packageUri` in the [specification for `package_config.json`][1],
+ /// for details.
+ ///
+ /// [1]: https://github.com/dart-lang/language/blob/main/accepted/2.8/language-versioning/package-config-file-v2.md
+ final Uri packageUri;
+
+ /// Contents of `extension/<targetPackage>/config.yaml` parsed as YAML and
+ /// converted to JSON compatible types.
+ ///
+ /// If parsing YAML from this file failed, then no [Extension] entry
+ /// will exist.
+ ///
+ /// This field is always a structure consisting of the following types:
+ /// * `null`,
+ /// * [bool] (`true` or `false`),
+ /// * [String],
+ /// * [num] ([int] or [double]),
+ /// * `List<Object?>`, and,
+ /// * `Map<String, Object?>`.
+ final Map<String, Object?> config;
+
+ Extension._({
+ required this.package,
+ required this.rootUri,
+ required this.packageUri,
+ required this.config,
+ });
+}
+
+/// Find extensions for [targetPackage] provided by packages in
+/// `.dart_tool/package_config.json`.
+///
+/// ## Locating `.dart_tool/package_config.json`
+///
+/// This method requires the location of the [packageConfig], unless the current
+/// isolate has been setup for package resolution.
+/// Notably, Dart programs compiled for AOT cannot find their own
+/// `package_config.json`.
+///
+/// If operating on a project that isn't the current project, for example, if
+/// you are developing a tool that users are globally activating and then
+/// running against their own projects, and you wish to detect extensions within
+/// their projects, then you must specify the path the
+/// `.dart_tool/package_config.json` for the users project as [packageConfig].
+///
+/// The [packageConfig] parameter must reference a file, absolute or
+/// relative-path, may use the `file://` scheme. This method throws, if
+/// [packageConfig] is not a valid [Uri] for a file-path.
+///
+/// ## Detection of extensions
+///
+/// An extension for [targetPackage] is detected in `package:foo` if `foo`
+/// contains `extension/<targetPackage>/config.yaml`, and the contents of this
+/// file is valid YAML, that can be represented as JSON.
+///
+/// ### Caching results
+///
+/// When [useCache] is `true` then the detected extensions will be cached
+/// in `.dart_tool/extension_discovery/<targetPackage>.json`.
+/// This function will compare modification timestamps of
+/// `.dart_tool/package_config.json` with the cache file, before reusing cached
+/// results.
+/// This function will also treat relative path-dependencies as mutable
+/// packages, and check such packages for extensions every time [findExtensions]
+/// is called. Notably, it'll compare the modification time of the
+/// `extension/<targetPackage>/config.yaml` file, to ensure that it's older than
+/// the extension cache file. Otherwise, it'll reload the extension
+/// configuration.
+///
+/// ## Exceptions
+///
+/// This method will throw [PackageConfigException], if the
+/// `.dart_tool/package_config.json` file specified in [packageConfig] could not
+/// be loaded or is invalid. This usually happens if dependencies are not
+/// resolved, and users can probably address it by running `dart pub get`.
+///
+/// But, **do consider catch** [PackageConfigException] and handling the failure
+/// to load extensions appropriately.
+///
+/// This method will throw an [Error] if [packageConfig] is not specified, and
+/// the current isolate isn't configured for package resolution.
+Future<List<Extension>> findExtensions(
+ String targetPackage, {
+ bool useCache = true,
+ Uri? packageConfig,
+}) async {
+ packageConfig ??= await Isolate.packageConfig;
+ if (packageConfig == null) {
+ throw UnsupportedError(
+ 'packageConfigUri must be provided, if not running in JIT mode',
+ );
+ }
+ if ((packageConfig.hasScheme && !packageConfig.isScheme('file')) ||
+ packageConfig.hasEmptyPath ||
+ packageConfig.hasFragment ||
+ packageConfig.hasPort ||
+ packageConfig.hasQuery) {
+ throw ArgumentError.value(
+ packageConfig,
+ 'packageConfig',
+ 'must be a file:// URI',
+ );
+ }
+ // Always normalize to an absolute URI
+ final packageConfigUri = File.fromUri(packageConfig).absolute.uri;
+
+ return await _findExtensions(
+ targetPackage: targetPackage,
+ useCache: useCache,
+ packageConfigUri: packageConfigUri,
+ );
+}
+
+/// Find extensions with normalized arguments.
+Future<List<Extension>> _findExtensions({
+ required String targetPackage,
+ required bool useCache,
+ required Uri packageConfigUri,
+}) async {
+ final packageConfigFile = File.fromUri(packageConfigUri);
+ final registryFile = File.fromUri(packageConfigFile.parent.uri.resolve(
+ 'extension_discovery/$targetPackage.json',
+ ));
+
+ Registry? registry;
+ final registryStat = registryFile.statSync();
+ if (registryStat.isFileOrLink && useCache) {
+ final packageConfigStat = packageConfigFile.statSync();
+ if (!packageConfigStat.isFileOrLink) {
+ throw packageConfigNotFound(packageConfigUri);
+ }
+ if (packageConfigStat.isPossiblyModifiedAfter(registryStat.modified)) {
+ await registryFile.tryDelete();
+ } else {
+ registry = await loadRegistry(registryFile);
+ }
+ }
+
+ final configFileName = 'extension/$targetPackage/config.yaml';
+ var registryUpdated = false;
+ if (registry != null) {
+ // Update mutable entries in registry
+ for (var i = 0; i < registry.length; i++) {
+ final p = registry[i];
+ if (p.rootUri.hasAbsolutePath) continue;
+
+ final rootUri = packageConfigUri.resolveUri(p.rootUri);
+ final configFile = File.fromUri(rootUri.resolve(configFileName));
+ final configStat = configFile.statSync();
+ if (configStat.isFileOrLink) {
+ if (configStat.isPossiblyModifiedAfter(registryStat.modified)) {
+ try {
+ registryUpdated = true;
+ registry[i] = (
+ package: p.package,
+ rootUri: p.rootUri,
+ packageUri: p.packageUri,
+ config: parseYamlFromConfigFile(await configFile.readAsString()),
+ );
+ continue;
+ } on FormatException {
+ // pass
+ } on IOException {
+ // pass
+ }
+ registryUpdated = true;
+ registry[i] = (
+ package: p.package,
+ rootUri: p.rootUri,
+ packageUri: p.packageUri,
+ config: null,
+ );
+ }
+ } else {
+ // If there is no file present, but registry says there is then we need
+ // to update the registry.
+ if (p.config != null) {
+ registryUpdated = true;
+ registry[i] = (
+ package: p.package,
+ rootUri: p.rootUri,
+ packageUri: p.packageUri,
+ config: null,
+ );
+ }
+ }
+ }
+ } else {
+ // Load packages from package_config.json
+ final packages = await loadPackageConfig(packageConfigFile);
+ registryUpdated = true;
+ registry = (await Future.wait(packages.map((p) async {
+ try {
+ final rootUri = packageConfigUri.resolveUri(p.rootUri);
+ final configFile = File.fromUri(rootUri.resolve(configFileName));
+ final configStat = configFile.statSync();
+ if (configStat.isFileOrLink) {
+ return (
+ package: p.name,
+ rootUri: p.rootUri,
+ packageUri: p.packageUri,
+ config: parseYamlFromConfigFile(await configFile.readAsString()),
+ );
+ }
+ } on FormatException {
+ // pass
+ } on IOException {
+ // pass
+ }
+ if (!p.rootUri.hasAbsolutePath) {
+ return (
+ package: p.name,
+ rootUri: p.rootUri,
+ packageUri: p.packageUri,
+ config: null,
+ );
+ }
+ return null;
+ })))
+ .whereType<RegistryEntry>()
+ .toList(growable: false);
+ }
+
+ // Save registry
+ if (registryUpdated && useCache) {
+ await saveRegistry(registryFile, registry);
+ }
+
+ return UnmodifiableListView(
+ registry
+ .where((e) => e.config != null)
+ .map((e) => Extension._(
+ package: e.package,
+ rootUri: packageConfigUri.resolveUri(e.rootUri),
+ packageUri: e.packageUri,
+ config: e.config!,
+ ))
+ .toList(growable: false),
+ );
+}
diff --git a/pkgs/extension_discovery/lib/src/expect_json.dart b/pkgs/extension_discovery/lib/src/expect_json.dart
new file mode 100644
index 0000000..c2784bc
--- /dev/null
+++ b/pkgs/extension_discovery/lib/src/expect_json.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show jsonDecode;
+
+Map<String, Object?> decodeJsonMap(String json) {
+ final root = jsonDecode(json);
+ if (root case Map<String, Object?> v) return v;
+ throw const FormatException('root must be a map');
+}
+
+extension ExpectJson on Map<String, Object?> {
+ bool expectBool(String key) {
+ if (this[key] case bool v) return v;
+ throw FormatException('The value at "$key" must be a bool:\n$toString()');
+ }
+
+ num expectNumber(String key) {
+ if (this[key] case num v) return v;
+ throw FormatException('The value at "$key" must be a number:\n$toString()');
+ }
+
+ String expectString(String key) {
+ if (this[key] case String v) return v;
+ throw FormatException('The value at "$key" must be a string:\n$toString()');
+ }
+
+ Uri expectUri(String key) {
+ try {
+ return Uri.parse(expectString(key));
+ } on FormatException {
+ throw FormatException('The value at "$key" must be a URI:\n$toString()');
+ }
+ }
+
+ Map<String, Object?> expectMap(String key) {
+ if (this[key] case Map<String, Object?> v) return v;
+ throw FormatException('The value at "$key" must be a map:\n$toString()');
+ }
+
+ Map<String, Object?>? optionalMap(String key) {
+ if (containsKey(key)) {
+ return expectMap(key);
+ }
+ return null;
+ }
+
+ Uri? optionalUri(String key) {
+ if (containsKey(key)) {
+ return expectUri(key);
+ }
+ return null;
+ }
+
+ List<Object?> expectList(String key) {
+ if (this[key] case List<Object?> v) return v;
+ throw FormatException('The value at "$key" must be a list:\n$toString()');
+ }
+
+ Iterable<Map<String, Object?>> expectListObjects(String key) sync* {
+ final list = expectList(key);
+ for (final entry in list) {
+ if (entry case Map<String, Object?> v) {
+ yield v;
+ } else {
+ throw FormatException(
+ 'The value at "$key" must be a list of map:\n$toString()',
+ );
+ }
+ }
+ }
+}
diff --git a/pkgs/extension_discovery/lib/src/io.dart b/pkgs/extension_discovery/lib/src/io.dart
new file mode 100644
index 0000000..9343ced
--- /dev/null
+++ b/pkgs/extension_discovery/lib/src/io.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io'
+ show
+ File,
+ FileStat,
+ FileSystemEntityType,
+ FileSystemException,
+ IOException,
+ Platform;
+
+const _maxAttempts = 20;
+
+/// When comparing modification timestamps of files to see if A is newer than B,
+/// such that data cached in A about B does not need to be recomputed, we
+/// required that A is at-least [modificationMaturityDelay] older than B.
+///
+/// This ensures that if `pub get` is racing with cache writing then we won't
+/// rely on the result.
+Duration modificationMaturityDelay = const Duration(seconds: 5);
+
+/// On windows some renaming files/folders recently created can be problematic
+/// as they may be locked by security scanning systems.
+///
+/// This function will retry [fn] a few times with a short delay, if running on
+/// Windows and the error appears to be related to permissions or file locking.
+Future<T> _attempt<T>(FutureOr<T> Function() fn) async {
+ if (!Platform.isWindows) {
+ return await fn();
+ }
+ var attempts = 0;
+ while (true) {
+ try {
+ await fn();
+ } on FileSystemException catch (e) {
+ attempts += 1;
+ if (attempts >= _maxAttempts) rethrow;
+
+ // Cargo culting error codes from:
+ // https://github.com/dart-lang/pub/blob/98565c3e5defcd80c59910795ba3548552102f2c/lib/src/io.dart#L419-L427
+ final code = e.osError?.errorCode;
+ if (code != 5 && code != 32) rethrow;
+
+ // Sleep a bit a try again.
+ await Future<void>.delayed(const Duration(milliseconds: 5));
+ }
+ }
+}
+
+extension FileExt on File {
+ /// Try to delete this file, ignore errors.
+ Future<void> tryDelete() async {
+ try {
+ await delete();
+ } on IOException {
+ // pass
+ }
+ }
+
+ Future<void> reliablyRename(String newPath) =>
+ _attempt(() => rename(newPath));
+}
+
+extension FileStatExt on FileStat {
+ /// Returns `false` if we're pretty certain that the current file was NOT
+ /// modified after [other].
+ ///
+ /// We do this by subtracting 5 seconds from [other], thus, making it more
+ /// likely that the current file was _possibly modified_ after [other].
+ ///
+ /// This, aims to ensure that file where modified within 5 seconds of
+ /// eachother then we don't trust the file modification stamps. This mostly
+ /// makes sense if someone is updating a file while we're writing the registry
+ /// cache file.
+ bool isPossiblyModifiedAfter(DateTime other) =>
+ modified.isAfter(other.subtract(modificationMaturityDelay));
+
+ /// True, if current [FileStat] is possibly a file (link or file)
+ bool get isFileOrLink =>
+ type == FileSystemEntityType.file || type == FileSystemEntityType.link;
+}
diff --git a/pkgs/extension_discovery/lib/src/package_config.dart b/pkgs/extension_discovery/lib/src/package_config.dart
new file mode 100644
index 0000000..f2eaffc
--- /dev/null
+++ b/pkgs/extension_discovery/lib/src/package_config.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' show File, IOException;
+import 'expect_json.dart';
+
+typedef PackageConfigEntry = ({String name, Uri rootUri, Uri packageUri});
+typedef PackageConfig = List<PackageConfigEntry>;
+
+/// Searches in [packageDir] and all directories above for a
+/// `.dart_tool/package_config.json` file. Returns the Uri of that file if
+/// found.
+///
+/// Returns `null` if no file was found.
+Uri? findPackageConfig(Uri packageDir) {
+ if (!packageDir.isScheme('file')) {
+ throw ArgumentError(
+ 'Expected [packageDir] to be a file URI, got $packageDir',
+ );
+ }
+ if (!packageDir.path.endsWith('/')) {
+ packageDir = packageDir.replace(path: '${packageDir.path}/');
+ }
+ while (true) {
+ final packageConfigCandidate =
+ packageDir.resolve('.dart_tool/package_config.json');
+ try {
+ if (File.fromUri(packageConfigCandidate).existsSync()) {
+ return packageConfigCandidate;
+ }
+ } on IOException {
+ return null; // if we get a permission error, etc, we return null
+ }
+ final next = packageDir.resolve('..');
+ if (next == packageDir) return null;
+ packageDir = next;
+ }
+}
+
+/// Load list of packages and associated URIs from the
+/// `.dart_tool/package_config.json` file in [packageConfigFile].
+Future<PackageConfig> loadPackageConfig(
+ File packageConfigFile,
+) async {
+ try {
+ final packageConfig = decodeJsonMap(await packageConfigFile.readAsString());
+ if (packageConfig.expectNumber('configVersion') != 2) {
+ throw const FormatException('"configVersion" must be 2');
+ }
+ return packageConfig.expectListObjects('packages').map((p) {
+ final rootUri = p.expectUri('rootUri').asDirectory();
+ return (
+ name: p.expectString('name'),
+ rootUri: rootUri,
+ packageUri: p.optionalUri('packageUri')?.asDirectory() ?? rootUri,
+ );
+ }).toList();
+ } on IOException catch (e) {
+ if (!packageConfigFile.existsSync()) {
+ throw packageConfigNotFound(packageConfigFile.uri);
+ }
+ throw packageConfigIOException(e);
+ } on FormatException catch (e) {
+ throw packageConfigInvalid(packageConfigFile.uri, e);
+ }
+}
+
+/// Thrown, if the `.dart_tool/package_config.json` cannot be found or parsing
+/// it fails.
+///
+/// This could be because the `package_config.json` file is missing or simply
+/// invalid.
+///
+/// Mostly, this will happen if dependencies are not resolved, the solution is
+/// call `dart pub get`.
+final class PackageConfigException implements Exception {
+ final String message;
+ PackageConfigException._(this.message);
+
+ @override
+ String toString() => message;
+}
+
+PackageConfigException packageConfigNotFound(Uri packageConfigUri) =>
+ PackageConfigException._(
+ 'package_config.json not found at: "$packageConfigUri"',
+ );
+
+PackageConfigException packageConfigInvalid(
+ Uri packageConfigUri, FormatException e) =>
+ PackageConfigException._(
+ 'Invalid package_config.json found at "$packageConfigUri": $e',
+ );
+
+PackageConfigException packageConfigIOException(IOException e) =>
+ PackageConfigException._(
+ 'Failed to read package_config.json: $e',
+ );
+
+extension on Uri {
+ Uri asDirectory() => replace(
+ pathSegments: pathSegments.lastOrNull != ''
+ ? pathSegments.followedBy([''])
+ : pathSegments,
+ );
+}
diff --git a/pkgs/extension_discovery/lib/src/registry.dart b/pkgs/extension_discovery/lib/src/registry.dart
new file mode 100644
index 0000000..60efc75
--- /dev/null
+++ b/pkgs/extension_discovery/lib/src/registry.dart
@@ -0,0 +1,144 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show jsonEncode;
+import 'dart:io' show File, FileSystemEntityType, IOException;
+
+import 'expect_json.dart';
+import 'io.dart';
+
+// TODO: Convert the 'rootUri' reference below to a doc comment reference once
+// https://github.com/dart-lang/linter/issues/4645 is addressed.
+
+/// Entry in the `.dart_tool/extension_discovery/<package>.json` file.
+///
+/// If the `rootUri` is not an absolute path, then we will assume that the
+/// package is mutable (either it's the root package or a path dependency).
+/// If there is no extension config file for a mutable package, then we will
+/// still store a [RegistryEntry] with `config = null`. Because everytime we
+/// load the registry, we still need to check if a configuration file has been
+/// added to the mutable package.
+typedef RegistryEntry = ({
+ String package,
+ Uri rootUri,
+ Uri packageUri,
+ Map<String, Object?>? config,
+});
+
+typedef Registry = List<RegistryEntry>;
+
+Future<Registry?> loadRegistry(File registryFile) async {
+ try {
+ final registryJson = decodeJsonMap(await registryFile.readAsString());
+ if (registryJson.expectNumber('version') != 2) {
+ throw const FormatException('"version" must be 2');
+ }
+ return registryJson
+ .expectListObjects('entries')
+ .map((e) => (
+ package: e.expectString('package'),
+ rootUri: e.expectUri('rootUri'),
+ packageUri: e.expectUri('packageUri'),
+ config: e.optionalMap('config'),
+ ))
+ .toList(growable: false);
+ } on IOException {
+ return null; // pass
+ } on FormatException {
+ await registryFile.tryDelete();
+ return null;
+ }
+}
+
+Future<void> saveRegistry(
+ File registryFile,
+ Registry registry,
+) async {
+ try {
+ if (!registryFile.parent.existsSync()) {
+ await registryFile.parent.create();
+ }
+ final tmpFile = File('${registryFile.path}.tmp');
+ final tmpFileStat = tmpFile.statSync();
+ if (tmpFileStat.type != FileSystemEntityType.notFound) {
+ final tmpAge = DateTime.now().difference(tmpFileStat.modified);
+ if (tmpAge.inSeconds < 5) {
+ // Don't try to write registry, if there is an abandoned temporary file
+ // no older than 5 seconds. Otherwise, we could have race conditions!
+ // Note: That saving the registry is a performance improvement, not a
+ // strict necessity!
+ return;
+ } else {
+ await tmpFile.delete();
+ }
+ }
+
+ await tmpFile.writeAsString(jsonEncode({
+ 'version': 2,
+ 'entries': registry
+ .map((e) => {
+ 'package': e.package,
+ 'rootUri': e.rootUri.toString(),
+ 'packageUri': e.packageUri.toString(),
+ if (e.config != null) 'config': e.config,
+ })
+ .toList(),
+ }));
+ await tmpFile.reliablyRename(registryFile.path);
+ await _ensureReadme(
+ File.fromUri(registryFile.parent.uri.resolve('README.md')),
+ );
+ } on IOException {
+ // pass
+ }
+}
+
+Future<void> _ensureReadme(File readmeFile) async {
+ try {
+ final stat = readmeFile.statSync();
+ if (stat.type != FileSystemEntityType.notFound) {
+ final age = DateTime.now().difference(stat.modified);
+ if (age.inDays < 5) {
+ return; // don't update README.md, if it's less than 5 days old
+ }
+ }
+ await readmeFile.writeAsString(_readmeContents);
+ } on IOException {
+ // pass
+ }
+}
+
+const _readmeContents = '''
+Extension Discovery Cache
+=========================
+
+This folder is used by `package:extension_discovery` to cache lists of
+packages that contains extensions for other packages.
+
+DO NOT USE THIS FOLDER
+----------------------
+
+ * Do not read (or rely) the contents of this folder.
+ * Do write to this folder.
+
+If you're interested in the lists of extensions stored in this folder use the
+API offered by package `extension_discovery` to get this information.
+
+If this package doesn't work for your use-case, then don't try to read the
+contents of this folder. It may change, and will not remain stable.
+
+Use package `extension_discovery`
+---------------------------------
+
+If you want to access information from this folder.
+
+Feel free to delete this folder
+-------------------------------
+
+Files in this folder act as a cache, and the cache is discarded if the files
+are older than the modification time of `.dart_tool/package_config.json`.
+
+Hence, it should never be necessary to clear this cache manually, if you find a
+need to do please file a bug.
+''';
diff --git a/pkgs/extension_discovery/lib/src/yaml_config_format.dart b/pkgs/extension_discovery/lib/src/yaml_config_format.dart
new file mode 100644
index 0000000..a28b31b
--- /dev/null
+++ b/pkgs/extension_discovery/lib/src/yaml_config_format.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utilities for loading and validating YAML from a config file.
+///
+/// When writing YAML config files it's often preferable to force a few
+/// constraints on the YAML files. Specifically:
+/// * Root value must be a map.
+/// * No anchors / aliases, this can't be represented in JSON and
+/// can be used to created cycles, which might crash someone trying to
+/// serialize the data as JSON.
+/// * Maps can only have string keys.
+///
+/// Basically, only allow value that can't be represented in JSON.
+///
+/// This library aims to provide a [parseYamlFromConfigFile] that throws
+/// a [FormatException] when parsing YAML files that doesn't satisfy this
+/// constraint.
+library;
+
+import 'package:yaml/yaml.dart'
+ show YamlList, YamlMap, YamlNode, YamlScalar, loadYamlNode;
+
+/// Parse YAML from a config file.
+///
+/// This will validate that:
+/// * Maps only have string keys.
+/// * Anchor and aliases are not used (to avoid cycles).
+/// * Values can be represented as JSON.
+/// * Root node is a map.
+///
+/// Throw will throw [FormatException], if the [yamlString] does not satisfy
+/// constraints above.
+///
+/// Returns a structure consisting of the following types:
+/// * `null`,
+/// * [bool] (`true` or `false`),
+/// * [String],
+/// * [num] ([int] or [double]),
+/// * `List<Object?>`, and,
+/// * `Map<String, Object?>`.
+Map<String, Object?> parseYamlFromConfigFile(String yamlString) {
+ final visited = <YamlNode>{};
+ Object? toPlainType(YamlNode n) {
+ if (!visited.add(n)) {
+ throw const FormatException(
+ 'Anchors/aliases are not supported in YAML config files',
+ );
+ }
+ if (n is YamlScalar) {
+ return switch (n.value) {
+ null => null,
+ String s => s,
+ num n => n,
+ bool b => b,
+ _ => throw const FormatException(
+ 'Only null, string, number, bool, map and lists are supported '
+ 'in YAML config files',
+ ),
+ };
+ }
+ if (n is YamlList) {
+ return n.nodes.map(toPlainType).toList();
+ }
+ if (n is YamlMap) {
+ return n.nodes.map((key, value) {
+ final k = toPlainType(key as YamlNode);
+ if (k is! String) {
+ throw const FormatException(
+ 'Only string keys are allowed in YAML config files',
+ );
+ }
+ return MapEntry(k, toPlainType(value));
+ });
+ }
+ throw UnsupportedError('Unknown YamlNode: $n');
+ }
+
+ final value = toPlainType(loadYamlNode(yamlString));
+ if (value is! Map<String, Object?>) {
+ throw const FormatException('The root of a YAML config file must be a map');
+ }
+ return value;
+}
diff --git a/pkgs/extension_discovery/pubspec.yaml b/pkgs/extension_discovery/pubspec.yaml
new file mode 100644
index 0000000..095be3f
--- /dev/null
+++ b/pkgs/extension_discovery/pubspec.yaml
@@ -0,0 +1,18 @@
+name: extension_discovery
+description: >-
+ A convention and utilities for package extension discovery.
+version: 2.1.0
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/extension_discovery
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aextension_discovery
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ yaml: ^3.0.0
+
+dev_dependencies:
+ collection: ^1.18.0
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.21.0
+ test_descriptor: ^2.0.1
diff --git a/pkgs/extension_discovery/test/find_extensions_test.dart b/pkgs/extension_discovery/test/find_extensions_test.dart
new file mode 100644
index 0000000..33e8bf7
--- /dev/null
+++ b/pkgs/extension_discovery/test/find_extensions_test.dart
@@ -0,0 +1,350 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:isolate' show Isolate;
+
+import 'package:extension_discovery/extension_discovery.dart';
+import 'package:extension_discovery/src/io.dart';
+import 'package:test/test.dart';
+
+import 'test_descriptor.dart' as d;
+
+void main() {
+ test('findExtensions', () async {
+ // Override the maturity delay for reliable testing of caching logic.
+ modificationMaturityDelay = const Duration(milliseconds: 500);
+
+ final pkgLibDir = await Isolate.resolvePackageUri(
+ Uri.parse('package:extension_discovery/'),
+ );
+ final pkgDir = pkgLibDir!.resolve('..');
+
+ await d.dir('myapp', [
+ d.pubspec({
+ 'name': 'myapp',
+ 'dependencies': {
+ 'extension_discovery': {'path': pkgDir.toFilePath()},
+ },
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // Check that we don't find any extensions
+ expect(
+ await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ ),
+ isEmpty);
+
+ // Check that there is a myapp.json cache file
+ await d
+ .file(
+ 'myapp/.dart_tool/extension_discovery/myapp.json',
+ isNotEmpty,
+ )
+ .validate();
+
+ // ################################## Create foo that provides extension
+ await d.dir('foo', [
+ d.pubspec({
+ 'name': 'foo',
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ // It has a config.yaml for myapp
+ d.dir('extension/myapp', [
+ d.json('config.yaml', {'fromFoo': true}),
+ ]),
+ ]).create();
+
+ // Update the pubspec.yaml with a dependency on foo
+ await d.dir('myapp', [
+ d.pubspec({
+ 'name': 'myapp',
+ 'dependencies': {
+ 'extension_discovery': {'path': pkgDir.toFilePath()},
+ 'foo': {'path': '../foo'},
+ },
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // Check that we do find an extension
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext, isNotEmpty);
+ expect(
+ ext.any(
+ (e) =>
+ e.package == 'foo' &&
+ e.rootUri == d.directoryUri('foo/') &&
+ e.packageUri == Uri.parse('lib/') &&
+ e.config['fromFoo'] == true,
+ ),
+ isTrue,
+ );
+ }
+
+ // ################################## Modify the config
+ await d.json('foo/extension/myapp/config.yaml', {'fromFoo': 42}).create();
+
+ // Check that we do find an extension
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext, isNotEmpty);
+ expect(
+ ext.any(
+ (e) =>
+ e.package == 'foo' &&
+ e.rootUri == d.directoryUri('foo/') &&
+ e.packageUri == Uri.parse('lib/') &&
+ e.config['fromFoo'] == 42,
+ ),
+ isTrue,
+ );
+ }
+
+ // ################################## Make config invalid
+ await d.file('foo/extension/myapp/config.yaml', 'invalid YAML').create();
+
+ // Check that we do not find extensions
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext, isEmpty);
+ }
+
+ // ################################## Make config valid again
+ await d.json('foo/extension/myapp/config.yaml', {'fromFoo': true}).create();
+
+ // Check that we do find extensions
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext, isNotEmpty);
+ }
+
+ // ################################## Remove config file
+ await d.file('foo/extension/myapp/config.yaml').io.delete();
+ // Check that we do not find extensions
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext, isEmpty);
+ }
+
+ // ################################## Make config valid again
+ await d.json('foo/extension/myapp/config.yaml', {'fromFoo': true}).create();
+
+ // Check that we do find extensions
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext, isNotEmpty);
+ }
+
+ // ################################## Create bar as absolute path-dep
+ await d.dir('bar', [
+ d.pubspec({
+ 'name': 'bar',
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ // It has a config.yaml for myapp
+ d.dir('extension/myapp', [
+ d.json('config.yaml', {'fromFoo': false}),
+ ]),
+ ]).create();
+
+ // Update the pubspec.yaml with a dependency on foo
+ await d.dir('myapp', [
+ d.pubspec({
+ 'name': 'myapp',
+ 'dependencies': {
+ 'extension_discovery': {'path': pkgDir.toFilePath()},
+ 'foo': {'path': '../foo'},
+ 'bar': {'path': d.path('bar')},
+ },
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ // We won't find bar without running `dart pub get`
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext.any((e) => e.package == 'bar'), isFalse);
+ }
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // Check that we do find both extensions
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext, isNotEmpty);
+ expect(
+ ext.any(
+ (e) =>
+ e.package == 'foo' &&
+ e.rootUri == d.directoryUri('foo/') &&
+ e.packageUri == Uri.parse('lib/') &&
+ e.config['fromFoo'] == true,
+ ),
+ isTrue,
+ );
+ expect(
+ ext.any(
+ (e) =>
+ e.package == 'bar' &&
+ e.rootUri == d.directoryUri('bar/') &&
+ e.packageUri == Uri.parse('lib/') &&
+ e.config['fromFoo'] == false,
+ ),
+ isTrue,
+ );
+ }
+
+ // ################################## Changes to bar are not detected
+
+ // Ensure that we wait long enough for the cache to be trusted,
+ // this delay is to make sure that the logic we have handling races isn't
+ // triggered. Think of it as waiting...
+ // If the modification time of package_config.json and the cache is no more
+ // than [modificationMaturityDelay] time apart, we'll ignore the cache.
+ // Under the assumption that there was a tiny risk of a race condition.
+ await Future<void>.delayed(modificationMaturityDelay * 2);
+ // Ensure that we have a cache value!
+ await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+
+ // Delete config from package that has an absolute path, hence, a package
+ // we assume to be immutable.
+ await d.file('bar/extension/myapp/config.yaml').io.delete();
+
+ // Check that we do find both extensions
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext.any((e) => e.package == 'foo'), isTrue);
+ // This is the wrong result, but it is expected. Essentially, if we expect
+ // that if you have packages in package_config.json using an absolute path
+ // then these won't be modified. If you do modify the
+ // extension/<targetPackage>/config.yaml
+ // file, then the cache will give the wrong result. The workaround is to
+ // touch `package_config.json`, or run `dart pub get` (essentially).
+ expect(ext.any((e) => e.package == 'bar'), isTrue);
+ }
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // We won't find bar after `dart pub get`, because we removed the config
+ {
+ final ext = await findExtensions(
+ 'myapp',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext.any((e) => e.package == 'foo'), isTrue);
+ expect(ext.any((e) => e.package == 'bar'), isFalse);
+ }
+
+ // ################################## Sanity check bar and foo
+ expect(
+ await findExtensions(
+ 'foo',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ ),
+ isEmpty,
+ );
+ expect(
+ await findExtensions(
+ 'bar',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ ),
+ isEmpty,
+ );
+
+ // ################################## What if foo has extensions for bar
+ await d.dir('foo/extension/bar', [
+ d.json('config.yaml', {'fromFoo': true}),
+ ]).create();
+
+ {
+ final ext = await findExtensions(
+ 'bar',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext.any((e) => e.package == 'foo'), isTrue);
+ expect(ext.any((e) => e.package == 'bar'), isFalse);
+ expect(ext.any((e) => e.package == 'myapp'), isFalse);
+ }
+
+ // ################################## myapp could also extend bar
+ await d.dir('myapp/extension/bar', [
+ d.json('config.yaml', {'fromFoo': false}),
+ ]).create();
+
+ {
+ final ext = await findExtensions(
+ 'bar',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext.any((e) => e.package == 'foo'), isTrue);
+ expect(ext.any((e) => e.package == 'bar'), isFalse);
+ expect(ext.any((e) => e.package == 'myapp'), isTrue);
+ }
+
+ // ################################## config could also be written in YAML
+ await d.dir('myapp/extension/bar', [
+ d.file('config.yaml', '''
+writtenAsYaml: true
+'''),
+ ]).create();
+
+ {
+ final ext = await findExtensions(
+ 'bar',
+ packageConfig: d.fileUri('myapp/.dart_tool/package_config.json'),
+ );
+ expect(ext.any((e) => e.package == 'foo'), isTrue);
+ expect(ext.any((e) => e.package == 'bar'), isFalse);
+ expect(ext.any((e) => e.package == 'myapp'), isTrue);
+ expect(
+ ext.any(
+ (e) => e.package == 'myapp' && e.config['writtenAsYaml'] == true,
+ ),
+ isTrue,
+ );
+ }
+ });
+}
diff --git a/pkgs/extension_discovery/test/integration_test.dart b/pkgs/extension_discovery/test/integration_test.dart
new file mode 100644
index 0000000..ec52265
--- /dev/null
+++ b/pkgs/extension_discovery/test/integration_test.dart
@@ -0,0 +1,134 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show jsonDecode;
+import 'dart:isolate' show Isolate;
+
+import 'package:test/test.dart';
+
+import 'test_descriptor.dart' as d;
+
+typedef Ext = ({
+ String package,
+ String rootUri,
+ String packageUri,
+ dynamic config
+});
+
+void main() {
+ test('findExtensions', () async {
+ final pkgLibDir = await Isolate.resolvePackageUri(
+ Uri.parse('package:extension_discovery/'),
+ );
+ final pkgDir = pkgLibDir!.resolve('..');
+
+ await d.dir('myapp', [
+ d.pubspec({
+ 'name': 'myapp',
+ 'dependencies': {
+ 'extension_discovery': {'path': pkgDir.toFilePath()},
+ },
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ d.dir('bin', [
+ d.file('find_extensions.dart', '''
+import 'dart:convert' show JsonEncoder;
+import 'package:extension_discovery/extension_discovery.dart';
+
+Future<void> main(List<String> args) async {
+ final extensions = await findExtensions(args.first);
+ print(JsonEncoder.withIndent(' ').convert([
+ for (final e in extensions)
+ {
+ 'package': e.package,
+ 'rootUri': e.rootUri.toString(),
+ 'packageUri': e.packageUri.toString(),
+ 'config': e.config,
+ },
+ ]));
+}
+ '''),
+ ])
+ ]).create();
+
+ Future<List<Ext>> findExtensionsInSandbox(String target) async {
+ final out = await d.dart(
+ d.path('myapp/bin/find_extensions.dart'),
+ target,
+ );
+ return (jsonDecode(out) as List<Object?>)
+ .cast<Map>()
+ .map((e) => (
+ package: e['package'] as String,
+ rootUri: e['rootUri'] as String,
+ packageUri: e['packageUri'] as String,
+ config: e['config'],
+ ))
+ .toList();
+ }
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // Check that we don't find any extensions
+ expect(await findExtensionsInSandbox('myapp'), isEmpty);
+
+ // Check that there is a myapp.json cache file
+ await d
+ .file(
+ 'myapp/.dart_tool/extension_discovery/myapp.json',
+ isNotEmpty,
+ )
+ .validate();
+
+ // Check that there is README.md
+ await d
+ .file(
+ 'myapp/.dart_tool/extension_discovery/README.md',
+ isNotEmpty,
+ )
+ .validate();
+
+ // Create a foo package
+ await d.dir('foo', [
+ d.pubspec({
+ 'name': 'foo',
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ // It has a config.yaml for myapp
+ d.dir('extension/myapp', [
+ d.json('config.yaml', {'fromFoo': true}),
+ ]),
+ ]).create();
+
+ // Update the pubspec.yaml with a dependency on foo
+ await d.dir('myapp', [
+ d.pubspec({
+ 'name': 'myapp',
+ 'dependencies': {
+ 'extension_discovery': {'path': pkgDir.toFilePath()},
+ 'foo': {'path': '../foo'},
+ },
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // Check that we do find an extension
+ final ext = await findExtensionsInSandbox('myapp');
+ expect(ext, isNotEmpty);
+ expect(
+ ext.any(
+ (e) =>
+ e.package == 'foo' &&
+ e.rootUri == d.directoryUri('foo/').toString() &&
+ e.packageUri == Uri.parse('lib/').toString() &&
+ (e.config as Map)['fromFoo'] == true,
+ ),
+ isTrue,
+ );
+ });
+}
diff --git a/pkgs/extension_discovery/test/package_config_test.dart b/pkgs/extension_discovery/test/package_config_test.dart
new file mode 100644
index 0000000..83c6c4d
--- /dev/null
+++ b/pkgs/extension_discovery/test/package_config_test.dart
@@ -0,0 +1,192 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show jsonDecode, jsonEncode;
+
+import 'package:extension_discovery/src/package_config.dart';
+import 'package:test/test.dart';
+
+import 'test_descriptor.dart' as d;
+
+void main() {
+ test('loadPackageConfig', () async {
+ await d.dir('myapp', [
+ d.pubspec({
+ 'name': 'myapp',
+ 'dependencies': {},
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ final packageConfigFile = d.file('myapp/.dart_tool/package_config.json').io;
+
+ // Loading before `dart pub get` throws PackageConfigException
+ expect(
+ loadPackageConfig(packageConfigFile),
+ throwsA(isA<PackageConfigException>()),
+ );
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // Parse package_config
+ {
+ final packages = await loadPackageConfig(packageConfigFile);
+ expect(packages, isNotEmpty);
+ expect(packages.any((p) => p.name == 'myapp'), isTrue);
+ expect(packages.any((p) => p.name == 'foo'), isFalse);
+ expect(packages.any((p) => p.name == 'bar'), isFalse);
+ }
+
+ // ################################## Create foo as relative path-dep
+ await d.dir('foo', [
+ d.pubspec({
+ 'name': 'foo',
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ // Update the pubspec.yaml with a dependency on foo
+ await d.dir('myapp', [
+ d.pubspec({
+ 'name': 'myapp',
+ 'dependencies': {
+ 'foo': {'path': '../foo'},
+ },
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // Parse package_config
+ {
+ final packages = await loadPackageConfig(packageConfigFile);
+ expect(packages, isNotEmpty);
+ expect(packages.any((p) => p.name == 'myapp'), isTrue);
+ expect(packages.any((p) => p.name == 'foo'), isTrue);
+ expect(packages.any((p) => p.name == 'bar'), isFalse);
+ }
+
+ // ################################## Create bar as absolute path-dep
+
+ await d.dir('bar', [
+ d.pubspec({
+ 'name': 'bar',
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ // Update the pubspec.yaml with a dependency on foo
+ await d.dir('myapp', [
+ d.pubspec({
+ 'name': 'myapp',
+ 'dependencies': {
+ 'foo': {'path': '../foo'},
+ 'bar': {'path': d.path('bar')},
+ },
+ 'environment': {'sdk': '^3.0.0'},
+ }),
+ ]).create();
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ // Parse package_config
+ {
+ final packages = await loadPackageConfig(packageConfigFile);
+ expect(packages, isNotEmpty);
+ expect(packages.any((p) => p.name == 'myapp'), isTrue);
+ expect(packages.any((p) => p.name == 'foo'), isTrue);
+ expect(packages.any((p) => p.name == 'bar'), isTrue);
+ }
+
+ // ################################## Cannot read version 99
+
+ {
+ final pkgcfg = jsonDecode(packageConfigFile.readAsStringSync()) as Map;
+ pkgcfg['configVersion'] = 99;
+ packageConfigFile.writeAsStringSync(jsonEncode(pkgcfg));
+ }
+
+ // Loading before `dart pub get` throws PackageConfigException
+ expect(
+ loadPackageConfig(packageConfigFile),
+ throwsA(isA<PackageConfigException>()),
+ );
+
+ // ################################## packageUri is optional
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ {
+ final pkgcfg = jsonDecode(packageConfigFile.readAsStringSync()) as Map;
+ for (final p in pkgcfg['packages'] as List) {
+ (p as Map).remove('packageUri');
+ }
+ packageConfigFile.writeAsStringSync(jsonEncode(pkgcfg));
+ }
+
+ // Parse package_config
+ {
+ final packages = await loadPackageConfig(packageConfigFile);
+ expect(packages, isNotEmpty);
+ expect(packages.any((p) => p.name == 'myapp'), isTrue);
+ expect(packages.any((p) => p.name == 'foo'), isTrue);
+ expect(packages.any((p) => p.name == 'bar'), isTrue);
+ expect(packages.every((p) => p.rootUri == p.packageUri), isTrue);
+ }
+
+ // ################################## packageUri is optional
+
+ // Get dependencies
+ await d.dartPubGet(d.path('myapp'));
+
+ {
+ final pkgcfg = jsonDecode(packageConfigFile.readAsStringSync()) as Map;
+ for (final p in pkgcfg['packages'] as List) {
+ (p as Map).remove('rootUri');
+ }
+ packageConfigFile.writeAsStringSync(jsonEncode(pkgcfg));
+ }
+
+ // Loading before `dart pub get` throws PackageConfigException
+ expect(
+ loadPackageConfig(packageConfigFile),
+ throwsA(isA<PackageConfigException>()),
+ );
+ });
+
+ test('`findPackageConfig()`', () async {
+ await d.dir('workspace', [
+ d.dir('.dart_tool', [
+ d.file('package_config.json'),
+ ]),
+ d.dir('myapp', [])
+ ]).create();
+
+ expect(
+ findPackageConfig(d.fileUri('workspace')),
+ d.fileUri('workspace/.dart_tool/package_config.json'),
+ );
+ expect(
+ findPackageConfig(d.fileUri('workspace/')),
+ d.fileUri('workspace/.dart_tool/package_config.json'),
+ );
+ expect(
+ findPackageConfig(d.fileUri('workspace/myapp')),
+ d.fileUri('workspace/.dart_tool/package_config.json'),
+ );
+ expect(
+ findPackageConfig(d.fileUri('.')),
+ isNull,
+ );
+ expect(
+ findPackageConfig(d.fileUri('foo')),
+ isNull,
+ );
+ });
+}
diff --git a/pkgs/extension_discovery/test/test_descriptor.dart b/pkgs/extension_discovery/test/test_descriptor.dart
new file mode 100644
index 0000000..0bd4a63
--- /dev/null
+++ b/pkgs/extension_discovery/test/test_descriptor.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show JsonEncoder;
+import 'dart:io' show Platform, Process;
+
+import 'package:test/test.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
+export 'package:test_descriptor/test_descriptor.dart';
+
+d.FileDescriptor json(String fileName, Object? json) =>
+ d.file(fileName, const JsonEncoder.withIndent(' ').convert(json));
+
+d.FileDescriptor pubspec(Map<String, Object?> pubspec) =>
+ json('pubspec.yaml', pubspec);
+
+Uri fileUri(String path) => Uri.file(d.path(path));
+Uri directoryUri(String path) => Uri.directory(d.path(path));
+
+Future<String> dart([
+ String? arg1,
+ String? arg2,
+ String? arg3,
+ String? arg4,
+ String? arg5,
+ String? arg6,
+ String? arg7,
+ String? arg8,
+]) async {
+ final arguments = [
+ if (arg1 != null) arg1,
+ if (arg2 != null) arg2,
+ if (arg3 != null) arg3,
+ if (arg4 != null) arg4,
+ if (arg5 != null) arg5,
+ if (arg6 != null) arg6,
+ if (arg7 != null) arg7,
+ if (arg8 != null) arg8,
+ ];
+ final result = await Process.run(
+ Platform.executable,
+ arguments,
+ workingDirectory: d.sandbox,
+ );
+ if (result.exitCode != 0) {
+ print(result.stderr);
+ print(result.stdout);
+ }
+ expect(result.exitCode, 0,
+ reason: 'failed executing "dart ${arguments.join(' ')}"');
+ return result.stdout as String;
+}
+
+Future<String> dartPubGet(String folder) async =>
+ await dart('pub', 'get', '-C', folder);
diff --git a/pkgs/extension_discovery/test/yaml_config_format_test.dart b/pkgs/extension_discovery/test/yaml_config_format_test.dart
new file mode 100644
index 0000000..0e3f568
--- /dev/null
+++ b/pkgs/extension_discovery/test/yaml_config_format_test.dart
@@ -0,0 +1,149 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:collection/collection.dart' show DeepCollectionEquality;
+
+import 'package:extension_discovery/src/yaml_config_format.dart';
+import 'package:test/test.dart';
+
+void _testInvalid(String name, String yaml, {String match = ''}) {
+ test(name, () {
+ expect(
+ () => parseYamlFromConfigFile(yaml),
+ throwsA(isFormatException.having(
+ (e) => e.message,
+ 'message',
+ contains(match),
+ )),
+ );
+ });
+}
+
+void _testValid(String name, String yaml) {
+ test(name, () {
+ parseYamlFromConfigFile(yaml);
+ });
+}
+
+void main() {
+ group('parseYamlFromConfigFile', () {
+ group('root must be a map', () {
+ _testInvalid('empty string', '', match: 'map');
+ _testInvalid('null', 'null', match: 'map');
+ _testInvalid('list', '[]', match: 'map');
+ _testInvalid('number (1)', '42', match: 'map');
+ _testInvalid('number (2)', '42.2', match: 'map');
+ _testInvalid('bool (1)', 'true', match: 'map');
+ _testInvalid('bool (2)', 'false', match: 'map');
+ _testInvalid('string', '"hello world"', match: 'map');
+ });
+
+ _testInvalid('must not have alias', match: 'alias', '''
+ keyA: &myref
+ - value 1
+ - value 2
+ KeyB: *myref
+ ''');
+
+ // it works without aliases
+ _testValid('listed inside a map is fine', '''
+ keyA:
+ - value 1
+ - value 2
+ KeyB:
+ - value 1
+ - value 2
+ ''');
+
+ _testValid('comments are cool', '''
+ keyA:
+ - value 1 # this is fine
+ - value 2
+ ''');
+
+ _testInvalid(
+ 'Top-level map with integer keys is not allowed', match: 'key', '''
+ 42: "value" # this is NOT fine
+ 43: true
+ ''');
+
+ _testValid('Map with quoted integer keys is fine', '''
+ "42": "value" # this is fine
+ '43': true
+ ''');
+
+ _testInvalid('Map with integer keys is not allowed', match: 'key', '''
+ keyA:
+ - value 1 # this is fine
+ - value 2
+ KeyB:
+ 42: value 3 # this is NOT fine
+ ''');
+
+ _testInvalid('Map with list keys is not allowed', match: 'key', '''
+ keyA:
+ - [1, 2, 3] # this is fine, crazy but fine!
+ keyB:
+ [1, 2, 3]: value 3 # this is NOT fine
+ ''');
+
+ _testInvalid('Map with boolean keys is not allowed (1)', match: 'key', '''
+ keyA: true
+ keyB:
+ true: value 3 # this is NOT fine
+ ''');
+
+ _testInvalid('Map with boolean keys is not allowed (2)', match: 'key', '''
+ keyA: true
+ keyB:
+ false: value 3 # this is NOT fine
+ ''');
+
+ _testInvalid('Map with null keys is not allowed', match: 'key', '''
+ keyA: null # fine
+ keyB:
+ null: value 3 # this is NOT fine
+ ''');
+
+ _testValid('complex structures is fine', '''
+ keyA: |
+ multi-line
+ string
+ keyB: 42 # number
+ keyC: 42.2 # double
+ keyD: [1, 2]
+ keyE:
+ - 1
+ - 2
+ keyF:
+ k: "v"
+ ''');
+
+ test('complex structures matches the same JSON', () {
+ final yaml = '''
+ keyA: "hello"
+ keyB: 42 # number
+ keyC: 42.2 # double
+ keyD: [1, 2]
+ keyE:
+ - 1
+ - 2
+ keyF:
+ k: "v"
+ ''';
+ final data = parseYamlFromConfigFile(yaml);
+ expect(
+ const DeepCollectionEquality().equals(data, {
+ 'keyA': 'hello',
+ 'keyB': 42,
+ 'keyC': 42.2,
+ 'keyD': [1, 2],
+ 'keyE': [1, 2],
+ 'keyF': {'k': 'v'},
+ }),
+ isTrue,
+ );
+ });
+ });
+}
diff --git a/pkgs/file/.gitignore b/pkgs/file/.gitignore
new file mode 100644
index 0000000..ddfdca1
--- /dev/null
+++ b/pkgs/file/.gitignore
@@ -0,0 +1,5 @@
+.dart_tool/
+.packages
+.pub/
+build/
+pubspec.lock
diff --git a/pkgs/file/CHANGELOG.md b/pkgs/file/CHANGELOG.md
new file mode 100644
index 0000000..50c96c4
--- /dev/null
+++ b/pkgs/file/CHANGELOG.md
@@ -0,0 +1,242 @@
+## 7.0.1
+
+* Update the pubspec repository field to reflect the new package repository.
+
+## 7.0.0
+
+* Dart 3 fixes for class modifiers.
+* Require Dart 3.0.
+* `MemoryFileSystem` now treats empty paths as non-existent.
+* Fix `FileSystem.isLink`/`FileSystem.isLinkSync` to not follow symbolic links.
+* Make the return type of `MemoryFile.openRead` and `_ChrootFile.openRead` again
+ match the return type from `dart:io`.
+
+## 6.1.4
+
+* Populate the pubspec `repository` field.
+
+## 6.1.3
+
+* In classes that implement `File` methods `create`, `createSync` now take `bool exclusive = true` parameter. No functional changes.
+
+## 6.1.2
+
+* `MemoryFileSystem` now provides `opHandle`s for exists operations.
+
+## 6.1.1
+
+* `MemoryFile` now provides `opHandle`s for copy and open operations.
+
+## 6.1.0
+
+* Reading invalid UTF8 with the `MemoryFileSystem` now correctly throws a `FileSystemException` instead of a `FormatError`.
+* `MemoryFileSystem` now provides an `opHandle` to inspect read/write operations.
+* `MemoryFileSystem` now creates the temporary directory before returning in `createTemp`/`createTempSync`.
+
+## 6.0.1
+
+* Fix sound type error in memory backend when reading non-existent `MemoryDirectory`.
+
+## 6.0.0
+
+* First stable null safe release.
+
+## 6.0.0-nullsafety.4
+
+* Update upper bound of SDK constraint.
+
+## 6.0.0-nullsafety.3
+
+* Update upper bound of SDK constraint.
+
+## 6.0.0-nullsafety.2
+
+* Make `ForwardingFile.openRead`'s return type again match the return type from
+ `dart:io`.
+* Remove some unnecessary `Uint8List` conversions in `ForwardingFile`.
+
+## 6.0.0-nullsafety.1
+
+* Update to null safety.
+* Remove record/replay functionality.
+* Made `MemoryRandomAccessFile` and `MemoryFile.openWrite` handle the file
+ being removed or renamed while open.
+* Fixed incorrect formatting in `NoMatchingInvocationError.toString()`.
+* Fixed more test flakiness.
+* Enabled more tests.
+* Internal cleanup.
+* Remove implicit dynamic in preparation for null safety.
+* Remove dependency on Intl.
+
+## 5.2.1
+
+* systemTemp directories created by `MemoryFileSystem` will allot names
+ based on the file system instance instead of globally.
+* `MemoryFile.readAsLines()`/`readAsLinesSync()` no longer treat a final newline
+ in the file as the start of a new, empty line.
+* `RecordingFile.readAsLine()`/`readAsLinesSync()` now always record a final
+ newline.
+* `MemoryFile.flush()` now returns `Future<void>` instead of `Future<dynamic>`.
+* Fixed some test flakiness.
+* Enabled more tests.
+* Internal cleanup.
+
+## 5.2.0
+
+* Added a `MemoryRandomAccessFile` class and implemented
+ `MemoryFile.open()`/`openSync()`.
+
+## 5.1.0
+
+* Added a new `MemoryFileSystem` constructor to use a test clock
+
+## 5.0.10
+
+* Added example
+
+## 5.0.9
+
+* Fix lints for project health
+
+## 5.0.8
+
+* Return `Uint8List` rather than `List<int>`.
+
+## 5.0.7
+
+* Dart 2 fixes for `RecordingProxyMixin` and `ReplayProxyMixin`.
+
+## 5.0.6
+
+* Dart 2 fixes for `RecordingFile.open()`
+
+## 5.0.5
+
+* Dart 2 fixes
+
+## 5.0.4
+
+* Update SDK constraint to 2.0.0-dev.67.0, remove workaround in
+ recording_proxy_mixin.dart.
+* Fix usage within Dart 2 runtime mode in Dart 2.0.0-dev.61.0 and later.
+* Relax constraints on `package:test`
+
+## 5.0.3
+
+* Update `package:test` dependency to 1.0
+
+## 5.0.2
+
+* Declare compatibility with Dart 2 stable
+
+## 5.0.1
+
+* Remove upper case constants
+* Update SDK constraint to 2.0.0-dev.54.0.
+
+## 5.0.0
+
+* Moved `testing` library into a dedicated `package:file_testing` so that
+ libraries don't need to take on a transitive dependency on `package:test`
+ in order to use `package:file`.
+
+## 4.0.1
+
+* General library cleanup
+* Add `style` support in `MemoryFileSystem`, so that callers can choose to
+ have a memory file system with windows-like paths. [#68]
+ (https://github.com/google/file.dart/issues/68)
+
+## 4.0.0
+
+* Change method signature for `RecordingRandomAccessFile._close` to return a
+ `Future<void>` instead of `Future<RandomAccessFile>`. This follows a change in
+ dart:io, Dart SDK `2.0.0-dev.40`.
+
+## 3.0.0
+
+* Import `dart:io` unconditionally. More recent Dart SDK revisions allow
+ `dart:io` to be imported in a browser context, though if methods are actually
+ invoked, they will fail. This matches well with `package:file`, where users
+ can use the `memory` library and get in-memory implementations of the
+ `dart:io` interfaces.
+* Bump minimum Dart SDK to `1.24.0`
+
+## 2.3.7
+
+* Fix Dart 2 error.
+
+## 2.3.6
+
+* Relax sdk upper bound constraint to '<2.0.0' to allow 'edge' dart sdk use.
+
+## 2.3.5
+
+* Fix internal use of a cast which fails on Dart 2.0 .
+
+## 2.3.4
+
+* Bumped maximum Dart SDK version to 2.0.0-dev.infinity
+
+## 2.3.3
+
+* Relaxes version requirements on `package:intl`
+
+## 2.3.2
+
+* Fixed `FileSystem.directory(Uri)`, `FileSystem.file(Uri)`, and
+ `FileSystem.link(Uri)` to consult the file system's path context when
+ converting the URI to a file path rather than using `Uri.toFilePath()`.
+
+## 2.3.1
+
+* Fixed `MemoryFileSystem` to make `File.writeAs...()` update the last modified
+ time of the file.
+
+## 2.3.0
+
+* Added the following convenience methods in `Directory`:
+ * `Directory.childDirectory(String basename)`
+ * `Directory.childFile(String basename)`
+ * `Directory.childLink(String basename)`
+
+## 2.2.0
+
+* Added `ErrorCodes` class, which holds errno values.
+
+## 2.1.0
+
+* Add support for new `dart:io` API methods added in Dart SDK 1.23
+
+## 2.0.1
+
+* Minor doc updates
+
+## 2.0.0
+
+* Improved `toString` implementations in file system entity classes
+* Added `ForwardingFileSystem` and associated forwarding classes to the
+ main `file` library
+* Removed `FileSystem.pathSeparator`, and added a more comprehensive
+ `FileSystem.path` property
+* Added `FileSystemEntity.basename` and `FileSystemEntity.dirname`
+* Added the `record_replay` library
+* Added the `testing` library
+
+## 1.0.1
+
+* Added `FileSystem.systemTempDirectory`
+* Added the ability to pass `Uri` and `FileSystemEntity` types to
+ `FileSystem.directory()`, `FileSystem.file()`, and `FileSystem.link()`
+* Added `FileSystem.pathSeparator`
+
+## 1.0.0
+
+* Unified interface to match dart:io API
+* Local file system implementation
+* In-memory file system implementation
+* Chroot file system implementation
+
+## 0.1.0
+
+* Initial version
diff --git a/pkgs/file/LICENSE b/pkgs/file/LICENSE
new file mode 100644
index 0000000..076334f
--- /dev/null
+++ b/pkgs/file/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2017, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/pkgs/file/README.md b/pkgs/file/README.md
new file mode 100644
index 0000000..a63d6e6
--- /dev/null
+++ b/pkgs/file/README.md
@@ -0,0 +1,44 @@
+[](https://github.com/dart-lang/tools/actions/workflows/file.yml)
+[](https://pub.dev/packages/file)
+[](https://pub.dev/packages/file/publisher)
+
+A generic file system abstraction for Dart.
+
+## Features
+
+Like `dart:io`, `package:file` supplies a rich Dart-idiomatic API for accessing
+a file system.
+
+Unlike `dart:io`, `package:file`:
+
+- Can be used to implement custom file systems.
+- Comes with an in-memory implementation out-of-the-box, making it super-easy to
+ test code that works with the file system.
+- Allows using multiple file systems simultaneously. A file system is a
+ first-class object. Instantiate however many you want and use them all.
+
+## Usage
+
+Implement your own custom file system:
+
+```dart
+import 'package:file/file.dart';
+
+class FooBarFileSystem implements FileSystem { ... }
+```
+
+Use the in-memory file system:
+
+```dart
+import 'package:file/memory.dart';
+
+var fs = MemoryFileSystem();
+```
+
+Use the local file system (requires dart:io access):
+
+```dart
+import 'package:file/local.dart';
+
+var fs = const LocalFileSystem();
+```
diff --git a/pkgs/file/analysis_options.yaml b/pkgs/file/analysis_options.yaml
new file mode 100644
index 0000000..8fbd2e4
--- /dev/null
+++ b/pkgs/file/analysis_options.yaml
@@ -0,0 +1,6 @@
+include: package:lints/recommended.yaml
+
+analyzer:
+ errors:
+ # Allow having TODOs in the code
+ todo: ignore
diff --git a/pkgs/file/example/main.dart b/pkgs/file/example/main.dart
new file mode 100644
index 0000000..7ca0bc7
--- /dev/null
+++ b/pkgs/file/example/main.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+
+Future<void> main() async {
+ final FileSystem fs = MemoryFileSystem();
+ final Directory tmp = await fs.systemTempDirectory.createTemp('example_');
+ final File outputFile = tmp.childFile('output');
+ await outputFile.writeAsString('Hello world!');
+ print(outputFile.readAsStringSync());
+}
diff --git a/pkgs/file/lib/chroot.dart b/pkgs/file/lib/chroot.dart
new file mode 100644
index 0000000..56d2bd5
--- /dev/null
+++ b/pkgs/file/lib/chroot.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A file system that provides a view into _another_ `FileSystem` via a path.
+export 'src/backends/chroot.dart';
diff --git a/pkgs/file/lib/file.dart b/pkgs/file/lib/file.dart
new file mode 100644
index 0000000..cdde9fe
--- /dev/null
+++ b/pkgs/file/lib/file.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Core interfaces containing the abstract `FileSystem` interface definition
+/// and all associated types used by `FileSystem`.
+export 'src/forwarding.dart';
+export 'src/interface.dart';
diff --git a/pkgs/file/lib/local.dart b/pkgs/file/lib/local.dart
new file mode 100644
index 0000000..74f506e
--- /dev/null
+++ b/pkgs/file/lib/local.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A local file system implementation. This relies on the use of `dart:io`
+/// and is thus not suitable for use in the browser.
+export 'src/backends/local.dart';
diff --git a/pkgs/file/lib/memory.dart b/pkgs/file/lib/memory.dart
new file mode 100644
index 0000000..c5705ef
--- /dev/null
+++ b/pkgs/file/lib/memory.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// An implementation of `FileSystem` that exists entirely in memory with an
+/// internal representation loosely based on the Filesystem Hierarchy Standard.
+export 'src/backends/memory.dart';
+export 'src/backends/memory/operations.dart';
diff --git a/pkgs/file/lib/src/backends/chroot.dart b/pkgs/file/lib/src/backends/chroot.dart
new file mode 100644
index 0000000..6082e80
--- /dev/null
+++ b/pkgs/file/lib/src/backends/chroot.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library file.src.backends.chroot;
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:file/file.dart';
+import 'package:file/src/common.dart' as common;
+import 'package:file/src/io.dart' as io;
+import 'package:path/path.dart' as p;
+
+part 'chroot/chroot_directory.dart';
+part 'chroot/chroot_file.dart';
+part 'chroot/chroot_file_system.dart';
+part 'chroot/chroot_file_system_entity.dart';
+part 'chroot/chroot_link.dart';
+part 'chroot/chroot_random_access_file.dart';
diff --git a/pkgs/file/lib/src/backends/chroot/chroot_directory.dart b/pkgs/file/lib/src/backends/chroot/chroot_directory.dart
new file mode 100644
index 0000000..8fec7b1
--- /dev/null
+++ b/pkgs/file/lib/src/backends/chroot/chroot_directory.dart
@@ -0,0 +1,176 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of file.src.backends.chroot;
+
+class _ChrootDirectory extends _ChrootFileSystemEntity<Directory, io.Directory>
+ with ForwardingDirectory<Directory>, common.DirectoryAddOnsMixin {
+ _ChrootDirectory(ChrootFileSystem fs, String path) : super(fs, path);
+
+ factory _ChrootDirectory.wrapped(
+ ChrootFileSystem fs,
+ Directory delegate, {
+ bool relative = false,
+ }) {
+ String localPath = fs._local(delegate.path, relative: relative);
+ return _ChrootDirectory(fs, localPath);
+ }
+
+ @override
+ FileSystemEntityType get expectedType => FileSystemEntityType.directory;
+
+ @override
+ io.Directory _rawDelegate(String path) => fileSystem.delegate.directory(path);
+
+ @override
+ Uri get uri => Uri.directory(path);
+
+ @override
+ Future<Directory> rename(String newPath) async {
+ if (_isLink) {
+ if (await fileSystem.type(path) != expectedType) {
+ throw common.notADirectory(path);
+ }
+ FileSystemEntityType type = await fileSystem.type(newPath);
+ if (type != FileSystemEntityType.notFound) {
+ if (type != expectedType) {
+ throw common.notADirectory(newPath);
+ }
+ if (!(await fileSystem
+ .directory(newPath)
+ .list(followLinks: false)
+ .isEmpty)) {
+ throw common.directoryNotEmpty(newPath);
+ }
+ }
+ String target = await fileSystem.link(path).target();
+ await fileSystem.link(path).delete();
+ await fileSystem.link(newPath).create(target);
+ return fileSystem.directory(newPath);
+ } else {
+ return wrap(await getDelegate(followLinks: true)
+ .rename(fileSystem._real(newPath)));
+ }
+ }
+
+ @override
+ Directory renameSync(String newPath) {
+ if (_isLink) {
+ if (fileSystem.typeSync(path) != expectedType) {
+ throw common.notADirectory(path);
+ }
+ FileSystemEntityType type = fileSystem.typeSync(newPath);
+ if (type != FileSystemEntityType.notFound) {
+ if (type != expectedType) {
+ throw common.notADirectory(newPath);
+ }
+ if (fileSystem
+ .directory(newPath)
+ .listSync(followLinks: false)
+ .isNotEmpty) {
+ throw common.directoryNotEmpty(newPath);
+ }
+ }
+ String target = fileSystem.link(path).targetSync();
+ fileSystem.link(path).deleteSync();
+ fileSystem.link(newPath).createSync(target);
+ return fileSystem.directory(newPath);
+ } else {
+ return wrap(
+ getDelegate(followLinks: true).renameSync(fileSystem._real(newPath)));
+ }
+ }
+
+ @override
+ Directory get absolute => _ChrootDirectory(fileSystem, _absolutePath);
+
+ @override
+ Directory get parent {
+ try {
+ return wrapDirectory(delegate.parent);
+ } on _ChrootJailException {
+ return this;
+ }
+ }
+
+ @override
+ Future<Directory> create({bool recursive = false}) async {
+ if (_isLink) {
+ switch (await fileSystem.type(path)) {
+ case FileSystemEntityType.notFound:
+ throw common.noSuchFileOrDirectory(path);
+ case FileSystemEntityType.file:
+ throw common.fileExists(path);
+ case FileSystemEntityType.directory:
+ // Nothing to do.
+ return this;
+ default:
+ throw AssertionError();
+ }
+ } else {
+ return wrap(await delegate.create(recursive: recursive));
+ }
+ }
+
+ @override
+ void createSync({bool recursive = false}) {
+ if (_isLink) {
+ switch (fileSystem.typeSync(path)) {
+ case FileSystemEntityType.notFound:
+ throw common.noSuchFileOrDirectory(path);
+ case FileSystemEntityType.file:
+ throw common.fileExists(path);
+ case FileSystemEntityType.directory:
+ // Nothing to do.
+ return;
+ default:
+ throw AssertionError();
+ }
+ } else {
+ delegate.createSync(recursive: recursive);
+ }
+ }
+
+ @override
+ Stream<FileSystemEntity> list({
+ bool recursive = false,
+ bool followLinks = true,
+ }) {
+ Directory delegate = this.delegate as Directory;
+ String dirname = delegate.path;
+ return delegate
+ .list(recursive: recursive, followLinks: followLinks)
+ .map((io.FileSystemEntity entity) => _denormalize(entity, dirname));
+ }
+
+ @override
+ List<FileSystemEntity> listSync({
+ bool recursive = false,
+ bool followLinks = true,
+ }) {
+ Directory delegate = this.delegate as Directory;
+ String dirname = delegate.path;
+ return delegate
+ .listSync(recursive: recursive, followLinks: followLinks)
+ .map((io.FileSystemEntity entity) => _denormalize(entity, dirname))
+ .toList();
+ }
+
+ FileSystemEntity _denormalize(io.FileSystemEntity entity, String dirname) {
+ p.Context ctx = fileSystem.path;
+ String relativePart = ctx.relative(entity.path, from: dirname);
+ String entityPath = ctx.join(path, relativePart);
+ if (entity is io.File) {
+ return _ChrootFile(fileSystem, entityPath);
+ } else if (entity is io.Directory) {
+ return _ChrootDirectory(fileSystem, entityPath);
+ } else if (entity is io.Link) {
+ return _ChrootLink(fileSystem, entityPath);
+ }
+ throw FileSystemException('Unsupported type: $entity', entity.path);
+ }
+
+ @override
+ String toString() => "ChrootDirectory: '$path'";
+}
diff --git a/pkgs/file/lib/src/backends/chroot/chroot_file.dart b/pkgs/file/lib/src/backends/chroot/chroot_file.dart
new file mode 100644
index 0000000..4b67bc1
--- /dev/null
+++ b/pkgs/file/lib/src/backends/chroot/chroot_file.dart
@@ -0,0 +1,339 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of file.src.backends.chroot;
+
+typedef _SetupCallback = dynamic Function();
+
+class _ChrootFile extends _ChrootFileSystemEntity<File, io.File>
+ with ForwardingFile {
+ _ChrootFile(ChrootFileSystem fs, String path) : super(fs, path);
+
+ factory _ChrootFile.wrapped(
+ ChrootFileSystem fs,
+ io.File delegate, {
+ bool relative = false,
+ }) {
+ String localPath = fs._local(delegate.path, relative: relative);
+ return _ChrootFile(fs, localPath);
+ }
+
+ @override
+ FileSystemEntityType get expectedType => FileSystemEntityType.file;
+
+ @override
+ io.File _rawDelegate(String path) => fileSystem.delegate.file(path);
+
+ @override
+ Future<File> rename(String newPath) async {
+ _SetupCallback setUp = () async {};
+
+ if (await fileSystem.type(newPath, followLinks: false) ==
+ FileSystemEntityType.link) {
+ // The delegate file system will ensure that the link target references
+ // an actual file before allowing the rename, but we want the link target
+ // to be resolved with respect to this file system. Thus, we perform that
+ // validation here instead.
+ switch (await fileSystem.type(newPath)) {
+ case FileSystemEntityType.file:
+ case FileSystemEntityType.notFound:
+ // Validation passed; delete the link to keep the delegate file
+ // system's validation from getting in the way.
+ setUp = () async {
+ await fileSystem.link(newPath).delete();
+ };
+ break;
+ case FileSystemEntityType.directory:
+ throw common.isADirectory(newPath);
+ default:
+ // Should never happen.
+ throw AssertionError();
+ }
+ }
+
+ if (_isLink) {
+ switch (await fileSystem.type(path)) {
+ case FileSystemEntityType.notFound:
+ throw common.noSuchFileOrDirectory(path);
+ case FileSystemEntityType.directory:
+ throw common.isADirectory(path);
+ case FileSystemEntityType.file:
+ await setUp();
+ await fileSystem.delegate
+ .link(fileSystem._real(path))
+ .rename(fileSystem._real(newPath));
+ return _ChrootFile(fileSystem, newPath);
+ default:
+ throw AssertionError();
+ }
+ } else {
+ await setUp();
+ return wrap(await delegate.rename(fileSystem._real(newPath)));
+ }
+ }
+
+ @override
+ File renameSync(String newPath) {
+ _SetupCallback setUp = () {};
+
+ if (fileSystem.typeSync(newPath, followLinks: false) ==
+ FileSystemEntityType.link) {
+ // The delegate file system will ensure that the link target references
+ // an actual file before allowing the rename, but we want the link target
+ // to be resolved with respect to this file system. Thus, we perform that
+ // validation here instead.
+ switch (fileSystem.typeSync(newPath)) {
+ case FileSystemEntityType.file:
+ case FileSystemEntityType.notFound:
+ // Validation passed; delete the link to keep the delegate file
+ // system's validation from getting in the way.
+ setUp = () {
+ fileSystem.link(newPath).deleteSync();
+ };
+ break;
+ case FileSystemEntityType.directory:
+ throw common.isADirectory(newPath);
+ default:
+ // Should never happen.
+ throw AssertionError();
+ }
+ }
+
+ if (_isLink) {
+ switch (fileSystem.typeSync(path)) {
+ case FileSystemEntityType.notFound:
+ throw common.noSuchFileOrDirectory(path);
+ case FileSystemEntityType.directory:
+ throw common.isADirectory(path);
+ case FileSystemEntityType.file:
+ setUp();
+ fileSystem.delegate
+ .link(fileSystem._real(path))
+ .renameSync(fileSystem._real(newPath));
+ return _ChrootFile(fileSystem, newPath);
+ default:
+ throw AssertionError();
+ }
+ } else {
+ setUp();
+ return wrap(delegate.renameSync(fileSystem._real(newPath)));
+ }
+ }
+
+ @override
+ File get absolute => _ChrootFile(fileSystem, _absolutePath);
+
+ @override
+ Future<File> create({bool recursive = false, bool exclusive = false}) async {
+ String path = fileSystem._resolve(
+ this.path,
+ followLinks: false,
+ notFound: recursive ? _NotFoundBehavior.mkdir : _NotFoundBehavior.allow,
+ );
+
+ String real() => fileSystem._real(path, resolve: false);
+ Future<FileSystemEntityType> type() =>
+ fileSystem.delegate.type(real(), followLinks: false);
+
+ if (await type() == FileSystemEntityType.link) {
+ path = fileSystem._resolve(p.basename(path),
+ from: p.dirname(path), notFound: _NotFoundBehavior.allowAtTail);
+ switch (await type()) {
+ case FileSystemEntityType.notFound:
+ await _rawDelegate(real()).create();
+ return this;
+ case FileSystemEntityType.file:
+ // Nothing to do.
+ return this;
+ case FileSystemEntityType.directory:
+ throw common.isADirectory(path);
+ default:
+ throw AssertionError();
+ }
+ } else {
+ return wrap(await _rawDelegate(real()).create());
+ }
+ }
+
+ @override
+ void createSync({bool recursive = false, bool exclusive = false}) {
+ String path = fileSystem._resolve(
+ this.path,
+ followLinks: false,
+ notFound: recursive ? _NotFoundBehavior.mkdir : _NotFoundBehavior.allow,
+ );
+
+ String real() => fileSystem._real(path, resolve: false);
+ FileSystemEntityType type() =>
+ fileSystem.delegate.typeSync(real(), followLinks: false);
+
+ if (type() == FileSystemEntityType.link) {
+ path = fileSystem._resolve(p.basename(path),
+ from: p.dirname(path), notFound: _NotFoundBehavior.allowAtTail);
+ switch (type()) {
+ case FileSystemEntityType.notFound:
+ _rawDelegate(real()).createSync();
+ return;
+ case FileSystemEntityType.file:
+ // Nothing to do.
+ return;
+ case FileSystemEntityType.directory:
+ throw common.isADirectory(path);
+ default:
+ throw AssertionError();
+ }
+ } else {
+ _rawDelegate(real()).createSync();
+ }
+ }
+
+ @override
+ Future<File> copy(String newPath) async {
+ return wrap(await getDelegate(followLinks: true)
+ .copy(fileSystem._real(newPath, followLinks: true)));
+ }
+
+ @override
+ File copySync(String newPath) {
+ return wrap(getDelegate(followLinks: true)
+ .copySync(fileSystem._real(newPath, followLinks: true)));
+ }
+
+ @override
+ Future<int> length() => getDelegate(followLinks: true).length();
+
+ @override
+ int lengthSync() => getDelegate(followLinks: true).lengthSync();
+
+ @override
+ Future<DateTime> lastAccessed() =>
+ getDelegate(followLinks: true).lastAccessed();
+
+ @override
+ DateTime lastAccessedSync() =>
+ getDelegate(followLinks: true).lastAccessedSync();
+
+ @override
+ Future<dynamic> setLastAccessed(DateTime time) =>
+ getDelegate(followLinks: true).setLastAccessed(time);
+
+ @override
+ void setLastAccessedSync(DateTime time) =>
+ getDelegate(followLinks: true).setLastAccessedSync(time);
+
+ @override
+ Future<DateTime> lastModified() =>
+ getDelegate(followLinks: true).lastModified();
+
+ @override
+ DateTime lastModifiedSync() =>
+ getDelegate(followLinks: true).lastModifiedSync();
+
+ @override
+ Future<dynamic> setLastModified(DateTime time) =>
+ getDelegate(followLinks: true).setLastModified(time);
+
+ @override
+ void setLastModifiedSync(DateTime time) =>
+ getDelegate(followLinks: true).setLastModifiedSync(time);
+
+ @override
+ Future<RandomAccessFile> open({
+ FileMode mode = FileMode.read,
+ }) async =>
+ _ChrootRandomAccessFile(
+ path, await getDelegate(followLinks: true).open(mode: mode));
+
+ @override
+ RandomAccessFile openSync({FileMode mode = FileMode.read}) =>
+ _ChrootRandomAccessFile(
+ path, getDelegate(followLinks: true).openSync(mode: mode));
+
+ @override
+ Stream<List<int>> openRead([int? start, int? end]) =>
+ getDelegate(followLinks: true).openRead(start, end);
+
+ @override
+ IOSink openWrite({
+ FileMode mode = FileMode.write,
+ Encoding encoding = utf8,
+ }) =>
+ getDelegate(followLinks: true).openWrite(mode: mode, encoding: encoding);
+
+ @override
+ Future<Uint8List> readAsBytes() =>
+ getDelegate(followLinks: true).readAsBytes();
+
+ @override
+ Uint8List readAsBytesSync() =>
+ getDelegate(followLinks: true).readAsBytesSync();
+
+ @override
+ Future<String> readAsString({Encoding encoding = utf8}) =>
+ getDelegate(followLinks: true).readAsString(encoding: encoding);
+
+ @override
+ String readAsStringSync({Encoding encoding = utf8}) =>
+ getDelegate(followLinks: true).readAsStringSync(encoding: encoding);
+
+ @override
+ Future<List<String>> readAsLines({Encoding encoding = utf8}) =>
+ getDelegate(followLinks: true).readAsLines(encoding: encoding);
+
+ @override
+ List<String> readAsLinesSync({Encoding encoding = utf8}) =>
+ getDelegate(followLinks: true).readAsLinesSync(encoding: encoding);
+
+ @override
+ Future<File> writeAsBytes(
+ List<int> bytes, {
+ FileMode mode = FileMode.write,
+ bool flush = false,
+ }) async =>
+ wrap(await getDelegate(followLinks: true).writeAsBytes(
+ bytes,
+ mode: mode,
+ flush: flush,
+ ));
+
+ @override
+ void writeAsBytesSync(
+ List<int> bytes, {
+ FileMode mode = FileMode.write,
+ bool flush = false,
+ }) =>
+ getDelegate(followLinks: true)
+ .writeAsBytesSync(bytes, mode: mode, flush: flush);
+
+ @override
+ Future<File> writeAsString(
+ String contents, {
+ FileMode mode = FileMode.write,
+ Encoding encoding = utf8,
+ bool flush = false,
+ }) async =>
+ wrap(await getDelegate(followLinks: true).writeAsString(
+ contents,
+ mode: mode,
+ encoding: encoding,
+ flush: flush,
+ ));
+
+ @override
+ void writeAsStringSync(
+ String contents, {
+ FileMode mode = FileMode.write,
+ Encoding encoding = utf8,
+ bool flush = false,
+ }) =>
+ getDelegate(followLinks: true).writeAsStringSync(
+ contents,
+ mode: mode,
+ encoding: encoding,
+ flush: flush,
+ );
+
+ @override
+ String toString() => "ChrootFile: '$path'";
+}
diff --git a/pkgs/file/lib/src/backends/chroot/chroot_file_system.dart b/pkgs/file/lib/src/backends/chroot/chroot_file_system.dart
new file mode 100644
index 0000000..6889c98
--- /dev/null
+++ b/pkgs/file/lib/src/backends/chroot/chroot_file_system.dart
@@ -0,0 +1,391 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of file.src.backends.chroot;
+
+const String _thisDir = '.';
+const String _parentDir = '..';
+
+/// File system that provides a view into _another_ [FileSystem] via a path.
+///
+/// This is similar in concept to the `chroot` operation in Linux operating
+/// systems. Such a modified file system cannot name or access files outside of
+/// the designated directory tree.
+///
+/// ## Example use:
+/// ```dart
+/// // Create a "file system" where the root directory is /tmp/some-dir.
+/// var fs = ChrootFileSystem(existingFileSystem, '/tmp/some-dir');
+/// ```
+///
+/// **Notes on usage**:
+///
+/// * This file system maintains its _own_ [currentDirectory], distinct from
+/// that of the underlying file system, and new instances automatically start
+/// at the root (i.e. `/`).
+///
+/// * This file system does _not_ leverage any underlying OS system calls (such
+/// as `chroot` itself), so the developer needs to take care to not assume any
+/// more of a secure environment than is actually provided. For instance, the
+/// underlying system is available via the [delegate] - which underscores this
+/// file system is intended to be a convenient abstraction, not a security
+/// measure.
+///
+/// * This file system _necessarily_ carries certain performance overhead due
+/// to the fact that symbolic links are resolved manually (not delegated).
+class ChrootFileSystem extends FileSystem {
+ /// Creates a new file system backed by [root] path in [delegate] file system.
+ ///
+ /// **NOTE**: [root] must be a _canonicalized_ path; see [p.canonicalize].
+ ChrootFileSystem(this.delegate, this.root) {
+ if (root != delegate.path.canonicalize(root)) {
+ throw ArgumentError.value(root, 'root', 'Must be canonical path');
+ }
+ _cwd = _localRoot;
+ }
+
+ /// Underlying file system.
+ final FileSystem delegate;
+
+ /// Directory in [delegate] file system that is treated as the root here.
+ final String root;
+
+ String? _systemTemp;
+
+ /// Path to the synthetic current working directory in this file system.
+ late String _cwd;
+
+ /// Gets the root path, as seen by entities in this file system.
+ String get _localRoot => delegate.path.rootPrefix(root);
+
+ @override
+ Directory directory(dynamic path) => _ChrootDirectory(this, getPath(path));
+
+ @override
+ File file(dynamic path) => _ChrootFile(this, getPath(path));
+
+ @override
+ Link link(dynamic path) => _ChrootLink(this, getPath(path));
+
+ @override
+ p.Context get path => p.Context(style: delegate.path.style, current: _cwd);
+
+ /// Gets the system temp directory. This directory will be created on-demand
+ /// in the local root of the file system. Once created, its location is fixed
+ /// for the life of the process.
+ @override
+ Directory get systemTempDirectory {
+ _systemTemp ??= directory(_localRoot).createTempSync('.tmp_').path;
+ return directory(_systemTemp)..createSync();
+ }
+
+ /// Creates a directory object pointing to the current working directory.
+ ///
+ /// **NOTE** This does _not_ proxy to the underlying file system's current
+ /// directory in any way; the state of this file system's current directory
+ /// is local to this file system.
+ @override
+ Directory get currentDirectory => directory(_cwd);
+
+ /// Sets the current working directory to the specified [path].
+ ///
+ /// **NOTE** This does _not_ proxy to the underlying file system's current
+ /// directory in any way; the state of this file system's current directory
+ /// is local to this file system.
+ /// Gets the path context for this file system given the current working dir.
+
+ @override
+ set currentDirectory(dynamic path) {
+ String value;
+ if (path is io.Directory) {
+ value = path.path;
+ } else if (path is String) {
+ value = path;
+ } else {
+ throw ArgumentError('Invalid type for "path": ${path?.runtimeType}');
+ }
+
+ value = _resolve(value, notFound: _NotFoundBehavior.throwError);
+ String realPath = _real(value, resolve: false);
+ switch (delegate.typeSync(realPath, followLinks: false)) {
+ case FileSystemEntityType.directory:
+ break;
+ case FileSystemEntityType.notFound:
+ throw common.noSuchFileOrDirectory(path as String);
+ default:
+ throw common.notADirectory(path as String);
+ }
+ assert(() {
+ p.Context ctx = delegate.path;
+ return ctx.isAbsolute(value) && value == ctx.canonicalize(value);
+ }());
+ _cwd = value;
+ }
+
+ @override
+ Future<FileStat> stat(String path) {
+ try {
+ path = _resolve(path);
+ } on FileSystemException {
+ return Future<FileStat>.value(const _NotFoundFileStat());
+ }
+ return delegate.stat(_real(path, resolve: false));
+ }
+
+ @override
+ FileStat statSync(String path) {
+ try {
+ path = _resolve(path);
+ } on FileSystemException {
+ return const _NotFoundFileStat();
+ }
+ return delegate.statSync(_real(path, resolve: false));
+ }
+
+ @override
+ Future<bool> identical(String path1, String path2) => delegate.identical(
+ _real(_resolve(path1, followLinks: false)),
+ _real(_resolve(path2, followLinks: false)),
+ );
+
+ @override
+ bool identicalSync(String path1, String path2) => delegate.identicalSync(
+ _real(_resolve(path1, followLinks: false)),
+ _real(_resolve(path2, followLinks: false)),
+ );
+
+ @override
+ bool get isWatchSupported => false;
+
+ @override
+ Future<FileSystemEntityType> type(String path, {bool followLinks = true}) {
+ String realPath;
+ try {
+ realPath = _real(path, followLinks: followLinks);
+ } on FileSystemException {
+ return Future<FileSystemEntityType>.value(FileSystemEntityType.notFound);
+ }
+ return delegate.type(realPath, followLinks: false);
+ }
+
+ @override
+ FileSystemEntityType typeSync(String path, {bool followLinks = true}) {
+ String realPath;
+ try {
+ realPath = _real(path, followLinks: followLinks);
+ } on FileSystemException {
+ return FileSystemEntityType.notFound;
+ }
+ return delegate.typeSync(realPath, followLinks: false);
+ }
+
+ /// Converts a [realPath] in the underlying file system to a local path here.
+ ///
+ /// If [relative] is set to `true`, then the resulting path will be relative
+ /// to [currentDirectory], otherwise the resulting path will be absolute.
+ ///
+ /// An exception is thrown if the path is outside of this file system's root
+ /// directory unless [keepInJail] is true, in which case this will instead
+ /// return the path of the root of this file system.
+ String _local(
+ String realPath, {
+ bool relative = false,
+ bool keepInJail = false,
+ }) {
+ assert(path.isAbsolute(realPath));
+ if (!realPath.startsWith(root)) {
+ if (keepInJail) {
+ return _localRoot;
+ }
+ throw _ChrootJailException();
+ }
+ // TODO(tvolkert): See if _context.relative() works here
+ String result = realPath.substring(root.length);
+ if (result.isEmpty) {
+ result = _localRoot;
+ }
+ if (relative) {
+ assert(result.startsWith(_cwd));
+ result = path.relative(result, from: _cwd);
+ }
+ return result;
+ }
+
+ /// Converts [localPath] in this file system to the real path in the delegate.
+ ///
+ /// The returned path will always be absolute.
+ ///
+ /// If [resolve] is true, symbolic links will be resolved in the local file
+ /// system _before_ converting the path to the delegate file system's
+ /// namespace, and if the tail element of the path is a symbolic link, it will
+ /// only be resolved if [followLinks] is true (where-as symbolic links found
+ /// in the middle of the path will always be resolved).
+ String _real(
+ String localPath, {
+ bool resolve = true,
+ bool followLinks = false,
+ }) {
+ if (resolve) {
+ localPath = _resolve(localPath, followLinks: followLinks);
+ } else {
+ assert(path.isAbsolute(localPath));
+ }
+ return '$root$localPath';
+ }
+
+ /// Resolves symbolic links on [path] and returns the resulting resolved path.
+ ///
+ /// The return value will always be an absolute path; if [path] is relative
+ /// it will be interpreted relative to [from] (or [currentDirectory] if
+ /// `null`).
+ ///
+ /// If the tail element is a symbolic link, then the link will be resolved
+ /// only if [followLinks] is `true`. Symbolic links found in the middle of
+ /// the path will always be resolved.
+ ///
+ /// If the path cannot be resolved, and [notFound] is:
+ /// - [_NotFoundBehavior.throwError]: a [FileSystemException] is thrown.
+ /// - [_NotFoundBehavior.mkdir]: the path will be created as needed.
+ /// - [_NotFoundBehavior.allowAtTail]: a [FileSystemException] is thrown,
+ /// unless only the *tail* path element cannot be resolved, in which case
+ /// the resolution will halt at the tail element, and the partially
+ /// resolved path will be returned.
+ /// - [_NotFoundBehavior.allow] (the default), the resolution will halt and
+ /// the partially resolved path will be returned.
+ String _resolve(
+ String path, {
+ String? from,
+ bool followLinks = true,
+ _NotFoundBehavior notFound = _NotFoundBehavior.allow,
+ }) {
+ if (path.isEmpty) {
+ throw common.noSuchFileOrDirectory(path);
+ }
+
+ p.Context ctx = this.path;
+ String root = _localRoot;
+ List<String> parts, ledger;
+ if (ctx.isAbsolute(path)) {
+ parts = ctx.split(path).sublist(1);
+ ledger = <String>[];
+ } else {
+ from ??= _cwd;
+ assert(ctx.isAbsolute(from));
+ parts = ctx.split(path);
+ ledger = ctx.split(from).sublist(1);
+ }
+
+ String getCurrentPath() => root + ctx.joinAll(ledger);
+ Set<String> breadcrumbs = <String>{};
+ while (parts.isNotEmpty) {
+ String segment = parts.removeAt(0);
+ if (segment == _thisDir) {
+ continue;
+ } else if (segment == _parentDir) {
+ if (ledger.isNotEmpty) {
+ ledger.removeLast();
+ }
+ continue;
+ }
+
+ ledger.add(segment);
+ String currentPath = getCurrentPath();
+ String realPath = _real(currentPath, resolve: false);
+
+ switch (delegate.typeSync(realPath, followLinks: false)) {
+ case FileSystemEntityType.directory:
+ breadcrumbs.clear();
+ break;
+ case FileSystemEntityType.file:
+ breadcrumbs.clear();
+ if (parts.isNotEmpty) {
+ throw common.notADirectory(currentPath);
+ }
+ break;
+ case FileSystemEntityType.notFound:
+ String returnEarly() {
+ ledger.addAll(parts);
+ return getCurrentPath();
+ }
+
+ switch (notFound) {
+ case _NotFoundBehavior.mkdir:
+ if (parts.isNotEmpty) {
+ delegate.directory(realPath).createSync();
+ }
+ break;
+ case _NotFoundBehavior.allow:
+ return returnEarly();
+ case _NotFoundBehavior.allowAtTail:
+ if (parts.isEmpty) {
+ return returnEarly();
+ }
+ throw common.noSuchFileOrDirectory(path);
+ case _NotFoundBehavior.throwError:
+ throw common.noSuchFileOrDirectory(path);
+ }
+ break;
+ case FileSystemEntityType.link:
+ if (parts.isEmpty && !followLinks) {
+ break;
+ }
+ if (!breadcrumbs.add(currentPath)) {
+ throw common.tooManyLevelsOfSymbolicLinks(path);
+ }
+ String target = delegate.link(realPath).targetSync();
+ if (ctx.isAbsolute(target)) {
+ ledger.clear();
+ parts.insertAll(0, ctx.split(target).sublist(1));
+ } else {
+ ledger.removeLast();
+ parts.insertAll(0, ctx.split(target));
+ }
+ break;
+ default:
+ throw AssertionError();
+ }
+ }
+
+ return getCurrentPath();
+ }
+}
+
+/// Thrown when a path is encountered that exists outside of the root path.
+class _ChrootJailException implements IOException {}
+
+/// What to do when `NOT_FOUND` paths are encountered while resolving.
+enum _NotFoundBehavior {
+ allow,
+ allowAtTail,
+ throwError,
+ mkdir,
+}
+
+/// A [FileStat] representing a `NOT_FOUND` entity.
+class _NotFoundFileStat implements FileStat {
+ const _NotFoundFileStat();
+
+ static final DateTime _empty = DateTime(0);
+
+ @override
+ DateTime get changed => _empty;
+
+ @override
+ DateTime get modified => _empty;
+
+ @override
+ DateTime get accessed => _empty;
+
+ @override
+ FileSystemEntityType get type => FileSystemEntityType.notFound;
+
+ @override
+ int get mode => 0;
+
+ @override
+ int get size => -1;
+
+ @override
+ String modeString() => '---------';
+}
diff --git a/pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart b/pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart
new file mode 100644
index 0000000..8e859ac
--- /dev/null
+++ b/pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart
@@ -0,0 +1,169 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of file.src.backends.chroot;
+
+abstract class _ChrootFileSystemEntity<T extends FileSystemEntity,
+ D extends io.FileSystemEntity> extends ForwardingFileSystemEntity<T, D> {
+ _ChrootFileSystemEntity(this.fileSystem, this.path);
+
+ @override
+ final ChrootFileSystem fileSystem;
+
+ @override
+ final String path;
+
+ @override
+ String get dirname => fileSystem.path.dirname(path);
+
+ @override
+ String get basename => fileSystem.path.basename(path);
+
+ @override
+ D get delegate => getDelegate();
+
+ /// Gets the delegate file system entity in the underlying file system that
+ /// corresponds to this entity's local file system path.
+ ///
+ /// If [followLinks] is true and this entity's path references a symbolic
+ /// link, then the path of the delegate entity will reference the ultimate
+ /// target of that symbolic link. Symbolic links in the middle of the path
+ /// will always be resolved in the delegate entity's path.
+ D getDelegate({bool followLinks = false}) =>
+ _rawDelegate(fileSystem._real(path, followLinks: followLinks));
+
+ /// Returns the expected type of this entity, which may differ from the type
+ /// of the entity that's found at the path specified by this entity.
+ FileSystemEntityType get expectedType;
+
+ /// Returns a delegate entity at the specified [realPath] (the path in the
+ /// underlying file system).
+ D _rawDelegate(String realPath);
+
+ /// Gets the path of this entity as an absolute path (unchanged if the
+ /// entity already specifies an absolute path).
+ String get _absolutePath => fileSystem.path.absolute(path);
+
+ /// Tells whether this entity's path references a symbolic link.
+ bool get _isLink =>
+ fileSystem.typeSync(path, followLinks: false) ==
+ FileSystemEntityType.link;
+
+ @override
+ Directory wrapDirectory(io.Directory delegate) =>
+ _ChrootDirectory.wrapped(fileSystem, delegate as Directory,
+ relative: !isAbsolute);
+
+ @override
+ File wrapFile(io.File delegate) =>
+ _ChrootFile.wrapped(fileSystem, delegate, relative: !isAbsolute);
+
+ @override
+ Link wrapLink(io.Link delegate) =>
+ _ChrootLink.wrapped(fileSystem, delegate, relative: !isAbsolute);
+
+ @override
+ Uri get uri => Uri.file(path);
+
+ @override
+ Future<bool> exists() => getDelegate(followLinks: true).exists();
+
+ @override
+ bool existsSync() => getDelegate(followLinks: true).existsSync();
+
+ @override
+ Future<String> resolveSymbolicLinks() async => resolveSymbolicLinksSync();
+
+ @override
+ String resolveSymbolicLinksSync() =>
+ fileSystem._resolve(path, notFound: _NotFoundBehavior.throwError);
+
+ @override
+ Future<FileStat> stat() {
+ D delegate;
+ try {
+ delegate = getDelegate(followLinks: true);
+ } on FileSystemException {
+ return Future<FileStat>.value(const _NotFoundFileStat());
+ }
+ return delegate.stat();
+ }
+
+ @override
+ FileStat statSync() {
+ D delegate;
+ try {
+ delegate = getDelegate(followLinks: true);
+ } on FileSystemException {
+ return const _NotFoundFileStat();
+ }
+ return delegate.statSync();
+ }
+
+ @override
+ Future<T> delete({bool recursive = false}) async {
+ String path = fileSystem._resolve(this.path,
+ followLinks: false, notFound: _NotFoundBehavior.throwError);
+
+ String real(String path) => fileSystem._real(path, resolve: false);
+ Future<FileSystemEntityType> type(String path) =>
+ fileSystem.delegate.type(real(path), followLinks: false);
+
+ if (await type(path) == FileSystemEntityType.link) {
+ if (expectedType == FileSystemEntityType.link) {
+ await fileSystem.delegate.link(real(path)).delete();
+ } else {
+ String resolvedPath = fileSystem._resolve(p.basename(path),
+ from: p.dirname(path), notFound: _NotFoundBehavior.allowAtTail);
+ if (!recursive && await type(resolvedPath) != expectedType) {
+ throw expectedType == FileSystemEntityType.file
+ ? common.isADirectory(path)
+ : common.notADirectory(path);
+ }
+ await fileSystem.delegate.link(real(path)).delete();
+ }
+ return this as T;
+ } else {
+ return wrap(
+ await _rawDelegate(real(path)).delete(recursive: recursive) as D);
+ }
+ }
+
+ @override
+ void deleteSync({bool recursive = false}) {
+ String path = fileSystem._resolve(this.path,
+ followLinks: false, notFound: _NotFoundBehavior.throwError);
+
+ String real(String path) => fileSystem._real(path, resolve: false);
+ FileSystemEntityType type(String path) =>
+ fileSystem.delegate.typeSync(real(path), followLinks: false);
+
+ if (type(path) == FileSystemEntityType.link) {
+ if (expectedType == FileSystemEntityType.link) {
+ fileSystem.delegate.link(real(path)).deleteSync();
+ } else {
+ String resolvedPath = fileSystem._resolve(p.basename(path),
+ from: p.dirname(path), notFound: _NotFoundBehavior.allowAtTail);
+ if (!recursive && type(resolvedPath) != expectedType) {
+ throw expectedType == FileSystemEntityType.file
+ ? common.isADirectory(path)
+ : common.notADirectory(path);
+ }
+ fileSystem.delegate.link(real(path)).deleteSync();
+ }
+ } else {
+ _rawDelegate(real(path)).deleteSync(recursive: recursive);
+ }
+ }
+
+ @override
+ Stream<FileSystemEvent> watch({
+ int events = FileSystemEvent.all,
+ bool recursive = false,
+ }) =>
+ throw UnsupportedError('watch is not supported on ChrootFileSystem');
+
+ @override
+ bool get isAbsolute => fileSystem.path.isAbsolute(path);
+}
diff --git a/pkgs/file/lib/src/backends/chroot/chroot_link.dart b/pkgs/file/lib/src/backends/chroot/chroot_link.dart
new file mode 100644
index 0000000..acbeda6
--- /dev/null
+++ b/pkgs/file/lib/src/backends/chroot/chroot_link.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of file.src.backends.chroot;
+
+class _ChrootLink extends _ChrootFileSystemEntity<Link, io.Link>
+ with ForwardingLink {
+ _ChrootLink(ChrootFileSystem fs, String path) : super(fs, path);
+
+ factory _ChrootLink.wrapped(
+ ChrootFileSystem fs,
+ io.Link delegate, {
+ bool relative = false,
+ }) {
+ String localPath = fs._local(delegate.path, relative: relative);
+ return _ChrootLink(fs, localPath);
+ }
+
+ @override
+ Future<bool> exists() => delegate.exists();
+
+ @override
+ bool existsSync() => delegate.existsSync();
+
+ @override
+ Future<Link> rename(String newPath) async {
+ return wrap(await delegate.rename(fileSystem._real(newPath)));
+ }
+
+ @override
+ Link renameSync(String newPath) {
+ return wrap(delegate.renameSync(fileSystem._real(newPath)));
+ }
+
+ @override
+ FileSystemEntityType get expectedType => FileSystemEntityType.link;
+
+ @override
+ io.Link _rawDelegate(String path) => fileSystem.delegate.link(path);
+
+ @override
+ Link get absolute => _ChrootLink(fileSystem, _absolutePath);
+
+ @override
+ String toString() => "ChrootLink: '$path'";
+}
diff --git a/pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart b/pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart
new file mode 100644
index 0000000..4105ac8
--- /dev/null
+++ b/pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of file.src.backends.chroot;
+
+class _ChrootRandomAccessFile with ForwardingRandomAccessFile {
+ _ChrootRandomAccessFile(this.path, this.delegate);
+
+ @override
+ final io.RandomAccessFile delegate;
+
+ @override
+ final String path;
+}
diff --git a/pkgs/file/lib/src/backends/local.dart b/pkgs/file/lib/src/backends/local.dart
new file mode 100644
index 0000000..1e92241
--- /dev/null
+++ b/pkgs/file/lib/src/backends/local.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'local/local_file_system.dart' show LocalFileSystem;
diff --git a/pkgs/file/lib/src/backends/local/local_directory.dart b/pkgs/file/lib/src/backends/local/local_directory.dart
new file mode 100644
index 0000000..e23e68f
--- /dev/null
+++ b/pkgs/file/lib/src/backends/local/local_directory.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/common.dart' as common;
+import 'package:file/src/io.dart' as io;
+
+import 'local_file_system_entity.dart';
+
+/// [Directory] implementation that forwards all calls to `dart:io`.
+class LocalDirectory extends LocalFileSystemEntity<LocalDirectory, io.Directory>
+ with ForwardingDirectory<LocalDirectory>, common.DirectoryAddOnsMixin {
+ /// Instantiates a new [LocalDirectory] tied to the specified file system
+ /// and delegating to the specified [delegate].
+ LocalDirectory(FileSystem fs, io.Directory delegate) : super(fs, delegate);
+
+ @override
+ String toString() => "LocalDirectory: '$path'";
+}
diff --git a/pkgs/file/lib/src/backends/local/local_file.dart b/pkgs/file/lib/src/backends/local/local_file.dart
new file mode 100644
index 0000000..36293ba
--- /dev/null
+++ b/pkgs/file/lib/src/backends/local/local_file.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/io.dart' as io;
+
+import 'local_file_system_entity.dart';
+
+/// [File] implementation that forwards all calls to `dart:io`.
+class LocalFile extends LocalFileSystemEntity<File, io.File>
+ with ForwardingFile {
+ /// Instantiates a new [LocalFile] tied to the specified file system
+ /// and delegating to the specified [delegate].
+ LocalFile(FileSystem fs, io.File delegate) : super(fs, delegate);
+
+ @override
+ String toString() => "LocalFile: '$path'";
+}
diff --git a/pkgs/file/lib/src/backends/local/local_file_system.dart b/pkgs/file/lib/src/backends/local/local_file_system.dart
new file mode 100644
index 0000000..635998e
--- /dev/null
+++ b/pkgs/file/lib/src/backends/local/local_file_system.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/src/io.dart' as io;
+import 'package:file/file.dart';
+import 'package:path/path.dart' as p;
+
+import 'local_directory.dart';
+import 'local_file.dart';
+import 'local_link.dart';
+
+/// A wrapper implementation around `dart:io`'s implementation.
+///
+/// Since this implementation of the [FileSystem] interface delegates to
+/// `dart:io`, is is not suitable for use in the browser.
+class LocalFileSystem extends FileSystem {
+ /// Creates a new `LocalFileSystem`.
+ const LocalFileSystem();
+
+ @override
+ Directory directory(dynamic path) =>
+ LocalDirectory(this, io.Directory(getPath(path)));
+
+ @override
+ File file(dynamic path) => LocalFile(this, io.File(getPath(path)));
+
+ @override
+ Link link(dynamic path) => LocalLink(this, io.Link(getPath(path)));
+
+ @override
+ p.Context get path => p.Context();
+
+ /// Gets the directory provided by the operating system for creating temporary
+ /// files and directories in. The location of the system temp directory is
+ /// platform-dependent, and may be set by an environment variable.
+ @override
+ Directory get systemTempDirectory =>
+ LocalDirectory(this, io.Directory.systemTemp);
+
+ @override
+ Directory get currentDirectory => directory(io.Directory.current.path);
+
+ @override
+ set currentDirectory(dynamic path) => io.Directory.current = path;
+
+ @override
+ Future<io.FileStat> stat(String path) => io.FileStat.stat(path);
+
+ @override
+ io.FileStat statSync(String path) => io.FileStat.statSync(path);
+
+ @override
+ Future<bool> identical(String path1, String path2) =>
+ io.FileSystemEntity.identical(path1, path2);
+
+ @override
+ bool identicalSync(String path1, String path2) =>
+ io.FileSystemEntity.identicalSync(path1, path2);
+
+ @override
+ bool get isWatchSupported => io.FileSystemEntity.isWatchSupported;
+
+ @override
+ Future<io.FileSystemEntityType> type(String path,
+ {bool followLinks = true}) =>
+ io.FileSystemEntity.type(path, followLinks: followLinks);
+
+ @override
+ io.FileSystemEntityType typeSync(String path, {bool followLinks = true}) =>
+ io.FileSystemEntity.typeSync(path, followLinks: followLinks);
+}
diff --git a/pkgs/file/lib/src/backends/local/local_file_system_entity.dart b/pkgs/file/lib/src/backends/local/local_file_system_entity.dart
new file mode 100644
index 0000000..ca4617b
--- /dev/null
+++ b/pkgs/file/lib/src/backends/local/local_file_system_entity.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/io.dart' as io;
+
+import 'local_directory.dart';
+import 'local_file.dart';
+import 'local_link.dart';
+
+/// [FileSystemEntity] implementation that forwards all calls to `dart:io`.
+abstract class LocalFileSystemEntity<T extends FileSystemEntity,
+ D extends io.FileSystemEntity> extends ForwardingFileSystemEntity<T, D> {
+ /// Instantiates a new [LocalFileSystemEntity] tied to the specified file
+ /// system and delegating to the specified [delegate].
+ LocalFileSystemEntity(this.fileSystem, this.delegate);
+
+ @override
+ final FileSystem fileSystem;
+
+ @override
+ final D delegate;
+
+ @override
+ String get dirname => fileSystem.path.dirname(path);
+
+ @override
+ String get basename => fileSystem.path.basename(path);
+
+ @override
+ Directory wrapDirectory(io.Directory delegate) =>
+ LocalDirectory(fileSystem, delegate);
+
+ @override
+ File wrapFile(io.File delegate) => LocalFile(fileSystem, delegate);
+
+ @override
+ Link wrapLink(io.Link delegate) => LocalLink(fileSystem, delegate);
+}
diff --git a/pkgs/file/lib/src/backends/local/local_link.dart b/pkgs/file/lib/src/backends/local/local_link.dart
new file mode 100644
index 0000000..fc67d5e
--- /dev/null
+++ b/pkgs/file/lib/src/backends/local/local_link.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/io.dart' as io;
+
+import 'local_file_system_entity.dart';
+
+/// [Link] implementation that forwards all calls to `dart:io`.
+class LocalLink extends LocalFileSystemEntity<Link, io.Link>
+ with ForwardingLink {
+ /// Instantiates a new [LocalLink] tied to the specified file system
+ /// and delegating to the specified [delegate].
+ LocalLink(FileSystem fs, io.Link delegate) : super(fs, delegate);
+
+ @override
+ String toString() => "LocalLink: '$path'";
+}
diff --git a/pkgs/file/lib/src/backends/memory.dart b/pkgs/file/lib/src/backends/memory.dart
new file mode 100644
index 0000000..428bc54
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'memory/memory_file_system.dart' show MemoryFileSystem;
+export 'memory/style.dart' show FileSystemStyle, StyleableFileSystem;
diff --git a/pkgs/file/lib/src/backends/memory/clock.dart b/pkgs/file/lib/src/backends/memory/clock.dart
new file mode 100644
index 0000000..98d5434
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/clock.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Interface describing clocks used by the [MemoryFileSystem].
+///
+/// The [MemoryFileSystem] uses a clock to determine the modification times of
+/// files that are created in that file system.
+abstract class Clock {
+ /// Abstract const constructor. This constructor enables subclasses to provide
+ /// const constructors so that they can be used in const expressions.
+ const Clock();
+
+ /// A real-time clock.
+ ///
+ /// Uses [DateTime.now] to reflect the actual time reported by the operating
+ /// system.
+ const factory Clock.realTime() = _RealtimeClock;
+
+ /// A monotonically-increasing test clock.
+ ///
+ /// Each time [now] is called, the time increases by one minute.
+ ///
+ /// The `start` argument can be used to set the seed time for the clock.
+ /// The first value will be that time plus one minute.
+ /// By default, `start` is midnight on the first of January, 2000.
+ factory Clock.monotonicTest() = _MonotonicTestClock;
+
+ /// Returns the value of the clock.
+ DateTime get now;
+}
+
+class _RealtimeClock extends Clock {
+ const _RealtimeClock();
+
+ @override
+ DateTime get now => DateTime.now();
+}
+
+class _MonotonicTestClock extends Clock {
+ _MonotonicTestClock({
+ DateTime? start,
+ }) : _current = start ?? DateTime(2000);
+
+ DateTime _current;
+
+ @override
+ DateTime get now {
+ _current = _current.add(const Duration(minutes: 1));
+ return _current;
+ }
+}
diff --git a/pkgs/file/lib/src/backends/memory/common.dart b/pkgs/file/lib/src/backends/memory/common.dart
new file mode 100644
index 0000000..80e3c38
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/common.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/src/common.dart' as common;
+
+/// Generates a path to use in error messages.
+typedef PathGenerator = dynamic Function();
+
+/// Throws a `FileSystemException` if [object] is null.
+void checkExists(Object? object, PathGenerator path) {
+ if (object == null) {
+ throw common.noSuchFileOrDirectory(path() as String);
+ }
+}
diff --git a/pkgs/file/lib/src/backends/memory/memory_directory.dart b/pkgs/file/lib/src/backends/memory/memory_directory.dart
new file mode 100644
index 0000000..95fe542
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/memory_directory.dart
@@ -0,0 +1,184 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/common.dart' as common;
+import 'package:file/src/io.dart' as io;
+import 'package:meta/meta.dart';
+
+import 'common.dart';
+import 'memory_file.dart';
+import 'memory_file_system_entity.dart';
+import 'memory_link.dart';
+import 'node.dart';
+import 'operations.dart';
+import 'style.dart';
+import 'utils.dart' as utils;
+
+// Tracks a unique name for system temp directories, per filesystem
+// instance.
+final Expando<int> _systemTempCounter = Expando<int>();
+
+/// Internal implementation of [Directory].
+class MemoryDirectory extends MemoryFileSystemEntity
+ with common.DirectoryAddOnsMixin
+ implements Directory {
+ /// Instantiates a new [MemoryDirectory].
+ MemoryDirectory(NodeBasedFileSystem fileSystem, String path)
+ : super(fileSystem, path);
+
+ @override
+ io.FileSystemEntityType get expectedType => io.FileSystemEntityType.directory;
+
+ @override
+ Uri get uri {
+ return Uri.directory(path,
+ windows: fileSystem.style == FileSystemStyle.windows);
+ }
+
+ @override
+ bool existsSync() {
+ fileSystem.opHandle.call(path, FileSystemOp.exists);
+ return backingOrNull?.stat.type == expectedType;
+ }
+
+ @override
+ Future<Directory> create({bool recursive = false}) async {
+ createSync(recursive: recursive);
+ return this;
+ }
+
+ @override
+ void createSync({bool recursive = false}) {
+ fileSystem.opHandle(path, FileSystemOp.create);
+ Node? node = internalCreateSync(
+ followTailLink: true,
+ visitLinks: true,
+ createChild: (DirectoryNode parent, bool isFinalSegment) {
+ if (recursive || isFinalSegment) {
+ return DirectoryNode(parent);
+ }
+ return null;
+ },
+ );
+ if (node?.type != expectedType) {
+ // There was an existing non-directory node at this object's path
+ throw common.notADirectory(path);
+ }
+ }
+
+ @override
+ Future<Directory> createTemp([String? prefix]) async =>
+ createTempSync(prefix);
+
+ @override
+ Directory createTempSync([String? prefix]) {
+ prefix = '${prefix ?? ''}rand';
+ String fullPath = fileSystem.path.join(path, prefix);
+ String dirname = fileSystem.path.dirname(fullPath);
+ String basename = fileSystem.path.basename(fullPath);
+ DirectoryNode? node = fileSystem.findNode(dirname) as DirectoryNode?;
+ checkExists(node, () => dirname);
+ utils.checkIsDir(node!, () => dirname);
+ int tempCounter = _systemTempCounter[fileSystem] ?? 0;
+ String name() => '$basename$tempCounter';
+ while (node.children.containsKey(name())) {
+ tempCounter++;
+ }
+ _systemTempCounter[fileSystem] = tempCounter;
+ DirectoryNode tempDir = DirectoryNode(node);
+ node.children[name()] = tempDir;
+ return MemoryDirectory(fileSystem, fileSystem.path.join(dirname, name()))
+ ..createSync();
+ }
+
+ @override
+ Future<Directory> rename(String newPath) async => renameSync(newPath);
+
+ @override
+ Directory renameSync(String newPath) => internalRenameSync<DirectoryNode>(
+ newPath,
+ validateOverwriteExistingEntity: (DirectoryNode existingNode) {
+ if (existingNode.children.isNotEmpty) {
+ throw common.directoryNotEmpty(newPath);
+ }
+ },
+ ) as Directory;
+
+ @override
+ Directory get parent =>
+ (backingOrNull?.isRoot ?? false) ? this : super.parent;
+
+ @override
+ Directory get absolute => super.absolute as Directory;
+
+ @override
+ Stream<FileSystemEntity> list({
+ bool recursive = false,
+ bool followLinks = true,
+ }) =>
+ Stream<FileSystemEntity>.fromIterable(listSync(
+ recursive: recursive,
+ followLinks: followLinks,
+ ));
+
+ @override
+ List<FileSystemEntity> listSync({
+ bool recursive = false,
+ bool followLinks = true,
+ }) {
+ DirectoryNode node = backing as DirectoryNode;
+ List<FileSystemEntity> listing = <FileSystemEntity>[];
+ List<_PendingListTask> tasks = <_PendingListTask>[
+ _PendingListTask(
+ node,
+ path.endsWith(fileSystem.path.separator)
+ ? path.substring(0, path.length - 1)
+ : path,
+ <LinkNode>{},
+ ),
+ ];
+ while (tasks.isNotEmpty) {
+ _PendingListTask task = tasks.removeLast();
+ task.dir.children.forEach((String name, Node child) {
+ Set<LinkNode> breadcrumbs = Set<LinkNode>.from(task.breadcrumbs);
+ String childPath = fileSystem.path.join(task.path, name);
+ while (followLinks &&
+ utils.isLink(child) &&
+ breadcrumbs.add(child as LinkNode)) {
+ Node? referent = child.referentOrNull;
+ if (referent != null) {
+ child = referent;
+ }
+ }
+ if (utils.isDirectory(child)) {
+ listing.add(MemoryDirectory(fileSystem, childPath));
+ if (recursive) {
+ tasks.add(_PendingListTask(
+ child as DirectoryNode, childPath, breadcrumbs));
+ }
+ } else if (utils.isLink(child)) {
+ listing.add(MemoryLink(fileSystem, childPath));
+ } else if (utils.isFile(child)) {
+ listing.add(MemoryFile(fileSystem, childPath));
+ }
+ });
+ }
+ return listing;
+ }
+
+ @override
+ @protected
+ Directory clone(String path) => MemoryDirectory(fileSystem, path);
+
+ @override
+ String toString() => "MemoryDirectory: '$path'";
+}
+
+class _PendingListTask {
+ _PendingListTask(this.dir, this.path, this.breadcrumbs);
+ final DirectoryNode dir;
+ final String path;
+ final Set<LinkNode> breadcrumbs;
+}
diff --git a/pkgs/file/lib/src/backends/memory/memory_file.dart b/pkgs/file/lib/src/backends/memory/memory_file.dart
new file mode 100644
index 0000000..ba4faab
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/memory_file.dart
@@ -0,0 +1,470 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:math' as math show min;
+import 'dart:typed_data';
+
+import 'package:file/file.dart';
+import 'package:file/src/backends/memory/operations.dart';
+import 'package:file/src/common.dart' as common;
+import 'package:file/src/io.dart' as io;
+import 'package:meta/meta.dart';
+
+import 'common.dart';
+import 'memory_file_system_entity.dart';
+import 'memory_random_access_file.dart';
+import 'node.dart';
+import 'utils.dart' as utils;
+
+/// Internal implementation of [File].
+class MemoryFile extends MemoryFileSystemEntity implements File {
+ /// Instantiates a new [MemoryFile].
+ const MemoryFile(NodeBasedFileSystem fileSystem, String path)
+ : super(fileSystem, path);
+
+ FileNode get _resolvedBackingOrCreate {
+ Node? node = backingOrNull;
+ if (node == null) {
+ node = _doCreate();
+ } else {
+ node = utils.isLink(node)
+ ? utils.resolveLinks(node as LinkNode, () => path)
+ : node;
+ utils.checkType(expectedType, node.type, () => path);
+ }
+ return node as FileNode;
+ }
+
+ @override
+ io.FileSystemEntityType get expectedType => io.FileSystemEntityType.file;
+
+ @override
+ bool existsSync() {
+ fileSystem.opHandle.call(path, FileSystemOp.exists);
+ return backingOrNull?.stat.type == expectedType;
+ }
+
+ @override
+ Future<File> create({bool recursive = false, bool exclusive = false}) async {
+ createSync(recursive: recursive, exclusive: exclusive);
+ return this;
+ }
+
+ // TODO(dartbug.com/49647): Pass `exclusive` through after it lands.
+ @override
+ void createSync({bool recursive = false, bool exclusive = false}) {
+ fileSystem.opHandle(path, FileSystemOp.create);
+ _doCreate(recursive: recursive /*, exclusive: exclusive*/);
+ }
+
+ Node? _doCreate({bool recursive = false}) {
+ Node? node = internalCreateSync(
+ followTailLink: true,
+ createChild: (DirectoryNode parent, bool isFinalSegment) {
+ if (isFinalSegment) {
+ return FileNode(parent);
+ } else if (recursive) {
+ return DirectoryNode(parent);
+ }
+ return null;
+ },
+ );
+ if (node?.type != expectedType) {
+ // There was an existing non-file entity at this object's path
+ assert(node?.type == FileSystemEntityType.directory);
+ throw common.isADirectory(path);
+ }
+ return node;
+ }
+
+ @override
+ Future<File> rename(String newPath) async => renameSync(newPath);
+
+ @override
+ File renameSync(String newPath) => internalRenameSync(
+ newPath,
+ followTailLink: true,
+ checkType: (Node node) {
+ FileSystemEntityType actualType = node.stat.type;
+ if (actualType != expectedType) {
+ throw actualType == FileSystemEntityType.notFound
+ ? common.noSuchFileOrDirectory(path)
+ : common.isADirectory(path);
+ }
+ },
+ ) as File;
+
+ @override
+ Future<File> copy(String newPath) async => copySync(newPath);
+
+ @override
+ File copySync(String newPath) {
+ fileSystem.opHandle(path, FileSystemOp.copy);
+ FileNode sourceNode = resolvedBacking as FileNode;
+ fileSystem.findNode(
+ newPath,
+ segmentVisitor: (
+ DirectoryNode parent,
+ String childName,
+ Node? child,
+ int currentSegment,
+ int finalSegment,
+ ) {
+ if (currentSegment == finalSegment) {
+ if (child != null) {
+ if (utils.isLink(child)) {
+ List<String> ledger = <String>[];
+ child = utils.resolveLinks(child as LinkNode, () => newPath,
+ ledger: ledger);
+ checkExists(child, () => newPath);
+ parent = child.parent;
+ childName = ledger.last;
+ assert(parent.children.containsKey(childName));
+ }
+ utils.checkType(expectedType, child.type, () => newPath);
+ parent.children.remove(childName);
+ }
+ FileNode newNode = FileNode(parent);
+ newNode.copyFrom(sourceNode);
+ parent.children[childName] = newNode;
+ }
+ return child;
+ },
+ );
+ return clone(newPath);
+ }
+
+ @override
+ Future<int> length() async => lengthSync();
+
+ @override
+ int lengthSync() => (resolvedBacking as FileNode).size;
+
+ @override
+ File get absolute => super.absolute as File;
+
+ @override
+ Future<DateTime> lastAccessed() async => lastAccessedSync();
+
+ @override
+ DateTime lastAccessedSync() => (resolvedBacking as FileNode).stat.accessed;
+
+ @override
+ Future<dynamic> setLastAccessed(DateTime time) async =>
+ setLastAccessedSync(time);
+
+ @override
+ void setLastAccessedSync(DateTime time) {
+ FileNode node = resolvedBacking as FileNode;
+ node.accessed = time.millisecondsSinceEpoch;
+ }
+
+ @override
+ Future<DateTime> lastModified() async => lastModifiedSync();
+
+ @override
+ DateTime lastModifiedSync() => (resolvedBacking as FileNode).stat.modified;
+
+ @override
+ Future<dynamic> setLastModified(DateTime time) async =>
+ setLastModifiedSync(time);
+
+ @override
+ void setLastModifiedSync(DateTime time) {
+ FileNode node = resolvedBacking as FileNode;
+ node.modified = time.millisecondsSinceEpoch;
+ }
+
+ @override
+ Future<io.RandomAccessFile> open(
+ {io.FileMode mode = io.FileMode.read}) async =>
+ openSync(mode: mode);
+
+ @override
+ io.RandomAccessFile openSync({io.FileMode mode = io.FileMode.read}) {
+ fileSystem.opHandle(path, FileSystemOp.open);
+ if (utils.isWriteMode(mode) && !existsSync()) {
+ // [resolvedBacking] requires that the file already exists, so we must
+ // create it here first.
+ createSync();
+ }
+
+ return MemoryRandomAccessFile(path, resolvedBacking as FileNode, mode);
+ }
+
+ @override
+ Stream<List<int>> openRead([int? start, int? end]) {
+ fileSystem.opHandle(path, FileSystemOp.open);
+ try {
+ FileNode node = resolvedBacking as FileNode;
+ Uint8List content = node.content;
+ if (start != null) {
+ content = end == null
+ ? content.sublist(start)
+ : content.sublist(start, math.min(end, content.length));
+ }
+ return Stream.value(content);
+ } catch (e) {
+ return Stream.error(e);
+ }
+ }
+
+ @override
+ io.IOSink openWrite({
+ io.FileMode mode = io.FileMode.write,
+ Encoding encoding = utf8,
+ }) {
+ fileSystem.opHandle(path, FileSystemOp.open);
+ if (!utils.isWriteMode(mode)) {
+ throw ArgumentError.value(mode, 'mode',
+ 'Must be either WRITE, APPEND, WRITE_ONLY, or WRITE_ONLY_APPEND');
+ }
+ return _FileSink.fromFile(this, mode, encoding);
+ }
+
+ @override
+ Future<Uint8List> readAsBytes() async => readAsBytesSync();
+
+ @override
+ Uint8List readAsBytesSync() {
+ fileSystem.opHandle(path, FileSystemOp.read);
+ return Uint8List.fromList((resolvedBacking as FileNode).content);
+ }
+
+ @override
+ Future<String> readAsString({Encoding encoding = utf8}) async =>
+ readAsStringSync(encoding: encoding);
+
+ @override
+ String readAsStringSync({Encoding encoding = utf8}) {
+ try {
+ return encoding.decode(readAsBytesSync());
+ } on FormatException catch (err) {
+ throw FileSystemException(err.message, path);
+ }
+ }
+
+ @override
+ Future<List<String>> readAsLines({Encoding encoding = utf8}) async =>
+ readAsLinesSync(encoding: encoding);
+
+ @override
+ List<String> readAsLinesSync({Encoding encoding = utf8}) {
+ String str = readAsStringSync(encoding: encoding);
+
+ if (str.isEmpty) {
+ return <String>[];
+ }
+
+ final List<String> lines = str.split('\n');
+ if (str.endsWith('\n')) {
+ // A final newline should not create an additional line.
+ lines.removeLast();
+ }
+
+ return lines;
+ }
+
+ @override
+ Future<File> writeAsBytes(
+ List<int> bytes, {
+ io.FileMode mode = io.FileMode.write,
+ bool flush = false,
+ }) async {
+ writeAsBytesSync(bytes, mode: mode, flush: flush);
+ return this;
+ }
+
+ @override
+ void writeAsBytesSync(
+ List<int> bytes, {
+ io.FileMode mode = io.FileMode.write,
+ bool flush = false,
+ }) {
+ if (!utils.isWriteMode(mode)) {
+ throw common.badFileDescriptor(path);
+ }
+ FileNode node = _resolvedBackingOrCreate;
+ _truncateIfNecessary(node, mode);
+ fileSystem.opHandle(path, FileSystemOp.write);
+ node.write(bytes);
+ node.touch();
+ }
+
+ @override
+ Future<File> writeAsString(
+ String contents, {
+ io.FileMode mode = io.FileMode.write,
+ Encoding encoding = utf8,
+ bool flush = false,
+ }) async {
+ writeAsStringSync(contents, mode: mode, encoding: encoding, flush: flush);
+ return this;
+ }
+
+ @override
+ void writeAsStringSync(
+ String contents, {
+ io.FileMode mode = io.FileMode.write,
+ Encoding encoding = utf8,
+ bool flush = false,
+ }) =>
+ writeAsBytesSync(encoding.encode(contents), mode: mode, flush: flush);
+
+ @override
+ @protected
+ File clone(String path) => MemoryFile(fileSystem, path);
+
+ void _truncateIfNecessary(FileNode node, io.FileMode mode) {
+ if (mode == io.FileMode.write || mode == io.FileMode.writeOnly) {
+ node.clear();
+ }
+ }
+
+ @override
+ String toString() => "MemoryFile: '$path'";
+}
+
+/// Implementation of an [io.IOSink] that's backed by a [FileNode].
+class _FileSink implements io.IOSink {
+ factory _FileSink.fromFile(
+ MemoryFile file,
+ io.FileMode mode,
+ Encoding encoding,
+ ) {
+ late FileNode node;
+ Exception? deferredException;
+
+ // Resolve the backing immediately to ensure that the [FileNode] we write
+ // to is the same as when [openWrite] was called. This can matter if the
+ // file is moved or removed while open.
+ try {
+ node = file._resolvedBackingOrCreate;
+ } on Exception catch (e) {
+ // For behavioral consistency with [LocalFile], do not report failures
+ // immediately.
+ deferredException = e;
+ }
+
+ Future<FileNode> future = Future<FileNode>.microtask(() {
+ if (deferredException != null) {
+ throw deferredException;
+ }
+ file._truncateIfNecessary(node, mode);
+ return node;
+ });
+ return _FileSink._(future, encoding);
+ }
+
+ _FileSink._(Future<FileNode> node, this.encoding) : _pendingWrites = node;
+
+ final Completer<void> _completer = Completer<void>();
+
+ Future<FileNode> _pendingWrites;
+ Completer<void>? _streamCompleter;
+ bool _isClosed = false;
+
+ @override
+ Encoding encoding;
+
+ bool get isStreaming => !(_streamCompleter?.isCompleted ?? true);
+
+ @override
+ void add(List<int> data) {
+ _checkNotStreaming();
+ if (_isClosed) {
+ throw StateError('StreamSink is closed');
+ }
+
+ _addData(data);
+ }
+
+ @override
+ void write(Object? obj) => add(encoding.encode(obj?.toString() ?? 'null'));
+
+ @override
+ void writeAll(Iterable<dynamic> objects, [String separator = '']) {
+ bool firstIter = true;
+ for (dynamic obj in objects) {
+ if (!firstIter) {
+ write(separator);
+ }
+ firstIter = false;
+ write(obj);
+ }
+ }
+
+ @override
+ void writeln([Object? obj = '']) {
+ write(obj);
+ write('\n');
+ }
+
+ @override
+ void writeCharCode(int charCode) => write(String.fromCharCode(charCode));
+
+ @override
+ void addError(Object error, [StackTrace? stackTrace]) {
+ _checkNotStreaming();
+ _completer.completeError(error, stackTrace);
+ }
+
+ @override
+ Future<void> addStream(Stream<List<int>> stream) {
+ _checkNotStreaming();
+ _streamCompleter = Completer<void>();
+
+ stream.listen(
+ (List<int> data) => _addData(data),
+ cancelOnError: true,
+ onError: (Object error, StackTrace stackTrace) {
+ _streamCompleter!.completeError(error, stackTrace);
+ _streamCompleter = null;
+ },
+ onDone: () {
+ _streamCompleter!.complete();
+ _streamCompleter = null;
+ },
+ );
+ return _streamCompleter!.future;
+ }
+
+ @override
+ Future<void> flush() {
+ _checkNotStreaming();
+ return _pendingWrites;
+ }
+
+ @override
+ Future<void> close() {
+ _checkNotStreaming();
+ if (!_isClosed) {
+ _isClosed = true;
+ _pendingWrites.then(
+ (_) => _completer.complete(),
+ onError: (Object error, StackTrace stackTrace) =>
+ _completer.completeError(error, stackTrace),
+ );
+ }
+ return _completer.future;
+ }
+
+ @override
+ Future<void> get done => _completer.future;
+
+ void _addData(List<int> data) {
+ _pendingWrites = _pendingWrites.then((FileNode node) {
+ node.write(data);
+ return node;
+ });
+ }
+
+ void _checkNotStreaming() {
+ if (isStreaming) {
+ throw StateError('StreamSink is bound to a stream');
+ }
+ }
+}
diff --git a/pkgs/file/lib/src/backends/memory/memory_file_stat.dart b/pkgs/file/lib/src/backends/memory/memory_file_stat.dart
new file mode 100644
index 0000000..94f86d1
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/memory_file_stat.dart
@@ -0,0 +1,68 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/src/io.dart' as io;
+
+/// Internal implementation of [io.FileStat].
+class MemoryFileStat implements io.FileStat {
+ /// Creates a new [MemoryFileStat] with the specified properties.
+ const MemoryFileStat(
+ this.changed,
+ this.modified,
+ this.accessed,
+ this.type,
+ this.mode,
+ this.size,
+ );
+
+ MemoryFileStat._internalNotFound()
+ : changed = DateTime(0),
+ modified = DateTime(0),
+ accessed = DateTime(0),
+ type = io.FileSystemEntityType.notFound,
+ mode = 0,
+ size = -1;
+
+ /// Shared instance representing a non-existent entity.
+ static final MemoryFileStat notFound = MemoryFileStat._internalNotFound();
+
+ @override
+ final DateTime changed;
+
+ @override
+ final DateTime modified;
+
+ @override
+ final DateTime accessed;
+
+ @override
+ final io.FileSystemEntityType type;
+
+ @override
+ final int mode;
+
+ @override
+ final int size;
+
+ @override
+ String modeString() {
+ int permissions = mode & 0xFFF;
+ List<String> codes = const <String>[
+ '---',
+ '--x',
+ '-w-',
+ '-wx',
+ 'r--',
+ 'r-x',
+ 'rw-',
+ 'rwx',
+ ];
+ List<String> result = <String>[];
+ result
+ ..add(codes[(permissions >> 6) & 0x7])
+ ..add(codes[(permissions >> 3) & 0x7])
+ ..add(codes[permissions & 0x7]);
+ return result.join();
+ }
+}
diff --git a/pkgs/file/lib/src/backends/memory/memory_file_system.dart b/pkgs/file/lib/src/backends/memory/memory_file_system.dart
new file mode 100644
index 0000000..f3cdaee
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/memory_file_system.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/backends/memory/operations.dart';
+import 'package:file/src/io.dart' as io;
+import 'package:path/path.dart' as p;
+
+import 'clock.dart';
+import 'common.dart';
+import 'memory_directory.dart';
+import 'memory_file.dart';
+import 'memory_file_stat.dart';
+import 'memory_link.dart';
+import 'node.dart';
+import 'style.dart';
+import 'utils.dart' as utils;
+
+const String _thisDir = '.';
+const String _parentDir = '..';
+
+void _defaultOpHandle(String context, FileSystemOp operation) {}
+
+/// An implementation of [FileSystem] that exists entirely in memory with an
+/// internal representation loosely based on the Filesystem Hierarchy Standard.
+///
+/// [MemoryFileSystem] is suitable for mocking and tests, as well as for
+/// caching or staging before writing or reading to a live system.
+///
+/// This implementation of the [FileSystem] interface does not directly use
+/// any `dart:io` APIs; it merely uses the library's enum values and interfaces.
+/// As such, it is suitable for use in the browser.
+abstract class MemoryFileSystem implements StyleableFileSystem {
+ /// Creates a new `MemoryFileSystem`.
+ ///
+ /// The file system will be empty, and the current directory will be the
+ /// root directory.
+ ///
+ /// The clock will be a real-time clock; file modification times will
+ /// reflect the real time as reported by the operating system.
+ ///
+ /// If [style] is specified, the file system will use the specified path
+ /// style. The default is [FileSystemStyle.posix].
+ factory MemoryFileSystem({
+ FileSystemStyle style = FileSystemStyle.posix,
+ void Function(String context, FileSystemOp operation) opHandle =
+ _defaultOpHandle,
+ }) =>
+ _MemoryFileSystem(
+ style: style,
+ clock: const Clock.realTime(),
+ opHandle: opHandle,
+ );
+
+ /// Creates a new `MemoryFileSystem` that has a fake clock.
+ ///
+ /// The file system will be empty, and the current directory will be the
+ /// root directory.
+ ///
+ /// The clock will increase monotonically each time it is used, disconnected
+ /// from any real-world clock.
+ ///
+ /// If [style] is specified, the file system will use the specified path
+ /// style. The default is [FileSystemStyle.posix].
+ factory MemoryFileSystem.test({
+ FileSystemStyle style = FileSystemStyle.posix,
+ void Function(String context, FileSystemOp operation) opHandle =
+ _defaultOpHandle,
+ }) =>
+ _MemoryFileSystem(
+ style: style,
+ clock: Clock.monotonicTest(),
+ opHandle: opHandle,
+ );
+}
+
+/// Internal implementation of [MemoryFileSystem].
+class _MemoryFileSystem extends FileSystem
+ implements MemoryFileSystem, NodeBasedFileSystem {
+ _MemoryFileSystem({
+ this.style = FileSystemStyle.posix,
+ required this.clock,
+ this.opHandle = _defaultOpHandle,
+ }) : _context = style.contextFor(style.root) {
+ _root = RootNode(this);
+ }
+
+ RootNode? _root;
+ String? _systemTemp;
+ p.Context _context;
+
+ @override
+ final Function(String context, FileSystemOp operation) opHandle;
+
+ @override
+ final Clock clock;
+
+ @override
+ final FileSystemStyle style;
+
+ @override
+ RootNode? get root => _root;
+
+ @override
+ String get cwd => _context.current;
+
+ @override
+ Directory directory(dynamic path) => MemoryDirectory(this, getPath(path));
+
+ @override
+ File file(dynamic path) => MemoryFile(this, getPath(path));
+
+ @override
+ Link link(dynamic path) => MemoryLink(this, getPath(path));
+
+ @override
+ p.Context get path => _context;
+
+ /// Gets the system temp directory. This directory will be created on-demand
+ /// in the root of the file system. Once created, its location is fixed for
+ /// the life of the process.
+ @override
+ Directory get systemTempDirectory {
+ _systemTemp ??= directory(style.root).createTempSync('.tmp_').path;
+ return directory(_systemTemp)..createSync();
+ }
+
+ @override
+ Directory get currentDirectory => directory(cwd);
+
+ @override
+ set currentDirectory(dynamic path) {
+ String value;
+ if (path is io.Directory) {
+ value = path.path;
+ } else if (path is String) {
+ value = path;
+ } else {
+ throw ArgumentError('Invalid type for "path": ${path?.runtimeType}');
+ }
+
+ value = directory(value).resolveSymbolicLinksSync();
+ Node? node = findNode(value);
+ checkExists(node, () => value);
+ utils.checkIsDir(node!, () => value);
+ assert(_context.isAbsolute(value));
+ _context = style.contextFor(value);
+ }
+
+ @override
+ Future<io.FileStat> stat(String path) async => statSync(path);
+
+ @override
+ io.FileStat statSync(String path) {
+ try {
+ return findNode(path)?.stat ?? MemoryFileStat.notFound;
+ } on io.FileSystemException {
+ return MemoryFileStat.notFound;
+ }
+ }
+
+ @override
+ Future<bool> identical(String path1, String path2) async =>
+ identicalSync(path1, path2);
+
+ @override
+ bool identicalSync(String path1, String path2) {
+ Node? node1 = findNode(path1);
+ checkExists(node1, () => path1);
+ Node? node2 = findNode(path2);
+ checkExists(node2, () => path2);
+ return node1 != null && node1 == node2;
+ }
+
+ @override
+ bool get isWatchSupported => false;
+
+ @override
+ Future<io.FileSystemEntityType> type(
+ String path, {
+ bool followLinks = true,
+ }) async =>
+ typeSync(path, followLinks: followLinks);
+
+ @override
+ io.FileSystemEntityType typeSync(String path, {bool followLinks = true}) {
+ Node? node;
+ try {
+ node = findNode(path, followTailLink: followLinks);
+ } on io.FileSystemException {
+ node = null;
+ }
+ if (node == null) {
+ return io.FileSystemEntityType.notFound;
+ }
+ return node.type;
+ }
+
+ /// Gets the node backing for the current working directory. Note that this
+ /// can return null if the directory has been deleted or moved from under our
+ /// feet.
+ DirectoryNode? get _current => findNode(cwd) as DirectoryNode?;
+
+ @override
+ Node? findNode(
+ String path, {
+ Node? reference,
+ SegmentVisitor? segmentVisitor,
+ bool visitLinks = false,
+ List<String>? pathWithSymlinks,
+ bool followTailLink = false,
+ }) {
+ if (path.isEmpty) {
+ return null;
+ } else if (_context.isAbsolute(path)) {
+ reference = _root;
+ path = path.substring(style.drive.length);
+ } else {
+ reference ??= _current;
+ }
+
+ List<String> parts = path.split(style.separator)
+ ..removeWhere(utils.isEmpty);
+ DirectoryNode? directory = reference?.directory;
+ Node? child = directory;
+
+ int finalSegment = parts.length - 1;
+ for (int i = 0; i <= finalSegment; i++) {
+ String basename = parts[i];
+ assert(basename.isNotEmpty);
+
+ switch (basename) {
+ case _thisDir:
+ child = directory;
+ break;
+ case _parentDir:
+ child = directory?.parent;
+ directory = directory?.parent;
+ break;
+ default:
+ child = directory?.children[basename];
+ }
+
+ if (pathWithSymlinks != null) {
+ pathWithSymlinks.add(basename);
+ }
+
+ // Generates a subpath for the current segment.
+ String subpath() => parts.sublist(0, i + 1).join(_context.separator);
+
+ if (utils.isLink(child) && (i < finalSegment || followTailLink)) {
+ if (visitLinks || segmentVisitor == null) {
+ if (segmentVisitor != null) {
+ child =
+ segmentVisitor(directory!, basename, child, i, finalSegment);
+ }
+ child = utils.resolveLinks(child as LinkNode, subpath,
+ ledger: pathWithSymlinks);
+ } else {
+ child = utils.resolveLinks(
+ child as LinkNode,
+ subpath,
+ ledger: pathWithSymlinks,
+ tailVisitor: (DirectoryNode parent, String childName, Node? child) {
+ return segmentVisitor(parent, childName, child, i, finalSegment);
+ },
+ );
+ }
+ } else if (segmentVisitor != null) {
+ child = segmentVisitor(directory!, basename, child, i, finalSegment);
+ }
+
+ if (i < finalSegment) {
+ checkExists(child, subpath);
+ utils.checkIsDir(child!, subpath);
+ directory = child as DirectoryNode;
+ }
+ }
+ return child;
+ }
+}
diff --git a/pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart b/pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart
new file mode 100644
index 0000000..ad987d7
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart
@@ -0,0 +1,309 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/common.dart' as common;
+import 'package:file/src/io.dart' as io;
+import 'package:meta/meta.dart';
+
+import 'common.dart';
+import 'memory_directory.dart';
+import 'node.dart';
+import 'operations.dart';
+import 'style.dart';
+import 'utils.dart' as utils;
+
+/// Validator function for use with `_renameSync`. This will be invoked if the
+/// rename would overwrite an existing entity at the new path. If this operation
+/// should not be allowed, this function is expected to throw a
+/// [io.FileSystemException]. The lack of such an exception will be interpreted
+/// as the overwrite being permissible.
+typedef RenameOverwriteValidator<T extends Node> = void Function(
+ T existingNode);
+
+/// Base class for all in-memory file system entity types.
+abstract class MemoryFileSystemEntity implements FileSystemEntity {
+ /// Constructor for subclasses.
+ const MemoryFileSystemEntity(this.fileSystem, this.path);
+
+ @override
+ final NodeBasedFileSystem fileSystem;
+
+ @override
+ final String path;
+
+ @override
+ String get dirname => fileSystem.path.dirname(path);
+
+ @override
+ String get basename => fileSystem.path.basename(path);
+
+ /// Returns the expected type of this entity, which may differ from the type
+ /// of the node that's found at the path specified by this entity.
+ io.FileSystemEntityType get expectedType;
+
+ /// Gets the node that backs this file system entity, or null if this
+ /// entity does not exist.
+ @protected
+ Node? get backingOrNull {
+ try {
+ return fileSystem.findNode(path);
+ } on io.FileSystemException {
+ return null;
+ }
+ }
+
+ /// Gets the node that backs this file system entity. Throws a
+ /// [io.FileSystemException] if this entity doesn't exist.
+ ///
+ /// The type of the node is not guaranteed to match [expectedType].
+ @protected
+ Node get backing {
+ Node? node = fileSystem.findNode(path);
+ checkExists(node, () => path);
+ return node!;
+ }
+
+ /// Gets the node that backs this file system entity, or if that node is
+ /// a symbolic link, the target node. This also will check that the type of
+ /// the node (after symlink resolution) matches [expectedType]. If the type
+ /// doesn't match, this will throw a [io.FileSystemException].
+ @protected
+ Node get resolvedBacking {
+ Node node = backing;
+ node = utils.isLink(node)
+ ? utils.resolveLinks(node as LinkNode, () => path)
+ : node;
+ utils.checkType(expectedType, node.type, () => path);
+ return node;
+ }
+
+ /// Checks the expected type of this file system entity against the specified
+ /// node's `stat` type, throwing a [FileSystemException] if the types don't
+ /// match. Note that since this checks the node's `stat` type, symbolic links
+ /// will be resolved to their target type for the purpose of this validation.
+ ///
+ /// Protected methods that accept a `checkType` argument will default to this
+ /// method if the `checkType` argument is unspecified.
+ @protected
+ void defaultCheckType(Node node) {
+ utils.checkType(expectedType, node.stat.type, () => path);
+ }
+
+ @override
+ Uri get uri {
+ return Uri.file(path, windows: fileSystem.style == FileSystemStyle.windows);
+ }
+
+ @override
+ Future<bool> exists() async => existsSync();
+
+ @override
+ Future<String> resolveSymbolicLinks() async => resolveSymbolicLinksSync();
+
+ @override
+ String resolveSymbolicLinksSync() {
+ if (path.isEmpty) {
+ throw common.noSuchFileOrDirectory(path);
+ }
+ List<String> ledger = <String>[];
+ if (isAbsolute) {
+ ledger.add(fileSystem.style.drive);
+ }
+ Node? node = fileSystem.findNode(path,
+ pathWithSymlinks: ledger, followTailLink: true);
+ checkExists(node, () => path);
+ String resolved = ledger.join(fileSystem.path.separator);
+ if (resolved == fileSystem.style.drive) {
+ resolved = fileSystem.style.root;
+ } else if (!fileSystem.path.isAbsolute(resolved)) {
+ resolved = fileSystem.cwd + fileSystem.path.separator + resolved;
+ }
+ return fileSystem.path.normalize(resolved);
+ }
+
+ @override
+ Future<io.FileStat> stat() => fileSystem.stat(path);
+
+ @override
+ io.FileStat statSync() => fileSystem.statSync(path);
+
+ @override
+ Future<FileSystemEntity> delete({bool recursive = false}) async {
+ deleteSync(recursive: recursive);
+ return this;
+ }
+
+ @override
+ void deleteSync({bool recursive = false}) =>
+ internalDeleteSync(recursive: recursive);
+
+ @override
+ Stream<io.FileSystemEvent> watch({
+ int events = io.FileSystemEvent.all,
+ bool recursive = false,
+ }) =>
+ throw UnsupportedError('Watching not supported in MemoryFileSystem');
+
+ @override
+ bool get isAbsolute => fileSystem.path.isAbsolute(path);
+
+ @override
+ FileSystemEntity get absolute {
+ String absolutePath = path;
+ if (!fileSystem.path.isAbsolute(absolutePath)) {
+ absolutePath = fileSystem.path.join(fileSystem.cwd, absolutePath);
+ }
+ return clone(absolutePath);
+ }
+
+ @override
+ Directory get parent => MemoryDirectory(fileSystem, dirname);
+
+ /// Helper method for subclasses wishing to synchronously create this entity.
+ /// This method will traverse the path to this entity one segment at a time,
+ /// calling [createChild] for each segment whose child does not already exist.
+ ///
+ /// When [createChild] is invoked:
+ /// - `parent` will be the parent node for the current segment and is
+ /// guaranteed to be non-null.
+ /// - `isFinalSegment` will indicate whether the current segment is the tail
+ /// segment, which in turn indicates that this is the segment into which to
+ /// create the node for this entity.
+ ///
+ /// This method returns with the backing node for the entity at this [path].
+ /// If an entity already existed at this path, [createChild] will not be
+ /// invoked at all, and this method will return with the backing node for the
+ /// existing entity (whose type may differ from this entity's type).
+ ///
+ /// If [followTailLink] is true and the result node is a link, this will
+ /// resolve it to its target prior to returning it.
+ @protected
+ Node? internalCreateSync({
+ required Node? Function(DirectoryNode parent, bool isFinalSegment)
+ createChild,
+ bool followTailLink = false,
+ bool visitLinks = false,
+ }) {
+ return fileSystem.findNode(
+ path,
+ followTailLink: followTailLink,
+ visitLinks: visitLinks,
+ segmentVisitor: (
+ DirectoryNode parent,
+ String childName,
+ Node? child,
+ int currentSegment,
+ int finalSegment,
+ ) {
+ if (child == null) {
+ assert(!parent.children.containsKey(childName));
+ child = createChild(parent, currentSegment == finalSegment);
+ if (child != null) {
+ parent.children[childName] = child;
+ }
+ }
+ return child;
+ },
+ );
+ }
+
+ /// Helper method for subclasses wishing to synchronously rename this entity.
+ /// This method will look for an existing file system entity at the location
+ /// identified by [newPath], and if it finds an existing entity, it will check
+ /// the following:
+ ///
+ /// - If the entity is of a different type than this entity, the operation
+ /// will fail, and a [io.FileSystemException] will be thrown.
+ /// - If the caller has specified [validateOverwriteExistingEntity], then that
+ /// method will be invoked and passed the node backing of the existing
+ /// entity that would overwritten by the rename action. That callback is
+ /// expected to throw a [io.FileSystemException] if overwriting the existing
+ /// entity is not allowed.
+ ///
+ /// If the previous two checks pass, or if there was no existing entity at
+ /// the specified location, this will perform the rename.
+ ///
+ /// If [newPath] cannot be traversed to because its directory does not exist,
+ /// a [io.FileSystemException] will be thrown.
+ ///
+ /// If [followTailLink] is true and there is an existing link at the location
+ /// identified by [newPath], this will resolve the link to its target prior
+ /// to running the validation checks above.
+ ///
+ /// If [checkType] is specified, it will be used to validate that the file
+ /// system entity that exists at [path] is of the expected type. By default,
+ /// [defaultCheckType] is used to perform this validation.
+ @protected
+ FileSystemEntity internalRenameSync<T extends Node>(
+ String newPath, {
+ RenameOverwriteValidator<T>? validateOverwriteExistingEntity,
+ bool followTailLink = false,
+ utils.TypeChecker? checkType,
+ }) {
+ Node node = backing;
+ (checkType ?? defaultCheckType)(node);
+ fileSystem.findNode(
+ newPath,
+ segmentVisitor: (
+ DirectoryNode parent,
+ String childName,
+ Node? child,
+ int currentSegment,
+ int finalSegment,
+ ) {
+ if (currentSegment == finalSegment) {
+ if (child != null) {
+ if (followTailLink) {
+ FileSystemEntityType childType = child.stat.type;
+ if (childType != FileSystemEntityType.notFound) {
+ utils.checkType(expectedType, child.stat.type, () => newPath);
+ }
+ } else {
+ utils.checkType(expectedType, child.type, () => newPath);
+ }
+ if (validateOverwriteExistingEntity != null) {
+ validateOverwriteExistingEntity(child as T);
+ }
+ parent.children.remove(childName);
+ }
+ node.parent.children.remove(basename);
+ parent.children[childName] = node;
+ node.parent = parent;
+ }
+ return child;
+ },
+ );
+ return clone(newPath);
+ }
+
+ /// Deletes this entity from the node tree.
+ ///
+ /// If [checkType] is specified, it will be used to validate that the file
+ /// system entity that exists at [path] is of the expected type. By default,
+ /// [defaultCheckType] is used to perform this validation.
+ @protected
+ void internalDeleteSync({
+ bool recursive = false,
+ utils.TypeChecker? checkType,
+ }) {
+ fileSystem.opHandle(path, FileSystemOp.delete);
+ Node node = backing;
+ if (!recursive) {
+ if (node is DirectoryNode && node.children.isNotEmpty) {
+ throw common.directoryNotEmpty(path);
+ }
+ (checkType ?? defaultCheckType)(node);
+ }
+ // Once we remove this reference, the node and all its children will be
+ // garbage collected; we don't need to explicitly delete all children in
+ // the recursive:true case.
+ node.parent.children.remove(basename);
+ }
+
+ /// Creates a new entity with the same type as this entity but with the
+ /// specified path.
+ @protected
+ FileSystemEntity clone(String path);
+}
diff --git a/pkgs/file/lib/src/backends/memory/memory_link.dart b/pkgs/file/lib/src/backends/memory/memory_link.dart
new file mode 100644
index 0000000..7d5afb4
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/memory_link.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/common.dart' as common;
+import 'package:file/src/io.dart' as io;
+import 'package:meta/meta.dart';
+
+import 'memory_file_system_entity.dart';
+import 'node.dart';
+import 'operations.dart';
+import 'utils.dart' as utils;
+
+/// Internal implementation of [Link].
+class MemoryLink extends MemoryFileSystemEntity implements Link {
+ /// Instantiates a new [MemoryLink].
+ const MemoryLink(NodeBasedFileSystem fileSystem, String path)
+ : super(fileSystem, path);
+
+ @override
+ io.FileSystemEntityType get expectedType => io.FileSystemEntityType.link;
+
+ @override
+ bool existsSync() {
+ fileSystem.opHandle.call(path, FileSystemOp.exists);
+ return backingOrNull?.type == expectedType;
+ }
+
+ @override
+ Future<Link> rename(String newPath) async => renameSync(newPath);
+
+ @override
+ Link renameSync(String newPath) => internalRenameSync(
+ newPath,
+ checkType: (Node node) {
+ if (node.type != expectedType) {
+ throw node.type == FileSystemEntityType.directory
+ ? common.isADirectory(newPath)
+ : common.invalidArgument(newPath);
+ }
+ },
+ ) as Link;
+
+ @override
+ Future<Link> create(String target, {bool recursive = false}) async {
+ createSync(target, recursive: recursive);
+ return this;
+ }
+
+ @override
+ void createSync(String target, {bool recursive = false}) {
+ bool preexisting = true;
+ fileSystem.opHandle(path, FileSystemOp.create);
+ internalCreateSync(
+ createChild: (DirectoryNode parent, bool isFinalSegment) {
+ if (isFinalSegment) {
+ preexisting = false;
+ return LinkNode(parent, target);
+ } else if (recursive) {
+ return DirectoryNode(parent);
+ }
+ return null;
+ });
+ if (preexisting) {
+ // Per the spec, this is an error.
+ throw common.fileExists(path);
+ }
+ }
+
+ @override
+ Future<Link> update(String target) async {
+ updateSync(target);
+ return this;
+ }
+
+ @override
+ void updateSync(String target) {
+ Node node = backing;
+ utils.checkType(expectedType, node.type, () => path);
+ (node as LinkNode).target = target;
+ }
+
+ @override
+ void deleteSync({bool recursive = false}) => internalDeleteSync(
+ recursive: recursive,
+ checkType: (Node node) =>
+ utils.checkType(expectedType, node.type, () => path),
+ );
+
+ @override
+ Future<String> target() async => targetSync();
+
+ @override
+ String targetSync() {
+ Node node = backing;
+ if (node.type != expectedType) {
+ // Note: this may change; https://github.com/dart-lang/sdk/issues/28204
+ throw common.noSuchFileOrDirectory(path);
+ }
+ return (node as LinkNode).target;
+ }
+
+ @override
+ Link get absolute => super.absolute as Link;
+
+ @override
+ @protected
+ Link clone(String path) => MemoryLink(fileSystem, path);
+
+ @override
+ String toString() => "MemoryLink: '$path'";
+}
diff --git a/pkgs/file/lib/src/backends/memory/memory_random_access_file.dart b/pkgs/file/lib/src/backends/memory/memory_random_access_file.dart
new file mode 100644
index 0000000..d4fe73d
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/memory_random_access_file.dart
@@ -0,0 +1,390 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:math' as math show min;
+import 'dart:typed_data';
+
+import 'package:file/src/common.dart' as common;
+import 'package:file/src/io.dart' as io;
+
+import 'memory_file.dart';
+import 'node.dart';
+import 'utils.dart' as utils;
+
+/// A [MemoryFileSystem]-backed implementation of [io.RandomAccessFile].
+class MemoryRandomAccessFile implements io.RandomAccessFile {
+ /// Constructs a [MemoryRandomAccessFile].
+ ///
+ /// This should be used only by [MemoryFile.open] or [MemoryFile.openSync].
+ MemoryRandomAccessFile(this.path, this._node, this._mode) {
+ switch (_mode) {
+ case io.FileMode.read:
+ break;
+ case io.FileMode.write:
+ case io.FileMode.writeOnly:
+ truncateSync(0);
+ break;
+ case io.FileMode.append:
+ case io.FileMode.writeOnlyAppend:
+ _position = lengthSync();
+ break;
+ default:
+ // [FileMode] provides no way of retrieving its value or name.
+ throw UnimplementedError('Unsupported FileMode');
+ }
+ }
+
+ @override
+ final String path;
+
+ final FileNode _node;
+ final io.FileMode _mode;
+
+ bool _isOpen = true;
+ int _position = 0;
+
+ /// Whether an asynchronous operation is pending.
+ ///
+ /// See [_asyncWrapper] for details.
+ bool get _asyncOperationPending => __asyncOperationPending;
+
+ set _asyncOperationPending(bool value) {
+ assert(__asyncOperationPending != value);
+ __asyncOperationPending = value;
+ }
+
+ bool __asyncOperationPending = false;
+
+ /// Throws a [io.FileSystemException] if an operation is attempted on a file
+ /// that is not open.
+ void _checkOpen() {
+ if (!_isOpen) {
+ throw io.FileSystemException('File closed', path);
+ }
+ }
+
+ /// Throws a [io.FileSystemException] if attempting to read from a file that
+ /// has not been opened for reading.
+ void _checkReadable(String operation) {
+ switch (_mode) {
+ case io.FileMode.read:
+ case io.FileMode.write:
+ case io.FileMode.append:
+ return;
+ case io.FileMode.writeOnly:
+ case io.FileMode.writeOnlyAppend:
+ default:
+ throw io.FileSystemException(
+ '$operation failed', path, common.badFileDescriptor(path).osError);
+ }
+ }
+
+ /// Throws a [io.FileSystemException] if attempting to read from a file that
+ /// has not been opened for writing.
+ void _checkWritable(String operation) {
+ if (utils.isWriteMode(_mode)) {
+ return;
+ }
+
+ throw io.FileSystemException(
+ '$operation failed', path, common.badFileDescriptor(path).osError);
+ }
+
+ /// Throws a [io.FileSystemException] if attempting to perform an operation
+ /// while an asynchronous operation is already in progress.
+ ///
+ /// See [_asyncWrapper] for details.
+ void _checkAsync() {
+ if (_asyncOperationPending) {
+ throw io.FileSystemException(
+ 'An async operation is currently pending', path);
+ }
+ }
+
+ /// Wraps a synchronous function to make it appear asynchronous.
+ ///
+ /// [_asyncOperationPending], [_checkAsync], and [_asyncWrapper] are used to
+ /// mimic [RandomAccessFile]'s enforcement that only one asynchronous
+ /// operation is pending for a [RandomAccessFile] instance. Since
+ /// [MemoryFileSystem]-based classes are likely to be used in tests, fidelity
+ /// is important to catch errors that might occur in production.
+ ///
+ /// [_asyncWrapper] does not call [f] directly since setting and unsetting
+ /// [_asyncOperationPending] synchronously would not be meaningful. We
+ /// instead execute [f] through a [Future.delayed] callback to better simulate
+ /// asynchrony.
+ Future<R> _asyncWrapper<R>(R Function() f) async {
+ _checkAsync();
+
+ _asyncOperationPending = true;
+ try {
+ return await Future<R>.delayed(
+ Duration.zero,
+ () {
+ // Temporarily reset [_asyncOpPending] in case [f]'s has its own
+ // checks for pending asynchronous operations.
+ _asyncOperationPending = false;
+ try {
+ return f();
+ } finally {
+ _asyncOperationPending = true;
+ }
+ },
+ );
+ } finally {
+ _asyncOperationPending = false;
+ }
+ }
+
+ @override
+ Future<void> close() async => _asyncWrapper(closeSync);
+
+ @override
+ void closeSync() {
+ _checkOpen();
+ _isOpen = false;
+ }
+
+ @override
+ Future<io.RandomAccessFile> flush() async {
+ await _asyncWrapper(flushSync);
+ return this;
+ }
+
+ @override
+ void flushSync() {
+ _checkOpen();
+ _checkAsync();
+ }
+
+ @override
+ Future<int> length() => _asyncWrapper(lengthSync);
+
+ @override
+ int lengthSync() {
+ _checkOpen();
+ _checkAsync();
+ return _node.size;
+ }
+
+ @override
+ Future<io.RandomAccessFile> lock([
+ io.FileLock mode = io.FileLock.exclusive,
+ int start = 0,
+ int end = -1,
+ ]) async {
+ await _asyncWrapper(() => lockSync(mode, start, end));
+ return this;
+ }
+
+ @override
+ void lockSync([
+ io.FileLock mode = io.FileLock.exclusive,
+ int start = 0,
+ int end = -1,
+ ]) {
+ _checkOpen();
+ _checkAsync();
+ // TODO(jamesderlin): Implement, https://github.com/google/file.dart/issues/140
+ throw UnimplementedError('TODO');
+ }
+
+ @override
+ Future<int> position() => _asyncWrapper(positionSync);
+
+ @override
+ int positionSync() {
+ _checkOpen();
+ _checkAsync();
+ return _position;
+ }
+
+ @override
+ Future<Uint8List> read(int bytes) => _asyncWrapper(() => readSync(bytes));
+
+ @override
+ Uint8List readSync(int bytes) {
+ _checkOpen();
+ _checkAsync();
+ _checkReadable('read');
+ // TODO(jamesderlin): Check for integer overflow.
+ final int end = math.min(_position + bytes, lengthSync());
+ final Uint8List copy = _node.content.sublist(_position, end);
+ _position = end;
+ return copy;
+ }
+
+ @override
+ Future<int> readByte() => _asyncWrapper(readByteSync);
+
+ @override
+ int readByteSync() {
+ _checkOpen();
+ _checkAsync();
+ _checkReadable('readByte');
+
+ if (_position >= lengthSync()) {
+ return -1;
+ }
+ return _node.content[_position++];
+ }
+
+ @override
+ Future<int> readInto(List<int> buffer, [int start = 0, int? end]) =>
+ _asyncWrapper(() => readIntoSync(buffer, start, end));
+
+ @override
+ int readIntoSync(List<int> buffer, [int start = 0, int? end]) {
+ _checkOpen();
+ _checkAsync();
+ _checkReadable('readInto');
+
+ end = RangeError.checkValidRange(start, end, buffer.length);
+
+ final int length = lengthSync();
+ int i;
+ for (i = start; i < end && _position < length; i += 1, _position += 1) {
+ buffer[i] = _node.content[_position];
+ }
+ return i - start;
+ }
+
+ @override
+ Future<io.RandomAccessFile> setPosition(int position) async {
+ await _asyncWrapper(() => setPositionSync(position));
+ return this;
+ }
+
+ @override
+ void setPositionSync(int position) {
+ _checkOpen();
+ _checkAsync();
+
+ if (position < 0) {
+ throw io.FileSystemException(
+ 'setPosition failed', path, common.invalidArgument(path).osError);
+ }
+
+ // Empirical testing indicates that setting the position to be beyond the
+ // end of the file is legal and will zero-fill upon the next write.
+ _position = position;
+ }
+
+ @override
+ Future<io.RandomAccessFile> truncate(int length) async {
+ await _asyncWrapper(() => truncateSync(length));
+ return this;
+ }
+
+ @override
+ void truncateSync(int length) {
+ _checkOpen();
+ _checkAsync();
+
+ if (length < 0 || !utils.isWriteMode(_mode)) {
+ throw io.FileSystemException(
+ 'truncate failed', path, common.invalidArgument(path).osError);
+ }
+
+ final int oldLength = lengthSync();
+ if (length < oldLength) {
+ _node.truncate(length);
+
+ // [_position] is intentionally left untouched to match the observed
+ // behavior of [RandomAccessFile].
+ } else if (length > oldLength) {
+ _node.write(Uint8List(length - oldLength));
+ }
+ assert(lengthSync() == length);
+ }
+
+ @override
+ Future<io.RandomAccessFile> unlock([int start = 0, int end = -1]) async {
+ await _asyncWrapper(() => unlockSync(start, end));
+ return this;
+ }
+
+ @override
+ void unlockSync([int start = 0, int end = -1]) {
+ _checkOpen();
+ _checkAsync();
+ // TODO(jamesderlin): Implement, https://github.com/google/file.dart/issues/140
+ throw UnimplementedError('TODO');
+ }
+
+ @override
+ Future<io.RandomAccessFile> writeByte(int value) async {
+ await _asyncWrapper(() => writeByteSync(value));
+ return this;
+ }
+
+ @override
+ int writeByteSync(int value) {
+ _checkOpen();
+ _checkAsync();
+ _checkWritable('writeByte');
+
+ // [Uint8List] will truncate values to 8-bits automatically, so we don't
+ // need to check [value].
+
+ int length = lengthSync();
+ if (_position >= length) {
+ // If [_position] is out of bounds, [RandomAccessFile] zero-fills the
+ // file.
+ truncateSync(_position + 1);
+ length = lengthSync();
+ }
+ assert(_position < length);
+ _node.content[_position++] = value;
+
+ // Despite what the documentation states, [RandomAccessFile.writeByteSync]
+ // always seems to return 1, even if we had to extend the file for an out of
+ // bounds write. See https://github.com/dart-lang/sdk/issues/42298.
+ return 1;
+ }
+
+ @override
+ Future<io.RandomAccessFile> writeFrom(
+ List<int> buffer, [
+ int start = 0,
+ int? end,
+ ]) async {
+ await _asyncWrapper(() => writeFromSync(buffer, start, end));
+ return this;
+ }
+
+ @override
+ void writeFromSync(List<int> buffer, [int start = 0, int? end]) {
+ _checkOpen();
+ _checkAsync();
+ _checkWritable('writeFrom');
+
+ end = RangeError.checkValidRange(start, end, buffer.length);
+
+ final int writeByteCount = end - start;
+ final int endPosition = _position + writeByteCount;
+
+ if (endPosition > lengthSync()) {
+ truncateSync(endPosition);
+ }
+
+ _node.content.setRange(_position, endPosition, buffer, start);
+ _position = endPosition;
+ }
+
+ @override
+ Future<io.RandomAccessFile> writeString(
+ String string, {
+ Encoding encoding = utf8,
+ }) async {
+ await _asyncWrapper(() => writeStringSync(string, encoding: encoding));
+ return this;
+ }
+
+ @override
+ void writeStringSync(String string, {Encoding encoding = utf8}) {
+ writeFromSync(encoding.encode(string));
+ }
+}
diff --git a/pkgs/file/lib/src/backends/memory/node.dart b/pkgs/file/lib/src/backends/memory/node.dart
new file mode 100644
index 0000000..ae4d3f7
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/node.dart
@@ -0,0 +1,358 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+
+import 'package:file/file.dart';
+import 'package:file/src/backends/memory/operations.dart';
+import 'package:file/src/io.dart' as io;
+
+import 'clock.dart';
+import 'common.dart';
+import 'memory_file_stat.dart';
+import 'style.dart';
+
+/// Visitor callback for use with [NodeBasedFileSystem.findNode].
+///
+/// [parent] is the parent node of the current path segment and is guaranteed
+/// to be non-null.
+///
+/// [childName] is the basename of the entity at the current path segment. It
+/// is guaranteed to be non-null.
+///
+/// [childNode] is the node at the current path segment. It will be
+/// non-null only if such an entity exists. The return value of this callback
+/// will be used as the value of this node, which allows this callback to
+/// do things like recursively create or delete folders.
+///
+/// [currentSegment] is the index of the current segment within the overall
+/// path that's being walked by [NodeBasedFileSystem.findNode].
+///
+/// [finalSegment] is the index of the final segment that will be walked by
+/// [NodeBasedFileSystem.findNode].
+typedef SegmentVisitor = Node? Function(
+ DirectoryNode parent,
+ String childName,
+ Node? childNode,
+ int currentSegment,
+ int finalSegment,
+);
+
+/// A [FileSystem] whose internal structure is made up of a tree of [Node]
+/// instances, rooted at a single node.
+abstract class NodeBasedFileSystem implements StyleableFileSystem {
+ /// An optional handle to hook into common file system operations.
+ void Function(String context, FileSystemOp operation) get opHandle;
+
+ /// The root node.
+ RootNode? get root;
+
+ /// The path of the current working directory.
+ String get cwd;
+
+ /// The clock to use when finding the current time (e.g. to set the creation
+ /// time of a new node).
+ Clock get clock;
+
+ /// Gets the backing node of the entity at the specified path. If the tail
+ /// element of the path does not exist, this will return null. If the tail
+ /// element cannot be reached because its directory does not exist, a
+ /// [io.FileSystemException] will be thrown.
+ ///
+ /// If [path] is a relative path, it will be resolved relative to
+ /// [reference], or the current working directory ([cwd]) if [reference] is
+ /// null. If [path] is an absolute path, [reference] will be ignored.
+ ///
+ /// If the last element in [path] represents a symbolic link, this will
+ /// return the [LinkNode] node for the link (it will not return the
+ /// node to which the link points), unless [followTailLink] is true.
+ /// Directory links in the _middle_ of the path will be followed in order to
+ /// find the node regardless of the value of [followTailLink].
+ ///
+ /// If [segmentVisitor] is specified, it will be invoked for every path
+ /// segment visited along the way starting where the reference (root folder
+ /// if the path is absolute) is the parent. For each segment, the return value
+ /// of [segmentVisitor] will be used as the backing node of that path
+ /// segment, thus allowing callers to create nodes on demand in the
+ /// specified path. Note that `..` and `.` segments may cause the visitor to
+ /// get invoked with the same node multiple times. When [segmentVisitor] is
+ /// invoked, for each path segment that resolves to a link node, the visitor
+ /// will visit the actual link node if [visitLinks] is true; otherwise it
+ /// will visit the target of the link node.
+ ///
+ /// If [pathWithSymlinks] is specified, the path to the node with symbolic
+ /// links explicitly broken out will be appended to the buffer. `..` and `.`
+ /// path segments will *not* be resolved and are left to the caller.
+ Node? findNode(
+ String path, {
+ Node reference,
+ SegmentVisitor segmentVisitor,
+ bool visitLinks = false,
+ List<String> pathWithSymlinks,
+ bool followTailLink = false,
+ });
+}
+
+/// A class that represents the actual storage of an existent file system
+/// entity (whereas classes [File], [Directory], and [Link] represent less
+/// concrete entities that may or may not yet exist).
+///
+/// This data structure is loosely based on a Unix-style file system inode
+/// (hence the name).
+abstract class Node {
+ /// Constructs a new [Node] as a child of the specified parent.
+ Node(this._parent) {
+ if (_parent == null && !isRoot) {
+ throw const io.FileSystemException('All nodes must have a parent.');
+ }
+ }
+
+ DirectoryNode? _parent;
+
+ /// Gets the directory that holds this node.
+ DirectoryNode get parent => _parent!;
+
+ /// Reparents this node to live in the specified directory.
+ set parent(DirectoryNode parent) {
+ DirectoryNode ancestor = parent;
+ while (!ancestor.isRoot) {
+ if (ancestor == this) {
+ throw const io.FileSystemException(
+ 'A directory cannot be its own ancestor.');
+ }
+ ancestor = ancestor.parent;
+ }
+ _parent = parent;
+ }
+
+ /// Returns the type of the file system entity that this node represents.
+ io.FileSystemEntityType get type;
+
+ /// Returns the POSIX stat information for this file system object.
+ io.FileStat get stat;
+
+ /// Returns the closest directory in the ancestry hierarchy starting with
+ /// this node. For directory nodes, it returns the node itself; for other
+ /// nodes, it returns the parent node.
+ DirectoryNode get directory => _parent!;
+
+ /// Tells if this node is a root node.
+ bool get isRoot => false;
+
+ /// Returns the file system responsible for this node.
+ NodeBasedFileSystem get fs => _parent!.fs;
+}
+
+/// Base class that represents the backing for those nodes that have
+/// substance (namely, node types that will not redirect to other types when
+/// you call [stat] on them).
+abstract class RealNode extends Node {
+ /// Constructs a new [RealNode] as a child of the specified [parent].
+ RealNode(DirectoryNode? parent) : super(parent) {
+ int now = clock.now.millisecondsSinceEpoch;
+ changed = now;
+ modified = now;
+ accessed = now;
+ }
+
+ /// See [NodeBasedFileSystem.clock].
+ Clock get clock => parent.clock;
+
+ /// Last changed time in milliseconds since the Epoch.
+ late int changed;
+
+ /// Last modified time in milliseconds since the Epoch.
+ late int modified;
+
+ /// Last accessed time in milliseconds since the Epoch.
+ late int accessed;
+
+ /// Bitmask representing the file read/write/execute mode.
+ int mode = 0x777;
+
+ @override
+ io.FileStat get stat {
+ return MemoryFileStat(
+ DateTime.fromMillisecondsSinceEpoch(changed),
+ DateTime.fromMillisecondsSinceEpoch(modified),
+ DateTime.fromMillisecondsSinceEpoch(accessed),
+ type,
+ mode,
+ size,
+ );
+ }
+
+ /// The size of the file system entity in bytes.
+ int get size;
+
+ /// Updates the last modified time of the node.
+ void touch() {
+ modified = clock.now.millisecondsSinceEpoch;
+ }
+}
+
+/// Class that represents the backing for an in-memory directory.
+class DirectoryNode extends RealNode {
+ /// Constructs a new [DirectoryNode] as a child of the specified [parent].
+ DirectoryNode(DirectoryNode? parent) : super(parent);
+
+ /// Child nodes, indexed by their basename.
+ final Map<String, Node> children = <String, Node>{};
+
+ @override
+ io.FileSystemEntityType get type => io.FileSystemEntityType.directory;
+
+ @override
+ DirectoryNode get directory => this;
+
+ @override
+ int get size => 0;
+}
+
+/// Class that represents the backing for the root of the in-memory file system.
+class RootNode extends DirectoryNode {
+ /// Constructs a new [RootNode] tied to the specified file system.
+ RootNode(this.fs)
+ : assert(fs.root == null),
+ super(null);
+
+ @override
+ final NodeBasedFileSystem fs;
+
+ @override
+ Clock get clock => fs.clock;
+
+ @override
+ DirectoryNode get parent => this;
+
+ @override
+ bool get isRoot => true;
+
+ @override
+ set parent(DirectoryNode parent) =>
+ throw UnsupportedError('Cannot set the parent of the root directory.');
+}
+
+/// Class that represents the backing for an in-memory regular file.
+class FileNode extends RealNode {
+ /// Constructs a new [FileNode] as a child of the specified [parent].
+ FileNode(DirectoryNode parent) : super(parent);
+
+ /// File contents in bytes.
+ Uint8List get content => _content;
+ Uint8List _content = Uint8List(0);
+
+ @override
+ io.FileSystemEntityType get type => io.FileSystemEntityType.file;
+
+ @override
+ int get size => _content.length;
+
+ /// Appends the specified bytes to the end of this node's [content].
+ void write(List<int> bytes) {
+ Uint8List existing = _content;
+ _content = Uint8List(existing.length + bytes.length);
+ _content.setRange(0, existing.length, existing);
+ _content.setRange(existing.length, _content.length, bytes);
+ }
+
+ /// Truncates this node's [content] to the specified length.
+ ///
+ /// [length] must be in the range \[0, [size]\].
+ void truncate(int length) {
+ assert(length >= 0);
+ assert(length <= _content.length);
+ _content = _content.sublist(0, length);
+ }
+
+ /// Clears the [content] of the node.
+ void clear() {
+ _content = Uint8List(0);
+ }
+
+ /// Copies data from [source] into this node. The [modified] and [changed]
+ /// fields will be reset as opposed to copied to indicate that this file
+ /// has been modified and changed.
+ void copyFrom(FileNode source) {
+ modified = changed = clock.now.millisecondsSinceEpoch;
+ accessed = source.accessed;
+ mode = source.mode;
+ _content = Uint8List.fromList(source.content);
+ }
+}
+
+/// Class that represents the backing for an in-memory symbolic link.
+class LinkNode extends Node {
+ /// Constructs a new [LinkNode] as a child of the specified [parent] and
+ /// linking to the specified [target] path.
+ LinkNode(DirectoryNode parent, this.target)
+ : assert(target.isNotEmpty),
+ super(parent);
+
+ /// The path to which this link points.
+ String target;
+
+ /// A marker used to detect circular link references.
+ bool _reentrant = false;
+
+ /// Gets the node backing for this link's target. Throws a
+ /// [FileSystemException] if this link references a non-existent file
+ /// system entity.
+ ///
+ /// If [tailVisitor] is specified, it will be invoked for the tail path
+ /// segment of this link's target, and its return value will be used as the
+ /// return value of this method. If the tail path segment of this link's
+ /// target cannot be traversed into, a [FileSystemException] will be thrown,
+ /// and [tailVisitor] will not be invoked.
+ Node getReferent({
+ Node? Function(DirectoryNode parent, String childName, Node? child)?
+ tailVisitor,
+ }) {
+ Node? referent = fs.findNode(
+ target,
+ reference: this,
+ segmentVisitor: (
+ DirectoryNode parent,
+ String childName,
+ Node? child,
+ int currentSegment,
+ int finalSegment,
+ ) {
+ if (tailVisitor != null && currentSegment == finalSegment) {
+ child = tailVisitor(parent, childName, child);
+ }
+ return child;
+ },
+ );
+ checkExists(referent, () => target);
+ return referent!;
+ }
+
+ /// Gets the node backing for this link's target, or null if this link
+ /// references a non-existent file system entity.
+ Node? get referentOrNull {
+ try {
+ return getReferent();
+ } on io.FileSystemException {
+ return null;
+ }
+ }
+
+ @override
+ io.FileSystemEntityType get type => io.FileSystemEntityType.link;
+
+ @override
+ io.FileStat get stat {
+ if (_reentrant) {
+ return MemoryFileStat.notFound;
+ }
+ _reentrant = true;
+ try {
+ Node? node = referentOrNull;
+ return node == null ? MemoryFileStat.notFound : node.stat;
+ } finally {
+ _reentrant = false;
+ }
+ }
+}
diff --git a/pkgs/file/lib/src/backends/memory/operations.dart b/pkgs/file/lib/src/backends/memory/operations.dart
new file mode 100644
index 0000000..9fc7462
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/operations.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A file system operation used by the [MemoryFileSytem] to allow
+/// tests to insert errors for certain operations.
+///
+/// This is not implemented as an enum to allow new values to be added in a
+/// backwards compatible manner.
+class FileSystemOp {
+ const FileSystemOp._(this._value);
+
+ // This field added to ensure const values can be different.
+ // ignore: unused_field
+ final int _value;
+
+ /// A file system operation used for all read methods.
+ ///
+ /// * [FileSystemEntity.readAsString]
+ /// * [FileSystemEntity.readAsStringSync]
+ /// * [FileSystemEntity.readAsBytes]
+ /// * [FileSystemEntity.readAsBytesSync]
+ static const FileSystemOp read = FileSystemOp._(0);
+
+ /// A file system operation used for all write methods.
+ ///
+ /// * [FileSystemEntity.writeAsString]
+ /// * [FileSystemEntity.writeAsStringSync]
+ /// * [FileSystemEntity.writeAsBytes]
+ /// * [FileSystemEntity.writeAsBytesSync]
+ static const FileSystemOp write = FileSystemOp._(1);
+
+ /// A file system operation used for all delete methods.
+ ///
+ /// * [FileSystemEntity.delete]
+ /// * [FileSystemEntity.deleteSync]
+ static const FileSystemOp delete = FileSystemOp._(2);
+
+ /// A file system operation used for all create methods.
+ ///
+ /// * [FileSystemEntity.create]
+ /// * [FileSystemEntity.createSync]
+ static const FileSystemOp create = FileSystemOp._(3);
+
+ /// A file operation used for all open methods.
+ ///
+ /// * [File.open]
+ /// * [File.openSync]
+ /// * [File.openRead]
+ /// * [File.openWrite]
+ static const FileSystemOp open = FileSystemOp._(4);
+
+ /// A file operation used for all copy methods.
+ ///
+ /// * [File.copy]
+ /// * [File.copySync]
+ static const FileSystemOp copy = FileSystemOp._(5);
+
+ /// A file system operation used for all exists methods.
+ ///
+ /// * [FileSystemEntity.exists]
+ /// * [FileSystemEntity.existsSync]
+ static const FileSystemOp exists = FileSystemOp._(6);
+
+ @override
+ String toString() {
+ switch (_value) {
+ case 0:
+ return 'FileSystemOp.read';
+ case 1:
+ return 'FileSystemOp.write';
+ case 2:
+ return 'FileSystemOp.delete';
+ case 3:
+ return 'FileSystemOp.create';
+ case 4:
+ return 'FileSystemOp.open';
+ case 5:
+ return 'FileSystemOp.copy';
+ case 6:
+ return 'FileSystemOp.exists';
+ default:
+ throw StateError('Invalid FileSytemOp type: $this');
+ }
+ }
+}
diff --git a/pkgs/file/lib/src/backends/memory/style.dart b/pkgs/file/lib/src/backends/memory/style.dart
new file mode 100644
index 0000000..701c9d0
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/style.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:path/path.dart' as p;
+
+/// Class that represents the path style that a memory file system should
+/// adopt.
+///
+/// This is primarily useful if you want to test how your code will behave
+/// when faced with particular paths or particular path separator characters.
+/// For instance, you may want to test that your code will work on Windows,
+/// while still using a memory file system in order to gain hermeticity in your
+/// tests.
+abstract class FileSystemStyle {
+ const FileSystemStyle._();
+
+ /// Mimics the Unix file system style.
+ ///
+ /// * This style does not have the notion of drives
+ /// * All file system paths are rooted at `/`
+ /// * The path separator is `/`
+ ///
+ /// An example path in this style is `/path/to/file`.
+ static const FileSystemStyle posix = _Posix();
+
+ /// Mimics the Windows file system style.
+ ///
+ /// * This style mounts its root folder on a single root drive (`C:`)
+ /// * All file system paths are rooted at `C:\`
+ /// * The path separator is `\`
+ ///
+ /// An example path in this style is `C:\path\to\file`.
+ static const FileSystemStyle windows = _Windows();
+
+ /// The drive upon which the root directory is mounted.
+ ///
+ /// While real-world file systems that have the notion of drives will support
+ /// multiple drives per system, memory file system will only support one
+ /// root drive.
+ ///
+ /// This will be the empty string for styles that don't have the notion of
+ /// drives (e.g. [posix]).
+ String get drive;
+
+ /// The String that represents the delineation between a directory and its
+ /// children.
+ String get separator;
+
+ /// The string that represents the root of the file system.
+ ///
+ /// Memory file system is always single-rooted.
+ String get root => '$drive$separator';
+
+ /// Gets an object useful for manipulating paths in this style.
+ ///
+ /// Relative path manipulations will be relative to the specified [path].
+ p.Context contextFor(String path);
+}
+
+class _Posix extends FileSystemStyle {
+ const _Posix() : super._();
+
+ @override
+ String get drive => '';
+
+ @override
+ String get separator {
+ return p.Style.posix.separator; // ignore: deprecated_member_use
+ }
+
+ @override
+ p.Context contextFor(String path) =>
+ p.Context(style: p.Style.posix, current: path);
+}
+
+class _Windows extends FileSystemStyle {
+ const _Windows() : super._();
+
+ @override
+ String get drive => 'C:';
+
+ @override
+ String get separator {
+ return p.Style.windows.separator; // ignore: deprecated_member_use
+ }
+
+ @override
+ p.Context contextFor(String path) =>
+ p.Context(style: p.Style.windows, current: path);
+}
+
+/// A file system that supports different styles.
+abstract class StyleableFileSystem implements FileSystem {
+ /// The style used by this file system.
+ FileSystemStyle get style;
+}
diff --git a/pkgs/file/lib/src/backends/memory/utils.dart b/pkgs/file/lib/src/backends/memory/utils.dart
new file mode 100644
index 0000000..eec9980
--- /dev/null
+++ b/pkgs/file/lib/src/backends/memory/utils.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/src/common.dart' as common;
+import 'package:file/src/io.dart' as io;
+
+import 'common.dart';
+import 'node.dart';
+
+/// Checks if `node.type` returns [io.FileSystemEntityType.FILE].
+bool isFile(Node? node) => node?.type == io.FileSystemEntityType.file;
+
+/// Checks if `node.type` returns [io.FileSystemEntityType.DIRECTORY].
+bool isDirectory(Node? node) => node?.type == io.FileSystemEntityType.directory;
+
+/// Checks if `node.type` returns [io.FileSystemEntityType.LINK].
+bool isLink(Node? node) => node?.type == io.FileSystemEntityType.link;
+
+/// Validator function that is expected to throw a [FileSystemException] if
+/// the node does not represent the type that is expected in any given context.
+typedef TypeChecker = void Function(Node node);
+
+/// Throws a [io.FileSystemException] if [node] is not a directory.
+void checkIsDir(Node node, PathGenerator path) {
+ if (!isDirectory(node)) {
+ throw common.notADirectory(path() as String);
+ }
+}
+
+/// Throws a [io.FileSystemException] if [expectedType] doesn't match
+/// [actualType].
+void checkType(
+ FileSystemEntityType expectedType,
+ FileSystemEntityType actualType,
+ PathGenerator path,
+) {
+ if (expectedType != actualType) {
+ switch (expectedType) {
+ case FileSystemEntityType.directory:
+ throw common.notADirectory(path() as String);
+ case FileSystemEntityType.file:
+ assert(actualType == FileSystemEntityType.directory);
+ throw common.isADirectory(path() as String);
+ case FileSystemEntityType.link:
+ throw common.invalidArgument(path() as String);
+ default:
+ // Should not happen
+ throw AssertionError();
+ }
+ }
+}
+
+/// Tells if the specified file mode represents a write mode.
+bool isWriteMode(io.FileMode mode) =>
+ mode == io.FileMode.write ||
+ mode == io.FileMode.append ||
+ mode == io.FileMode.writeOnly ||
+ mode == io.FileMode.writeOnlyAppend;
+
+/// Tells whether the given string is empty.
+bool isEmpty(String str) => str.isEmpty;
+
+/// Returns the node ultimately referred to by [link]. This will resolve
+/// the link references (following chains of links as necessary) and return
+/// the node at the end of the link chain.
+///
+/// If a loop in the link chain is found, this will throw a
+/// [FileSystemException], calling [path] to generate the path.
+///
+/// If [ledger] is specified, the resolved path to the terminal node will be
+/// appended to the ledger (or overwritten in the ledger if a link target
+/// specified an absolute path). The path will not be normalized, meaning
+/// `..` and `.` path segments may be present.
+///
+/// If [tailVisitor] is specified, it will be invoked for the tail element of
+/// the last link in the symbolic link chain, and its return value will be the
+/// return value of this method (thus allowing callers to create the entity
+/// at the end of the chain on demand).
+Node resolveLinks(
+ LinkNode link,
+ PathGenerator path, {
+ List<String>? ledger,
+ Node? Function(DirectoryNode parent, String childName, Node? child)?
+ tailVisitor,
+}) {
+ // Record a breadcrumb trail to guard against symlink loops.
+ Set<LinkNode> breadcrumbs = <LinkNode>{};
+
+ Node node = link;
+ while (isLink(node)) {
+ link = node as LinkNode;
+ if (!breadcrumbs.add(link)) {
+ throw common.tooManyLevelsOfSymbolicLinks(path() as String);
+ }
+ if (ledger != null) {
+ if (link.fs.path.isAbsolute(link.target)) {
+ ledger.clear();
+ } else if (ledger.isNotEmpty) {
+ ledger.removeLast();
+ }
+ ledger.addAll(link.target.split(link.fs.path.separator));
+ }
+ node = link.getReferent(
+ tailVisitor: (DirectoryNode parent, String childName, Node? child) {
+ if (tailVisitor != null && !isLink(child)) {
+ // Only invoke [tailListener] on the final resolution pass.
+ child = tailVisitor(parent, childName, child);
+ }
+ return child;
+ },
+ );
+ }
+
+ return node;
+}
diff --git a/pkgs/file/lib/src/common.dart b/pkgs/file/lib/src/common.dart
new file mode 100644
index 0000000..6706ec9
--- /dev/null
+++ b/pkgs/file/lib/src/common.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'interface.dart';
+
+/// Returns a 'No such file or directory' [FileSystemException].
+FileSystemException noSuchFileOrDirectory(String path) {
+ return _fsException(path, 'No such file or directory', ErrorCodes.ENOENT);
+}
+
+/// Returns a 'Not a directory' [FileSystemException].
+FileSystemException notADirectory(String path) {
+ return _fsException(path, 'Not a directory', ErrorCodes.ENOTDIR);
+}
+
+/// Returns a 'Is a directory' [FileSystemException].
+FileSystemException isADirectory(String path) {
+ return _fsException(path, 'Is a directory', ErrorCodes.EISDIR);
+}
+
+/// Returns a 'Directory not empty' [FileSystemException].
+FileSystemException directoryNotEmpty(String path) {
+ return _fsException(path, 'Directory not empty', ErrorCodes.ENOTEMPTY);
+}
+
+/// Returns a 'File exists' [FileSystemException].
+FileSystemException fileExists(String path) {
+ return _fsException(path, 'File exists', ErrorCodes.EEXIST);
+}
+
+/// Returns a 'Invalid argument' [FileSystemException].
+FileSystemException invalidArgument(String path) {
+ return _fsException(path, 'Invalid argument', ErrorCodes.EINVAL);
+}
+
+/// Returns a 'Too many levels of symbolic links' [FileSystemException].
+FileSystemException tooManyLevelsOfSymbolicLinks(String path) {
+ // TODO(tvolkert): Switch to ErrorCodes.EMLINK
+ return _fsException(
+ path, 'Too many levels of symbolic links', ErrorCodes.ELOOP);
+}
+
+/// Returns a 'Bad file descriptor' [FileSystemException].
+FileSystemException badFileDescriptor(String path) {
+ return _fsException(path, 'Bad file descriptor', ErrorCodes.EBADF);
+}
+
+FileSystemException _fsException(String path, String msg, int errorCode) {
+ return FileSystemException(msg, path, OSError(msg, errorCode));
+}
+
+/// Mixin containing implementations of [Directory] methods that are common
+/// to all implementations.
+mixin DirectoryAddOnsMixin implements Directory {
+ @override
+ Directory childDirectory(String basename) {
+ return fileSystem.directory(fileSystem.path.join(path, basename));
+ }
+
+ @override
+ File childFile(String basename) {
+ return fileSystem.file(fileSystem.path.join(path, basename));
+ }
+
+ @override
+ Link childLink(String basename) {
+ return fileSystem.link(fileSystem.path.join(path, basename));
+ }
+}
diff --git a/pkgs/file/lib/src/forwarding.dart b/pkgs/file/lib/src/forwarding.dart
new file mode 100644
index 0000000..9566a30
--- /dev/null
+++ b/pkgs/file/lib/src/forwarding.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'forwarding/forwarding_directory.dart';
+export 'forwarding/forwarding_file.dart';
+export 'forwarding/forwarding_file_system.dart';
+export 'forwarding/forwarding_file_system_entity.dart';
+export 'forwarding/forwarding_link.dart';
+export 'forwarding/forwarding_random_access_file.dart';
diff --git a/pkgs/file/lib/src/forwarding/forwarding_directory.dart b/pkgs/file/lib/src/forwarding/forwarding_directory.dart
new file mode 100644
index 0000000..dba0c8e
--- /dev/null
+++ b/pkgs/file/lib/src/forwarding/forwarding_directory.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/src/io.dart' as io;
+import 'package:file/file.dart';
+
+/// A directory that forwards all methods and properties to a delegate.
+mixin ForwardingDirectory<T extends Directory>
+ implements ForwardingFileSystemEntity<T, io.Directory>, Directory {
+ @override
+ T wrap(io.Directory delegate) => wrapDirectory(delegate) as T;
+
+ @override
+ Future<Directory> create({bool recursive = false}) async =>
+ wrap(await delegate.create(recursive: recursive));
+
+ @override
+ void createSync({bool recursive = false}) =>
+ delegate.createSync(recursive: recursive);
+
+ @override
+ Future<Directory> createTemp([String? prefix]) async =>
+ wrap(await delegate.createTemp(prefix));
+
+ @override
+ Directory createTempSync([String? prefix]) =>
+ wrap(delegate.createTempSync(prefix));
+
+ @override
+ Stream<FileSystemEntity> list({
+ bool recursive = false,
+ bool followLinks = true,
+ }) =>
+ delegate.list(recursive: recursive, followLinks: followLinks).map(_wrap);
+
+ @override
+ List<FileSystemEntity> listSync({
+ bool recursive = false,
+ bool followLinks = true,
+ }) =>
+ delegate
+ .listSync(recursive: recursive, followLinks: followLinks)
+ .map(_wrap)
+ .toList();
+
+ FileSystemEntity _wrap(io.FileSystemEntity entity) {
+ if (entity is io.File) {
+ return wrapFile(entity);
+ } else if (entity is io.Directory) {
+ return wrapDirectory(entity);
+ } else if (entity is io.Link) {
+ return wrapLink(entity);
+ }
+ throw FileSystemException('Unsupported type: $entity', entity.path);
+ }
+}
diff --git a/pkgs/file/lib/src/forwarding/forwarding_file.dart b/pkgs/file/lib/src/forwarding/forwarding_file.dart
new file mode 100644
index 0000000..49c211d
--- /dev/null
+++ b/pkgs/file/lib/src/forwarding/forwarding_file.dart
@@ -0,0 +1,156 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:file/src/io.dart' as io;
+import 'package:file/file.dart';
+
+/// A file that forwards all methods and properties to a delegate.
+mixin ForwardingFile
+ implements ForwardingFileSystemEntity<File, io.File>, File {
+ @override
+ ForwardingFile wrap(io.File delegate) => wrapFile(delegate) as ForwardingFile;
+
+ // TODO(dartbug.com/49647): Pass `exclusive` through after it lands.
+ @override
+ Future<File> create({bool recursive = false, bool exclusive = false}) async =>
+ wrap(await delegate.create(
+ recursive: recursive /*, exclusive: exclusive*/));
+
+ // TODO(dartbug.com/49647): Pass `exclusive` through after it lands.
+ @override
+ void createSync({bool recursive = false, bool exclusive = false}) =>
+ delegate.createSync(recursive: recursive /*, exclusive: exclusive*/);
+
+ @override
+ Future<File> copy(String newPath) async => wrap(await delegate.copy(newPath));
+
+ @override
+ File copySync(String newPath) => wrap(delegate.copySync(newPath));
+
+ @override
+ Future<int> length() => delegate.length();
+
+ @override
+ int lengthSync() => delegate.lengthSync();
+
+ @override
+ Future<DateTime> lastAccessed() => delegate.lastAccessed();
+
+ @override
+ DateTime lastAccessedSync() => delegate.lastAccessedSync();
+
+ @override
+ Future<dynamic> setLastAccessed(DateTime time) =>
+ delegate.setLastAccessed(time);
+
+ @override
+ void setLastAccessedSync(DateTime time) => delegate.setLastAccessedSync(time);
+
+ @override
+ Future<DateTime> lastModified() => delegate.lastModified();
+
+ @override
+ DateTime lastModifiedSync() => delegate.lastModifiedSync();
+
+ @override
+ Future<dynamic> setLastModified(DateTime time) =>
+ delegate.setLastModified(time);
+
+ @override
+ void setLastModifiedSync(DateTime time) => delegate.setLastModifiedSync(time);
+
+ @override
+ Future<RandomAccessFile> open({
+ FileMode mode = FileMode.read,
+ }) =>
+ delegate.open(mode: mode);
+
+ @override
+ RandomAccessFile openSync({FileMode mode = FileMode.read}) =>
+ delegate.openSync(mode: mode);
+
+ @override
+ Stream<List<int>> openRead([int? start, int? end]) =>
+ delegate.openRead(start, end);
+
+ @override
+ IOSink openWrite({
+ FileMode mode = FileMode.write,
+ Encoding encoding = utf8,
+ }) =>
+ delegate.openWrite(mode: mode, encoding: encoding);
+
+ @override
+ Future<Uint8List> readAsBytes() => delegate.readAsBytes();
+
+ @override
+ Uint8List readAsBytesSync() => delegate.readAsBytesSync();
+
+ @override
+ Future<String> readAsString({Encoding encoding = utf8}) =>
+ delegate.readAsString(encoding: encoding);
+
+ @override
+ String readAsStringSync({Encoding encoding = utf8}) =>
+ delegate.readAsStringSync(encoding: encoding);
+
+ @override
+ Future<List<String>> readAsLines({Encoding encoding = utf8}) =>
+ delegate.readAsLines(encoding: encoding);
+
+ @override
+ List<String> readAsLinesSync({Encoding encoding = utf8}) =>
+ delegate.readAsLinesSync(encoding: encoding);
+
+ @override
+ Future<File> writeAsBytes(
+ List<int> bytes, {
+ FileMode mode = FileMode.write,
+ bool flush = false,
+ }) async =>
+ wrap(await delegate.writeAsBytes(
+ bytes,
+ mode: mode,
+ flush: flush,
+ ));
+
+ @override
+ void writeAsBytesSync(
+ List<int> bytes, {
+ FileMode mode = FileMode.write,
+ bool flush = false,
+ }) =>
+ delegate.writeAsBytesSync(bytes, mode: mode, flush: flush);
+
+ @override
+ Future<File> writeAsString(
+ String contents, {
+ FileMode mode = FileMode.write,
+ Encoding encoding = utf8,
+ bool flush = false,
+ }) async =>
+ wrap(await delegate.writeAsString(
+ contents,
+ mode: mode,
+ encoding: encoding,
+ flush: flush,
+ ));
+
+ @override
+ void writeAsStringSync(
+ String contents, {
+ FileMode mode = FileMode.write,
+ Encoding encoding = utf8,
+ bool flush = false,
+ }) =>
+ delegate.writeAsStringSync(
+ contents,
+ mode: mode,
+ encoding: encoding,
+ flush: flush,
+ );
+}
diff --git a/pkgs/file/lib/src/forwarding/forwarding_file_system.dart b/pkgs/file/lib/src/forwarding/forwarding_file_system.dart
new file mode 100644
index 0000000..d864db9
--- /dev/null
+++ b/pkgs/file/lib/src/forwarding/forwarding_file_system.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/src/io.dart' as io;
+import 'package:file/file.dart';
+import 'package:meta/meta.dart';
+import 'package:path/path.dart' as p;
+
+/// A file system that forwards all methods and properties to a delegate.
+abstract class ForwardingFileSystem extends FileSystem {
+ /// Creates a new [ForwardingFileSystem] that forwards all methods and
+ /// properties to the specified [delegate].
+ ForwardingFileSystem(this.delegate);
+
+ /// The file system to which this file system will forward all activity.
+ @protected
+ final FileSystem delegate;
+
+ @override
+ Directory directory(dynamic path) => delegate.directory(path);
+
+ @override
+ File file(dynamic path) => delegate.file(path);
+
+ @override
+ Link link(dynamic path) => delegate.link(path);
+
+ @override
+ p.Context get path => delegate.path;
+
+ @override
+ Directory get systemTempDirectory => delegate.systemTempDirectory;
+
+ @override
+ Directory get currentDirectory => delegate.currentDirectory;
+
+ @override
+ set currentDirectory(dynamic path) => delegate.currentDirectory = path;
+
+ @override
+ Future<io.FileStat> stat(String path) => delegate.stat(path);
+
+ @override
+ io.FileStat statSync(String path) => delegate.statSync(path);
+
+ @override
+ Future<bool> identical(String path1, String path2) =>
+ delegate.identical(path1, path2);
+
+ @override
+ bool identicalSync(String path1, String path2) =>
+ delegate.identicalSync(path1, path2);
+
+ @override
+ bool get isWatchSupported => delegate.isWatchSupported;
+
+ @override
+ Future<io.FileSystemEntityType> type(String path,
+ {bool followLinks = true}) =>
+ delegate.type(path, followLinks: followLinks);
+
+ @override
+ io.FileSystemEntityType typeSync(String path, {bool followLinks = true}) =>
+ delegate.typeSync(path, followLinks: followLinks);
+}
diff --git a/pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart b/pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart
new file mode 100644
index 0000000..3c41b39
--- /dev/null
+++ b/pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/src/io.dart' as io;
+import 'package:file/file.dart';
+import 'package:meta/meta.dart';
+
+/// A file system entity that forwards all methods and properties to a delegate.
+abstract class ForwardingFileSystemEntity<T extends FileSystemEntity,
+ D extends io.FileSystemEntity> implements FileSystemEntity {
+ /// The entity to which this entity will forward all methods and properties.
+ @protected
+ D get delegate;
+
+ /// Creates a new entity with the same file system and same type as this
+ /// entity but backed by the specified delegate.
+ @protected
+ T wrap(D delegate);
+
+ /// Creates a new directory with the same file system as this entity and
+ /// backed by the specified delegate.
+ @protected
+ Directory wrapDirectory(io.Directory delegate);
+
+ /// Creates a new file with the same file system as this entity and
+ /// backed by the specified delegate.
+ @protected
+ File wrapFile(io.File delegate);
+
+ /// Creates a new link with the same file system as this entity and
+ /// backed by the specified delegate.
+ @protected
+ Link wrapLink(io.Link delegate);
+
+ @override
+ Uri get uri => delegate.uri;
+
+ @override
+ Future<bool> exists() => delegate.exists();
+
+ @override
+ bool existsSync() => delegate.existsSync();
+
+ @override
+ Future<T> rename(String newPath) async =>
+ wrap(await delegate.rename(newPath) as D);
+
+ @override
+ T renameSync(String newPath) => wrap(delegate.renameSync(newPath) as D);
+
+ @override
+ Future<String> resolveSymbolicLinks() => delegate.resolveSymbolicLinks();
+
+ @override
+ String resolveSymbolicLinksSync() => delegate.resolveSymbolicLinksSync();
+
+ @override
+ Future<io.FileStat> stat() => delegate.stat();
+
+ @override
+ io.FileStat statSync() => delegate.statSync();
+
+ @override
+ Future<T> delete({bool recursive = false}) async =>
+ wrap(await delegate.delete(recursive: recursive) as D);
+
+ @override
+ void deleteSync({bool recursive = false}) =>
+ delegate.deleteSync(recursive: recursive);
+
+ @override
+ Stream<FileSystemEvent> watch({
+ int events = FileSystemEvent.all,
+ bool recursive = false,
+ }) =>
+ delegate.watch(events: events, recursive: recursive);
+
+ @override
+ bool get isAbsolute => delegate.isAbsolute;
+
+ @override
+ T get absolute => wrap(delegate.absolute as D);
+
+ @override
+ Directory get parent => wrapDirectory(delegate.parent);
+
+ @override
+ String get path => delegate.path;
+
+ @override
+ String get basename => fileSystem.path.basename(path);
+
+ @override
+ String get dirname => fileSystem.path.dirname(path);
+}
diff --git a/pkgs/file/lib/src/forwarding/forwarding_link.dart b/pkgs/file/lib/src/forwarding/forwarding_link.dart
new file mode 100644
index 0000000..7a60ecb
--- /dev/null
+++ b/pkgs/file/lib/src/forwarding/forwarding_link.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/src/io.dart' as io;
+import 'package:file/file.dart';
+
+/// A link that forwards all methods and properties to a delegate.
+mixin ForwardingLink
+ implements ForwardingFileSystemEntity<Link, io.Link>, Link {
+ @override
+ ForwardingLink wrap(io.Link delegate) => wrapLink(delegate) as ForwardingLink;
+
+ @override
+ Future<Link> create(String target, {bool recursive = false}) async =>
+ wrap(await delegate.create(target, recursive: recursive));
+
+ @override
+ void createSync(String target, {bool recursive = false}) =>
+ delegate.createSync(target, recursive: recursive);
+
+ @override
+ Future<Link> update(String target) async =>
+ wrap(await delegate.update(target));
+
+ @override
+ void updateSync(String target) => delegate.updateSync(target);
+
+ @override
+ Future<String> target() => delegate.target();
+
+ @override
+ String targetSync() => delegate.targetSync();
+}
diff --git a/pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart b/pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart
new file mode 100644
index 0000000..9dd4079
--- /dev/null
+++ b/pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart
@@ -0,0 +1,149 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:file/src/io.dart' as io;
+import 'package:meta/meta.dart';
+
+/// A [RandomAccessFile] implementation that forwards all methods and properties
+/// to a delegate.
+mixin ForwardingRandomAccessFile implements io.RandomAccessFile {
+ /// The entity to which this entity will forward all methods and properties.
+ @protected
+ io.RandomAccessFile get delegate;
+
+ @override
+ String get path => delegate.path;
+
+ @override
+ Future<void> close() => delegate.close();
+
+ @override
+ void closeSync() => delegate.closeSync();
+
+ @override
+ Future<io.RandomAccessFile> flush() async {
+ await delegate.flush();
+ return this;
+ }
+
+ @override
+ void flushSync() => delegate.flushSync();
+
+ @override
+ Future<int> length() => delegate.length();
+
+ @override
+ int lengthSync() => delegate.lengthSync();
+
+ @override
+ Future<io.RandomAccessFile> lock([
+ io.FileLock mode = io.FileLock.exclusive,
+ int start = 0,
+ int end = -1,
+ ]) async {
+ await delegate.lock(mode, start, end);
+ return this;
+ }
+
+ @override
+ void lockSync([
+ io.FileLock mode = io.FileLock.exclusive,
+ int start = 0,
+ int end = -1,
+ ]) =>
+ delegate.lockSync(mode, start, end);
+
+ @override
+ Future<int> position() => delegate.position();
+
+ @override
+ int positionSync() => delegate.positionSync();
+
+ @override
+ Future<Uint8List> read(int bytes) => delegate.read(bytes);
+
+ @override
+ Uint8List readSync(int bytes) => delegate.readSync(bytes);
+
+ @override
+ Future<int> readByte() => delegate.readByte();
+
+ @override
+ int readByteSync() => delegate.readByteSync();
+
+ @override
+ Future<int> readInto(List<int> buffer, [int start = 0, int? end]) =>
+ delegate.readInto(buffer, start, end);
+
+ @override
+ int readIntoSync(List<int> buffer, [int start = 0, int? end]) =>
+ delegate.readIntoSync(buffer, start, end);
+
+ @override
+ Future<io.RandomAccessFile> setPosition(int position) async {
+ await delegate.setPosition(position);
+ return this;
+ }
+
+ @override
+ void setPositionSync(int position) => delegate.setPositionSync(position);
+
+ @override
+ Future<io.RandomAccessFile> truncate(int length) async {
+ await delegate.truncate(length);
+ return this;
+ }
+
+ @override
+ void truncateSync(int length) => delegate.truncateSync(length);
+
+ @override
+ Future<io.RandomAccessFile> unlock([int start = 0, int end = -1]) async {
+ await delegate.unlock(start, end);
+ return this;
+ }
+
+ @override
+ void unlockSync([int start = 0, int end = -1]) =>
+ delegate.unlockSync(start, end);
+
+ @override
+ Future<io.RandomAccessFile> writeByte(int value) async {
+ await delegate.writeByte(value);
+ return this;
+ }
+
+ @override
+ int writeByteSync(int value) => delegate.writeByteSync(value);
+
+ @override
+ Future<io.RandomAccessFile> writeFrom(
+ List<int> buffer, [
+ int start = 0,
+ int? end,
+ ]) async {
+ await delegate.writeFrom(buffer, start, end);
+ return this;
+ }
+
+ @override
+ void writeFromSync(List<int> buffer, [int start = 0, int? end]) =>
+ delegate.writeFromSync(buffer, start, end);
+
+ @override
+ Future<io.RandomAccessFile> writeString(
+ String string, {
+ Encoding encoding = utf8,
+ }) async {
+ await delegate.writeString(string, encoding: encoding);
+ return this;
+ }
+
+ @override
+ void writeStringSync(String string, {Encoding encoding = utf8}) =>
+ delegate.writeStringSync(string, encoding: encoding);
+}
diff --git a/pkgs/file/lib/src/interface.dart b/pkgs/file/lib/src/interface.dart
new file mode 100644
index 0000000..4662e35
--- /dev/null
+++ b/pkgs/file/lib/src/interface.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library file.src.interface;
+
+export 'interface/directory.dart';
+export 'interface/error_codes.dart';
+export 'interface/file.dart';
+export 'interface/file_system.dart';
+export 'interface/file_system_entity.dart';
+export 'interface/link.dart';
+export 'io.dart' hide Directory, File, FileSystemEntity, Link;
diff --git a/pkgs/file/lib/src/interface/directory.dart b/pkgs/file/lib/src/interface/directory.dart
new file mode 100644
index 0000000..e62ad8c
--- /dev/null
+++ b/pkgs/file/lib/src/interface/directory.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../io.dart' as io;
+
+import 'file.dart';
+import 'file_system_entity.dart';
+import 'link.dart';
+
+/// A reference to a directory on the file system.
+abstract class Directory implements FileSystemEntity, io.Directory {
+ // Override method definitions to codify the return type covariance.
+ @override
+ Future<Directory> create({bool recursive = false});
+
+ @override
+ Future<Directory> createTemp([String? prefix]);
+
+ @override
+ Directory createTempSync([String? prefix]);
+
+ @override
+ Future<Directory> rename(String newPath);
+
+ @override
+ Directory renameSync(String newPath);
+
+ @override
+ Directory get absolute;
+
+ @override
+ Stream<FileSystemEntity> list(
+ {bool recursive = false, bool followLinks = true});
+
+ @override
+ List<FileSystemEntity> listSync(
+ {bool recursive = false, bool followLinks = true});
+
+ /// Returns a reference to a [Directory] that exists as a child of this
+ /// directory and has the specified [basename].
+ Directory childDirectory(String basename);
+
+ /// Returns a reference to a [File] that exists as a child of this directory
+ /// and has the specified [basename].
+ File childFile(String basename);
+
+ /// Returns a reference to a [Link] that exists as a child of this directory
+ /// and has the specified [basename].
+ Link childLink(String basename);
+}
diff --git a/pkgs/file/lib/src/interface/error_codes.dart b/pkgs/file/lib/src/interface/error_codes.dart
new file mode 100644
index 0000000..8943538
--- /dev/null
+++ b/pkgs/file/lib/src/interface/error_codes.dart
@@ -0,0 +1,585 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'error_codes_internal.dart'
+ if (dart.library.io) 'error_codes_dart_io.dart';
+
+/// Operating system error codes.
+// TODO(tvolkert): Remove (https://github.com/dart-lang/sdk/issues/28860)
+class ErrorCodes {
+ ErrorCodes._();
+
+ /// Argument list too long
+ // ignore: non_constant_identifier_names
+ static int get E2BIG => _platform((_Codes codes) => codes.e2big);
+
+ /// Permission denied
+ // ignore: non_constant_identifier_names
+ static int get EACCES => _platform((_Codes codes) => codes.eacces);
+
+ /// Try again
+ // ignore: non_constant_identifier_names
+ static int get EAGAIN => _platform((_Codes codes) => codes.eagain);
+
+ /// Bad file number
+ // ignore: non_constant_identifier_names
+ static int get EBADF => _platform((_Codes codes) => codes.ebadf);
+
+ /// Device or resource busy
+ // ignore: non_constant_identifier_names
+ static int get EBUSY => _platform((_Codes codes) => codes.ebusy);
+
+ /// No child processes
+ // ignore: non_constant_identifier_names
+ static int get ECHILD => _platform((_Codes codes) => codes.echild);
+
+ /// Resource deadlock would occur
+ // ignore: non_constant_identifier_names
+ static int get EDEADLK => _platform((_Codes codes) => codes.edeadlk);
+
+ /// Math argument out of domain of func
+ // ignore: non_constant_identifier_names
+ static int get EDOM => _platform((_Codes codes) => codes.edom);
+
+ /// File exists
+ // ignore: non_constant_identifier_names
+ static int get EEXIST => _platform((_Codes codes) => codes.eexist);
+
+ /// Bad address
+ // ignore: non_constant_identifier_names
+ static int get EFAULT => _platform((_Codes codes) => codes.efault);
+
+ /// File too large
+ // ignore: non_constant_identifier_names
+ static int get EFBIG => _platform((_Codes codes) => codes.efbig);
+
+ /// Illegal byte sequence
+ // ignore: non_constant_identifier_names
+ static int get EILSEQ => _platform((_Codes codes) => codes.eilseq);
+
+ /// Interrupted system call
+ // ignore: non_constant_identifier_names
+ static int get EINTR => _platform((_Codes codes) => codes.eintr);
+
+ /// Invalid argument
+ // ignore: non_constant_identifier_names
+ static int get EINVAL => _platform((_Codes codes) => codes.einval);
+
+ /// I/O error
+ // ignore: non_constant_identifier_names
+ static int get EIO => _platform((_Codes codes) => codes.eio);
+
+ /// Is a directory
+ // ignore: non_constant_identifier_names
+ static int get EISDIR => _platform((_Codes codes) => codes.eisdir);
+
+ /// Too many levels of symbolic links
+ // ignore: non_constant_identifier_names
+ static int get ELOOP => _platform((_Codes codes) => codes.eloop);
+
+ /// Too many open files
+ // ignore: non_constant_identifier_names
+ static int get EMFILE => _platform((_Codes codes) => codes.emfile);
+
+ /// Too many links
+ // ignore: non_constant_identifier_names
+ static int get EMLINK => _platform((_Codes codes) => codes.emlink);
+
+ /// File name too long
+ // ignore: non_constant_identifier_names
+ static int get ENAMETOOLONG =>
+ _platform((_Codes codes) => codes.enametoolong);
+
+ /// File table overflow
+ // ignore: non_constant_identifier_names
+ static int get ENFILE => _platform((_Codes codes) => codes.enfile);
+
+ /// No such device
+ // ignore: non_constant_identifier_names
+ static int get ENODEV => _platform((_Codes codes) => codes.enodev);
+
+ /// No such file or directory
+ // ignore: non_constant_identifier_names
+ static int get ENOENT => _platform((_Codes codes) => codes.enoent);
+
+ /// Exec format error
+ // ignore: non_constant_identifier_names
+ static int get ENOEXEC => _platform((_Codes codes) => codes.enoexec);
+
+ /// No record locks available
+ // ignore: non_constant_identifier_names
+ static int get ENOLCK => _platform((_Codes codes) => codes.enolck);
+
+ /// Out of memory
+ // ignore: non_constant_identifier_names
+ static int get ENOMEM => _platform((_Codes codes) => codes.enomem);
+
+ /// No space left on device
+ // ignore: non_constant_identifier_names
+ static int get ENOSPC => _platform((_Codes codes) => codes.enospc);
+
+ /// Function not implemented
+ // ignore: non_constant_identifier_names
+ static int get ENOSYS => _platform((_Codes codes) => codes.enosys);
+
+ /// Not a directory
+ // ignore: non_constant_identifier_names
+ static int get ENOTDIR => _platform((_Codes codes) => codes.enotdir);
+
+ /// Directory not empty
+ // ignore: non_constant_identifier_names
+ static int get ENOTEMPTY => _platform((_Codes codes) => codes.enotempty);
+
+ /// Not a typewriter
+ // ignore: non_constant_identifier_names
+ static int get ENOTTY => _platform((_Codes codes) => codes.enotty);
+
+ /// No such device or address
+ // ignore: non_constant_identifier_names
+ static int get ENXIO => _platform((_Codes codes) => codes.enxio);
+
+ /// Operation not permitted
+ // ignore: non_constant_identifier_names
+ static int get EPERM => _platform((_Codes codes) => codes.eperm);
+
+ /// Broken pipe
+ // ignore: non_constant_identifier_names
+ static int get EPIPE => _platform((_Codes codes) => codes.epipe);
+
+ /// Math result not representable
+ // ignore: non_constant_identifier_names
+ static int get ERANGE => _platform((_Codes codes) => codes.erange);
+
+ /// Read-only file system
+ // ignore: non_constant_identifier_names
+ static int get EROFS => _platform((_Codes codes) => codes.erofs);
+
+ /// Illegal seek
+ // ignore: non_constant_identifier_names
+ static int get ESPIPE => _platform((_Codes codes) => codes.espipe);
+
+ /// No such process
+ // ignore: non_constant_identifier_names
+ static int get ESRCH => _platform((_Codes codes) => codes.esrch);
+
+ /// Cross-device link
+ // ignore: non_constant_identifier_names
+ static int get EXDEV => _platform((_Codes codes) => codes.exdev);
+
+ static int _platform(int Function(_Codes codes) getCode) {
+ _Codes codes = (_platforms[operatingSystem] ?? _platforms['linux'])!;
+ return getCode(codes);
+ }
+}
+
+const Map<String, _Codes> _platforms = <String, _Codes>{
+ 'linux': _LinuxCodes(),
+ 'macos': _MacOSCodes(),
+ 'windows': _WindowsCodes(),
+};
+
+abstract class _Codes {
+ int get e2big;
+ int get eacces;
+ int get eagain;
+ int get ebadf;
+ int get ebusy;
+ int get echild;
+ int get edeadlk;
+ int get edom;
+ int get eexist;
+ int get efault;
+ int get efbig;
+ int get eilseq;
+ int get eintr;
+ int get einval;
+ int get eio;
+ int get eisdir;
+ int get eloop;
+ int get emfile;
+ int get emlink;
+ int get enametoolong;
+ int get enfile;
+ int get enodev;
+ int get enoent;
+ int get enoexec;
+ int get enolck;
+ int get enomem;
+ int get enospc;
+ int get enosys;
+ int get enotdir;
+ int get enotempty;
+ int get enotty;
+ int get enxio;
+ int get eperm;
+ int get epipe;
+ int get erange;
+ int get erofs;
+ int get espipe;
+ int get esrch;
+ int get exdev;
+}
+
+class _LinuxCodes implements _Codes {
+ const _LinuxCodes();
+
+ @override
+ int get e2big => 7;
+
+ @override
+ int get eacces => 13;
+
+ @override
+ int get eagain => 11;
+
+ @override
+ int get ebadf => 9;
+
+ @override
+ int get ebusy => 16;
+
+ @override
+ int get echild => 10;
+
+ @override
+ int get edeadlk => 35;
+
+ @override
+ int get edom => 33;
+
+ @override
+ int get eexist => 17;
+
+ @override
+ int get efault => 14;
+
+ @override
+ int get efbig => 27;
+
+ @override
+ int get eilseq => 84;
+
+ @override
+ int get eintr => 4;
+
+ @override
+ int get einval => 22;
+
+ @override
+ int get eio => 5;
+
+ @override
+ int get eisdir => 21;
+
+ @override
+ int get eloop => 40;
+
+ @override
+ int get emfile => 24;
+
+ @override
+ int get emlink => 31;
+
+ @override
+ int get enametoolong => 36;
+
+ @override
+ int get enfile => 23;
+
+ @override
+ int get enodev => 19;
+
+ @override
+ int get enoent => 2;
+
+ @override
+ int get enoexec => 8;
+
+ @override
+ int get enolck => 37;
+
+ @override
+ int get enomem => 12;
+
+ @override
+ int get enospc => 28;
+
+ @override
+ int get enosys => 38;
+
+ @override
+ int get enotdir => 20;
+
+ @override
+ int get enotempty => 39;
+
+ @override
+ int get enotty => 25;
+
+ @override
+ int get enxio => 6;
+
+ @override
+ int get eperm => 1;
+
+ @override
+ int get epipe => 32;
+
+ @override
+ int get erange => 34;
+
+ @override
+ int get erofs => 30;
+
+ @override
+ int get espipe => 29;
+
+ @override
+ int get esrch => 3;
+
+ @override
+ int get exdev => 18;
+}
+
+class _MacOSCodes implements _Codes {
+ const _MacOSCodes();
+
+ @override
+ int get e2big => 7;
+
+ @override
+ int get eacces => 13;
+
+ @override
+ int get eagain => 35;
+
+ @override
+ int get ebadf => 9;
+
+ @override
+ int get ebusy => 16;
+
+ @override
+ int get echild => 10;
+
+ @override
+ int get edeadlk => 11;
+
+ @override
+ int get edom => 33;
+
+ @override
+ int get eexist => 17;
+
+ @override
+ int get efault => 14;
+
+ @override
+ int get efbig => 27;
+
+ @override
+ int get eilseq => 92;
+
+ @override
+ int get eintr => 4;
+
+ @override
+ int get einval => 22;
+
+ @override
+ int get eio => 5;
+
+ @override
+ int get eisdir => 21;
+
+ @override
+ int get eloop => 62;
+
+ @override
+ int get emfile => 24;
+
+ @override
+ int get emlink => 31;
+
+ @override
+ int get enametoolong => 63;
+
+ @override
+ int get enfile => 23;
+
+ @override
+ int get enodev => 19;
+
+ @override
+ int get enoent => 2;
+
+ @override
+ int get enoexec => 8;
+
+ @override
+ int get enolck => 77;
+
+ @override
+ int get enomem => 12;
+
+ @override
+ int get enospc => 28;
+
+ @override
+ int get enosys => 78;
+
+ @override
+ int get enotdir => 20;
+
+ @override
+ int get enotempty => 66;
+
+ @override
+ int get enotty => 25;
+
+ @override
+ int get enxio => 6;
+
+ @override
+ int get eperm => 1;
+
+ @override
+ int get epipe => 32;
+
+ @override
+ int get erange => 34;
+
+ @override
+ int get erofs => 30;
+
+ @override
+ int get espipe => 29;
+
+ @override
+ int get esrch => 3;
+
+ @override
+ int get exdev => 18;
+}
+
+class _WindowsCodes implements _Codes {
+ const _WindowsCodes();
+
+ @override
+ int get e2big => 7;
+
+ @override
+ int get eacces => 13;
+
+ @override
+ int get eagain => 11;
+
+ @override
+ int get ebadf => 9;
+
+ @override
+ int get ebusy => 16;
+
+ @override
+ int get echild => 10;
+
+ @override
+ int get edeadlk => 36;
+
+ @override
+ int get edom => 33;
+
+ @override
+ int get eexist => 17;
+
+ @override
+ int get efault => 14;
+
+ @override
+ int get efbig => 27;
+
+ @override
+ int get eilseq => 42;
+
+ @override
+ int get eintr => 4;
+
+ @override
+ int get einval => 22;
+
+ @override
+ int get eio => 5;
+
+ @override
+ int get eisdir => 21;
+
+ @override
+ int get eloop => -1;
+
+ @override
+ int get emfile => 24;
+
+ @override
+ int get emlink => 31;
+
+ @override
+ int get enametoolong => 38;
+
+ @override
+ int get enfile => 23;
+
+ @override
+ int get enodev => 19;
+
+ @override
+ int get enoent => 2;
+
+ @override
+ int get enoexec => 8;
+
+ @override
+ int get enolck => 39;
+
+ @override
+ int get enomem => 12;
+
+ @override
+ int get enospc => 28;
+
+ @override
+ int get enosys => 40;
+
+ @override
+ int get enotdir => 20;
+
+ @override
+ int get enotempty => 41;
+
+ @override
+ int get enotty => 25;
+
+ @override
+ int get enxio => 6;
+
+ @override
+ int get eperm => 1;
+
+ @override
+ int get epipe => 32;
+
+ @override
+ int get erange => 34;
+
+ @override
+ int get erofs => 30;
+
+ @override
+ int get espipe => 29;
+
+ @override
+ int get esrch => 3;
+
+ @override
+ int get exdev => 18;
+}
diff --git a/pkgs/file/lib/src/interface/error_codes_dart_io.dart b/pkgs/file/lib/src/interface/error_codes_dart_io.dart
new file mode 100644
index 0000000..3f0a97f
--- /dev/null
+++ b/pkgs/file/lib/src/interface/error_codes_dart_io.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' show Platform;
+
+/// If we have `dart:io` available, we pull the current operating system from
+/// the [Platform] class, so we'll get errno values that match our current
+/// operating system.
+final String operatingSystem = Platform.operatingSystem;
diff --git a/pkgs/file/lib/src/interface/error_codes_internal.dart b/pkgs/file/lib/src/interface/error_codes_internal.dart
new file mode 100644
index 0000000..0a9d7dc
--- /dev/null
+++ b/pkgs/file/lib/src/interface/error_codes_internal.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// In environments that don't have `dart:io`, we can't access the Platform
+/// class to determine what platform we're on, so we just pretend we're on
+/// Linux, meaning we'll get errno values that match Linux's errno.h.
+const String operatingSystem = 'linux';
diff --git a/pkgs/file/lib/src/interface/file.dart b/pkgs/file/lib/src/interface/file.dart
new file mode 100644
index 0000000..87417c6
--- /dev/null
+++ b/pkgs/file/lib/src/interface/file.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import '../io.dart' as io;
+
+import 'file_system_entity.dart';
+
+/// A reference to a file on the file system.
+abstract class File implements FileSystemEntity, io.File {
+ // Override method definitions to codify the return type covariance.
+ @override
+ Future<File> create({bool recursive = false, bool exclusive = false});
+
+ @override
+ Future<File> rename(String newPath);
+
+ @override
+ File renameSync(String newPath);
+
+ @override
+ Future<File> copy(String newPath);
+
+ @override
+ File copySync(String newPath);
+
+ @override
+ File get absolute;
+
+ @override
+ Future<File> writeAsBytes(List<int> bytes,
+ {io.FileMode mode = io.FileMode.write, bool flush = false});
+
+ @override
+ Future<File> writeAsString(String contents,
+ {io.FileMode mode = io.FileMode.write,
+ Encoding encoding = utf8,
+ bool flush = false});
+}
diff --git a/pkgs/file/lib/src/interface/file_system.dart b/pkgs/file/lib/src/interface/file_system.dart
new file mode 100644
index 0000000..ecc01a8
--- /dev/null
+++ b/pkgs/file/lib/src/interface/file_system.dart
@@ -0,0 +1,163 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:meta/meta.dart';
+import 'package:path/path.dart' as p;
+
+import '../io.dart' as io;
+
+import 'directory.dart';
+import 'file.dart';
+import 'file_system_entity.dart';
+import 'link.dart';
+
+/// A generic representation of a file system.
+///
+/// Note that this class uses `dart:io` only inasmuch as it deals in the types
+/// exposed by the `dart:io` library. Subclasses should document their level of
+/// dependence on the library (and the associated implications of using that
+/// implementation in the browser).
+abstract class FileSystem {
+ /// Creates a new `FileSystem`.
+ const FileSystem();
+
+ /// Returns a reference to a [Directory] at [path].
+ ///
+ /// [path] can be either a [String], a [Uri], or a [FileSystemEntity].
+ Directory directory(dynamic path);
+
+ /// Returns a reference to a [File] at [path].
+ ///
+ /// [path] can be either a [String], a [Uri], or a [FileSystemEntity].
+ File file(dynamic path);
+
+ /// Returns a reference to a [Link] at [path].
+ ///
+ /// [path] can be either a [String], a [Uri], or a [FileSystemEntity].
+ Link link(dynamic path);
+
+ /// An object for manipulating paths in this file system.
+ p.Context get path;
+
+ /// Gets the system temp directory.
+ ///
+ /// It is left to file system implementations to decide how to define the
+ /// "system temp directory".
+ Directory get systemTempDirectory;
+
+ /// Creates a directory object pointing to the current working directory.
+ Directory get currentDirectory;
+
+ /// Sets the current working directory to the specified [path].
+ ///
+ /// The new value set can be either a [Directory] or a [String].
+ ///
+ /// Relative paths will be resolved by the underlying file system
+ /// implementation (meaning it is up to the underlying implementation to
+ /// decide whether to support relative paths).
+ set currentDirectory(dynamic path);
+
+ /// Asynchronously calls the operating system's stat() function on [path].
+ /// Returns a Future which completes with a [io.FileStat] object containing
+ /// the data returned by stat().
+ /// If the call fails, completes the future with a [io.FileStat] object with
+ /// .type set to FileSystemEntityType.NOT_FOUND and the other fields invalid.
+ Future<io.FileStat> stat(String path);
+
+ /// Calls the operating system's stat() function on [path].
+ /// Returns a [io.FileStat] object containing the data returned by stat().
+ /// If the call fails, returns a [io.FileStat] object with .type set to
+ /// FileSystemEntityType.NOT_FOUND and the other fields invalid.
+ io.FileStat statSync(String path);
+
+ /// Checks whether two paths refer to the same object in the
+ /// file system. Returns a [Future<bool>] that completes with the result.
+ ///
+ /// Comparing a link to its target returns false, as does comparing two links
+ /// that point to the same target. To check the target of a link, use
+ /// Link.target explicitly to fetch it. Directory links appearing
+ /// inside a path are followed, though, to find the file system object.
+ ///
+ /// Completes the returned Future with an error if one of the paths points
+ /// to an object that does not exist.
+ Future<bool> identical(String path1, String path2);
+
+ /// Synchronously checks whether two paths refer to the same object in the
+ /// file system.
+ ///
+ /// Comparing a link to its target returns false, as does comparing two links
+ /// that point to the same target. To check the target of a link, use
+ /// Link.target explicitly to fetch it. Directory links appearing
+ /// inside a path are followed, though, to find the file system object.
+ ///
+ /// Throws an error if one of the paths points to an object that does not
+ /// exist.
+ bool identicalSync(String path1, String path2);
+
+ /// Tests if [FileSystemEntity.watch] is supported on the current system.
+ bool get isWatchSupported;
+
+ /// Finds the type of file system object that a [path] points to. Returns
+ /// a Future<FileSystemEntityType> that completes with the result.
+ ///
+ /// [io.FileSystemEntityType.LINK] will only be returned if [followLinks] is
+ /// `false`, and [path] points to a link
+ ///
+ /// If the [path] does not point to a file system object or an error occurs
+ /// then [io.FileSystemEntityType.notFound] is returned.
+ Future<io.FileSystemEntityType> type(String path, {bool followLinks = true});
+
+ /// Syncronously finds the type of file system object that a [path] points
+ /// to. Returns a [io.FileSystemEntityType].
+ ///
+ /// [io.FileSystemEntityType.LINK] will only be returned if [followLinks] is
+ /// `false`, and [path] points to a link
+ ///
+ /// If the [path] does not point to a file system object or an error occurs
+ /// then [io.FileSystemEntityType.notFound] is returned.
+ io.FileSystemEntityType typeSync(String path, {bool followLinks = true});
+
+ /// Checks if [`type(path)`](type) returns [io.FileSystemEntityType.FILE].
+ Future<bool> isFile(String path) async =>
+ await type(path) == io.FileSystemEntityType.file;
+
+ /// Synchronously checks if [`type(path)`](type) returns
+ /// [io.FileSystemEntityType.FILE].
+ bool isFileSync(String path) =>
+ typeSync(path) == io.FileSystemEntityType.file;
+
+ /// Checks if [`type(path)`](type) returns [io.FileSystemEntityType.DIRECTORY].
+ Future<bool> isDirectory(String path) async =>
+ await type(path) == io.FileSystemEntityType.directory;
+
+ /// Synchronously checks if [`type(path)`](type) returns
+ /// [io.FileSystemEntityType.DIRECTORY].
+ bool isDirectorySync(String path) =>
+ typeSync(path) == io.FileSystemEntityType.directory;
+
+ /// Checks if [`type(path)`](type) returns [io.FileSystemEntityType.LINK].
+ Future<bool> isLink(String path) async =>
+ await type(path, followLinks: false) == io.FileSystemEntityType.link;
+
+ /// Synchronously checks if [`type(path)`](type) returns
+ /// [io.FileSystemEntityType.LINK].
+ bool isLinkSync(String path) =>
+ typeSync(path, followLinks: false) == io.FileSystemEntityType.link;
+
+ /// Gets the string path represented by the specified generic [path].
+ ///
+ /// [path] may be a [io.FileSystemEntity], a [String], or a [Uri].
+ @protected
+ String getPath(dynamic path) {
+ if (path is io.FileSystemEntity) {
+ return path.path;
+ } else if (path is String) {
+ return path;
+ } else if (path is Uri) {
+ return this.path.fromUri(path);
+ } else {
+ throw ArgumentError('Invalid type for "path": ${path?.runtimeType}');
+ }
+ }
+}
diff --git a/pkgs/file/lib/src/interface/file_system_entity.dart b/pkgs/file/lib/src/interface/file_system_entity.dart
new file mode 100644
index 0000000..a377397
--- /dev/null
+++ b/pkgs/file/lib/src/interface/file_system_entity.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../io.dart' as io;
+
+import 'directory.dart';
+import 'file_system.dart';
+
+/// The common super class for [io.File], [io.Directory], and [io.Link] objects.
+abstract class FileSystemEntity implements io.FileSystemEntity {
+ /// Returns the file system responsible for this entity.
+ FileSystem get fileSystem;
+
+ /// Gets the part of this entity's path after the last separator.
+ ///
+ /// context.basename('path/to/foo.dart'); // -> 'foo.dart'
+ /// context.basename('path/to'); // -> 'to'
+ ///
+ /// Trailing separators are ignored.
+ ///
+ /// context.basename('path/to/'); // -> 'to'
+ String get basename;
+
+ /// Gets the part of this entity's path before the last separator.
+ ///
+ /// context.dirname('path/to/foo.dart'); // -> 'path/to'
+ /// context.dirname('path/to'); // -> 'path'
+ /// context.dirname('foo.dart'); // -> '.'
+ ///
+ /// Trailing separators are ignored.
+ ///
+ /// context.dirname('path/to/'); // -> 'path'
+ String get dirname;
+
+ // Override method definitions to codify the return type covariance.
+ @override
+ Future<FileSystemEntity> delete({bool recursive = false});
+
+ @override
+ Directory get parent;
+}
diff --git a/pkgs/file/lib/src/interface/link.dart b/pkgs/file/lib/src/interface/link.dart
new file mode 100644
index 0000000..27874b3
--- /dev/null
+++ b/pkgs/file/lib/src/interface/link.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../io.dart' as io;
+
+import 'file_system_entity.dart';
+
+/// A reference to a symbolic link on the file system.
+abstract class Link implements FileSystemEntity, io.Link {
+ // Override method definitions to codify the return type covariance.
+ @override
+ Future<Link> create(String target, {bool recursive = false});
+
+ @override
+ Future<Link> update(String target);
+
+ @override
+ Future<Link> rename(String newPath);
+
+ @override
+ Link renameSync(String newPath);
+
+ @override
+ Link get absolute;
+}
diff --git a/pkgs/file/lib/src/io.dart b/pkgs/file/lib/src/io.dart
new file mode 100644
index 0000000..9d57e78
--- /dev/null
+++ b/pkgs/file/lib/src/io.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// For internal use only!
+///
+/// This exposes the subset of the `dart:io` interfaces that are required by
+/// the `file` package. The `file` package re-exports these interfaces (or in
+/// some cases, implementations of these interfaces by the same name), so this
+/// file need not be exposes publicly and exists for internal use only.
+export 'dart:io'
+ show
+ Directory,
+ File,
+ FileLock,
+ FileMode,
+ FileStat,
+ FileSystemEntity,
+ FileSystemEntityType,
+ FileSystemEvent,
+ FileSystemException,
+ IOException,
+ IOSink,
+ Link,
+ OSError,
+ RandomAccessFile;
diff --git a/pkgs/file/pubspec.yaml b/pkgs/file/pubspec.yaml
new file mode 100644
index 0000000..5de5d37
--- /dev/null
+++ b/pkgs/file/pubspec.yaml
@@ -0,0 +1,17 @@
+name: file
+version: 7.0.1
+description: A pluggable, mockable file system abstraction for Dart.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/file
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Afile
+
+environment:
+ sdk: ^3.0.0
+
+dependencies:
+ meta: ^1.9.1
+ path: ^1.8.3
+
+dev_dependencies:
+ file_testing: ^3.0.0
+ lints: ^2.0.1
+ test: ^1.23.1
diff --git a/pkgs/file/test/chroot_test.dart b/pkgs/file/test/chroot_test.dart
new file mode 100644
index 0000000..6c34ff2
--- /dev/null
+++ b/pkgs/file/test/chroot_test.dart
@@ -0,0 +1,177 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+import 'dart:io' as io;
+
+import 'package:file/chroot.dart';
+import 'package:file/file.dart';
+import 'package:file/local.dart';
+import 'package:file/memory.dart';
+import 'package:file_testing/file_testing.dart';
+import 'package:test/test.dart';
+
+import 'common_tests.dart';
+
+void main() {
+ group('ChrootFileSystem', () {
+ ChrootFileSystem createMemoryBackedChrootFileSystem() {
+ MemoryFileSystem fs = MemoryFileSystem();
+ fs.directory('/tmp').createSync();
+ return ChrootFileSystem(fs, '/tmp');
+ }
+
+ // TODO(jamesderlin): Make ChrootFile.openSync return a delegating
+ // RandomAccessFile that uses the chroot'd path.
+ List<String> skipCommon = <String>[
+ 'File > open > .* > RandomAccessFile > read > openReadHandleDoesNotChange',
+ 'File > open > .* > RandomAccessFile > openWriteHandleDoesNotChange',
+ ];
+
+ group('memoryBacked', () {
+ runCommonTests(createMemoryBackedChrootFileSystem, skip: skipCommon);
+ });
+
+ group('localBacked', () {
+ late ChrootFileSystem fs;
+ late io.Directory tmp;
+
+ setUp(() {
+ tmp = io.Directory.systemTemp.createTempSync('file_test_');
+ tmp = io.Directory(tmp.resolveSymbolicLinksSync());
+ fs = ChrootFileSystem(const LocalFileSystem(), tmp.path);
+ });
+
+ tearDown(() {
+ tmp.deleteSync(recursive: true);
+ });
+
+ runCommonTests(
+ () => fs,
+ skip: <String>[
+ // https://github.com/dart-lang/sdk/issues/28275
+ 'Link > rename > throwsIfDestinationExistsAsDirectory',
+
+ // https://github.com/dart-lang/sdk/issues/28277
+ 'Link > rename > throwsIfDestinationExistsAsFile',
+
+ ...skipCommon,
+ ],
+ );
+ }, skip: io.Platform.isWindows);
+
+ group('chrootSpecific', () {
+ late ChrootFileSystem fs;
+ late MemoryFileSystem mem;
+
+ setUp(() {
+ fs = createMemoryBackedChrootFileSystem();
+ mem = fs.delegate as MemoryFileSystem;
+ });
+
+ group('FileSystem', () {
+ group('currentDirectory', () {
+ test('staysInJailIfSetToParentOfRoot', () {
+ fs.currentDirectory = '../../../..';
+ fs.file('foo').createSync();
+ expect(mem.file('/tmp/foo'), exists);
+ });
+
+ test('throwsIfSetToSymlinkToDirectoryOutsideJail', () {
+ mem.directory('/bar').createSync();
+ mem.link('/tmp/foo').createSync('/bar');
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.currentDirectory = '/foo';
+ });
+ });
+ });
+
+ group('stat', () {
+ test('isNotFoundForJailbreakPath', () {
+ mem.file('/foo').createSync();
+ expect(fs.statSync('../foo').type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundForSymlinkWithJailbreakTarget', () {
+ mem.file('/foo').createSync();
+ mem.link('/tmp/bar').createSync('/foo');
+ expect(mem.statSync('/tmp/bar').type, FileSystemEntityType.file);
+ expect(fs.statSync('/bar').type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundForSymlinkToOutsideAndBackInsideJail', () {
+ mem.file('/tmp/bar').createSync();
+ mem.link('/foo').createSync('/tmp/bar');
+ mem.link('/tmp/baz').createSync('/foo');
+ expect(mem.statSync('/tmp/baz').type, FileSystemEntityType.file);
+ expect(fs.statSync('/baz').type, FileSystemEntityType.notFound);
+ });
+ });
+
+ group('type', () {
+ test('isNotFoundForJailbreakPath', () {
+ mem.file('/foo').createSync();
+ expect(fs.typeSync('../foo'), FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundForSymlinkWithJailbreakTarget', () {
+ mem.file('/foo').createSync();
+ mem.link('/tmp/bar').createSync('/foo');
+ expect(mem.typeSync('/tmp/bar'), FileSystemEntityType.file);
+ expect(fs.typeSync('/bar'), FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundForSymlinkToOutsideAndBackInsideJail', () {
+ mem.file('/tmp/bar').createSync();
+ mem.link('/foo').createSync('/tmp/bar');
+ mem.link('/tmp/baz').createSync('/foo');
+ expect(mem.typeSync('/tmp/baz'), FileSystemEntityType.file);
+ expect(fs.typeSync('/baz'), FileSystemEntityType.notFound);
+ });
+ });
+ });
+
+ group('File', () {
+ group('delegate', () {
+ test('referencesRootEntityForJailbreakPath', () {
+ mem.file('/foo').createSync();
+ dynamic f = fs.file('../foo');
+ expect(f.delegate.path, '/tmp/foo');
+ });
+ });
+
+ group('create', () {
+ test('createsAtRootIfPathReferencesJailbreakFile', () {
+ fs.file('../foo').createSync();
+ expect(mem.file('/foo'), isNot(exists));
+ expect(mem.file('/tmp/foo'), exists);
+ });
+ });
+
+ group('copy', () {
+ test('copiesToRootDirectoryIfDestinationIsJailbreakPath', () {
+ File f = fs.file('/foo')..createSync();
+ f.copySync('../bar');
+ expect(mem.file('/bar'), isNot(exists));
+ expect(mem.file('/tmp/bar'), exists);
+ });
+ });
+ });
+
+ group('Link', () {
+ group('target', () {
+ test('chrootAndDelegateFileSystemsReturnSameValue', () {
+ mem.file('/foo').createSync();
+ mem.link('/tmp/bar').createSync('/foo');
+ mem.link('/tmp/baz').createSync('../foo');
+ expect(mem.link('/tmp/bar').targetSync(), '/foo');
+ expect(fs.link('/bar').targetSync(), '/foo');
+ expect(mem.link('/tmp/baz').targetSync(), '../foo');
+ expect(fs.link('/baz').targetSync(), '../foo');
+ });
+ });
+ });
+ });
+ });
+}
diff --git a/pkgs/file/test/common_tests.dart b/pkgs/file/test/common_tests.dart
new file mode 100644
index 0000000..6028c77
--- /dev/null
+++ b/pkgs/file/test/common_tests.dart
@@ -0,0 +1,3517 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io' as io;
+
+import 'package:file/file.dart';
+import 'package:file_testing/file_testing.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test/test.dart' as testpkg show group, setUp, tearDown, test;
+
+import 'utils.dart';
+
+/// Callback used in [runCommonTests] to produce the root folder in which all
+/// file system entities will be created.
+typedef RootPathGenerator = String Function();
+
+/// Callback used in [runCommonTests] to create the file system under test.
+/// It must return either a [FileSystem] or a [Future] that completes with a
+/// [FileSystem].
+typedef FileSystemGenerator = dynamic Function();
+
+/// A function to run before tests (passed to [setUp]) or after tests
+/// (passed to [tearDown]).
+typedef SetUpTearDown = dynamic Function();
+
+/// Runs a suite of tests common to all file system implementations. All file
+/// system implementations should run *at least* these tests to ensure
+/// compliance with file system API.
+///
+/// If [root] is specified, its return value will be used as the root folder
+/// in which all file system entities will be created. If not specified, the
+/// tests will attempt to create entities in the file system root.
+///
+/// [skip] may be used to skip certain tests (or entire groups of tests) in
+/// this suite (to be used, for instance, if a file system implementation is
+/// not yet fully complete). The format of each entry in the list is:
+/// `$group1Description > $group2Description > ... > $testDescription`.
+/// Entries may use regular expression syntax.
+///
+/// If [replay] is specified, each test (and its setup callbacks) will run
+/// twice - once as a "setup" pass with the file system returned by
+/// [createFileSystem], and again as the "test" pass with the file system
+/// returned by [replay]. This is intended for use with `ReplayFileSystem`,
+/// where in order for the file system to behave as expected, a recording of
+/// the invocation(s) must first be made.
+void runCommonTests(
+ FileSystemGenerator createFileSystem, {
+ RootPathGenerator? root,
+ List<String> skip = const <String>[],
+ FileSystemGenerator? replay,
+}) {
+ RootPathGenerator? rootfn = root;
+
+ group('common', () {
+ late FileSystemGenerator createFs;
+ late List<SetUpTearDown> setUps;
+ late List<SetUpTearDown> tearDowns;
+ late FileSystem fs;
+ late String root;
+ List<String> stack = <String>[];
+
+ void skipIfNecessary(String description, void Function() callback) {
+ stack.add(description);
+ bool matchesCurrentFrame(String input) =>
+ RegExp('^$input\$').hasMatch(stack.join(' > '));
+ if (skip.where(matchesCurrentFrame).isEmpty) {
+ callback();
+ }
+ stack.removeLast();
+ }
+
+ testpkg.setUp(() async {
+ createFs = createFileSystem;
+ setUps = <SetUpTearDown>[];
+ tearDowns = <SetUpTearDown>[];
+ });
+
+ void setUp(FutureOr<void> Function() callback) {
+ testpkg.setUp(replay == null ? callback : () => setUps.add(callback));
+ }
+
+ void tearDown(FutureOr<void> Function() callback) {
+ if (replay == null) {
+ testpkg.tearDown(callback);
+ } else {
+ testpkg.setUp(() => tearDowns.insert(0, callback));
+ }
+ }
+
+ void group(String description, void Function() body) =>
+ skipIfNecessary(description, () => testpkg.group(description, body));
+
+ void test(String description, FutureOr<void> Function() body,
+ {dynamic skip}) =>
+ skipIfNecessary(description, () {
+ if (replay == null) {
+ testpkg.test(description, body, skip: skip);
+ } else {
+ group('rerun', () {
+ testpkg.setUp(() async {
+ await Future.forEach(setUps, (SetUpTearDown setUp) => setUp());
+ await body();
+ for (SetUpTearDown tearDown in tearDowns) {
+ await tearDown();
+ }
+ createFs = replay;
+ await Future.forEach(setUps, (SetUpTearDown setUp) => setUp());
+ });
+
+ testpkg.test(description, body, skip: skip);
+
+ testpkg.tearDown(() async {
+ for (SetUpTearDown tearDown in tearDowns) {
+ await tearDown();
+ }
+ });
+ });
+ }
+ });
+
+ /// Returns [path] prefixed by the [root] namespace.
+ /// This is only intended for absolute paths.
+ String ns(String path) {
+ p.Context posix = p.Context(style: p.Style.posix);
+ List<String> parts = posix.split(path);
+ parts[0] = root;
+ path = fs.path.joinAll(parts);
+ String rootPrefix = fs.path.rootPrefix(path);
+ assert(rootPrefix.isNotEmpty);
+ String result = root == rootPrefix
+ ? path
+ : (path == rootPrefix
+ ? root
+ : fs.path.join(root, fs.path.joinAll(parts.sublist(1))));
+ return result;
+ }
+
+ setUp(() async {
+ root = rootfn != null ? rootfn() : '/';
+ fs = await createFs() as FileSystem;
+ assert(fs.path.isAbsolute(root));
+ assert(!root.endsWith(fs.path.separator) ||
+ fs.path.rootPrefix(root) == root);
+ });
+
+ group('FileSystem', () {
+ group('directory', () {
+ test('allowsStringArgument', () {
+ expect(fs.directory(ns('/foo')), isDirectory);
+ });
+
+ test('allowsUriArgument', () {
+ expect(fs.directory(Uri.parse('file:///')), isDirectory);
+ });
+
+ test('succeedsWithUriArgument', () {
+ fs.directory(ns('/foo')).createSync();
+ Uri uri = fs.path.toUri(ns('/foo'));
+ expect(fs.directory(uri), exists);
+ });
+
+ test('allowsDirectoryArgument', () {
+ expect(fs.directory(io.Directory(ns('/foo'))), isDirectory);
+ });
+
+ test('disallowsOtherArgumentType', () {
+ expect(() => fs.directory(123), throwsArgumentError);
+ });
+
+ // Fails due to
+ // https://github.com/google/file.dart/issues/112
+ test('considersBothSlashesEquivalent', () {
+ fs.directory(r'foo\bar_dir').createSync(recursive: true);
+ expect(fs.directory(r'foo/bar_dir'), exists);
+ }, skip: 'Fails due to https://github.com/google/file.dart/issues/112');
+ });
+
+ group('file', () {
+ test('allowsStringArgument', () {
+ expect(fs.file(ns('/foo')), isFile);
+ });
+
+ test('allowsUriArgument', () {
+ expect(fs.file(Uri.parse('file:///')), isFile);
+ });
+
+ test('succeedsWithUriArgument', () {
+ fs.file(ns('/foo')).createSync();
+ Uri uri = fs.path.toUri(ns('/foo'));
+ expect(fs.file(uri), exists);
+ });
+
+ test('allowsDirectoryArgument', () {
+ expect(fs.file(io.File(ns('/foo'))), isFile);
+ });
+
+ test('disallowsOtherArgumentType', () {
+ expect(() => fs.file(123), throwsArgumentError);
+ });
+
+ // Fails due to
+ // https://github.com/google/file.dart/issues/112
+ test('considersBothSlashesEquivalent', () {
+ fs.file(r'foo\bar_file').createSync(recursive: true);
+ expect(fs.file(r'foo/bar_file'), exists);
+ }, skip: 'Fails due to https://github.com/google/file.dart/issues/112');
+ });
+
+ group('link', () {
+ test('allowsStringArgument', () {
+ expect(fs.link(ns('/foo')), isLink);
+ });
+
+ test('allowsUriArgument', () {
+ expect(fs.link(Uri.parse('file:///')), isLink);
+ });
+
+ test('succeedsWithUriArgument', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ Uri uri = fs.path.toUri(ns('/bar'));
+ expect(fs.link(uri), exists);
+ });
+
+ test('allowsDirectoryArgument', () {
+ expect(fs.link(io.File(ns('/foo'))), isLink);
+ });
+
+ test('disallowsOtherArgumentType', () {
+ expect(() => fs.link(123), throwsArgumentError);
+ });
+ });
+
+ group('path', () {
+ test('hasCorrectCurrentWorkingDirectory', () {
+ expect(fs.path.current, fs.currentDirectory.path);
+ });
+
+ test('separatorIsAmongExpectedValues', () {
+ expect(fs.path.separator, anyOf('/', r'\'));
+ });
+ });
+
+ group('systemTempDirectory', () {
+ test('existsAsDirectory', () {
+ Directory tmp = fs.systemTempDirectory;
+ expect(tmp, isDirectory);
+ expect(tmp, exists);
+ });
+ });
+
+ group('currentDirectory', () {
+ test('defaultsToRoot', () {
+ expect(fs.currentDirectory.path, root);
+ });
+
+ test('throwsIfSetToNonExistentPath', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.currentDirectory = ns('/foo');
+ });
+ });
+
+ test('throwsIfHasNonExistentPathInComplexChain', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.currentDirectory = ns('/bar/../foo');
+ });
+ });
+
+ test('succeedsIfSetToValidStringPath', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.currentDirectory = ns('/foo');
+ expect(fs.currentDirectory.path, ns('/foo'));
+ });
+
+ test('succeedsIfSetToValidDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.currentDirectory = io.Directory(ns('/foo'));
+ expect(fs.currentDirectory.path, ns('/foo'));
+ });
+
+ test('throwsIfArgumentIsNotStringOrDirectory', () {
+ expect(() {
+ fs.currentDirectory = 123;
+ }, throwsArgumentError);
+ });
+
+ test('succeedsIfSetToRelativePath', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ fs.currentDirectory = 'foo';
+ expect(fs.currentDirectory.path, ns('/foo'));
+ fs.currentDirectory = 'bar';
+ expect(fs.currentDirectory.path, ns('/foo/bar'));
+ });
+
+ test('succeedsIfSetToAbsolutePathWhenCwdIsNotRoot', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ fs.directory(ns('/baz/qux')).createSync(recursive: true);
+ fs.currentDirectory = ns('/foo/bar');
+ expect(fs.currentDirectory.path, ns('/foo/bar'));
+ fs.currentDirectory = fs.directory(ns('/baz/qux'));
+ expect(fs.currentDirectory.path, ns('/baz/qux'));
+ });
+
+ test('succeedsIfSetToParentDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.currentDirectory = 'foo';
+ expect(fs.currentDirectory.path, ns('/foo'));
+ fs.currentDirectory = '..';
+ expect(fs.currentDirectory.path, ns('/'));
+ });
+
+ test('staysAtRootIfSetToParentOfRoot', () {
+ fs.currentDirectory =
+ List<String>.filled(20, '..').join(fs.path.separator);
+ String cwd = fs.currentDirectory.path;
+ expect(cwd, fs.path.rootPrefix(cwd));
+ });
+
+ test('removesTrailingSlashIfSet', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.currentDirectory = ns('/foo/');
+ expect(fs.currentDirectory.path, ns('/foo'));
+ });
+
+ test('throwsIfSetToFilePathSegmentAtTail', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ fs.currentDirectory = ns('/foo');
+ });
+ });
+
+ test('throwsIfSetToFilePathSegmentViaTraversal', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ fs.currentDirectory = ns('/foo/bar/baz');
+ });
+ });
+
+ test('resolvesLinksIfEncountered', () {
+ fs.link(ns('/foo/bar/baz')).createSync(ns('/qux'), recursive: true);
+ fs.directory(ns('/qux')).createSync();
+ fs.directory(ns('/quux')).createSync();
+ fs.currentDirectory = ns('/foo/bar/baz/../quux/');
+ expect(fs.currentDirectory.path, ns('/quux'));
+ });
+
+ test('succeedsIfSetToDirectoryLinkAtTail', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.currentDirectory = ns('/bar');
+ expect(fs.currentDirectory.path, ns('/foo'));
+ });
+
+ test('throwsIfSetToLinkLoop', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(
+ anyOf(ErrorCodes.EMLINK, ErrorCodes.ELOOP),
+ () {
+ fs.currentDirectory = ns('/foo');
+ },
+ );
+ });
+ });
+
+ group('stat', () {
+ test('isNotFoundForEmptyPath', () {
+ FileStat stat = fs.statSync('');
+ expect(stat.type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundForPathToNonExistentEntityAtTail', () {
+ FileStat stat = fs.statSync(ns('/foo'));
+ expect(stat.type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundForPathToNonExistentEntityInTraversal', () {
+ FileStat stat = fs.statSync(ns('/foo/bar'));
+ expect(stat.type, FileSystemEntityType.notFound);
+ });
+
+ test('isDirectoryForDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ FileStat stat = fs.statSync(ns('/foo'));
+ expect(stat.type, FileSystemEntityType.directory);
+ });
+
+ test('isFileForFile', () {
+ fs.file(ns('/foo')).createSync();
+ FileStat stat = fs.statSync(ns('/foo'));
+ expect(stat.type, FileSystemEntityType.file);
+ });
+
+ test('isFileForLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ FileStat stat = fs.statSync(ns('/bar'));
+ expect(stat.type, FileSystemEntityType.file);
+ });
+
+ test('isNotFoundForLinkWithCircularReference', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/baz'));
+ fs.link(ns('/baz')).createSync(ns('/foo'));
+ FileStat stat = fs.statSync(ns('/foo'));
+ expect(stat.type, FileSystemEntityType.notFound);
+ });
+ });
+
+ group('identical', () {
+ test('isTrueForIdenticalPathsToExistentFile', () {
+ fs.file(ns('/foo')).createSync();
+ expect(fs.identicalSync(ns('/foo'), ns('/foo')), true);
+ });
+
+ test('isFalseForDifferentPathsToDifferentFiles', () {
+ fs.file(ns('/foo')).createSync();
+ fs.file(ns('/bar')).createSync();
+ expect(fs.identicalSync(ns('/foo'), ns('/bar')), false);
+ });
+
+ test('isTrueForDifferentPathsToSameFileViaLinkInTraversal', () {
+ fs.file(ns('/foo/file')).createSync(recursive: true);
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.identicalSync(ns('/foo/file'), ns('/bar/file')), true);
+ });
+
+ test('isFalseForDifferentPathsToSameFileViaLinkAtTail', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.identicalSync(ns('/foo'), ns('/bar')), false);
+ });
+
+ test('throwsForDifferentPathsToNonExistentEntities', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.identicalSync(ns('/foo'), ns('/bar'));
+ });
+ });
+
+ test('throwsForDifferentPathsToOneFileOneNonExistentEntity', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.identicalSync(ns('/foo'), ns('/bar'));
+ });
+ });
+ });
+
+ group('type', () {
+ test('isFileForFile', () {
+ fs.file(ns('/foo')).createSync();
+ FileSystemEntityType type = fs.typeSync(ns('/foo'));
+ expect(type, FileSystemEntityType.file);
+ });
+
+ test('isDirectoryForDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ FileSystemEntityType type = fs.typeSync(ns('/foo'));
+ expect(type, FileSystemEntityType.directory);
+ });
+
+ test('isDirectoryForAncestorOfRoot', () {
+ FileSystemEntityType type = fs
+ .typeSync(List<String>.filled(20, '..').join(fs.path.separator));
+ expect(type, FileSystemEntityType.directory);
+ });
+
+ test('isFileForLinkToFileAndFollowLinksTrue', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ FileSystemEntityType type = fs.typeSync(ns('/bar'));
+ expect(type, FileSystemEntityType.file);
+ });
+
+ test('isLinkForLinkToFileAndFollowLinksFalse', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ FileSystemEntityType type =
+ fs.typeSync(ns('/bar'), followLinks: false);
+ expect(type, FileSystemEntityType.link);
+ });
+
+ test('isNotFoundForLinkWithCircularReferenceAndFollowLinksTrue', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/baz'));
+ fs.link(ns('/baz')).createSync(ns('/foo'));
+ FileSystemEntityType type = fs.typeSync(ns('/foo'));
+ expect(type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundForNoEntityAtTail', () {
+ FileSystemEntityType type = fs.typeSync(ns('/foo'));
+ expect(type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundForNoDirectoryInTraversal', () {
+ FileSystemEntityType type = fs.typeSync(ns('/foo/bar/baz'));
+ expect(type, FileSystemEntityType.notFound);
+ });
+ });
+
+ group('isFile/isDirectory/isLink', () {
+ late String filePath;
+ late String directoryPath;
+ late String fileLinkPath;
+ late String directoryLinkPath;
+
+ setUp(() {
+ filePath = ns('/file');
+ directoryPath = ns('/directory');
+ fileLinkPath = ns('/file-link');
+ directoryLinkPath = ns('/directory-link');
+
+ fs.file(filePath).createSync();
+ fs.directory(directoryPath).createSync();
+ fs.link(fileLinkPath).createSync(filePath);
+ fs.link(directoryLinkPath).createSync(directoryPath);
+ });
+
+ test('isFile', () {
+ expect(fs.isFileSync(filePath), true);
+ expect(fs.isFileSync(directoryPath), false);
+ expect(fs.isFileSync(fileLinkPath), true);
+ expect(fs.isFileSync(directoryLinkPath), false);
+ });
+
+ test('isDirectory', () {
+ expect(fs.isDirectorySync(filePath), false);
+ expect(fs.isDirectorySync(directoryPath), true);
+ expect(fs.isDirectorySync(fileLinkPath), false);
+ expect(fs.isDirectorySync(directoryLinkPath), true);
+ });
+
+ test('isLink', () {
+ expect(fs.isLinkSync(filePath), false);
+ expect(fs.isLinkSync(directoryPath), false);
+ expect(fs.isLinkSync(fileLinkPath), true);
+ expect(fs.isLinkSync(directoryLinkPath), true);
+ });
+ });
+ });
+
+ group('Directory', () {
+ test('uri', () {
+ expect(fs.directory(ns('/foo')).uri, fs.path.toUri('${ns('/foo')}/'));
+ expect(fs.directory('foo').uri.toString(), 'foo/');
+ });
+
+ group('exists', () {
+ test('falseIfNotExists', () {
+ expect(fs.directory(ns('/foo')), isNot(exists));
+ expect(fs.directory('foo'), isNot(exists));
+ expect(fs.directory(ns('/foo/bar')), isNot(exists));
+ });
+
+ test('trueIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expect(fs.directory(ns('/foo')), exists);
+ expect(fs.directory('foo'), exists);
+ });
+
+ test('falseIfExistsAsFile', () {
+ fs.file(ns('/foo')).createSync();
+ expect(fs.directory(ns('/foo')), isNot(exists));
+ expect(fs.directory('foo'), isNot(exists));
+ });
+
+ test('trueIfExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.directory(ns('/bar')), exists);
+ expect(fs.directory('bar'), exists);
+ });
+
+ test('falseIfExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.directory(ns('/bar')), isNot(exists));
+ expect(fs.directory('bar'), isNot(exists));
+ });
+
+ test('falseIfNotFoundSegmentExistsThenIsBackedOut', () {
+ fs.directory(ns('/foo')).createSync();
+ expect(fs.directory(ns('/bar/../foo')), isNot(exists));
+ });
+ });
+
+ group('create', () {
+ test('returnsCovariantType', () async {
+ expect(await fs.directory(ns('/foo')).create(), isDirectory);
+ });
+
+ test('succeedsIfAlreadyExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.directory(ns('/foo')).createSync();
+ });
+
+ test('throwsIfAlreadyExistsAsFile', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ fs.directory(ns('/foo')).createSync();
+ });
+ });
+
+ test('succeedsIfAlreadyExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.directory(ns('/bar')).createSync();
+ });
+
+ test('throwsIfAlreadyExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ // TODO(tvolkert): Change this to just be 'Not a directory'
+ // once Dart 1.22 is stable.
+ expectFileSystemException(
+ anyOf(ErrorCodes.EEXIST, ErrorCodes.ENOTDIR),
+ () {
+ fs.directory(ns('/bar')).createSync();
+ },
+ );
+ });
+
+ test('throwsIfAlreadyExistsAsLinkToNotFoundAtTail', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo')).createSync();
+ });
+ });
+
+ test('throwsIfAlreadyExistsAsLinkToNotFoundViaTraversal', () {
+ fs.link(ns('/foo')).createSync(ns('/bar/baz'));
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo')).createSync();
+ });
+ });
+
+ test('throwsIfAlreadyExistsAsLinkToNotFoundInDifferentDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.directory(ns('/bar')).createSync();
+ fs.link(ns('/bar/baz')).createSync(ns('/foo/qux'));
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/bar/baz')).createSync();
+ });
+ });
+
+ test('succeedsIfTailDoesntExist', () {
+ expect(fs.directory(ns('/')), exists);
+ fs.directory(ns('/foo')).createSync();
+ expect(fs.directory(ns('/foo')), exists);
+ });
+
+ test('throwsIfAncestorDoesntExistRecursiveFalse', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo/bar')).createSync();
+ });
+ });
+
+ test('succeedsIfAncestorDoesntExistRecursiveTrue', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ expect(fs.directory(ns('/foo')), exists);
+ expect(fs.directory(ns('/foo/bar')), exists);
+ });
+ });
+
+ group('rename', () {
+ test('returnsCovariantType', () async {
+ Directory src() => fs.directory(ns('/foo'))..createSync();
+ expect(src().renameSync(ns('/bar')), isDirectory);
+ expect(await src().rename(ns('/baz')), isDirectory);
+ });
+
+ test('succeedsIfDestinationDoesntExist', () {
+ Directory src = fs.directory(ns('/foo'))..createSync();
+ Directory dest = src.renameSync(ns('/bar'));
+ expect(dest.path, ns('/bar'));
+ expect(dest, exists);
+ });
+
+ test(
+ 'succeedsIfDestinationIsEmptyDirectory',
+ () {
+ fs.directory(ns('/bar')).createSync();
+ Directory src = fs.directory(ns('/foo'))..createSync();
+ Directory dest = src.renameSync(ns('/bar'));
+ expect(src, isNot(exists));
+ expect(dest, exists);
+ },
+ // See https://github.com/google/file.dart/issues/197.
+ skip: io.Platform.isWindows,
+ );
+
+ test('throwsIfDestinationIsFile', () {
+ fs.file(ns('/bar')).createSync();
+ Directory src = fs.directory(ns('/foo'))..createSync();
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ src.renameSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfDestinationParentFolderDoesntExist', () {
+ Directory src = fs.directory(ns('/foo'))..createSync();
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ src.renameSync(ns('/bar/baz'));
+ });
+ });
+
+ test('throwsIfDestinationIsNonEmptyDirectory', () {
+ fs.file(ns('/bar/baz')).createSync(recursive: true);
+ Directory src = fs.directory(ns('/foo'))..createSync();
+ // The error will be 'Directory not empty' on OS X, but it will be
+ // 'File exists' on Linux.
+ expectFileSystemException(
+ anyOf(ErrorCodes.ENOTEMPTY, ErrorCodes.EEXIST),
+ () {
+ src.renameSync(ns('/bar'));
+ },
+ );
+ });
+
+ test('throwsIfSourceDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo')).renameSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfSourceIsFile', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ fs.directory(ns('/foo')).renameSync(ns('/bar'));
+ });
+ });
+
+ test('succeedsIfSourceIsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.directory(ns('/bar')).renameSync(ns('/baz'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.directory);
+ expect(fs.typeSync(ns('/bar')), FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/baz')).targetSync(), ns('/foo'));
+ });
+
+ test('throwsIfDestinationIsLinkToNotFound', () {
+ Directory src = fs.directory(ns('/foo'))..createSync();
+ fs.link(ns('/bar')).createSync(ns('/baz'));
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ src.renameSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfDestinationIsLinkToEmptyDirectory', () {
+ Directory src = fs.directory(ns('/foo'))..createSync();
+ fs.directory(ns('/bar')).createSync();
+ fs.link(ns('/baz')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ src.renameSync(ns('/baz'));
+ });
+ });
+
+ test('succeedsIfDestinationIsInDifferentDirectory', () {
+ Directory src = fs.directory(ns('/foo'))..createSync();
+ fs.directory(ns('/bar')).createSync();
+ src.renameSync(ns('/bar/baz'));
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar/baz')), FileSystemEntityType.directory);
+ });
+
+ test('succeedsIfSourceIsLinkToDifferentDirectory', () {
+ fs.directory(ns('/foo/subfoo')).createSync(recursive: true);
+ fs.directory(ns('/bar/subbar')).createSync(recursive: true);
+ fs.directory(ns('/baz/subbaz')).createSync(recursive: true);
+ fs.link(ns('/foo/subfoo/lnk')).createSync(ns('/bar/subbar'));
+ fs.directory(ns('/foo/subfoo/lnk')).renameSync(ns('/baz/subbaz/dst'));
+ expect(fs.typeSync(ns('/foo/subfoo/lnk')),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/baz/subbaz/dst'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.typeSync(ns('/baz/subbaz/dst'), followLinks: true),
+ FileSystemEntityType.directory);
+ });
+ });
+
+ group('delete', () {
+ test('returnsCovariantType', () async {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ expect(await dir.delete(), isDirectory);
+ });
+
+ test('succeedsIfEmptyDirectoryExistsAndRecursiveFalse', () {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ dir.deleteSync();
+ expect(dir, isNot(exists));
+ });
+
+ test('succeedsIfEmptyDirectoryExistsAndRecursiveTrue', () {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ dir.deleteSync(recursive: true);
+ expect(dir, isNot(exists));
+ });
+
+ test('throwsIfNonEmptyDirectoryExistsAndRecursiveFalse', () {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ fs.file(ns('/foo/bar')).createSync();
+ expectFileSystemException(ErrorCodes.ENOTEMPTY, () {
+ dir.deleteSync();
+ });
+ });
+
+ test('succeedsIfNonEmptyDirectoryExistsAndRecursiveTrue', () {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ fs.file(ns('/foo/bar')).createSync();
+ dir.deleteSync(recursive: true);
+ expect(fs.directory(ns('/foo')), isNot(exists));
+ expect(fs.file(ns('/foo/bar')), isNot(exists));
+ });
+
+ test('throwsIfDirectoryDoesntExistAndRecursiveFalse', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo')).deleteSync();
+ });
+ });
+
+ test('throwsIfDirectoryDoesntExistAndRecursiveTrue', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo')).deleteSync(recursive: true);
+ });
+ });
+
+ test('succeedsIfPathReferencesFileAndRecursiveTrue', () {
+ fs.file(ns('/foo')).createSync();
+ fs.directory(ns('/foo')).deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound);
+ });
+
+ test('throwsIfPathReferencesFileAndRecursiveFalse', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ fs.directory(ns('/foo')).deleteSync();
+ });
+ });
+
+ test('succeedsIfPathReferencesLinkToDirectoryAndRecursiveTrue', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.directory(ns('/bar')).deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.directory);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.notFound);
+ });
+
+ test('succeedsIfPathReferencesLinkToDirectoryAndRecursiveFalse', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.directory(ns('/bar')).deleteSync();
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.directory);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.notFound);
+ });
+
+ test('succeedsIfExistsAsLinkToDirectoryInDifferentDirectory', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ fs.link(ns('/baz/qux')).createSync(ns('/foo/bar'), recursive: true);
+ fs.directory(ns('/baz/qux')).deleteSync();
+ expect(fs.typeSync(ns('/foo/bar'), followLinks: false),
+ FileSystemEntityType.directory);
+ expect(fs.typeSync(ns('/baz/qux'), followLinks: false),
+ FileSystemEntityType.notFound);
+ });
+
+ test('succeedsIfPathReferencesLinkToFileAndRecursiveTrue', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.directory(ns('/bar')).deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.notFound);
+ });
+
+ test('throwsIfPathReferencesLinkToFileAndRecursiveFalse', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ fs.directory(ns('/bar')).deleteSync();
+ });
+ });
+
+ test('throwsIfPathReferencesLinkToNotFoundAndRecursiveFalse', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.ENOTDIR, () {
+ fs.directory(ns('/foo')).deleteSync();
+ });
+ });
+ });
+
+ group('resolveSymbolicLinks', () {
+ test('succeedsForRootDirectory', () {
+ expect(fs.directory(ns('/')).resolveSymbolicLinksSync(), ns('/'));
+ });
+
+ test('throwsIfPathIsEmpty', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory('').resolveSymbolicLinksSync();
+ });
+ });
+
+ test('throwsIfLoopInLinkChain', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/baz'));
+ fs.link(ns('/baz')).createSync(ns('/foo'));
+ expectFileSystemException(
+ anyOf(ErrorCodes.EMLINK, ErrorCodes.ELOOP),
+ () {
+ fs.directory(ns('/foo')).resolveSymbolicLinksSync();
+ },
+ );
+ });
+
+ test('throwsIfPathNotFoundInTraversal', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo/bar')).resolveSymbolicLinksSync();
+ });
+ });
+
+ test('throwsIfPathNotFoundAtTail', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo')).resolveSymbolicLinksSync();
+ });
+ });
+
+ test('throwsIfPathNotFoundInMiddleThenBackedOut', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo/baz/../bar')).resolveSymbolicLinksSync();
+ });
+ });
+
+ test('resolvesRelativePathToCurrentDirectory', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ fs.link(ns('/foo/baz')).createSync(ns('/foo/bar'));
+ fs.currentDirectory = ns('/foo');
+ expect(
+ fs.directory('baz').resolveSymbolicLinksSync(), ns('/foo/bar'));
+ });
+
+ test('resolvesAbsolutePathsAbsolutely', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ fs.currentDirectory = ns('/foo');
+ expect(fs.directory(ns('/foo/bar')).resolveSymbolicLinksSync(),
+ ns('/foo/bar'));
+ });
+
+ test('handlesRelativeLinks', () {
+ fs.directory(ns('/foo/bar/baz')).createSync(recursive: true);
+ fs.link(ns('/foo/qux')).createSync(fs.path.join('bar', 'baz'));
+ expect(
+ fs.directory(ns('/foo/qux')).resolveSymbolicLinksSync(),
+ ns('/foo/bar/baz'),
+ );
+ expect(
+ fs.directory(fs.path.join('foo', 'qux')).resolveSymbolicLinksSync(),
+ ns('/foo/bar/baz'),
+ );
+ });
+
+ test('handlesAbsoluteLinks', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.directory(ns('/bar/baz/qux')).createSync(recursive: true);
+ fs.link(ns('/foo/quux')).createSync(ns('/bar/baz/qux'));
+ expect(fs.directory(ns('/foo/quux')).resolveSymbolicLinksSync(),
+ ns('/bar/baz/qux'));
+ });
+
+ test('handlesLinksWhoseTargetsHaveNestedLinks', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/foo/quuz')).createSync(ns('/bar'));
+ fs.link(ns('/foo/grault')).createSync(ns('/baz/quux'));
+ fs.directory(ns('/bar')).createSync();
+ fs.link(ns('/bar/qux')).createSync(ns('/baz'));
+ fs.link(ns('/bar/garply')).createSync(ns('/foo'));
+ fs.directory(ns('/baz')).createSync();
+ fs.link(ns('/baz/quux')).createSync(ns('/bar/garply/quuz'));
+ expect(fs.directory(ns('/foo/grault/qux')).resolveSymbolicLinksSync(),
+ ns('/baz'));
+ });
+
+ test('handlesParentAndThisFolderReferences', () {
+ fs.directory(ns('/foo/bar/baz')).createSync(recursive: true);
+ fs.link(ns('/foo/bar/baz/qux')).createSync(fs.path.join('..', '..'));
+ String resolved = fs
+ .directory(ns('/foo/./bar/baz/../baz/qux/bar'))
+ .resolveSymbolicLinksSync();
+ expect(resolved, ns('/foo/bar'));
+ });
+
+ test('handlesBackToBackSlashesInPath', () {
+ fs.directory(ns('/foo/bar/baz')).createSync(recursive: true);
+ expect(fs.directory(ns('//foo/bar///baz')).resolveSymbolicLinksSync(),
+ ns('/foo/bar/baz'));
+ });
+
+ test('handlesComplexPathWithMultipleLinks', () {
+ fs
+ .link(ns('/foo/bar/baz'))
+ .createSync(fs.path.join('..', '..', 'qux'), recursive: true);
+ fs.link(ns('/qux')).createSync('quux');
+ fs.link(ns('/quux/quuz')).createSync(ns('/foo'), recursive: true);
+ String resolved = fs
+ .directory(ns('/foo//bar/./baz/quuz/bar/..///bar/baz/'))
+ .resolveSymbolicLinksSync();
+ expect(resolved, ns('/quux'));
+ });
+ });
+
+ group('absolute', () {
+ test('returnsCovariantType', () {
+ expect(fs.directory('foo').absolute, isDirectory);
+ });
+
+ test('returnsSamePathIfAlreadyAbsolute', () {
+ expect(fs.directory(ns('/foo')).absolute.path, ns('/foo'));
+ });
+
+ test('succeedsForRelativePaths', () {
+ expect(fs.directory('foo').absolute.path, ns('/foo'));
+ });
+ });
+
+ group('parent', () {
+ late String root;
+
+ setUp(() {
+ root = fs.path.style.name == 'windows' ? r'C:\' : '/';
+ });
+
+ test('returnsCovariantType', () {
+ expect(fs.directory(root).parent, isDirectory);
+ });
+
+ test('returnsRootForRoot', () {
+ expect(fs.directory(root).parent.path, root);
+ });
+
+ test('succeedsForNonRoot', () {
+ expect(fs.directory(ns('/foo/bar')).parent.path, ns('/foo'));
+ });
+ });
+
+ group('createTemp', () {
+ test('returnsCovariantType', () {
+ expect(fs.directory(ns('/')).createTempSync(), isDirectory);
+ });
+
+ test('throwsIfDirectoryDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/foo')).createTempSync();
+ });
+ });
+
+ test('resolvesNameCollisions', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ Directory tmp = fs.directory(ns('/foo')).createTempSync('bar');
+ expect(tmp.path,
+ allOf(isNot(ns('/foo/bar')), startsWith(ns('/foo/bar'))));
+ });
+
+ test('succeedsWithoutPrefix', () {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ expect(dir.createTempSync().path, startsWith(ns('/foo/')));
+ });
+
+ test('succeedsWithPrefix', () {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ expect(dir.createTempSync('bar').path, startsWith(ns('/foo/bar')));
+ });
+
+ test('succeedsWithNestedPathPrefixThatExists', () {
+ fs.directory(ns('/foo/bar')).createSync(recursive: true);
+ Directory tmp = fs.directory(ns('/foo')).createTempSync('bar/baz');
+ expect(tmp.path, startsWith(ns('/foo/bar/baz')));
+ });
+
+ test('throwsWithNestedPathPrefixThatDoesntExist', () {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ dir.createTempSync('bar/baz');
+ });
+ });
+ });
+
+ group('list', () {
+ late Directory dir;
+
+ setUp(() {
+ dir = fs.currentDirectory = fs.directory(ns('/foo'))..createSync();
+ fs.file('bar').createSync();
+ fs.file(fs.path.join('baz', 'qux')).createSync(recursive: true);
+ fs.link('quux').createSync(fs.path.join('baz', 'qux'));
+ fs
+ .link(fs.path.join('baz', 'quuz'))
+ .createSync(fs.path.join('..', 'quux'));
+ fs.link(fs.path.join('baz', 'grault')).createSync('.');
+ fs.currentDirectory = ns('/');
+ });
+
+ test('returnsCovariantType', () async {
+ void expectIsFileSystemEntity(dynamic entity) {
+ expect(entity, isFileSystemEntity);
+ }
+
+ dir.listSync().forEach(expectIsFileSystemEntity);
+ (await dir.list().toList()).forEach(expectIsFileSystemEntity);
+ });
+
+ test('returnsEmptyListForEmptyDirectory', () {
+ Directory empty = fs.directory(ns('/bar'))..createSync();
+ expect(empty.listSync(), isEmpty);
+ });
+
+ test('throwsIfDirectoryDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.directory(ns('/bar')).listSync();
+ });
+ });
+
+ test('returnsLinkObjectsIfFollowLinksFalse', () {
+ List<FileSystemEntity> list = dir.listSync(followLinks: false);
+ expect(list, hasLength(3));
+ expect(list, contains(allOf(isFile, hasPath(ns('/foo/bar')))));
+ expect(list, contains(allOf(isDirectory, hasPath(ns('/foo/baz')))));
+ expect(list, contains(allOf(isLink, hasPath(ns('/foo/quux')))));
+ });
+
+ test('followsLinksIfFollowLinksTrue', () {
+ List<FileSystemEntity> list = dir.listSync();
+ expect(list, hasLength(3));
+ expect(list, contains(allOf(isFile, hasPath(ns('/foo/bar')))));
+ expect(list, contains(allOf(isDirectory, hasPath(ns('/foo/baz')))));
+ expect(list, contains(allOf(isFile, hasPath(ns('/foo/quux')))));
+ });
+
+ test('returnsLinkObjectsForRecursiveLinkIfFollowLinksTrue', () {
+ expect(
+ dir.listSync(recursive: true),
+ allOf(
+ hasLength(9),
+ allOf(
+ contains(allOf(isFile, hasPath(ns('/foo/bar')))),
+ contains(allOf(isFile, hasPath(ns('/foo/quux')))),
+ contains(allOf(isFile, hasPath(ns('/foo/baz/qux')))),
+ contains(allOf(isFile, hasPath(ns('/foo/baz/quuz')))),
+ contains(allOf(isFile, hasPath(ns('/foo/baz/grault/qux')))),
+ contains(allOf(isFile, hasPath(ns('/foo/baz/grault/quuz')))),
+ ),
+ allOf(
+ contains(allOf(isDirectory, hasPath(ns('/foo/baz')))),
+ contains(allOf(isDirectory, hasPath(ns('/foo/baz/grault')))),
+ ),
+ contains(allOf(isLink, hasPath(ns('/foo/baz/grault/grault')))),
+ ),
+ );
+ });
+
+ test('recurseIntoDirectoriesIfRecursiveTrueFollowLinksFalse', () {
+ expect(
+ dir.listSync(recursive: true, followLinks: false),
+ allOf(
+ hasLength(6),
+ contains(allOf(isFile, hasPath(ns('/foo/bar')))),
+ contains(allOf(isFile, hasPath(ns('/foo/baz/qux')))),
+ contains(allOf(isLink, hasPath(ns('/foo/quux')))),
+ contains(allOf(isLink, hasPath(ns('/foo/baz/quuz')))),
+ contains(allOf(isLink, hasPath(ns('/foo/baz/grault')))),
+ contains(allOf(isDirectory, hasPath(ns('/foo/baz')))),
+ ),
+ );
+ });
+
+ test('childEntriesNotNormalized', () {
+ dir = fs.directory(ns('/bar/baz'))..createSync(recursive: true);
+ fs.file(ns('/bar/baz/qux')).createSync();
+ List<FileSystemEntity> list =
+ fs.directory(ns('/bar//../bar/./baz')).listSync();
+ expect(list, hasLength(1));
+ expect(list[0], allOf(isFile, hasPath(ns('/bar//../bar/./baz/qux'))));
+ });
+
+ test('symlinksToNotFoundAlwaysReturnedAsLinks', () {
+ dir = fs.directory(ns('/bar'))..createSync();
+ fs.link(ns('/bar/baz')).createSync('qux');
+ for (bool followLinks in const <bool>[true, false]) {
+ List<FileSystemEntity> list =
+ dir.listSync(followLinks: followLinks);
+ expect(list, hasLength(1));
+ expect(list[0], allOf(isLink, hasPath(ns('/bar/baz'))));
+ }
+ });
+ });
+
+ test('childEntities', () {
+ Directory dir = fs.directory(ns('/foo'))..createSync();
+ dir.childDirectory('bar').createSync();
+ dir.childFile('baz').createSync();
+ dir.childLink('qux').createSync('bar');
+ expect(fs.directory(ns('/foo/bar')), exists);
+ expect(fs.file(ns('/foo/baz')), exists);
+ expect(fs.link(ns('/foo/qux')), exists);
+ });
+ });
+
+ group('File', () {
+ test('uri', () {
+ expect(fs.file(ns('/foo')).uri, fs.path.toUri(ns('/foo')));
+ expect(fs.file('foo').uri.toString(), 'foo');
+ });
+
+ group('create', () {
+ test('returnsCovariantType', () async {
+ expect(await fs.file(ns('/foo')).create(), isFile);
+ });
+
+ test('succeedsIfTailDoesntAlreadyExist', () {
+ fs.file(ns('/foo')).createSync();
+ expect(fs.file(ns('/foo')), exists);
+ });
+
+ test('succeedsIfAlreadyExistsAsFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.file(ns('/foo')).createSync();
+ expect(fs.file(ns('/foo')), exists);
+ });
+
+ test('throwsIfAncestorDoesntExistRecursiveFalse', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo/bar')).createSync();
+ });
+ });
+
+ test('succeedsIfAncestorDoesntExistRecursiveTrue', () {
+ fs.file(ns('/foo/bar')).createSync(recursive: true);
+ expect(fs.file(ns('/foo/bar')), exists);
+ });
+
+ test('throwsIfAlreadyExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).createSync();
+ });
+ });
+
+ test('throwsIfAlreadyExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/bar')).createSync();
+ });
+ });
+
+ test('succeedsIfAlreadyExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.file(ns('/bar')).createSync();
+ expect(fs.file(ns('/bar')), exists);
+ });
+
+ test('succeedsIfAlreadyExistsAsLinkToNotFoundAtTail', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ fs.file(ns('/foo')).createSync();
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ });
+
+ test('throwsIfAlreadyExistsAsLinkToNotFoundViaTraversal', () {
+ fs.link(ns('/foo')).createSync(ns('/bar/baz'));
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).createSync();
+ });
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).createSync(recursive: true);
+ });
+ });
+
+ /*
+ test('throwsIfPathSegmentIsLinkToNotFoundAndRecursiveTrue', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo/baz')).createSync(recursive: true);
+ });
+ });
+ */
+
+ test('succeedsIfAlreadyExistsAsLinkToNotFoundInDifferentDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.directory(ns('/bar')).createSync();
+ fs.link(ns('/bar/baz')).createSync(ns('/foo/qux'));
+ fs.file(ns('/bar/baz')).createSync();
+ expect(fs.typeSync(ns('/bar/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.typeSync(ns('/foo/qux'), followLinks: false),
+ FileSystemEntityType.file);
+ });
+ });
+
+ group('rename', () {
+ test('returnsCovariantType', () async {
+ File f() => fs.file(ns('/foo'))..createSync();
+ expect(await f().rename(ns('/bar')), isFile);
+ expect(f().renameSync(ns('/baz')), isFile);
+ });
+
+ test('succeedsIfDestinationDoesntExistAtTail', () {
+ File src = fs.file(ns('/foo'))..createSync();
+ File dest = src.renameSync(ns('/bar'));
+ expect(fs.file(ns('/foo')), isNot(exists));
+ expect(fs.file(ns('/bar')), exists);
+ expect(dest.path, ns('/bar'));
+ });
+
+ test('throwsIfDestinationDoesntExistViaTraversal', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ f.renameSync(ns('/bar/baz'));
+ });
+ });
+
+ test('succeedsIfDestinationExistsAsFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.file(ns('/bar')).createSync();
+ f.renameSync(ns('/bar'));
+ expect(fs.file(ns('/foo')), isNot(exists));
+ expect(fs.file(ns('/bar')), exists);
+ });
+
+ test('throwsIfDestinationExistsAsDirectory', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.directory(ns('/bar')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ f.renameSync(ns('/bar'));
+ });
+ });
+
+ test('succeedsIfDestinationExistsAsLinkToFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.file(ns('/bar')).createSync();
+ fs.link(ns('/baz')).createSync(ns('/bar'));
+ f.renameSync(ns('/baz'));
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.file);
+ });
+
+ test('throwsIfDestinationExistsAsLinkToDirectory', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.directory(ns('/bar')).createSync();
+ fs.link(ns('/baz')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ f.renameSync(ns('/baz'));
+ });
+ });
+
+ test('succeedsIfDestinationExistsAsLinkToNotFound', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.link(ns('/bar')).createSync(ns('/baz'));
+ f.renameSync(ns('/bar'));
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ });
+
+ test('throwsIfSourceDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).renameSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfSourceExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).renameSync(ns('/bar'));
+ });
+ });
+
+ test('succeedsIfSourceExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.file(ns('/bar')).renameSync(ns('/baz'));
+ expect(fs.typeSync(ns('/bar')), FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.typeSync(ns('/baz'), followLinks: true),
+ FileSystemEntityType.file);
+ });
+
+ test('throwsIfSourceExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/bar')).renameSync(ns('/baz'));
+ });
+ });
+
+ test('throwsIfSourceExistsAsLinkToNotFound', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).renameSync(ns('/baz'));
+ });
+ });
+ });
+
+ group('copy', () {
+ test('returnsCovariantType', () async {
+ File f() => fs.file(ns('/foo'))..createSync();
+ expect(await f().copy(ns('/bar')), isFile);
+ expect(f().copySync(ns('/baz')), isFile);
+ });
+
+ test('succeedsIfDestinationDoesntExistAtTail', () {
+ File f = fs.file(ns('/foo'))
+ ..createSync()
+ ..writeAsStringSync('foo');
+ f.copySync(ns('/bar'));
+ expect(fs.file(ns('/foo')), exists);
+ expect(fs.file(ns('/bar')), exists);
+ expect(fs.file(ns('/foo')).readAsStringSync(), 'foo');
+ });
+
+ test('throwsIfDestinationDoesntExistViaTraversal', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ f.copySync(ns('/bar/baz'));
+ });
+ });
+
+ test('succeedsIfDestinationExistsAsFile', () {
+ File f = fs.file(ns('/foo'))
+ ..createSync()
+ ..writeAsStringSync('foo');
+ fs.file(ns('/bar'))
+ ..createSync()
+ ..writeAsStringSync('bar');
+ f.copySync(ns('/bar'));
+ expect(fs.file(ns('/foo')), exists);
+ expect(fs.file(ns('/bar')), exists);
+ expect(fs.file(ns('/foo')).readAsStringSync(), 'foo');
+ expect(fs.file(ns('/bar')).readAsStringSync(), 'foo');
+ });
+
+ test('throwsIfDestinationExistsAsDirectory', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.directory(ns('/bar')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ f.copySync(ns('/bar'));
+ });
+ });
+
+ test('succeedsIfDestinationExistsAsLinkToFile', () {
+ File f = fs.file(ns('/foo'))
+ ..createSync()
+ ..writeAsStringSync('foo');
+ fs.file(ns('/bar'))
+ ..createSync()
+ ..writeAsStringSync('bar');
+ fs.link(ns('/baz')).createSync(ns('/bar'));
+ f.copySync(ns('/baz'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.file(ns('/foo')).readAsStringSync(), 'foo');
+ expect(fs.file(ns('/bar')).readAsStringSync(), 'foo');
+ }, skip: io.Platform.isWindows /* No links on Windows */);
+
+ test('throwsIfDestinationExistsAsLinkToDirectory', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.directory(ns('/bar')).createSync();
+ fs.link(ns('/baz')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ f.copySync(ns('/baz'));
+ });
+ });
+
+ test('throwsIfSourceDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).copySync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfSourceExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).copySync(ns('/bar'));
+ });
+ });
+
+ test('succeedsIfSourceExistsAsLinkToFile', () {
+ fs.file(ns('/foo'))
+ ..createSync()
+ ..writeAsStringSync('foo');
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.file(ns('/bar')).copySync(ns('/baz'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.file(ns('/foo')).readAsStringSync(), 'foo');
+ expect(fs.file(ns('/baz')).readAsStringSync(), 'foo');
+ });
+
+ test('succeedsIfDestinationIsInDifferentDirectoryThanSource', () {
+ File f = fs.file(ns('/foo/bar'))
+ ..createSync(recursive: true)
+ ..writeAsStringSync('foo');
+ fs.directory(ns('/baz')).createSync();
+ f.copySync(ns('/baz/qux'));
+ expect(fs.file(ns('/foo/bar')), exists);
+ expect(fs.file(ns('/baz/qux')), exists);
+ expect(fs.file(ns('/foo/bar')).readAsStringSync(), 'foo');
+ expect(fs.file(ns('/baz/qux')).readAsStringSync(), 'foo');
+ });
+
+ test('succeedsIfSourceIsLinkToFileInDifferentDirectory', () {
+ fs.file(ns('/foo/bar'))
+ ..createSync(recursive: true)
+ ..writeAsStringSync('foo');
+ fs.link(ns('/baz/qux')).createSync(ns('/foo/bar'), recursive: true);
+ fs.file(ns('/baz/qux')).copySync(ns('/baz/quux'));
+ expect(fs.typeSync(ns('/foo/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/baz/qux'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.typeSync(ns('/baz/quux'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.file(ns('/foo/bar')).readAsStringSync(), 'foo');
+ expect(fs.file(ns('/baz/quux')).readAsStringSync(), 'foo');
+ });
+
+ test('succeedsIfDestinationIsLinkToFileInDifferentDirectory', () {
+ fs.file(ns('/foo/bar'))
+ ..createSync(recursive: true)
+ ..writeAsStringSync('bar');
+ fs.file(ns('/baz/qux'))
+ ..createSync(recursive: true)
+ ..writeAsStringSync('qux');
+ fs.link(ns('/baz/quux')).createSync(ns('/foo/bar'));
+ fs.file(ns('/baz/qux')).copySync(ns('/baz/quux'));
+ expect(fs.typeSync(ns('/foo/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/baz/qux'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/baz/quux'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.file(ns('/foo/bar')).readAsStringSync(), 'qux');
+ expect(fs.file(ns('/baz/qux')).readAsStringSync(), 'qux');
+ }, skip: io.Platform.isWindows /* No links on Windows */);
+ });
+
+ group('length', () {
+ test('throwsIfDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).lengthSync();
+ });
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).lengthSync();
+ });
+ });
+
+ test('returnsZeroForNewlyCreatedFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ expect(f.lengthSync(), 0);
+ });
+
+ test('writeNBytesReturnsLengthN', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsBytesSync(<int>[1, 2, 3, 4], flush: true);
+ expect(f.lengthSync(), 4);
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.file(ns('/bar')).lengthSync(), 0);
+ });
+ });
+
+ group('absolute', () {
+ test('returnsSamePathIfAlreadyAbsolute', () {
+ expect(fs.file(ns('/foo')).absolute.path, ns('/foo'));
+ });
+
+ test('succeedsForRelativePaths', () {
+ expect(fs.file('foo').absolute.path, ns('/foo'));
+ });
+ });
+
+ group('lastAccessed', () {
+ test('isNowForNewlyCreatedFile', () {
+ DateTime before = downstairs();
+ File f = fs.file(ns('/foo'))..createSync();
+ DateTime after = ceil();
+ DateTime accessed = f.lastAccessedSync();
+ expect(accessed, isSameOrAfter(before));
+ expect(accessed, isSameOrBefore(after));
+ });
+
+ test('throwsIfDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).lastAccessedSync();
+ });
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).lastAccessedSync();
+ });
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ DateTime before = downstairs();
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ DateTime after = ceil();
+ DateTime accessed = fs.file(ns('/bar')).lastAccessedSync();
+ expect(accessed, isSameOrAfter(before));
+ expect(accessed, isSameOrBefore(after));
+ });
+ });
+
+ group('setLastAccessed', () {
+ final DateTime time = DateTime(1999);
+
+ test('throwsIfDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).setLastAccessedSync(time);
+ });
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).setLastAccessedSync(time);
+ });
+ });
+
+ test('succeedsIfExistsAsFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.setLastAccessedSync(time);
+ expect(fs.file(ns('/foo')).lastAccessedSync(), time);
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ f.setLastAccessedSync(time);
+ expect(fs.file(ns('/bar')).lastAccessedSync(), time);
+ });
+ });
+
+ group('lastModified', () {
+ test('isNowForNewlyCreatedFile', () {
+ DateTime before = downstairs();
+ File f = fs.file(ns('/foo'))..createSync();
+ DateTime after = ceil();
+ DateTime modified = f.lastModifiedSync();
+ expect(modified, isSameOrAfter(before));
+ expect(modified, isSameOrBefore(after));
+ });
+
+ test('throwsIfDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).lastModifiedSync();
+ });
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).lastModifiedSync();
+ });
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ DateTime before = downstairs();
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ DateTime after = ceil();
+ DateTime modified = fs.file(ns('/bar')).lastModifiedSync();
+ expect(modified, isSameOrAfter(before));
+ expect(modified, isSameOrBefore(after));
+ });
+ });
+
+ group('setLastModified', () {
+ final DateTime time = DateTime(1999);
+
+ test('throwsIfDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).setLastModifiedSync(time);
+ });
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).setLastModifiedSync(time);
+ });
+ });
+
+ test('succeedsIfExistsAsFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.setLastModifiedSync(time);
+ expect(fs.file(ns('/foo')).lastModifiedSync(), time);
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ f.setLastModifiedSync(time);
+ expect(fs.file(ns('/bar')).lastModifiedSync(), time);
+ });
+ });
+
+ group('open', () {
+ void testIfDoesntExistAtTail(FileMode mode) {
+ if (mode == FileMode.read) {
+ test('throwsIfDoesntExistAtTail', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/bar')).openSync(mode: mode);
+ });
+ });
+ } else {
+ test('createsFileIfDoesntExistAtTail', () {
+ RandomAccessFile raf = fs.file(ns('/bar')).openSync(mode: mode);
+ raf.closeSync();
+ expect(fs.file(ns('/bar')), exists);
+ });
+ }
+ }
+
+ void testThrowsIfDoesntExistViaTraversal(FileMode mode) {
+ test('throwsIfDoesntExistViaTraversal', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/bar/baz')).openSync(mode: mode);
+ });
+ });
+ }
+
+ void testRandomAccessFileOperations(FileMode mode) {
+ group('RandomAccessFile', () {
+ late File f;
+ late RandomAccessFile raf;
+
+ setUp(() {
+ f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('pre-existing content\n', flush: true);
+ raf = f.openSync(mode: mode);
+ });
+
+ tearDown(() {
+ try {
+ raf.closeSync();
+ } on FileSystemException {
+ // Ignore; a test may have already closed it.
+ }
+ });
+
+ test('succeedsIfClosedAfterClosed', () {
+ raf.closeSync();
+ expectFileSystemException(null, () {
+ raf.closeSync();
+ });
+ });
+
+ test('throwsIfReadAfterClose', () {
+ raf.closeSync();
+ expectFileSystemException(null, () {
+ raf.readByteSync();
+ });
+ });
+
+ test('throwsIfWriteAfterClose', () {
+ raf.closeSync();
+ expectFileSystemException(null, () {
+ raf.writeByteSync(0xBAD);
+ });
+ });
+
+ test('throwsIfTruncateAfterClose', () {
+ raf.closeSync();
+ expectFileSystemException(null, () {
+ raf.truncateSync(0);
+ });
+ });
+
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ test('lengthIsResetToZeroIfOpened', () {
+ expect(raf.lengthSync(), equals(0));
+ });
+
+ test('throwsIfAsyncUnawaited', () async {
+ try {
+ final Future<void> future = raf.flush();
+ expectFileSystemException(null, () => raf.flush());
+ expectFileSystemException(null, () => raf.flushSync());
+ await expectLater(future, completes);
+ raf.flushSync();
+ } finally {
+ raf.closeSync();
+ }
+ });
+ } else {
+ test('lengthIsNotModifiedIfOpened', () {
+ expect(raf.lengthSync(), isNot(equals(0)));
+ });
+ }
+
+ if (mode == FileMode.writeOnly ||
+ mode == FileMode.writeOnlyAppend) {
+ test('throwsIfReadByte', () {
+ expectFileSystemException(ErrorCodes.EBADF, () {
+ raf.readByteSync();
+ });
+ });
+
+ test('throwsIfRead', () {
+ expectFileSystemException(ErrorCodes.EBADF, () {
+ raf.readSync(2);
+ });
+ });
+
+ test('throwsIfReadInto', () {
+ expectFileSystemException(ErrorCodes.EBADF, () {
+ raf.readIntoSync(List<int>.filled(5, 0));
+ });
+ });
+ } else {
+ group('read', () {
+ setUp(() {
+ if (mode == FileMode.write) {
+ // Write data back that we truncated when opening the file.
+ raf.writeStringSync('pre-existing content\n');
+ }
+ // Reset the position to zero so we can read the content.
+ raf.setPositionSync(0);
+ });
+
+ test('readByte', () {
+ expect(utf8.decode(<int>[raf.readByteSync()]), 'p');
+ });
+
+ test('read', () {
+ List<int> bytes = raf.readSync(1024);
+ expect(bytes.length, 21);
+ expect(utf8.decode(bytes), 'pre-existing content\n');
+ });
+
+ test('readIntoWithBufferLargerThanContent', () {
+ List<int> buffer = List<int>.filled(1024, 0);
+ int numRead = raf.readIntoSync(buffer);
+ expect(numRead, 21);
+ expect(utf8.decode(buffer.sublist(0, 21)),
+ 'pre-existing content\n');
+ });
+
+ test('readIntoWithBufferSmallerThanContent', () {
+ List<int> buffer = List<int>.filled(10, 0);
+ int numRead = raf.readIntoSync(buffer);
+ expect(numRead, 10);
+ expect(utf8.decode(buffer), 'pre-existi');
+ });
+
+ test('readIntoWithStart', () {
+ List<int> buffer = List<int>.filled(10, 0);
+ int numRead = raf.readIntoSync(buffer, 2);
+ expect(numRead, 8);
+ expect(utf8.decode(buffer.sublist(2)), 'pre-exis');
+ });
+
+ test('readIntoWithStartAndEnd', () {
+ List<int> buffer = List<int>.filled(10, 0);
+ int numRead = raf.readIntoSync(buffer, 2, 5);
+ expect(numRead, 3);
+ expect(utf8.decode(buffer.sublist(2, 5)), 'pre');
+ });
+
+ test('openReadHandleDoesNotChange', () {
+ final String initial = utf8.decode(raf.readSync(4));
+ expect(initial, 'pre-');
+ final File newFile = f.renameSync(ns('/bar'));
+ String rest = utf8.decode(raf.readSync(1024));
+ expect(rest, 'existing content\n');
+
+ assert(newFile.path != f.path);
+ expect(f, isNot(exists));
+ expect(newFile, exists);
+
+ // [RandomAccessFile.path] always returns the original path.
+ expect(raf.path, f.path);
+ });
+ });
+ }
+
+ if (mode == FileMode.read) {
+ test('throwsIfWriteByte', () {
+ expectFileSystemException(ErrorCodes.EBADF, () {
+ raf.writeByteSync(0xBAD);
+ });
+ });
+
+ test('throwsIfWriteFrom', () {
+ expectFileSystemException(ErrorCodes.EBADF, () {
+ raf.writeFromSync(<int>[1, 2, 3, 4]);
+ });
+ });
+
+ test('throwsIfWriteString', () {
+ expectFileSystemException(ErrorCodes.EBADF, () {
+ raf.writeStringSync('This should throw.');
+ });
+ });
+ } else {
+ test('lengthGrowsAsDataIsWritten', () {
+ int lengthBefore = f.lengthSync();
+ raf.writeByteSync(0xFACE);
+ expect(raf.lengthSync(), lengthBefore + 1);
+ });
+
+ test('flush', () {
+ int lengthBefore = f.lengthSync();
+ raf.writeByteSync(0xFACE);
+ raf.flushSync();
+ expect(f.lengthSync(), lengthBefore + 1);
+ });
+
+ test('writeByte', () {
+ raf.writeByteSync(utf8.encode('A').first);
+ raf.flushSync();
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ expect(f.readAsStringSync(), 'A');
+ } else {
+ expect(f.readAsStringSync(), 'pre-existing content\nA');
+ }
+ });
+
+ test('writeFrom', () {
+ raf.writeFromSync(utf8.encode('Hello world'));
+ raf.flushSync();
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ expect(f.readAsStringSync(), 'Hello world');
+ } else {
+ expect(f.readAsStringSync(),
+ 'pre-existing content\nHello world');
+ }
+ });
+
+ test('writeFromWithStart', () {
+ raf.writeFromSync(utf8.encode('Hello world'), 2);
+ raf.flushSync();
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ expect(f.readAsStringSync(), 'llo world');
+ } else {
+ expect(
+ f.readAsStringSync(), 'pre-existing content\nllo world');
+ }
+ });
+
+ test('writeFromWithStartAndEnd', () {
+ raf.writeFromSync(utf8.encode('Hello world'), 2, 5);
+ raf.flushSync();
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ expect(f.readAsStringSync(), 'llo');
+ } else {
+ expect(f.readAsStringSync(), 'pre-existing content\nllo');
+ }
+ });
+
+ test('writeString', () {
+ raf.writeStringSync('Hello world');
+ raf.flushSync();
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ expect(f.readAsStringSync(), 'Hello world');
+ } else {
+ expect(f.readAsStringSync(),
+ 'pre-existing content\nHello world');
+ }
+ });
+
+ test('openWriteHandleDoesNotChange', () {
+ raf.writeStringSync('Hello ');
+ final File newFile = f.renameSync(ns('/bar'));
+ raf.writeStringSync('world');
+
+ final String contents = newFile.readAsStringSync();
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ expect(contents, 'Hello world');
+ } else {
+ expect(contents, 'pre-existing content\nHello world');
+ }
+
+ assert(newFile.path != f.path);
+ expect(f, isNot(exists));
+ expect(newFile, exists);
+
+ // [RandomAccessFile.path] always returns the original path.
+ expect(raf.path, f.path);
+ });
+ }
+
+ if (mode == FileMode.append || mode == FileMode.writeOnlyAppend) {
+ test('positionInitializedToEndOfFile', () {
+ expect(raf.positionSync(), 21);
+ });
+ } else {
+ test('positionInitializedToZero', () {
+ expect(raf.positionSync(), 0);
+ });
+ }
+
+ group('position', () {
+ setUp(() {
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ // Write data back that we truncated when opening the file.
+ raf.writeStringSync('pre-existing content\n');
+ }
+ });
+
+ if (mode != FileMode.writeOnly &&
+ mode != FileMode.writeOnlyAppend) {
+ test('growsAfterRead', () {
+ raf.setPositionSync(0);
+ raf.readSync(10);
+ expect(raf.positionSync(), 10);
+ });
+
+ test('affectsRead', () {
+ raf.setPositionSync(5);
+ expect(utf8.decode(raf.readSync(5)), 'xisti');
+ });
+ }
+
+ if (mode == FileMode.read) {
+ test('succeedsIfSetPastEndOfFile', () {
+ raf.setPositionSync(32);
+ expect(raf.positionSync(), 32);
+ });
+ } else {
+ test('growsAfterWrite', () {
+ int positionBefore = raf.positionSync();
+ raf.writeStringSync('Hello world');
+ expect(raf.positionSync(), positionBefore + 11);
+ });
+
+ test('affectsWrite', () {
+ raf.setPositionSync(5);
+ raf.writeStringSync('-yo-');
+ raf.flushSync();
+ expect(f.readAsStringSync(), 'pre-e-yo-ing content\n');
+ });
+
+ test('succeedsIfSetAndWrittenPastEndOfFile', () {
+ raf.setPositionSync(32);
+ expect(raf.positionSync(), 32);
+ raf.writeStringSync('here');
+ raf.flushSync();
+ List<int> bytes = f.readAsBytesSync();
+ expect(bytes.length, 36);
+ expect(utf8.decode(bytes.sublist(0, 21)),
+ 'pre-existing content\n');
+ expect(utf8.decode(bytes.sublist(32, 36)), 'here');
+ expect(bytes.sublist(21, 32), everyElement(0));
+ });
+ }
+
+ test('throwsIfSetToNegativeNumber', () {
+ expectFileSystemException(ErrorCodes.EINVAL, () {
+ raf.setPositionSync(-12);
+ });
+ });
+ });
+
+ if (mode == FileMode.read) {
+ test('throwsIfTruncate', () {
+ expectFileSystemException(ErrorCodes.EINVAL, () {
+ raf.truncateSync(5);
+ });
+ });
+ } else {
+ group('truncate', () {
+ setUp(() {
+ if (mode == FileMode.write || mode == FileMode.writeOnly) {
+ // Write data back that we truncated when opening the file.
+ raf.writeStringSync('pre-existing content\n');
+ }
+ });
+
+ test('succeedsIfSetWithinRangeOfContent', () {
+ raf.truncateSync(5);
+ raf.flushSync();
+ expect(f.lengthSync(), 5);
+ expect(f.readAsStringSync(), 'pre-e');
+ });
+
+ test('succeedsIfSetToZero', () {
+ raf.truncateSync(0);
+ raf.flushSync();
+ expect(f.lengthSync(), 0);
+ expect(f.readAsStringSync(), isEmpty);
+ });
+
+ test('throwsIfSetToNegativeNumber', () {
+ expectFileSystemException(ErrorCodes.EINVAL, () {
+ raf.truncateSync(-2);
+ });
+ });
+
+ test('extendsFileIfSetPastEndOfFile', () {
+ raf.truncateSync(32);
+ raf.flushSync();
+ List<int> bytes = f.readAsBytesSync();
+ expect(bytes.length, 32);
+ expect(utf8.decode(bytes.sublist(0, 21)),
+ 'pre-existing content\n');
+ expect(bytes.sublist(21, 32), everyElement(0));
+ });
+ });
+ }
+ });
+ }
+
+ void testOpenWithMode(FileMode mode) {
+ testIfDoesntExistAtTail(mode);
+ testThrowsIfDoesntExistViaTraversal(mode);
+ testRandomAccessFileOperations(mode);
+ }
+
+ group('READ', () => testOpenWithMode(FileMode.read));
+ group('WRITE', () => testOpenWithMode(FileMode.write));
+ group('APPEND', () => testOpenWithMode(FileMode.append));
+ group('WRITE_ONLY', () => testOpenWithMode(FileMode.writeOnly));
+ group('WRITE_ONLY_APPEND',
+ () => testOpenWithMode(FileMode.writeOnlyAppend));
+ });
+
+ group('openRead', () {
+ test('throwsIfDoesntExist', () {
+ Stream<List<int>> stream = fs.file(ns('/foo')).openRead();
+ expect(stream.drain<void>(),
+ throwsFileSystemException(ErrorCodes.ENOENT));
+ });
+
+ test('succeedsIfExistsAsFile', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello world', flush: true);
+ Stream<List<int>> stream = f.openRead();
+ List<List<int>> data = await stream.toList();
+ expect(data, hasLength(1));
+ expect(utf8.decode(data[0]), 'Hello world');
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ Stream<List<int>> stream = fs.file(ns('/foo')).openRead();
+ expect(stream.drain<void>(),
+ throwsFileSystemException(ErrorCodes.EISDIR));
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ f.writeAsStringSync('Hello world', flush: true);
+ Stream<List<int>> stream = fs.file(ns('/bar')).openRead();
+ List<List<int>> data = await stream.toList();
+ expect(data, hasLength(1));
+ expect(utf8.decode(data[0]), 'Hello world');
+ });
+
+ test('respectsStartAndEndParameters', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello world', flush: true);
+ Stream<List<int>> stream = f.openRead(2);
+ List<List<int>> data = await stream.toList();
+ expect(data, hasLength(1));
+ expect(utf8.decode(data[0]), 'llo world');
+ stream = f.openRead(2, 5);
+ data = await stream.toList();
+ expect(data, hasLength(1));
+ expect(utf8.decode(data[0]), 'llo');
+ });
+
+ test('throwsIfStartParameterIsNegative', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ Stream<List<int>> stream = f.openRead(-2);
+ expect(stream.drain<void>(), throwsRangeError);
+ });
+
+ test('stopsAtEndOfFileIfEndParameterIsPastEndOfFile', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello world', flush: true);
+ Stream<List<int>> stream = f.openRead(2, 1024);
+ List<List<int>> data = await stream.toList();
+ expect(data, hasLength(1));
+ expect(utf8.decode(data[0]), 'llo world');
+ });
+
+ test('providesSingleSubscriptionStream', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello world', flush: true);
+ Stream<List<int>> stream = f.openRead();
+ expect(stream.isBroadcast, isFalse);
+ await stream.drain<void>();
+ });
+
+ test('openReadHandleDoesNotChange', () async {
+ // Ideally, `data` should be large enough so that its contents are
+ // split across multiple chunks in the [Stream]. However, there
+ // doesn't seem to be a good way to determine the chunk size used by
+ // [io.File].
+ final List<int> data = List<int>.generate(
+ 1024 * 256,
+ (int index) => index & 0xFF,
+ growable: false,
+ );
+
+ final File f = fs.file(ns('/foo'))..createSync();
+
+ f.writeAsBytesSync(data, flush: true);
+ final Stream<List<int>> stream = f.openRead();
+
+ File? newFile;
+ List<int>? initialChunk;
+ final List<int> remainingChunks = <int>[];
+
+ await for (List<int> chunk in stream) {
+ if (initialChunk == null) {
+ initialChunk = chunk;
+ assert(initialChunk.isNotEmpty);
+ expect(initialChunk, data.getRange(0, initialChunk.length));
+
+ newFile = f.renameSync(ns('/bar'));
+ } else {
+ remainingChunks.addAll(chunk);
+ }
+ }
+
+ expect(
+ remainingChunks,
+ data.getRange(initialChunk!.length, data.length),
+ );
+
+ assert(newFile?.path != f.path);
+ expect(f, isNot(exists));
+ expect(newFile, exists);
+ });
+
+ test('openReadCompatibleWithUtf8Decoder', () async {
+ const content = 'Hello world!';
+ File file = fs.file(ns('/foo'))
+ ..createSync()
+ ..writeAsStringSync(content);
+ expect(
+ await file
+ .openRead()
+ .transform(utf8.decoder)
+ .transform(const LineSplitter())
+ .first,
+ content,
+ );
+ });
+ });
+
+ group('openWrite', () {
+ test('createsFileIfDoesntExist', () async {
+ await fs.file(ns('/foo')).openWrite().close();
+ expect(fs.file(ns('/foo')), exists);
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expect(fs.file(ns('/foo')).openWrite().close(),
+ throwsFileSystemException(ErrorCodes.EISDIR));
+ });
+
+ test('throwsIfExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.file(ns('/bar')).openWrite().close(),
+ throwsFileSystemException(ErrorCodes.EISDIR));
+ });
+
+ test('throwsIfModeIsRead', () {
+ expect(() => fs.file(ns('/foo')).openWrite(mode: FileMode.read),
+ throwsArgumentError);
+ });
+
+ test('succeedsIfExistsAsEmptyFile', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ IOSink sink = f.openWrite();
+ sink.write('Hello world');
+ await sink.flush();
+ await sink.close();
+ expect(f.readAsStringSync(), 'Hello world');
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () async {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ IOSink sink = fs.file(ns('/bar')).openWrite();
+ sink.write('Hello world');
+ await sink.flush();
+ await sink.close();
+ expect(fs.file(ns('/foo')).readAsStringSync(), 'Hello world');
+ });
+
+ test('overwritesContentInWriteMode', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello');
+ IOSink sink = f.openWrite();
+ sink.write('Goodbye');
+ await sink.flush();
+ await sink.close();
+ expect(fs.file(ns('/foo')).readAsStringSync(), 'Goodbye');
+ });
+
+ test('appendsContentInAppendMode', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello');
+ IOSink sink = f.openWrite(mode: FileMode.append);
+ sink.write('Goodbye');
+ await sink.flush();
+ await sink.close();
+ expect(fs.file(ns('/foo')).readAsStringSync(), 'HelloGoodbye');
+ });
+
+ test('openWriteHandleDoesNotChange', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ IOSink sink = f.openWrite();
+ sink.write('Hello');
+ await sink.flush();
+
+ final File newFile = f.renameSync(ns('/bar'));
+ sink.write('Goodbye');
+ await sink.flush();
+ await sink.close();
+
+ expect(newFile.readAsStringSync(), 'HelloGoodbye');
+
+ assert(newFile.path != f.path);
+ expect(f, isNot(exists));
+ expect(newFile, exists);
+ });
+
+ group('ioSink', () {
+ late File f;
+ late IOSink sink;
+ late bool isSinkClosed;
+
+ Future<dynamic> closeSink() {
+ Future<dynamic> future = sink.close();
+ isSinkClosed = true;
+ return future;
+ }
+
+ setUp(() {
+ f = fs.file(ns('/foo'));
+ sink = f.openWrite();
+ isSinkClosed = false;
+ });
+
+ tearDown(() async {
+ if (!isSinkClosed) {
+ await closeSink();
+ }
+ });
+
+ test('throwsIfAddError', () async {
+ sink.addError(ArgumentError());
+ expect(sink.done, throwsArgumentError);
+ isSinkClosed = true;
+ });
+
+ test('allowsChangingEncoding', () async {
+ sink.encoding = latin1;
+ sink.write('ÿ');
+ sink.encoding = utf8;
+ sink.write('ÿ');
+ await sink.flush();
+ expect(await f.readAsBytes(), <int>[255, 195, 191]);
+ });
+
+ test('succeedsIfAddRawData', () async {
+ sink.add(<int>[1, 2, 3, 4]);
+ await sink.flush();
+ expect(await f.readAsBytes(), <int>[1, 2, 3, 4]);
+ });
+
+ test('succeedsIfWrite', () async {
+ sink.write('Hello world');
+ await sink.flush();
+ expect(await f.readAsString(), 'Hello world');
+ });
+
+ test('succeedsIfWriteAll', () async {
+ sink.writeAll(<String>['foo', 'bar', 'baz'], ' ');
+ await sink.flush();
+ expect(await f.readAsString(), 'foo bar baz');
+ });
+
+ test('succeedsIfWriteCharCode', () async {
+ sink.writeCharCode(35);
+ await sink.flush();
+ expect(await f.readAsString(), '#');
+ });
+
+ test('succeedsIfWriteln', () async {
+ sink.writeln('Hello world');
+ await sink.flush();
+ expect(await f.readAsString(), 'Hello world\n');
+ });
+
+ test('ignoresDataWrittenAfterClose', () async {
+ sink.write('Before close');
+ await closeSink();
+ expect(() => sink.write('After close'), throwsStateError);
+ expect(await f.readAsString(), 'Before close');
+ });
+
+ test('ignoresCloseAfterAlreadyClosed', () async {
+ sink.write('Hello world');
+ Future<dynamic> f1 = closeSink();
+ Future<dynamic> f2 = closeSink();
+ await Future.wait<dynamic>(<Future<dynamic>>[f1, f2]);
+ });
+
+ test('returnsAccurateDoneFuture', () async {
+ bool done = false;
+ // ignore: unawaited_futures
+ sink.done.then((dynamic _) => done = true);
+ expect(done, isFalse);
+ sink.write('foo');
+ expect(done, isFalse);
+ await sink.close();
+ expect(done, isTrue);
+ });
+
+ group('addStream', () {
+ late StreamController<List<int>> controller;
+ late bool isControllerClosed;
+
+ Future<dynamic> closeController() {
+ Future<dynamic> future = controller.close();
+ isControllerClosed = true;
+ return future;
+ }
+
+ setUp(() {
+ controller = StreamController<List<int>>();
+ isControllerClosed = false;
+ sink.addStream(controller.stream);
+ });
+
+ tearDown(() async {
+ if (!isControllerClosed) {
+ await closeController();
+ }
+ });
+
+ test('succeedsIfStreamProducesData', () async {
+ controller.add(<int>[1, 2, 3, 4, 5]);
+ await closeController();
+ await sink.flush();
+ expect(await f.readAsBytes(), <int>[1, 2, 3, 4, 5]);
+ });
+
+ test('blocksCallToAddWhileStreamIsActive', () {
+ expect(() => sink.add(<int>[1, 2, 3]), throwsStateError);
+ });
+
+ test('blocksCallToWriteWhileStreamIsActive', () {
+ expect(() => sink.write('foo'), throwsStateError);
+ });
+
+ test('blocksCallToWriteAllWhileStreamIsActive', () {
+ expect(() => sink.writeAll(<String>['a', 'b']), throwsStateError);
+ });
+
+ test('blocksCallToWriteCharCodeWhileStreamIsActive', () {
+ expect(() => sink.writeCharCode(35), throwsStateError);
+ });
+
+ test('blocksCallToWritelnWhileStreamIsActive', () {
+ expect(() => sink.writeln('foo'), throwsStateError);
+ });
+
+ test('blocksCallToFlushWhileStreamIsActive', () {
+ expect(() => sink.flush(), throwsStateError);
+ });
+ });
+ });
+ });
+
+ group('readAsBytes', () {
+ test('throwsIfDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).readAsBytesSync();
+ });
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).readAsBytesSync();
+ });
+ });
+
+ test('throwsIfExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/bar')).readAsBytesSync();
+ });
+ });
+
+ test('succeedsIfExistsAsFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsBytesSync(<int>[1, 2, 3, 4]);
+ expect(f.readAsBytesSync(), <int>[1, 2, 3, 4]);
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.file(ns('/foo')).writeAsBytesSync(<int>[1, 2, 3, 4]);
+ expect(fs.file(ns('/bar')).readAsBytesSync(), <int>[1, 2, 3, 4]);
+ });
+
+ test('returnsEmptyListForZeroByteFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ expect(f.readAsBytesSync(), isEmpty);
+ });
+
+ test('returns a copy, not a view, of the file content', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsBytesSync(<int>[1, 2, 3, 4]);
+ List<int> result = f.readAsBytesSync();
+ expect(result, <int>[1, 2, 3, 4]);
+ result[0] = 10;
+ expect(f.readAsBytesSync(), <int>[1, 2, 3, 4]);
+ });
+ });
+
+ group('readAsString', () {
+ test('throwsIfDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).readAsStringSync();
+ });
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).readAsStringSync();
+ });
+ });
+
+ test('throwsIfExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/bar')).readAsStringSync();
+ });
+ });
+
+ test('succeedsIfExistsAsFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello world');
+ expect(f.readAsStringSync(), 'Hello world');
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.file(ns('/foo')).writeAsStringSync('Hello world');
+ expect(fs.file(ns('/bar')).readAsStringSync(), 'Hello world');
+ });
+
+ test('returnsEmptyStringForZeroByteFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ expect(f.readAsStringSync(), isEmpty);
+ });
+ });
+
+ group('readAsLines', () {
+ const String testString = 'Hello world\nHow are you?\nI am fine';
+ final List<String> expectedLines = <String>[
+ 'Hello world',
+ 'How are you?',
+ 'I am fine',
+ ];
+
+ test('throwsIfDoesntExist', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).readAsLinesSync();
+ });
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).readAsLinesSync();
+ });
+ });
+
+ test('throwsIfExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/bar')).readAsLinesSync();
+ });
+ });
+
+ test('succeedsIfExistsAsFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync(testString);
+ expect(f.readAsLinesSync(), expectedLines);
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ f.writeAsStringSync(testString);
+ expect(f.readAsLinesSync(), expectedLines);
+ });
+
+ test('returnsEmptyListForZeroByteFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ expect(f.readAsLinesSync(), isEmpty);
+ });
+
+ test('isTrailingNewlineAgnostic', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('$testString\n');
+ expect(f.readAsLinesSync(), expectedLines);
+
+ f.writeAsStringSync('\n');
+ expect(f.readAsLinesSync(), <String>['']);
+
+ f.writeAsStringSync('\n\n');
+ expect(f.readAsLinesSync(), <String>['', '']);
+ });
+ });
+
+ group('writeAsBytes', () {
+ test('returnsCovariantType', () async {
+ expect(await fs.file(ns('/foo')).writeAsBytes(<int>[]), isFile);
+ });
+
+ test('createsFileIfDoesntExist', () {
+ File f = fs.file(ns('/foo'));
+ expect(f, isNot(exists));
+ f.writeAsBytesSync(<int>[1, 2, 3, 4]);
+ expect(f, exists);
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).writeAsBytesSync(<int>[1, 2, 3, 4]);
+ });
+ });
+
+ test('throwsIfExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).writeAsBytesSync(<int>[1, 2, 3, 4]);
+ });
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.file(ns('/bar')).writeAsBytesSync(<int>[1, 2, 3, 4]);
+ expect(f.readAsBytesSync(), <int>[1, 2, 3, 4]);
+ });
+
+ test('throwsIfFileModeRead', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ expectFileSystemException(ErrorCodes.EBADF, () {
+ f.writeAsBytesSync(<int>[1], mode: FileMode.read);
+ });
+ });
+
+ test('overwritesContentIfFileModeWrite', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsBytesSync(<int>[1, 2]);
+ expect(f.readAsBytesSync(), <int>[1, 2]);
+ f.writeAsBytesSync(<int>[3, 4]);
+ expect(f.readAsBytesSync(), <int>[3, 4]);
+ });
+
+ test('appendsContentIfFileModeAppend', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsBytesSync(<int>[1, 2], mode: FileMode.append);
+ expect(f.readAsBytesSync(), <int>[1, 2]);
+ f.writeAsBytesSync(<int>[3, 4], mode: FileMode.append);
+ expect(f.readAsBytesSync(), <int>[1, 2, 3, 4]);
+ });
+
+ test('acceptsEmptyBytesList', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsBytesSync(<int>[]);
+ expect(f.readAsBytesSync(), <int>[]);
+ });
+
+ test('updatesLastModifiedTime', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ DateTime before = f.statSync().modified;
+ await Future<void>.delayed(const Duration(seconds: 2));
+ f.writeAsBytesSync(<int>[1, 2, 3]);
+ DateTime after = f.statSync().modified;
+ expect(after, isAfter(before));
+ });
+ });
+
+ group('writeAsString', () {
+ test('returnsCovariantType', () async {
+ expect(await fs.file(ns('/foo')).writeAsString('foo'), isFile);
+ });
+
+ test('createsFileIfDoesntExist', () {
+ File f = fs.file(ns('/foo'));
+ expect(f, isNot(exists));
+ f.writeAsStringSync('Hello world');
+ expect(f, exists);
+ });
+
+ test('throwsIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).writeAsStringSync('Hello world');
+ });
+ });
+
+ test('throwsIfExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).writeAsStringSync('Hello world');
+ });
+ });
+
+ test('succeedsIfExistsAsLinkToFile', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ fs.file(ns('/bar')).writeAsStringSync('Hello world');
+ expect(f.readAsStringSync(), 'Hello world');
+ });
+
+ test('throwsIfFileModeRead', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ expectFileSystemException(ErrorCodes.EBADF, () {
+ f.writeAsStringSync('Hello world', mode: FileMode.read);
+ });
+ });
+
+ test('overwritesContentIfFileModeWrite', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello world');
+ expect(f.readAsStringSync(), 'Hello world');
+ f.writeAsStringSync('Goodbye cruel world');
+ expect(f.readAsStringSync(), 'Goodbye cruel world');
+ });
+
+ test('appendsContentIfFileModeAppend', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('Hello', mode: FileMode.append);
+ expect(f.readAsStringSync(), 'Hello');
+ f.writeAsStringSync('Goodbye', mode: FileMode.append);
+ expect(f.readAsStringSync(), 'HelloGoodbye');
+ });
+
+ test('acceptsEmptyString', () {
+ File f = fs.file(ns('/foo'))..createSync();
+ f.writeAsStringSync('');
+ expect(f.readAsStringSync(), isEmpty);
+ });
+ });
+
+ group('exists', () {
+ test('trueIfExists', () {
+ fs.file(ns('/foo')).createSync();
+ expect(fs.file(ns('/foo')), exists);
+ });
+
+ test('falseIfDoesntExistAtTail', () {
+ expect(fs.file(ns('/foo')), isNot(exists));
+ });
+
+ test('falseIfDoesntExistViaTraversal', () {
+ expect(fs.file(ns('/foo/bar')), isNot(exists));
+ });
+
+ test('falseIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expect(fs.file(ns('/foo')), isNot(exists));
+ });
+
+ test('falseIfExistsAsLinkToDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.file(ns('/bar')), isNot(exists));
+ });
+
+ test('trueIfExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.file(ns('/bar')), exists);
+ });
+
+ test('falseIfNotFoundSegmentExistsThenIsBackedOut', () {
+ fs.file(ns('/foo/bar')).createSync(recursive: true);
+ expect(fs.directory(ns('/baz/../foo/bar')), isNot(exists));
+ });
+ });
+
+ group('stat', () {
+ test('isNotFoundIfDoesntExistAtTail', () {
+ FileStat stat = fs.file(ns('/foo')).statSync();
+ expect(stat.type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundIfDoesntExistViaTraversal', () {
+ FileStat stat = fs.file(ns('/foo/bar')).statSync();
+ expect(stat.type, FileSystemEntityType.notFound);
+ });
+
+ test('isDirectoryIfExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ FileStat stat = fs.file(ns('/foo')).statSync();
+ expect(stat.type, FileSystemEntityType.directory);
+ });
+
+ test('isFileIfExistsAsFile', () {
+ fs.file(ns('/foo')).createSync();
+ FileStat stat = fs.file(ns('/foo')).statSync();
+ expect(stat.type, FileSystemEntityType.file);
+ });
+
+ test('isFileIfExistsAsLinkToFile', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ FileStat stat = fs.file(ns('/bar')).statSync();
+ expect(stat.type, FileSystemEntityType.file);
+ });
+ });
+
+ group('delete', () {
+ test('returnsCovariantType', () async {
+ File f = fs.file(ns('/foo'))..createSync();
+ expect(await f.delete(), isFile);
+ });
+
+ test('succeedsIfExistsAsFile', () {
+ fs.file(ns('/foo')).createSync();
+ expect(fs.file(ns('/foo')), exists);
+ fs.file(ns('/foo')).deleteSync();
+ expect(fs.file(ns('/foo')), isNot(exists));
+ });
+
+ test('throwsIfDoesntExistAndRecursiveFalse', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).deleteSync();
+ });
+ });
+
+ test('throwsIfDoesntExistAndRecursiveTrue', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.file(ns('/foo')).deleteSync(recursive: true);
+ });
+ });
+
+ test('succeedsIfExistsAsDirectoryAndRecursiveTrue', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.file(ns('/foo')).deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound);
+ });
+
+ test('throwsIfExistsAsDirectoryAndRecursiveFalse', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/foo')).deleteSync();
+ });
+ });
+
+ test('succeedsIfExistsAsLinkToFileAndRecursiveTrue', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.file(ns('/bar')), exists);
+ fs.file(ns('/bar')).deleteSync(recursive: true);
+ expect(fs.file(ns('/bar')), isNot(exists));
+ });
+
+ test('succeedsIfExistsAsLinkToFileAndRecursiveFalse', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.file(ns('/bar')), exists);
+ fs.file(ns('/bar')).deleteSync();
+ expect(fs.file(ns('/bar')), isNot(exists));
+ });
+
+ test('succeedsIfExistsAsLinkToDirectoryAndRecursiveTrue', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(fs.typeSync(ns('/bar')), FileSystemEntityType.directory);
+ fs.file(ns('/bar')).deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.directory);
+ expect(fs.typeSync(ns('/bar')), FileSystemEntityType.notFound);
+ });
+
+ test('throwsIfExistsAsLinkToDirectoryAndRecursiveFalse', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.file(ns('/bar')).deleteSync();
+ });
+ });
+ });
+ });
+
+ group('Link', () {
+ group('uri', () {
+ test('whenTargetIsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ Link l = fs.link(ns('/bar'))..createSync(ns('/foo'));
+ expect(l.uri, fs.path.toUri(ns('/bar')));
+ expect(fs.link('bar').uri.toString(), 'bar');
+ });
+
+ test('whenTargetIsFile', () {
+ fs.file(ns('/foo')).createSync();
+ Link l = fs.link(ns('/bar'))..createSync(ns('/foo'));
+ expect(l.uri, fs.path.toUri(ns('/bar')));
+ expect(fs.link('bar').uri.toString(), 'bar');
+ });
+
+ test('whenLinkDoesntExist', () {
+ expect(fs.link(ns('/foo')).uri, fs.path.toUri(ns('/foo')));
+ expect(fs.link('foo').uri.toString(), 'foo');
+ });
+ });
+
+ group('exists', () {
+ test('isFalseIfLinkDoesntExistAtTail', () {
+ expect(fs.link(ns('/foo')), isNot(exists));
+ });
+
+ test('isFalseIfLinkDoesntExistViaTraversal', () {
+ expect(fs.link(ns('/foo/bar')), isNot(exists));
+ });
+
+ test('isFalseIfPathReferencesFile', () {
+ fs.file(ns('/foo')).createSync();
+ expect(fs.link(ns('/foo')), isNot(exists));
+ });
+
+ test('isFalseIfPathReferencesDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expect(fs.link(ns('/foo')), isNot(exists));
+ });
+
+ test('isTrueIfTargetIsNotFound', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ expect(l, exists);
+ });
+
+ test('isTrueIfTargetIsFile', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.file(ns('/bar')).createSync();
+ expect(l, exists);
+ });
+
+ test('isTrueIfTargetIsDirectory', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.directory(ns('/bar')).createSync();
+ expect(l, exists);
+ });
+
+ test('isTrueIfTargetIsLinkLoop', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(l, exists);
+ });
+ });
+
+ group('stat', () {
+ test('isNotFoundIfLinkDoesntExistAtTail', () {
+ expect(fs.link(ns('/foo')).statSync().type,
+ FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundIfLinkDoesntExistViaTraversal', () {
+ expect(fs.link(ns('/foo/bar')).statSync().type,
+ FileSystemEntityType.notFound);
+ });
+
+ test('isFileIfPathReferencesFile', () {
+ fs.file(ns('/foo')).createSync();
+ expect(
+ fs.link(ns('/foo')).statSync().type, FileSystemEntityType.file);
+ });
+
+ test('isDirectoryIfPathReferencesDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expect(fs.link(ns('/foo')).statSync().type,
+ FileSystemEntityType.directory);
+ });
+
+ test('isNotFoundIfTargetNotFoundAtTail', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ expect(l.statSync().type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundIfTargetNotFoundViaTraversal', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar/baz'));
+ expect(l.statSync().type, FileSystemEntityType.notFound);
+ });
+
+ test('isNotFoundIfTargetIsLinkLoop', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(l.statSync().type, FileSystemEntityType.notFound);
+ });
+
+ test('isFileIfTargetIsFile', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.file(ns('/bar')).createSync();
+ expect(l.statSync().type, FileSystemEntityType.file);
+ });
+
+ test('isDirectoryIfTargetIsDirectory', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.directory(ns('/bar')).createSync();
+ expect(l.statSync().type, FileSystemEntityType.directory);
+ });
+ });
+
+ group('delete', () {
+ test('returnsCovariantType', () async {
+ Link link = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ expect(await link.delete(), isLink);
+ });
+
+ test('throwsIfLinkDoesntExistAtTail', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo')).deleteSync();
+ });
+ });
+
+ test('throwsIfLinkDoesntExistViaTraversal', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo/bar')).deleteSync();
+ });
+ });
+
+ test('throwsIfPathReferencesFileAndRecursiveFalse', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EINVAL, () {
+ fs.link(ns('/foo')).deleteSync();
+ });
+ });
+
+ test('succeedsIfPathReferencesFileAndRecursiveTrue', () {
+ fs.file(ns('/foo')).createSync();
+ fs.link(ns('/foo')).deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ });
+
+ test('throwsIfPathReferencesDirectoryAndRecursiveFalse', () {
+ fs.directory(ns('/foo')).createSync();
+ // TODO(tvolkert): Change this to just be 'Is a directory'
+ // once Dart 1.22 is stable.
+ expectFileSystemException(
+ anyOf(ErrorCodes.EINVAL, ErrorCodes.EISDIR),
+ () {
+ fs.link(ns('/foo')).deleteSync();
+ },
+ );
+ });
+
+ test('succeedsIfPathReferencesDirectoryAndRecursiveTrue', () {
+ fs.directory(ns('/foo')).createSync();
+ fs.link(ns('/foo')).deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ });
+
+ test('unlinksIfTargetIsFileAndRecursiveFalse', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.file(ns('/bar')).createSync();
+ l.deleteSync();
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ });
+
+ test('unlinksIfTargetIsFileAndRecursiveTrue', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.file(ns('/bar')).createSync();
+ l.deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ });
+
+ test('unlinksIfTargetIsDirectoryAndRecursiveFalse', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.directory(ns('/bar')).createSync();
+ l.deleteSync();
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.directory);
+ });
+
+ test('unlinksIfTargetIsDirectoryAndRecursiveTrue', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.directory(ns('/bar')).createSync();
+ l.deleteSync(recursive: true);
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.directory);
+ });
+
+ test('unlinksIfTargetIsLinkLoop', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ l.deleteSync();
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.link);
+ });
+ });
+
+ group('parent', () {
+ test('returnsCovariantType', () {
+ expect(fs.link(ns('/foo')).parent, isDirectory);
+ });
+
+ test('succeedsIfLinkDoesntExist', () {
+ expect(fs.link(ns('/foo')).parent.path, ns('/'));
+ });
+
+ test('ignoresLinkTarget', () {
+ Link l = fs.link(ns('/foo/bar'))
+ ..createSync(ns('/baz/qux'), recursive: true);
+ expect(l.parent.path, ns('/foo'));
+ });
+ });
+
+ group('create', () {
+ test('returnsCovariantType', () async {
+ expect(await fs.link(ns('/foo')).create(ns('/bar')), isLink);
+ });
+
+ test('succeedsIfLinkDoesntExistAtTail', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(l.targetSync(), ns('/bar'));
+ });
+
+ test('throwsIfLinkDoesntExistViaTraversalAndRecursiveFalse', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo/bar')).createSync('baz');
+ });
+ });
+
+ test('succeedsIfLinkDoesntExistViaTraversalAndRecursiveTrue', () {
+ Link l = fs.link(ns('/foo/bar'))..createSync('baz', recursive: true);
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.directory);
+ expect(fs.typeSync(ns('/foo/bar'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(l.targetSync(), 'baz');
+ });
+
+ test('throwsIfAlreadyExistsAsFile', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EEXIST, () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfAlreadyExistsAsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EEXIST, () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfAlreadyExistsWithSameTarget', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.EEXIST, () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfAlreadyExistsWithDifferentTarget', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.EEXIST, () {
+ fs.link(ns('/foo')).createSync(ns('/baz'));
+ });
+ });
+ });
+
+ group('update', () {
+ test('returnsCovariantType', () async {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ expect(await l.update(ns('/baz')), isLink);
+ });
+
+ test('throwsIfLinkDoesntExistAtTail', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo')).updateSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfLinkDoesntExistViaTraversal', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo/bar')).updateSync(ns('/baz'));
+ });
+ });
+
+ test('throwsIfPathReferencesFile', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EINVAL, () {
+ fs.link(ns('/foo')).updateSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfPathReferencesDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ // TODO(tvolkert): Change this to just be 'Is a directory'
+ // once Dart 1.22 is stable.
+ expectFileSystemException(
+ anyOf(ErrorCodes.EINVAL, ErrorCodes.EISDIR),
+ () {
+ fs.link(ns('/foo')).updateSync(ns('/bar'));
+ },
+ );
+ });
+
+ test('succeedsIfNewTargetSameAsOldTarget', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ fs.link(ns('/foo')).updateSync(ns('/bar'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/foo')).targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfNewTargetDifferentFromOldTarget', () {
+ fs.link(ns('/foo')).createSync(ns('/bar'));
+ fs.link(ns('/foo')).updateSync(ns('/baz'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/foo')).targetSync(), ns('/baz'));
+ });
+ });
+
+ group('absolute', () {
+ test('returnsCovariantType', () {
+ expect(fs.link('foo').absolute, isLink);
+ });
+
+ test('returnsSamePathIfAlreadyAbsolute', () {
+ expect(fs.link(ns('/foo')).absolute.path, ns('/foo'));
+ });
+
+ test('succeedsForRelativePaths', () {
+ expect(fs.link('foo').absolute.path, ns('/foo'));
+ });
+ });
+
+ group('target', () {
+ test('throwsIfLinkDoesntExistAtTail', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo')).targetSync();
+ });
+ });
+
+ test('throwsIfLinkDoesntExistViaTraversal', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo/bar')).targetSync();
+ });
+ });
+
+ test('throwsIfPathReferencesFile', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo')).targetSync();
+ });
+ });
+
+ test('throwsIfPathReferencesDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo')).targetSync();
+ });
+ });
+
+ test('succeedsIfTargetIsNotFound', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ expect(l.targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfTargetIsFile', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.file(ns('/bar')).createSync();
+ expect(l.targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfTargetIsDirectory', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.directory(ns('/bar')).createSync();
+ expect(l.targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfTargetIsLinkLoop', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ expect(l.targetSync(), ns('/bar'));
+ });
+ });
+
+ group('rename', () {
+ test('returnsCovariantType', () async {
+ Link l() => fs.link(ns('/foo'))..createSync(ns('/bar'));
+ expect(l().renameSync(ns('/bar')), isLink);
+ expect(await l().rename(ns('/bar')), isLink);
+ });
+
+ test('throwsIfSourceDoesntExistAtTail', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo')).renameSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfSourceDoesntExistViaTraversal', () {
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ fs.link(ns('/foo/bar')).renameSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfSourceIsFile', () {
+ fs.file(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EINVAL, () {
+ fs.link(ns('/foo')).renameSync(ns('/bar'));
+ });
+ });
+
+ test('throwsIfSourceIsDirectory', () {
+ fs.directory(ns('/foo')).createSync();
+ expectFileSystemException(ErrorCodes.EISDIR, () {
+ fs.link(ns('/foo')).renameSync(ns('/bar'));
+ });
+ });
+
+ test('succeedsIfSourceIsLinkToFile', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.file(ns('/bar')).createSync();
+ Link renamed = l.renameSync(ns('/baz'));
+ expect(renamed.path, ns('/baz'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/baz')).targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfSourceIsLinkToNotFound', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ Link renamed = l.renameSync(ns('/baz'));
+ expect(renamed.path, ns('/baz'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/baz')).targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfSourceIsLinkToDirectory', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.directory(ns('/bar')).createSync();
+ Link renamed = l.renameSync(ns('/baz'));
+ expect(renamed.path, ns('/baz'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.directory);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/baz')).targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfSourceIsLinkLoop', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.link(ns('/bar')).createSync(ns('/foo'));
+ Link renamed = l.renameSync(ns('/baz'));
+ expect(renamed.path, ns('/baz'));
+ expect(fs.typeSync(ns('/foo'), followLinks: false),
+ FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/bar'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/baz')).targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfDestinationDoesntExistAtTail', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ Link renamed = l.renameSync(ns('/baz'));
+ expect(renamed.path, ns('/baz'));
+ expect(fs.link(ns('/foo')), isNot(exists));
+ expect(fs.link(ns('/baz')), exists);
+ });
+
+ test('throwsIfDestinationDoesntExistViaTraversal', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ expectFileSystemException(ErrorCodes.ENOENT, () {
+ l.renameSync(ns('/baz/qux'));
+ });
+ });
+
+ test('throwsIfDestinationExistsAsFile', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.file(ns('/baz')).createSync();
+ expectFileSystemException(ErrorCodes.EINVAL, () {
+ l.renameSync(ns('/baz'));
+ });
+ });
+
+ test('throwsIfDestinationExistsAsDirectory', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.directory(ns('/baz')).createSync();
+ expectFileSystemException(ErrorCodes.EINVAL, () {
+ l.renameSync(ns('/baz'));
+ });
+ });
+
+ test('succeedsIfDestinationExistsAsLinkToFile', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.file(ns('/baz')).createSync();
+ fs.link(ns('/qux')).createSync(ns('/baz'));
+ l.renameSync(ns('/qux'));
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.file);
+ expect(fs.typeSync(ns('/qux'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/qux')).targetSync(), ns('/bar'));
+ });
+
+ test('throwsIfDestinationExistsAsLinkToDirectory', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.directory(ns('/baz')).createSync();
+ fs.link(ns('/qux')).createSync(ns('/baz'));
+ l.renameSync(ns('/qux'));
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.directory);
+ expect(fs.typeSync(ns('/qux'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/qux')).targetSync(), ns('/bar'));
+ });
+
+ test('succeedsIfDestinationExistsAsLinkToNotFound', () {
+ Link l = fs.link(ns('/foo'))..createSync(ns('/bar'));
+ fs.link(ns('/baz')).createSync(ns('/qux'));
+ l.renameSync(ns('/baz'));
+ expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound);
+ expect(fs.typeSync(ns('/baz'), followLinks: false),
+ FileSystemEntityType.link);
+ expect(fs.link(ns('/baz')).targetSync(), ns('/bar'));
+ });
+ });
+ });
+ });
+}
diff --git a/pkgs/file/test/local_test.dart b/pkgs/file/test/local_test.dart
new file mode 100644
index 0000000..e1618d2
--- /dev/null
+++ b/pkgs/file/test/local_test.dart
@@ -0,0 +1,132 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+import 'dart:io' as io;
+
+import 'package:file/local.dart';
+import 'package:file_testing/src/testing/internal.dart';
+import 'package:test/test.dart';
+
+import 'common_tests.dart';
+
+void main() {
+ group('LocalFileSystem', () {
+ late LocalFileSystem fs;
+ late io.Directory tmp;
+ late String cwd;
+
+ setUp(() {
+ fs = const LocalFileSystem();
+ tmp = io.Directory.systemTemp.createTempSync('file_test_');
+ tmp = io.Directory(tmp.resolveSymbolicLinksSync());
+ cwd = io.Directory.current.path;
+ io.Directory.current = tmp;
+ });
+
+ tearDown(() {
+ io.Directory.current = cwd;
+ tmp.deleteSync(recursive: true);
+ });
+
+ setUpAll(() {
+ if (io.Platform.isWindows) {
+ // TODO(tvolkert): Remove once all more serious test failures are fixed
+ // https://github.com/google/file.dart/issues/56
+ ignoreOsErrorCodes = true;
+ }
+ });
+
+ tearDownAll(() {
+ ignoreOsErrorCodes = false;
+ });
+
+ Map<String, List<String>> skipOnPlatform = <String, List<String>>{
+ 'windows': <String>[
+ 'FileSystem > currentDirectory > throwsIfHasNonExistentPathInComplexChain',
+ 'FileSystem > currentDirectory > resolvesLinksIfEncountered',
+ 'FileSystem > currentDirectory > succeedsIfSetToDirectoryLinkAtTail',
+ 'FileSystem > stat > isFileForLinkToFile',
+ 'FileSystem > type > isFileForLinkToFileAndFollowLinksTrue',
+ 'FileSystem > type > isNotFoundForLinkWithCircularReferenceAndFollowLinksTrue',
+ 'Directory > exists > falseIfNotFoundSegmentExistsThenIsBackedOut',
+ 'Directory > rename > throwsIfDestinationIsNonEmptyDirectory',
+ 'Directory > rename > throwsIfDestinationIsLinkToEmptyDirectory',
+ 'Directory > resolveSymbolicLinks > throwsIfPathNotFoundInMiddleThenBackedOut',
+ 'Directory > resolveSymbolicLinks > handlesRelativeLinks',
+ 'Directory > resolveSymbolicLinks > handlesLinksWhoseTargetsHaveNestedLinks',
+ 'Directory > resolveSymbolicLinks > handlesComplexPathWithMultipleLinks',
+ 'Directory > createTemp > succeedsWithNestedPathPrefixThatExists',
+ 'Directory > list > followsLinksIfFollowLinksTrue',
+ 'Directory > list > returnsCovariantType',
+ 'Directory > list > returnsLinkObjectsForRecursiveLinkIfFollowLinksTrue',
+ 'Directory > delete > succeedsIfPathReferencesLinkToFileAndRecursiveTrue',
+ 'File > rename > succeedsIfSourceExistsAsLinkToFile',
+ 'File > copy > succeedsIfSourceExistsAsLinkToFile',
+ 'File > copy > succeedsIfSourceIsLinkToFileInDifferentDirectory',
+ 'File > delete > succeedsIfExistsAsLinkToFileAndRecursiveTrue',
+ 'File > openWrite > ioSink > throwsIfEncodingIsNullAndWriteObject',
+ 'File > openWrite > ioSink > allowsChangingEncoding',
+ 'File > openWrite > ioSink > succeedsIfAddRawData',
+ 'File > openWrite > ioSink > succeedsIfWrite',
+ 'File > openWrite > ioSink > succeedsIfWriteAll',
+ 'File > openWrite > ioSink > succeedsIfWriteCharCode',
+ 'File > openWrite > ioSink > succeedsIfWriteln',
+ 'File > openWrite > ioSink > addStream > succeedsIfStreamProducesData',
+ 'File > openWrite > ioSink > addStream > blocksCallToAddWhileStreamIsActive',
+ 'File > openWrite > ioSink > addStream > blocksCallToWriteWhileStreamIsActive',
+ 'File > openWrite > ioSink > addStream > blocksCallToWriteAllWhileStreamIsActive',
+ 'File > openWrite > ioSink > addStream > blocksCallToWriteCharCodeWhileStreamIsActive',
+ 'File > openWrite > ioSink > addStream > blocksCallToWritelnWhileStreamIsActive',
+ 'File > openWrite > ioSink > addStream > blocksCallToFlushWhileStreamIsActive',
+ 'File > stat > isFileIfExistsAsLinkToFile',
+ 'Link > stat > isFileIfTargetIsFile',
+ 'Link > stat > isDirectoryIfTargetIsDirectory',
+ 'Link > delete > unlinksIfTargetIsDirectoryAndRecursiveTrue',
+ 'Link > delete > unlinksIfTargetIsFileAndRecursiveTrue',
+
+ // Fixed in SDK 1.23 (https://github.com/dart-lang/sdk/issues/28852)
+ 'File > open > WRITE > RandomAccessFile > truncate > throwsIfSetToNegativeNumber',
+ 'File > open > APPEND > RandomAccessFile > truncate > throwsIfSetToNegativeNumber',
+ 'File > open > WRITE_ONLY > RandomAccessFile > truncate > throwsIfSetToNegativeNumber',
+ 'File > open > WRITE_ONLY_APPEND > RandomAccessFile > truncate > throwsIfSetToNegativeNumber',
+
+ // Windows does not allow removing or renaming open files.
+ '.* > openReadHandleDoesNotChange',
+ '.* > openWriteHandleDoesNotChange',
+ ],
+ };
+
+ runCommonTests(
+ () => fs,
+ root: () => tmp.path,
+ skip: <String>[
+ // https://github.com/dart-lang/sdk/issues/28171
+ 'File > rename > throwsIfDestinationExistsAsLinkToDirectory',
+
+ // https://github.com/dart-lang/sdk/issues/28275
+ 'Link > rename > throwsIfDestinationExistsAsDirectory',
+
+ // https://github.com/dart-lang/sdk/issues/28277
+ 'Link > rename > throwsIfDestinationExistsAsFile',
+
+ ...skipOnPlatform[io.Platform.operatingSystem] ?? <String>[],
+ ],
+ );
+
+ group('toString', () {
+ test('File', () {
+ expect(fs.file('/foo').toString(), "LocalFile: '/foo'");
+ });
+
+ test('Directory', () {
+ expect(fs.directory('/foo').toString(), "LocalDirectory: '/foo'");
+ });
+
+ test('Link', () {
+ expect(fs.link('/foo').toString(), "LocalLink: '/foo'");
+ });
+ });
+ });
+}
diff --git a/pkgs/file/test/memory_operations_test.dart b/pkgs/file/test/memory_operations_test.dart
new file mode 100644
index 0000000..5e27843
--- /dev/null
+++ b/pkgs/file/test/memory_operations_test.dart
@@ -0,0 +1,231 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('Read operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.read) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ final File file = fs.file('test')..createSync();
+
+ await file.readAsBytes();
+ file.readAsBytesSync();
+ await file.readAsString();
+ file.readAsStringSync();
+
+ expect(contexts, <String>['test', 'test', 'test', 'test']);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.read,
+ FileSystemOp.read,
+ FileSystemOp.read,
+ FileSystemOp.read
+ ]);
+ });
+
+ test('Write operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.write) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ final File file = fs.file('test')..createSync();
+
+ await file.writeAsBytes(<int>[]);
+ file.writeAsBytesSync(<int>[]);
+ await file.writeAsString('');
+ file.writeAsStringSync('');
+
+ expect(contexts, <String>['test', 'test', 'test', 'test']);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.write,
+ FileSystemOp.write,
+ FileSystemOp.write,
+ FileSystemOp.write
+ ]);
+ });
+
+ test('Delete operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.delete) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ final File file = fs.file('test')..createSync();
+ final Directory directory = fs.directory('testDir')..createSync();
+ final Link link = fs.link('testLink')..createSync('foo');
+
+ await file.delete();
+ file.createSync();
+ file.deleteSync();
+
+ await directory.delete();
+ directory.createSync();
+ directory.deleteSync();
+
+ await link.delete();
+ link.createSync('foo');
+ link.deleteSync();
+
+ expect(contexts,
+ <String>['test', 'test', 'testDir', 'testDir', 'testLink', 'testLink']);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.delete,
+ FileSystemOp.delete,
+ FileSystemOp.delete,
+ FileSystemOp.delete,
+ FileSystemOp.delete,
+ FileSystemOp.delete,
+ ]);
+ });
+
+ test('Create operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.create) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ fs.file('testA').createSync();
+ await fs.file('testB').create();
+ fs.directory('testDirA').createSync();
+ await fs.directory('testDirB').create();
+ fs.link('testLinkA').createSync('foo');
+ await fs.link('testLinkB').create('foo');
+ fs.currentDirectory.createTempSync('tmp.bar');
+ await fs.currentDirectory.createTemp('tmp.bar');
+
+ expect(contexts, <dynamic>[
+ 'testA',
+ 'testB',
+ 'testDirA',
+ 'testDirB',
+ 'testLinkA',
+ 'testLinkB',
+ startsWith('/tmp.bar'),
+ startsWith('/tmp.bar'),
+ ]);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.create,
+ FileSystemOp.create,
+ FileSystemOp.create,
+ FileSystemOp.create,
+ FileSystemOp.create,
+ FileSystemOp.create,
+ FileSystemOp.create,
+ FileSystemOp.create,
+ ]);
+ });
+
+ test('Open operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.open) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ final File file = fs.file('test')..createSync();
+
+ await file.open();
+ file.openSync();
+ file.openRead();
+ file.openWrite();
+
+ expect(contexts, <String>['test', 'test', 'test', 'test']);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.open,
+ FileSystemOp.open,
+ FileSystemOp.open,
+ FileSystemOp.open,
+ ]);
+ });
+
+ test('Copy operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.copy) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ final File file = fs.file('test')..createSync();
+
+ await file.copy('A');
+ file.copySync('B');
+
+ expect(contexts, <String>['test', 'test']);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.copy,
+ FileSystemOp.copy,
+ ]);
+ });
+
+ test('Exists operations invoke opHandle', () async {
+ List<String> contexts = <String>[];
+ List<FileSystemOp> operations = <FileSystemOp>[];
+ MemoryFileSystem fs = MemoryFileSystem.test(
+ opHandle: (String context, FileSystemOp operation) {
+ if (operation == FileSystemOp.exists) {
+ contexts.add(context);
+ operations.add(operation);
+ }
+ });
+ fs.file('testA').existsSync();
+ await fs.file('testB').exists();
+ fs.directory('testDirA').existsSync();
+ await fs.directory('testDirB').exists();
+ fs.link('testLinkA').existsSync();
+ await fs.link('testLinkB').exists();
+
+ expect(contexts, <dynamic>[
+ 'testA',
+ 'testB',
+ 'testDirA',
+ 'testDirB',
+ 'testLinkA',
+ 'testLinkB',
+ ]);
+ expect(operations, <FileSystemOp>[
+ FileSystemOp.exists,
+ FileSystemOp.exists,
+ FileSystemOp.exists,
+ FileSystemOp.exists,
+ FileSystemOp.exists,
+ FileSystemOp.exists,
+ ]);
+ });
+
+ test('FileSystemOp toString', () {
+ expect(FileSystemOp.create.toString(), 'FileSystemOp.create');
+ expect(FileSystemOp.delete.toString(), 'FileSystemOp.delete');
+ expect(FileSystemOp.read.toString(), 'FileSystemOp.read');
+ expect(FileSystemOp.write.toString(), 'FileSystemOp.write');
+ expect(FileSystemOp.exists.toString(), 'FileSystemOp.exists');
+ });
+}
diff --git a/pkgs/file/test/memory_test.dart b/pkgs/file/test/memory_test.dart
new file mode 100644
index 0000000..f3b324e
--- /dev/null
+++ b/pkgs/file/test/memory_test.dart
@@ -0,0 +1,173 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io' as io;
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:file/src/backends/memory/memory_random_access_file.dart';
+import 'package:test/test.dart';
+
+import 'common_tests.dart';
+
+void main() {
+ group('MemoryFileSystem unix style', () {
+ late MemoryFileSystem fs;
+
+ setUp(() {
+ fs = MemoryFileSystem();
+ });
+
+ runCommonTests(() => fs);
+
+ group('toString', () {
+ test('File', () {
+ expect(fs.file('/foo').toString(), "MemoryFile: '/foo'");
+ });
+
+ test('Directory', () {
+ expect(fs.directory('/foo').toString(), "MemoryDirectory: '/foo'");
+ });
+
+ test('Link', () {
+ expect(fs.link('/foo').toString(), "MemoryLink: '/foo'");
+ });
+ });
+ });
+
+ group('MemoryFileSystem windows style', () {
+ late MemoryFileSystem fs;
+
+ setUp(() {
+ fs = MemoryFileSystem(style: FileSystemStyle.windows);
+ });
+
+ runCommonTests(
+ () => fs,
+ root: () => fs.style.root,
+ );
+
+ group('toString', () {
+ test('File', () {
+ expect(fs.file('C:\\foo').toString(), "MemoryFile: 'C:\\foo'");
+ });
+
+ test('Directory', () {
+ expect(
+ fs.directory('C:\\foo').toString(), "MemoryDirectory: 'C:\\foo'");
+ });
+
+ test('Link', () {
+ expect(fs.link('C:\\foo').toString(), "MemoryLink: 'C:\\foo'");
+ });
+ });
+ });
+
+ test('MemoryFileSystem.test', () {
+ final MemoryFileSystem fs =
+ MemoryFileSystem.test(); // creates root directory
+ fs.file('/test1.txt').createSync(); // creates file
+ fs.file('/test2.txt').createSync(); // creates file
+ expect(fs.directory('/').statSync().modified, DateTime(2000, 1, 1, 0, 1));
+ expect(
+ fs.file('/test1.txt').statSync().modified, DateTime(2000, 1, 1, 0, 2));
+ expect(
+ fs.file('/test2.txt').statSync().modified, DateTime(2000, 1, 1, 0, 3));
+ fs.file('/test1.txt').createSync();
+ fs.file('/test2.txt').createSync();
+ expect(fs.file('/test1.txt').statSync().modified,
+ DateTime(2000, 1, 1, 0, 2)); // file already existed
+ expect(fs.file('/test2.txt').statSync().modified,
+ DateTime(2000, 1, 1, 0, 3)); // file already existed
+ fs.file('/test1.txt').writeAsStringSync('test'); // touches file
+ expect(
+ fs.file('/test1.txt').statSync().modified, DateTime(2000, 1, 1, 0, 4));
+ expect(fs.file('/test2.txt').statSync().modified,
+ DateTime(2000, 1, 1, 0, 3)); // didn't touch it
+ fs.file('/test1.txt').copySync(
+ '/test2.txt'); // creates file, then mutates file (so time changes twice)
+ expect(fs.file('/test1.txt').statSync().modified,
+ DateTime(2000, 1, 1, 0, 4)); // didn't touch it
+ expect(
+ fs.file('/test2.txt').statSync().modified, DateTime(2000, 1, 1, 0, 6));
+ });
+
+ test('MemoryFile.openSync returns a MemoryRandomAccessFile', () async {
+ final MemoryFileSystem fs = MemoryFileSystem.test();
+ final io.File file = fs.file('/test1')..createSync();
+
+ io.RandomAccessFile raf = file.openSync();
+ try {
+ expect(raf, isA<MemoryRandomAccessFile>());
+ } finally {
+ raf.closeSync();
+ }
+
+ raf = await file.open();
+ try {
+ expect(raf, isA<MemoryRandomAccessFile>());
+ } finally {
+ raf.closeSync();
+ }
+ });
+
+ test('MemoryFileSystem.systemTempDirectory test', () {
+ final MemoryFileSystem fs = MemoryFileSystem.test();
+
+ final io.Directory fooA = fs.systemTempDirectory.createTempSync('foo');
+ final io.Directory fooB = fs.systemTempDirectory.createTempSync('foo');
+
+ expect(fooA.path, '/.tmp_rand0/foorand0');
+ expect(fooB.path, '/.tmp_rand0/foorand1');
+
+ final MemoryFileSystem secondFs = MemoryFileSystem.test();
+
+ final io.Directory fooAA =
+ secondFs.systemTempDirectory.createTempSync('foo');
+ final io.Directory fooBB =
+ secondFs.systemTempDirectory.createTempSync('foo');
+
+ // Names are recycled with a new instance
+ expect(fooAA.path, '/.tmp_rand0/foorand0');
+ expect(fooBB.path, '/.tmp_rand0/foorand1');
+ });
+
+ test('Failed UTF8 decoding in MemoryFileSystem throws a FileSystemException',
+ () {
+ final MemoryFileSystem fileSystem = MemoryFileSystem.test();
+ final File file = fileSystem.file('foo')
+ ..writeAsBytesSync(<int>[0xFFFE]); // Invalid UTF8
+
+ expect(file.readAsStringSync, throwsA(isA<FileSystemException>()));
+ });
+
+ test('Creating a temporary directory actually creates the directory', () {
+ final MemoryFileSystem fileSystem = MemoryFileSystem.test();
+ final Directory tempDir = fileSystem.currentDirectory.createTempSync('foo');
+
+ expect(tempDir.existsSync(), true);
+ });
+
+ test(
+ 'addStream forwards error to returned future and file can still be '
+ 'closed', () async {
+ final file = MemoryFileSystem.test().file('foo').openWrite();
+ await expectLater(file.addStream(Stream.error('bar')), throwsA('bar'));
+ await file.close();
+ });
+
+ test(
+ 'addStream cancels on error and does not misbehave if the stream '
+ 'produces multiple errors and then closes', () async {
+ final file = MemoryFileSystem.test().file('foo').openWrite();
+ final controller = StreamController<List<int>>()
+ ..addError('bar')
+ ..addError('baz');
+ final close = controller.close();
+ await expectLater(file.addStream(controller.stream), throwsA('bar'));
+ await file.close();
+ await close;
+ });
+}
diff --git a/pkgs/file/test/utils.dart b/pkgs/file/test/utils.dart
new file mode 100644
index 0000000..231312f
--- /dev/null
+++ b/pkgs/file/test/utils.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:meta/meta.dart';
+import 'package:test/test.dart';
+
+const Duration _oneSecond = Duration(seconds: 1);
+
+/// Returns a [DateTime] with an exact second-precision by removing the
+/// milliseconds and microseconds from the specified [time].
+///
+/// If [time] is not specified, it will default to the current time.
+DateTime floor([DateTime? time]) {
+ time ??= DateTime.now();
+ return time.subtract(Duration(
+ milliseconds: time.millisecond,
+ microseconds: time.microsecond,
+ ));
+}
+
+/// Returns a [DateTime] with an exact second precision, rounding up to the
+/// nearest second if necessary.
+///
+/// If [time] is not specified, it will default to the current time.
+DateTime ceil([DateTime? time]) {
+ time ??= DateTime.now();
+ int microseconds = (1000 * time.millisecond) + time.microsecond;
+ return (microseconds == 0)
+ ? time
+ // Add just enough milliseconds and microseconds to reach the next second.
+ : time.add(Duration(microseconds: 1000000 - microseconds));
+}
+
+/// Returns 1 second before the [floor] of the specified [DateTime].
+// TODO(jamesderlin): Remove this and use [floor], https://github.com/dart-lang/sdk/issues/42444
+DateTime downstairs([DateTime? time]) => floor(time).subtract(_oneSecond);
+
+/// Successfully matches against a [DateTime] that is the same moment or before
+/// the specified [time].
+Matcher isSameOrBefore(DateTime time) => _IsSameOrBefore(time);
+
+/// Successfully matches against a [DateTime] that is the same moment or after
+/// the specified [time].
+Matcher isSameOrAfter(DateTime time) => _IsSameOrAfter(time);
+
+/// Successfully matches against a [DateTime] that is after the specified
+/// [time].
+Matcher isAfter(DateTime time) => _IsAfter(time);
+
+abstract class _CompareDateTime extends Matcher {
+ const _CompareDateTime(this._time, this._matcher);
+
+ final DateTime _time;
+ final Matcher _matcher;
+
+ @override
+ bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
+ return item is DateTime &&
+ _matcher.matches(item.compareTo(_time), <dynamic, dynamic>{});
+ }
+
+ @protected
+ String get descriptionOperator;
+
+ @override
+ Description describe(Description description) =>
+ description.add('a DateTime $descriptionOperator $_time');
+
+ @protected
+ String get mismatchAdjective;
+
+ @override
+ Description describeMismatch(
+ dynamic item,
+ Description description,
+ Map<dynamic, dynamic> matchState,
+ bool verbose,
+ ) {
+ if (item is DateTime) {
+ Duration diff = item.difference(_time).abs();
+ return description.add('is $mismatchAdjective $_time by $diff');
+ } else {
+ return description.add('is not a DateTime');
+ }
+ }
+}
+
+class _IsSameOrBefore extends _CompareDateTime {
+ const _IsSameOrBefore(DateTime time) : super(time, isNonPositive);
+
+ @override
+ String get descriptionOperator => '<=';
+
+ @override
+ String get mismatchAdjective => 'after';
+}
+
+class _IsSameOrAfter extends _CompareDateTime {
+ const _IsSameOrAfter(DateTime time) : super(time, isNonNegative);
+
+ @override
+ String get descriptionOperator => '>=';
+
+ @override
+ String get mismatchAdjective => 'before';
+}
+
+class _IsAfter extends _CompareDateTime {
+ const _IsAfter(DateTime time) : super(time, isPositive);
+
+ @override
+ String get descriptionOperator => '>';
+
+ @override
+ String get mismatchAdjective => 'before';
+}
diff --git a/pkgs/file/test/utils_test.dart b/pkgs/file/test/utils_test.dart
new file mode 100644
index 0000000..75293bf
--- /dev/null
+++ b/pkgs/file/test/utils_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ test('floorAndCeilProduceExactSecondDateTime', () {
+ DateTime time = DateTime.fromMicrosecondsSinceEpoch(1001);
+ DateTime lower = floor(time);
+ DateTime upper = ceil(time);
+ expect(lower.millisecond, 0);
+ expect(upper.millisecond, 0);
+ expect(lower.microsecond, 0);
+ expect(upper.microsecond, 0);
+ });
+
+ test('floorAndCeilWorkWithNow', () {
+ DateTime time = DateTime.now();
+ int lower = time.difference(floor(time)).inMicroseconds;
+ int upper = ceil(time).difference(time).inMicroseconds;
+ expect(lower, lessThan(1000000));
+ expect(upper, lessThanOrEqualTo(1000000));
+ });
+
+ test('floorAndCeilWorkWithExactSecondDateTime', () {
+ DateTime time = DateTime.parse('1999-12-31 23:59:59');
+ DateTime lower = floor(time);
+ DateTime upper = ceil(time);
+ expect(lower, time);
+ expect(upper, time);
+ });
+
+ test('floorAndCeilWorkWithInexactSecondDateTime', () {
+ DateTime time = DateTime.parse('1999-12-31 23:59:59.500');
+ DateTime lower = floor(time);
+ DateTime upper = ceil(time);
+ Duration difference = upper.difference(lower);
+ expect(difference.inMicroseconds, 1000000);
+ });
+}
diff --git a/pkgs/file_testing/.gitignore b/pkgs/file_testing/.gitignore
new file mode 100644
index 0000000..ddfdca1
--- /dev/null
+++ b/pkgs/file_testing/.gitignore
@@ -0,0 +1,5 @@
+.dart_tool/
+.packages
+.pub/
+build/
+pubspec.lock
diff --git a/pkgs/file_testing/CHANGELOG.md b/pkgs/file_testing/CHANGELOG.md
new file mode 100644
index 0000000..0af779d
--- /dev/null
+++ b/pkgs/file_testing/CHANGELOG.md
@@ -0,0 +1,44 @@
+## 3.0.2
+
+* Require Dart 3.1.
+
+## 3.0.1
+
+* Update the pubspec repository field to reflect the new package repository.
+* Require Dart 3.0.
+
+## 3.0.0
+
+* Migrate to null safety.
+
+## 2.2.0
+
+* Change dependency on `package:test_api` back to `package:test`.
+
+## 2.1.0
+
+* Changed dependency on `package:test` to `package:test_api`
+* Bumped Dart SDK constraint to match `package:test_api`'s requirements
+* Updated style to match latest lint rules from Flutter repo.
+
+## 2.0.3
+
+* Relaxed constraints on `package:test`
+
+## 2.0.2
+
+* Bumped dependency on `package:test` to version 1.0
+
+## 2.0.1
+
+* Bumped Dart SDK constraint to allow for Dart 2 stable
+
+## 2.0.0
+
+* Removed `record_replay_matchers.dart` from API
+
+## 1.0.0
+
+* Moved `package:file/testing.dart` library into a dedicated package so that
+ libraries don't need to take on a transitive dependency on `package:test`
+ in order to use `package:file`.
diff --git a/pkgs/file_testing/LICENSE b/pkgs/file_testing/LICENSE
new file mode 100644
index 0000000..076334f
--- /dev/null
+++ b/pkgs/file_testing/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2017, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/pkgs/file_testing/README.md b/pkgs/file_testing/README.md
new file mode 100644
index 0000000..7dda57e
--- /dev/null
+++ b/pkgs/file_testing/README.md
@@ -0,0 +1,39 @@
+[](https://pub.dev/packages/file_testing)
+[](https://pub.dev/packages/file_testing/publisher)
+
+Testing utilities intended to work with `package:file`.
+
+## Features
+
+This package provides a series of matchers to be used in tests that work with file
+system types.
+
+## Usage
+
+```dart
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:file_testing/file_testing.dart';
+import 'package:test/test.dart';
+
+void main() {
+ MemoryFileSystem fs;
+
+ setUp(() {
+ fs = MemoryFileSystem();
+ fs.file('/foo').createSync();
+ });
+
+ test('some test', () {
+ expectFileSystemException(
+ ErrorCodes.ENOENT,
+ () {
+ fs.directory('').resolveSymbolicLinksSync();
+ },
+ );
+ expect(fs.file('/path/to/file'), isFile);
+ expect(fs.file('/path/to/directory'), isDirectory);
+ expect(fs.file('/foo'), exists);
+ });
+}
+```
diff --git a/pkgs/file_testing/analysis_options.yaml b/pkgs/file_testing/analysis_options.yaml
new file mode 100644
index 0000000..8fbd2e4
--- /dev/null
+++ b/pkgs/file_testing/analysis_options.yaml
@@ -0,0 +1,6 @@
+include: package:lints/recommended.yaml
+
+analyzer:
+ errors:
+ # Allow having TODOs in the code
+ todo: ignore
diff --git a/pkgs/file_testing/lib/file_testing.dart b/pkgs/file_testing/lib/file_testing.dart
new file mode 100644
index 0000000..2ac2d0a
--- /dev/null
+++ b/pkgs/file_testing/lib/file_testing.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Matchers (from `package:test`) for use in tests that deal with file systems.
+library;
+
+export 'src/testing/core_matchers.dart';
diff --git a/pkgs/file_testing/lib/src/testing/core_matchers.dart b/pkgs/file_testing/lib/src/testing/core_matchers.dart
new file mode 100644
index 0000000..f58539f
--- /dev/null
+++ b/pkgs/file_testing/lib/src/testing/core_matchers.dart
@@ -0,0 +1,155 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:test/test.dart';
+
+import 'internal.dart';
+
+/// Matcher that successfully matches against any instance of [Directory].
+const Matcher isDirectory = TypeMatcher<Directory>();
+
+/// Matcher that successfully matches against any instance of [File].
+const Matcher isFile = TypeMatcher<File>();
+
+/// Matcher that successfully matches against any instance of [Link].
+const Matcher isLink = TypeMatcher<Link>();
+
+/// Matcher that successfully matches against any instance of
+/// [FileSystemEntity].
+const Matcher isFileSystemEntity = TypeMatcher<FileSystemEntity>();
+
+/// Matcher that successfully matches against any instance of [FileStat].
+const Matcher isFileStat = TypeMatcher<FileStat>();
+
+/// Returns a [Matcher] that matches [path] against an entity's path.
+///
+/// [path] may be a String, a predicate function, or a [Matcher]. If it is
+/// a String, it will be wrapped in an equality matcher.
+Matcher hasPath(dynamic path) => _HasPath(path);
+
+/// Returns a [Matcher] that successfully matches against an instance of
+/// [FileSystemException].
+///
+/// If [osErrorCode] is specified, matches will be limited to exceptions whose
+/// `osError.errorCode` also match the specified matcher.
+///
+/// [osErrorCode] may be an `int`, a predicate function, or a [Matcher]. If it
+/// is an `int`, it will be wrapped in an equality matcher.
+Matcher isFileSystemException([dynamic osErrorCode]) =>
+ _FileSystemException(osErrorCode);
+
+/// Returns a matcher that successfully matches against a future or function
+/// that throws a [FileSystemException].
+///
+/// If [osErrorCode] is specified, matches will be limited to exceptions whose
+/// `osError.errorCode` also match the specified matcher.
+///
+/// [osErrorCode] may be an `int`, a predicate function, or a [Matcher]. If it
+/// is an `int`, it will be wrapped in an equality matcher.
+Matcher throwsFileSystemException([dynamic osErrorCode]) =>
+ throwsA(isFileSystemException(osErrorCode));
+
+/// Expects the specified [callback] to throw a [FileSystemException] with the
+/// specified [osErrorCode] (matched against the exception's
+/// `osError.errorCode`).
+///
+/// [osErrorCode] may be an `int`, a predicate function, or a [Matcher]. If it
+/// is an `int`, it will be wrapped in an equality matcher.
+///
+/// See also:
+/// - [ErrorCodes]
+void expectFileSystemException(dynamic osErrorCode, void Function() callback) {
+ expect(callback, throwsFileSystemException(osErrorCode));
+}
+
+/// Matcher that successfully matches against a [FileSystemEntity] that
+/// exists ([FileSystemEntity.existsSync] returns true).
+const Matcher exists = _Exists();
+
+class _FileSystemException extends Matcher {
+ _FileSystemException(dynamic osErrorCode)
+ : _matcher = _wrapMatcher(osErrorCode);
+
+ final Matcher? _matcher;
+
+ static Matcher? _wrapMatcher(dynamic osErrorCode) {
+ if (osErrorCode == null) {
+ return null;
+ }
+ return ignoreOsErrorCodes ? anything : wrapMatcher(osErrorCode);
+ }
+
+ @override
+ bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
+ if (item is FileSystemException) {
+ return _matcher == null ||
+ _matcher!.matches(item.osError?.errorCode, matchState);
+ }
+ return false;
+ }
+
+ @override
+ Description describe(Description desc) {
+ if (_matcher == null) {
+ return desc.add('FileSystemException');
+ } else {
+ desc.add('FileSystemException with osError.errorCode: ');
+ return _matcher!.describe(desc);
+ }
+ }
+}
+
+class _HasPath extends Matcher {
+ _HasPath(dynamic path) : _matcher = wrapMatcher(path);
+
+ final Matcher _matcher;
+
+ @override
+ bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
+ _matcher.matches(item.path, matchState);
+
+ @override
+ Description describe(Description desc) {
+ desc.add('has path: ');
+ return _matcher.describe(desc);
+ }
+
+ @override
+ Description describeMismatch(
+ dynamic item,
+ Description desc,
+ Map<dynamic, dynamic> matchState,
+ bool verbose,
+ ) {
+ desc.add('has path: \'${item.path}\'').add('\n Which: ');
+ final Description pathDesc = StringDescription();
+ _matcher.describeMismatch(item.path, pathDesc, matchState, verbose);
+ desc.add(pathDesc.toString());
+ return desc;
+ }
+}
+
+class _Exists extends Matcher {
+ const _Exists();
+
+ @override
+ bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
+ item is FileSystemEntity && item.existsSync();
+
+ @override
+ Description describe(Description description) =>
+ description.add('a file system entity that exists');
+
+ @override
+ Description describeMismatch(
+ dynamic item,
+ Description description,
+ Map<dynamic, dynamic> matchState,
+ bool verbose,
+ ) {
+ return description.add('does not exist');
+ }
+}
diff --git a/pkgs/file_testing/lib/src/testing/internal.dart b/pkgs/file_testing/lib/src/testing/internal.dart
new file mode 100644
index 0000000..8f53a65
--- /dev/null
+++ b/pkgs/file_testing/lib/src/testing/internal.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// True if we should ignore OS error codes in our matchers.
+bool ignoreOsErrorCodes = false;
diff --git a/pkgs/file_testing/pubspec.yaml b/pkgs/file_testing/pubspec.yaml
new file mode 100644
index 0000000..691efa0
--- /dev/null
+++ b/pkgs/file_testing/pubspec.yaml
@@ -0,0 +1,14 @@
+name: file_testing
+version: 3.0.2
+description: Testing utilities for package:file.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/file_testing
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Afile_testing
+
+environment:
+ sdk: ^3.1.0
+
+dependencies:
+ test: ^1.23.1
+
+dev_dependencies:
+ lints: ^5.0.0
diff --git a/pkgs/graphs/.gitignore b/pkgs/graphs/.gitignore
new file mode 100644
index 0000000..ddfdca1
--- /dev/null
+++ b/pkgs/graphs/.gitignore
@@ -0,0 +1,5 @@
+.dart_tool/
+.packages
+.pub/
+build/
+pubspec.lock
diff --git a/pkgs/graphs/CHANGELOG.md b/pkgs/graphs/CHANGELOG.md
new file mode 100644
index 0000000..7213b5a
--- /dev/null
+++ b/pkgs/graphs/CHANGELOG.md
@@ -0,0 +1,77 @@
+## 2.3.3-wip
+
+- Add an example usage to the README.
+
+## 2.3.2
+
+- Require Dart 3.4
+- Update to the latest version of `package:dart_flutter_team_lints`.
+
+## 2.3.1
+
+- Update package repository after move.
+
+## 2.3.0
+
+- Add a `transitiveClosure` function.
+- Make `stronglyConnectedComponents` and `topologicalSort` iterative rather than
+ recursive to avoid stack overflows on very large graphs.
+- Require Dart 2.18
+
+## 2.2.0
+
+- Add a `secondarySort` parameter to the `topologicalSort()` function which
+ applies an additional lexical sort where that doesn't break the topological
+ sort.
+
+## 2.1.0
+
+- Add a `topologicalSort()` function.
+
+## 2.0.0
+
+- **Breaking**: `crawlAsync` will no longer ignore a node from the graph if the
+ `readNode` callback returns null.
+
+## 1.0.0
+
+- Migrate to null safety.
+- **Breaking**: Paths from `shortestPath[s]` are now returned as iterables to
+ reduce memory consumption of the algorithm to O(n).
+
+## 0.2.0
+
+- **BREAKING** `shortestPath`, `shortestPaths` and `stronglyConnectedComponents`
+ now have one generic parameter and have replaced the `key` parameter with
+ optional params: `{bool equals(T key1, T key2), int hashCode(T key)}`.
+ This follows the pattern used in `dart:collection` classes `HashMap` and
+ `LinkedHashMap`. It improves the usability and performance of the case where
+ the source values are directly usable in a hash data structure.
+
+## 0.1.3+1
+
+- Fixed a bug with non-identity `key` in `shortestPath` and `shortestPaths`.
+
+## 0.1.3
+
+- Added `shortestPath` and `shortestPaths` functions.
+- Use `HashMap` and `HashSet` from `dart:collection` for
+ `stronglyConnectedComponents`. Improves runtime performance.
+
+## 0.1.2+1
+
+- Allow using non-dev Dart 2 SDK.
+
+## 0.1.2
+
+- `crawlAsync` surfaces exceptions while crawling through the result stream
+ rather than as uncaught asynchronous errors.
+
+## 0.1.1
+
+- `crawlAsync` will now ignore nodes that are resolved to `null`.
+
+## 0.1.0
+
+- Initial release with an implementation of `stronglyConnectedComponents` and
+ `crawlAsync`.
diff --git a/pkgs/graphs/LICENSE b/pkgs/graphs/LICENSE
new file mode 100644
index 0000000..03af64a
--- /dev/null
+++ b/pkgs/graphs/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2017, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/graphs/README.md b/pkgs/graphs/README.md
new file mode 100644
index 0000000..09512b8
--- /dev/null
+++ b/pkgs/graphs/README.md
@@ -0,0 +1,57 @@
+[](https://github.com/dart-lang/tools/actions/workflows/graphs.yml)
+[](https://pub.dev/packages/graphs)
+[](https://pub.dev/packages/graphs/publisher)
+
+Graph algorithms that do not specify a particular approach for representing a
+Graph.
+
+Each algorithm is a top level function which takes callback arguments that
+provide the mechanism for traversing the graph. For example, two common
+approaches for representing a graph:
+
+```dart
+class AdjacencyListGraph<T> {
+ Map<T, List<T>> nodes;
+ // ...
+}
+```
+
+```dart
+class TreeGraph<T> {
+ Node<T> root;
+ // ...
+}
+class Node<T> {
+ List<Node<T>> edges;
+ T value;
+}
+```
+
+Any representation can be adapted to the callback arguments.
+
+- Algorithms which need to traverse the graph take an `edges` callback which
+ provides the immediate neighbors of a given node.
+- Algorithms which need to associate unique data with each node in the graph
+ allow passing `equals` and/or `hashCode` callbacks if the unique data type
+ does not correctly or efficiently implement `operator==` or `get hashCode`.
+
+
+Algorithms that support graphs which are resolved asynchronously will have
+similar callbacks which return `FutureOr`.
+
+```dart
+import 'package:graphs/graphs.dart';
+
+void sendMessage() {
+ final network = AdjacencyListGraph();
+ // ...
+ final route = shortestPath(
+ sender, receiver, (node) => network.nodes[node] ?? const []);
+}
+
+void resolveBuildOrder() {
+ final dependencies = TreeGraph();
+ // ...
+ final buildOrder = topologicalSort([dependencies.root], (node) => node.edges);
+}
+```
diff --git a/pkgs/graphs/analysis_options.yaml b/pkgs/graphs/analysis_options.yaml
new file mode 100644
index 0000000..fcbc888
--- /dev/null
+++ b/pkgs/graphs/analysis_options.yaml
@@ -0,0 +1,35 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-raw-types: true
+ errors:
+ sort_pub_dependencies: ignore
+ # https://github.com/dart-lang/sdk/issues/56465
+ unintended_html_in_doc_comment: ignore
+
+linter:
+ rules:
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_classes_with_only_static_members
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_returning_this
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - join_return_with_assignment
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - no_runtimeType_toString
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - require_trailing_commas
+ - unnecessary_await_in_return
+ - unnecessary_raw_strings
+ - use_if_null_to_convert_nulls_to_bools
+ - use_raw_strings
+ - use_string_buffers
diff --git a/pkgs/graphs/benchmark/connected_components_benchmark.dart b/pkgs/graphs/benchmark/connected_components_benchmark.dart
new file mode 100644
index 0000000..1f71879
--- /dev/null
+++ b/pkgs/graphs/benchmark/connected_components_benchmark.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:math' show Random;
+
+import 'package:graphs/graphs.dart';
+
+void main() {
+ final rnd = Random(0);
+ const size = 2000;
+ final graph = HashMap<int, List<int>>();
+
+ for (var i = 0; i < size * 3; i++) {
+ final toList = graph.putIfAbsent(rnd.nextInt(size), () => <int>[]);
+
+ final toValue = rnd.nextInt(size);
+ if (!toList.contains(toValue)) {
+ toList.add(toValue);
+ }
+ }
+
+ var maxCount = 0;
+ var maxIteration = 0;
+
+ const duration = Duration(milliseconds: 100);
+
+ for (var i = 1;; i++) {
+ var count = 0;
+ final watch = Stopwatch()..start();
+ while (watch.elapsed < duration) {
+ count++;
+ final length =
+ stronglyConnectedComponents(graph.keys, (e) => graph[e] ?? <Never>[])
+ .length;
+ assert(length == 244, '$length');
+ }
+
+ if (count > maxCount) {
+ maxCount = count;
+ maxIteration = i;
+ }
+
+ if (maxIteration == i || (i - maxIteration) % 20 == 0) {
+ print('max iterations in ${duration.inMilliseconds}ms: $maxCount\t'
+ 'after $maxIteration of $i iterations');
+ }
+ }
+}
diff --git a/pkgs/graphs/benchmark/shortest_path_benchmark.dart b/pkgs/graphs/benchmark/shortest_path_benchmark.dart
new file mode 100644
index 0000000..67e7367
--- /dev/null
+++ b/pkgs/graphs/benchmark/shortest_path_benchmark.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:math' show Random;
+
+import 'package:graphs/graphs.dart';
+
+void main() {
+ final rnd = Random(1);
+ const size = 1000;
+ final graph = HashMap<int, List<int>>();
+
+ for (var i = 0; i < size * 5; i++) {
+ final toList = graph.putIfAbsent(rnd.nextInt(size), () => <int>[]);
+
+ final toValue = rnd.nextInt(size);
+ if (!toList.contains(toValue)) {
+ toList.add(toValue);
+ }
+ }
+
+ int? minTicks;
+ var maxIteration = 0;
+
+ final testOutput =
+ shortestPath(0, size - 1, (e) => graph[e] ?? <Never>[]).toString();
+ print(testOutput);
+ assert(testOutput == '(258, 252, 819, 999)', testOutput);
+
+ final watch = Stopwatch();
+ for (var i = 1;; i++) {
+ watch
+ ..reset()
+ ..start();
+ final result = shortestPath(0, size - 1, (e) => graph[e] ?? <Never>[])!;
+ final length = result.length;
+ final first = result.first;
+ watch.stop();
+ assert(length == 4, '$length');
+ assert(first == 258, '$first');
+
+ if (minTicks == null || watch.elapsedTicks < minTicks) {
+ minTicks = watch.elapsedTicks;
+ maxIteration = i;
+ }
+
+ if (maxIteration == i || (i - maxIteration) % 100000 == 0) {
+ print('min ticks for one run: $minTicks\t'
+ 'after $maxIteration of $i iterations');
+ }
+ }
+}
diff --git a/pkgs/graphs/benchmark/shortest_path_worst_case_benchmark.dart b/pkgs/graphs/benchmark/shortest_path_worst_case_benchmark.dart
new file mode 100644
index 0000000..d3117ac
--- /dev/null
+++ b/pkgs/graphs/benchmark/shortest_path_worst_case_benchmark.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'package:graphs/graphs.dart';
+
+void main() {
+ const size = 1000;
+ final graph = HashMap<int, List<int>>();
+
+ // We create a graph where every subsequent node has an edge to every other
+ // node before it as well as the next node. This triggers worst case behavior
+ // in many algorithms as it requires visiting all nodes and edges before
+ // finding a solution, and there are a maximum number of edges.
+ for (var i = 0; i < size; i++) {
+ final toList = graph.putIfAbsent(i, () => <int>[]);
+ for (var t = 0; t < i + 2 && i < size; t++) {
+ if (i == t) continue;
+ toList.add(t);
+ }
+ }
+
+ int? minTicks;
+ var maxIteration = 0;
+
+ final testOutput =
+ shortestPath(0, size - 1, (e) => graph[e] ?? <Never>[]).toString();
+ print(testOutput);
+ assert(
+ testOutput == Iterable.generate(size - 1, (i) => i + 1).toString(),
+ testOutput,
+ );
+
+ final watch = Stopwatch();
+ for (var i = 1;; i++) {
+ watch
+ ..reset()
+ ..start();
+ final result = shortestPath(0, size - 1, (e) => graph[e] ?? <Never>[])!;
+ final length = result.length;
+ final first = result.first;
+ watch.stop();
+ assert(length == 999, '$length');
+ assert(first == 1, '$first');
+
+ if (minTicks == null || watch.elapsedTicks < minTicks) {
+ minTicks = watch.elapsedTicks;
+ maxIteration = i;
+ }
+
+ if (maxIteration == i || (i - maxIteration) % 100000 == 0) {
+ print('min ticks for one run: $minTicks\t'
+ 'after $maxIteration of $i iterations');
+ }
+ }
+}
diff --git a/pkgs/graphs/example/crawl_async_example.dart b/pkgs/graphs/example/crawl_async_example.dart
new file mode 100644
index 0000000..bd305c9
--- /dev/null
+++ b/pkgs/graphs/example/crawl_async_example.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:graphs/graphs.dart';
+import 'package:path/path.dart' as p;
+import 'package:pool/pool.dart';
+
+/// Print a transitive set of imported URIs where libraries are read
+/// asynchronously.
+Future<void> main() async {
+ // Limits calls to [findImports].
+ final pool = Pool(10);
+ final allImports = await crawlAsync<Uri, Source>(
+ [Uri.parse('package:graphs/graphs.dart')],
+ read,
+ (from, source) => pool.withResource(() => findImports(from, source)),
+ ).toList();
+ print(allImports.map((s) => s.uri).toList());
+}
+
+AnalysisContextCollection? _analysisContextCollection;
+
+Future<AnalysisContextCollection> get analysisContextCollection async {
+ var collection = _analysisContextCollection;
+ if (collection == null) {
+ final libUri = Uri.parse('package:graphs/');
+ final libPath = await pathForUri(libUri);
+ final packagePath = p.dirname(libPath);
+
+ collection = _analysisContextCollection = AnalysisContextCollection(
+ includedPaths: [packagePath],
+ );
+ }
+
+ return collection;
+}
+
+Future<Iterable<Uri>> findImports(Uri from, Source source) async =>
+ source.unit.directives
+ .whereType<UriBasedDirective>()
+ .map((d) => d.uri.stringValue!)
+ .where((uri) => !uri.startsWith('dart:'))
+ .map((import) => resolveImport(import, from));
+
+Future<CompilationUnit> parseUri(Uri uri) async {
+ final path = await pathForUri(uri);
+ final analysisContext = (await analysisContextCollection).contexts.single;
+ final analysisSession = analysisContext.currentSession;
+ final parseResult = analysisSession.getParsedUnit(path);
+ return (parseResult as ParsedUnitResult).unit;
+}
+
+Future<String> pathForUri(Uri uri) async {
+ final fileUri = await Isolate.resolvePackageUri(uri);
+ if (fileUri == null || !fileUri.isScheme('file')) {
+ throw StateError('Expected to resolve $uri to a file URI, got $fileUri');
+ }
+ return p.fromUri(fileUri);
+}
+
+Future<Source> read(Uri uri) async => Source(uri, await parseUri(uri));
+
+Uri resolveImport(String import, Uri from) {
+ if (import.startsWith('package:')) return Uri.parse(import);
+ assert(from.scheme == 'package');
+ final package = from.pathSegments.first;
+ final fromPath = p.joinAll(from.pathSegments.skip(1));
+ final path = p.normalize(p.join(p.dirname(fromPath), import));
+ return Uri.parse('package:${p.join(package, path)}');
+}
+
+class Source {
+ final Uri uri;
+ final CompilationUnit unit;
+
+ Source(this.uri, this.unit);
+}
diff --git a/pkgs/graphs/example/example.dart b/pkgs/graphs/example/example.dart
new file mode 100644
index 0000000..c9cf6dd
--- /dev/null
+++ b/pkgs/graphs/example/example.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:graphs/graphs.dart';
+
+/// A representation of a directed graph.
+///
+/// Data is stored on the [Node] class.
+class Graph {
+ final Map<Node, List<Node>> nodes;
+
+ Graph(this.nodes);
+}
+
+class Node {
+ final String id;
+ final int data;
+
+ Node(this.id, this.data);
+
+ @override
+ bool operator ==(Object other) => other is Node && other.id == id;
+
+ @override
+ int get hashCode => id.hashCode;
+
+ @override
+ String toString() => '<$id -> $data>';
+}
+
+void main() {
+ final nodeA = Node('A', 1);
+ final nodeB = Node('B', 2);
+ final nodeC = Node('C', 3);
+ final nodeD = Node('D', 4);
+ final graph = Graph({
+ nodeA: [nodeB, nodeC],
+ nodeB: [nodeC, nodeD],
+ nodeC: [nodeB, nodeD],
+ });
+
+ final components = stronglyConnectedComponents<Node>(
+ graph.nodes.keys,
+ (node) => graph.nodes[node] ?? [],
+ );
+
+ print(components);
+}
diff --git a/pkgs/graphs/lib/graphs.dart b/pkgs/graphs/lib/graphs.dart
new file mode 100644
index 0000000..f10b2e4
--- /dev/null
+++ b/pkgs/graphs/lib/graphs.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/crawl_async.dart' show crawlAsync;
+export 'src/cycle_exception.dart' show CycleException;
+export 'src/shortest_path.dart' show shortestPath, shortestPaths;
+export 'src/strongly_connected_components.dart'
+ show stronglyConnectedComponents;
+export 'src/topological_sort.dart' show topologicalSort;
+export 'src/transitive_closure.dart' show transitiveClosure;
diff --git a/pkgs/graphs/lib/src/crawl_async.dart b/pkgs/graphs/lib/src/crawl_async.dart
new file mode 100644
index 0000000..68c0a5b
--- /dev/null
+++ b/pkgs/graphs/lib/src/crawl_async.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+
+final _empty = Future<void>.value();
+
+/// Finds and returns every node in a graph who's nodes and edges are
+/// asynchronously resolved.
+///
+/// Cycles are allowed. If this is an undirected graph the [edges] function
+/// may be symmetric. In this case the [roots] may be any node in each connected
+/// graph.
+///
+/// [V] is the type of values in the graph nodes. [K] must be a type suitable
+/// for using as a Map or Set key. [edges] should return the next reachable
+/// nodes.
+///
+/// There are no ordering guarantees. This is useful for ensuring some work is
+/// performed at every node in an asynchronous graph, but does not give
+/// guarantees that the work is done in topological order.
+///
+/// If either [readNode] or [edges] throws the error will be forwarded
+/// through the result stream and no further nodes will be crawled, though some
+/// work may have already been started.
+///
+/// Crawling is eager, so calls to [edges] may overlap with other calls that
+/// have not completed. If the [edges] callback needs to be limited or throttled
+/// that must be done by wrapping it before calling [crawlAsync].
+Stream<V> crawlAsync<K extends Object, V>(
+ Iterable<K> roots,
+ FutureOr<V> Function(K) readNode,
+ FutureOr<Iterable<K>> Function(K, V) edges,
+) {
+ final crawl = _CrawlAsync(roots, readNode, edges)..run();
+ return crawl.result.stream;
+}
+
+class _CrawlAsync<K, V> {
+ final result = StreamController<V>();
+
+ final FutureOr<V> Function(K) readNode;
+ final FutureOr<Iterable<K>> Function(K, V) edges;
+ final Iterable<K> roots;
+
+ final _seen = HashSet<K>();
+
+ _CrawlAsync(this.roots, this.readNode, this.edges);
+
+ /// Add all nodes in the graph to [result] and return a Future which fires
+ /// after all nodes have been seen.
+ Future<void> run() async {
+ try {
+ await Future.wait(roots.map(_visit), eagerError: true);
+ await result.close();
+ } catch (e, st) {
+ result.addError(e, st);
+ await result.close();
+ }
+ }
+
+ /// Resolve the node at [key] and output it, then start crawling all of it's
+ /// edges.
+ Future<void> _crawlFrom(K key) async {
+ final value = await readNode(key);
+ if (result.isClosed) return;
+ result.add(value);
+ final next = await edges(key, value);
+ await Future.wait(next.map(_visit), eagerError: true);
+ }
+
+ /// Synchronously record that [key] is being handled then start work on the
+ /// node for [key].
+ ///
+ /// The returned Future will complete only after the work for [key] and all
+ /// transitively reachable nodes has either been finished, or will be finished
+ /// by some other Future in [_seen].
+ Future<void> _visit(K key) {
+ if (_seen.contains(key)) return _empty;
+ _seen.add(key);
+ return _crawlFrom(key);
+ }
+}
diff --git a/pkgs/graphs/lib/src/cycle_exception.dart b/pkgs/graphs/lib/src/cycle_exception.dart
new file mode 100644
index 0000000..eb9b433
--- /dev/null
+++ b/pkgs/graphs/lib/src/cycle_exception.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// An exception indicating that a cycle was detected in a graph that was
+/// expected to be acyclic.
+class CycleException<T> implements Exception {
+ /// The list of nodes comprising the cycle.
+ ///
+ /// Each node in this list has an edge to the next node. The final node has an
+ /// edge to the first node.
+ final List<T> cycle;
+
+ CycleException(Iterable<T> cycle) : cycle = List.unmodifiable(cycle);
+
+ @override
+ String toString() => 'A cycle was detected in a graph that must be acyclic:\n'
+ '${cycle.map((node) => '* $node').join('\n')}';
+}
diff --git a/pkgs/graphs/lib/src/shortest_path.dart b/pkgs/graphs/lib/src/shortest_path.dart
new file mode 100644
index 0000000..28f7e51
--- /dev/null
+++ b/pkgs/graphs/lib/src/shortest_path.dart
@@ -0,0 +1,144 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+/// Returns the shortest path from [start] to [target] given the directed
+/// edges of a graph provided by [edges].
+///
+/// If [start] `==` [target], an empty [List] is returned and [edges] is never
+/// called.
+///
+/// If [equals] is provided, it is used to compare nodes in the graph. If
+/// [equals] is omitted, the node's own [Object.==] is used instead.
+///
+/// Similarly, if [hashCode] is provided, it is used to produce a hash value
+/// for nodes to efficiently calculate the return value. If it is omitted, the
+/// key's own [Object.hashCode] is used.
+///
+/// If you supply one of [equals] or [hashCode], you should generally also to
+/// supply the other.
+Iterable<T>? shortestPath<T extends Object>(
+ T start,
+ T target,
+ Iterable<T> Function(T) edges, {
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+}) =>
+ _shortestPaths<T>(
+ start,
+ edges,
+ target: target,
+ equals: equals,
+ hashCode: hashCode,
+ )[target];
+
+/// Returns a [Map] of the shortest paths from [start] to all of the nodes in
+/// the directed graph defined by [edges].
+///
+/// All return values will contain the key [start] with an empty [List] value.
+///
+/// [start] and all values returned by [edges] must not be `null`.
+/// If asserts are enabled, an [AssertionError] is raised if these conditions
+/// are not met. If asserts are not enabled, violations result in undefined
+/// behavior.
+///
+/// If [equals] is provided, it is used to compare nodes in the graph. If
+/// [equals] is omitted, the node's own [Object.==] is used instead.
+///
+/// Similarly, if [hashCode] is provided, it is used to produce a hash value
+/// for nodes to efficiently calculate the return value. If it is omitted, the
+/// key's own [Object.hashCode] is used.
+///
+/// If you supply one of [equals] or [hashCode], you should generally also to
+/// supply the other.
+Map<T, Iterable<T>> shortestPaths<T extends Object>(
+ T start,
+ Iterable<T> Function(T) edges, {
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+}) =>
+ _shortestPaths<T>(
+ start,
+ edges,
+ equals: equals,
+ hashCode: hashCode,
+ );
+
+Map<T, Iterable<T>> _shortestPaths<T extends Object>(
+ T start,
+ Iterable<T> Function(T) edges, {
+ T? target,
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+}) {
+ final distances = HashMap<T, _Tail<T>>(equals: equals, hashCode: hashCode);
+ distances[start] = _Tail<T>();
+
+ final nonNullEquals = equals ??= _defaultEquals;
+ final isTarget =
+ target == null ? _neverTarget : (T node) => nonNullEquals(node, target);
+ if (isTarget(start)) {
+ return distances;
+ }
+
+ final toVisit = ListQueue<T>()..add(start);
+
+ while (toVisit.isNotEmpty) {
+ final current = toVisit.removeFirst();
+ final currentPath = distances[current]!;
+
+ for (var edge in edges(current)) {
+ final existingPath = distances[edge];
+
+ if (existingPath == null) {
+ distances[edge] = currentPath.append(edge);
+ if (isTarget(edge)) {
+ return distances;
+ }
+ toVisit.add(edge);
+ }
+ }
+ }
+
+ return distances;
+}
+
+bool _defaultEquals(Object a, Object b) => a == b;
+bool _neverTarget(Object _) => false;
+
+/// An immutable iterable that can efficiently return a copy with a value
+/// appended.
+///
+/// This implementation has an efficient [length] property.
+///
+/// Note that grabbing an [iterator] for the first time is O(n) in time and
+/// space because it copies all the values to a new list and uses that
+/// iterator in order to avoid stack overflows for large paths. This copy is
+/// cached for subsequent calls.
+class _Tail<T extends Object> extends Iterable<T> {
+ final T? tail;
+ final _Tail<T>? head;
+ @override
+ final int length;
+ _Tail()
+ : tail = null,
+ head = null,
+ length = 0;
+ _Tail._(this.tail, this.head, this.length);
+ _Tail<T> append(T value) => _Tail._(value, this, length + 1);
+
+ @override
+ Iterator<T> get iterator => _asIterable.iterator;
+
+ late final _asIterable = () {
+ _Tail<T>? next = this;
+ final reversed = List.generate(length, (_) {
+ final val = next!.tail;
+ next = next!.head;
+ return val as T;
+ });
+ return reversed.reversed;
+ }();
+}
diff --git a/pkgs/graphs/lib/src/strongly_connected_components.dart b/pkgs/graphs/lib/src/strongly_connected_components.dart
new file mode 100644
index 0000000..e8a775c
--- /dev/null
+++ b/pkgs/graphs/lib/src/strongly_connected_components.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:math' show min;
+
+/// Finds the strongly connected components of a directed graph using Tarjan's
+/// algorithm.
+///
+/// The result will be a valid reverse topological order ordering of the
+/// strongly connected components. Components further from a root will appear in
+/// the result before the components which they are connected to.
+///
+/// Nodes within a strongly connected component have no ordering guarantees,
+/// except that if the first value in [nodes] is a valid root, and is contained
+/// in a cycle, it will be the last element of that cycle.
+///
+/// [nodes] must contain at least a root of every tree in the graph if there are
+/// disjoint subgraphs but it may contain all nodes in the graph if the roots
+/// are not known.
+///
+/// If [equals] is provided, it is used to compare nodes in the graph. If
+/// [equals] is omitted, the node's own [Object.==] is used instead.
+///
+/// Similarly, if [hashCode] is provided, it is used to produce a hash value
+/// for nodes to efficiently calculate the return value. If it is omitted, the
+/// key's own [Object.hashCode] is used.
+///
+/// If you supply one of [equals] or [hashCode], you should generally also to
+/// supply the other.
+List<List<T>> stronglyConnectedComponents<T extends Object>(
+ Iterable<T> nodes,
+ Iterable<T> Function(T) edges, {
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+}) {
+ final result = <List<T>>[];
+ final lowLinks = HashMap<T, int>(equals: equals, hashCode: hashCode);
+ final indexes = HashMap<T, int>(equals: equals, hashCode: hashCode);
+ final onStack = HashSet<T>(equals: equals, hashCode: hashCode);
+
+ final nonNullEquals = equals ?? _defaultEquals;
+
+ var index = 0;
+ final lastVisited = Queue<T>();
+
+ final stack = [for (final node in nodes) _StackState(node)];
+ outer:
+ while (stack.isNotEmpty) {
+ final state = stack.removeLast();
+ final node = state.node;
+ var iterator = state.iterator;
+
+ int lowLink;
+ if (iterator == null) {
+ if (indexes.containsKey(node)) continue;
+ indexes[node] = index;
+ lowLink = lowLinks[node] = index;
+ index++;
+ iterator = edges(node).iterator;
+
+ // Nodes with no edges are always in their own component.
+ if (!iterator.moveNext()) {
+ result.add([node]);
+ continue;
+ }
+
+ lastVisited.addLast(node);
+ onStack.add(node);
+ } else {
+ lowLink = min(lowLinks[node]!, lowLinks[iterator.current]!);
+ }
+
+ do {
+ final next = iterator.current;
+ if (!indexes.containsKey(next)) {
+ stack.add(_StackState(node, iterator));
+ stack.add(_StackState(next));
+ continue outer;
+ } else if (onStack.contains(next)) {
+ lowLink = lowLinks[node] = min(lowLink, indexes[next]!);
+ }
+ } while (iterator.moveNext());
+
+ if (lowLink == indexes[node]) {
+ final component = <T>[];
+ T next;
+ do {
+ next = lastVisited.removeLast();
+ onStack.remove(next);
+ component.add(next);
+ } while (!nonNullEquals(next, node));
+ result.add(component);
+ }
+ }
+
+ return result;
+}
+
+/// The state of a pass on a single node in Tarjan's Algorithm.
+///
+/// This is used to perform the algorithm with an explicit stack rather than
+/// recursively, to avoid stack overflow errors for very large graphs.
+class _StackState<T> {
+ /// The node being inspected.
+ final T node;
+
+ /// The iterator traversing [node]'s edges.
+ ///
+ /// This is null if the node hasn't yet begun being traversed.
+ final Iterator<T>? iterator;
+
+ _StackState(this.node, [this.iterator]);
+}
+
+bool _defaultEquals(Object a, Object b) => a == b;
diff --git a/pkgs/graphs/lib/src/topological_sort.dart b/pkgs/graphs/lib/src/topological_sort.dart
new file mode 100644
index 0000000..948e696
--- /dev/null
+++ b/pkgs/graphs/lib/src/topological_sort.dart
@@ -0,0 +1,146 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'package:collection/collection.dart' hide stronglyConnectedComponents;
+
+import 'cycle_exception.dart';
+
+/// Returns a topological sort of the nodes of the directed edges of a graph
+/// provided by [nodes] and [edges].
+///
+/// Each element of the returned iterable is guaranteed to appear after all
+/// nodes that have edges leading to that node. The result is not guaranteed to
+/// be unique, nor is it guaranteed to be stable across releases of this
+/// package; however, it will be stable for a given input within a given package
+/// version.
+///
+/// If [equals] is provided, it is used to compare nodes in the graph. If
+/// [equals] is omitted, the node's own [Object.==] is used instead.
+///
+/// Similarly, if [hashCode] is provided, it is used to produce a hash value
+/// for nodes to efficiently calculate the return value. If it is omitted, the
+/// key's own [Object.hashCode] is used.
+///
+/// If you supply one of [equals] or [hashCode], you should generally also to
+/// supply the other.
+///
+/// If you supply [secondarySort], the resulting list will be sorted by that
+/// comparison function as much as possible without violating the topological
+/// ordering. Note that even with a secondary sort, the result is _still_ not
+/// guaranteed to be unique or stable across releases of this package.
+///
+/// Note: this requires that [nodes] and each iterable returned by [edges]
+/// contain no duplicate entries.
+///
+/// Throws a [CycleException<T>] if the graph is cyclical.
+List<T> topologicalSort<T>(
+ Iterable<T> nodes,
+ Iterable<T> Function(T) edges, {
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+ Comparator<T>? secondarySort,
+}) {
+ if (secondarySort != null) {
+ return _topologicalSortWithSecondary(
+ [...nodes],
+ edges,
+ secondarySort,
+ equals,
+ hashCode,
+ );
+ }
+
+ // https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search
+ final result = QueueList<T>();
+ final permanentMark = HashSet<T>(equals: equals, hashCode: hashCode);
+ final temporaryMark = LinkedHashSet<T>(equals: equals, hashCode: hashCode);
+ final stack = [...nodes];
+ while (stack.isNotEmpty) {
+ final node = stack.removeLast();
+ if (permanentMark.contains(node)) continue;
+
+ // If we're visiting this node while it's already marked and not through a
+ // dependency, that must mean we've traversed all its dependencies and it's
+ // safe to add it to the result.
+ if (temporaryMark.contains(node)) {
+ temporaryMark.remove(node);
+ permanentMark.add(node);
+ result.addFirst(node);
+ } else {
+ temporaryMark.add(node);
+
+ // Revisit this node once we've visited all its children.
+ stack.add(node);
+ for (var child in edges(node)) {
+ if (temporaryMark.contains(child)) throw CycleException(temporaryMark);
+ stack.add(child);
+ }
+ }
+ }
+
+ return result;
+}
+
+/// An implementation of [topologicalSort] with a secondary comparison function.
+List<T> _topologicalSortWithSecondary<T>(
+ List<T> nodes,
+ Iterable<T> Function(T) edges,
+ Comparator<T> comparator,
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+) {
+ // https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm,
+ // modified to sort the nodes to traverse. Also documented in
+ // https://www.algotree.org/algorithms/tree_graph_traversal/lexical_topological_sort_c++/
+
+ // For each node, the number of incoming edges it has that we haven't yet
+ // traversed.
+ final incomingEdges = HashMap<T, int>(equals: equals, hashCode: hashCode);
+ for (var node in nodes) {
+ for (var child in edges(node)) {
+ incomingEdges[child] = (incomingEdges[child] ?? 0) + 1;
+ }
+ }
+
+ // A priority queue of nodes that have no remaining incoming edges.
+ final nodesToTraverse = PriorityQueue<T>(comparator);
+ for (var node in nodes) {
+ if (!incomingEdges.containsKey(node)) nodesToTraverse.add(node);
+ }
+
+ final result = <T>[];
+ while (nodesToTraverse.isNotEmpty) {
+ final node = nodesToTraverse.removeFirst();
+ result.add(node);
+ for (var child in edges(node)) {
+ var remainingEdges = incomingEdges[child]!;
+ remainingEdges--;
+ incomingEdges[child] = remainingEdges;
+ if (remainingEdges == 0) nodesToTraverse.add(child);
+ }
+ }
+
+ if (result.length < nodes.length) {
+ // This algorithm doesn't automatically produce a cycle list as a side
+ // effect of sorting, so to throw the appropriate [CycleException] we just
+ // call the normal [topologicalSort] with a view of this graph that only
+ // includes nodes that still have edges.
+ bool nodeIsInCycle(T node) {
+ final edges = incomingEdges[node];
+ return edges != null && edges > 0;
+ }
+
+ topologicalSort<T>(
+ nodes.where(nodeIsInCycle),
+ edges,
+ equals: equals,
+ hashCode: hashCode,
+ );
+ assert(false, 'topologicalSort() should throw if the graph has a cycle');
+ }
+
+ return result;
+}
diff --git a/pkgs/graphs/lib/src/transitive_closure.dart b/pkgs/graphs/lib/src/transitive_closure.dart
new file mode 100644
index 0000000..24791d6
--- /dev/null
+++ b/pkgs/graphs/lib/src/transitive_closure.dart
@@ -0,0 +1,143 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'cycle_exception.dart';
+import 'strongly_connected_components.dart';
+import 'topological_sort.dart';
+
+/// Returns a transitive closure of a directed graph provided by [nodes] and
+/// [edges].
+///
+/// The result is a map from [nodes] to the sets of nodes that are transitively
+/// reachable through [edges]. No particular ordering is guaranteed.
+///
+/// If [equals] is provided, it is used to compare nodes in the graph. If
+/// [equals] is omitted, the node's own [Object.==] is used instead.
+///
+/// Similarly, if [hashCode] is provided, it is used to produce a hash value
+/// for nodes to efficiently calculate the return value. If it is omitted, the
+/// key's own [Object.hashCode] is used.
+///
+/// If you supply one of [equals] or [hashCode], you should generally also to
+/// supply the other.
+///
+/// Note: this requires that [nodes] and each iterable returned by [edges]
+/// contain no duplicate entries.
+///
+/// By default, this can handle either cyclic or acyclic graphs. If [acyclic] is
+/// true, this will run more efficiently but throw a [CycleException] if the
+/// graph is cyclical.
+Map<T, Set<T>> transitiveClosure<T extends Object>(
+ Iterable<T> nodes,
+ Iterable<T> Function(T) edges, {
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+ bool acyclic = false,
+}) {
+ if (!acyclic) {
+ return _cyclicTransitiveClosure(
+ nodes,
+ edges,
+ equals: equals,
+ hashCode: hashCode,
+ );
+ }
+
+ final topologicalOrder =
+ topologicalSort(nodes, edges, equals: equals, hashCode: hashCode);
+ final result = LinkedHashMap<T, Set<T>>(equals: equals, hashCode: hashCode);
+ for (final node in topologicalOrder.reversed) {
+ final closure = LinkedHashSet<T>(equals: equals, hashCode: hashCode);
+ for (var child in edges(node)) {
+ closure.add(child);
+ closure.addAll(result[child]!);
+ }
+
+ result[node] = closure;
+ }
+
+ return result;
+}
+
+/// Returns the transitive closure of a cyclic graph using [Purdom's algorithm].
+///
+/// [Purdom's algorithm]: https://algowiki-project.org/en/Purdom%27s_algorithm
+///
+/// This first computes the strongly connected components of the graph and finds
+/// the transitive closure of those before flattening it out into the transitive
+/// closure of the entire graph.
+Map<T, Set<T>> _cyclicTransitiveClosure<T extends Object>(
+ Iterable<T> nodes,
+ Iterable<T> Function(T) edges, {
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+}) {
+ final components = stronglyConnectedComponents<T>(
+ nodes,
+ edges,
+ equals: equals,
+ hashCode: hashCode,
+ );
+ final nodesToComponents =
+ HashMap<T, List<T>>(equals: equals, hashCode: hashCode);
+ for (final component in components) {
+ for (final node in component) {
+ nodesToComponents[node] = component;
+ }
+ }
+
+ // Because [stronglyConnectedComponents] returns the components in reverse
+ // topological order, we can avoid an additional topological sort here.
+ // Instead, we directly traverse the component list with the knowledge that
+ // once we reach a component, everything reachable from it has already been
+ // registered in [result].
+ final result = LinkedHashMap<T, Set<T>>(equals: equals, hashCode: hashCode);
+ for (final component in components) {
+ final closure = LinkedHashSet<T>(equals: equals, hashCode: hashCode);
+ if (_componentIncludesCycle(component, edges, equals)) {
+ closure.addAll(component);
+ }
+
+ // De-duplicate downstream components to avoid adding the same transitive
+ // children over and over.
+ final downstreamComponents = {
+ for (final node in component)
+ for (final child in edges(node)) nodesToComponents[child]!,
+ };
+ for (final childComponent in downstreamComponents) {
+ if (childComponent == component) continue;
+
+ // This if check is just for efficiency. If [childComponent] has multiple
+ // nodes, `result[childComponent.first]` will contain all the nodes in
+ // `childComponent` anyway since it's cyclical.
+ if (childComponent.length == 1) closure.addAll(childComponent);
+ closure.addAll(result[childComponent.first]!);
+ }
+
+ for (final node in component) {
+ result[node] = closure;
+ }
+ }
+ return result;
+}
+
+/// Returns whether the strongly-connected component [component] of a graph
+/// defined by [edges] includes a cycle.
+bool _componentIncludesCycle<T>(
+ List<T> component,
+ Iterable<T> Function(T) edges,
+ bool Function(T, T)? equals,
+) {
+ // A strongly-connected component with more than one node always contains a
+ // cycle, by definition.
+ if (component.length > 1) return true;
+
+ // A component with only a single node only contains a cycle if that node has
+ // an edge to itself.
+ final node = component.single;
+ return edges(node)
+ .any((edge) => equals == null ? edge == node : equals(edge, node));
+}
diff --git a/pkgs/graphs/pubspec.yaml b/pkgs/graphs/pubspec.yaml
new file mode 100644
index 0000000..bdbda2f
--- /dev/null
+++ b/pkgs/graphs/pubspec.yaml
@@ -0,0 +1,20 @@
+name: graphs
+version: 2.3.3-wip
+description: Graph algorithms that operate on graphs in any representation.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/graphs
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Agraphs
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ collection: ^1.15.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.21.6
+
+ # For examples
+ analyzer: '>=5.2.0 <7.0.0'
+ path: ^1.8.0
+ pool: ^1.5.0
diff --git a/pkgs/graphs/test/crawl_async_test.dart b/pkgs/graphs/test/crawl_async_test.dart
new file mode 100644
index 0000000..9e168e6
--- /dev/null
+++ b/pkgs/graphs/test/crawl_async_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:graphs/graphs.dart';
+import 'package:test/test.dart';
+
+import 'utils/graph.dart';
+
+void main() {
+ group('asyncCrawl', () {
+ Future<List<String?>> crawl(
+ Map<String, List<String>?> g,
+ Iterable<String> roots,
+ ) {
+ final graph = AsyncGraph(g);
+ return crawlAsync(roots, graph.readNode, graph.edges).toList();
+ }
+
+ test('empty result for empty graph', () async {
+ final result = await crawl({}, []);
+ expect(result, isEmpty);
+ });
+
+ test('single item for a single node', () async {
+ final result = await crawl({'a': []}, ['a']);
+ expect(result, ['a']);
+ });
+
+ test('hits every node in a graph', () async {
+ final result = await crawl({
+ 'a': ['b', 'c'],
+ 'b': ['c'],
+ 'c': ['d'],
+ 'd': [],
+ }, [
+ 'a',
+ ]);
+ expect(result, hasLength(4));
+ expect(
+ result,
+ allOf(contains('a'), contains('b'), contains('c'), contains('d')),
+ );
+ });
+
+ test('handles cycles', () async {
+ final result = await crawl({
+ 'a': ['b'],
+ 'b': ['c'],
+ 'c': ['b'],
+ }, [
+ 'a',
+ ]);
+ expect(result, hasLength(3));
+ expect(result, allOf(contains('a'), contains('b'), contains('c')));
+ });
+
+ test('handles self cycles', () async {
+ final result = await crawl({
+ 'a': ['b'],
+ 'b': ['b'],
+ }, [
+ 'a',
+ ]);
+ expect(result, hasLength(2));
+ expect(result, allOf(contains('a'), contains('b')));
+ });
+
+ test('allows null edges', () async {
+ final result = await crawl({
+ 'a': ['b'],
+ 'b': null,
+ }, [
+ 'a',
+ ]);
+ expect(result, hasLength(2));
+ expect(result, allOf(contains('a'), contains('b')));
+ });
+
+ test('allows null nodes', () async {
+ final result = await crawl({
+ 'a': ['b'],
+ }, [
+ 'a',
+ ]);
+ expect(result, ['a', null]);
+ });
+
+ test('surfaces exceptions for crawling edges', () {
+ final graph = {
+ 'a': ['b'],
+ };
+ final nodes = crawlAsync(
+ ['a'],
+ (n) => n,
+ (k, n) => k == 'b' ? throw ArgumentError() : graph[k] ?? <String>[],
+ );
+ expect(nodes, emitsThrough(emitsError(isArgumentError)));
+ });
+
+ test('surfaces exceptions for resolving keys', () {
+ final graph = {
+ 'a': ['b'],
+ };
+ final nodes = crawlAsync(
+ ['a'],
+ (n) => n == 'b' ? throw ArgumentError() : n,
+ (k, n) => graph[k] ?? <Never>[],
+ );
+ expect(nodes, emitsThrough(emitsError(isArgumentError)));
+ });
+ });
+}
diff --git a/pkgs/graphs/test/shortest_path_test.dart b/pkgs/graphs/test/shortest_path_test.dart
new file mode 100644
index 0000000..88281d4
--- /dev/null
+++ b/pkgs/graphs/test/shortest_path_test.dart
@@ -0,0 +1,161 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:math' show Random;
+
+import 'package:graphs/graphs.dart';
+import 'package:test/test.dart';
+
+import 'utils/utils.dart';
+
+void main() {
+ const graph = <String, List<String>>{
+ '1': ['2', '5'],
+ '2': ['3'],
+ '3': ['4', '5'],
+ '4': ['1'],
+ '5': ['8'],
+ '6': ['7'],
+ };
+
+ List<String> readEdges(String key) => graph[key] ?? [];
+
+ List<X> getXValues(X key) => graph[key.value]?.map(X.new).toList() ?? [];
+
+ void singlePathTest(String from, String to, List<String>? expected) {
+ test('$from -> $to should be $expected (mapped)', () {
+ expect(
+ shortestPath<X>(
+ X(from),
+ X(to),
+ getXValues,
+ equals: xEquals,
+ hashCode: xHashCode,
+ )?.map((x) => x.value),
+ expected,
+ );
+ });
+
+ test('$from -> $to should be $expected', () {
+ expect(shortestPath(from, to, readEdges), expected);
+ });
+ }
+
+ void pathsTest(
+ String from,
+ Map<String, List<String>> expected,
+ List<String> nullPaths,
+ ) {
+ test('paths from $from (mapped)', () {
+ final result = shortestPaths<X>(
+ X(from),
+ getXValues,
+ equals: xEquals,
+ hashCode: xHashCode,
+ ).map((k, v) => MapEntry(k.value, v.map((x) => x.value).toList()));
+ expect(result, expected);
+ });
+
+ test('paths from $from', () {
+ final result = shortestPaths(from, readEdges);
+ expect(result, expected);
+ });
+
+ for (var entry in expected.entries) {
+ singlePathTest(from, entry.key, entry.value);
+ }
+
+ for (var entry in nullPaths) {
+ singlePathTest(from, entry, null);
+ }
+ }
+
+ pathsTest('1', {
+ '5': ['5'],
+ '3': ['2', '3'],
+ '8': ['5', '8'],
+ '1': [],
+ '2': ['2'],
+ '4': ['2', '3', '4'],
+ }, [
+ '6',
+ '7',
+ ]);
+
+ pathsTest('6', {
+ '7': ['7'],
+ '6': [],
+ }, [
+ '1',
+ ]);
+ pathsTest('7', {'7': []}, ['1', '6']);
+
+ pathsTest('42', {'42': []}, ['1', '6']);
+
+ test('integration test', () {
+ // Be deterministic in the generated graph. This test may have to be updated
+ // if the behavior of `Random` changes for the provided seed.
+ final rnd = Random(1);
+ const size = 1000;
+ final graph = HashMap<int, List<int>>();
+
+ Iterable<int>? resultForGraph() =>
+ shortestPath(0, size - 1, (e) => graph[e] ?? const []);
+
+ void addRandomEdge() {
+ final toList = graph.putIfAbsent(rnd.nextInt(size), () => <int>[]);
+
+ final toValue = rnd.nextInt(size);
+ if (!toList.contains(toValue)) {
+ toList.add(toValue);
+ }
+ }
+
+ Iterable<int>? result;
+
+ // Add edges until there is a shortest path between `0` and `size - 1`
+ do {
+ addRandomEdge();
+ result = resultForGraph();
+ } while (result == null);
+
+ expect(result, [313, 547, 91, 481, 74, 64, 439, 388, 660, 275, 999]);
+
+ var count = 0;
+ // Add edges until the shortest path between `0` and `size - 1` is 2 items
+ // Adding edges should never increase the length of the shortest path.
+ // Adding enough edges should reduce the length of the shortest path.
+ do {
+ expect(++count, lessThan(size * 5), reason: 'This loop should finish.');
+ addRandomEdge();
+ final previousResultLength = result!.length;
+ result = resultForGraph();
+ expect(result, hasLength(lessThanOrEqualTo(previousResultLength)));
+ } while (result!.length > 2);
+
+ expect(result, [275, 999]);
+
+ count = 0;
+ // Remove edges until there is no shortest path.
+ // Removing edges should never reduce the length of the shortest path.
+ // Removing enough edges should increase the length of the shortest path and
+ // eventually eliminate any path.
+ do {
+ expect(++count, lessThan(size * 5), reason: 'This loop should finish.');
+ final randomKey = graph.keys.elementAt(rnd.nextInt(graph.length));
+ final list = graph[randomKey]!;
+ expect(list, isNotEmpty);
+ list.removeAt(rnd.nextInt(list.length));
+ if (list.isEmpty) {
+ graph.remove(randomKey);
+ }
+ final previousResultLength = result!.length;
+ result = resultForGraph();
+ if (result != null) {
+ expect(result, hasLength(greaterThanOrEqualTo(previousResultLength)));
+ }
+ } while (result != null);
+ });
+}
diff --git a/pkgs/graphs/test/strongly_connected_components_test.dart b/pkgs/graphs/test/strongly_connected_components_test.dart
new file mode 100644
index 0000000..2fa4d88
--- /dev/null
+++ b/pkgs/graphs/test/strongly_connected_components_test.dart
@@ -0,0 +1,304 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:graphs/graphs.dart';
+import 'package:test/test.dart';
+
+import 'utils/graph.dart';
+import 'utils/utils.dart';
+
+void main() {
+ group('strongly connected components', () {
+ /// Run [stronglyConnectedComponents] on [g].
+ List<List<String>> components(
+ Map<String, List<String>?> g, {
+ Iterable<String>? startNodes,
+ }) {
+ final graph = Graph(g);
+ return stronglyConnectedComponents(
+ startNodes ?? graph.allNodes,
+ graph.edges,
+ );
+ }
+
+ test('empty result for empty graph', () {
+ final result = components({});
+ expect(result, isEmpty);
+ });
+
+ test('single item for single node', () {
+ final result = components({'a': []});
+ expect(result, [
+ ['a'],
+ ]);
+ });
+
+ test('handles non-cycles', () {
+ final result = components({
+ 'a': ['b'],
+ 'b': ['c'],
+ 'c': [],
+ });
+ expect(result, [
+ ['c'],
+ ['b'],
+ ['a'],
+ ]);
+ });
+
+ test('handles entire graph as cycle', () {
+ final result = components({
+ 'a': ['b'],
+ 'b': ['c'],
+ 'c': ['d'],
+ 'd': ['a'],
+ });
+ expect(
+ result,
+ [allOf(contains('a'), contains('b'), contains('c'), contains('d'))],
+ );
+ });
+
+ test('includes the first passed root last in a cycle', () {
+ // In cases where this is used to find a topological ordering the first
+ // value in nodes should always come last.
+ final graph = {
+ 'a': ['b'],
+ 'b': ['a'],
+ };
+ final resultFromA = components(graph, startNodes: ['a']);
+ final resultFromB = components(graph, startNodes: ['b']);
+ expect(resultFromA.single.last, 'a');
+ expect(resultFromB.single.last, 'b');
+ });
+
+ test('handles cycles in the middle', () {
+ final result = components({
+ 'a': ['b', 'c'],
+ 'b': ['c', 'd'],
+ 'c': ['b', 'd'],
+ 'd': [],
+ });
+ expect(result, [
+ ['d'],
+ allOf(contains('b'), contains('c')),
+ ['a'],
+ ]);
+ });
+
+ test('handles self cycles', () {
+ final result = components({
+ 'a': ['b'],
+ 'b': ['b'],
+ });
+ expect(result, [
+ ['b'],
+ ['a'],
+ ]);
+ });
+
+ test('valid topological ordering for disjoint subgraphs', () {
+ final result = components({
+ 'a': ['b', 'c'],
+ 'b': ['b1', 'b2'],
+ 'c': ['c1', 'c2'],
+ 'b1': [],
+ 'b2': [],
+ 'c1': [],
+ 'c2': [],
+ });
+
+ expect(
+ result,
+ containsAllInOrder([
+ ['c1'],
+ ['c'],
+ ['a'],
+ ]),
+ );
+ expect(
+ result,
+ containsAllInOrder([
+ ['c2'],
+ ['c'],
+ ['a'],
+ ]),
+ );
+ expect(
+ result,
+ containsAllInOrder([
+ ['b1'],
+ ['b'],
+ ['a'],
+ ]),
+ );
+ expect(
+ result,
+ containsAllInOrder([
+ ['b2'],
+ ['b'],
+ ['a'],
+ ]),
+ );
+ });
+
+ test('handles getting null for edges', () {
+ final result = components({
+ 'a': ['b'],
+ 'b': null,
+ });
+ expect(result, [
+ ['b'],
+ ['a'],
+ ]);
+ });
+ });
+
+ group('custom hashCode and equals', () {
+ /// Run [stronglyConnectedComponents] on [g].
+ List<List<String>> components(
+ Map<String, List<String>?> g, {
+ Iterable<String>? startNodes,
+ }) {
+ final graph = BadGraph(g);
+
+ startNodes ??= graph.allNodes.map((n) => n.value);
+
+ return stronglyConnectedComponents<X>(
+ startNodes.map(X.new),
+ graph.edges,
+ equals: xEquals,
+ hashCode: xHashCode,
+ ).map((list) => list.map((x) => x.value).toList()).toList();
+ }
+
+ test('empty result for empty graph', () {
+ final result = components({});
+ expect(result, isEmpty);
+ });
+
+ test('single item for single node', () {
+ final result = components({'a': []});
+ expect(result, [
+ ['a'],
+ ]);
+ });
+
+ test('handles non-cycles', () {
+ final result = components({
+ 'a': ['b'],
+ 'b': ['c'],
+ 'c': [],
+ });
+ expect(result, [
+ ['c'],
+ ['b'],
+ ['a'],
+ ]);
+ });
+
+ test('handles entire graph as cycle', () {
+ final result = components({
+ 'a': ['b'],
+ 'b': ['c'],
+ 'c': ['a'],
+ });
+ expect(result, [allOf(contains('a'), contains('b'), contains('c'))]);
+ });
+
+ test('includes the first passed root last in a cycle', () {
+ // In cases where this is used to find a topological ordering the first
+ // value in nodes should always come last.
+ final graph = {
+ 'a': ['b'],
+ 'b': ['a'],
+ };
+ final resultFromA = components(graph, startNodes: ['a']);
+ final resultFromB = components(graph, startNodes: ['b']);
+ expect(resultFromA.single.last, 'a');
+ expect(resultFromB.single.last, 'b');
+ });
+
+ test('handles cycles in the middle', () {
+ final result = components({
+ 'a': ['b', 'c'],
+ 'b': ['c', 'd'],
+ 'c': ['b', 'd'],
+ 'd': [],
+ });
+ expect(result, [
+ ['d'],
+ allOf(contains('b'), contains('c')),
+ ['a'],
+ ]);
+ });
+
+ test('handles self cycles', () {
+ final result = components({
+ 'a': ['b'],
+ 'b': ['b'],
+ });
+ expect(result, [
+ ['b'],
+ ['a'],
+ ]);
+ });
+
+ test('valid topological ordering for disjoint subgraphs', () {
+ final result = components({
+ 'a': ['b', 'c'],
+ 'b': ['b1', 'b2'],
+ 'c': ['c1', 'c2'],
+ 'b1': [],
+ 'b2': [],
+ 'c1': [],
+ 'c2': [],
+ });
+
+ expect(
+ result,
+ containsAllInOrder([
+ ['c1'],
+ ['c'],
+ ['a'],
+ ]),
+ );
+ expect(
+ result,
+ containsAllInOrder([
+ ['c2'],
+ ['c'],
+ ['a'],
+ ]),
+ );
+ expect(
+ result,
+ containsAllInOrder([
+ ['b1'],
+ ['b'],
+ ['a'],
+ ]),
+ );
+ expect(
+ result,
+ containsAllInOrder([
+ ['b2'],
+ ['b'],
+ ['a'],
+ ]),
+ );
+ });
+
+ test('handles getting null for edges', () {
+ final result = components({
+ 'a': ['b'],
+ 'b': null,
+ });
+ expect(result, [
+ ['b'],
+ ['a'],
+ ]);
+ });
+ });
+}
diff --git a/pkgs/graphs/test/topological_sort_test.dart b/pkgs/graphs/test/topological_sort_test.dart
new file mode 100644
index 0000000..831946b
--- /dev/null
+++ b/pkgs/graphs/test/topological_sort_test.dart
@@ -0,0 +1,362 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'package:graphs/graphs.dart';
+import 'package:test/test.dart';
+
+import 'utils/utils.dart';
+
+void main() {
+ group('without secondarySort', () {
+ group('topologically sorts a graph', () {
+ test('with no nodes', () {
+ expect(_topologicalSort({}), isEmpty);
+ });
+
+ test('with only one node', () {
+ expect(_topologicalSort({1: []}), equals([1]));
+ });
+
+ test('with no edges', () {
+ expect(
+ _topologicalSort({1: [], 2: [], 3: [], 4: []}),
+ unorderedEquals([1, 2, 3, 4]),
+ );
+ });
+
+ test('with single edges', () {
+ expect(
+ _topologicalSort({
+ 1: [2],
+ 2: [3],
+ 3: [4],
+ 4: [],
+ }),
+ equals([1, 2, 3, 4]),
+ );
+ });
+
+ test('with many edges from one node', () {
+ final result = _topologicalSort({
+ 1: [2, 3, 4],
+ 2: [],
+ 3: [],
+ 4: [],
+ });
+ expect(result.indexOf(1), lessThan(result.indexOf(2)));
+ expect(result.indexOf(1), lessThan(result.indexOf(3)));
+ expect(result.indexOf(1), lessThan(result.indexOf(4)));
+ });
+
+ test('with transitive edges', () {
+ final result = _topologicalSort({
+ 1: [2, 4],
+ 2: [],
+ 3: [],
+ 4: [3],
+ });
+ expect(result.indexOf(1), lessThan(result.indexOf(2)));
+ expect(result.indexOf(1), lessThan(result.indexOf(3)));
+ expect(result.indexOf(1), lessThan(result.indexOf(4)));
+ expect(result.indexOf(4), lessThan(result.indexOf(3)));
+ });
+
+ test('with diamond edges', () {
+ final result = _topologicalSort({
+ 1: [2, 3],
+ 2: [4],
+ 3: [4],
+ 4: [],
+ });
+ expect(result.indexOf(1), lessThan(result.indexOf(2)));
+ expect(result.indexOf(1), lessThan(result.indexOf(3)));
+ expect(result.indexOf(1), lessThan(result.indexOf(4)));
+ expect(result.indexOf(2), lessThan(result.indexOf(4)));
+ expect(result.indexOf(3), lessThan(result.indexOf(4)));
+ });
+ });
+
+ test('respects custom equality and hash functions', () {
+ expect(
+ _topologicalSort<int>(
+ {
+ 0: [2],
+ 3: [4],
+ 5: [6],
+ 7: [],
+ },
+ equals: (i, j) => (i ~/ 2) == (j ~/ 2),
+ hashCode: (i) => (i ~/ 2).hashCode,
+ ),
+ equals([
+ 0,
+ anyOf([2, 3]),
+ anyOf([4, 5]),
+ anyOf([6, 7]),
+ ]),
+ );
+ });
+
+ group('throws a CycleException for a graph with', () {
+ test('a one-node cycle', () {
+ expect(
+ () => _topologicalSort({
+ 1: [1],
+ }),
+ throwsCycleException([1]),
+ );
+ });
+
+ test('a multi-node cycle', () {
+ expect(
+ () => _topologicalSort({
+ 1: [2],
+ 2: [3],
+ 3: [4],
+ 4: [1],
+ }),
+ throwsCycleException([4, 1, 2, 3]),
+ );
+ });
+ });
+ });
+
+ group('with secondarySort', () {
+ group('topologically sorts a graph', () {
+ test('with no nodes', () {
+ expect(_topologicalSort({}, secondarySort: true), isEmpty);
+ });
+
+ test('with only one node', () {
+ expect(_topologicalSort({1: []}, secondarySort: true), equals([1]));
+ });
+
+ test('with no edges', () {
+ expect(
+ _topologicalSort({1: [], 2: [], 3: [], 4: []}, secondarySort: true),
+ unorderedEquals([1, 2, 3, 4]),
+ );
+ });
+
+ test('with single edges', () {
+ expect(
+ _topologicalSort(
+ {
+ 1: [2],
+ 2: [3],
+ 3: [4],
+ 4: [],
+ },
+ secondarySort: true,
+ ),
+ equals([1, 2, 3, 4]),
+ );
+ });
+
+ test('with many edges from one node', () {
+ final result = _topologicalSort(
+ {
+ 1: [2, 3, 4],
+ 2: [],
+ 3: [],
+ 4: [],
+ },
+ secondarySort: true,
+ );
+ expect(result.indexOf(1), lessThan(result.indexOf(2)));
+ expect(result.indexOf(1), lessThan(result.indexOf(3)));
+ expect(result.indexOf(1), lessThan(result.indexOf(4)));
+ });
+
+ test('with transitive edges', () {
+ final result = _topologicalSort(
+ {
+ 1: [2, 4],
+ 2: [],
+ 3: [],
+ 4: [3],
+ },
+ secondarySort: true,
+ );
+ expect(result.indexOf(1), lessThan(result.indexOf(2)));
+ expect(result.indexOf(1), lessThan(result.indexOf(3)));
+ expect(result.indexOf(1), lessThan(result.indexOf(4)));
+ expect(result.indexOf(4), lessThan(result.indexOf(3)));
+ });
+
+ test('with diamond edges', () {
+ final result = _topologicalSort(
+ {
+ 1: [2, 3],
+ 2: [4],
+ 3: [4],
+ 4: [],
+ },
+ secondarySort: true,
+ );
+ expect(result.indexOf(1), lessThan(result.indexOf(2)));
+ expect(result.indexOf(1), lessThan(result.indexOf(3)));
+ expect(result.indexOf(1), lessThan(result.indexOf(4)));
+ expect(result.indexOf(2), lessThan(result.indexOf(4)));
+ expect(result.indexOf(3), lessThan(result.indexOf(4)));
+ });
+ });
+
+ group('lexically sorts a graph where possible', () {
+ test('with no edges', () {
+ final result =
+ _topologicalSort({4: [], 3: [], 1: [], 2: []}, secondarySort: true);
+ expect(result, equals([1, 2, 3, 4]));
+ });
+
+ test('with one non-lexical edge', () {
+ final result = _topologicalSort(
+ {
+ 4: [],
+ 3: [1],
+ 1: [],
+ 2: [],
+ },
+ secondarySort: true,
+ );
+ expect(
+ result,
+ equals(
+ anyOf([
+ [2, 3, 1, 4],
+ [3, 1, 2, 4],
+ ]),
+ ),
+ );
+ });
+
+ test('with a non-lexical topolgical order', () {
+ final result = _topologicalSort(
+ {
+ 4: [3],
+ 3: [2],
+ 2: [1],
+ 1: [],
+ },
+ secondarySort: true,
+ );
+ expect(result, equals([4, 3, 2, 1]));
+ });
+
+ group('with multiple layers', () {
+ test('in lexical order', () {
+ final result = _topologicalSort(
+ {
+ 1: [2],
+ 2: [3],
+ 3: [],
+ 4: [5],
+ 5: [6],
+ 6: [],
+ },
+ secondarySort: true,
+ );
+ expect(result, equals([1, 2, 3, 4, 5, 6]));
+ });
+
+ test('in non-lexical order', () {
+ final result = _topologicalSort(
+ {
+ 1: [3],
+ 3: [5],
+ 4: [2],
+ 2: [6],
+ 5: [],
+ 6: [],
+ },
+ secondarySort: true,
+ );
+ expect(
+ result,
+ anyOf([
+ equals([1, 3, 4, 2, 5, 6]),
+ equals([1, 4, 2, 3, 5, 6]),
+ ]),
+ );
+ });
+ });
+ });
+
+ test('respects custom equality and hash functions', () {
+ expect(
+ _topologicalSort<int>(
+ {
+ 0: [2],
+ 3: [4],
+ 5: [6],
+ 7: [],
+ },
+ equals: (i, j) => (i ~/ 2) == (j ~/ 2),
+ hashCode: (i) => (i ~/ 2).hashCode,
+ secondarySort: true,
+ ),
+ equals([
+ 0,
+ anyOf([2, 3]),
+ anyOf([4, 5]),
+ anyOf([6, 7]),
+ ]),
+ );
+ });
+
+ group('throws a CycleException for a graph with', () {
+ test('a one-node cycle', () {
+ expect(
+ () => _topologicalSort(
+ {
+ 1: [1],
+ },
+ secondarySort: true,
+ ),
+ throwsCycleException([1]),
+ );
+ });
+
+ test('a multi-node cycle', () {
+ expect(
+ () => _topologicalSort(
+ {
+ 1: [2],
+ 2: [3],
+ 3: [4],
+ 4: [1],
+ },
+ secondarySort: true,
+ ),
+ throwsCycleException([4, 1, 2, 3]),
+ );
+ });
+ });
+ });
+}
+
+/// Runs a topological sort on a graph represented a map from keys to edges.
+List<T> _topologicalSort<T>(
+ Map<T, List<T>> graph, {
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+ bool secondarySort = false,
+}) {
+ if (equals != null) {
+ graph = LinkedHashMap(equals: equals, hashCode: hashCode)..addAll(graph);
+ }
+ return topologicalSort(
+ graph.keys,
+ (node) {
+ expect(graph, contains(node));
+ return graph[node]!;
+ },
+ equals: equals,
+ hashCode: hashCode,
+ secondarySort:
+ secondarySort ? (a, b) => (a as Comparable<T>).compareTo(b) : null,
+ );
+}
diff --git a/pkgs/graphs/test/transitive_closure_test.dart b/pkgs/graphs/test/transitive_closure_test.dart
new file mode 100644
index 0000000..f732573
--- /dev/null
+++ b/pkgs/graphs/test/transitive_closure_test.dart
@@ -0,0 +1,350 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'package:graphs/graphs.dart';
+import 'package:test/test.dart';
+
+import 'utils/utils.dart';
+
+void main() {
+ group('for an acyclic graph', () {
+ for (final acyclic in [true, false]) {
+ group('with acyclic: $acyclic', () {
+ group('returns the transitive closure for a graph', () {
+ test('with no nodes', () {
+ expect(_transitiveClosure<int>({}, acyclic: acyclic), isEmpty);
+ });
+
+ test('with only one node', () {
+ expect(
+ _transitiveClosure<int>({1: []}, acyclic: acyclic),
+ equals({1: <int>{}}),
+ );
+ });
+
+ test('with no edges', () {
+ expect(
+ _transitiveClosure<int>(
+ {1: [], 2: [], 3: [], 4: []},
+ acyclic: acyclic,
+ ),
+ equals(<int, Set<int>>{1: {}, 2: {}, 3: {}, 4: {}}),
+ );
+ });
+
+ test('with single edges', () {
+ expect(
+ _transitiveClosure<int>(
+ {
+ 1: [2],
+ 2: [3],
+ 3: [4],
+ 4: [],
+ },
+ acyclic: acyclic,
+ ),
+ equals({
+ 1: {2, 3, 4},
+ 2: {3, 4},
+ 3: {4},
+ 4: <int>{},
+ }),
+ );
+ });
+
+ test('with many edges from one node', () {
+ expect(
+ _transitiveClosure<int>(
+ {
+ 1: [2, 3, 4],
+ 2: [],
+ 3: [],
+ 4: [],
+ },
+ acyclic: acyclic,
+ ),
+ equals(<int, Set<int>>{
+ 1: {2, 3, 4},
+ 2: {},
+ 3: {},
+ 4: {},
+ }),
+ );
+ });
+
+ test('with transitive edges', () {
+ expect(
+ _transitiveClosure<int>(
+ {
+ 1: [2, 4],
+ 2: [],
+ 3: [],
+ 4: [3],
+ },
+ acyclic: acyclic,
+ ),
+ equals(<int, Set<int>>{
+ 1: {2, 3, 4},
+ 2: {},
+ 3: {},
+ 4: {3},
+ }),
+ );
+ });
+
+ test('with diamond edges', () {
+ expect(
+ _transitiveClosure<int>(
+ {
+ 1: [2, 3],
+ 2: [4],
+ 3: [4],
+ 4: [],
+ },
+ acyclic: acyclic,
+ ),
+ equals(<int, Set<int>>{
+ 1: {2, 3, 4},
+ 2: {4},
+ 3: {4},
+ 4: {},
+ }),
+ );
+ });
+
+ test('with disjoint subgraphs', () {
+ expect(
+ _transitiveClosure<int>(
+ {
+ 1: [2],
+ 2: [3],
+ 3: [],
+ 4: [5],
+ 5: [6],
+ 6: [],
+ },
+ acyclic: acyclic,
+ ),
+ equals(<int, Set<int>>{
+ 1: {2, 3},
+ 2: {3},
+ 3: {},
+ 4: {5, 6},
+ 5: {6},
+ 6: {},
+ }),
+ );
+ });
+ });
+
+ test('respects custom equality and hash functions', () {
+ final result = _transitiveClosure<int>(
+ {
+ 0: [2],
+ 3: [4],
+ 5: [6],
+ 7: [],
+ },
+ equals: (i, j) => (i ~/ 2) == (j ~/ 2),
+ hashCode: (i) => (i ~/ 2).hashCode,
+ );
+
+ expect(
+ result.keys,
+ unorderedMatches([
+ 0,
+ anyOf([2, 3]),
+ anyOf([4, 5]),
+ anyOf([6, 7]),
+ ]),
+ );
+ expect(
+ result[0],
+ equals({
+ anyOf([2, 3]),
+ anyOf([4, 5]),
+ anyOf([6, 7]),
+ }),
+ );
+ expect(
+ result[2],
+ equals({
+ anyOf([4, 5]),
+ anyOf([6, 7]),
+ }),
+ );
+ expect(
+ result[4],
+ equals({
+ anyOf([6, 7]),
+ }),
+ );
+ expect(result[6], isEmpty);
+ });
+ });
+ }
+ });
+
+ group('for a cyclic graph', () {
+ group('with acyclic: true throws a CycleException for a graph with', () {
+ test('a one-node cycle', () {
+ expect(
+ () => _transitiveClosure<int>(
+ {
+ 1: [1],
+ },
+ acyclic: true,
+ ),
+ throwsCycleException([1]),
+ );
+ });
+
+ test('a multi-node cycle', () {
+ expect(
+ () => _transitiveClosure<int>(
+ {
+ 1: [2],
+ 2: [3],
+ 3: [4],
+ 4: [1],
+ },
+ acyclic: true,
+ ),
+ throwsCycleException([4, 1, 2, 3]),
+ );
+ });
+ });
+
+ group('returns the transitive closure for a graph', () {
+ test('with a single one-node component', () {
+ expect(
+ _transitiveClosure<int>({
+ 1: [1],
+ }),
+ equals({
+ 1: {1},
+ }),
+ );
+ });
+
+ test('with a single multi-node component', () {
+ expect(
+ _transitiveClosure<int>({
+ 1: [2],
+ 2: [3],
+ 3: [4],
+ 4: [1],
+ }),
+ equals({
+ 1: {1, 2, 3, 4},
+ 2: {1, 2, 3, 4},
+ 3: {1, 2, 3, 4},
+ 4: {1, 2, 3, 4},
+ }),
+ );
+ });
+
+ test('with a series of multi-node components', () {
+ expect(
+ _transitiveClosure<int>({
+ 1: [2],
+ 2: [1, 3],
+ 3: [4],
+ 4: [3, 5],
+ 5: [6],
+ 6: [5, 7],
+ 7: [8],
+ 8: [7],
+ }),
+ equals({
+ 1: {1, 2, 3, 4, 5, 6, 7, 8},
+ 2: {1, 2, 3, 4, 5, 6, 7, 8},
+ 3: {3, 4, 5, 6, 7, 8},
+ 4: {3, 4, 5, 6, 7, 8},
+ 5: {5, 6, 7, 8},
+ 6: {5, 6, 7, 8},
+ 7: {7, 8},
+ 8: {7, 8},
+ }),
+ );
+ });
+
+ test('with a diamond of multi-node components', () {
+ expect(
+ _transitiveClosure<int>({
+ 1: [2],
+ 2: [1, 3, 5],
+ 3: [4],
+ 4: [3, 7],
+ 5: [6],
+ 6: [5, 7],
+ 7: [8],
+ 8: [7],
+ }),
+ equals({
+ 1: {1, 2, 3, 4, 5, 6, 7, 8},
+ 2: {1, 2, 3, 4, 5, 6, 7, 8},
+ 3: {3, 4, 7, 8},
+ 4: {3, 4, 7, 8},
+ 5: {5, 6, 7, 8},
+ 6: {5, 6, 7, 8},
+ 7: {7, 8},
+ 8: {7, 8},
+ }),
+ );
+ });
+
+ test('mixed single- and multi-node components', () {
+ expect(
+ _transitiveClosure<int>({
+ 1: [2],
+ 2: [1, 3],
+ 3: [4],
+ 4: [5],
+ 5: [4, 6],
+ 6: [7],
+ 7: [8],
+ 8: [7],
+ }),
+ equals({
+ 1: {1, 2, 3, 4, 5, 6, 7, 8},
+ 2: {1, 2, 3, 4, 5, 6, 7, 8},
+ 3: {4, 5, 6, 7, 8},
+ 4: {4, 5, 6, 7, 8},
+ 5: {4, 5, 6, 7, 8},
+ 6: {7, 8},
+ 7: {7, 8},
+ 8: {7, 8},
+ }),
+ );
+ });
+ });
+ });
+}
+
+/// Returns the transitive closure of a graph represented a map from keys to
+/// edges.
+Map<T, Set<T>> _transitiveClosure<T extends Object>(
+ Map<T, List<T>> graph, {
+ bool Function(T, T)? equals,
+ int Function(T)? hashCode,
+ bool acyclic = false,
+}) {
+ assert((equals == null) == (hashCode == null));
+ if (equals != null) {
+ graph = LinkedHashMap(equals: equals, hashCode: hashCode)..addAll(graph);
+ }
+ return transitiveClosure(
+ graph.keys,
+ (node) {
+ expect(graph, contains(node));
+ return graph[node]!;
+ },
+ equals: equals,
+ hashCode: hashCode,
+ acyclic: acyclic,
+ );
+}
diff --git a/pkgs/graphs/test/utils/graph.dart b/pkgs/graphs/test/utils/graph.dart
new file mode 100644
index 0000000..ffa24b5
--- /dev/null
+++ b/pkgs/graphs/test/utils/graph.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'utils.dart';
+
+/// A representation of a Graph since none is specified in `lib/`.
+class Graph {
+ final Map<String, List<String>?> _graph;
+
+ Graph(this._graph);
+
+ List<String> edges(String node) => _graph[node] ?? <Never>[];
+
+ Iterable<String> get allNodes => _graph.keys;
+}
+
+class BadGraph {
+ final Map<X, List<X>?> _graph;
+
+ BadGraph(Map<String, List<String>?> values)
+ : _graph = LinkedHashMap(equals: xEquals, hashCode: xHashCode)
+ ..addEntries(
+ values.entries
+ .map((e) => MapEntry(X(e.key), e.value?.map(X.new).toList())),
+ );
+
+ List<X> edges(X node) => _graph[node] ?? <Never>[];
+
+ Iterable<X> get allNodes => _graph.keys;
+}
+
+/// A representation of a Graph where keys can asynchronously be resolved to
+/// real values or to edges.
+class AsyncGraph {
+ final Map<String, List<String>?> graph;
+
+ AsyncGraph(this.graph);
+
+ Future<String?> readNode(String node) async =>
+ graph.containsKey(node) ? node : null;
+
+ Future<Iterable<String>> edges(String key, String? node) async =>
+ graph[key] ?? <Never>[];
+}
diff --git a/pkgs/graphs/test/utils/utils.dart b/pkgs/graphs/test/utils/utils.dart
new file mode 100644
index 0000000..45a42c6
--- /dev/null
+++ b/pkgs/graphs/test/utils/utils.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:graphs/graphs.dart';
+import 'package:test/test.dart';
+
+bool xEquals(X a, X b) => a.value == b.value;
+
+int xHashCode(X a) => a.value.hashCode;
+
+/// Returns a matcher that verifies that a function throws a [CycleException<T>]
+/// with the given [cycle].
+Matcher throwsCycleException<T>(List<T> cycle) => throwsA(
+ allOf([
+ isA<CycleException<T>>(),
+ predicate((exception) {
+ expect((exception as CycleException<T>).cycle, equals(cycle));
+ return true;
+ }),
+ ]),
+ );
+
+class X {
+ final String value;
+
+ X(this.value);
+
+ @override
+ bool operator ==(Object other) => throw UnimplementedError();
+
+ @override
+ int get hashCode => 42;
+
+ @override
+ String toString() => '($value)';
+}
diff --git a/pkgs/html/.gitignore b/pkgs/html/.gitignore
new file mode 100644
index 0000000..3ab3a44
--- /dev/null
+++ b/pkgs/html/.gitignore
@@ -0,0 +1,19 @@
+# Don’t commit the following directories created by pub.
+.pub
+.dart_tool/
+build/
+packages
+.packages
+
+# Or the files created by dart2js.
+*.dart.js
+*.dart.precompiled.js
+*.js_
+*.js.deps
+*.js.map
+*.sw?
+.idea/
+.pub/
+
+# Include when developing application packages.
+pubspec.lock
diff --git a/pkgs/html/CHANGELOG.md b/pkgs/html/CHANGELOG.md
new file mode 100644
index 0000000..9a881e9
--- /dev/null
+++ b/pkgs/html/CHANGELOG.md
@@ -0,0 +1,149 @@
+## 0.15.5
+
+- Require Dart `3.2`.
+- Move to `dart-lang/tools` monorepo.
+
+## 0.15.4
+
+- Widen the dependency on `package:csslib`.
+- Require Dart `2.19`.
+
+## 0.15.3
+
+- Added package topics to the pubspec file.
+
+## 0.15.2
+
+- Add additional types at the API boundary (in `lib/parser.dart` and others).
+- Adopted the `package:dart_flutter_team_lints` linting rules.
+- Fixed an issue with `querySelector` where it would fail in some cases with
+ descendant or sibling combinators (#157).
+- Add an API example in `example/`.
+
+## 0.15.1
+
+- Move `htmlSerializeEscape` to its own library,
+ `package:html/html_escape.dart`, which is exported from
+ `package:html/dom_parsing.dart`.
+- Use more non-growable lists, and type annotations on List literals.
+- Switch analysis option `implicit-casts: false` to `strict-casts: true`.
+
+## 0.15.0
+
+- Migrate to null safety.
+- Drop `lastPhase`, `beforeRcDataPhase`, and `container` fields from
+ `HtmlParser` class. These fields never had a value other than `null`.
+
+## 0.14.0+4
+
+- Fix a bug parsing bad HTML where a 'button' end tag needs to close other
+ elements.
+
+## 0.14.0+3
+
+- Fix spans generated for HTML with higher-plane unicode characters
+ (eg. emojis).
+
+## 0.14.0+2
+
+- Support `package:css` `>=0.13.2 <0.17.0`.
+
+## 0.14.0+1
+
+- Support `package:css` `>=0.13.2 <0.16.0`.
+
+## 0.14.0
+
+*BREAKING CHANGES*
+
+- Drop support for encodings other than UTF-8 and ASCII.
+- Removed `parser_console.dart` library.
+
+## 0.13.4+1
+
+* Fixes to readme and pubspec.
+
+## 0.13.4
+
+* Require Dart 2.0 stable.
+
+## 0.13.3+3
+
+* Do not use this tag in our systems - there was an earlier version of it
+ pointing to a different commit, that is still in some caches.
+
+* Fix missing_return analyzer errors in `processStartTag` and `processEndTag`
+ methods.
+
+## 0.13.3+2
+
+* Set max SDK version to `<3.0.0`, and adjust other dependencies.
+
+## 0.13.3+1
+
+ * Updated SDK version to 2.0.0-dev.17.0
+
+## 0.13.3
+
+ * Update the signatures of `FilteredElementList.indexOf` and
+ `FilteredElementList.lastIndexOf` to include type annotations.
+
+## 0.13.2+2
+
+ * Update signature for implementations of `Iterable.singleWhere` to include
+ optional argument.
+
+## 0.13.2+1
+
+ * Changed the implementation of `Set` and `List` classes to use base classes
+ from `dart:collection`.
+
+## 0.13.2
+
+ * Support the latest release of `pkg/csslib`.
+
+## 0.13.1
+ * Update Set.difference to take a Set<Object>.
+
+## 0.13.0
+
+ * **BREAKING** Fix all [strong mode][] errors and warnings.
+ This involved adding more precise types on some public APIs, which is why it
+ may break users.
+
+[strong mode]: https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
+
+#### Pub version 0.12.2+2
+ * Support `csslib` versions `0.13.x`.
+
+#### Pub version 0.12.2+1
+ * Exclude `.packages` file from the published package.
+
+#### Pub version 0.12.2
+ * Added `Element.endSourceSpan`, containing the span of a closing tag.
+
+#### Pub version 0.12.0+1
+ * Support `csslib` version `0.12.0`.
+
+#### Rename to package:html 0.12.0
+ * package has been renamed to `html`
+
+#### Pub version 0.12.0
+ * switch from `source_maps`' `Span` class to `source_span`'s
+ `SourceSpan` class.
+
+#### Pub version 0.11.0+2
+ * expand the version constraint for csslib.
+
+#### Pub version 0.10.0+1
+ * use a more recent source_maps version.
+
+#### Pub version 0.10.0
+ * fix how document fragments are added in NodeList.add/addAll/insertAll.
+
+#### Pub version 0.9.2-dev
+ * add Node.text, Node.append, Document.documentElement
+ * add Text.data, deprecate Node.value and Text.value.
+ * deprecate Node.$dom_nodeType
+ * added querySelector/querySelectorAll, deprecated query/queryAll.
+ This matches the current APIs in dart:html.
diff --git a/pkgs/html/LICENSE b/pkgs/html/LICENSE
new file mode 100644
index 0000000..1d776b2
--- /dev/null
+++ b/pkgs/html/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2006-2012 The Authors
+
+Contributors:
+James Graham - jg307@cam.ac.uk
+Anne van Kesteren - annevankesteren@gmail.com
+Lachlan Hunt - lachlan.hunt@lachy.id.au
+Matt McDonald - kanashii@kanashii.ca
+Sam Ruby - rubys@intertwingly.net
+Ian Hickson (Google) - ian@hixie.ch
+Thomas Broyer - t.broyer@ltgt.net
+Jacques Distler - distler@golem.ph.utexas.edu
+Henri Sivonen - hsivonen@iki.fi
+Adam Barth - abarth@webkit.org
+Eric Seidel - eric@webkit.org
+The Mozilla Foundation (contributions from Henri Sivonen since 2008)
+David Flanagan (Mozilla) - dflanagan@mozilla.com
+Google LLC (contributed the Dart port) - misc@dartlang.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/pkgs/html/README.md b/pkgs/html/README.md
new file mode 100644
index 0000000..ed1d000
--- /dev/null
+++ b/pkgs/html/README.md
@@ -0,0 +1,28 @@
+[](https://github.com/dart-lang/tools/actions/workflows/html.yaml)
+[](https://pub.dev/packages/html)
+[](https://pub.dev/packages/html/publisher)
+
+A Dart implementation of an HTML5 parser.
+
+## Usage
+
+Parsing HTML is easy!
+
+```dart
+import 'package:html/parser.dart';
+
+void main() {
+ var document = parse(
+ '<body>Hello world! <a href="www.html5rocks.com">HTML5 rocks!');
+ print(document.outerHtml);
+}
+```
+
+You can pass a String or list of bytes to `parse`. There's also `parseFragment`
+for parsing a document fragment, and `HtmlParser` if you want more low level
+control.
+
+## Background
+
+This package was a port of the Python
+[html5lib](https://github.com/html5lib/html5lib-python) library.
diff --git a/pkgs/html/analysis_options.yaml b/pkgs/html/analysis_options.yaml
new file mode 100644
index 0000000..90d920e
--- /dev/null
+++ b/pkgs/html/analysis_options.yaml
@@ -0,0 +1,10 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-raw-types: true
+ errors:
+ lines_longer_than_80_chars: ignore
+ # https://github.com/dart-lang/linter/issues/1649
+ prefer_collection_literals: ignore
diff --git a/pkgs/html/example/main.dart b/pkgs/html/example/main.dart
new file mode 100644
index 0000000..309ed7c
--- /dev/null
+++ b/pkgs/html/example/main.dart
@@ -0,0 +1,57 @@
+import 'package:html/dom.dart';
+import 'package:html/dom_parsing.dart';
+import 'package:html/parser.dart';
+
+void main(List<String> args) {
+ var document = parse('''
+<body>
+ <h2>Header 1</h2>
+ <p>Text.</p>
+ <h2>Header 2</h2>
+ More text.
+ <br/>
+</body>''');
+
+ // outerHtml output
+ print('outer html:');
+ print(document.outerHtml);
+
+ print('');
+
+ // visitor output
+ print('html visitor:');
+ _Visitor().visit(document);
+}
+
+// Note: this example visitor doesn't handle things like printing attributes and
+// such.
+class _Visitor extends TreeVisitor {
+ String indent = '';
+
+ @override
+ void visitText(Text node) {
+ if (node.data.trim().isNotEmpty) {
+ print('$indent${node.data.trim()}');
+ }
+ }
+
+ @override
+ void visitElement(Element node) {
+ if (isVoidElement(node.localName)) {
+ print('$indent<${node.localName}/>');
+ } else {
+ print('$indent<${node.localName}>');
+ indent += ' ';
+ visitChildren(node);
+ indent = indent.substring(0, indent.length - 2);
+ print('$indent</${node.localName}>');
+ }
+ }
+
+ @override
+ void visitChildren(Node node) {
+ for (var child in node.nodes) {
+ visit(child);
+ }
+ }
+}
diff --git a/pkgs/html/lib/dom.dart b/pkgs/html/lib/dom.dart
new file mode 100644
index 0000000..0c6b38e
--- /dev/null
+++ b/pkgs/html/lib/dom.dart
@@ -0,0 +1,1120 @@
+/// A simple tree API that results from parsing html. Intended to be compatible
+/// with dart:html, but it is missing many types and APIs.
+library;
+
+// ignore_for_file: constant_identifier_names
+
+// TODO(jmesserly): lots to do here. Originally I wanted to generate this using
+// our Blink IDL generator, but another idea is to directly use the excellent
+// http://dom.spec.whatwg.org/ and http://html.spec.whatwg.org/ and just
+// implement that.
+
+import 'dart:collection';
+
+import 'package:source_span/source_span.dart';
+
+import 'dom_parsing.dart';
+import 'parser.dart';
+import 'src/constants.dart';
+import 'src/css_class_set.dart';
+import 'src/list_proxy.dart';
+import 'src/query_selector.dart' as query;
+import 'src/token.dart';
+import 'src/tokenizer.dart';
+
+export 'src/css_class_set.dart' show CssClassSet;
+
+// TODO(jmesserly): this needs to be replaced by an AttributeMap for attributes
+// that exposes namespace info.
+class AttributeName implements Comparable<Object> {
+ /// The namespace prefix, e.g. `xlink`.
+ final String? prefix;
+
+ /// The attribute name, e.g. `title`.
+ final String name;
+
+ /// The namespace url, e.g. `http://www.w3.org/1999/xlink`
+ final String namespace;
+
+ const AttributeName(this.prefix, this.name, this.namespace);
+
+ @override
+ String toString() {
+ // Implement:
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
+ // If we get here we know we are xml, xmlns, or xlink, because of
+ // [HtmlParser.adjustForeignAttriubtes] is the only place we create
+ // an AttributeName.
+ return prefix != null ? '$prefix:$name' : name;
+ }
+
+ @override
+ int get hashCode {
+ var h = prefix.hashCode;
+ h = 37 * (h & 0x1FFFFF) + name.hashCode;
+ h = 37 * (h & 0x1FFFFF) + namespace.hashCode;
+ return h & 0x3FFFFFFF;
+ }
+
+ @override
+ int compareTo(Object other) {
+ // Not sure about this sort order
+ if (other is! AttributeName) return 1;
+ var cmp = (prefix ?? '').compareTo(other.prefix ?? '');
+ if (cmp != 0) return cmp;
+ cmp = name.compareTo(other.name);
+ if (cmp != 0) return cmp;
+ return namespace.compareTo(other.namespace);
+ }
+
+ @override
+ bool operator ==(Object other) =>
+ other is AttributeName &&
+ prefix == other.prefix &&
+ name == other.name &&
+ namespace == other.namespace;
+}
+
+// http://dom.spec.whatwg.org/#parentnode
+mixin _ParentNode implements Node {
+ // TODO(jmesserly): this is only a partial implementation
+
+ /// Seaches for the first descendant node matching the given selectors, using
+ /// a preorder traversal.
+ ///
+ /// NOTE: Not all selectors from
+ /// [selectors level 4](http://dev.w3.org/csswg/selectors-4/)
+ /// are implemented. For example, nth-child does not implement An+B syntax
+ /// and *-of-type is not implemented. If a selector is not implemented this
+ /// method will throw [UnimplementedError].
+ Element? querySelector(String selector) =>
+ query.querySelector(this, selector);
+
+ /// Returns all descendant nodes matching the given selectors, using a
+ /// preorder traversal.
+ ///
+ /// NOTE: Not all selectors from
+ /// [selectors level 4](http://dev.w3.org/csswg/selectors-4/)
+ /// are implemented. For example, nth-child does not implement An+B syntax
+ /// and *-of-type is not implemented. If a selector is not implemented this
+ /// method will throw [UnimplementedError].
+ List<Element> querySelectorAll(String selector) =>
+ query.querySelectorAll(this, selector);
+}
+
+// http://dom.spec.whatwg.org/#interface-nonelementparentnode
+mixin _NonElementParentNode implements _ParentNode {
+ // TODO(jmesserly): could be faster, should throw on invalid id.
+ Element? getElementById(String id) => querySelector('#$id');
+}
+
+// This doesn't exist as an interface in the spec, but it's useful to merge
+// common methods from these:
+// http://dom.spec.whatwg.org/#interface-document
+// http://dom.spec.whatwg.org/#element
+abstract mixin class _ElementAndDocument implements _ParentNode {
+ // TODO(jmesserly): could be faster, should throw on invalid tag/class names.
+
+ List<Element> getElementsByTagName(String localName) =>
+ querySelectorAll(localName);
+
+ List<Element> getElementsByClassName(String classNames) =>
+ querySelectorAll(classNames.splitMapJoin(' ',
+ onNonMatch: (m) => m.isNotEmpty ? '.$m' : m, onMatch: (m) => ''));
+}
+
+/// Really basic implementation of a DOM-core like Node.
+abstract class Node {
+ static const int ATTRIBUTE_NODE = 2;
+ static const int CDATA_SECTION_NODE = 4;
+ static const int COMMENT_NODE = 8;
+ static const int DOCUMENT_FRAGMENT_NODE = 11;
+ static const int DOCUMENT_NODE = 9;
+ static const int DOCUMENT_TYPE_NODE = 10;
+ static const int ELEMENT_NODE = 1;
+ static const int ENTITY_NODE = 6;
+ static const int ENTITY_REFERENCE_NODE = 5;
+ static const int NOTATION_NODE = 12;
+ static const int PROCESSING_INSTRUCTION_NODE = 7;
+ static const int TEXT_NODE = 3;
+
+ /// The parent of the current node (or null for the document node).
+ Node? parentNode;
+
+ /// The parent element of this node.
+ ///
+ /// Returns null if this node either does not have a parent or its parent is
+ /// not an element.
+ Element? get parent {
+ final parentNode = this.parentNode;
+ return parentNode is Element ? parentNode : null;
+ }
+
+ // TODO(jmesserly): should move to Element.
+ /// A map holding name, value pairs for attributes of the node.
+ ///
+ /// Note that attribute order needs to be stable for serialization, so we use
+ /// a LinkedHashMap. Each key is a [String] or [AttributeName].
+ LinkedHashMap<Object, String> attributes = LinkedHashMap();
+
+ /// A list of child nodes of the current node. This must
+ /// include all elements but not necessarily other node types.
+ late final nodes = NodeList._(this);
+
+ late final List<Element> children = FilteredElementList(this);
+
+ // TODO(jmesserly): consider using an Expando for this, and put it in
+ // dom_parsing. Need to check the performance affect.
+ /// The source span of this node, if it was created by the [HtmlParser].
+ FileSpan? sourceSpan;
+
+ /// The attribute spans if requested. Otherwise null.
+ LinkedHashMap<Object, FileSpan>? _attributeSpans;
+ LinkedHashMap<Object, FileSpan>? _attributeValueSpans;
+
+ Node._();
+
+ /// If [sourceSpan] is available, this contains the spans of each attribute.
+ /// The span of an attribute is the entire attribute, including the name and
+ /// quotes (if any). For example, the span of "attr" in `<a attr="value">`
+ /// would be the text `attr="value"`.
+ LinkedHashMap<Object, FileSpan>? get attributeSpans {
+ _ensureAttributeSpans();
+ return _attributeSpans;
+ }
+
+ /// If [sourceSpan] is available, this contains the spans of each attribute's
+ /// value. Unlike [attributeSpans], this span will include only the value.
+ /// For example, the value span of "attr" in `<a attr="value">` would be the
+ /// text `value`.
+ LinkedHashMap<Object, FileSpan>? get attributeValueSpans {
+ _ensureAttributeSpans();
+ return _attributeValueSpans;
+ }
+
+ /// Returns a copy of this node.
+ ///
+ /// If [deep] is `true`, then all of this node's children and decendents are
+ /// copied as well. If [deep] is `false`, then only this node is copied.
+ Node clone(bool deep);
+
+ int get nodeType;
+
+ // http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
+ String get _outerHtml {
+ final str = StringBuffer();
+ _addOuterHtml(str);
+ return str.toString();
+ }
+
+ String get _innerHtml {
+ final str = StringBuffer();
+ _addInnerHtml(str);
+ return str.toString();
+ }
+
+ // Implemented per: http://dom.spec.whatwg.org/#dom-node-textcontent
+ String? get text => null;
+
+ set text(String? value) {}
+
+ void append(Node node) => nodes.add(node);
+
+ Node? get firstChild => nodes.isNotEmpty ? nodes[0] : null;
+
+ void _addOuterHtml(StringBuffer str);
+
+ void _addInnerHtml(StringBuffer str) {
+ for (var child in nodes) {
+ child._addOuterHtml(str);
+ }
+ }
+
+ Node remove() {
+ // TODO(jmesserly): is parent == null an error?
+ parentNode?.nodes.remove(this);
+ return this;
+ }
+
+ /// Insert [node] as a child of the current node, before [refNode] in the
+ void insertBefore(Node node, Node? refNode) {
+ if (refNode == null) {
+ nodes.add(node);
+ } else {
+ nodes.insert(nodes.indexOf(refNode), node);
+ }
+ }
+
+ /// Replaces this node with another node.
+ Node replaceWith(Node otherNode) {
+ if (parentNode == null) {
+ throw UnsupportedError('Node must have a parent to replace it.');
+ }
+ parentNode!.nodes[parentNode!.nodes.indexOf(this)] = otherNode;
+ return this;
+ }
+
+ // TODO(jmesserly): should this be a property or remove?
+ /// Return true if the node has children or text.
+ bool hasContent() => nodes.isNotEmpty;
+
+ /// Move all the children of the current node to [newParent].
+ /// This is needed so that trees that don't store text as nodes move the
+ /// text in the correct way.
+ void reparentChildren(Node newParent) {
+ newParent.nodes.addAll(nodes);
+ nodes.clear();
+ }
+
+ bool hasChildNodes() => nodes.isNotEmpty;
+
+ bool contains(Node node) => nodes.contains(node);
+
+ /// Initialize [attributeSpans] using [sourceSpan].
+ void _ensureAttributeSpans() {
+ if (_attributeSpans != null) return;
+
+ final attributeSpans = _attributeSpans = LinkedHashMap<Object, FileSpan>();
+ final attributeValueSpans =
+ _attributeValueSpans = LinkedHashMap<Object, FileSpan>();
+
+ if (sourceSpan == null) return;
+
+ final tokenizer = HtmlTokenizer(sourceSpan!.text,
+ generateSpans: true, attributeSpans: true);
+
+ tokenizer.moveNext();
+ final token = tokenizer.current as StartTagToken;
+
+ if (token.attributeSpans == null) return; // no attributes
+
+ for (var attr in token.attributeSpans!) {
+ final offset = sourceSpan!.start.offset;
+ final name = attr.name!;
+ attributeSpans[name] =
+ sourceSpan!.file.span(offset + attr.start, offset + attr.end);
+ if (attr.startValue != null) {
+ attributeValueSpans[name] = sourceSpan!.file
+ .span(offset + attr.startValue!, offset + attr.endValue);
+ }
+ }
+ }
+
+ T _clone<T extends Node>(T shallowClone, bool deep) {
+ if (deep) {
+ for (var child in nodes) {
+ shallowClone.append(child.clone(true));
+ }
+ }
+ return shallowClone;
+ }
+}
+
+class Document extends Node
+ with _ParentNode, _NonElementParentNode, _ElementAndDocument {
+ Document() : super._();
+
+ factory Document.html(String html) => parse(html);
+
+ @override
+ int get nodeType => Node.DOCUMENT_NODE;
+
+ // TODO(jmesserly): optmize this if needed
+ Element? get documentElement => querySelector('html');
+
+ Element? get head => documentElement?.querySelector('head');
+
+ Element? get body => documentElement?.querySelector('body');
+
+ /// Returns a fragment of HTML or XML that represents the element and its
+ /// contents.
+ // TODO(jmesserly): this API is not specified in:
+ // <http://domparsing.spec.whatwg.org/> nor is it in dart:html, instead
+ // only Element has outerHtml. However it is quite useful. Should we move it
+ // to dom_parsing, where we keep other custom APIs?
+ String get outerHtml => _outerHtml;
+
+ @override
+ String toString() => '#document';
+
+ @override
+ void _addOuterHtml(StringBuffer str) => _addInnerHtml(str);
+
+ @override
+ Document clone(bool deep) => _clone(Document(), deep);
+
+ Element createElement(String tag) => Element.tag(tag);
+
+ // TODO(jmesserly): this is only a partial implementation of:
+ // http://dom.spec.whatwg.org/#dom-document-createelementns
+ Element createElementNS(String? namespaceUri, String? tag) {
+ if (namespaceUri == '') namespaceUri = null;
+ return Element._(tag, namespaceUri);
+ }
+
+ DocumentFragment createDocumentFragment() => DocumentFragment();
+}
+
+class DocumentFragment extends Node with _ParentNode, _NonElementParentNode {
+ DocumentFragment() : super._();
+
+ factory DocumentFragment.html(String html) => parseFragment(html);
+
+ @override
+ int get nodeType => Node.DOCUMENT_FRAGMENT_NODE;
+
+ /// Returns a fragment of HTML or XML that represents the element and its
+ /// contents.
+ // TODO(jmesserly): this API is not specified in:
+ // <http://domparsing.spec.whatwg.org/> nor is it in dart:html, instead
+ // only Element has outerHtml. However it is quite useful. Should we move it
+ // to dom_parsing, where we keep other custom APIs?
+ String get outerHtml => _outerHtml;
+
+ @override
+ String toString() => '#document-fragment';
+
+ @override
+ DocumentFragment clone(bool deep) => _clone(DocumentFragment(), deep);
+
+ @override
+ void _addOuterHtml(StringBuffer str) => _addInnerHtml(str);
+
+ @override
+ String? get text => _getText(this);
+
+ @override
+ set text(String? value) => _setText(this, value);
+}
+
+class DocumentType extends Node {
+ final String? name;
+ final String? publicId;
+ final String? systemId;
+
+ DocumentType(this.name, this.publicId, this.systemId) : super._();
+
+ @override
+ int get nodeType => Node.DOCUMENT_TYPE_NODE;
+
+ @override
+ String toString() {
+ if (publicId != null || systemId != null) {
+ // TODO(jmesserly): the html5 serialization spec does not add these. But
+ // it seems useful, and the parser can handle it, so for now keeping it.
+ final pid = publicId ?? '';
+ final sid = systemId ?? '';
+ return '<!DOCTYPE $name "$pid" "$sid">';
+ } else {
+ return '<!DOCTYPE $name>';
+ }
+ }
+
+ @override
+ void _addOuterHtml(StringBuffer str) {
+ str.write(toString());
+ }
+
+ @override
+ DocumentType clone(bool deep) => DocumentType(name, publicId, systemId);
+}
+
+class Text extends Node {
+ /// The text node's data, stored as either a String or StringBuffer.
+ /// We support storing a StringBuffer here to support fast [appendData].
+ /// It will flatten back to a String on read.
+ Object _data;
+
+ Text(String? data)
+ : _data = data ?? '',
+ super._();
+
+ @override
+ int get nodeType => Node.TEXT_NODE;
+
+ String get data => _data = _data.toString();
+
+ set data(String value) {
+ // Handle unsound null values.
+ _data = identical(value, null) ? '' : value;
+ }
+
+ @override
+ String toString() => '"$data"';
+
+ @override
+ void _addOuterHtml(StringBuffer str) => writeTextNodeAsHtml(str, this);
+
+ @override
+ Text clone(bool deep) => Text(data);
+
+ void appendData(String data) {
+ if (_data is! StringBuffer) _data = StringBuffer(_data);
+ final sb = _data as StringBuffer;
+ sb.write(data);
+ }
+
+ @override
+ String get text => data;
+
+ @override
+ // Text has a non-nullable `text` field, while Node has a nullable field.
+ set text(covariant String value) {
+ data = value;
+ }
+}
+
+// TODO(jmesserly): Elements should have a pointer back to their document
+class Element extends Node with _ParentNode, _ElementAndDocument {
+ final String? namespaceUri;
+
+ /// The [local name](http://dom.spec.whatwg.org/#concept-element-local-name)
+ /// of this element.
+ final String? localName;
+
+ // TODO(jmesserly): consider using an Expando for this, and put it in
+ // dom_parsing. Need to check the performance affect.
+ /// The source span of the end tag this element, if it was created by the
+ /// [HtmlParser]. May be `null` if does not have an implicit end tag.
+ FileSpan? endSourceSpan;
+
+ Element._(this.localName, [this.namespaceUri]) : super._();
+
+ Element.tag(this.localName)
+ : namespaceUri = Namespaces.html,
+ super._();
+
+ static final _startTagRegexp = RegExp('<(\\w+)');
+
+ static final _customParentTagMap = const {
+ 'body': 'html',
+ 'head': 'html',
+ 'caption': 'table',
+ 'td': 'tr',
+ 'colgroup': 'table',
+ 'col': 'colgroup',
+ 'tr': 'tbody',
+ 'tbody': 'table',
+ 'tfoot': 'table',
+ 'thead': 'table',
+ 'track': 'audio',
+ };
+
+ // TODO(jmesserly): this is from dart:html _ElementFactoryProvider...
+ // TODO(jmesserly): have a look at fixing some things in dart:html, in
+ // particular: is the parent tag map complete? Is it faster without regexp?
+ // TODO(jmesserly): for our version we can do something smarter in the parser.
+ // All we really need is to set the correct parse state.
+ factory Element.html(String html) {
+ // TODO(jacobr): this method can be made more robust and performant.
+ // 1) Cache the dummy parent elements required to use innerHTML rather than
+ // creating them every call.
+ // 2) Verify that the html does not contain leading or trailing text nodes.
+ // 3) Verify that the html does not contain both <head> and <body> tags.
+ // 4) Detach the created element from its dummy parent.
+ var parentTag = 'div';
+ String? tag;
+ final match = _startTagRegexp.firstMatch(html);
+ if (match != null) {
+ tag = match.group(1)!.toLowerCase();
+ if (_customParentTagMap.containsKey(tag)) {
+ parentTag = _customParentTagMap[tag]!;
+ }
+ }
+
+ final fragment = parseFragment(html, container: parentTag);
+ Element element;
+ if (fragment.children.length == 1) {
+ element = fragment.children[0];
+ } else if (parentTag == 'html' && fragment.children.length == 2) {
+ // You'll always get a head and a body when starting from html.
+ element = fragment.children[tag == 'head' ? 0 : 1];
+ } else {
+ throw ArgumentError('HTML had ${fragment.children.length} '
+ 'top level elements but 1 expected');
+ }
+ element.remove();
+ return element;
+ }
+
+ @override
+ int get nodeType => Node.ELEMENT_NODE;
+
+ // TODO(jmesserly): we can make this faster
+ Element? get previousElementSibling {
+ if (parentNode == null) return null;
+ final siblings = parentNode!.nodes;
+ for (var i = siblings.indexOf(this) - 1; i >= 0; i--) {
+ final s = siblings[i];
+ if (s is Element) return s;
+ }
+ return null;
+ }
+
+ Element? get nextElementSibling {
+ final parentNode = this.parentNode;
+ if (parentNode == null) return null;
+ final siblings = parentNode.nodes;
+ for (var i = siblings.indexOf(this) + 1; i < siblings.length; i++) {
+ final s = siblings[i];
+ if (s is Element) return s;
+ }
+ return null;
+ }
+
+ @override
+ String toString() {
+ final prefix = Namespaces.getPrefix(namespaceUri);
+ return "<${prefix == null ? '' : '$prefix '}$localName>";
+ }
+
+ @override
+ String get text => _getText(this);
+
+ @override
+ set text(String? value) => _setText(this, value);
+
+ /// Returns a fragment of HTML or XML that represents the element and its
+ /// contents.
+ String get outerHtml => _outerHtml;
+
+ /// Returns a fragment of HTML or XML that represents the element's contents.
+ /// Can be set, to replace the contents of the element with nodes parsed from
+ /// the given string.
+ String get innerHtml => _innerHtml;
+
+ // TODO(jmesserly): deprecate in favor of:
+ // <https://api.dartlang.org/apidocs/channels/stable/#dart-dom-html.Element@id_setInnerHtml>
+ set innerHtml(String value) {
+ nodes.clear();
+ // TODO(jmesserly): should be able to get the same effect by adding the
+ // fragment directly.
+ nodes.addAll(parseFragment(value, container: localName!).nodes);
+ }
+
+ @override
+ void _addOuterHtml(StringBuffer str) {
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
+ // Element is the most complicated one.
+ str.write('<');
+ str.write(_getSerializationPrefix(namespaceUri));
+ str.write(localName);
+
+ if (attributes.isNotEmpty) {
+ attributes.forEach((key, v) {
+ // Note: AttributeName.toString handles serialization of attribute
+ // namespace, if needed.
+ str.write(' ');
+ str.write(key);
+ str.write('="');
+ str.write(htmlSerializeEscape(v, attributeMode: true));
+ str.write('"');
+ });
+ }
+
+ str.write('>');
+
+ if (nodes.isNotEmpty) {
+ if (localName == 'pre' ||
+ localName == 'textarea' ||
+ localName == 'listing') {
+ final first = nodes[0];
+ if (first is Text && first.data.startsWith('\n')) {
+ // These nodes will remove a leading \n at parse time, so if we still
+ // have one, it means we started with two. Add it back.
+ str.write('\n');
+ }
+ }
+
+ _addInnerHtml(str);
+ }
+
+ // void elements must not have an end tag
+ // http://dev.w3.org/html5/markup/syntax.html#void-elements
+ if (!isVoidElement(localName)) str.write('</$localName>');
+ }
+
+ static String _getSerializationPrefix(String? uri) {
+ if (uri == null ||
+ uri == Namespaces.html ||
+ uri == Namespaces.mathml ||
+ uri == Namespaces.svg) {
+ return '';
+ }
+ final prefix = Namespaces.getPrefix(uri);
+ // TODO(jmesserly): the spec doesn't define "qualified name".
+ // I'm not sure if this is correct, but it should parse reasonably.
+ return prefix == null ? '' : '$prefix:';
+ }
+
+ @override
+ Element clone(bool deep) {
+ final result = Element._(localName, namespaceUri)
+ ..attributes = LinkedHashMap.from(attributes);
+ return _clone(result, deep);
+ }
+
+ // http://dom.spec.whatwg.org/#dom-element-id
+ String get id {
+ final result = attributes['id'];
+ return result ?? '';
+ }
+
+ set id(String value) {
+ attributes['id'] = value;
+ }
+
+ // http://dom.spec.whatwg.org/#dom-element-classname
+ String get className {
+ final result = attributes['class'];
+ return result ?? '';
+ }
+
+ set className(String value) {
+ attributes['class'] = value;
+ }
+
+ /// The set of CSS classes applied to this element.
+ ///
+ /// This set makes it easy to add, remove or toggle the classes applied to
+ /// this element.
+ ///
+ /// element.classes.add('selected');
+ /// element.classes.toggle('isOnline');
+ /// element.classes.remove('selected');
+ CssClassSet get classes => ElementCssClassSet(this);
+}
+
+class Comment extends Node {
+ String? data;
+
+ Comment(this.data) : super._();
+
+ @override
+ int get nodeType => Node.COMMENT_NODE;
+
+ @override
+ String toString() => '<!-- $data -->';
+
+ @override
+ void _addOuterHtml(StringBuffer str) {
+ str.write('<!--$data-->');
+ }
+
+ @override
+ Comment clone(bool deep) => Comment(data);
+
+ @override
+ String? get text => data;
+
+ @override
+ set text(String? value) {
+ data = value;
+ }
+}
+
+// TODO(jmesserly): fix this to extend one of the corelib classes if possible.
+// (The requirement to remove the node from the old node list makes it tricky.)
+// TODO(jmesserly): is there any way to share code with the _NodeListImpl?
+class NodeList extends ListProxy<Node> {
+ final Node _parent;
+
+ NodeList._(this._parent);
+
+ Node _setParent(Node node) {
+ // Note: we need to remove the node from its previous parent node, if any,
+ // before updating its parent pointer to point at our parent.
+ node.remove();
+ node.parentNode = _parent;
+ return node;
+ }
+
+ @override
+ void add(Node element) {
+ if (element is DocumentFragment) {
+ addAll(element.nodes);
+ } else {
+ super.add(_setParent(element));
+ }
+ }
+
+ void addLast(Node value) => add(value);
+
+ @override
+ void addAll(Iterable<Node> iterable) {
+ // Note: we need to be careful if collection is another NodeList.
+ // In particular:
+ // 1. we need to copy the items before updating their parent pointers,
+ // _flattenDocFragments does a copy internally.
+ // 2. we should update parent pointers in reverse order. That way they
+ // are removed from the original NodeList (if any) from the end, which
+ // is faster.
+ final list = _flattenDocFragments(iterable);
+ for (var node in list.reversed) {
+ _setParent(node);
+ }
+ super.addAll(list);
+ }
+
+ @override
+ void insert(int index, Node element) {
+ if (element is DocumentFragment) {
+ insertAll(index, element.nodes);
+ } else {
+ super.insert(index, _setParent(element));
+ }
+ }
+
+ @override
+ Node removeLast() => super.removeLast()..parentNode = null;
+
+ @override
+ Node removeAt(int index) => super.removeAt(index)..parentNode = null;
+
+ @override
+ void clear() {
+ for (var node in this) {
+ node.parentNode = null;
+ }
+ super.clear();
+ }
+
+ @override
+ void operator []=(int index, Node value) {
+ if (value is DocumentFragment) {
+ removeAt(index);
+ insertAll(index, value.nodes);
+ } else {
+ this[index].parentNode = null;
+ super[index] = _setParent(value);
+ }
+ }
+
+ // TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see
+ // http://code.google.com/p/dart/issues/detail?id=5371
+ @override
+ void setRange(int start, int end, Iterable<Node> iterable,
+ [int skipCount = 0]) {
+ var fromVar = iterable as List<Node>;
+ if (fromVar is NodeList) {
+ // Note: this is presumed to make a copy
+ fromVar = fromVar.sublist(skipCount, skipCount + end);
+ }
+ // Note: see comment in [addAll]. We need to be careful about the order of
+ // operations if [from] is also a NodeList.
+ for (var i = end - 1; i >= 0; i--) {
+ this[start + i] = fromVar[skipCount + i];
+ }
+ }
+
+ @override
+ void replaceRange(int start, int end, Iterable<Node> newContents) {
+ removeRange(start, end);
+ insertAll(start, newContents);
+ }
+
+ @override
+ void removeRange(int start, int end) {
+ for (var i = start; i < end; i++) {
+ this[i].parentNode = null;
+ }
+ super.removeRange(start, end);
+ }
+
+ @override
+ void removeWhere(bool Function(Node) test) {
+ for (var node in where(test)) {
+ node.parentNode = null;
+ }
+ super.removeWhere(test);
+ }
+
+ @override
+ void retainWhere(bool Function(Node) test) {
+ for (var node in where((n) => !test(n))) {
+ node.parentNode = null;
+ }
+ super.retainWhere(test);
+ }
+
+ @override
+ void insertAll(int index, Iterable<Node> iterable) {
+ // Note: we need to be careful how we copy nodes. See note in addAll.
+ final list = _flattenDocFragments(iterable);
+ for (var node in list.reversed) {
+ _setParent(node);
+ }
+ super.insertAll(index, list);
+ }
+
+ List<Node> _flattenDocFragments(Iterable<Node> collection) {
+ // Note: this function serves two purposes:
+ // * it flattens document fragments
+ // * it creates a copy of [collections] when `collection is NodeList`.
+ final result = <Node>[];
+ for (var node in collection) {
+ if (node is DocumentFragment) {
+ result.addAll(node.nodes);
+ } else {
+ result.add(node);
+ }
+ }
+ return result;
+ }
+}
+
+/// An indexable collection of a node's descendants in the document tree,
+/// filtered so that only elements are in the collection.
+// TODO(jmesserly): this was copied from dart:html
+// TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug.
+class FilteredElementList extends IterableBase<Element>
+ with ListMixin<Element>
+ implements List<Element> {
+ final List<Node> _childNodes;
+
+ /// Creates a collection of the elements that descend from a node.
+ ///
+ /// Example usage:
+ ///
+ /// var filteredElements = new FilteredElementList(query("#container"));
+ /// // filteredElements is [a, b, c].
+ FilteredElementList(Node node) : _childNodes = node.nodes;
+
+ // We can't memoize this, since it's possible that children will be messed
+ // with externally to this class.
+ //
+ // TODO(nweiz): we don't always need to create a new list. For example
+ // forEach, every, any, ... could directly work on the _childNodes.
+ List<Element> get _filtered =>
+ _childNodes.whereType<Element>().toList(growable: false);
+
+ @override
+ void forEach(void Function(Element) action) {
+ _filtered.forEach(action);
+ }
+
+ @override
+ void operator []=(int index, Element value) {
+ this[index].replaceWith(value);
+ }
+
+ @override
+ set length(int newLength) {
+ final len = length;
+ if (newLength >= len) {
+ return;
+ } else if (newLength < 0) {
+ throw ArgumentError('Invalid list length');
+ }
+
+ removeRange(newLength, len);
+ }
+
+ @override
+ String join([String separator = '']) => _filtered.join(separator);
+
+ @override
+ void add(Element element) {
+ _childNodes.add(element);
+ }
+
+ @override
+ void addAll(Iterable<Element> iterable) {
+ for (var element in iterable) {
+ add(element);
+ }
+ }
+
+ @override
+ bool contains(Object? element) {
+ return element is Element && _childNodes.contains(element);
+ }
+
+ @override
+ Iterable<Element> get reversed => _filtered.reversed;
+
+ @override
+ void sort([int Function(Element, Element)? compare]) {
+ throw UnsupportedError('TODO(jacobr): should we impl?');
+ }
+
+ @override
+ void setRange(int start, int end, Iterable<Element> iterable,
+ [int skipCount = 0]) {
+ throw UnimplementedError();
+ }
+
+ @override
+ void fillRange(int start, int end, [Element? fill]) {
+ throw UnimplementedError();
+ }
+
+ @override
+ void replaceRange(int start, int end, Iterable<Element> newContents) {
+ throw UnimplementedError();
+ }
+
+ @override
+ void removeRange(int start, int end) {
+ _filtered.sublist(start, end).forEach((el) => el.remove());
+ }
+
+ @override
+ void clear() {
+ // Currently, ElementList#clear clears even non-element nodes, so we follow
+ // that behavior.
+ _childNodes.clear();
+ }
+
+ @override
+ Element removeLast() {
+ return last..remove();
+ }
+
+ @override
+ Iterable<T> map<T>(T Function(Element) f) => _filtered.map(f);
+
+ @override
+ Iterable<Element> where(bool Function(Element) test) => _filtered.where(test);
+
+ @override
+ Iterable<T> expand<T>(Iterable<T> Function(Element) f) => _filtered.expand(f);
+
+ @override
+ void insert(int index, Element element) {
+ _childNodes.insert(index, element);
+ }
+
+ @override
+ void insertAll(int index, Iterable<Element> iterable) {
+ _childNodes.insertAll(index, iterable);
+ }
+
+ @override
+ Element removeAt(int index) {
+ final result = this[index];
+ result.remove();
+ return result;
+ }
+
+ @override
+ bool remove(Object? element) {
+ if (element is! Element) return false;
+ for (var i = 0; i < length; i++) {
+ final indexElement = this[i];
+ if (identical(indexElement, element)) {
+ indexElement.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @override
+ Element reduce(Element Function(Element, Element) combine) {
+ return _filtered.reduce(combine);
+ }
+
+ @override
+ T fold<T>(
+ T initialValue, T Function(T previousValue, Element element) combine) {
+ return _filtered.fold(initialValue, combine);
+ }
+
+ @override
+ bool every(bool Function(Element) test) => _filtered.every(test);
+
+ @override
+ bool any(bool Function(Element) test) => _filtered.any(test);
+
+ @override
+ List<Element> toList({bool growable = true}) =>
+ List<Element>.of(this, growable: growable);
+
+ @override
+ Set<Element> toSet() => Set<Element>.from(this);
+
+ @override
+ Element firstWhere(bool Function(Element) test,
+ {Element Function()? orElse}) {
+ return _filtered.firstWhere(test, orElse: orElse);
+ }
+
+ @override
+ Element lastWhere(bool Function(Element) test, {Element Function()? orElse}) {
+ return _filtered.lastWhere(test, orElse: orElse);
+ }
+
+ @override
+ Element singleWhere(bool Function(Element) test,
+ {Element Function()? orElse}) {
+ if (orElse != null) throw UnimplementedError('orElse');
+ return _filtered.singleWhere(test);
+ }
+
+ @override
+ Element elementAt(int index) {
+ return this[index];
+ }
+
+ @override
+ bool get isEmpty => _filtered.isEmpty;
+
+ @override
+ int get length => _filtered.length;
+
+ @override
+ Element operator [](int index) => _filtered[index];
+
+ @override
+ Iterator<Element> get iterator => _filtered.iterator;
+
+ @override
+ List<Element> sublist(int start, [int? end]) => _filtered.sublist(start, end);
+
+ @override
+ Iterable<Element> getRange(int start, int end) =>
+ _filtered.getRange(start, end);
+
+ @override
+ int indexOf(Object? element, [int start = 0]) =>
+ // Cast forced by ListMixin https://github.com/dart-lang/sdk/issues/31311
+ _filtered.indexOf(element as Element, start);
+
+ @override
+ int lastIndexOf(Object? element, [int? start]) {
+ start ??= length - 1;
+ // Cast forced by ListMixin https://github.com/dart-lang/sdk/issues/31311
+ return _filtered.lastIndexOf(element as Element, start);
+ }
+
+ @override
+ Element get first => _filtered.first;
+
+ @override
+ Element get last => _filtered.last;
+
+ @override
+ Element get single => _filtered.single;
+}
+
+// http://dom.spec.whatwg.org/#dom-node-textcontent
+// For Element and DocumentFragment
+String _getText(Node node) => (_ConcatTextVisitor()..visit(node)).toString();
+
+void _setText(Node node, String? value) {
+ node.nodes.clear();
+ node.append(Text(value));
+}
+
+class _ConcatTextVisitor extends TreeVisitor {
+ final _str = StringBuffer();
+
+ @override
+ String toString() => _str.toString();
+
+ @override
+ void visitText(Text node) {
+ _str.write(node.data);
+ }
+}
diff --git a/pkgs/html/lib/dom_parsing.dart b/pkgs/html/lib/dom_parsing.dart
new file mode 100644
index 0000000..69b0bbd
--- /dev/null
+++ b/pkgs/html/lib/dom_parsing.dart
@@ -0,0 +1,157 @@
+/// This library contains extra APIs that aren't in the DOM, but are useful
+/// when interacting with the parse tree.
+library;
+
+import 'dom.dart';
+import 'html_escape.dart';
+import 'src/constants.dart' show rcdataElements;
+
+// Export a function which was previously declared here.
+export 'html_escape.dart';
+
+/// A simple tree visitor for the DOM nodes.
+class TreeVisitor {
+ void visit(Node node) {
+ return switch (node.nodeType) {
+ Node.ELEMENT_NODE => visitElement(node as Element),
+ Node.TEXT_NODE => visitText(node as Text),
+ Node.COMMENT_NODE => visitComment(node as Comment),
+ Node.DOCUMENT_FRAGMENT_NODE =>
+ visitDocumentFragment(node as DocumentFragment),
+ Node.DOCUMENT_NODE => visitDocument(node as Document),
+ Node.DOCUMENT_TYPE_NODE => visitDocumentType(node as DocumentType),
+ _ => throw UnsupportedError('DOM node type ${node.nodeType}')
+ };
+ }
+
+ void visitChildren(Node node) {
+ // Allow for mutations (remove works) while iterating.
+ for (var child in node.nodes.toList(growable: false)) {
+ visit(child);
+ }
+ }
+
+ /// The fallback handler if the more specific visit method hasn't been
+ /// overriden. Only use this from a subclass of [TreeVisitor], otherwise
+ /// call [visit] instead.
+ void visitNodeFallback(Node node) => visitChildren(node);
+
+ void visitDocument(Document node) => visitNodeFallback(node);
+
+ void visitDocumentType(DocumentType node) => visitNodeFallback(node);
+
+ void visitText(Text node) => visitNodeFallback(node);
+
+ // TODO(jmesserly): visit attributes.
+ void visitElement(Element node) => visitNodeFallback(node);
+
+ void visitComment(Comment node) => visitNodeFallback(node);
+
+ void visitDocumentFragment(DocumentFragment node) => visitNodeFallback(node);
+}
+
+/// Converts the DOM tree into an HTML string with code markup suitable for
+/// displaying the HTML's source code with CSS colors for different parts of the
+/// markup. See also [CodeMarkupVisitor].
+String htmlToCodeMarkup(Node node) {
+ return (CodeMarkupVisitor()..visit(node)).toString();
+}
+
+/// Converts the DOM tree into an HTML string with code markup suitable for
+/// displaying the HTML's source code with CSS colors for different parts of the
+/// markup. See also [htmlToCodeMarkup].
+class CodeMarkupVisitor extends TreeVisitor {
+ final StringBuffer _str;
+
+ CodeMarkupVisitor() : _str = StringBuffer();
+
+ @override
+ String toString() => _str.toString();
+
+ @override
+ void visitDocument(Document node) {
+ _str.write('<pre>');
+ visitChildren(node);
+ _str.write('</pre>');
+ }
+
+ @override
+ void visitDocumentType(DocumentType node) {
+ _str.write('<code class="markup doctype"><!DOCTYPE ${node.name}>'
+ '</code>');
+ }
+
+ @override
+ void visitText(Text node) {
+ writeTextNodeAsHtml(_str, node);
+ }
+
+ @override
+ void visitElement(Element node) {
+ final tag = node.localName;
+ _str.write('<<code class="markup element-name">$tag</code>');
+ if (node.attributes.isNotEmpty) {
+ node.attributes.forEach((key, v) {
+ v = htmlSerializeEscape(v, attributeMode: true);
+ _str.write(' <code class="markup attribute-name">$key</code>'
+ '=<code class="markup attribute-value">"$v"</code>');
+ });
+ }
+ if (node.nodes.isNotEmpty) {
+ _str.write('>');
+ visitChildren(node);
+ } else if (isVoidElement(tag)) {
+ _str.write('>');
+ return;
+ }
+ _str.write('</<code class="markup element-name">$tag</code>>');
+ }
+
+ @override
+ void visitComment(Comment node) {
+ final data = htmlSerializeEscape(node.data!);
+ _str.write('<code class="markup comment"><!--$data--></code>');
+ }
+}
+
+/// Returns true if this tag name is a void element.
+/// This method is useful to a pretty printer, because void elements must not
+/// have an end tag.
+/// See also: <http://dev.w3.org/html5/markup/syntax.html#void-elements>.
+bool isVoidElement(String? tagName) {
+ switch (tagName) {
+ case 'area':
+ case 'base':
+ case 'br':
+ case 'col':
+ case 'command':
+ case 'embed':
+ case 'hr':
+ case 'img':
+ case 'input':
+ case 'keygen':
+ case 'link':
+ case 'meta':
+ case 'param':
+ case 'source':
+ case 'track':
+ case 'wbr':
+ return true;
+ }
+ return false;
+}
+
+/// Serialize text node according to:
+/// <http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#html-fragment-serialization-algorithm>
+void writeTextNodeAsHtml(StringBuffer str, Text node) {
+ // Don't escape text for certain elements, notably <script>.
+ final parent = node.parentNode;
+ if (parent is Element) {
+ final tag = parent.localName;
+ if (rcdataElements.contains(tag) || tag == 'plaintext') {
+ str.write(node.data);
+ return;
+ }
+ }
+ str.write(htmlSerializeEscape(node.data));
+}
diff --git a/pkgs/html/lib/html_escape.dart b/pkgs/html/lib/html_escape.dart
new file mode 100644
index 0000000..b9c20c8
--- /dev/null
+++ b/pkgs/html/lib/html_escape.dart
@@ -0,0 +1,51 @@
+// TODO(jmesserly): reconcile this with dart:web htmlEscape.
+// This one might be more useful, as it is HTML5 spec compliant.
+/// Escapes [text] for use in the
+/// [HTML fragment serialization algorithm][1]. In particular, as described
+/// in the [specification][2]:
+///
+/// - Replace any occurrence of the `&` character by the string `&`.
+/// - Replace any occurrences of the U+00A0 NO-BREAK SPACE character by the
+/// string ` `.
+/// - If the algorithm was invoked in [attributeMode], replace any occurrences
+/// of the `"` character by the string `"`.
+/// - If the algorithm was not invoked in [attributeMode], replace any
+/// occurrences of the `<` character by the string `<`, and any occurrences
+/// of the `>` character by the string `>`.
+///
+/// [1]: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
+/// [2]: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString
+String htmlSerializeEscape(String text, {bool attributeMode = false}) {
+ // TODO(jmesserly): is it faster to build up a list of codepoints?
+ // StringBuffer seems cleaner assuming Dart can unbox 1-char strings.
+ StringBuffer? result;
+ for (var i = 0; i < text.length; i++) {
+ final ch = text[i];
+ String? replace;
+ switch (ch) {
+ case '&':
+ replace = '&';
+ break;
+ case '\u00A0' /*NO-BREAK SPACE*/ :
+ replace = ' ';
+ break;
+ case '"':
+ if (attributeMode) replace = '"';
+ break;
+ case '<':
+ if (!attributeMode) replace = '<';
+ break;
+ case '>':
+ if (!attributeMode) replace = '>';
+ break;
+ }
+ if (replace != null) {
+ result ??= StringBuffer(text.substring(0, i));
+ result.write(replace);
+ } else if (result != null) {
+ result.write(ch);
+ }
+ }
+
+ return result != null ? result.toString() : text;
+}
diff --git a/pkgs/html/lib/parser.dart b/pkgs/html/lib/parser.dart
new file mode 100644
index 0000000..0e89e66
--- /dev/null
+++ b/pkgs/html/lib/parser.dart
@@ -0,0 +1,3984 @@
+/// This library has a parser for HTML5 documents, that lets you parse HTML
+/// easily from a script or server side application:
+///
+/// import 'package:html/parser.dart' show parse;
+/// import 'package:html/dom.dart';
+/// main() {
+/// var document = parse(
+/// '<body>Hello world! <a href="www.html5rocks.com">HTML5 rocks!');
+/// print(document.outerHtml);
+/// }
+///
+/// The resulting document you get back has a DOM-like API for easy tree
+/// traversal and manipulation.
+library;
+
+import 'dart:collection';
+import 'dart:math';
+
+import 'package:source_span/source_span.dart';
+
+import 'dom.dart';
+import 'src/constants.dart';
+import 'src/encoding_parser.dart';
+import 'src/token.dart';
+import 'src/tokenizer.dart';
+import 'src/treebuilder.dart';
+import 'src/utils.dart';
+
+/// Parse an html5 document into a tree.
+///
+/// The [input] can be a `String`, a `List<int>` of bytes, or an
+/// [HtmlTokenizer].
+///
+/// If [input] is not a [HtmlTokenizer], you can optionally specify the file's
+/// [encoding], which must be a string. If specified that encoding will be
+/// used regardless of any BOM or later declaration (such as in a meta element).
+///
+/// Set [generateSpans] if you want to generate [SourceSpan]s, otherwise the
+/// [Node.sourceSpan] property will be `null`. When using [generateSpans] you
+/// can additionally pass [sourceUrl] to indicate where the [input] was
+/// extracted from.
+Document parse(dynamic input,
+ {String? encoding, bool generateSpans = false, String? sourceUrl}) {
+ final p = HtmlParser(input,
+ encoding: encoding, generateSpans: generateSpans, sourceUrl: sourceUrl);
+ return p.parse();
+}
+
+/// Parse an html5 document fragment into a tree.
+///
+/// The [input] can be a `String`, a `List<int>` of bytes, or an
+/// [HtmlTokenizer].
+/// The [container] element can optionally be specified, otherwise it defaults
+/// to "div".
+///
+/// If [input] is not a [HtmlTokenizer], you can optionally specify the file's
+/// [encoding], which must be a string. If specified, that encoding will be used,
+/// regardless of any BOM or later declaration (such as in a meta element).
+///
+/// Set [generateSpans] if you want to generate [SourceSpan]s, otherwise the
+/// [Node.sourceSpan] property will be `null`. When using [generateSpans] you can
+/// additionally pass [sourceUrl] to indicate where the [input] was extracted
+/// from.
+DocumentFragment parseFragment(dynamic input,
+ {String container = 'div',
+ String? encoding,
+ bool generateSpans = false,
+ String? sourceUrl}) {
+ final p = HtmlParser(input,
+ encoding: encoding, generateSpans: generateSpans, sourceUrl: sourceUrl);
+ return p.parseFragment(container);
+}
+
+/// Parser for HTML, which generates a tree structure from a stream of
+/// (possibly malformed) characters.
+class HtmlParser {
+ /// Raise an exception on the first error encountered.
+ final bool strict;
+
+ /// True to generate [SourceSpan]s for the [Node.sourceSpan] property.
+ final bool generateSpans;
+
+ final HtmlTokenizer tokenizer;
+
+ final TreeBuilder tree;
+
+ final List<ParseError> errors = <ParseError>[];
+
+ bool firstStartTag = false;
+
+ // TODO(jmesserly): use enum?
+ /// "quirks" / "limited quirks" / "no quirks"
+ String compatMode = 'no quirks';
+
+ /// innerHTML container when parsing document fragment.
+ String? innerHTML;
+
+ late Phase phase = _initialPhase;
+
+ Phase? originalPhase;
+
+ bool framesetOK = true;
+
+ // These fields hold the different phase singletons. At any given time one
+ // of them will be active.
+ late final _initialPhase = InitialPhase(this);
+ late final _beforeHtmlPhase = BeforeHtmlPhase(this);
+ late final _beforeHeadPhase = BeforeHeadPhase(this);
+ late final _inHeadPhase = InHeadPhase(this);
+ // TODO: html5lib did not implement the no script parsing mode
+ // More information here:
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#scripting-flag
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-inheadnoscript
+ // late final _inHeadNoscript = InHeadNoScriptPhase(this);
+ late final _afterHeadPhase = AfterHeadPhase(this);
+ late final _inBodyPhase = InBodyPhase(this);
+ late final _textPhase = TextPhase(this);
+ late final _inTablePhase = InTablePhase(this);
+ late final _inTableTextPhase = InTableTextPhase(this);
+ late final _inCaptionPhase = InCaptionPhase(this);
+ late final _inColumnGroupPhase = InColumnGroupPhase(this);
+ late final _inTableBodyPhase = InTableBodyPhase(this);
+ late final _inRowPhase = InRowPhase(this);
+ late final _inCellPhase = InCellPhase(this);
+ late final _inSelectPhase = InSelectPhase(this);
+ late final _inSelectInTablePhase = InSelectInTablePhase(this);
+ late final _inForeignContentPhase = InForeignContentPhase(this);
+ late final _afterBodyPhase = AfterBodyPhase(this);
+ late final _inFramesetPhase = InFramesetPhase(this);
+ late final _afterFramesetPhase = AfterFramesetPhase(this);
+ late final _afterAfterBodyPhase = AfterAfterBodyPhase(this);
+ late final _afterAfterFramesetPhase = AfterAfterFramesetPhase(this);
+
+ /// Create and configure an HtmlParser.
+ ///
+ /// The [input] can be a `String`, a `List<int>` of bytes, or an
+ /// [HtmlTokenizer].
+ ///
+ /// The [strict], [tree] builder, and [generateSpans] arguments configure
+ /// behavior for any type of input.
+ ///
+ /// If [input] is not a [HtmlTokenizer], you can specify a few more arguments.
+ ///
+ /// The [encoding] must be a string that indicates the encoding. If specified,
+ /// that encoding will be used, regardless of any BOM or later declaration
+ /// (such as in a meta element).
+ ///
+ /// Set [parseMeta] to false if you want to disable parsing the meta element.
+ ///
+ /// Set [lowercaseElementName] or [lowercaseAttrName] to false to disable the
+ /// automatic conversion of element and attribute names to lower case. Note
+ /// that standard way to parse HTML is to lowercase, which is what the browser
+ /// DOM will do if you request `Element.outerHTML`, for example.
+ HtmlParser(
+ dynamic input, {
+ TreeBuilder? tree,
+ this.strict = false,
+ this.generateSpans = false,
+ String? encoding,
+ bool parseMeta = true,
+ bool lowercaseElementName = true,
+ bool lowercaseAttrName = true,
+ String? sourceUrl,
+ }) : tree = tree ?? TreeBuilder(true),
+ tokenizer = input is HtmlTokenizer
+ ? input
+ : HtmlTokenizer(input,
+ encoding: encoding,
+ parseMeta: parseMeta,
+ lowercaseElementName: lowercaseElementName,
+ lowercaseAttrName: lowercaseAttrName,
+ generateSpans: generateSpans,
+ sourceUrl: sourceUrl) {
+ tokenizer.parser = this;
+ }
+
+ bool get innerHTMLMode => innerHTML != null;
+
+ /// Parse an html5 document into a tree.
+ ///
+ /// After parsing, [errors] will be populated with parse errors, if any.
+ Document parse() {
+ innerHTML = null;
+ _parse();
+ return tree.getDocument();
+ }
+
+ /// Parse an html5 document fragment into a tree.
+ ///
+ /// Pass a [container] to change the type of the containing element.
+ /// After parsing, [errors] will be populated with parse errors, if any.
+ DocumentFragment parseFragment([String container = 'div']) {
+ ArgumentError.checkNotNull(container, 'container');
+ innerHTML = container.toLowerCase();
+ _parse();
+ return tree.getFragment();
+ }
+
+ void _parse() {
+ reset();
+
+ while (true) {
+ try {
+ mainLoop();
+ break;
+ } on ReparseException catch (_) {
+ // Note: this happens if we start parsing but the character encoding
+ // changes. So we should only need to restart very early in the parse.
+ reset();
+ }
+ }
+ }
+
+ void reset() {
+ tokenizer.reset();
+
+ tree.reset();
+ firstStartTag = false;
+ errors.clear();
+ // "quirks" / "limited quirks" / "no quirks"
+ compatMode = 'no quirks';
+
+ if (innerHTMLMode) {
+ if (cdataElements.contains(innerHTML)) {
+ tokenizer.state = tokenizer.rcdataState;
+ } else if (rcdataElements.contains(innerHTML)) {
+ tokenizer.state = tokenizer.rawtextState;
+ } else if (innerHTML == 'plaintext') {
+ tokenizer.state = tokenizer.plaintextState;
+ } else {
+ // state already is data state
+ // tokenizer.state = tokenizer.dataState;
+ }
+ phase = _beforeHtmlPhase;
+ _beforeHtmlPhase.insertHtmlElement();
+ resetInsertionMode();
+ } else {
+ phase = _initialPhase;
+ }
+
+ framesetOK = true;
+ }
+
+ bool isHTMLIntegrationPoint(Element element) {
+ if (element.localName == 'annotation-xml' &&
+ element.namespaceUri == Namespaces.mathml) {
+ final enc = element.attributes['encoding']?.toAsciiLowerCase();
+ return enc == 'text/html' || enc == 'application/xhtml+xml';
+ } else {
+ return htmlIntegrationPointElements
+ .contains((element.namespaceUri, element.localName));
+ }
+ }
+
+ bool isMathMLTextIntegrationPoint(Element element) {
+ return mathmlTextIntegrationPointElements
+ .contains((element.namespaceUri, element.localName));
+ }
+
+ bool inForeignContent(Token token, int type) {
+ if (tree.openElements.isEmpty) return false;
+
+ final node = tree.openElements.last;
+ if (node.namespaceUri == tree.defaultNamespace) return false;
+
+ if (isMathMLTextIntegrationPoint(node)) {
+ if (type == TokenKind.startTag &&
+ (token as StartTagToken).name != 'mglyph' &&
+ token.name != 'malignmark') {
+ return false;
+ }
+ if (type == TokenKind.characters || type == TokenKind.spaceCharacters) {
+ return false;
+ }
+ }
+
+ if (node.localName == 'annotation-xml' &&
+ type == TokenKind.startTag &&
+ (token as StartTagToken).name == 'svg') {
+ return false;
+ }
+
+ if (isHTMLIntegrationPoint(node)) {
+ if (type == TokenKind.startTag ||
+ type == TokenKind.characters ||
+ type == TokenKind.spaceCharacters) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void mainLoop() {
+ while (tokenizer.moveNext()) {
+ final token = tokenizer.current;
+ Token? newToken = token;
+ int type;
+ while (newToken != null) {
+ type = newToken.kind;
+
+ // Note: avoid "is" test here, see http://dartbug.com/4795
+ if (type == TokenKind.parseError) {
+ final error = newToken as ParseErrorToken;
+ parseError(error.span, error.data, error.messageParams);
+ newToken = null;
+ } else {
+ var localPhase = phase;
+ if (inForeignContent(token, type)) {
+ localPhase = _inForeignContentPhase;
+ }
+
+ switch (type) {
+ case TokenKind.characters:
+ newToken =
+ localPhase.processCharacters(newToken as CharactersToken);
+ break;
+ case TokenKind.spaceCharacters:
+ newToken = localPhase
+ .processSpaceCharacters(newToken as SpaceCharactersToken);
+ break;
+ case TokenKind.startTag:
+ newToken = localPhase.processStartTag(newToken as StartTagToken);
+ break;
+ case TokenKind.endTag:
+ newToken = localPhase.processEndTag(newToken as EndTagToken);
+ break;
+ case TokenKind.comment:
+ newToken = localPhase.processComment(newToken as CommentToken);
+ break;
+ case TokenKind.doctype:
+ newToken = localPhase.processDoctype(newToken as DoctypeToken);
+ break;
+ }
+ }
+ }
+
+ if (token is StartTagToken) {
+ if (token.selfClosing && !token.selfClosingAcknowledged) {
+ parseError(token.span, 'non-void-element-with-trailing-solidus',
+ {'name': token.name});
+ }
+ }
+ }
+
+ // When the loop finishes it's EOF
+ var reprocess = true;
+ final reprocessPhases = <Phase>[];
+ while (reprocess) {
+ reprocessPhases.add(phase);
+ reprocess = phase.processEOF();
+ if (reprocess) {
+ assert(!reprocessPhases.contains(phase));
+ }
+ }
+ }
+
+ /// The last span available. Used for EOF errors if we don't have something
+ /// better.
+ SourceSpan? get _lastSpan => tokenizer.stream.fileInfo
+ ?.location(tokenizer.stream.position)
+ .pointSpan();
+
+ void parseError(SourceSpan? span, String errorcode,
+ [Map<String, Object?>? datavars = const {}]) {
+ if (!generateSpans && span == null) {
+ span = _lastSpan;
+ }
+
+ final err = ParseError(errorcode, span, datavars);
+ errors.add(err);
+ if (strict) throw err;
+ }
+
+ void adjustMathMLAttributes(StartTagToken token) {
+ final orig = token.data.remove('definitionurl');
+ if (orig != null) {
+ token.data['definitionURL'] = orig;
+ }
+ }
+
+ void adjustSVGAttributes(StartTagToken token) {
+ final replacements = const {
+ 'attributename': 'attributeName',
+ 'attributetype': 'attributeType',
+ 'basefrequency': 'baseFrequency',
+ 'baseprofile': 'baseProfile',
+ 'calcmode': 'calcMode',
+ 'clippathunits': 'clipPathUnits',
+ 'contentscripttype': 'contentScriptType',
+ 'contentstyletype': 'contentStyleType',
+ 'diffuseconstant': 'diffuseConstant',
+ 'edgemode': 'edgeMode',
+ 'externalresourcesrequired': 'externalResourcesRequired',
+ 'filterres': 'filterRes',
+ 'filterunits': 'filterUnits',
+ 'glyphref': 'glyphRef',
+ 'gradienttransform': 'gradientTransform',
+ 'gradientunits': 'gradientUnits',
+ 'kernelmatrix': 'kernelMatrix',
+ 'kernelunitlength': 'kernelUnitLength',
+ 'keypoints': 'keyPoints',
+ 'keysplines': 'keySplines',
+ 'keytimes': 'keyTimes',
+ 'lengthadjust': 'lengthAdjust',
+ 'limitingconeangle': 'limitingConeAngle',
+ 'markerheight': 'markerHeight',
+ 'markerunits': 'markerUnits',
+ 'markerwidth': 'markerWidth',
+ 'maskcontentunits': 'maskContentUnits',
+ 'maskunits': 'maskUnits',
+ 'numoctaves': 'numOctaves',
+ 'pathlength': 'pathLength',
+ 'patterncontentunits': 'patternContentUnits',
+ 'patterntransform': 'patternTransform',
+ 'patternunits': 'patternUnits',
+ 'pointsatx': 'pointsAtX',
+ 'pointsaty': 'pointsAtY',
+ 'pointsatz': 'pointsAtZ',
+ 'preservealpha': 'preserveAlpha',
+ 'preserveaspectratio': 'preserveAspectRatio',
+ 'primitiveunits': 'primitiveUnits',
+ 'refx': 'refX',
+ 'refy': 'refY',
+ 'repeatcount': 'repeatCount',
+ 'repeatdur': 'repeatDur',
+ 'requiredextensions': 'requiredExtensions',
+ 'requiredfeatures': 'requiredFeatures',
+ 'specularconstant': 'specularConstant',
+ 'specularexponent': 'specularExponent',
+ 'spreadmethod': 'spreadMethod',
+ 'startoffset': 'startOffset',
+ 'stddeviation': 'stdDeviation',
+ 'stitchtiles': 'stitchTiles',
+ 'surfacescale': 'surfaceScale',
+ 'systemlanguage': 'systemLanguage',
+ 'tablevalues': 'tableValues',
+ 'targetx': 'targetX',
+ 'targety': 'targetY',
+ 'textlength': 'textLength',
+ 'viewbox': 'viewBox',
+ 'viewtarget': 'viewTarget',
+ 'xchannelselector': 'xChannelSelector',
+ 'ychannelselector': 'yChannelSelector',
+ 'zoomandpan': 'zoomAndPan'
+ };
+ for (var originalName in token.data.keys.toList(growable: false)) {
+ final svgName = replacements[originalName as String];
+ if (svgName != null) {
+ token.data[svgName] = token.data.remove(originalName)!;
+ }
+ }
+ }
+
+ void adjustForeignAttributes(StartTagToken token) {
+ // TODO(jmesserly): I don't like mixing non-string objects with strings in
+ // the Node.attributes Map. Is there another solution?
+ final replacements = const {
+ 'xlink:actuate': AttributeName('xlink', 'actuate', Namespaces.xlink),
+ 'xlink:arcrole': AttributeName('xlink', 'arcrole', Namespaces.xlink),
+ 'xlink:href': AttributeName('xlink', 'href', Namespaces.xlink),
+ 'xlink:role': AttributeName('xlink', 'role', Namespaces.xlink),
+ 'xlink:show': AttributeName('xlink', 'show', Namespaces.xlink),
+ 'xlink:title': AttributeName('xlink', 'title', Namespaces.xlink),
+ 'xlink:type': AttributeName('xlink', 'type', Namespaces.xlink),
+ 'xml:base': AttributeName('xml', 'base', Namespaces.xml),
+ 'xml:lang': AttributeName('xml', 'lang', Namespaces.xml),
+ 'xml:space': AttributeName('xml', 'space', Namespaces.xml),
+ 'xmlns': AttributeName(null, 'xmlns', Namespaces.xmlns),
+ 'xmlns:xlink': AttributeName('xmlns', 'xlink', Namespaces.xmlns)
+ };
+
+ for (var originalName in token.data.keys.toList(growable: false)) {
+ final foreignName = replacements[originalName as String];
+ if (foreignName != null) {
+ token.data[foreignName] = token.data.remove(originalName)!;
+ }
+ }
+ }
+
+ void resetInsertionMode() {
+ // The name of this method is mostly historical. (It's also used in the
+ // specification.)
+ for (var node in tree.openElements.reversed) {
+ var nodeName = node.localName;
+ final last = node == tree.openElements[0];
+ if (last) {
+ assert(innerHTMLMode);
+ nodeName = innerHTML;
+ }
+ // Check for conditions that should only happen in the innerHTML
+ // case
+ switch (nodeName) {
+ case 'select':
+ case 'colgroup':
+ case 'head':
+ case 'html':
+ assert(innerHTMLMode);
+ break;
+ }
+ if (!last && node.namespaceUri != tree.defaultNamespace) {
+ continue;
+ }
+ switch (nodeName) {
+ case 'select':
+ phase = _inSelectPhase;
+ return;
+ case 'td':
+ phase = _inCellPhase;
+ return;
+ case 'th':
+ phase = _inCellPhase;
+ return;
+ case 'tr':
+ phase = _inRowPhase;
+ return;
+ case 'tbody':
+ phase = _inTableBodyPhase;
+ return;
+ case 'thead':
+ phase = _inTableBodyPhase;
+ return;
+ case 'tfoot':
+ phase = _inTableBodyPhase;
+ return;
+ case 'caption':
+ phase = _inCaptionPhase;
+ return;
+ case 'colgroup':
+ phase = _inColumnGroupPhase;
+ return;
+ case 'table':
+ phase = _inTablePhase;
+ return;
+ case 'head':
+ phase = _inBodyPhase;
+ return;
+ case 'body':
+ phase = _inBodyPhase;
+ return;
+ case 'frameset':
+ phase = _inFramesetPhase;
+ return;
+ case 'html':
+ phase = _beforeHeadPhase;
+ return;
+ }
+ }
+ phase = _inBodyPhase;
+ }
+
+ /// Generic RCDATA/RAWTEXT Parsing algorithm
+ /// [contentType] - RCDATA or RAWTEXT
+ void parseRCDataRawtext(Token token, String contentType) {
+ assert(contentType == 'RAWTEXT' || contentType == 'RCDATA');
+
+ tree.insertElement(token as StartTagToken);
+
+ if (contentType == 'RAWTEXT') {
+ tokenizer.state = tokenizer.rawtextState;
+ } else {
+ tokenizer.state = tokenizer.rcdataState;
+ }
+
+ originalPhase = phase;
+ phase = _textPhase;
+ }
+}
+
+/// Base class for helper object that implements each phase of processing.
+class Phase {
+ // Order should be (they can be omitted):
+ // * EOF
+ // * Comment
+ // * Doctype
+ // * SpaceCharacters
+ // * Characters
+ // * StartTag
+ // - startTag* methods
+ // * EndTag
+ // - endTag* methods
+
+ final HtmlParser parser;
+
+ final TreeBuilder tree;
+
+ Phase(this.parser) : tree = parser.tree;
+
+ bool processEOF() {
+ throw UnimplementedError();
+ }
+
+ Token? processComment(CommentToken token) {
+ // For most phases the following is correct. Where it's not it will be
+ // overridden.
+ tree.insertComment(token, tree.openElements.last);
+ return null;
+ }
+
+ Token? processDoctype(DoctypeToken token) {
+ parser.parseError(token.span, 'unexpected-doctype');
+ return null;
+ }
+
+ Token? processCharacters(CharactersToken token) {
+ tree.insertText(token.data, token.span);
+ return null;
+ }
+
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ tree.insertText(token.data, token.span);
+ return null;
+ }
+
+ Token? processStartTag(StartTagToken token) {
+ throw UnimplementedError();
+ }
+
+ Token? startTagHtml(StartTagToken token) {
+ if (parser.firstStartTag == false && token.name == 'html') {
+ parser.parseError(token.span, 'non-html-root');
+ }
+ // XXX Need a check here to see if the first start tag token emitted is
+ // this token... If it's not, invoke parser.parseError().
+ tree.openElements[0].sourceSpan = token.span;
+ token.data.forEach((attr, value) {
+ tree.openElements[0].attributes.putIfAbsent(attr, () => value);
+ });
+ parser.firstStartTag = false;
+ return null;
+ }
+
+ Token? processEndTag(EndTagToken token) {
+ throw UnimplementedError();
+ }
+
+ /// Helper method for popping openElements.
+ void popOpenElementsUntil(EndTagToken token) {
+ final name = token.name;
+ var node = tree.openElements.removeLast();
+ while (node.localName != name) {
+ node = tree.openElements.removeLast();
+ }
+ node.endSourceSpan = token.span;
+ }
+}
+
+class InitialPhase extends Phase {
+ InitialPhase(super.parser);
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ return null;
+ }
+
+ @override
+ Token? processComment(CommentToken token) {
+ tree.insertComment(token, tree.document);
+ return null;
+ }
+
+ @override
+ Token? processDoctype(DoctypeToken token) {
+ final name = token.name;
+ var publicId = token.publicId?.toAsciiLowerCase();
+ final systemId = token.systemId;
+ final correct = token.correct;
+
+ if (name != 'html' ||
+ publicId != null ||
+ systemId != null && systemId != 'about:legacy-compat') {
+ parser.parseError(token.span, 'unknown-doctype');
+ }
+
+ publicId ??= '';
+
+ tree.insertDoctype(token);
+
+ if (!correct ||
+ token.name != 'html' ||
+ startsWithAny(publicId, const [
+ '+//silmaril//dtd html pro v0r11 19970101//',
+ '-//advasoft ltd//dtd html 3.0 aswedit + extensions//',
+ '-//as//dtd html 3.0 aswedit + extensions//',
+ '-//ietf//dtd html 2.0 level 1//',
+ '-//ietf//dtd html 2.0 level 2//',
+ '-//ietf//dtd html 2.0 strict level 1//',
+ '-//ietf//dtd html 2.0 strict level 2//',
+ '-//ietf//dtd html 2.0 strict//',
+ '-//ietf//dtd html 2.0//',
+ '-//ietf//dtd html 2.1e//',
+ '-//ietf//dtd html 3.0//',
+ '-//ietf//dtd html 3.2 final//',
+ '-//ietf//dtd html 3.2//',
+ '-//ietf//dtd html 3//',
+ '-//ietf//dtd html level 0//',
+ '-//ietf//dtd html level 1//',
+ '-//ietf//dtd html level 2//',
+ '-//ietf//dtd html level 3//',
+ '-//ietf//dtd html strict level 0//',
+ '-//ietf//dtd html strict level 1//',
+ '-//ietf//dtd html strict level 2//',
+ '-//ietf//dtd html strict level 3//',
+ '-//ietf//dtd html strict//',
+ '-//ietf//dtd html//',
+ '-//metrius//dtd metrius presentational//',
+ '-//microsoft//dtd internet explorer 2.0 html strict//',
+ '-//microsoft//dtd internet explorer 2.0 html//',
+ '-//microsoft//dtd internet explorer 2.0 tables//',
+ '-//microsoft//dtd internet explorer 3.0 html strict//',
+ '-//microsoft//dtd internet explorer 3.0 html//',
+ '-//microsoft//dtd internet explorer 3.0 tables//',
+ '-//netscape comm. corp.//dtd html//',
+ '-//netscape comm. corp.//dtd strict html//',
+ "-//o'reilly and associates//dtd html 2.0//",
+ "-//o'reilly and associates//dtd html extended 1.0//",
+ "-//o'reilly and associates//dtd html extended relaxed 1.0//",
+ '-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//',
+ '-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//',
+ '-//spyglass//dtd html 2.0 extended//',
+ '-//sq//dtd html 2.0 hotmetal + extensions//',
+ '-//sun microsystems corp.//dtd hotjava html//',
+ '-//sun microsystems corp.//dtd hotjava strict html//',
+ '-//w3c//dtd html 3 1995-03-24//',
+ '-//w3c//dtd html 3.2 draft//',
+ '-//w3c//dtd html 3.2 final//',
+ '-//w3c//dtd html 3.2//',
+ '-//w3c//dtd html 3.2s draft//',
+ '-//w3c//dtd html 4.0 frameset//',
+ '-//w3c//dtd html 4.0 transitional//',
+ '-//w3c//dtd html experimental 19960712//',
+ '-//w3c//dtd html experimental 970421//',
+ '-//w3c//dtd w3 html//',
+ '-//w3o//dtd w3 html 3.0//',
+ '-//webtechs//dtd mozilla html 2.0//',
+ '-//webtechs//dtd mozilla html//'
+ ]) ||
+ const [
+ '-//w3o//dtd w3 html strict 3.0//en//',
+ '-/w3c/dtd html 4.0 transitional/en',
+ 'html'
+ ].contains(publicId) ||
+ startsWithAny(publicId, const [
+ '-//w3c//dtd html 4.01 frameset//',
+ '-//w3c//dtd html 4.01 transitional//'
+ ]) &&
+ systemId == null ||
+ systemId != null &&
+ systemId.toLowerCase() ==
+ 'http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd') {
+ parser.compatMode = 'quirks';
+ } else if (startsWithAny(publicId, const [
+ '-//w3c//dtd xhtml 1.0 frameset//',
+ '-//w3c//dtd xhtml 1.0 transitional//'
+ ]) ||
+ startsWithAny(publicId, const [
+ '-//w3c//dtd html 4.01 frameset//',
+ '-//w3c//dtd html 4.01 transitional//'
+ ]) &&
+ systemId != null) {
+ parser.compatMode = 'limited quirks';
+ }
+ parser.phase = parser._beforeHtmlPhase;
+ return null;
+ }
+
+ void anythingElse() {
+ parser.compatMode = 'quirks';
+ parser.phase = parser._beforeHtmlPhase;
+ }
+
+ @override
+ Token processCharacters(CharactersToken token) {
+ parser.parseError(token.span, 'expected-doctype-but-got-chars');
+ anythingElse();
+ return token;
+ }
+
+ @override
+ Token processStartTag(StartTagToken token) {
+ parser.parseError(
+ token.span, 'expected-doctype-but-got-start-tag', {'name': token.name});
+ anythingElse();
+ return token;
+ }
+
+ @override
+ Token processEndTag(EndTagToken token) {
+ parser.parseError(
+ token.span, 'expected-doctype-but-got-end-tag', {'name': token.name});
+ anythingElse();
+ return token;
+ }
+
+ @override
+ bool processEOF() {
+ parser.parseError(parser._lastSpan, 'expected-doctype-but-got-eof');
+ anythingElse();
+ return true;
+ }
+}
+
+class BeforeHtmlPhase extends Phase {
+ BeforeHtmlPhase(super.parser);
+
+ // helper methods
+ void insertHtmlElement() {
+ tree.insertRoot(
+ StartTagToken('html', data: LinkedHashMap<Object, String>()));
+ parser.phase = parser._beforeHeadPhase;
+ }
+
+ // other
+ @override
+ bool processEOF() {
+ insertHtmlElement();
+ return true;
+ }
+
+ @override
+ Token? processComment(CommentToken token) {
+ tree.insertComment(token, tree.document);
+ return null;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ return null;
+ }
+
+ @override
+ Token processCharacters(CharactersToken token) {
+ insertHtmlElement();
+ return token;
+ }
+
+ @override
+ @override
+ Token processStartTag(StartTagToken token) {
+ if (token.name == 'html') {
+ parser.firstStartTag = true;
+ }
+ insertHtmlElement();
+ return token;
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'head':
+ case 'body':
+ case 'html':
+ case 'br':
+ insertHtmlElement();
+ return token;
+ default:
+ parser.parseError(
+ token.span, 'unexpected-end-tag-before-html', {'name': token.name});
+ return null;
+ }
+ }
+}
+
+class BeforeHeadPhase extends Phase {
+ BeforeHeadPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'head':
+ startTagHead(token);
+ return null;
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'head':
+ case 'body':
+ case 'html':
+ case 'br':
+ return endTagImplyHead(token);
+ default:
+ endTagOther(token);
+ return null;
+ }
+ }
+
+ @override
+ bool processEOF() {
+ startTagHead(StartTagToken('head', data: LinkedHashMap<Object, String>()));
+ return true;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ return null;
+ }
+
+ @override
+ Token processCharacters(CharactersToken token) {
+ startTagHead(StartTagToken('head', data: LinkedHashMap<Object, String>()));
+ return token;
+ }
+
+ @override
+ Token? startTagHtml(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ void startTagHead(StartTagToken token) {
+ tree.insertElement(token);
+ tree.headPointer = tree.openElements.last;
+ parser.phase = parser._inHeadPhase;
+ }
+
+ Token startTagOther(StartTagToken token) {
+ startTagHead(StartTagToken('head', data: LinkedHashMap<Object, String>()));
+ return token;
+ }
+
+ Token endTagImplyHead(EndTagToken token) {
+ startTagHead(StartTagToken('head', data: LinkedHashMap<Object, String>()));
+ return token;
+ }
+
+ void endTagOther(EndTagToken token) {
+ parser.parseError(
+ token.span, 'end-tag-after-implied-root', {'name': token.name});
+ }
+}
+
+class InHeadPhase extends Phase {
+ InHeadPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'title':
+ startTagTitle(token);
+ return null;
+ case 'noscript':
+ case 'noframes':
+ case 'style':
+ startTagNoScriptNoFramesStyle(token);
+ return null;
+ case 'script':
+ startTagScript(token);
+ return null;
+ case 'base':
+ case 'basefont':
+ case 'bgsound':
+ case 'command':
+ case 'link':
+ startTagBaseLinkCommand(token);
+ return null;
+ case 'meta':
+ startTagMeta(token);
+ return null;
+ case 'head':
+ startTagHead(token);
+ return null;
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'head':
+ endTagHead(token);
+ return null;
+ case 'br':
+ case 'html':
+ case 'body':
+ return endTagHtmlBodyBr(token);
+ default:
+ endTagOther(token);
+ return null;
+ }
+ }
+
+ // the real thing
+ @override
+ bool processEOF() {
+ anythingElse();
+ return true;
+ }
+
+ @override
+ Token processCharacters(CharactersToken token) {
+ anythingElse();
+ return token;
+ }
+
+ @override
+ Token? startTagHtml(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ void startTagHead(StartTagToken token) {
+ parser.parseError(token.span, 'two-heads-are-not-better-than-one');
+ }
+
+ void startTagBaseLinkCommand(StartTagToken token) {
+ tree.insertElement(token);
+ tree.openElements.removeLast();
+ token.selfClosingAcknowledged = true;
+ }
+
+ void startTagMeta(StartTagToken token) {
+ tree.insertElement(token);
+ tree.openElements.removeLast();
+ token.selfClosingAcknowledged = true;
+
+ final attributes = token.data;
+ if (!parser.tokenizer.stream.charEncodingCertain) {
+ final charset = attributes['charset'];
+ final content = attributes['content'];
+ if (charset != null) {
+ parser.tokenizer.stream.changeEncoding(charset);
+ } else if (content != null) {
+ final data = EncodingBytes(content);
+ final codec = ContentAttrParser(data).parse();
+ parser.tokenizer.stream.changeEncoding(codec);
+ }
+ }
+ }
+
+ void startTagTitle(StartTagToken token) {
+ parser.parseRCDataRawtext(token, 'RCDATA');
+ }
+
+ void startTagNoScriptNoFramesStyle(StartTagToken token) {
+ // Need to decide whether to implement the scripting-disabled case
+ parser.parseRCDataRawtext(token, 'RAWTEXT');
+ }
+
+ void startTagScript(StartTagToken token) {
+ tree.insertElement(token);
+ parser.tokenizer.state = parser.tokenizer.scriptDataState;
+ parser.originalPhase = parser.phase;
+ parser.phase = parser._textPhase;
+ }
+
+ Token startTagOther(StartTagToken token) {
+ anythingElse();
+ return token;
+ }
+
+ void endTagHead(EndTagToken token) {
+ final node = parser.tree.openElements.removeLast();
+ assert(node.localName == 'head');
+ node.endSourceSpan = token.span;
+ parser.phase = parser._afterHeadPhase;
+ }
+
+ Token endTagHtmlBodyBr(EndTagToken token) {
+ anythingElse();
+ return token;
+ }
+
+ void endTagOther(EndTagToken token) {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+ }
+
+ void anythingElse() {
+ endTagHead(EndTagToken('head'));
+ }
+}
+
+// XXX If we implement a parser for which scripting is disabled we need to
+// implement this phase.
+//
+// class InHeadNoScriptPhase extends Phase {
+
+class AfterHeadPhase extends Phase {
+ AfterHeadPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'body':
+ startTagBody(token);
+ return null;
+ case 'frameset':
+ startTagFrameset(token);
+ return null;
+ case 'base':
+ case 'basefont':
+ case 'bgsound':
+ case 'link':
+ case 'meta':
+ case 'noframes':
+ case 'script':
+ case 'style':
+ case 'title':
+ startTagFromHead(token);
+ return null;
+ case 'head':
+ startTagHead(token);
+ return null;
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'body':
+ case 'html':
+ case 'br':
+ return endTagHtmlBodyBr(token);
+ default:
+ endTagOther(token);
+ return null;
+ }
+ }
+
+ @override
+ bool processEOF() {
+ anythingElse();
+ return true;
+ }
+
+ @override
+ Token processCharacters(CharactersToken token) {
+ anythingElse();
+ return token;
+ }
+
+ @override
+ Token? startTagHtml(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ void startTagBody(StartTagToken token) {
+ parser.framesetOK = false;
+ tree.insertElement(token);
+ parser.phase = parser._inBodyPhase;
+ }
+
+ void startTagFrameset(StartTagToken token) {
+ tree.insertElement(token);
+ parser.phase = parser._inFramesetPhase;
+ }
+
+ void startTagFromHead(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-start-tag-out-of-my-head',
+ {'name': token.name});
+ tree.openElements.add(tree.headPointer as Element);
+ parser._inHeadPhase.processStartTag(token);
+ for (var node in tree.openElements.reversed) {
+ if (node.localName == 'head') {
+ tree.openElements.remove(node);
+ break;
+ }
+ }
+ }
+
+ void startTagHead(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-start-tag', {'name': token.name});
+ }
+
+ Token startTagOther(StartTagToken token) {
+ anythingElse();
+ return token;
+ }
+
+ Token endTagHtmlBodyBr(EndTagToken token) {
+ anythingElse();
+ return token;
+ }
+
+ void endTagOther(EndTagToken token) {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+ }
+
+ void anythingElse() {
+ tree.insertElement(
+ StartTagToken('body', data: LinkedHashMap<Object, String>()));
+ parser.phase = parser._inBodyPhase;
+ parser.framesetOK = true;
+ }
+}
+
+typedef TokenProccessor = Token Function(Token token);
+
+class InBodyPhase extends Phase {
+ bool dropNewline = false;
+
+ // http://www.whatwg.org/specs/web-apps/current-work///parsing-main-inbody
+ // the really-really-really-very crazy mode
+ InBodyPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'base':
+ case 'basefont':
+ case 'bgsound':
+ case 'command':
+ case 'link':
+ case 'meta':
+ case 'noframes':
+ case 'script':
+ case 'style':
+ case 'title':
+ return startTagProcessInHead(token);
+ case 'body':
+ startTagBody(token);
+ return null;
+ case 'frameset':
+ startTagFrameset(token);
+ return null;
+ case 'address':
+ case 'article':
+ case 'aside':
+ case 'blockquote':
+ case 'center':
+ case 'details':
+ case 'dir':
+ case 'div':
+ case 'dl':
+ case 'fieldset':
+ case 'figcaption':
+ case 'figure':
+ case 'footer':
+ case 'header':
+ case 'hgroup':
+ case 'menu':
+ case 'nav':
+ case 'ol':
+ case 'p':
+ case 'section':
+ case 'summary':
+ case 'ul':
+ startTagCloseP(token);
+ return null;
+ // headingElements
+ case 'h1':
+ case 'h2':
+ case 'h3':
+ case 'h4':
+ case 'h5':
+ case 'h6':
+ startTagHeading(token);
+ return null;
+ case 'pre':
+ case 'listing':
+ startTagPreListing(token);
+ return null;
+ case 'form':
+ startTagForm(token);
+ return null;
+ case 'li':
+ case 'dd':
+ case 'dt':
+ startTagListItem(token);
+ return null;
+ case 'plaintext':
+ startTagPlaintext(token);
+ return null;
+ case 'a':
+ startTagA(token);
+ return null;
+ case 'b':
+ case 'big':
+ case 'code':
+ case 'em':
+ case 'font':
+ case 'i':
+ case 's':
+ case 'small':
+ case 'strike':
+ case 'strong':
+ case 'tt':
+ case 'u':
+ startTagFormatting(token);
+ return null;
+ case 'nobr':
+ startTagNobr(token);
+ return null;
+ case 'button':
+ return startTagButton(token);
+ case 'applet':
+ case 'marquee':
+ case 'object':
+ startTagAppletMarqueeObject(token);
+ return null;
+ case 'xmp':
+ startTagXmp(token);
+ return null;
+ case 'table':
+ startTagTable(token);
+ return null;
+ case 'area':
+ case 'br':
+ case 'embed':
+ case 'img':
+ case 'keygen':
+ case 'wbr':
+ startTagVoidFormatting(token);
+ return null;
+ case 'param':
+ case 'source':
+ case 'track':
+ startTagParamSource(token);
+ return null;
+ case 'input':
+ startTagInput(token);
+ return null;
+ case 'hr':
+ startTagHr(token);
+ return null;
+ case 'image':
+ startTagImage(token);
+ return null;
+ case 'isindex':
+ startTagIsIndex(token);
+ return null;
+ case 'textarea':
+ startTagTextarea(token);
+ return null;
+ case 'iframe':
+ startTagIFrame(token);
+ return null;
+ case 'noembed':
+ case 'noscript':
+ startTagRawtext(token);
+ return null;
+ case 'select':
+ startTagSelect(token);
+ return null;
+ case 'rp':
+ case 'rt':
+ startTagRpRt(token);
+ return null;
+ case 'option':
+ case 'optgroup':
+ startTagOpt(token);
+ return null;
+ case 'math':
+ startTagMath(token);
+ return null;
+ case 'svg':
+ startTagSvg(token);
+ return null;
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'frame':
+ case 'head':
+ case 'tbody':
+ case 'td':
+ case 'tfoot':
+ case 'th':
+ case 'thead':
+ case 'tr':
+ startTagMisplaced(token);
+ return null;
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'body':
+ endTagBody(token);
+ return null;
+ case 'html':
+ return endTagHtml(token);
+ case 'address':
+ case 'article':
+ case 'aside':
+ case 'blockquote':
+ case 'button':
+ case 'center':
+ case 'details':
+ case 'dir':
+ case 'div':
+ case 'dl':
+ case 'fieldset':
+ case 'figcaption':
+ case 'figure':
+ case 'footer':
+ case 'header':
+ case 'hgroup':
+ case 'listing':
+ case 'menu':
+ case 'nav':
+ case 'ol':
+ case 'pre':
+ case 'section':
+ case 'summary':
+ case 'ul':
+ endTagBlock(token);
+ return null;
+ case 'form':
+ endTagForm(token);
+ return null;
+ case 'p':
+ endTagP(token);
+ return null;
+ case 'dd':
+ case 'dt':
+ case 'li':
+ endTagListItem(token);
+ return null;
+ // headingElements
+ case 'h1':
+ case 'h2':
+ case 'h3':
+ case 'h4':
+ case 'h5':
+ case 'h6':
+ endTagHeading(token);
+ return null;
+ case 'a':
+ case 'b':
+ case 'big':
+ case 'code':
+ case 'em':
+ case 'font':
+ case 'i':
+ case 'nobr':
+ case 's':
+ case 'small':
+ case 'strike':
+ case 'strong':
+ case 'tt':
+ case 'u':
+ endTagFormatting(token);
+ return null;
+ case 'applet':
+ case 'marquee':
+ case 'object':
+ endTagAppletMarqueeObject(token);
+ return null;
+ case 'br':
+ endTagBr(token);
+ return null;
+ default:
+ endTagOther(token);
+ return null;
+ }
+ }
+
+ bool isMatchingFormattingElement(Element node1, Element node2) {
+ if (node1.localName != node2.localName ||
+ node1.namespaceUri != node2.namespaceUri) {
+ return false;
+ } else if (node1.attributes.length != node2.attributes.length) {
+ return false;
+ } else {
+ for (var key in node1.attributes.keys) {
+ if (node1.attributes[key] != node2.attributes[key]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ // helper
+ void addFormattingElement(StartTagToken token) {
+ tree.insertElement(token);
+ final element = tree.openElements.last;
+
+ final matchingElements = <Node?>[];
+ for (Node? node in tree.activeFormattingElements.reversed) {
+ if (node == null) {
+ break;
+ } else if (isMatchingFormattingElement(node as Element, element)) {
+ matchingElements.add(node);
+ }
+ }
+
+ assert(matchingElements.length <= 3);
+ if (matchingElements.length == 3) {
+ tree.activeFormattingElements.remove(matchingElements.last);
+ }
+ tree.activeFormattingElements.add(element);
+ }
+
+ // the real deal
+ @override
+ bool processEOF() {
+ for (var node in tree.openElements.reversed) {
+ switch (node.localName) {
+ case 'dd':
+ case 'dt':
+ case 'li':
+ case 'p':
+ case 'tbody':
+ case 'td':
+ case 'tfoot':
+ case 'th':
+ case 'thead':
+ case 'tr':
+ case 'body':
+ case 'html':
+ continue;
+ }
+ parser.parseError(node.sourceSpan, 'expected-closing-tag-but-got-eof');
+ break;
+ }
+ //Stop parsing
+ return false;
+ }
+
+ void processSpaceCharactersDropNewline(StringToken token) {
+ // Sometimes (start of <pre>, <listing>, and <textarea> blocks) we
+ // want to drop leading newlines
+ var data = token.data;
+ dropNewline = false;
+ if (data.startsWith('\n')) {
+ final lastOpen = tree.openElements.last;
+ if (const ['pre', 'listing', 'textarea'].contains(lastOpen.localName) &&
+ !lastOpen.hasContent()) {
+ data = data.substring(1);
+ }
+ }
+ if (data.isNotEmpty) {
+ tree.reconstructActiveFormattingElements();
+ tree.insertText(data, token.span);
+ }
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ if (token.data == '\u0000') {
+ //The tokenizer should always emit null on its own
+ return null;
+ }
+ tree.reconstructActiveFormattingElements();
+ tree.insertText(token.data, token.span);
+ if (parser.framesetOK && !allWhitespace(token.data)) {
+ parser.framesetOK = false;
+ }
+ return null;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ if (dropNewline) {
+ processSpaceCharactersDropNewline(token);
+ } else {
+ tree.reconstructActiveFormattingElements();
+ tree.insertText(token.data, token.span);
+ }
+ return null;
+ }
+
+ Token? startTagProcessInHead(StartTagToken token) {
+ return parser._inHeadPhase.processStartTag(token);
+ }
+
+ void startTagBody(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-start-tag', {'name': 'body'});
+ if (tree.openElements.length == 1 ||
+ tree.openElements[1].localName != 'body') {
+ assert(parser.innerHTMLMode);
+ } else {
+ parser.framesetOK = false;
+ token.data.forEach((attr, value) {
+ tree.openElements[1].attributes.putIfAbsent(attr, () => value);
+ });
+ }
+ }
+
+ void startTagFrameset(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-start-tag', {'name': 'frameset'});
+ if (tree.openElements.length == 1 ||
+ tree.openElements[1].localName != 'body') {
+ assert(parser.innerHTMLMode);
+ } else if (parser.framesetOK) {
+ if (tree.openElements[1].parentNode != null) {
+ tree.openElements[1].parentNode!.nodes.remove(tree.openElements[1]);
+ }
+ while (tree.openElements.last.localName != 'html') {
+ tree.openElements.removeLast();
+ }
+ tree.insertElement(token);
+ parser.phase = parser._inFramesetPhase;
+ }
+ }
+
+ void startTagCloseP(StartTagToken token) {
+ if (tree.elementInScope('p', variant: 'button')) {
+ endTagP(EndTagToken('p'));
+ }
+ tree.insertElement(token);
+ }
+
+ void startTagPreListing(StartTagToken token) {
+ if (tree.elementInScope('p', variant: 'button')) {
+ endTagP(EndTagToken('p'));
+ }
+ tree.insertElement(token);
+ parser.framesetOK = false;
+ dropNewline = true;
+ }
+
+ void startTagForm(StartTagToken token) {
+ if (tree.formPointer != null) {
+ parser.parseError(token.span, 'unexpected-start-tag', {'name': 'form'});
+ } else {
+ if (tree.elementInScope('p', variant: 'button')) {
+ endTagP(EndTagToken('p'));
+ }
+ tree.insertElement(token);
+ tree.formPointer = tree.openElements.last;
+ }
+ }
+
+ void startTagListItem(StartTagToken token) {
+ parser.framesetOK = false;
+
+ final stopNamesMap = const {
+ 'li': ['li'],
+ 'dt': ['dt', 'dd'],
+ 'dd': ['dt', 'dd']
+ };
+ final stopNames = stopNamesMap[token.name!]!;
+ for (var node in tree.openElements.reversed) {
+ if (stopNames.contains(node.localName)) {
+ parser.phase.processEndTag(EndTagToken(node.localName));
+ break;
+ }
+ if (specialElements.contains(getElementNameTuple(node)) &&
+ !const ['address', 'div', 'p'].contains(node.localName)) {
+ break;
+ }
+ }
+
+ if (tree.elementInScope('p', variant: 'button')) {
+ parser.phase.processEndTag(EndTagToken('p'));
+ }
+
+ tree.insertElement(token);
+ }
+
+ void startTagPlaintext(StartTagToken token) {
+ if (tree.elementInScope('p', variant: 'button')) {
+ endTagP(EndTagToken('p'));
+ }
+ tree.insertElement(token);
+ parser.tokenizer.state = parser.tokenizer.plaintextState;
+ }
+
+ void startTagHeading(StartTagToken token) {
+ if (tree.elementInScope('p', variant: 'button')) {
+ endTagP(EndTagToken('p'));
+ }
+ if (headingElements.contains(tree.openElements.last.localName)) {
+ parser
+ .parseError(token.span, 'unexpected-start-tag', {'name': token.name});
+ tree.openElements.removeLast();
+ }
+ tree.insertElement(token);
+ }
+
+ void startTagA(StartTagToken token) {
+ final afeAElement = tree.elementInActiveFormattingElements('a');
+ if (afeAElement != null) {
+ parser.parseError(token.span, 'unexpected-start-tag-implies-end-tag',
+ {'startName': 'a', 'endName': 'a'});
+ endTagFormatting(EndTagToken('a'));
+ tree.openElements.remove(afeAElement);
+ tree.activeFormattingElements.remove(afeAElement);
+ }
+ tree.reconstructActiveFormattingElements();
+ addFormattingElement(token);
+ }
+
+ void startTagFormatting(StartTagToken token) {
+ tree.reconstructActiveFormattingElements();
+ addFormattingElement(token);
+ }
+
+ void startTagNobr(StartTagToken token) {
+ tree.reconstructActiveFormattingElements();
+ if (tree.elementInScope('nobr')) {
+ parser.parseError(token.span, 'unexpected-start-tag-implies-end-tag',
+ {'startName': 'nobr', 'endName': 'nobr'});
+ processEndTag(EndTagToken('nobr'));
+ // XXX Need tests that trigger the following
+ tree.reconstructActiveFormattingElements();
+ }
+ addFormattingElement(token);
+ }
+
+ Token? startTagButton(StartTagToken token) {
+ if (tree.elementInScope('button')) {
+ parser.parseError(token.span, 'unexpected-start-tag-implies-end-tag',
+ {'startName': 'button', 'endName': 'button'});
+ processEndTag(EndTagToken('button'));
+ return token;
+ } else {
+ tree.reconstructActiveFormattingElements();
+ tree.insertElement(token);
+ parser.framesetOK = false;
+ }
+ return null;
+ }
+
+ void startTagAppletMarqueeObject(StartTagToken token) {
+ tree.reconstructActiveFormattingElements();
+ tree.insertElement(token);
+ tree.activeFormattingElements.add(null);
+ parser.framesetOK = false;
+ }
+
+ void startTagXmp(StartTagToken token) {
+ if (tree.elementInScope('p', variant: 'button')) {
+ endTagP(EndTagToken('p'));
+ }
+ tree.reconstructActiveFormattingElements();
+ parser.framesetOK = false;
+ parser.parseRCDataRawtext(token, 'RAWTEXT');
+ }
+
+ void startTagTable(StartTagToken token) {
+ if (parser.compatMode != 'quirks') {
+ if (tree.elementInScope('p', variant: 'button')) {
+ processEndTag(EndTagToken('p'));
+ }
+ }
+ tree.insertElement(token);
+ parser.framesetOK = false;
+ parser.phase = parser._inTablePhase;
+ }
+
+ void startTagVoidFormatting(StartTagToken token) {
+ tree.reconstructActiveFormattingElements();
+ tree.insertElement(token);
+ tree.openElements.removeLast();
+ token.selfClosingAcknowledged = true;
+ parser.framesetOK = false;
+ }
+
+ void startTagInput(StartTagToken token) {
+ final savedFramesetOK = parser.framesetOK;
+ startTagVoidFormatting(token);
+ if (token.data['type']?.toAsciiLowerCase() == 'hidden') {
+ //input type=hidden doesn't change framesetOK
+ parser.framesetOK = savedFramesetOK;
+ }
+ }
+
+ void startTagParamSource(StartTagToken token) {
+ tree.insertElement(token);
+ tree.openElements.removeLast();
+ token.selfClosingAcknowledged = true;
+ }
+
+ void startTagHr(StartTagToken token) {
+ if (tree.elementInScope('p', variant: 'button')) {
+ endTagP(EndTagToken('p'));
+ }
+ tree.insertElement(token);
+ tree.openElements.removeLast();
+ token.selfClosingAcknowledged = true;
+ parser.framesetOK = false;
+ }
+
+ void startTagImage(StartTagToken token) {
+ // No really...
+ parser.parseError(token.span, 'unexpected-start-tag-treated-as',
+ {'originalName': 'image', 'newName': 'img'});
+ processStartTag(
+ StartTagToken('img', data: token.data, selfClosing: token.selfClosing));
+ }
+
+ void startTagIsIndex(StartTagToken token) {
+ parser.parseError(token.span, 'deprecated-tag', {'name': 'isindex'});
+ if (tree.formPointer != null) {
+ return;
+ }
+ final formAttrs = LinkedHashMap<Object, String>();
+ final dataAction = token.data['action'];
+ if (dataAction != null) {
+ formAttrs['action'] = dataAction;
+ }
+ processStartTag(StartTagToken('form', data: formAttrs));
+ processStartTag(StartTagToken('hr', data: LinkedHashMap<Object, String>()));
+ processStartTag(
+ StartTagToken('label', data: LinkedHashMap<Object, String>()));
+ // XXX Localization ...
+ var prompt = token.data['prompt'];
+ prompt ??= 'This is a searchable index. Enter search keywords: ';
+ processCharacters(CharactersToken(prompt));
+ final attributes = LinkedHashMap<Object, String>.from(token.data);
+ attributes.remove('action');
+ attributes.remove('prompt');
+ attributes['name'] = 'isindex';
+ processStartTag(StartTagToken('input',
+ data: attributes, selfClosing: token.selfClosing));
+ processEndTag(EndTagToken('label'));
+ processStartTag(StartTagToken('hr', data: LinkedHashMap<Object, String>()));
+ processEndTag(EndTagToken('form'));
+ }
+
+ void startTagTextarea(StartTagToken token) {
+ tree.insertElement(token);
+ parser.tokenizer.state = parser.tokenizer.rcdataState;
+ dropNewline = true;
+ parser.framesetOK = false;
+ }
+
+ void startTagIFrame(StartTagToken token) {
+ parser.framesetOK = false;
+ startTagRawtext(token);
+ }
+
+ /// iframe, noembed noframes, noscript(if scripting enabled).
+ void startTagRawtext(StartTagToken token) {
+ parser.parseRCDataRawtext(token, 'RAWTEXT');
+ }
+
+ void startTagOpt(StartTagToken token) {
+ if (tree.openElements.last.localName == 'option') {
+ parser.phase.processEndTag(EndTagToken('option'));
+ }
+ tree.reconstructActiveFormattingElements();
+ parser.tree.insertElement(token);
+ }
+
+ void startTagSelect(StartTagToken token) {
+ tree.reconstructActiveFormattingElements();
+ tree.insertElement(token);
+ parser.framesetOK = false;
+
+ if (parser._inTablePhase == parser.phase ||
+ parser._inCaptionPhase == parser.phase ||
+ parser._inColumnGroupPhase == parser.phase ||
+ parser._inTableBodyPhase == parser.phase ||
+ parser._inRowPhase == parser.phase ||
+ parser._inCellPhase == parser.phase) {
+ parser.phase = parser._inSelectInTablePhase;
+ } else {
+ parser.phase = parser._inSelectPhase;
+ }
+ }
+
+ void startTagRpRt(StartTagToken token) {
+ if (tree.elementInScope('ruby')) {
+ tree.generateImpliedEndTags();
+ final last = tree.openElements.last;
+ if (last.localName != 'ruby') {
+ parser.parseError(last.sourceSpan, 'undefined-error');
+ }
+ }
+ tree.insertElement(token);
+ }
+
+ void startTagMath(StartTagToken token) {
+ tree.reconstructActiveFormattingElements();
+ parser.adjustMathMLAttributes(token);
+ parser.adjustForeignAttributes(token);
+ token.namespace = Namespaces.mathml;
+ tree.insertElement(token);
+ //Need to get the parse error right for the case where the token
+ //has a namespace not equal to the xmlns attribute
+ if (token.selfClosing) {
+ tree.openElements.removeLast();
+ token.selfClosingAcknowledged = true;
+ }
+ }
+
+ void startTagSvg(StartTagToken token) {
+ tree.reconstructActiveFormattingElements();
+ parser.adjustSVGAttributes(token);
+ parser.adjustForeignAttributes(token);
+ token.namespace = Namespaces.svg;
+ tree.insertElement(token);
+ //Need to get the parse error right for the case where the token
+ //has a namespace not equal to the xmlns attribute
+ if (token.selfClosing) {
+ tree.openElements.removeLast();
+ token.selfClosingAcknowledged = true;
+ }
+ }
+
+ /// Elements that should be children of other elements that have a
+ /// different insertion mode; here they are ignored
+ /// "caption", "col", "colgroup", "frame", "frameset", "head",
+ /// "option", "optgroup", "tbody", "td", "tfoot", "th", "thead",
+ /// "tr", "noscript"
+ void startTagMisplaced(StartTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-start-tag-ignored', {'name': token.name});
+ }
+
+ Token? startTagOther(StartTagToken token) {
+ tree.reconstructActiveFormattingElements();
+ tree.insertElement(token);
+ return null;
+ }
+
+ void endTagP(EndTagToken token) {
+ if (!tree.elementInScope('p', variant: 'button')) {
+ startTagCloseP(StartTagToken('p', data: LinkedHashMap<Object, String>()));
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': 'p'});
+ endTagP(EndTagToken('p'));
+ } else {
+ tree.generateImpliedEndTags('p');
+ if (tree.openElements.last.localName != 'p') {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': 'p'});
+ }
+ popOpenElementsUntil(token);
+ }
+ }
+
+ void endTagBody(EndTagToken token) {
+ if (!tree.elementInScope('body')) {
+ parser.parseError(token.span, 'undefined-error');
+ return;
+ } else if (tree.openElements.last.localName == 'body') {
+ tree.openElements.last.endSourceSpan = token.span;
+ } else {
+ for (var node in slice(tree.openElements, 2)) {
+ switch (node.localName) {
+ case 'dd':
+ case 'dt':
+ case 'li':
+ case 'optgroup':
+ case 'option':
+ case 'p':
+ case 'rp':
+ case 'rt':
+ case 'tbody':
+ case 'td':
+ case 'tfoot':
+ case 'th':
+ case 'thead':
+ case 'tr':
+ case 'body':
+ case 'html':
+ continue;
+ }
+ // Not sure this is the correct name for the parse error
+ parser.parseError(token.span, 'expected-one-end-tag-but-got-another',
+ {'gotName': 'body', 'expectedName': node.localName});
+ break;
+ }
+ }
+ parser.phase = parser._afterBodyPhase;
+ }
+
+ Token? endTagHtml(EndTagToken token) {
+ //We repeat the test for the body end tag token being ignored here
+ if (tree.elementInScope('body')) {
+ endTagBody(EndTagToken('body'));
+ return token;
+ }
+ return null;
+ }
+
+ void endTagBlock(EndTagToken token) {
+ //Put us back in the right whitespace handling mode
+ if (token.name == 'pre') {
+ dropNewline = false;
+ }
+ final inScope = tree.elementInScope(token.name);
+ if (inScope) {
+ tree.generateImpliedEndTags();
+ }
+ if (tree.openElements.last.localName != token.name) {
+ parser.parseError(token.span, 'end-tag-too-early', {'name': token.name});
+ }
+ if (inScope) {
+ popOpenElementsUntil(token);
+ }
+ }
+
+ void endTagForm(EndTagToken token) {
+ final node = tree.formPointer;
+ tree.formPointer = null;
+ if (node == null || !tree.elementInScope(node)) {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': 'form'});
+ } else {
+ tree.generateImpliedEndTags();
+ if (tree.openElements.last != node) {
+ parser.parseError(
+ token.span, 'end-tag-too-early-ignored', {'name': 'form'});
+ }
+ tree.openElements.remove(node);
+ node.endSourceSpan = token.span;
+ }
+ }
+
+ void endTagListItem(EndTagToken token) {
+ String? variant;
+ if (token.name == 'li') {
+ variant = 'list';
+ } else {
+ variant = null;
+ }
+ if (!tree.elementInScope(token.name, variant: variant)) {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+ } else {
+ tree.generateImpliedEndTags(token.name);
+ if (tree.openElements.last.localName != token.name) {
+ parser
+ .parseError(token.span, 'end-tag-too-early', {'name': token.name});
+ }
+ popOpenElementsUntil(token);
+ }
+ }
+
+ void endTagHeading(EndTagToken token) {
+ for (var item in headingElements) {
+ if (tree.elementInScope(item)) {
+ tree.generateImpliedEndTags();
+ break;
+ }
+ }
+ if (tree.openElements.last.localName != token.name) {
+ parser.parseError(token.span, 'end-tag-too-early', {'name': token.name});
+ }
+
+ for (var item in headingElements) {
+ if (tree.elementInScope(item)) {
+ var node = tree.openElements.removeLast();
+ while (!headingElements.contains(node.localName)) {
+ node = tree.openElements.removeLast();
+ }
+ node.endSourceSpan = token.span;
+ break;
+ }
+ }
+ }
+
+ /// The much-feared adoption agency algorithm.
+ void endTagFormatting(EndTagToken token) {
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adoptionAgency
+ // TODO(jmesserly): the comments here don't match the numbered steps in the
+ // updated spec. This needs a pass over it to verify that it still matches.
+ // In particular the html5lib Python code skiped "step 4", I'm not sure why.
+ // XXX Better parseError messages appreciated.
+ var outerLoopCounter = 0;
+ while (outerLoopCounter < 8) {
+ outerLoopCounter += 1;
+
+ // Step 1 paragraph 1
+ final formattingElement =
+ tree.elementInActiveFormattingElements(token.name);
+ if (formattingElement == null ||
+ (tree.openElements.contains(formattingElement) &&
+ !tree.elementInScope(formattingElement.localName))) {
+ parser.parseError(
+ token.span, 'adoption-agency-1.1', {'name': token.name});
+ return;
+ // Step 1 paragraph 2
+ } else if (!tree.openElements.contains(formattingElement)) {
+ parser.parseError(
+ token.span, 'adoption-agency-1.2', {'name': token.name});
+ tree.activeFormattingElements.remove(formattingElement);
+ return;
+ }
+
+ // Step 1 paragraph 3
+ if (formattingElement != tree.openElements.last) {
+ parser.parseError(
+ token.span, 'adoption-agency-1.3', {'name': token.name});
+ }
+
+ // Step 2
+ // Start of the adoption agency algorithm proper
+ final afeIndex = tree.openElements.indexOf(formattingElement);
+ Element? furthestBlock;
+ for (var element in slice(tree.openElements, afeIndex)) {
+ if (specialElements.contains(getElementNameTuple(element))) {
+ furthestBlock = element;
+ break;
+ }
+ }
+ // Step 3
+ if (furthestBlock == null) {
+ var element = tree.openElements.removeLast();
+ while (element != formattingElement) {
+ element = tree.openElements.removeLast();
+ }
+ element.endSourceSpan = token.span;
+ tree.activeFormattingElements.remove(element);
+ return;
+ }
+
+ final commonAncestor = tree.openElements[afeIndex - 1];
+
+ // Step 5
+ // The bookmark is supposed to help us identify where to reinsert
+ // nodes in step 12. We have to ensure that we reinsert nodes after
+ // the node before the active formatting element. Note the bookmark
+ // can move in step 7.4
+ var bookmark = tree.activeFormattingElements.indexOf(formattingElement);
+
+ // Step 6
+ var lastNode = furthestBlock;
+ var node = furthestBlock;
+ var innerLoopCounter = 0;
+
+ var index = tree.openElements.indexOf(node);
+ while (innerLoopCounter < 3) {
+ innerLoopCounter += 1;
+
+ // Node is element before node in open elements
+ index -= 1;
+ node = tree.openElements[index];
+ if (!tree.activeFormattingElements.contains(node)) {
+ tree.openElements.remove(node);
+ continue;
+ }
+ // Step 6.3
+ if (node == formattingElement) {
+ break;
+ }
+ // Step 6.4
+ if (lastNode == furthestBlock) {
+ bookmark = tree.activeFormattingElements.indexOf(node) + 1;
+ }
+ // Step 6.5
+ //cite = node.parent
+ final clone = node.clone(false);
+ // Replace node with clone
+ tree.activeFormattingElements[
+ tree.activeFormattingElements.indexOf(node)] = clone;
+ tree.openElements[tree.openElements.indexOf(node)] = clone;
+ node = clone;
+
+ // Step 6.6
+ // Remove lastNode from its parents, if any
+ if (lastNode.parentNode != null) {
+ lastNode.parentNode!.nodes.remove(lastNode);
+ }
+ node.nodes.add(lastNode);
+ // Step 7.7
+ lastNode = node;
+ // End of inner loop
+ }
+
+ // Step 7
+ // Foster parent lastNode if commonAncestor is a
+ // table, tbody, tfoot, thead, or tr we need to foster parent the
+ // lastNode
+ if (lastNode.parentNode != null) {
+ lastNode.parentNode!.nodes.remove(lastNode);
+ }
+
+ if (const ['table', 'tbody', 'tfoot', 'thead', 'tr']
+ .contains(commonAncestor.localName)) {
+ final nodePos = tree.getTableMisnestedNodePosition();
+ nodePos[0]!.insertBefore(lastNode, nodePos[1]);
+ } else {
+ commonAncestor.nodes.add(lastNode);
+ }
+
+ // Step 8
+ final clone = formattingElement.clone(false);
+
+ // Step 9
+ furthestBlock.reparentChildren(clone);
+
+ // Step 10
+ furthestBlock.nodes.add(clone);
+
+ // Step 11
+ tree.activeFormattingElements.remove(formattingElement);
+ tree.activeFormattingElements
+ .insert(min(bookmark, tree.activeFormattingElements.length), clone);
+
+ // Step 12
+ tree.openElements.remove(formattingElement);
+ tree.openElements
+ .insert(tree.openElements.indexOf(furthestBlock) + 1, clone);
+ }
+ }
+
+ void endTagAppletMarqueeObject(EndTagToken token) {
+ if (tree.elementInScope(token.name)) {
+ tree.generateImpliedEndTags();
+ }
+ if (tree.openElements.last.localName != token.name) {
+ parser.parseError(token.span, 'end-tag-too-early', {'name': token.name});
+ }
+ if (tree.elementInScope(token.name)) {
+ popOpenElementsUntil(token);
+ tree.clearActiveFormattingElements();
+ }
+ }
+
+ void endTagBr(EndTagToken token) {
+ parser.parseError(token.span, 'unexpected-end-tag-treated-as',
+ {'originalName': 'br', 'newName': 'br element'});
+ tree.reconstructActiveFormattingElements();
+ tree.insertElement(
+ StartTagToken('br', data: LinkedHashMap<Object, String>()));
+ tree.openElements.removeLast();
+ }
+
+ void endTagOther(EndTagToken token) {
+ for (var node in tree.openElements.reversed) {
+ if (node.localName == token.name) {
+ tree.generateImpliedEndTags(token.name);
+ if (tree.openElements.last.localName != token.name) {
+ parser.parseError(
+ token.span, 'unexpected-end-tag', {'name': token.name});
+ }
+ while (tree.openElements.removeLast() != node) {
+ // noop
+ }
+ node.endSourceSpan = token.span;
+ break;
+ } else {
+ if (specialElements.contains(getElementNameTuple(node))) {
+ parser.parseError(
+ token.span, 'unexpected-end-tag', {'name': token.name});
+ break;
+ }
+ }
+ }
+ }
+}
+
+class TextPhase extends Phase {
+ TextPhase(super.parser);
+
+ // "Tried to process start tag %s in RCDATA/RAWTEXT mode"%token.name
+ @override
+ Token processStartTag(StartTagToken token) {
+ throw StateError('Cannot process start stag in text phase');
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ if (token.name == 'script') {
+ endTagScript(token);
+ return null;
+ }
+ endTagOther(token);
+ return null;
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ tree.insertText(token.data, token.span);
+ return null;
+ }
+
+ @override
+ bool processEOF() {
+ final last = tree.openElements.last;
+ parser.parseError(last.sourceSpan, 'expected-named-closing-tag-but-got-eof',
+ {'name': last.localName});
+ tree.openElements.removeLast();
+ parser.phase = parser.originalPhase!;
+ return true;
+ }
+
+ void endTagScript(EndTagToken token) {
+ final node = tree.openElements.removeLast();
+ assert(node.localName == 'script');
+ parser.phase = parser.originalPhase!;
+ //The rest of this method is all stuff that only happens if
+ //document.write works
+ }
+
+ void endTagOther(EndTagToken token) {
+ tree.openElements.removeLast();
+ parser.phase = parser.originalPhase!;
+ }
+}
+
+class InTablePhase extends Phase {
+ // http://www.whatwg.org/specs/web-apps/current-work///in-table
+ InTablePhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'caption':
+ startTagCaption(token);
+ return null;
+ case 'colgroup':
+ startTagColgroup(token);
+ return null;
+ case 'col':
+ return startTagCol(token);
+ case 'tbody':
+ case 'tfoot':
+ case 'thead':
+ startTagRowGroup(token);
+ return null;
+ case 'td':
+ case 'th':
+ case 'tr':
+ return startTagImplyTbody(token);
+ case 'table':
+ return startTagTable(token);
+ case 'style':
+ case 'script':
+ return startTagStyleScript(token);
+ case 'input':
+ startTagInput(token);
+ return null;
+ case 'form':
+ startTagForm(token);
+ return null;
+ default:
+ startTagOther(token);
+ return null;
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'table':
+ endTagTable(token);
+ return null;
+ case 'body':
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'html':
+ case 'tbody':
+ case 'td':
+ case 'tfoot':
+ case 'th':
+ case 'thead':
+ case 'tr':
+ endTagIgnore(token);
+ return null;
+ default:
+ endTagOther(token);
+ return null;
+ }
+ }
+
+ // helper methods
+ void clearStackToTableContext() {
+ // 'clear the stack back to a table context'
+ while (tree.openElements.last.localName != 'table' &&
+ tree.openElements.last.localName != 'html') {
+ //parser.parseError(token.span, "unexpected-implied-end-tag-in-table",
+ // {"name": tree.openElements.last.name})
+ tree.openElements.removeLast();
+ }
+ // When the current node is <html> it's an innerHTML case
+ }
+
+ // processing methods
+ @override
+ bool processEOF() {
+ final last = tree.openElements.last;
+ if (last.localName != 'html') {
+ parser.parseError(last.sourceSpan, 'eof-in-table');
+ } else {
+ assert(parser.innerHTMLMode);
+ }
+ //Stop parsing
+ return false;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ final originalPhase = parser.phase;
+ parser.phase = parser._inTableTextPhase;
+ parser._inTableTextPhase.originalPhase = originalPhase;
+ parser.phase.processSpaceCharacters(token);
+ return null;
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ final originalPhase = parser.phase;
+ parser.phase = parser._inTableTextPhase;
+ parser._inTableTextPhase.originalPhase = originalPhase;
+ parser.phase.processCharacters(token);
+ return null;
+ }
+
+ void insertText(CharactersToken token) {
+ // If we get here there must be at least one non-whitespace character
+ // Do the table magic!
+ tree.insertFromTable = true;
+ parser._inBodyPhase.processCharacters(token);
+ tree.insertFromTable = false;
+ }
+
+ void startTagCaption(StartTagToken token) {
+ clearStackToTableContext();
+ tree.activeFormattingElements.add(null);
+ tree.insertElement(token);
+ parser.phase = parser._inCaptionPhase;
+ }
+
+ void startTagColgroup(StartTagToken token) {
+ clearStackToTableContext();
+ tree.insertElement(token);
+ parser.phase = parser._inColumnGroupPhase;
+ }
+
+ Token startTagCol(StartTagToken token) {
+ startTagColgroup(
+ StartTagToken('colgroup', data: LinkedHashMap<Object, String>()));
+ return token;
+ }
+
+ void startTagRowGroup(StartTagToken token) {
+ clearStackToTableContext();
+ tree.insertElement(token);
+ parser.phase = parser._inTableBodyPhase;
+ }
+
+ Token startTagImplyTbody(StartTagToken token) {
+ startTagRowGroup(
+ StartTagToken('tbody', data: LinkedHashMap<Object, String>()));
+ return token;
+ }
+
+ Token? startTagTable(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-start-tag-implies-end-tag',
+ {'startName': 'table', 'endName': 'table'});
+ parser.phase.processEndTag(EndTagToken('table'));
+ if (!parser.innerHTMLMode) {
+ return token;
+ }
+ return null;
+ }
+
+ Token? startTagStyleScript(StartTagToken token) {
+ return parser._inHeadPhase.processStartTag(token);
+ }
+
+ void startTagInput(StartTagToken token) {
+ if (token.data['type']?.toAsciiLowerCase() == 'hidden') {
+ parser.parseError(token.span, 'unexpected-hidden-input-in-table');
+ tree.insertElement(token);
+ // XXX associate with form
+ tree.openElements.removeLast();
+ } else {
+ startTagOther(token);
+ }
+ }
+
+ void startTagForm(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-form-in-table');
+ if (tree.formPointer == null) {
+ tree.insertElement(token);
+ tree.formPointer = tree.openElements.last;
+ tree.openElements.removeLast();
+ }
+ }
+
+ void startTagOther(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-start-tag-implies-table-voodoo',
+ {'name': token.name});
+ // Do the table magic!
+ tree.insertFromTable = true;
+ parser._inBodyPhase.processStartTag(token);
+ tree.insertFromTable = false;
+ }
+
+ void endTagTable(EndTagToken token) {
+ if (tree.elementInScope('table', variant: 'table')) {
+ tree.generateImpliedEndTags();
+ final last = tree.openElements.last;
+ if (last.localName != 'table') {
+ parser.parseError(token.span, 'end-tag-too-early-named',
+ {'gotName': 'table', 'expectedName': last.localName});
+ }
+ while (tree.openElements.last.localName != 'table') {
+ tree.openElements.removeLast();
+ }
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ parser.resetInsertionMode();
+ } else {
+ // innerHTML case
+ assert(parser.innerHTMLMode);
+ parser.parseError(token.span, 'undefined-error');
+ }
+ }
+
+ void endTagIgnore(EndTagToken token) {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+ }
+
+ void endTagOther(EndTagToken token) {
+ parser.parseError(token.span, 'unexpected-end-tag-implies-table-voodoo',
+ {'name': token.name});
+ // Do the table magic!
+ tree.insertFromTable = true;
+ parser._inBodyPhase.processEndTag(token);
+ tree.insertFromTable = false;
+ }
+}
+
+class InTableTextPhase extends Phase {
+ Phase? originalPhase;
+ List<StringToken> characterTokens;
+
+ InTableTextPhase(super.parser) : characterTokens = <StringToken>[];
+
+ void flushCharacters() {
+ if (characterTokens.isEmpty) return;
+
+ // TODO(sigmund,jmesserly): remove '' (dartbug.com/8480)
+ final data = characterTokens.map((t) => t.data).join('');
+ FileSpan? span;
+
+ if (parser.generateSpans) {
+ span = characterTokens[0].span!.expand(characterTokens.last.span!);
+ }
+
+ if (!allWhitespace(data)) {
+ parser._inTablePhase.insertText(CharactersToken(data)..span = span);
+ } else if (data.isNotEmpty) {
+ tree.insertText(data, span);
+ }
+ characterTokens = <StringToken>[];
+ }
+
+ @override
+ Token processComment(CommentToken token) {
+ flushCharacters();
+ parser.phase = originalPhase!;
+ return token;
+ }
+
+ @override
+ bool processEOF() {
+ flushCharacters();
+ parser.phase = originalPhase!;
+ return true;
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ if (token.data == '\u0000') {
+ return null;
+ }
+ characterTokens.add(token);
+ return null;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ //pretty sure we should never reach here
+ characterTokens.add(token);
+ // XXX assert(false);
+ return null;
+ }
+
+ @override
+ Token processStartTag(StartTagToken token) {
+ flushCharacters();
+ parser.phase = originalPhase!;
+ return token;
+ }
+
+ @override
+ Token processEndTag(EndTagToken token) {
+ flushCharacters();
+ parser.phase = originalPhase!;
+ return token;
+ }
+}
+
+class InCaptionPhase extends Phase {
+ // http://www.whatwg.org/specs/web-apps/current-work///in-caption
+ InCaptionPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'tbody':
+ case 'td':
+ case 'tfoot':
+ case 'th':
+ case 'thead':
+ case 'tr':
+ return startTagTableElement(token);
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'caption':
+ endTagCaption(token);
+ return null;
+ case 'table':
+ return endTagTable(token);
+ case 'body':
+ case 'col':
+ case 'colgroup':
+ case 'html':
+ case 'tbody':
+ case 'td':
+ case 'tfoot':
+ case 'th':
+ case 'thead':
+ case 'tr':
+ endTagIgnore(token);
+ return null;
+ default:
+ return endTagOther(token);
+ }
+ }
+
+ bool ignoreEndTagCaption() {
+ return !tree.elementInScope('caption', variant: 'table');
+ }
+
+ @override
+ bool processEOF() {
+ parser._inBodyPhase.processEOF();
+ return false;
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ return parser._inBodyPhase.processCharacters(token);
+ }
+
+ Token? startTagTableElement(StartTagToken token) {
+ parser.parseError(token.span, 'undefined-error');
+ //XXX Have to duplicate logic here to find out if the tag is ignored
+ final ignoreEndTag = ignoreEndTagCaption();
+ parser.phase.processEndTag(EndTagToken('caption'));
+ if (!ignoreEndTag) {
+ return token;
+ }
+ return null;
+ }
+
+ Token? startTagOther(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ void endTagCaption(EndTagToken token) {
+ if (!ignoreEndTagCaption()) {
+ // AT this code is quite similar to endTagTable in "InTable"
+ tree.generateImpliedEndTags();
+ if (tree.openElements.last.localName != 'caption') {
+ parser.parseError(token.span, 'expected-one-end-tag-but-got-another', {
+ 'gotName': 'caption',
+ 'expectedName': tree.openElements.last.localName
+ });
+ }
+ while (tree.openElements.last.localName != 'caption') {
+ tree.openElements.removeLast();
+ }
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ tree.clearActiveFormattingElements();
+ parser.phase = parser._inTablePhase;
+ } else {
+ // innerHTML case
+ assert(parser.innerHTMLMode);
+ parser.parseError(token.span, 'undefined-error');
+ }
+ }
+
+ Token? endTagTable(EndTagToken token) {
+ parser.parseError(token.span, 'undefined-error');
+ final ignoreEndTag = ignoreEndTagCaption();
+ parser.phase.processEndTag(EndTagToken('caption'));
+ if (!ignoreEndTag) {
+ return token;
+ }
+ return null;
+ }
+
+ void endTagIgnore(EndTagToken token) {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+ }
+
+ Token? endTagOther(EndTagToken token) {
+ return parser._inBodyPhase.processEndTag(token);
+ }
+}
+
+class InColumnGroupPhase extends Phase {
+ // http://www.whatwg.org/specs/web-apps/current-work///in-column
+ InColumnGroupPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'col':
+ startTagCol(token);
+ return null;
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'colgroup':
+ endTagColgroup(token);
+ return null;
+ case 'col':
+ endTagCol(token);
+ return null;
+ default:
+ return endTagOther(token);
+ }
+ }
+
+ bool ignoreEndTagColgroup() {
+ return tree.openElements.last.localName == 'html';
+ }
+
+ @override
+ bool processEOF() {
+ final ignoreEndTag = ignoreEndTagColgroup();
+ if (ignoreEndTag) {
+ assert(parser.innerHTMLMode);
+ return false;
+ } else {
+ endTagColgroup(EndTagToken('colgroup'));
+ return true;
+ }
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ final ignoreEndTag = ignoreEndTagColgroup();
+ endTagColgroup(EndTagToken('colgroup'));
+ return ignoreEndTag ? null : token;
+ }
+
+ void startTagCol(StartTagToken token) {
+ tree.insertElement(token);
+ tree.openElements.removeLast();
+ }
+
+ Token? startTagOther(StartTagToken token) {
+ final ignoreEndTag = ignoreEndTagColgroup();
+ endTagColgroup(EndTagToken('colgroup'));
+ return ignoreEndTag ? null : token;
+ }
+
+ void endTagColgroup(EndTagToken token) {
+ if (ignoreEndTagColgroup()) {
+ // innerHTML case
+ assert(parser.innerHTMLMode);
+ parser.parseError(token.span, 'undefined-error');
+ } else {
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ parser.phase = parser._inTablePhase;
+ }
+ }
+
+ void endTagCol(EndTagToken token) {
+ parser.parseError(token.span, 'no-end-tag', {'name': 'col'});
+ }
+
+ Token? endTagOther(EndTagToken token) {
+ final ignoreEndTag = ignoreEndTagColgroup();
+ endTagColgroup(EndTagToken('colgroup'));
+ return ignoreEndTag ? null : token;
+ }
+}
+
+class InTableBodyPhase extends Phase {
+ // http://www.whatwg.org/specs/web-apps/current-work///in-table0
+ InTableBodyPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'tr':
+ startTagTr(token);
+ return null;
+ case 'td':
+ case 'th':
+ return startTagTableCell(token);
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'tbody':
+ case 'tfoot':
+ case 'thead':
+ return startTagTableOther(token);
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'tbody':
+ case 'tfoot':
+ case 'thead':
+ endTagTableRowGroup(token);
+ return null;
+ case 'table':
+ return endTagTable(token);
+ case 'body':
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'html':
+ case 'td':
+ case 'th':
+ case 'tr':
+ endTagIgnore(token);
+ return null;
+ default:
+ return endTagOther(token);
+ }
+ }
+
+ // helper methods
+ void clearStackToTableBodyContext() {
+ final tableTags = const ['tbody', 'tfoot', 'thead', 'html'];
+ while (!tableTags.contains(tree.openElements.last.localName)) {
+ //XXX parser.parseError(token.span, "unexpected-implied-end-tag-in-table",
+ // {"name": tree.openElements.last.name})
+ tree.openElements.removeLast();
+ }
+ if (tree.openElements.last.localName == 'html') {
+ assert(parser.innerHTMLMode);
+ }
+ }
+
+ // the rest
+ @override
+ bool processEOF() {
+ parser._inTablePhase.processEOF();
+ return false;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ return parser._inTablePhase.processSpaceCharacters(token);
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ return parser._inTablePhase.processCharacters(token);
+ }
+
+ void startTagTr(StartTagToken token) {
+ clearStackToTableBodyContext();
+ tree.insertElement(token);
+ parser.phase = parser._inRowPhase;
+ }
+
+ Token startTagTableCell(StartTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-cell-in-table-body', {'name': token.name});
+ startTagTr(StartTagToken('tr', data: LinkedHashMap<Object, String>()));
+ return token;
+ }
+
+ Token? startTagTableOther(TagToken token) => endTagTable(token);
+
+ Token? startTagOther(StartTagToken token) {
+ return parser._inTablePhase.processStartTag(token);
+ }
+
+ void endTagTableRowGroup(EndTagToken token) {
+ if (tree.elementInScope(token.name, variant: 'table')) {
+ clearStackToTableBodyContext();
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ parser.phase = parser._inTablePhase;
+ } else {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-in-table-body', {'name': token.name});
+ }
+ }
+
+ Token? endTagTable(TagToken token) {
+ // XXX AT Any ideas on how to share this with endTagTable?
+ if (tree.elementInScope('tbody', variant: 'table') ||
+ tree.elementInScope('thead', variant: 'table') ||
+ tree.elementInScope('tfoot', variant: 'table')) {
+ clearStackToTableBodyContext();
+ endTagTableRowGroup(EndTagToken(tree.openElements.last.localName));
+ return token;
+ } else {
+ // innerHTML case
+ assert(parser.innerHTMLMode);
+ parser.parseError(token.span, 'undefined-error');
+ }
+ return null;
+ }
+
+ void endTagIgnore(EndTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-in-table-body', {'name': token.name});
+ }
+
+ Token? endTagOther(EndTagToken token) {
+ return parser._inTablePhase.processEndTag(token);
+ }
+}
+
+class InRowPhase extends Phase {
+ // http://www.whatwg.org/specs/web-apps/current-work///in-row
+ InRowPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'td':
+ case 'th':
+ startTagTableCell(token);
+ return null;
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'tbody':
+ case 'tfoot':
+ case 'thead':
+ case 'tr':
+ return startTagTableOther(token);
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'tr':
+ endTagTr(token);
+ return null;
+ case 'table':
+ return endTagTable(token);
+ case 'tbody':
+ case 'tfoot':
+ case 'thead':
+ return endTagTableRowGroup(token);
+ case 'body':
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'html':
+ case 'td':
+ case 'th':
+ endTagIgnore(token);
+ return null;
+ default:
+ return endTagOther(token);
+ }
+ }
+
+ // helper methods (XXX unify this with other table helper methods)
+ void clearStackToTableRowContext() {
+ while (true) {
+ final last = tree.openElements.last;
+ if (last.localName == 'tr' || last.localName == 'html') break;
+
+ parser.parseError(
+ last.sourceSpan,
+ 'unexpected-implied-end-tag-in-table-row',
+ {'name': tree.openElements.last.localName});
+ tree.openElements.removeLast();
+ }
+ }
+
+ bool ignoreEndTagTr() {
+ return !tree.elementInScope('tr', variant: 'table');
+ }
+
+ // the rest
+ @override
+ bool processEOF() {
+ parser._inTablePhase.processEOF();
+ return false;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ return parser._inTablePhase.processSpaceCharacters(token);
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ return parser._inTablePhase.processCharacters(token);
+ }
+
+ void startTagTableCell(StartTagToken token) {
+ clearStackToTableRowContext();
+ tree.insertElement(token);
+ parser.phase = parser._inCellPhase;
+ tree.activeFormattingElements.add(null);
+ }
+
+ Token? startTagTableOther(StartTagToken token) {
+ final ignoreEndTag = ignoreEndTagTr();
+ endTagTr(EndTagToken('tr'));
+ // XXX how are we sure it's always ignored in the innerHTML case?
+ return ignoreEndTag ? null : token;
+ }
+
+ Token? startTagOther(StartTagToken token) {
+ return parser._inTablePhase.processStartTag(token);
+ }
+
+ void endTagTr(EndTagToken token) {
+ if (!ignoreEndTagTr()) {
+ clearStackToTableRowContext();
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ parser.phase = parser._inTableBodyPhase;
+ } else {
+ // innerHTML case
+ assert(parser.innerHTMLMode);
+ parser.parseError(token.span, 'undefined-error');
+ }
+ }
+
+ Token? endTagTable(EndTagToken token) {
+ final ignoreEndTag = ignoreEndTagTr();
+ endTagTr(EndTagToken('tr'));
+ // Reprocess the current tag if the tr end tag was not ignored
+ // XXX how are we sure it's always ignored in the innerHTML case?
+ return ignoreEndTag ? null : token;
+ }
+
+ Token? endTagTableRowGroup(EndTagToken token) {
+ if (tree.elementInScope(token.name, variant: 'table')) {
+ endTagTr(EndTagToken('tr'));
+ return token;
+ } else {
+ parser.parseError(token.span, 'undefined-error');
+ return null;
+ }
+ }
+
+ void endTagIgnore(EndTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-in-table-row', {'name': token.name});
+ }
+
+ Token? endTagOther(EndTagToken token) {
+ return parser._inTablePhase.processEndTag(token);
+ }
+}
+
+class InCellPhase extends Phase {
+ // http://www.whatwg.org/specs/web-apps/current-work///in-cell
+ InCellPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'tbody':
+ case 'td':
+ case 'tfoot':
+ case 'th':
+ case 'thead':
+ case 'tr':
+ return startTagTableOther(token);
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'td':
+ case 'th':
+ endTagTableCell(token);
+ return null;
+ case 'body':
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'html':
+ endTagIgnore(token);
+ return null;
+ case 'table':
+ case 'tbody':
+ case 'tfoot':
+ case 'thead':
+ case 'tr':
+ return endTagImply(token);
+ default:
+ return endTagOther(token);
+ }
+ }
+
+ // helper
+ void closeCell() {
+ if (tree.elementInScope('td', variant: 'table')) {
+ endTagTableCell(EndTagToken('td'));
+ } else if (tree.elementInScope('th', variant: 'table')) {
+ endTagTableCell(EndTagToken('th'));
+ }
+ }
+
+ // the rest
+ @override
+ bool processEOF() {
+ parser._inBodyPhase.processEOF();
+ return false;
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ return parser._inBodyPhase.processCharacters(token);
+ }
+
+ Token? startTagTableOther(StartTagToken token) {
+ if (tree.elementInScope('td', variant: 'table') ||
+ tree.elementInScope('th', variant: 'table')) {
+ closeCell();
+ return token;
+ } else {
+ // innerHTML case
+ assert(parser.innerHTMLMode);
+ parser.parseError(token.span, 'undefined-error');
+ return null;
+ }
+ }
+
+ Token? startTagOther(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ void endTagTableCell(EndTagToken token) {
+ if (tree.elementInScope(token.name, variant: 'table')) {
+ tree.generateImpliedEndTags(token.name);
+ if (tree.openElements.last.localName != token.name) {
+ parser.parseError(
+ token.span, 'unexpected-cell-end-tag', {'name': token.name});
+ popOpenElementsUntil(token);
+ } else {
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ }
+ tree.clearActiveFormattingElements();
+ parser.phase = parser._inRowPhase;
+ } else {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+ }
+ }
+
+ void endTagIgnore(EndTagToken token) {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+ }
+
+ Token? endTagImply(EndTagToken token) {
+ if (tree.elementInScope(token.name, variant: 'table')) {
+ closeCell();
+ return token;
+ } else {
+ // sometimes innerHTML case
+ parser.parseError(token.span, 'undefined-error');
+ }
+ return null;
+ }
+
+ Token? endTagOther(EndTagToken token) {
+ return parser._inBodyPhase.processEndTag(token);
+ }
+}
+
+class InSelectPhase extends Phase {
+ InSelectPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'option':
+ startTagOption(token);
+ return null;
+ case 'optgroup':
+ startTagOptgroup(token);
+ return null;
+ case 'select':
+ startTagSelect(token);
+ return null;
+ case 'input':
+ case 'keygen':
+ case 'textarea':
+ return startTagInput(token);
+ case 'script':
+ return startTagScript(token);
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'option':
+ endTagOption(token);
+ return null;
+ case 'optgroup':
+ endTagOptgroup(token);
+ return null;
+ case 'select':
+ endTagSelect(token);
+ return null;
+ default:
+ endTagOther(token);
+ return null;
+ }
+ }
+
+ // http://www.whatwg.org/specs/web-apps/current-work///in-select
+ @override
+ bool processEOF() {
+ final last = tree.openElements.last;
+ if (last.localName != 'html') {
+ parser.parseError(last.sourceSpan, 'eof-in-select');
+ } else {
+ assert(parser.innerHTMLMode);
+ }
+ return false;
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ if (token.data == '\u0000') {
+ return null;
+ }
+ tree.insertText(token.data, token.span);
+ return null;
+ }
+
+ void startTagOption(StartTagToken token) {
+ // We need to imply </option> if <option> is the current node.
+ if (tree.openElements.last.localName == 'option') {
+ tree.openElements.removeLast();
+ }
+ tree.insertElement(token);
+ }
+
+ void startTagOptgroup(StartTagToken token) {
+ if (tree.openElements.last.localName == 'option') {
+ tree.openElements.removeLast();
+ }
+ if (tree.openElements.last.localName == 'optgroup') {
+ tree.openElements.removeLast();
+ }
+ tree.insertElement(token);
+ }
+
+ void startTagSelect(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-select-in-select');
+ endTagSelect(EndTagToken('select'));
+ }
+
+ Token? startTagInput(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-input-in-select');
+ if (tree.elementInScope('select', variant: 'select')) {
+ endTagSelect(EndTagToken('select'));
+ return token;
+ } else {
+ assert(parser.innerHTMLMode);
+ }
+ return null;
+ }
+
+ Token? startTagScript(StartTagToken token) {
+ return parser._inHeadPhase.processStartTag(token);
+ }
+
+ Token? startTagOther(StartTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-start-tag-in-select', {'name': token.name});
+ return null;
+ }
+
+ void endTagOption(EndTagToken token) {
+ if (tree.openElements.last.localName == 'option') {
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ } else {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-in-select', {'name': 'option'});
+ }
+ }
+
+ void endTagOptgroup(EndTagToken token) {
+ // </optgroup> implicitly closes <option>
+ if (tree.openElements.last.localName == 'option' &&
+ tree.openElements[tree.openElements.length - 2].localName ==
+ 'optgroup') {
+ tree.openElements.removeLast();
+ }
+ // It also closes </optgroup>
+ if (tree.openElements.last.localName == 'optgroup') {
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ // But nothing else
+ } else {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-in-select', {'name': 'optgroup'});
+ }
+ }
+
+ void endTagSelect(EndTagToken token) {
+ if (tree.elementInScope('select', variant: 'select')) {
+ popOpenElementsUntil(token);
+ parser.resetInsertionMode();
+ } else {
+ // innerHTML case
+ assert(parser.innerHTMLMode);
+ parser.parseError(token.span, 'undefined-error');
+ }
+ }
+
+ void endTagOther(EndTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-in-select', {'name': token.name});
+ }
+}
+
+class InSelectInTablePhase extends Phase {
+ InSelectInTablePhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'caption':
+ case 'table':
+ case 'tbody':
+ case 'tfoot':
+ case 'thead':
+ case 'tr':
+ case 'td':
+ case 'th':
+ return startTagTable(token);
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'caption':
+ case 'table':
+ case 'tbody':
+ case 'tfoot':
+ case 'thead':
+ case 'tr':
+ case 'td':
+ case 'th':
+ return endTagTable(token);
+ default:
+ return endTagOther(token);
+ }
+ }
+
+ @override
+ bool processEOF() {
+ parser._inSelectPhase.processEOF();
+ return false;
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ return parser._inSelectPhase.processCharacters(token);
+ }
+
+ Token startTagTable(StartTagToken token) {
+ parser.parseError(
+ token.span,
+ 'unexpected-table-element-start-tag-in-select-in-table',
+ {'name': token.name});
+ endTagOther(EndTagToken('select'));
+ return token;
+ }
+
+ Token? startTagOther(StartTagToken token) {
+ return parser._inSelectPhase.processStartTag(token);
+ }
+
+ Token? endTagTable(EndTagToken token) {
+ parser.parseError(
+ token.span,
+ 'unexpected-table-element-end-tag-in-select-in-table',
+ {'name': token.name});
+ if (tree.elementInScope(token.name, variant: 'table')) {
+ endTagOther(EndTagToken('select'));
+ return token;
+ }
+ return null;
+ }
+
+ Token? endTagOther(EndTagToken token) {
+ return parser._inSelectPhase.processEndTag(token);
+ }
+}
+
+class InForeignContentPhase extends Phase {
+ // TODO(jmesserly): this is sorted so we could binary search.
+ static const breakoutElements = [
+ 'b',
+ 'big',
+ 'blockquote',
+ 'body',
+ 'br',
+ 'center',
+ 'code',
+ 'dd',
+ 'div',
+ 'dl',
+ 'dt',
+ 'em',
+ 'embed',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'head',
+ 'hr',
+ 'i',
+ 'img',
+ 'li',
+ 'listing',
+ 'menu',
+ 'meta',
+ 'nobr',
+ 'ol',
+ 'p',
+ 'pre',
+ 'ruby',
+ 's',
+ 'small',
+ 'span',
+ 'strike',
+ 'strong',
+ 'sub',
+ 'sup',
+ 'table',
+ 'tt',
+ 'u',
+ 'ul',
+ 'var'
+ ];
+
+ InForeignContentPhase(super.parser);
+
+ void adjustSVGTagNames(StartTagToken token) {
+ final replacements = const {
+ 'altglyph': 'altGlyph',
+ 'altglyphdef': 'altGlyphDef',
+ 'altglyphitem': 'altGlyphItem',
+ 'animatecolor': 'animateColor',
+ 'animatemotion': 'animateMotion',
+ 'animatetransform': 'animateTransform',
+ 'clippath': 'clipPath',
+ 'feblend': 'feBlend',
+ 'fecolormatrix': 'feColorMatrix',
+ 'fecomponenttransfer': 'feComponentTransfer',
+ 'fecomposite': 'feComposite',
+ 'feconvolvematrix': 'feConvolveMatrix',
+ 'fediffuselighting': 'feDiffuseLighting',
+ 'fedisplacementmap': 'feDisplacementMap',
+ 'fedistantlight': 'feDistantLight',
+ 'feflood': 'feFlood',
+ 'fefunca': 'feFuncA',
+ 'fefuncb': 'feFuncB',
+ 'fefuncg': 'feFuncG',
+ 'fefuncr': 'feFuncR',
+ 'fegaussianblur': 'feGaussianBlur',
+ 'feimage': 'feImage',
+ 'femerge': 'feMerge',
+ 'femergenode': 'feMergeNode',
+ 'femorphology': 'feMorphology',
+ 'feoffset': 'feOffset',
+ 'fepointlight': 'fePointLight',
+ 'fespecularlighting': 'feSpecularLighting',
+ 'fespotlight': 'feSpotLight',
+ 'fetile': 'feTile',
+ 'feturbulence': 'feTurbulence',
+ 'foreignobject': 'foreignObject',
+ 'glyphref': 'glyphRef',
+ 'lineargradient': 'linearGradient',
+ 'radialgradient': 'radialGradient',
+ 'textpath': 'textPath'
+ };
+
+ final replace = replacements[token.name];
+ if (replace != null) {
+ token.name = replace;
+ }
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ if (token.data == '\u0000') {
+ token.replaceData('\uFFFD');
+ } else if (parser.framesetOK && !allWhitespace(token.data)) {
+ parser.framesetOK = false;
+ }
+ return super.processCharacters(token);
+ }
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ final currentNode = tree.openElements.last;
+ if (breakoutElements.contains(token.name) ||
+ (token.name == 'font' &&
+ (token.data.containsKey('color') ||
+ token.data.containsKey('face') ||
+ token.data.containsKey('size')))) {
+ parser.parseError(token.span,
+ 'unexpected-html-element-in-foreign-content', {'name': token.name});
+ while (tree.openElements.last.namespaceUri != tree.defaultNamespace &&
+ !parser.isHTMLIntegrationPoint(tree.openElements.last) &&
+ !parser.isMathMLTextIntegrationPoint(tree.openElements.last)) {
+ tree.openElements.removeLast();
+ }
+ return token;
+ } else {
+ if (currentNode.namespaceUri == Namespaces.mathml) {
+ parser.adjustMathMLAttributes(token);
+ } else if (currentNode.namespaceUri == Namespaces.svg) {
+ adjustSVGTagNames(token);
+ parser.adjustSVGAttributes(token);
+ }
+ parser.adjustForeignAttributes(token);
+ token.namespace = currentNode.namespaceUri;
+ tree.insertElement(token);
+ if (token.selfClosing) {
+ tree.openElements.removeLast();
+ token.selfClosingAcknowledged = true;
+ }
+ return null;
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ var nodeIndex = tree.openElements.length - 1;
+ var node = tree.openElements.last;
+ if (node.localName?.toAsciiLowerCase() != token.name) {
+ parser.parseError(token.span, 'unexpected-end-tag', {'name': token.name});
+ }
+
+ Token? newToken;
+ while (true) {
+ if (node.localName?.toAsciiLowerCase() == token.name) {
+ //XXX this isn't in the spec but it seems necessary
+ if (parser.phase == parser._inTableTextPhase) {
+ final inTableText = parser.phase as InTableTextPhase;
+ inTableText.flushCharacters();
+ parser.phase = inTableText.originalPhase!;
+ }
+ while (tree.openElements.removeLast() != node) {
+ assert(tree.openElements.isNotEmpty);
+ }
+ newToken = null;
+ break;
+ }
+ nodeIndex -= 1;
+
+ node = tree.openElements[nodeIndex];
+ if (node.namespaceUri != tree.defaultNamespace) {
+ continue;
+ } else {
+ newToken = parser.phase.processEndTag(token);
+ break;
+ }
+ }
+ return newToken;
+ }
+}
+
+class AfterBodyPhase extends Phase {
+ AfterBodyPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ if (token.name == 'html') return startTagHtml(token);
+ return startTagOther(token);
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ if (token.name == 'html') {
+ endTagHtml(token);
+ return null;
+ }
+ return endTagOther(token);
+ }
+
+ //Stop parsing
+ @override
+ bool processEOF() => false;
+
+ @override
+ Token? processComment(CommentToken token) {
+ // This is needed because data is to be appended to the <html> element
+ // here and not to whatever is currently open.
+ tree.insertComment(token, tree.openElements[0]);
+ return null;
+ }
+
+ @override
+ Token processCharacters(CharactersToken token) {
+ parser.parseError(token.span, 'unexpected-char-after-body');
+ parser.phase = parser._inBodyPhase;
+ return token;
+ }
+
+ @override
+ Token? startTagHtml(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ Token startTagOther(StartTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-start-tag-after-body', {'name': token.name});
+ parser.phase = parser._inBodyPhase;
+ return token;
+ }
+
+ void endTagHtml(Token token) {
+ for (var node in tree.openElements.reversed) {
+ if (node.localName == 'html') {
+ node.endSourceSpan = token.span;
+ break;
+ }
+ }
+ if (parser.innerHTMLMode) {
+ parser.parseError(token.span, 'unexpected-end-tag-after-body-innerhtml');
+ } else {
+ parser.phase = parser._afterAfterBodyPhase;
+ }
+ }
+
+ Token endTagOther(EndTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-after-body', {'name': token.name});
+ parser.phase = parser._inBodyPhase;
+ return token;
+ }
+}
+
+class InFramesetPhase extends Phase {
+ // http://www.whatwg.org/specs/web-apps/current-work///in-frameset
+ InFramesetPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'frameset':
+ startTagFrameset(token);
+ return null;
+ case 'frame':
+ startTagFrame(token);
+ return null;
+ case 'noframes':
+ return startTagNoframes(token);
+ default:
+ return startTagOther(token);
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'frameset':
+ endTagFrameset(token);
+ return null;
+ default:
+ endTagOther(token);
+ return null;
+ }
+ }
+
+ @override
+ bool processEOF() {
+ final last = tree.openElements.last;
+ if (last.localName != 'html') {
+ parser.parseError(last.sourceSpan, 'eof-in-frameset');
+ } else {
+ assert(parser.innerHTMLMode);
+ }
+ return false;
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ parser.parseError(token.span, 'unexpected-char-in-frameset');
+ return null;
+ }
+
+ void startTagFrameset(StartTagToken token) {
+ tree.insertElement(token);
+ }
+
+ void startTagFrame(StartTagToken token) {
+ tree.insertElement(token);
+ tree.openElements.removeLast();
+ }
+
+ Token? startTagNoframes(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ Token? startTagOther(StartTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-start-tag-in-frameset', {'name': token.name});
+ return null;
+ }
+
+ void endTagFrameset(EndTagToken token) {
+ if (tree.openElements.last.localName == 'html') {
+ // innerHTML case
+ parser.parseError(
+ token.span, 'unexpected-frameset-in-frameset-innerhtml');
+ } else {
+ final node = tree.openElements.removeLast();
+ node.endSourceSpan = token.span;
+ }
+ if (!parser.innerHTMLMode &&
+ tree.openElements.last.localName != 'frameset') {
+ // If we're not in innerHTML mode and the the current node is not a
+ // "frameset" element (anymore) then switch.
+ parser.phase = parser._afterFramesetPhase;
+ }
+ }
+
+ void endTagOther(EndTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-in-frameset', {'name': token.name});
+ }
+}
+
+class AfterFramesetPhase extends Phase {
+ // http://www.whatwg.org/specs/web-apps/current-work///after3
+ AfterFramesetPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'noframes':
+ return startTagNoframes(token);
+ default:
+ startTagOther(token);
+ return null;
+ }
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ switch (token.name) {
+ case 'html':
+ endTagHtml(token);
+ return null;
+ default:
+ endTagOther(token);
+ return null;
+ }
+ }
+
+ // Stop parsing
+ @override
+ bool processEOF() => false;
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ parser.parseError(token.span, 'unexpected-char-after-frameset');
+ return null;
+ }
+
+ Token? startTagNoframes(StartTagToken token) {
+ return parser._inHeadPhase.processStartTag(token);
+ }
+
+ void startTagOther(StartTagToken token) {
+ parser.parseError(token.span, 'unexpected-start-tag-after-frameset',
+ {'name': token.name});
+ }
+
+ void endTagHtml(EndTagToken token) {
+ parser.phase = parser._afterAfterFramesetPhase;
+ }
+
+ void endTagOther(EndTagToken token) {
+ parser.parseError(
+ token.span, 'unexpected-end-tag-after-frameset', {'name': token.name});
+ }
+}
+
+class AfterAfterBodyPhase extends Phase {
+ AfterAfterBodyPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ if (token.name == 'html') return startTagHtml(token);
+ return startTagOther(token);
+ }
+
+ @override
+ bool processEOF() => false;
+
+ @override
+ Token? processComment(CommentToken token) {
+ tree.insertComment(token, tree.document);
+ return null;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ return parser._inBodyPhase.processSpaceCharacters(token);
+ }
+
+ @override
+ Token processCharacters(CharactersToken token) {
+ parser.parseError(token.span, 'expected-eof-but-got-char');
+ parser.phase = parser._inBodyPhase;
+ return token;
+ }
+
+ @override
+ Token? startTagHtml(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ Token startTagOther(StartTagToken token) {
+ parser.parseError(
+ token.span, 'expected-eof-but-got-start-tag', {'name': token.name});
+ parser.phase = parser._inBodyPhase;
+ return token;
+ }
+
+ @override
+ Token processEndTag(EndTagToken token) {
+ parser.parseError(
+ token.span, 'expected-eof-but-got-end-tag', {'name': token.name});
+ parser.phase = parser._inBodyPhase;
+ return token;
+ }
+}
+
+class AfterAfterFramesetPhase extends Phase {
+ AfterAfterFramesetPhase(super.parser);
+
+ @override
+ Token? processStartTag(StartTagToken token) {
+ switch (token.name) {
+ case 'html':
+ return startTagHtml(token);
+ case 'noframes':
+ return startTagNoFrames(token);
+ default:
+ startTagOther(token);
+ return null;
+ }
+ }
+
+ @override
+ bool processEOF() => false;
+
+ @override
+ Token? processComment(CommentToken token) {
+ tree.insertComment(token, tree.document);
+ return null;
+ }
+
+ @override
+ Token? processSpaceCharacters(SpaceCharactersToken token) {
+ return parser._inBodyPhase.processSpaceCharacters(token);
+ }
+
+ @override
+ Token? processCharacters(CharactersToken token) {
+ parser.parseError(token.span, 'expected-eof-but-got-char');
+ return null;
+ }
+
+ @override
+ Token? startTagHtml(StartTagToken token) {
+ return parser._inBodyPhase.processStartTag(token);
+ }
+
+ Token? startTagNoFrames(StartTagToken token) {
+ return parser._inHeadPhase.processStartTag(token);
+ }
+
+ void startTagOther(StartTagToken token) {
+ parser.parseError(
+ token.span, 'expected-eof-but-got-start-tag', {'name': token.name});
+ }
+
+ @override
+ Token? processEndTag(EndTagToken token) {
+ parser.parseError(
+ token.span, 'expected-eof-but-got-end-tag', {'name': token.name});
+ return null;
+ }
+}
+
+/// Error in parsed document.
+class ParseError implements SourceSpanException {
+ final String errorCode;
+ @override
+ final SourceSpan? span;
+ final Map<String, Object?>? data;
+
+ ParseError(this.errorCode, this.span, this.data);
+
+ int get line => span!.start.line;
+
+ int get column => span!.start.column;
+
+ /// Returns the human readable error message for this error.
+ ///
+ /// Use [SourceSpan.message] or the [toString] from the [span] field to get a
+ /// message including span information
+ @override
+ String get message => formatStr(errorMessages[errorCode]!, data);
+
+ @override
+ String toString({dynamic color}) {
+ final res = span!.message(message, color: color);
+ return span!.sourceUrl == null ? 'ParserError on $res' : 'On $res';
+ }
+}
+
+/// Convenience function to get the pair of namespace and localName.
+(String, String?) getElementNameTuple(Element e) {
+ final ns = e.namespaceUri ?? Namespaces.html;
+ return (ns, e.localName);
+}
diff --git a/pkgs/html/lib/src/constants.dart b/pkgs/html/lib/src/constants.dart
new file mode 100644
index 0000000..e70b1e2
--- /dev/null
+++ b/pkgs/html/lib/src/constants.dart
@@ -0,0 +1,3046 @@
+import 'utils.dart';
+
+// TODO(jmesserly): fix up the const lists. For the bigger ones, we need faster
+// lookup than linear search "contains". In the Python code they were
+// frozensets.
+
+final String? eof = null;
+
+class ReparseException implements Exception {
+ final String message;
+ ReparseException(this.message);
+ @override
+ String toString() => 'ReparseException: $message';
+}
+
+// TODO(jmesserly): assuming the programmatic name is not important, it would be
+// good to make these "static const" fields on an ErrorMessage class.
+/// Error messages emitted by `HtmlParser`.
+///
+/// The values use Python style string formatting, as implemented by
+/// [formatStr]. That function only supports the subset of format functionality
+/// used here.
+const Map<String, String> errorMessages = {
+ 'null-character': 'Null character in input stream, replaced with U+FFFD.',
+ 'invalid-codepoint': 'Invalid codepoint in stream.',
+ 'incorrectly-placed-solidus': 'Solidus (/) incorrectly placed in tag.',
+ 'incorrect-cr-newline-entity':
+ 'Incorrect CR newline entity, replaced with LF.',
+ 'illegal-windows-1252-entity':
+ 'Entity used with illegal number (windows-1252 reference).',
+ 'cant-convert-numeric-entity':
+ "Numeric entity couldn't be converted to character "
+ '(codepoint U+%(charAsInt)08x).',
+ 'illegal-codepoint-for-numeric-entity':
+ 'Numeric entity represents an illegal codepoint: '
+ 'U+%(charAsInt)08x.',
+ 'numeric-entity-without-semicolon': "Numeric entity didn't end with ';'.",
+ 'expected-numeric-entity-but-got-eof':
+ 'Numeric entity expected. Got end of file instead.',
+ 'expected-numeric-entity': 'Numeric entity expected but none found.',
+ 'named-entity-without-semicolon': "Named entity didn't end with ';'.",
+ 'expected-named-entity': 'Named entity expected. Got none.',
+ 'attributes-in-end-tag': 'End tag contains unexpected attributes.',
+ 'self-closing-flag-on-end-tag':
+ 'End tag contains unexpected self-closing flag.',
+ 'expected-tag-name-but-got-right-bracket':
+ "Expected tag name. Got '>' instead.",
+ 'expected-tag-name-but-got-question-mark':
+ "Expected tag name. Got '?' instead. (HTML doesn't "
+ 'support processing instructions.)',
+ 'expected-tag-name': 'Expected tag name. Got something else instead',
+ 'expected-closing-tag-but-got-right-bracket':
+ "Expected closing tag. Got '>' instead. Ignoring '</>'.",
+ 'expected-closing-tag-but-got-eof':
+ 'Expected closing tag. Unexpected end of file.',
+ 'expected-closing-tag-but-got-char':
+ "Expected closing tag. Unexpected character '%(data)s' found.",
+ 'eof-in-tag-name': 'Unexpected end of file in the tag name.',
+ 'expected-attribute-name-but-got-eof':
+ 'Unexpected end of file. Expected attribute name instead.',
+ 'eof-in-attribute-name': 'Unexpected end of file in attribute name.',
+ 'invalid-character-in-attribute-name': 'Invalid character in attribute name',
+ 'duplicate-attribute': 'Dropped duplicate attribute on tag.',
+ 'expected-end-of-tag-name-but-got-eof':
+ 'Unexpected end of file. Expected = or end of tag.',
+ 'expected-attribute-value-but-got-eof':
+ 'Unexpected end of file. Expected attribute value.',
+ 'expected-attribute-value-but-got-right-bracket':
+ "Expected attribute value. Got '>' instead.",
+ 'equals-in-unquoted-attribute-value': 'Unexpected = in unquoted attribute',
+ 'unexpected-character-in-unquoted-attribute-value':
+ 'Unexpected character in unquoted attribute',
+ 'invalid-character-after-attribute-name':
+ 'Unexpected character after attribute name.',
+ 'unexpected-character-after-attribute-value':
+ 'Unexpected character after attribute value.',
+ 'eof-in-attribute-value-double-quote':
+ 'Unexpected end of file in attribute value (".',
+ 'eof-in-attribute-value-single-quote':
+ "Unexpected end of file in attribute value (').",
+ 'eof-in-attribute-value-no-quotes':
+ 'Unexpected end of file in attribute value.',
+ 'unexpected-EOF-after-solidus-in-tag':
+ 'Unexpected end of file in tag. Expected >',
+ 'unexpected-character-after-soldius-in-tag':
+ 'Unexpected character after / in tag. Expected >',
+ 'expected-dashes-or-doctype': "Expected '--' or 'DOCTYPE'. Not found.",
+ 'unexpected-bang-after-double-dash-in-comment':
+ 'Unexpected ! after -- in comment',
+ 'unexpected-space-after-double-dash-in-comment':
+ 'Unexpected space after -- in comment',
+ 'incorrect-comment': 'Incorrect comment.',
+ 'eof-in-comment': 'Unexpected end of file in comment.',
+ 'eof-in-comment-end-dash': 'Unexpected end of file in comment (-)',
+ 'unexpected-dash-after-double-dash-in-comment':
+ "Unexpected '-' after '--' found in comment.",
+ 'eof-in-comment-double-dash': 'Unexpected end of file in comment (--).',
+ 'eof-in-comment-end-space-state': 'Unexpected end of file in comment.',
+ 'eof-in-comment-end-bang-state': 'Unexpected end of file in comment.',
+ 'unexpected-char-in-comment': 'Unexpected character in comment found.',
+ 'need-space-after-doctype': "No space after literal string 'DOCTYPE'.",
+ 'expected-doctype-name-but-got-right-bracket':
+ 'Unexpected > character. Expected DOCTYPE name.',
+ 'expected-doctype-name-but-got-eof':
+ 'Unexpected end of file. Expected DOCTYPE name.',
+ 'eof-in-doctype-name': 'Unexpected end of file in DOCTYPE name.',
+ 'eof-in-doctype': 'Unexpected end of file in DOCTYPE.',
+ 'expected-space-or-right-bracket-in-doctype':
+ "Expected space or '>'. Got '%(data)s'",
+ 'unexpected-end-of-doctype': 'Unexpected end of DOCTYPE.',
+ 'unexpected-char-in-doctype': 'Unexpected character in DOCTYPE.',
+ 'eof-in-innerhtml': 'XXX innerHTML EOF',
+ 'unexpected-doctype': 'Unexpected DOCTYPE. Ignored.',
+ 'non-html-root': 'html needs to be the first start tag.',
+ 'expected-doctype-but-got-eof': 'Unexpected End of file. Expected DOCTYPE.',
+ 'unknown-doctype': 'Erroneous DOCTYPE.',
+ 'expected-doctype-but-got-chars':
+ 'Unexpected non-space characters. Expected DOCTYPE.',
+ 'expected-doctype-but-got-start-tag':
+ 'Unexpected start tag (%(name)s). Expected DOCTYPE.',
+ 'expected-doctype-but-got-end-tag':
+ 'Unexpected end tag (%(name)s). Expected DOCTYPE.',
+ 'end-tag-after-implied-root':
+ 'Unexpected end tag (%(name)s) after the (implied) root element.',
+ 'expected-named-closing-tag-but-got-eof':
+ 'Unexpected end of file. Expected end tag (%(name)s).',
+ 'two-heads-are-not-better-than-one':
+ 'Unexpected start tag head in existing head. Ignored.',
+ 'unexpected-end-tag': 'Unexpected end tag (%(name)s). Ignored.',
+ 'unexpected-start-tag-out-of-my-head':
+ 'Unexpected start tag (%(name)s) that can be in head. Moved.',
+ 'unexpected-start-tag': 'Unexpected start tag (%(name)s).',
+ 'missing-end-tag': 'Missing end tag (%(name)s).',
+ 'missing-end-tags': 'Missing end tags (%(name)s).',
+ 'unexpected-start-tag-implies-end-tag':
+ 'Unexpected start tag (%(startName)s) '
+ 'implies end tag (%(endName)s).',
+ 'unexpected-start-tag-treated-as':
+ 'Unexpected start tag (%(originalName)s). Treated as %(newName)s.',
+ 'deprecated-tag': "Unexpected start tag %(name)s. Don't use it!",
+ 'unexpected-start-tag-ignored': 'Unexpected start tag %(name)s. Ignored.',
+ 'expected-one-end-tag-but-got-another': 'Unexpected end tag (%(gotName)s). '
+ 'Missing end tag (%(expectedName)s).',
+ 'end-tag-too-early':
+ 'End tag (%(name)s) seen too early. Expected other end tag.',
+ 'end-tag-too-early-named':
+ 'Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s).',
+ 'end-tag-too-early-ignored': 'End tag (%(name)s) seen too early. Ignored.',
+ 'adoption-agency-1.1': 'End tag (%(name)s) violates step 1, '
+ 'paragraph 1 of the adoption agency algorithm.',
+ 'adoption-agency-1.2': 'End tag (%(name)s) violates step 1, '
+ 'paragraph 2 of the adoption agency algorithm.',
+ 'adoption-agency-1.3': 'End tag (%(name)s) violates step 1, '
+ 'paragraph 3 of the adoption agency algorithm.',
+ 'unexpected-end-tag-treated-as':
+ 'Unexpected end tag (%(originalName)s). Treated as %(newName)s.',
+ 'no-end-tag': 'This element (%(name)s) has no end tag.',
+ 'unexpected-implied-end-tag-in-table':
+ 'Unexpected implied end tag (%(name)s) in the table phase.',
+ 'unexpected-implied-end-tag-in-table-body':
+ 'Unexpected implied end tag (%(name)s) in the table body phase.',
+ 'unexpected-char-implies-table-voodoo': 'Unexpected non-space characters in '
+ 'table context caused voodoo mode.',
+ 'unexpected-hidden-input-in-table':
+ 'Unexpected input with type hidden in table context.',
+ 'unexpected-form-in-table': 'Unexpected form in table context.',
+ 'unexpected-start-tag-implies-table-voodoo':
+ 'Unexpected start tag (%(name)s) in '
+ 'table context caused voodoo mode.',
+ 'unexpected-end-tag-implies-table-voodoo': 'Unexpected end tag (%(name)s) in '
+ 'table context caused voodoo mode.',
+ 'unexpected-cell-in-table-body': 'Unexpected table cell start tag (%(name)s) '
+ 'in the table body phase.',
+ 'unexpected-cell-end-tag': 'Got table cell end tag (%(name)s) '
+ 'while required end tags are missing.',
+ 'unexpected-end-tag-in-table-body':
+ 'Unexpected end tag (%(name)s) in the table body phase. Ignored.',
+ 'unexpected-implied-end-tag-in-table-row':
+ 'Unexpected implied end tag (%(name)s) in the table row phase.',
+ 'unexpected-end-tag-in-table-row':
+ 'Unexpected end tag (%(name)s) in the table row phase. Ignored.',
+ 'unexpected-select-in-select':
+ 'Unexpected select start tag in the select phase '
+ 'treated as select end tag.',
+ 'unexpected-input-in-select':
+ 'Unexpected input start tag in the select phase.',
+ 'unexpected-start-tag-in-select':
+ 'Unexpected start tag token (%(name)s in the select phase. '
+ 'Ignored.',
+ 'unexpected-end-tag-in-select':
+ 'Unexpected end tag (%(name)s) in the select phase. Ignored.',
+ 'unexpected-table-element-start-tag-in-select-in-table':
+ 'Unexpected table element start tag (%(name)s) in the select in table phase.',
+ 'unexpected-table-element-end-tag-in-select-in-table':
+ 'Unexpected table element end tag (%(name)s) in the select in table phase.',
+ 'unexpected-char-after-body':
+ 'Unexpected non-space characters in the after body phase.',
+ 'unexpected-start-tag-after-body': 'Unexpected start tag token (%(name)s)'
+ ' in the after body phase.',
+ 'unexpected-end-tag-after-body': 'Unexpected end tag token (%(name)s)'
+ ' in the after body phase.',
+ 'unexpected-char-in-frameset':
+ 'Unexpected characters in the frameset phase. Characters ignored.',
+ 'unexpected-start-tag-in-frameset': 'Unexpected start tag token (%(name)s)'
+ ' in the frameset phase. Ignored.',
+ 'unexpected-frameset-in-frameset-innerhtml':
+ 'Unexpected end tag token (frameset) '
+ 'in the frameset phase (innerHTML).',
+ 'unexpected-end-tag-in-frameset': 'Unexpected end tag token (%(name)s)'
+ ' in the frameset phase. Ignored.',
+ 'unexpected-char-after-frameset': 'Unexpected non-space characters in the '
+ 'after frameset phase. Ignored.',
+ 'unexpected-start-tag-after-frameset': 'Unexpected start tag (%(name)s)'
+ ' in the after frameset phase. Ignored.',
+ 'unexpected-end-tag-after-frameset': 'Unexpected end tag (%(name)s)'
+ ' in the after frameset phase. Ignored.',
+ 'unexpected-end-tag-after-body-innerhtml':
+ 'Unexpected end tag after body(innerHtml)',
+ 'expected-eof-but-got-char':
+ 'Unexpected non-space characters. Expected end of file.',
+ 'expected-eof-but-got-start-tag': 'Unexpected start tag (%(name)s)'
+ '. Expected end of file.',
+ 'expected-eof-but-got-end-tag': 'Unexpected end tag (%(name)s)'
+ '. Expected end of file.',
+ 'eof-in-table': 'Unexpected end of file. Expected table content.',
+ 'eof-in-select': 'Unexpected end of file. Expected select content.',
+ 'eof-in-frameset': 'Unexpected end of file. Expected frameset content.',
+ 'eof-in-script-in-script': 'Unexpected end of file. Expected script content.',
+ 'eof-in-foreign-lands': 'Unexpected end of file. Expected foreign content',
+ 'non-void-element-with-trailing-solidus':
+ 'Trailing solidus not allowed on element %(name)s',
+ 'unexpected-html-element-in-foreign-content':
+ 'Element %(name)s not allowed in a non-html context',
+ 'unexpected-end-tag-before-html':
+ 'Unexpected end tag (%(name)s) before html.',
+ 'undefined-error': 'Undefined error (this sucks and should be fixed)',
+};
+
+class Namespaces {
+ static const html = 'http://www.w3.org/1999/xhtml';
+ static const mathml = 'http://www.w3.org/1998/Math/MathML';
+ static const svg = 'http://www.w3.org/2000/svg';
+ static const xlink = 'http://www.w3.org/1999/xlink';
+ static const xml = 'http://www.w3.org/XML/1998/namespace';
+ static const xmlns = 'http://www.w3.org/2000/xmlns/';
+ Namespaces._();
+
+ static String? getPrefix(String? url) {
+ return switch (url) {
+ html => 'html',
+ mathml => 'math',
+ svg => 'svg',
+ xlink => 'xlink',
+ xml => 'xml',
+ xmlns => 'xmlns',
+ _ => null
+ };
+ }
+}
+
+const List<(String, String)> scopingElements = [
+ (Namespaces.html, 'applet'),
+ (Namespaces.html, 'caption'),
+ (Namespaces.html, 'html'),
+ (Namespaces.html, 'marquee'),
+ (Namespaces.html, 'object'),
+ (Namespaces.html, 'table'),
+ (Namespaces.html, 'td'),
+ (Namespaces.html, 'th'),
+ (Namespaces.mathml, 'mi'),
+ (Namespaces.mathml, 'mo'),
+ (Namespaces.mathml, 'mn'),
+ (Namespaces.mathml, 'ms'),
+ (Namespaces.mathml, 'mtext'),
+ (Namespaces.mathml, 'annotation-xml'),
+ (Namespaces.svg, 'foreignObject'),
+ (Namespaces.svg, 'desc'),
+ (Namespaces.svg, 'title')
+];
+
+const formattingElements = [
+ (Namespaces.html, 'a'),
+ (Namespaces.html, 'b'),
+ (Namespaces.html, 'big'),
+ (Namespaces.html, 'code'),
+ (Namespaces.html, 'em'),
+ (Namespaces.html, 'font'),
+ (Namespaces.html, 'i'),
+ (Namespaces.html, 'nobr'),
+ (Namespaces.html, 's'),
+ (Namespaces.html, 'small'),
+ (Namespaces.html, 'strike'),
+ (Namespaces.html, 'strong'),
+ (Namespaces.html, 'tt'),
+ (Namespaces.html, '')
+];
+
+const specialElements = [
+ (Namespaces.html, 'address'),
+ (Namespaces.html, 'applet'),
+ (Namespaces.html, 'area'),
+ (Namespaces.html, 'article'),
+ (Namespaces.html, 'aside'),
+ (Namespaces.html, 'base'),
+ (Namespaces.html, 'basefont'),
+ (Namespaces.html, 'bgsound'),
+ (Namespaces.html, 'blockquote'),
+ (Namespaces.html, 'body'),
+ (Namespaces.html, 'br'),
+ (Namespaces.html, 'button'),
+ (Namespaces.html, 'caption'),
+ (Namespaces.html, 'center'),
+ (Namespaces.html, 'col'),
+ (Namespaces.html, 'colgroup'),
+ (Namespaces.html, 'command'),
+ (Namespaces.html, 'dd'),
+ (Namespaces.html, 'details'),
+ (Namespaces.html, 'dir'),
+ (Namespaces.html, 'div'),
+ (Namespaces.html, 'dl'),
+ (Namespaces.html, 'dt'),
+ (Namespaces.html, 'embed'),
+ (Namespaces.html, 'fieldset'),
+ (Namespaces.html, 'figure'),
+ (Namespaces.html, 'footer'),
+ (Namespaces.html, 'form'),
+ (Namespaces.html, 'frame'),
+ (Namespaces.html, 'frameset'),
+ (Namespaces.html, 'h1'),
+ (Namespaces.html, 'h2'),
+ (Namespaces.html, 'h3'),
+ (Namespaces.html, 'h4'),
+ (Namespaces.html, 'h5'),
+ (Namespaces.html, 'h6'),
+ (Namespaces.html, 'head'),
+ (Namespaces.html, 'header'),
+ (Namespaces.html, 'hr'),
+ (Namespaces.html, 'html'),
+ (Namespaces.html, 'iframe'),
+ // Note that image is commented out in the spec as "this isn't an
+ // element that can end up on the stack, so it doesn't matter,"
+ (Namespaces.html, 'image'),
+ (Namespaces.html, 'img'),
+ (Namespaces.html, 'input'),
+ (Namespaces.html, 'isindex'),
+ (Namespaces.html, 'li'),
+ (Namespaces.html, 'link'),
+ (Namespaces.html, 'listing'),
+ (Namespaces.html, 'marquee'),
+ (Namespaces.html, 'men'),
+ (Namespaces.html, 'meta'),
+ (Namespaces.html, 'nav'),
+ (Namespaces.html, 'noembed'),
+ (Namespaces.html, 'noframes'),
+ (Namespaces.html, 'noscript'),
+ (Namespaces.html, 'object'),
+ (Namespaces.html, 'ol'),
+ (Namespaces.html, 'p'),
+ (Namespaces.html, 'param'),
+ (Namespaces.html, 'plaintext'),
+ (Namespaces.html, 'pre'),
+ (Namespaces.html, 'script'),
+ (Namespaces.html, 'section'),
+ (Namespaces.html, 'select'),
+ (Namespaces.html, 'style'),
+ (Namespaces.html, 'table'),
+ (Namespaces.html, 'tbody'),
+ (Namespaces.html, 'td'),
+ (Namespaces.html, 'textarea'),
+ (Namespaces.html, 'tfoot'),
+ (Namespaces.html, 'th'),
+ (Namespaces.html, 'thead'),
+ (Namespaces.html, 'title'),
+ (Namespaces.html, 'tr'),
+ (Namespaces.html, 'ul'),
+ (Namespaces.html, 'wbr'),
+ (Namespaces.html, 'xmp'),
+ (Namespaces.svg, 'foreignObject')
+];
+
+const htmlIntegrationPointElements = [
+ (Namespaces.mathml, 'annotaion-xml'),
+ (Namespaces.svg, 'foreignObject'),
+ (Namespaces.svg, 'desc'),
+ (Namespaces.svg, 'title')
+];
+
+const mathmlTextIntegrationPointElements = [
+ (Namespaces.mathml, 'mi'),
+ (Namespaces.mathml, 'mo'),
+ (Namespaces.mathml, 'mn'),
+ (Namespaces.mathml, 'ms'),
+ (Namespaces.mathml, 'mtext')
+];
+
+const spaceCharacters = ' \n\r\t\u000C';
+
+const int newLine = 10;
+const int returnCode = 13;
+
+bool isWhitespace(String? char) {
+ if (char == null) return false;
+ return isWhitespaceCC(char.codeUnitAt(0));
+}
+
+bool isWhitespaceCC(int charCode) {
+ switch (charCode) {
+ case 9: // '\t'
+ case newLine: // '\n'
+ case 12: // '\f'
+ case returnCode: // '\r'
+ case 32: // ' '
+ return true;
+ }
+ return false;
+}
+
+const List<String> tableInsertModeElements = [
+ 'table',
+ 'tbody',
+ 'tfoot',
+ 'thead',
+ 'tr'
+];
+
+// TODO(jmesserly): remove these in favor of the test functions
+const asciiLetters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+
+const _zeroCode = 48;
+const _lowerACode = 97;
+const _lowerZCode = 122;
+const _upperACode = 65;
+const _upperZCode = 90;
+
+bool isLetterOrDigit(String? char) => isLetter(char) || isDigit(char);
+
+// Note: this is intentially ASCII only
+bool isLetter(String? char) {
+ if (char == null) return false;
+ final cc = char.codeUnitAt(0);
+ return cc >= _lowerACode && cc <= _lowerZCode ||
+ cc >= _upperACode && cc <= _upperZCode;
+}
+
+bool isDigit(String? char) {
+ if (char == null) return false;
+ final cc = char.codeUnitAt(0);
+ return cc >= _zeroCode && cc < _zeroCode + 10;
+}
+
+bool isHexDigit(String? char) {
+ if (char == null) return false;
+ switch (char.codeUnitAt(0)) {
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52: // '0' - '4'
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57: // '5' - '9'
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70: // 'A' - 'F'
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102: // 'a' - 'f'
+ return true;
+ }
+ return false;
+}
+
+extension AsciiUpperToLower on String {
+ /// Converts ASCII characters to lowercase.
+ ///
+ /// Unlike [String.toLowerCase] does not touch non-ASCII characters.
+ String toAsciiLowerCase() =>
+ String.fromCharCodes(codeUnits.map(_asciiToLower));
+
+ static int _asciiToLower(int c) => (c >= _upperACode && c <= _upperZCode)
+ ? c + _lowerACode - _upperACode
+ : c;
+}
+
+// Heading elements need to be ordered
+const headingElements = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
+
+const cdataElements = ['title', 'textarea'];
+
+const rcdataElements = [
+ 'style',
+ 'script',
+ 'xmp',
+ 'iframe',
+ 'noembed',
+ 'noframes',
+ 'noscript'
+];
+
+// entitiesWindows1252 has to be _ordered_ and needs to have an index. It
+// therefore can't be a frozenset.
+const List<int> entitiesWindows1252 = [
+ 8364, // 0x80 0x20AC EURO SIGN
+ 65533, // 0x81 UNDEFINED
+ 8218, // 0x82 0x201A SINGLE LOW-9 QUOTATION MARK
+ 402, // 0x83 0x0192 LATIN SMALL LETTER F WITH HOOK
+ 8222, // 0x84 0x201E DOUBLE LOW-9 QUOTATION MARK
+ 8230, // 0x85 0x2026 HORIZONTAL ELLIPSIS
+ 8224, // 0x86 0x2020 DAGGER
+ 8225, // 0x87 0x2021 DOUBLE DAGGER
+ 710, // 0x88 0x02C6 MODIFIER LETTER CIRCUMFLEX ACCENT
+ 8240, // 0x89 0x2030 PER MILLE SIGN
+ 352, // 0x8A 0x0160 LATIN CAPITAL LETTER S WITH CARON
+ 8249, // 0x8B 0x2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 338, // 0x8C 0x0152 LATIN CAPITAL LIGATURE OE
+ 65533, // 0x8D UNDEFINED
+ 381, // 0x8E 0x017D LATIN CAPITAL LETTER Z WITH CARON
+ 65533, // 0x8F UNDEFINED
+ 65533, // 0x90 UNDEFINED
+ 8216, // 0x91 0x2018 LEFT SINGLE QUOTATION MARK
+ 8217, // 0x92 0x2019 RIGHT SINGLE QUOTATION MARK
+ 8220, // 0x93 0x201C LEFT DOUBLE QUOTATION MARK
+ 8221, // 0x94 0x201D RIGHT DOUBLE QUOTATION MARK
+ 8226, // 0x95 0x2022 BULLET
+ 8211, // 0x96 0x2013 EN DASH
+ 8212, // 0x97 0x2014 EM DASH
+ 732, // 0x98 0x02DC SMALL TILDE
+ 8482, // 0x99 0x2122 TRADE MARK SIGN
+ 353, // 0x9A 0x0161 LATIN SMALL LETTER S WITH CARON
+ 8250, // 0x9B 0x203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 339, // 0x9C 0x0153 LATIN SMALL LIGATURE OE
+ 65533, // 0x9D UNDEFINED
+ 382, // 0x9E 0x017E LATIN SMALL LETTER Z WITH CARON
+ 376 // 0x9F 0x0178 LATIN CAPITAL LETTER Y WITH DIAERESIS
+];
+
+const xmlEntities = ['lt;', 'gt;', 'amp;', 'apos;', 'quot;'];
+
+const Map<String, String> entities = {
+ 'AElig': '\xc6',
+ 'AElig;': '\xc6',
+ 'AMP': '&',
+ 'AMP;': '&',
+ 'Aacute': '\xc1',
+ 'Aacute;': '\xc1',
+ 'Abreve;': '\u0102',
+ 'Acirc': '\xc2',
+ 'Acirc;': '\xc2',
+ 'Acy;': '\u0410',
+ 'Afr;': '\u{01d504}',
+ 'Agrave': '\xc0',
+ 'Agrave;': '\xc0',
+ 'Alpha;': '\u0391',
+ 'Amacr;': '\u0100',
+ 'And;': '\u2a53',
+ 'Aogon;': '\u0104',
+ 'Aopf;': '\u{01d538}',
+ 'ApplyFunction;': '\u2061',
+ 'Aring': '\xc5',
+ 'Aring;': '\xc5',
+ 'Ascr;': '\u{01d49c}',
+ 'Assign;': '\u2254',
+ 'Atilde': '\xc3',
+ 'Atilde;': '\xc3',
+ 'Auml': '\xc4',
+ 'Auml;': '\xc4',
+ 'Backslash;': '\u2216',
+ 'Barv;': '\u2ae7',
+ 'Barwed;': '\u2306',
+ 'Bcy;': '\u0411',
+ 'Because;': '\u2235',
+ 'Bernoullis;': '\u212c',
+ 'Beta;': '\u0392',
+ 'Bfr;': '\u{01d505}',
+ 'Bopf;': '\u{01d539}',
+ 'Breve;': '\u02d8',
+ 'Bscr;': '\u212c',
+ 'Bumpeq;': '\u224e',
+ 'CHcy;': '\u0427',
+ 'COPY': '\xa9',
+ 'COPY;': '\xa9',
+ 'Cacute;': '\u0106',
+ 'Cap;': '\u22d2',
+ 'CapitalDifferentialD;': '\u2145',
+ 'Cayleys;': '\u212d',
+ 'Ccaron;': '\u010c',
+ 'Ccedil': '\xc7',
+ 'Ccedil;': '\xc7',
+ 'Ccirc;': '\u0108',
+ 'Cconint;': '\u2230',
+ 'Cdot;': '\u010a',
+ 'Cedilla;': '\xb8',
+ 'CenterDot;': '\xb7',
+ 'Cfr;': '\u212d',
+ 'Chi;': '\u03a7',
+ 'CircleDot;': '\u2299',
+ 'CircleMinus;': '\u2296',
+ 'CirclePlus;': '\u2295',
+ 'CircleTimes;': '\u2297',
+ 'ClockwiseContourIntegral;': '\u2232',
+ 'CloseCurlyDoubleQuote;': '\u201d',
+ 'CloseCurlyQuote;': '\u2019',
+ 'Colon;': '\u2237',
+ 'Colone;': '\u2a74',
+ 'Congruent;': '\u2261',
+ 'Conint;': '\u222f',
+ 'ContourIntegral;': '\u222e',
+ 'Copf;': '\u2102',
+ 'Coproduct;': '\u2210',
+ 'CounterClockwiseContourIntegral;': '\u2233',
+ 'Cross;': '\u2a2f',
+ 'Cscr;': '\u{01d49e}',
+ 'Cup;': '\u22d3',
+ 'CupCap;': '\u224d',
+ 'DD;': '\u2145',
+ 'DDotrahd;': '\u2911',
+ 'DJcy;': '\u0402',
+ 'DScy;': '\u0405',
+ 'DZcy;': '\u040f',
+ 'Dagger;': '\u2021',
+ 'Darr;': '\u21a1',
+ 'Dashv;': '\u2ae4',
+ 'Dcaron;': '\u010e',
+ 'Dcy;': '\u0414',
+ 'Del;': '\u2207',
+ 'Delta;': '\u0394',
+ 'Dfr;': '\u{01d507}',
+ 'DiacriticalAcute;': '\xb4',
+ 'DiacriticalDot;': '\u02d9',
+ 'DiacriticalDoubleAcute;': '\u02dd',
+ 'DiacriticalGrave;': '`',
+ 'DiacriticalTilde;': '\u02dc',
+ 'Diamond;': '\u22c4',
+ 'DifferentialD;': '\u2146',
+ 'Dopf;': '\u{01d53b}',
+ 'Dot;': '\xa8',
+ 'DotDot;': '\u20dc',
+ 'DotEqual;': '\u2250',
+ 'DoubleContourIntegral;': '\u222f',
+ 'DoubleDot;': '\xa8',
+ 'DoubleDownArrow;': '\u21d3',
+ 'DoubleLeftArrow;': '\u21d0',
+ 'DoubleLeftRightArrow;': '\u21d4',
+ 'DoubleLeftTee;': '\u2ae4',
+ 'DoubleLongLeftArrow;': '\u27f8',
+ 'DoubleLongLeftRightArrow;': '\u27fa',
+ 'DoubleLongRightArrow;': '\u27f9',
+ 'DoubleRightArrow;': '\u21d2',
+ 'DoubleRightTee;': '\u22a8',
+ 'DoubleUpArrow;': '\u21d1',
+ 'DoubleUpDownArrow;': '\u21d5',
+ 'DoubleVerticalBar;': '\u2225',
+ 'DownArrow;': '\u2193',
+ 'DownArrowBar;': '\u2913',
+ 'DownArrowUpArrow;': '\u21f5',
+ 'DownBreve;': '\u0311',
+ 'DownLeftRightVector;': '\u2950',
+ 'DownLeftTeeVector;': '\u295e',
+ 'DownLeftVector;': '\u21bd',
+ 'DownLeftVectorBar;': '\u2956',
+ 'DownRightTeeVector;': '\u295f',
+ 'DownRightVector;': '\u21c1',
+ 'DownRightVectorBar;': '\u2957',
+ 'DownTee;': '\u22a4',
+ 'DownTeeArrow;': '\u21a7',
+ 'Downarrow;': '\u21d3',
+ 'Dscr;': '\u{01d49f}',
+ 'Dstrok;': '\u0110',
+ 'ENG;': '\u014a',
+ 'ETH': '\xd0',
+ 'ETH;': '\xd0',
+ 'Eacute': '\xc9',
+ 'Eacute;': '\xc9',
+ 'Ecaron;': '\u011a',
+ 'Ecirc': '\xca',
+ 'Ecirc;': '\xca',
+ 'Ecy;': '\u042d',
+ 'Edot;': '\u0116',
+ 'Efr;': '\u{01d508}',
+ 'Egrave': '\xc8',
+ 'Egrave;': '\xc8',
+ 'Element;': '\u2208',
+ 'Emacr;': '\u0112',
+ 'EmptySmallSquare;': '\u25fb',
+ 'EmptyVerySmallSquare;': '\u25ab',
+ 'Eogon;': '\u0118',
+ 'Eopf;': '\u{01d53c}',
+ 'Epsilon;': '\u0395',
+ 'Equal;': '\u2a75',
+ 'EqualTilde;': '\u2242',
+ 'Equilibrium;': '\u21cc',
+ 'Escr;': '\u2130',
+ 'Esim;': '\u2a73',
+ 'Eta;': '\u0397',
+ 'Euml': '\xcb',
+ 'Euml;': '\xcb',
+ 'Exists;': '\u2203',
+ 'ExponentialE;': '\u2147',
+ 'Fcy;': '\u0424',
+ 'Ffr;': '\u{01d509}',
+ 'FilledSmallSquare;': '\u25fc',
+ 'FilledVerySmallSquare;': '\u25aa',
+ 'Fopf;': '\u{01d53d}',
+ 'ForAll;': '\u2200',
+ 'Fouriertrf;': '\u2131',
+ 'Fscr;': '\u2131',
+ 'GJcy;': '\u0403',
+ 'GT': '>',
+ 'GT;': '>',
+ 'Gamma;': '\u0393',
+ 'Gammad;': '\u03dc',
+ 'Gbreve;': '\u011e',
+ 'Gcedil;': '\u0122',
+ 'Gcirc;': '\u011c',
+ 'Gcy;': '\u0413',
+ 'Gdot;': '\u0120',
+ 'Gfr;': '\u{01d50a}',
+ 'Gg;': '\u22d9',
+ 'Gopf;': '\u{01d53e}',
+ 'GreaterEqual;': '\u2265',
+ 'GreaterEqualLess;': '\u22db',
+ 'GreaterFullEqual;': '\u2267',
+ 'GreaterGreater;': '\u2aa2',
+ 'GreaterLess;': '\u2277',
+ 'GreaterSlantEqual;': '\u2a7e',
+ 'GreaterTilde;': '\u2273',
+ 'Gscr;': '\u{01d4a2}',
+ 'Gt;': '\u226b',
+ 'HARDcy;': '\u042a',
+ 'Hacek;': '\u02c7',
+ 'Hat;': '^',
+ 'Hcirc;': '\u0124',
+ 'Hfr;': '\u210c',
+ 'HilbertSpace;': '\u210b',
+ 'Hopf;': '\u210d',
+ 'HorizontalLine;': '\u2500',
+ 'Hscr;': '\u210b',
+ 'Hstrok;': '\u0126',
+ 'HumpDownHump;': '\u224e',
+ 'HumpEqual;': '\u224f',
+ 'IEcy;': '\u0415',
+ 'IJlig;': '\u0132',
+ 'IOcy;': '\u0401',
+ 'Iacute': '\xcd',
+ 'Iacute;': '\xcd',
+ 'Icirc': '\xce',
+ 'Icirc;': '\xce',
+ 'Icy;': '\u0418',
+ 'Idot;': '\u0130',
+ 'Ifr;': '\u2111',
+ 'Igrave': '\xcc',
+ 'Igrave;': '\xcc',
+ 'Im;': '\u2111',
+ 'Imacr;': '\u012a',
+ 'ImaginaryI;': '\u2148',
+ 'Implies;': '\u21d2',
+ 'Int;': '\u222c',
+ 'Integral;': '\u222b',
+ 'Intersection;': '\u22c2',
+ 'InvisibleComma;': '\u2063',
+ 'InvisibleTimes;': '\u2062',
+ 'Iogon;': '\u012e',
+ 'Iopf;': '\u{01d540}',
+ 'Iota;': '\u0399',
+ 'Iscr;': '\u2110',
+ 'Itilde;': '\u0128',
+ 'Iukcy;': '\u0406',
+ 'Iuml': '\xcf',
+ 'Iuml;': '\xcf',
+ 'Jcirc;': '\u0134',
+ 'Jcy;': '\u0419',
+ 'Jfr;': '\u{01d50d}',
+ 'Jopf;': '\u{01d541}',
+ 'Jscr;': '\u{01d4a5}',
+ 'Jsercy;': '\u0408',
+ 'Jukcy;': '\u0404',
+ 'KHcy;': '\u0425',
+ 'KJcy;': '\u040c',
+ 'Kappa;': '\u039a',
+ 'Kcedil;': '\u0136',
+ 'Kcy;': '\u041a',
+ 'Kfr;': '\u{01d50e}',
+ 'Kopf;': '\u{01d542}',
+ 'Kscr;': '\u{01d4a6}',
+ 'LJcy;': '\u0409',
+ 'LT': '<',
+ 'LT;': '<',
+ 'Lacute;': '\u0139',
+ 'Lambda;': '\u039b',
+ 'Lang;': '\u27ea',
+ 'Laplacetrf;': '\u2112',
+ 'Larr;': '\u219e',
+ 'Lcaron;': '\u013d',
+ 'Lcedil;': '\u013b',
+ 'Lcy;': '\u041b',
+ 'LeftAngleBracket;': '\u27e8',
+ 'LeftArrow;': '\u2190',
+ 'LeftArrowBar;': '\u21e4',
+ 'LeftArrowRightArrow;': '\u21c6',
+ 'LeftCeiling;': '\u2308',
+ 'LeftDoubleBracket;': '\u27e6',
+ 'LeftDownTeeVector;': '\u2961',
+ 'LeftDownVector;': '\u21c3',
+ 'LeftDownVectorBar;': '\u2959',
+ 'LeftFloor;': '\u230a',
+ 'LeftRightArrow;': '\u2194',
+ 'LeftRightVector;': '\u294e',
+ 'LeftTee;': '\u22a3',
+ 'LeftTeeArrow;': '\u21a4',
+ 'LeftTeeVector;': '\u295a',
+ 'LeftTriangle;': '\u22b2',
+ 'LeftTriangleBar;': '\u29cf',
+ 'LeftTriangleEqual;': '\u22b4',
+ 'LeftUpDownVector;': '\u2951',
+ 'LeftUpTeeVector;': '\u2960',
+ 'LeftUpVector;': '\u21bf',
+ 'LeftUpVectorBar;': '\u2958',
+ 'LeftVector;': '\u21bc',
+ 'LeftVectorBar;': '\u2952',
+ 'Leftarrow;': '\u21d0',
+ 'Leftrightarrow;': '\u21d4',
+ 'LessEqualGreater;': '\u22da',
+ 'LessFullEqual;': '\u2266',
+ 'LessGreater;': '\u2276',
+ 'LessLess;': '\u2aa1',
+ 'LessSlantEqual;': '\u2a7d',
+ 'LessTilde;': '\u2272',
+ 'Lfr;': '\u{01d50f}',
+ 'Ll;': '\u22d8',
+ 'Lleftarrow;': '\u21da',
+ 'Lmidot;': '\u013f',
+ 'LongLeftArrow;': '\u27f5',
+ 'LongLeftRightArrow;': '\u27f7',
+ 'LongRightArrow;': '\u27f6',
+ 'Longleftarrow;': '\u27f8',
+ 'Longleftrightarrow;': '\u27fa',
+ 'Longrightarrow;': '\u27f9',
+ 'Lopf;': '\u{01d543}',
+ 'LowerLeftArrow;': '\u2199',
+ 'LowerRightArrow;': '\u2198',
+ 'Lscr;': '\u2112',
+ 'Lsh;': '\u21b0',
+ 'Lstrok;': '\u0141',
+ 'Lt;': '\u226a',
+ 'Map;': '\u2905',
+ 'Mcy;': '\u041c',
+ 'MediumSpace;': '\u205f',
+ 'Mellintrf;': '\u2133',
+ 'Mfr;': '\u{01d510}',
+ 'MinusPlus;': '\u2213',
+ 'Mopf;': '\u{01d544}',
+ 'Mscr;': '\u2133',
+ 'Mu;': '\u039c',
+ 'NJcy;': '\u040a',
+ 'Nacute;': '\u0143',
+ 'Ncaron;': '\u0147',
+ 'Ncedil;': '\u0145',
+ 'Ncy;': '\u041d',
+ 'NegativeMediumSpace;': '\u200b',
+ 'NegativeThickSpace;': '\u200b',
+ 'NegativeThinSpace;': '\u200b',
+ 'NegativeVeryThinSpace;': '\u200b',
+ 'NestedGreaterGreater;': '\u226b',
+ 'NestedLessLess;': '\u226a',
+ 'NewLine;': '\n',
+ 'Nfr;': '\u{01d511}',
+ 'NoBreak;': '\u2060',
+ 'NonBreakingSpace;': '\xa0',
+ 'Nopf;': '\u2115',
+ 'Not;': '\u2aec',
+ 'NotCongruent;': '\u2262',
+ 'NotCupCap;': '\u226d',
+ 'NotDoubleVerticalBar;': '\u2226',
+ 'NotElement;': '\u2209',
+ 'NotEqual;': '\u2260',
+ 'NotEqualTilde;': '\u2242\u0338',
+ 'NotExists;': '\u2204',
+ 'NotGreater;': '\u226f',
+ 'NotGreaterEqual;': '\u2271',
+ 'NotGreaterFullEqual;': '\u2267\u0338',
+ 'NotGreaterGreater;': '\u226b\u0338',
+ 'NotGreaterLess;': '\u2279',
+ 'NotGreaterSlantEqual;': '\u2a7e\u0338',
+ 'NotGreaterTilde;': '\u2275',
+ 'NotHumpDownHump;': '\u224e\u0338',
+ 'NotHumpEqual;': '\u224f\u0338',
+ 'NotLeftTriangle;': '\u22ea',
+ 'NotLeftTriangleBar;': '\u29cf\u0338',
+ 'NotLeftTriangleEqual;': '\u22ec',
+ 'NotLess;': '\u226e',
+ 'NotLessEqual;': '\u2270',
+ 'NotLessGreater;': '\u2278',
+ 'NotLessLess;': '\u226a\u0338',
+ 'NotLessSlantEqual;': '\u2a7d\u0338',
+ 'NotLessTilde;': '\u2274',
+ 'NotNestedGreaterGreater;': '\u2aa2\u0338',
+ 'NotNestedLessLess;': '\u2aa1\u0338',
+ 'NotPrecedes;': '\u2280',
+ 'NotPrecedesEqual;': '\u2aaf\u0338',
+ 'NotPrecedesSlantEqual;': '\u22e0',
+ 'NotReverseElement;': '\u220c',
+ 'NotRightTriangle;': '\u22eb',
+ 'NotRightTriangleBar;': '\u29d0\u0338',
+ 'NotRightTriangleEqual;': '\u22ed',
+ 'NotSquareSubset;': '\u228f\u0338',
+ 'NotSquareSubsetEqual;': '\u22e2',
+ 'NotSquareSuperset;': '\u2290\u0338',
+ 'NotSquareSupersetEqual;': '\u22e3',
+ 'NotSubset;': '\u2282\u20d2',
+ 'NotSubsetEqual;': '\u2288',
+ 'NotSucceeds;': '\u2281',
+ 'NotSucceedsEqual;': '\u2ab0\u0338',
+ 'NotSucceedsSlantEqual;': '\u22e1',
+ 'NotSucceedsTilde;': '\u227f\u0338',
+ 'NotSuperset;': '\u2283\u20d2',
+ 'NotSupersetEqual;': '\u2289',
+ 'NotTilde;': '\u2241',
+ 'NotTildeEqual;': '\u2244',
+ 'NotTildeFullEqual;': '\u2247',
+ 'NotTildeTilde;': '\u2249',
+ 'NotVerticalBar;': '\u2224',
+ 'Nscr;': '\u{01d4a9}',
+ 'Ntilde': '\xd1',
+ 'Ntilde;': '\xd1',
+ 'Nu;': '\u039d',
+ 'OElig;': '\u0152',
+ 'Oacute': '\xd3',
+ 'Oacute;': '\xd3',
+ 'Ocirc': '\xd4',
+ 'Ocirc;': '\xd4',
+ 'Ocy;': '\u041e',
+ 'Odblac;': '\u0150',
+ 'Ofr;': '\u{01d512}',
+ 'Ograve': '\xd2',
+ 'Ograve;': '\xd2',
+ 'Omacr;': '\u014c',
+ 'Omega;': '\u03a9',
+ 'Omicron;': '\u039f',
+ 'Oopf;': '\u{01d546}',
+ 'OpenCurlyDoubleQuote;': '\u201c',
+ 'OpenCurlyQuote;': '\u2018',
+ 'Or;': '\u2a54',
+ 'Oscr;': '\u{01d4aa}',
+ 'Oslash': '\xd8',
+ 'Oslash;': '\xd8',
+ 'Otilde': '\xd5',
+ 'Otilde;': '\xd5',
+ 'Otimes;': '\u2a37',
+ 'Ouml': '\xd6',
+ 'Ouml;': '\xd6',
+ 'OverBar;': '\u203e',
+ 'OverBrace;': '\u23de',
+ 'OverBracket;': '\u23b4',
+ 'OverParenthesis;': '\u23dc',
+ 'PartialD;': '\u2202',
+ 'Pcy;': '\u041f',
+ 'Pfr;': '\u{01d513}',
+ 'Phi;': '\u03a6',
+ 'Pi;': '\u03a0',
+ 'PlusMinus;': '\xb1',
+ 'Poincareplane;': '\u210c',
+ 'Popf;': '\u2119',
+ 'Pr;': '\u2abb',
+ 'Precedes;': '\u227a',
+ 'PrecedesEqual;': '\u2aaf',
+ 'PrecedesSlantEqual;': '\u227c',
+ 'PrecedesTilde;': '\u227e',
+ 'Prime;': '\u2033',
+ 'Product;': '\u220f',
+ 'Proportion;': '\u2237',
+ 'Proportional;': '\u221d',
+ 'Pscr;': '\u{01d4ab}',
+ 'Psi;': '\u03a8',
+ 'QUOT': '"',
+ 'QUOT;': '"',
+ 'Qfr;': '\u{01d514}',
+ 'Qopf;': '\u211a',
+ 'Qscr;': '\u{01d4ac}',
+ 'RBarr;': '\u2910',
+ 'REG': '\xae',
+ 'REG;': '\xae',
+ 'Racute;': '\u0154',
+ 'Rang;': '\u27eb',
+ 'Rarr;': '\u21a0',
+ 'Rarrtl;': '\u2916',
+ 'Rcaron;': '\u0158',
+ 'Rcedil;': '\u0156',
+ 'Rcy;': '\u0420',
+ 'Re;': '\u211c',
+ 'ReverseElement;': '\u220b',
+ 'ReverseEquilibrium;': '\u21cb',
+ 'ReverseUpEquilibrium;': '\u296f',
+ 'Rfr;': '\u211c',
+ 'Rho;': '\u03a1',
+ 'RightAngleBracket;': '\u27e9',
+ 'RightArrow;': '\u2192',
+ 'RightArrowBar;': '\u21e5',
+ 'RightArrowLeftArrow;': '\u21c4',
+ 'RightCeiling;': '\u2309',
+ 'RightDoubleBracket;': '\u27e7',
+ 'RightDownTeeVector;': '\u295d',
+ 'RightDownVector;': '\u21c2',
+ 'RightDownVectorBar;': '\u2955',
+ 'RightFloor;': '\u230b',
+ 'RightTee;': '\u22a2',
+ 'RightTeeArrow;': '\u21a6',
+ 'RightTeeVector;': '\u295b',
+ 'RightTriangle;': '\u22b3',
+ 'RightTriangleBar;': '\u29d0',
+ 'RightTriangleEqual;': '\u22b5',
+ 'RightUpDownVector;': '\u294f',
+ 'RightUpTeeVector;': '\u295c',
+ 'RightUpVector;': '\u21be',
+ 'RightUpVectorBar;': '\u2954',
+ 'RightVector;': '\u21c0',
+ 'RightVectorBar;': '\u2953',
+ 'Rightarrow;': '\u21d2',
+ 'Ropf;': '\u211d',
+ 'RoundImplies;': '\u2970',
+ 'Rrightarrow;': '\u21db',
+ 'Rscr;': '\u211b',
+ 'Rsh;': '\u21b1',
+ 'RuleDelayed;': '\u29f4',
+ 'SHCHcy;': '\u0429',
+ 'SHcy;': '\u0428',
+ 'SOFTcy;': '\u042c',
+ 'Sacute;': '\u015a',
+ 'Sc;': '\u2abc',
+ 'Scaron;': '\u0160',
+ 'Scedil;': '\u015e',
+ 'Scirc;': '\u015c',
+ 'Scy;': '\u0421',
+ 'Sfr;': '\u{01d516}',
+ 'ShortDownArrow;': '\u2193',
+ 'ShortLeftArrow;': '\u2190',
+ 'ShortRightArrow;': '\u2192',
+ 'ShortUpArrow;': '\u2191',
+ 'Sigma;': '\u03a3',
+ 'SmallCircle;': '\u2218',
+ 'Sopf;': '\u{01d54a}',
+ 'Sqrt;': '\u221a',
+ 'Square;': '\u25a1',
+ 'SquareIntersection;': '\u2293',
+ 'SquareSubset;': '\u228f',
+ 'SquareSubsetEqual;': '\u2291',
+ 'SquareSuperset;': '\u2290',
+ 'SquareSupersetEqual;': '\u2292',
+ 'SquareUnion;': '\u2294',
+ 'Sscr;': '\u{01d4ae}',
+ 'Star;': '\u22c6',
+ 'Sub;': '\u22d0',
+ 'Subset;': '\u22d0',
+ 'SubsetEqual;': '\u2286',
+ 'Succeeds;': '\u227b',
+ 'SucceedsEqual;': '\u2ab0',
+ 'SucceedsSlantEqual;': '\u227d',
+ 'SucceedsTilde;': '\u227f',
+ 'SuchThat;': '\u220b',
+ 'Sum;': '\u2211',
+ 'Sup;': '\u22d1',
+ 'Superset;': '\u2283',
+ 'SupersetEqual;': '\u2287',
+ 'Supset;': '\u22d1',
+ 'THORN': '\xde',
+ 'THORN;': '\xde',
+ 'TRADE;': '\u2122',
+ 'TSHcy;': '\u040b',
+ 'TScy;': '\u0426',
+ 'Tab;': '\t',
+ 'Tau;': '\u03a4',
+ 'Tcaron;': '\u0164',
+ 'Tcedil;': '\u0162',
+ 'Tcy;': '\u0422',
+ 'Tfr;': '\u{01d517}',
+ 'Therefore;': '\u2234',
+ 'Theta;': '\u0398',
+ 'ThickSpace;': '\u205f\u200a',
+ 'ThinSpace;': '\u2009',
+ 'Tilde;': '\u223c',
+ 'TildeEqual;': '\u2243',
+ 'TildeFullEqual;': '\u2245',
+ 'TildeTilde;': '\u2248',
+ 'Topf;': '\u{01d54b}',
+ 'TripleDot;': '\u20db',
+ 'Tscr;': '\u{01d4af}',
+ 'Tstrok;': '\u0166',
+ 'Uacute': '\xda',
+ 'Uacute;': '\xda',
+ 'Uarr;': '\u219f',
+ 'Uarrocir;': '\u2949',
+ 'Ubrcy;': '\u040e',
+ 'Ubreve;': '\u016c',
+ 'Ucirc': '\xdb',
+ 'Ucirc;': '\xdb',
+ 'Ucy;': '\u0423',
+ 'Udblac;': '\u0170',
+ 'Ufr;': '\u{01d518}',
+ 'Ugrave': '\xd9',
+ 'Ugrave;': '\xd9',
+ 'Umacr;': '\u016a',
+ 'UnderBar;': '_',
+ 'UnderBrace;': '\u23df',
+ 'UnderBracket;': '\u23b5',
+ 'UnderParenthesis;': '\u23dd',
+ 'Union;': '\u22c3',
+ 'UnionPlus;': '\u228e',
+ 'Uogon;': '\u0172',
+ 'Uopf;': '\u{01d54c}',
+ 'UpArrow;': '\u2191',
+ 'UpArrowBar;': '\u2912',
+ 'UpArrowDownArrow;': '\u21c5',
+ 'UpDownArrow;': '\u2195',
+ 'UpEquilibrium;': '\u296e',
+ 'UpTee;': '\u22a5',
+ 'UpTeeArrow;': '\u21a5',
+ 'Uparrow;': '\u21d1',
+ 'Updownarrow;': '\u21d5',
+ 'UpperLeftArrow;': '\u2196',
+ 'UpperRightArrow;': '\u2197',
+ 'Upsi;': '\u03d2',
+ 'Upsilon;': '\u03a5',
+ 'Uring;': '\u016e',
+ 'Uscr;': '\u{01d4b0}',
+ 'Utilde;': '\u0168',
+ 'Uuml': '\xdc',
+ 'Uuml;': '\xdc',
+ 'VDash;': '\u22ab',
+ 'Vbar;': '\u2aeb',
+ 'Vcy;': '\u0412',
+ 'Vdash;': '\u22a9',
+ 'Vdashl;': '\u2ae6',
+ 'Vee;': '\u22c1',
+ 'Verbar;': '\u2016',
+ 'Vert;': '\u2016',
+ 'VerticalBar;': '\u2223',
+ 'VerticalLine;': '|',
+ 'VerticalSeparator;': '\u2758',
+ 'VerticalTilde;': '\u2240',
+ 'VeryThinSpace;': '\u200a',
+ 'Vfr;': '\u{01d519}',
+ 'Vopf;': '\u{01d54d}',
+ 'Vscr;': '\u{01d4b1}',
+ 'Vvdash;': '\u22aa',
+ 'Wcirc;': '\u0174',
+ 'Wedge;': '\u22c0',
+ 'Wfr;': '\u{01d51a}',
+ 'Wopf;': '\u{01d54e}',
+ 'Wscr;': '\u{01d4b2}',
+ 'Xfr;': '\u{01d51b}',
+ 'Xi;': '\u039e',
+ 'Xopf;': '\u{01d54f}',
+ 'Xscr;': '\u{01d4b3}',
+ 'YAcy;': '\u042f',
+ 'YIcy;': '\u0407',
+ 'YUcy;': '\u042e',
+ 'Yacute': '\xdd',
+ 'Yacute;': '\xdd',
+ 'Ycirc;': '\u0176',
+ 'Ycy;': '\u042b',
+ 'Yfr;': '\u{01d51c}',
+ 'Yopf;': '\u{01d550}',
+ 'Yscr;': '\u{01d4b4}',
+ 'Yuml;': '\u0178',
+ 'ZHcy;': '\u0416',
+ 'Zacute;': '\u0179',
+ 'Zcaron;': '\u017d',
+ 'Zcy;': '\u0417',
+ 'Zdot;': '\u017b',
+ 'ZeroWidthSpace;': '\u200b',
+ 'Zeta;': '\u0396',
+ 'Zfr;': '\u2128',
+ 'Zopf;': '\u2124',
+ 'Zscr;': '\u{01d4b5}',
+ 'aacute': '\xe1',
+ 'aacute;': '\xe1',
+ 'abreve;': '\u0103',
+ 'ac;': '\u223e',
+ 'acE;': '\u223e\u0333',
+ 'acd;': '\u223f',
+ 'acirc': '\xe2',
+ 'acirc;': '\xe2',
+ 'acute': '\xb4',
+ 'acute;': '\xb4',
+ 'acy;': '\u0430',
+ 'aelig': '\xe6',
+ 'aelig;': '\xe6',
+ 'af;': '\u2061',
+ 'afr;': '\u{01d51e}',
+ 'agrave': '\xe0',
+ 'agrave;': '\xe0',
+ 'alefsym;': '\u2135',
+ 'aleph;': '\u2135',
+ 'alpha;': '\u03b1',
+ 'amacr;': '\u0101',
+ 'amalg;': '\u2a3f',
+ 'amp': '&',
+ 'amp;': '&',
+ 'and;': '\u2227',
+ 'andand;': '\u2a55',
+ 'andd;': '\u2a5c',
+ 'andslope;': '\u2a58',
+ 'andv;': '\u2a5a',
+ 'ang;': '\u2220',
+ 'ange;': '\u29a4',
+ 'angle;': '\u2220',
+ 'angmsd;': '\u2221',
+ 'angmsdaa;': '\u29a8',
+ 'angmsdab;': '\u29a9',
+ 'angmsdac;': '\u29aa',
+ 'angmsdad;': '\u29ab',
+ 'angmsdae;': '\u29ac',
+ 'angmsdaf;': '\u29ad',
+ 'angmsdag;': '\u29ae',
+ 'angmsdah;': '\u29af',
+ 'angrt;': '\u221f',
+ 'angrtvb;': '\u22be',
+ 'angrtvbd;': '\u299d',
+ 'angsph;': '\u2222',
+ 'angst;': '\xc5',
+ 'angzarr;': '\u237c',
+ 'aogon;': '\u0105',
+ 'aopf;': '\u{01d552}',
+ 'ap;': '\u2248',
+ 'apE;': '\u2a70',
+ 'apacir;': '\u2a6f',
+ 'ape;': '\u224a',
+ 'apid;': '\u224b',
+ 'apos;': "'",
+ 'approx;': '\u2248',
+ 'approxeq;': '\u224a',
+ 'aring': '\xe5',
+ 'aring;': '\xe5',
+ 'ascr;': '\u{01d4b6}',
+ 'ast;': '*',
+ 'asymp;': '\u2248',
+ 'asympeq;': '\u224d',
+ 'atilde': '\xe3',
+ 'atilde;': '\xe3',
+ 'auml': '\xe4',
+ 'auml;': '\xe4',
+ 'awconint;': '\u2233',
+ 'awint;': '\u2a11',
+ 'bNot;': '\u2aed',
+ 'backcong;': '\u224c',
+ 'backepsilon;': '\u03f6',
+ 'backprime;': '\u2035',
+ 'backsim;': '\u223d',
+ 'backsimeq;': '\u22cd',
+ 'barvee;': '\u22bd',
+ 'barwed;': '\u2305',
+ 'barwedge;': '\u2305',
+ 'bbrk;': '\u23b5',
+ 'bbrktbrk;': '\u23b6',
+ 'bcong;': '\u224c',
+ 'bcy;': '\u0431',
+ 'bdquo;': '\u201e',
+ 'becaus;': '\u2235',
+ 'because;': '\u2235',
+ 'bemptyv;': '\u29b0',
+ 'bepsi;': '\u03f6',
+ 'bernou;': '\u212c',
+ 'beta;': '\u03b2',
+ 'beth;': '\u2136',
+ 'between;': '\u226c',
+ 'bfr;': '\u{01d51f}',
+ 'bigcap;': '\u22c2',
+ 'bigcirc;': '\u25ef',
+ 'bigcup;': '\u22c3',
+ 'bigodot;': '\u2a00',
+ 'bigoplus;': '\u2a01',
+ 'bigotimes;': '\u2a02',
+ 'bigsqcup;': '\u2a06',
+ 'bigstar;': '\u2605',
+ 'bigtriangledown;': '\u25bd',
+ 'bigtriangleup;': '\u25b3',
+ 'biguplus;': '\u2a04',
+ 'bigvee;': '\u22c1',
+ 'bigwedge;': '\u22c0',
+ 'bkarow;': '\u290d',
+ 'blacklozenge;': '\u29eb',
+ 'blacksquare;': '\u25aa',
+ 'blacktriangle;': '\u25b4',
+ 'blacktriangledown;': '\u25be',
+ 'blacktriangleleft;': '\u25c2',
+ 'blacktriangleright;': '\u25b8',
+ 'blank;': '\u2423',
+ 'blk12;': '\u2592',
+ 'blk14;': '\u2591',
+ 'blk34;': '\u2593',
+ 'block;': '\u2588',
+ 'bne;': '=\u20e5',
+ 'bnequiv;': '\u2261\u20e5',
+ 'bnot;': '\u2310',
+ 'bopf;': '\u{01d553}',
+ 'bot;': '\u22a5',
+ 'bottom;': '\u22a5',
+ 'bowtie;': '\u22c8',
+ 'boxDL;': '\u2557',
+ 'boxDR;': '\u2554',
+ 'boxDl;': '\u2556',
+ 'boxDr;': '\u2553',
+ 'boxH;': '\u2550',
+ 'boxHD;': '\u2566',
+ 'boxHU;': '\u2569',
+ 'boxHd;': '\u2564',
+ 'boxHu;': '\u2567',
+ 'boxUL;': '\u255d',
+ 'boxUR;': '\u255a',
+ 'boxUl;': '\u255c',
+ 'boxUr;': '\u2559',
+ 'boxV;': '\u2551',
+ 'boxVH;': '\u256c',
+ 'boxVL;': '\u2563',
+ 'boxVR;': '\u2560',
+ 'boxVh;': '\u256b',
+ 'boxVl;': '\u2562',
+ 'boxVr;': '\u255f',
+ 'boxbox;': '\u29c9',
+ 'boxdL;': '\u2555',
+ 'boxdR;': '\u2552',
+ 'boxdl;': '\u2510',
+ 'boxdr;': '\u250c',
+ 'boxh;': '\u2500',
+ 'boxhD;': '\u2565',
+ 'boxhU;': '\u2568',
+ 'boxhd;': '\u252c',
+ 'boxhu;': '\u2534',
+ 'boxminus;': '\u229f',
+ 'boxplus;': '\u229e',
+ 'boxtimes;': '\u22a0',
+ 'boxuL;': '\u255b',
+ 'boxuR;': '\u2558',
+ 'boxul;': '\u2518',
+ 'boxur;': '\u2514',
+ 'boxv;': '\u2502',
+ 'boxvH;': '\u256a',
+ 'boxvL;': '\u2561',
+ 'boxvR;': '\u255e',
+ 'boxvh;': '\u253c',
+ 'boxvl;': '\u2524',
+ 'boxvr;': '\u251c',
+ 'bprime;': '\u2035',
+ 'breve;': '\u02d8',
+ 'brvbar': '\xa6',
+ 'brvbar;': '\xa6',
+ 'bscr;': '\u{01d4b7}',
+ 'bsemi;': '\u204f',
+ 'bsim;': '\u223d',
+ 'bsime;': '\u22cd',
+ 'bsol;': '\\',
+ 'bsolb;': '\u29c5',
+ 'bsolhsub;': '\u27c8',
+ 'bull;': '\u2022',
+ 'bullet;': '\u2022',
+ 'bump;': '\u224e',
+ 'bumpE;': '\u2aae',
+ 'bumpe;': '\u224f',
+ 'bumpeq;': '\u224f',
+ 'cacute;': '\u0107',
+ 'cap;': '\u2229',
+ 'capand;': '\u2a44',
+ 'capbrcup;': '\u2a49',
+ 'capcap;': '\u2a4b',
+ 'capcup;': '\u2a47',
+ 'capdot;': '\u2a40',
+ 'caps;': '\u2229\ufe00',
+ 'caret;': '\u2041',
+ 'caron;': '\u02c7',
+ 'ccaps;': '\u2a4d',
+ 'ccaron;': '\u010d',
+ 'ccedil': '\xe7',
+ 'ccedil;': '\xe7',
+ 'ccirc;': '\u0109',
+ 'ccups;': '\u2a4c',
+ 'ccupssm;': '\u2a50',
+ 'cdot;': '\u010b',
+ 'cedil': '\xb8',
+ 'cedil;': '\xb8',
+ 'cemptyv;': '\u29b2',
+ 'cent': '\xa2',
+ 'cent;': '\xa2',
+ 'centerdot;': '\xb7',
+ 'cfr;': '\u{01d520}',
+ 'chcy;': '\u0447',
+ 'check;': '\u2713',
+ 'checkmark;': '\u2713',
+ 'chi;': '\u03c7',
+ 'cir;': '\u25cb',
+ 'cirE;': '\u29c3',
+ 'circ;': '\u02c6',
+ 'circeq;': '\u2257',
+ 'circlearrowleft;': '\u21ba',
+ 'circlearrowright;': '\u21bb',
+ 'circledR;': '\xae',
+ 'circledS;': '\u24c8',
+ 'circledast;': '\u229b',
+ 'circledcirc;': '\u229a',
+ 'circleddash;': '\u229d',
+ 'cire;': '\u2257',
+ 'cirfnint;': '\u2a10',
+ 'cirmid;': '\u2aef',
+ 'cirscir;': '\u29c2',
+ 'clubs;': '\u2663',
+ 'clubsuit;': '\u2663',
+ 'colon;': ':',
+ 'colone;': '\u2254',
+ 'coloneq;': '\u2254',
+ 'comma;': ',',
+ 'commat;': '@',
+ 'comp;': '\u2201',
+ 'compfn;': '\u2218',
+ 'complement;': '\u2201',
+ 'complexes;': '\u2102',
+ 'cong;': '\u2245',
+ 'congdot;': '\u2a6d',
+ 'conint;': '\u222e',
+ 'copf;': '\u{01d554}',
+ 'coprod;': '\u2210',
+ 'copy': '\xa9',
+ 'copy;': '\xa9',
+ 'copysr;': '\u2117',
+ 'crarr;': '\u21b5',
+ 'cross;': '\u2717',
+ 'cscr;': '\u{01d4b8}',
+ 'csub;': '\u2acf',
+ 'csube;': '\u2ad1',
+ 'csup;': '\u2ad0',
+ 'csupe;': '\u2ad2',
+ 'ctdot;': '\u22ef',
+ 'cudarrl;': '\u2938',
+ 'cudarrr;': '\u2935',
+ 'cuepr;': '\u22de',
+ 'cuesc;': '\u22df',
+ 'cularr;': '\u21b6',
+ 'cularrp;': '\u293d',
+ 'cup;': '\u222a',
+ 'cupbrcap;': '\u2a48',
+ 'cupcap;': '\u2a46',
+ 'cupcup;': '\u2a4a',
+ 'cupdot;': '\u228d',
+ 'cupor;': '\u2a45',
+ 'cups;': '\u222a\ufe00',
+ 'curarr;': '\u21b7',
+ 'curarrm;': '\u293c',
+ 'curlyeqprec;': '\u22de',
+ 'curlyeqsucc;': '\u22df',
+ 'curlyvee;': '\u22ce',
+ 'curlywedge;': '\u22cf',
+ 'curren': '\xa4',
+ 'curren;': '\xa4',
+ 'curvearrowleft;': '\u21b6',
+ 'curvearrowright;': '\u21b7',
+ 'cuvee;': '\u22ce',
+ 'cuwed;': '\u22cf',
+ 'cwconint;': '\u2232',
+ 'cwint;': '\u2231',
+ 'cylcty;': '\u232d',
+ 'dArr;': '\u21d3',
+ 'dHar;': '\u2965',
+ 'dagger;': '\u2020',
+ 'daleth;': '\u2138',
+ 'darr;': '\u2193',
+ 'dash;': '\u2010',
+ 'dashv;': '\u22a3',
+ 'dbkarow;': '\u290f',
+ 'dblac;': '\u02dd',
+ 'dcaron;': '\u010f',
+ 'dcy;': '\u0434',
+ 'dd;': '\u2146',
+ 'ddagger;': '\u2021',
+ 'ddarr;': '\u21ca',
+ 'ddotseq;': '\u2a77',
+ 'deg': '\xb0',
+ 'deg;': '\xb0',
+ 'delta;': '\u03b4',
+ 'demptyv;': '\u29b1',
+ 'dfisht;': '\u297f',
+ 'dfr;': '\u{01d521}',
+ 'dharl;': '\u21c3',
+ 'dharr;': '\u21c2',
+ 'diam;': '\u22c4',
+ 'diamond;': '\u22c4',
+ 'diamondsuit;': '\u2666',
+ 'diams;': '\u2666',
+ 'die;': '\xa8',
+ 'digamma;': '\u03dd',
+ 'disin;': '\u22f2',
+ 'div;': '\xf7',
+ 'divide': '\xf7',
+ 'divide;': '\xf7',
+ 'divideontimes;': '\u22c7',
+ 'divonx;': '\u22c7',
+ 'djcy;': '\u0452',
+ 'dlcorn;': '\u231e',
+ 'dlcrop;': '\u230d',
+ 'dollar;': '\$',
+ 'dopf;': '\u{01d555}',
+ 'dot;': '\u02d9',
+ 'doteq;': '\u2250',
+ 'doteqdot;': '\u2251',
+ 'dotminus;': '\u2238',
+ 'dotplus;': '\u2214',
+ 'dotsquare;': '\u22a1',
+ 'doublebarwedge;': '\u2306',
+ 'downarrow;': '\u2193',
+ 'downdownarrows;': '\u21ca',
+ 'downharpoonleft;': '\u21c3',
+ 'downharpoonright;': '\u21c2',
+ 'drbkarow;': '\u2910',
+ 'drcorn;': '\u231f',
+ 'drcrop;': '\u230c',
+ 'dscr;': '\u{01d4b9}',
+ 'dscy;': '\u0455',
+ 'dsol;': '\u29f6',
+ 'dstrok;': '\u0111',
+ 'dtdot;': '\u22f1',
+ 'dtri;': '\u25bf',
+ 'dtrif;': '\u25be',
+ 'duarr;': '\u21f5',
+ 'duhar;': '\u296f',
+ 'dwangle;': '\u29a6',
+ 'dzcy;': '\u045f',
+ 'dzigrarr;': '\u27ff',
+ 'eDDot;': '\u2a77',
+ 'eDot;': '\u2251',
+ 'eacute': '\xe9',
+ 'eacute;': '\xe9',
+ 'easter;': '\u2a6e',
+ 'ecaron;': '\u011b',
+ 'ecir;': '\u2256',
+ 'ecirc': '\xea',
+ 'ecirc;': '\xea',
+ 'ecolon;': '\u2255',
+ 'ecy;': '\u044d',
+ 'edot;': '\u0117',
+ 'ee;': '\u2147',
+ 'efDot;': '\u2252',
+ 'efr;': '\u{01d522}',
+ 'eg;': '\u2a9a',
+ 'egrave': '\xe8',
+ 'egrave;': '\xe8',
+ 'egs;': '\u2a96',
+ 'egsdot;': '\u2a98',
+ 'el;': '\u2a99',
+ 'elinters;': '\u23e7',
+ 'ell;': '\u2113',
+ 'els;': '\u2a95',
+ 'elsdot;': '\u2a97',
+ 'emacr;': '\u0113',
+ 'empty;': '\u2205',
+ 'emptyset;': '\u2205',
+ 'emptyv;': '\u2205',
+ 'emsp13;': '\u2004',
+ 'emsp14;': '\u2005',
+ 'emsp;': '\u2003',
+ 'eng;': '\u014b',
+ 'ensp;': '\u2002',
+ 'eogon;': '\u0119',
+ 'eopf;': '\u{01d556}',
+ 'epar;': '\u22d5',
+ 'eparsl;': '\u29e3',
+ 'eplus;': '\u2a71',
+ 'epsi;': '\u03b5',
+ 'epsilon;': '\u03b5',
+ 'epsiv;': '\u03f5',
+ 'eqcirc;': '\u2256',
+ 'eqcolon;': '\u2255',
+ 'eqsim;': '\u2242',
+ 'eqslantgtr;': '\u2a96',
+ 'eqslantless;': '\u2a95',
+ 'equals;': '=',
+ 'equest;': '\u225f',
+ 'equiv;': '\u2261',
+ 'equivDD;': '\u2a78',
+ 'eqvparsl;': '\u29e5',
+ 'erDot;': '\u2253',
+ 'erarr;': '\u2971',
+ 'escr;': '\u212f',
+ 'esdot;': '\u2250',
+ 'esim;': '\u2242',
+ 'eta;': '\u03b7',
+ 'eth': '\xf0',
+ 'eth;': '\xf0',
+ 'euml': '\xeb',
+ 'euml;': '\xeb',
+ 'euro;': '\u20ac',
+ 'excl;': '!',
+ 'exist;': '\u2203',
+ 'expectation;': '\u2130',
+ 'exponentiale;': '\u2147',
+ 'fallingdotseq;': '\u2252',
+ 'fcy;': '\u0444',
+ 'female;': '\u2640',
+ 'ffilig;': '\ufb03',
+ 'fflig;': '\ufb00',
+ 'ffllig;': '\ufb04',
+ 'ffr;': '\u{01d523}',
+ 'filig;': '\ufb01',
+ 'fjlig;': 'fj',
+ 'flat;': '\u266d',
+ 'fllig;': '\ufb02',
+ 'fltns;': '\u25b1',
+ 'fnof;': '\u0192',
+ 'fopf;': '\u{01d557}',
+ 'forall;': '\u2200',
+ 'fork;': '\u22d4',
+ 'forkv;': '\u2ad9',
+ 'fpartint;': '\u2a0d',
+ 'frac12': '\xbd',
+ 'frac12;': '\xbd',
+ 'frac13;': '\u2153',
+ 'frac14': '\xbc',
+ 'frac14;': '\xbc',
+ 'frac15;': '\u2155',
+ 'frac16;': '\u2159',
+ 'frac18;': '\u215b',
+ 'frac23;': '\u2154',
+ 'frac25;': '\u2156',
+ 'frac34': '\xbe',
+ 'frac34;': '\xbe',
+ 'frac35;': '\u2157',
+ 'frac38;': '\u215c',
+ 'frac45;': '\u2158',
+ 'frac56;': '\u215a',
+ 'frac58;': '\u215d',
+ 'frac78;': '\u215e',
+ 'frasl;': '\u2044',
+ 'frown;': '\u2322',
+ 'fscr;': '\u{01d4bb}',
+ 'gE;': '\u2267',
+ 'gEl;': '\u2a8c',
+ 'gacute;': '\u01f5',
+ 'gamma;': '\u03b3',
+ 'gammad;': '\u03dd',
+ 'gap;': '\u2a86',
+ 'gbreve;': '\u011f',
+ 'gcirc;': '\u011d',
+ 'gcy;': '\u0433',
+ 'gdot;': '\u0121',
+ 'ge;': '\u2265',
+ 'gel;': '\u22db',
+ 'geq;': '\u2265',
+ 'geqq;': '\u2267',
+ 'geqslant;': '\u2a7e',
+ 'ges;': '\u2a7e',
+ 'gescc;': '\u2aa9',
+ 'gesdot;': '\u2a80',
+ 'gesdoto;': '\u2a82',
+ 'gesdotol;': '\u2a84',
+ 'gesl;': '\u22db\ufe00',
+ 'gesles;': '\u2a94',
+ 'gfr;': '\u{01d524}',
+ 'gg;': '\u226b',
+ 'ggg;': '\u22d9',
+ 'gimel;': '\u2137',
+ 'gjcy;': '\u0453',
+ 'gl;': '\u2277',
+ 'glE;': '\u2a92',
+ 'gla;': '\u2aa5',
+ 'glj;': '\u2aa4',
+ 'gnE;': '\u2269',
+ 'gnap;': '\u2a8a',
+ 'gnapprox;': '\u2a8a',
+ 'gne;': '\u2a88',
+ 'gneq;': '\u2a88',
+ 'gneqq;': '\u2269',
+ 'gnsim;': '\u22e7',
+ 'gopf;': '\u{01d558}',
+ 'grave;': '`',
+ 'gscr;': '\u210a',
+ 'gsim;': '\u2273',
+ 'gsime;': '\u2a8e',
+ 'gsiml;': '\u2a90',
+ 'gt': '>',
+ 'gt;': '>',
+ 'gtcc;': '\u2aa7',
+ 'gtcir;': '\u2a7a',
+ 'gtdot;': '\u22d7',
+ 'gtlPar;': '\u2995',
+ 'gtquest;': '\u2a7c',
+ 'gtrapprox;': '\u2a86',
+ 'gtrarr;': '\u2978',
+ 'gtrdot;': '\u22d7',
+ 'gtreqless;': '\u22db',
+ 'gtreqqless;': '\u2a8c',
+ 'gtrless;': '\u2277',
+ 'gtrsim;': '\u2273',
+ 'gvertneqq;': '\u2269\ufe00',
+ 'gvnE;': '\u2269\ufe00',
+ 'hArr;': '\u21d4',
+ 'hairsp;': '\u200a',
+ 'half;': '\xbd',
+ 'hamilt;': '\u210b',
+ 'hardcy;': '\u044a',
+ 'harr;': '\u2194',
+ 'harrcir;': '\u2948',
+ 'harrw;': '\u21ad',
+ 'hbar;': '\u210f',
+ 'hcirc;': '\u0125',
+ 'hearts;': '\u2665',
+ 'heartsuit;': '\u2665',
+ 'hellip;': '\u2026',
+ 'hercon;': '\u22b9',
+ 'hfr;': '\u{01d525}',
+ 'hksearow;': '\u2925',
+ 'hkswarow;': '\u2926',
+ 'hoarr;': '\u21ff',
+ 'homtht;': '\u223b',
+ 'hookleftarrow;': '\u21a9',
+ 'hookrightarrow;': '\u21aa',
+ 'hopf;': '\u{01d559}',
+ 'horbar;': '\u2015',
+ 'hscr;': '\u{01d4bd}',
+ 'hslash;': '\u210f',
+ 'hstrok;': '\u0127',
+ 'hybull;': '\u2043',
+ 'hyphen;': '\u2010',
+ 'iacute': '\xed',
+ 'iacute;': '\xed',
+ 'ic;': '\u2063',
+ 'icirc': '\xee',
+ 'icirc;': '\xee',
+ 'icy;': '\u0438',
+ 'iecy;': '\u0435',
+ 'iexcl': '\xa1',
+ 'iexcl;': '\xa1',
+ 'iff;': '\u21d4',
+ 'ifr;': '\u{01d526}',
+ 'igrave': '\xec',
+ 'igrave;': '\xec',
+ 'ii;': '\u2148',
+ 'iiiint;': '\u2a0c',
+ 'iiint;': '\u222d',
+ 'iinfin;': '\u29dc',
+ 'iiota;': '\u2129',
+ 'ijlig;': '\u0133',
+ 'imacr;': '\u012b',
+ 'image;': '\u2111',
+ 'imagline;': '\u2110',
+ 'imagpart;': '\u2111',
+ 'imath;': '\u0131',
+ 'imof;': '\u22b7',
+ 'imped;': '\u01b5',
+ 'in;': '\u2208',
+ 'incare;': '\u2105',
+ 'infin;': '\u221e',
+ 'infintie;': '\u29dd',
+ 'inodot;': '\u0131',
+ 'int;': '\u222b',
+ 'intcal;': '\u22ba',
+ 'integers;': '\u2124',
+ 'intercal;': '\u22ba',
+ 'intlarhk;': '\u2a17',
+ 'intprod;': '\u2a3c',
+ 'iocy;': '\u0451',
+ 'iogon;': '\u012f',
+ 'iopf;': '\u{01d55a}',
+ 'iota;': '\u03b9',
+ 'iprod;': '\u2a3c',
+ 'iquest': '\xbf',
+ 'iquest;': '\xbf',
+ 'iscr;': '\u{01d4be}',
+ 'isin;': '\u2208',
+ 'isinE;': '\u22f9',
+ 'isindot;': '\u22f5',
+ 'isins;': '\u22f4',
+ 'isinsv;': '\u22f3',
+ 'isinv;': '\u2208',
+ 'it;': '\u2062',
+ 'itilde;': '\u0129',
+ 'iukcy;': '\u0456',
+ 'iuml': '\xef',
+ 'iuml;': '\xef',
+ 'jcirc;': '\u0135',
+ 'jcy;': '\u0439',
+ 'jfr;': '\u{01d527}',
+ 'jmath;': '\u0237',
+ 'jopf;': '\u{01d55b}',
+ 'jscr;': '\u{01d4bf}',
+ 'jsercy;': '\u0458',
+ 'jukcy;': '\u0454',
+ 'kappa;': '\u03ba',
+ 'kappav;': '\u03f0',
+ 'kcedil;': '\u0137',
+ 'kcy;': '\u043a',
+ 'kfr;': '\u{01d528}',
+ 'kgreen;': '\u0138',
+ 'khcy;': '\u0445',
+ 'kjcy;': '\u045c',
+ 'kopf;': '\u{01d55c}',
+ 'kscr;': '\u{01d4c0}',
+ 'lAarr;': '\u21da',
+ 'lArr;': '\u21d0',
+ 'lAtail;': '\u291b',
+ 'lBarr;': '\u290e',
+ 'lE;': '\u2266',
+ 'lEg;': '\u2a8b',
+ 'lHar;': '\u2962',
+ 'lacute;': '\u013a',
+ 'laemptyv;': '\u29b4',
+ 'lagran;': '\u2112',
+ 'lambda;': '\u03bb',
+ 'lang;': '\u27e8',
+ 'langd;': '\u2991',
+ 'langle;': '\u27e8',
+ 'lap;': '\u2a85',
+ 'laquo': '\xab',
+ 'laquo;': '\xab',
+ 'larr;': '\u2190',
+ 'larrb;': '\u21e4',
+ 'larrbfs;': '\u291f',
+ 'larrfs;': '\u291d',
+ 'larrhk;': '\u21a9',
+ 'larrlp;': '\u21ab',
+ 'larrpl;': '\u2939',
+ 'larrsim;': '\u2973',
+ 'larrtl;': '\u21a2',
+ 'lat;': '\u2aab',
+ 'latail;': '\u2919',
+ 'late;': '\u2aad',
+ 'lates;': '\u2aad\ufe00',
+ 'lbarr;': '\u290c',
+ 'lbbrk;': '\u2772',
+ 'lbrace;': '{',
+ 'lbrack;': '[',
+ 'lbrke;': '\u298b',
+ 'lbrksld;': '\u298f',
+ 'lbrkslu;': '\u298d',
+ 'lcaron;': '\u013e',
+ 'lcedil;': '\u013c',
+ 'lceil;': '\u2308',
+ 'lcub;': '{',
+ 'lcy;': '\u043b',
+ 'ldca;': '\u2936',
+ 'ldquo;': '\u201c',
+ 'ldquor;': '\u201e',
+ 'ldrdhar;': '\u2967',
+ 'ldrushar;': '\u294b',
+ 'ldsh;': '\u21b2',
+ 'le;': '\u2264',
+ 'leftarrow;': '\u2190',
+ 'leftarrowtail;': '\u21a2',
+ 'leftharpoondown;': '\u21bd',
+ 'leftharpoonup;': '\u21bc',
+ 'leftleftarrows;': '\u21c7',
+ 'leftrightarrow;': '\u2194',
+ 'leftrightarrows;': '\u21c6',
+ 'leftrightharpoons;': '\u21cb',
+ 'leftrightsquigarrow;': '\u21ad',
+ 'leftthreetimes;': '\u22cb',
+ 'leg;': '\u22da',
+ 'leq;': '\u2264',
+ 'leqq;': '\u2266',
+ 'leqslant;': '\u2a7d',
+ 'les;': '\u2a7d',
+ 'lescc;': '\u2aa8',
+ 'lesdot;': '\u2a7f',
+ 'lesdoto;': '\u2a81',
+ 'lesdotor;': '\u2a83',
+ 'lesg;': '\u22da\ufe00',
+ 'lesges;': '\u2a93',
+ 'lessapprox;': '\u2a85',
+ 'lessdot;': '\u22d6',
+ 'lesseqgtr;': '\u22da',
+ 'lesseqqgtr;': '\u2a8b',
+ 'lessgtr;': '\u2276',
+ 'lesssim;': '\u2272',
+ 'lfisht;': '\u297c',
+ 'lfloor;': '\u230a',
+ 'lfr;': '\u{01d529}',
+ 'lg;': '\u2276',
+ 'lgE;': '\u2a91',
+ 'lhard;': '\u21bd',
+ 'lharu;': '\u21bc',
+ 'lharul;': '\u296a',
+ 'lhblk;': '\u2584',
+ 'ljcy;': '\u0459',
+ 'll;': '\u226a',
+ 'llarr;': '\u21c7',
+ 'llcorner;': '\u231e',
+ 'llhard;': '\u296b',
+ 'lltri;': '\u25fa',
+ 'lmidot;': '\u0140',
+ 'lmoust;': '\u23b0',
+ 'lmoustache;': '\u23b0',
+ 'lnE;': '\u2268',
+ 'lnap;': '\u2a89',
+ 'lnapprox;': '\u2a89',
+ 'lne;': '\u2a87',
+ 'lneq;': '\u2a87',
+ 'lneqq;': '\u2268',
+ 'lnsim;': '\u22e6',
+ 'loang;': '\u27ec',
+ 'loarr;': '\u21fd',
+ 'lobrk;': '\u27e6',
+ 'longleftarrow;': '\u27f5',
+ 'longleftrightarrow;': '\u27f7',
+ 'longmapsto;': '\u27fc',
+ 'longrightarrow;': '\u27f6',
+ 'looparrowleft;': '\u21ab',
+ 'looparrowright;': '\u21ac',
+ 'lopar;': '\u2985',
+ 'lopf;': '\u{01d55d}',
+ 'loplus;': '\u2a2d',
+ 'lotimes;': '\u2a34',
+ 'lowast;': '\u2217',
+ 'lowbar;': '_',
+ 'loz;': '\u25ca',
+ 'lozenge;': '\u25ca',
+ 'lozf;': '\u29eb',
+ 'lpar;': '(',
+ 'lparlt;': '\u2993',
+ 'lrarr;': '\u21c6',
+ 'lrcorner;': '\u231f',
+ 'lrhar;': '\u21cb',
+ 'lrhard;': '\u296d',
+ 'lrm;': '\u200e',
+ 'lrtri;': '\u22bf',
+ 'lsaquo;': '\u2039',
+ 'lscr;': '\u{01d4c1}',
+ 'lsh;': '\u21b0',
+ 'lsim;': '\u2272',
+ 'lsime;': '\u2a8d',
+ 'lsimg;': '\u2a8f',
+ 'lsqb;': '[',
+ 'lsquo;': '\u2018',
+ 'lsquor;': '\u201a',
+ 'lstrok;': '\u0142',
+ 'lt': '<',
+ 'lt;': '<',
+ 'ltcc;': '\u2aa6',
+ 'ltcir;': '\u2a79',
+ 'ltdot;': '\u22d6',
+ 'lthree;': '\u22cb',
+ 'ltimes;': '\u22c9',
+ 'ltlarr;': '\u2976',
+ 'ltquest;': '\u2a7b',
+ 'ltrPar;': '\u2996',
+ 'ltri;': '\u25c3',
+ 'ltrie;': '\u22b4',
+ 'ltrif;': '\u25c2',
+ 'lurdshar;': '\u294a',
+ 'luruhar;': '\u2966',
+ 'lvertneqq;': '\u2268\ufe00',
+ 'lvnE;': '\u2268\ufe00',
+ 'mDDot;': '\u223a',
+ 'macr': '\xaf',
+ 'macr;': '\xaf',
+ 'male;': '\u2642',
+ 'malt;': '\u2720',
+ 'maltese;': '\u2720',
+ 'map;': '\u21a6',
+ 'mapsto;': '\u21a6',
+ 'mapstodown;': '\u21a7',
+ 'mapstoleft;': '\u21a4',
+ 'mapstoup;': '\u21a5',
+ 'marker;': '\u25ae',
+ 'mcomma;': '\u2a29',
+ 'mcy;': '\u043c',
+ 'mdash;': '\u2014',
+ 'measuredangle;': '\u2221',
+ 'mfr;': '\u{01d52a}',
+ 'mho;': '\u2127',
+ 'micro': '\xb5',
+ 'micro;': '\xb5',
+ 'mid;': '\u2223',
+ 'midast;': '*',
+ 'midcir;': '\u2af0',
+ 'middot': '\xb7',
+ 'middot;': '\xb7',
+ 'minus;': '\u2212',
+ 'minusb;': '\u229f',
+ 'minusd;': '\u2238',
+ 'minusdu;': '\u2a2a',
+ 'mlcp;': '\u2adb',
+ 'mldr;': '\u2026',
+ 'mnplus;': '\u2213',
+ 'models;': '\u22a7',
+ 'mopf;': '\u{01d55e}',
+ 'mp;': '\u2213',
+ 'mscr;': '\u{01d4c2}',
+ 'mstpos;': '\u223e',
+ 'mu;': '\u03bc',
+ 'multimap;': '\u22b8',
+ 'mumap;': '\u22b8',
+ 'nGg;': '\u22d9\u0338',
+ 'nGt;': '\u226b\u20d2',
+ 'nGtv;': '\u226b\u0338',
+ 'nLeftarrow;': '\u21cd',
+ 'nLeftrightarrow;': '\u21ce',
+ 'nLl;': '\u22d8\u0338',
+ 'nLt;': '\u226a\u20d2',
+ 'nLtv;': '\u226a\u0338',
+ 'nRightarrow;': '\u21cf',
+ 'nVDash;': '\u22af',
+ 'nVdash;': '\u22ae',
+ 'nabla;': '\u2207',
+ 'nacute;': '\u0144',
+ 'nang;': '\u2220\u20d2',
+ 'nap;': '\u2249',
+ 'napE;': '\u2a70\u0338',
+ 'napid;': '\u224b\u0338',
+ 'napos;': '\u0149',
+ 'napprox;': '\u2249',
+ 'natur;': '\u266e',
+ 'natural;': '\u266e',
+ 'naturals;': '\u2115',
+ 'nbsp': '\xa0',
+ 'nbsp;': '\xa0',
+ 'nbump;': '\u224e\u0338',
+ 'nbumpe;': '\u224f\u0338',
+ 'ncap;': '\u2a43',
+ 'ncaron;': '\u0148',
+ 'ncedil;': '\u0146',
+ 'ncong;': '\u2247',
+ 'ncongdot;': '\u2a6d\u0338',
+ 'ncup;': '\u2a42',
+ 'ncy;': '\u043d',
+ 'ndash;': '\u2013',
+ 'ne;': '\u2260',
+ 'neArr;': '\u21d7',
+ 'nearhk;': '\u2924',
+ 'nearr;': '\u2197',
+ 'nearrow;': '\u2197',
+ 'nedot;': '\u2250\u0338',
+ 'nequiv;': '\u2262',
+ 'nesear;': '\u2928',
+ 'nesim;': '\u2242\u0338',
+ 'nexist;': '\u2204',
+ 'nexists;': '\u2204',
+ 'nfr;': '\u{01d52b}',
+ 'ngE;': '\u2267\u0338',
+ 'nge;': '\u2271',
+ 'ngeq;': '\u2271',
+ 'ngeqq;': '\u2267\u0338',
+ 'ngeqslant;': '\u2a7e\u0338',
+ 'nges;': '\u2a7e\u0338',
+ 'ngsim;': '\u2275',
+ 'ngt;': '\u226f',
+ 'ngtr;': '\u226f',
+ 'nhArr;': '\u21ce',
+ 'nharr;': '\u21ae',
+ 'nhpar;': '\u2af2',
+ 'ni;': '\u220b',
+ 'nis;': '\u22fc',
+ 'nisd;': '\u22fa',
+ 'niv;': '\u220b',
+ 'njcy;': '\u045a',
+ 'nlArr;': '\u21cd',
+ 'nlE;': '\u2266\u0338',
+ 'nlarr;': '\u219a',
+ 'nldr;': '\u2025',
+ 'nle;': '\u2270',
+ 'nleftarrow;': '\u219a',
+ 'nleftrightarrow;': '\u21ae',
+ 'nleq;': '\u2270',
+ 'nleqq;': '\u2266\u0338',
+ 'nleqslant;': '\u2a7d\u0338',
+ 'nles;': '\u2a7d\u0338',
+ 'nless;': '\u226e',
+ 'nlsim;': '\u2274',
+ 'nlt;': '\u226e',
+ 'nltri;': '\u22ea',
+ 'nltrie;': '\u22ec',
+ 'nmid;': '\u2224',
+ 'nopf;': '\u{01d55f}',
+ 'not': '\xac',
+ 'not;': '\xac',
+ 'notin;': '\u2209',
+ 'notinE;': '\u22f9\u0338',
+ 'notindot;': '\u22f5\u0338',
+ 'notinva;': '\u2209',
+ 'notinvb;': '\u22f7',
+ 'notinvc;': '\u22f6',
+ 'notni;': '\u220c',
+ 'notniva;': '\u220c',
+ 'notnivb;': '\u22fe',
+ 'notnivc;': '\u22fd',
+ 'npar;': '\u2226',
+ 'nparallel;': '\u2226',
+ 'nparsl;': '\u2afd\u20e5',
+ 'npart;': '\u2202\u0338',
+ 'npolint;': '\u2a14',
+ 'npr;': '\u2280',
+ 'nprcue;': '\u22e0',
+ 'npre;': '\u2aaf\u0338',
+ 'nprec;': '\u2280',
+ 'npreceq;': '\u2aaf\u0338',
+ 'nrArr;': '\u21cf',
+ 'nrarr;': '\u219b',
+ 'nrarrc;': '\u2933\u0338',
+ 'nrarrw;': '\u219d\u0338',
+ 'nrightarrow;': '\u219b',
+ 'nrtri;': '\u22eb',
+ 'nrtrie;': '\u22ed',
+ 'nsc;': '\u2281',
+ 'nsccue;': '\u22e1',
+ 'nsce;': '\u2ab0\u0338',
+ 'nscr;': '\u{01d4c3}',
+ 'nshortmid;': '\u2224',
+ 'nshortparallel;': '\u2226',
+ 'nsim;': '\u2241',
+ 'nsime;': '\u2244',
+ 'nsimeq;': '\u2244',
+ 'nsmid;': '\u2224',
+ 'nspar;': '\u2226',
+ 'nsqsube;': '\u22e2',
+ 'nsqsupe;': '\u22e3',
+ 'nsub;': '\u2284',
+ 'nsubE;': '\u2ac5\u0338',
+ 'nsube;': '\u2288',
+ 'nsubset;': '\u2282\u20d2',
+ 'nsubseteq;': '\u2288',
+ 'nsubseteqq;': '\u2ac5\u0338',
+ 'nsucc;': '\u2281',
+ 'nsucceq;': '\u2ab0\u0338',
+ 'nsup;': '\u2285',
+ 'nsupE;': '\u2ac6\u0338',
+ 'nsupe;': '\u2289',
+ 'nsupset;': '\u2283\u20d2',
+ 'nsupseteq;': '\u2289',
+ 'nsupseteqq;': '\u2ac6\u0338',
+ 'ntgl;': '\u2279',
+ 'ntilde': '\xf1',
+ 'ntilde;': '\xf1',
+ 'ntlg;': '\u2278',
+ 'ntriangleleft;': '\u22ea',
+ 'ntrianglelefteq;': '\u22ec',
+ 'ntriangleright;': '\u22eb',
+ 'ntrianglerighteq;': '\u22ed',
+ 'nu;': '\u03bd',
+ 'num;': '#',
+ 'numero;': '\u2116',
+ 'numsp;': '\u2007',
+ 'nvDash;': '\u22ad',
+ 'nvHarr;': '\u2904',
+ 'nvap;': '\u224d\u20d2',
+ 'nvdash;': '\u22ac',
+ 'nvge;': '\u2265\u20d2',
+ 'nvgt;': '>\u20d2',
+ 'nvinfin;': '\u29de',
+ 'nvlArr;': '\u2902',
+ 'nvle;': '\u2264\u20d2',
+ 'nvlt;': '<\u20d2',
+ 'nvltrie;': '\u22b4\u20d2',
+ 'nvrArr;': '\u2903',
+ 'nvrtrie;': '\u22b5\u20d2',
+ 'nvsim;': '\u223c\u20d2',
+ 'nwArr;': '\u21d6',
+ 'nwarhk;': '\u2923',
+ 'nwarr;': '\u2196',
+ 'nwarrow;': '\u2196',
+ 'nwnear;': '\u2927',
+ 'oS;': '\u24c8',
+ 'oacute': '\xf3',
+ 'oacute;': '\xf3',
+ 'oast;': '\u229b',
+ 'ocir;': '\u229a',
+ 'ocirc': '\xf4',
+ 'ocirc;': '\xf4',
+ 'ocy;': '\u043e',
+ 'odash;': '\u229d',
+ 'odblac;': '\u0151',
+ 'odiv;': '\u2a38',
+ 'odot;': '\u2299',
+ 'odsold;': '\u29bc',
+ 'oelig;': '\u0153',
+ 'ofcir;': '\u29bf',
+ 'ofr;': '\u{01d52c}',
+ 'ogon;': '\u02db',
+ 'ograve': '\xf2',
+ 'ograve;': '\xf2',
+ 'ogt;': '\u29c1',
+ 'ohbar;': '\u29b5',
+ 'ohm;': '\u03a9',
+ 'oint;': '\u222e',
+ 'olarr;': '\u21ba',
+ 'olcir;': '\u29be',
+ 'olcross;': '\u29bb',
+ 'oline;': '\u203e',
+ 'olt;': '\u29c0',
+ 'omacr;': '\u014d',
+ 'omega;': '\u03c9',
+ 'omicron;': '\u03bf',
+ 'omid;': '\u29b6',
+ 'ominus;': '\u2296',
+ 'oopf;': '\u{01d560}',
+ 'opar;': '\u29b7',
+ 'operp;': '\u29b9',
+ 'oplus;': '\u2295',
+ 'or;': '\u2228',
+ 'orarr;': '\u21bb',
+ 'ord;': '\u2a5d',
+ 'order;': '\u2134',
+ 'orderof;': '\u2134',
+ 'ordf': '\xaa',
+ 'ordf;': '\xaa',
+ 'ordm': '\xba',
+ 'ordm;': '\xba',
+ 'origof;': '\u22b6',
+ 'oror;': '\u2a56',
+ 'orslope;': '\u2a57',
+ 'orv;': '\u2a5b',
+ 'oscr;': '\u2134',
+ 'oslash': '\xf8',
+ 'oslash;': '\xf8',
+ 'osol;': '\u2298',
+ 'otilde': '\xf5',
+ 'otilde;': '\xf5',
+ 'otimes;': '\u2297',
+ 'otimesas;': '\u2a36',
+ 'ouml': '\xf6',
+ 'ouml;': '\xf6',
+ 'ovbar;': '\u233d',
+ 'par;': '\u2225',
+ 'para': '\xb6',
+ 'para;': '\xb6',
+ 'parallel;': '\u2225',
+ 'parsim;': '\u2af3',
+ 'parsl;': '\u2afd',
+ 'part;': '\u2202',
+ 'pcy;': '\u043f',
+ 'percnt;': '%',
+ 'period;': '.',
+ 'permil;': '\u2030',
+ 'perp;': '\u22a5',
+ 'pertenk;': '\u2031',
+ 'pfr;': '\u{01d52d}',
+ 'phi;': '\u03c6',
+ 'phiv;': '\u03d5',
+ 'phmmat;': '\u2133',
+ 'phone;': '\u260e',
+ 'pi;': '\u03c0',
+ 'pitchfork;': '\u22d4',
+ 'piv;': '\u03d6',
+ 'planck;': '\u210f',
+ 'planckh;': '\u210e',
+ 'plankv;': '\u210f',
+ 'plus;': '+',
+ 'plusacir;': '\u2a23',
+ 'plusb;': '\u229e',
+ 'pluscir;': '\u2a22',
+ 'plusdo;': '\u2214',
+ 'plusdu;': '\u2a25',
+ 'pluse;': '\u2a72',
+ 'plusmn': '\xb1',
+ 'plusmn;': '\xb1',
+ 'plussim;': '\u2a26',
+ 'plustwo;': '\u2a27',
+ 'pm;': '\xb1',
+ 'pointint;': '\u2a15',
+ 'popf;': '\u{01d561}',
+ 'pound': '\xa3',
+ 'pound;': '\xa3',
+ 'pr;': '\u227a',
+ 'prE;': '\u2ab3',
+ 'prap;': '\u2ab7',
+ 'prcue;': '\u227c',
+ 'pre;': '\u2aaf',
+ 'prec;': '\u227a',
+ 'precapprox;': '\u2ab7',
+ 'preccurlyeq;': '\u227c',
+ 'preceq;': '\u2aaf',
+ 'precnapprox;': '\u2ab9',
+ 'precneqq;': '\u2ab5',
+ 'precnsim;': '\u22e8',
+ 'precsim;': '\u227e',
+ 'prime;': '\u2032',
+ 'primes;': '\u2119',
+ 'prnE;': '\u2ab5',
+ 'prnap;': '\u2ab9',
+ 'prnsim;': '\u22e8',
+ 'prod;': '\u220f',
+ 'profalar;': '\u232e',
+ 'profline;': '\u2312',
+ 'profsurf;': '\u2313',
+ 'prop;': '\u221d',
+ 'propto;': '\u221d',
+ 'prsim;': '\u227e',
+ 'prurel;': '\u22b0',
+ 'pscr;': '\u{01d4c5}',
+ 'psi;': '\u03c8',
+ 'puncsp;': '\u2008',
+ 'qfr;': '\u{01d52e}',
+ 'qint;': '\u2a0c',
+ 'qopf;': '\u{01d562}',
+ 'qprime;': '\u2057',
+ 'qscr;': '\u{01d4c6}',
+ 'quaternions;': '\u210d',
+ 'quatint;': '\u2a16',
+ 'quest;': '?',
+ 'questeq;': '\u225f',
+ 'quot': '"',
+ 'quot;': '"',
+ 'rAarr;': '\u21db',
+ 'rArr;': '\u21d2',
+ 'rAtail;': '\u291c',
+ 'rBarr;': '\u290f',
+ 'rHar;': '\u2964',
+ 'race;': '\u223d\u0331',
+ 'racute;': '\u0155',
+ 'radic;': '\u221a',
+ 'raemptyv;': '\u29b3',
+ 'rang;': '\u27e9',
+ 'rangd;': '\u2992',
+ 'range;': '\u29a5',
+ 'rangle;': '\u27e9',
+ 'raquo': '\xbb',
+ 'raquo;': '\xbb',
+ 'rarr;': '\u2192',
+ 'rarrap;': '\u2975',
+ 'rarrb;': '\u21e5',
+ 'rarrbfs;': '\u2920',
+ 'rarrc;': '\u2933',
+ 'rarrfs;': '\u291e',
+ 'rarrhk;': '\u21aa',
+ 'rarrlp;': '\u21ac',
+ 'rarrpl;': '\u2945',
+ 'rarrsim;': '\u2974',
+ 'rarrtl;': '\u21a3',
+ 'rarrw;': '\u219d',
+ 'ratail;': '\u291a',
+ 'ratio;': '\u2236',
+ 'rationals;': '\u211a',
+ 'rbarr;': '\u290d',
+ 'rbbrk;': '\u2773',
+ 'rbrace;': '}',
+ 'rbrack;': ']',
+ 'rbrke;': '\u298c',
+ 'rbrksld;': '\u298e',
+ 'rbrkslu;': '\u2990',
+ 'rcaron;': '\u0159',
+ 'rcedil;': '\u0157',
+ 'rceil;': '\u2309',
+ 'rcub;': '}',
+ 'rcy;': '\u0440',
+ 'rdca;': '\u2937',
+ 'rdldhar;': '\u2969',
+ 'rdquo;': '\u201d',
+ 'rdquor;': '\u201d',
+ 'rdsh;': '\u21b3',
+ 'real;': '\u211c',
+ 'realine;': '\u211b',
+ 'realpart;': '\u211c',
+ 'reals;': '\u211d',
+ 'rect;': '\u25ad',
+ 'reg': '\xae',
+ 'reg;': '\xae',
+ 'rfisht;': '\u297d',
+ 'rfloor;': '\u230b',
+ 'rfr;': '\u{01d52f}',
+ 'rhard;': '\u21c1',
+ 'rharu;': '\u21c0',
+ 'rharul;': '\u296c',
+ 'rho;': '\u03c1',
+ 'rhov;': '\u03f1',
+ 'rightarrow;': '\u2192',
+ 'rightarrowtail;': '\u21a3',
+ 'rightharpoondown;': '\u21c1',
+ 'rightharpoonup;': '\u21c0',
+ 'rightleftarrows;': '\u21c4',
+ 'rightleftharpoons;': '\u21cc',
+ 'rightrightarrows;': '\u21c9',
+ 'rightsquigarrow;': '\u219d',
+ 'rightthreetimes;': '\u22cc',
+ 'ring;': '\u02da',
+ 'risingdotseq;': '\u2253',
+ 'rlarr;': '\u21c4',
+ 'rlhar;': '\u21cc',
+ 'rlm;': '\u200f',
+ 'rmoust;': '\u23b1',
+ 'rmoustache;': '\u23b1',
+ 'rnmid;': '\u2aee',
+ 'roang;': '\u27ed',
+ 'roarr;': '\u21fe',
+ 'robrk;': '\u27e7',
+ 'ropar;': '\u2986',
+ 'ropf;': '\u{01d563}',
+ 'roplus;': '\u2a2e',
+ 'rotimes;': '\u2a35',
+ 'rpar;': ')',
+ 'rpargt;': '\u2994',
+ 'rppolint;': '\u2a12',
+ 'rrarr;': '\u21c9',
+ 'rsaquo;': '\u203a',
+ 'rscr;': '\u{01d4c7}',
+ 'rsh;': '\u21b1',
+ 'rsqb;': ']',
+ 'rsquo;': '\u2019',
+ 'rsquor;': '\u2019',
+ 'rthree;': '\u22cc',
+ 'rtimes;': '\u22ca',
+ 'rtri;': '\u25b9',
+ 'rtrie;': '\u22b5',
+ 'rtrif;': '\u25b8',
+ 'rtriltri;': '\u29ce',
+ 'ruluhar;': '\u2968',
+ 'rx;': '\u211e',
+ 'sacute;': '\u015b',
+ 'sbquo;': '\u201a',
+ 'sc;': '\u227b',
+ 'scE;': '\u2ab4',
+ 'scap;': '\u2ab8',
+ 'scaron;': '\u0161',
+ 'sccue;': '\u227d',
+ 'sce;': '\u2ab0',
+ 'scedil;': '\u015f',
+ 'scirc;': '\u015d',
+ 'scnE;': '\u2ab6',
+ 'scnap;': '\u2aba',
+ 'scnsim;': '\u22e9',
+ 'scpolint;': '\u2a13',
+ 'scsim;': '\u227f',
+ 'scy;': '\u0441',
+ 'sdot;': '\u22c5',
+ 'sdotb;': '\u22a1',
+ 'sdote;': '\u2a66',
+ 'seArr;': '\u21d8',
+ 'searhk;': '\u2925',
+ 'searr;': '\u2198',
+ 'searrow;': '\u2198',
+ 'sect': '\xa7',
+ 'sect;': '\xa7',
+ 'semi;': ';',
+ 'seswar;': '\u2929',
+ 'setminus;': '\u2216',
+ 'setmn;': '\u2216',
+ 'sext;': '\u2736',
+ 'sfr;': '\u{01d530}',
+ 'sfrown;': '\u2322',
+ 'sharp;': '\u266f',
+ 'shchcy;': '\u0449',
+ 'shcy;': '\u0448',
+ 'shortmid;': '\u2223',
+ 'shortparallel;': '\u2225',
+ 'shy': '\xad',
+ 'shy;': '\xad',
+ 'sigma;': '\u03c3',
+ 'sigmaf;': '\u03c2',
+ 'sigmav;': '\u03c2',
+ 'sim;': '\u223c',
+ 'simdot;': '\u2a6a',
+ 'sime;': '\u2243',
+ 'simeq;': '\u2243',
+ 'simg;': '\u2a9e',
+ 'simgE;': '\u2aa0',
+ 'siml;': '\u2a9d',
+ 'simlE;': '\u2a9f',
+ 'simne;': '\u2246',
+ 'simplus;': '\u2a24',
+ 'simrarr;': '\u2972',
+ 'slarr;': '\u2190',
+ 'smallsetminus;': '\u2216',
+ 'smashp;': '\u2a33',
+ 'smeparsl;': '\u29e4',
+ 'smid;': '\u2223',
+ 'smile;': '\u2323',
+ 'smt;': '\u2aaa',
+ 'smte;': '\u2aac',
+ 'smtes;': '\u2aac\ufe00',
+ 'softcy;': '\u044c',
+ 'sol;': '/',
+ 'solb;': '\u29c4',
+ 'solbar;': '\u233f',
+ 'sopf;': '\u{01d564}',
+ 'spades;': '\u2660',
+ 'spadesuit;': '\u2660',
+ 'spar;': '\u2225',
+ 'sqcap;': '\u2293',
+ 'sqcaps;': '\u2293\ufe00',
+ 'sqcup;': '\u2294',
+ 'sqcups;': '\u2294\ufe00',
+ 'sqsub;': '\u228f',
+ 'sqsube;': '\u2291',
+ 'sqsubset;': '\u228f',
+ 'sqsubseteq;': '\u2291',
+ 'sqsup;': '\u2290',
+ 'sqsupe;': '\u2292',
+ 'sqsupset;': '\u2290',
+ 'sqsupseteq;': '\u2292',
+ 'squ;': '\u25a1',
+ 'square;': '\u25a1',
+ 'squarf;': '\u25aa',
+ 'squf;': '\u25aa',
+ 'srarr;': '\u2192',
+ 'sscr;': '\u{01d4c8}',
+ 'ssetmn;': '\u2216',
+ 'ssmile;': '\u2323',
+ 'sstarf;': '\u22c6',
+ 'star;': '\u2606',
+ 'starf;': '\u2605',
+ 'straightepsilon;': '\u03f5',
+ 'straightphi;': '\u03d5',
+ 'strns;': '\xaf',
+ 'sub;': '\u2282',
+ 'subE;': '\u2ac5',
+ 'subdot;': '\u2abd',
+ 'sube;': '\u2286',
+ 'subedot;': '\u2ac3',
+ 'submult;': '\u2ac1',
+ 'subnE;': '\u2acb',
+ 'subne;': '\u228a',
+ 'subplus;': '\u2abf',
+ 'subrarr;': '\u2979',
+ 'subset;': '\u2282',
+ 'subseteq;': '\u2286',
+ 'subseteqq;': '\u2ac5',
+ 'subsetneq;': '\u228a',
+ 'subsetneqq;': '\u2acb',
+ 'subsim;': '\u2ac7',
+ 'subsub;': '\u2ad5',
+ 'subsup;': '\u2ad3',
+ 'succ;': '\u227b',
+ 'succapprox;': '\u2ab8',
+ 'succcurlyeq;': '\u227d',
+ 'succeq;': '\u2ab0',
+ 'succnapprox;': '\u2aba',
+ 'succneqq;': '\u2ab6',
+ 'succnsim;': '\u22e9',
+ 'succsim;': '\u227f',
+ 'sum;': '\u2211',
+ 'sung;': '\u266a',
+ 'sup1': '\xb9',
+ 'sup1;': '\xb9',
+ 'sup2': '\xb2',
+ 'sup2;': '\xb2',
+ 'sup3': '\xb3',
+ 'sup3;': '\xb3',
+ 'sup;': '\u2283',
+ 'supE;': '\u2ac6',
+ 'supdot;': '\u2abe',
+ 'supdsub;': '\u2ad8',
+ 'supe;': '\u2287',
+ 'supedot;': '\u2ac4',
+ 'suphsol;': '\u27c9',
+ 'suphsub;': '\u2ad7',
+ 'suplarr;': '\u297b',
+ 'supmult;': '\u2ac2',
+ 'supnE;': '\u2acc',
+ 'supne;': '\u228b',
+ 'supplus;': '\u2ac0',
+ 'supset;': '\u2283',
+ 'supseteq;': '\u2287',
+ 'supseteqq;': '\u2ac6',
+ 'supsetneq;': '\u228b',
+ 'supsetneqq;': '\u2acc',
+ 'supsim;': '\u2ac8',
+ 'supsub;': '\u2ad4',
+ 'supsup;': '\u2ad6',
+ 'swArr;': '\u21d9',
+ 'swarhk;': '\u2926',
+ 'swarr;': '\u2199',
+ 'swarrow;': '\u2199',
+ 'swnwar;': '\u292a',
+ 'szlig': '\xdf',
+ 'szlig;': '\xdf',
+ 'target;': '\u2316',
+ 'tau;': '\u03c4',
+ 'tbrk;': '\u23b4',
+ 'tcaron;': '\u0165',
+ 'tcedil;': '\u0163',
+ 'tcy;': '\u0442',
+ 'tdot;': '\u20db',
+ 'telrec;': '\u2315',
+ 'tfr;': '\u{01d531}',
+ 'there4;': '\u2234',
+ 'therefore;': '\u2234',
+ 'theta;': '\u03b8',
+ 'thetasym;': '\u03d1',
+ 'thetav;': '\u03d1',
+ 'thickapprox;': '\u2248',
+ 'thicksim;': '\u223c',
+ 'thinsp;': '\u2009',
+ 'thkap;': '\u2248',
+ 'thksim;': '\u223c',
+ 'thorn': '\xfe',
+ 'thorn;': '\xfe',
+ 'tilde;': '\u02dc',
+ 'times': '\xd7',
+ 'times;': '\xd7',
+ 'timesb;': '\u22a0',
+ 'timesbar;': '\u2a31',
+ 'timesd;': '\u2a30',
+ 'tint;': '\u222d',
+ 'toea;': '\u2928',
+ 'top;': '\u22a4',
+ 'topbot;': '\u2336',
+ 'topcir;': '\u2af1',
+ 'topf;': '\u{01d565}',
+ 'topfork;': '\u2ada',
+ 'tosa;': '\u2929',
+ 'tprime;': '\u2034',
+ 'trade;': '\u2122',
+ 'triangle;': '\u25b5',
+ 'triangledown;': '\u25bf',
+ 'triangleleft;': '\u25c3',
+ 'trianglelefteq;': '\u22b4',
+ 'triangleq;': '\u225c',
+ 'triangleright;': '\u25b9',
+ 'trianglerighteq;': '\u22b5',
+ 'tridot;': '\u25ec',
+ 'trie;': '\u225c',
+ 'triminus;': '\u2a3a',
+ 'triplus;': '\u2a39',
+ 'trisb;': '\u29cd',
+ 'tritime;': '\u2a3b',
+ 'trpezium;': '\u23e2',
+ 'tscr;': '\u{01d4c9}',
+ 'tscy;': '\u0446',
+ 'tshcy;': '\u045b',
+ 'tstrok;': '\u0167',
+ 'twixt;': '\u226c',
+ 'twoheadleftarrow;': '\u219e',
+ 'twoheadrightarrow;': '\u21a0',
+ 'uArr;': '\u21d1',
+ 'uHar;': '\u2963',
+ 'uacute': '\xfa',
+ 'uacute;': '\xfa',
+ 'uarr;': '\u2191',
+ 'ubrcy;': '\u045e',
+ 'ubreve;': '\u016d',
+ 'ucirc': '\xfb',
+ 'ucirc;': '\xfb',
+ 'ucy;': '\u0443',
+ 'udarr;': '\u21c5',
+ 'udblac;': '\u0171',
+ 'udhar;': '\u296e',
+ 'ufisht;': '\u297e',
+ 'ufr;': '\u{01d532}',
+ 'ugrave': '\xf9',
+ 'ugrave;': '\xf9',
+ 'uharl;': '\u21bf',
+ 'uharr;': '\u21be',
+ 'uhblk;': '\u2580',
+ 'ulcorn;': '\u231c',
+ 'ulcorner;': '\u231c',
+ 'ulcrop;': '\u230f',
+ 'ultri;': '\u25f8',
+ 'umacr;': '\u016b',
+ 'uml': '\xa8',
+ 'uml;': '\xa8',
+ 'uogon;': '\u0173',
+ 'uopf;': '\u{01d566}',
+ 'uparrow;': '\u2191',
+ 'updownarrow;': '\u2195',
+ 'upharpoonleft;': '\u21bf',
+ 'upharpoonright;': '\u21be',
+ 'uplus;': '\u228e',
+ 'upsi;': '\u03c5',
+ 'upsih;': '\u03d2',
+ 'upsilon;': '\u03c5',
+ 'upuparrows;': '\u21c8',
+ 'urcorn;': '\u231d',
+ 'urcorner;': '\u231d',
+ 'urcrop;': '\u230e',
+ 'uring;': '\u016f',
+ 'urtri;': '\u25f9',
+ 'uscr;': '\u{01d4ca}',
+ 'utdot;': '\u22f0',
+ 'utilde;': '\u0169',
+ 'utri;': '\u25b5',
+ 'utrif;': '\u25b4',
+ 'uuarr;': '\u21c8',
+ 'uuml': '\xfc',
+ 'uuml;': '\xfc',
+ 'uwangle;': '\u29a7',
+ 'vArr;': '\u21d5',
+ 'vBar;': '\u2ae8',
+ 'vBarv;': '\u2ae9',
+ 'vDash;': '\u22a8',
+ 'vangrt;': '\u299c',
+ 'varepsilon;': '\u03f5',
+ 'varkappa;': '\u03f0',
+ 'varnothing;': '\u2205',
+ 'varphi;': '\u03d5',
+ 'varpi;': '\u03d6',
+ 'varpropto;': '\u221d',
+ 'varr;': '\u2195',
+ 'varrho;': '\u03f1',
+ 'varsigma;': '\u03c2',
+ 'varsubsetneq;': '\u228a\ufe00',
+ 'varsubsetneqq;': '\u2acb\ufe00',
+ 'varsupsetneq;': '\u228b\ufe00',
+ 'varsupsetneqq;': '\u2acc\ufe00',
+ 'vartheta;': '\u03d1',
+ 'vartriangleleft;': '\u22b2',
+ 'vartriangleright;': '\u22b3',
+ 'vcy;': '\u0432',
+ 'vdash;': '\u22a2',
+ 'vee;': '\u2228',
+ 'veebar;': '\u22bb',
+ 'veeeq;': '\u225a',
+ 'vellip;': '\u22ee',
+ 'verbar;': '|',
+ 'vert;': '|',
+ 'vfr;': '\u{01d533}',
+ 'vltri;': '\u22b2',
+ 'vnsub;': '\u2282\u20d2',
+ 'vnsup;': '\u2283\u20d2',
+ 'vopf;': '\u{01d567}',
+ 'vprop;': '\u221d',
+ 'vrtri;': '\u22b3',
+ 'vscr;': '\u{01d4cb}',
+ 'vsubnE;': '\u2acb\ufe00',
+ 'vsubne;': '\u228a\ufe00',
+ 'vsupnE;': '\u2acc\ufe00',
+ 'vsupne;': '\u228b\ufe00',
+ 'vzigzag;': '\u299a',
+ 'wcirc;': '\u0175',
+ 'wedbar;': '\u2a5f',
+ 'wedge;': '\u2227',
+ 'wedgeq;': '\u2259',
+ 'weierp;': '\u2118',
+ 'wfr;': '\u{01d534}',
+ 'wopf;': '\u{01d568}',
+ 'wp;': '\u2118',
+ 'wr;': '\u2240',
+ 'wreath;': '\u2240',
+ 'wscr;': '\u{01d4cc}',
+ 'xcap;': '\u22c2',
+ 'xcirc;': '\u25ef',
+ 'xcup;': '\u22c3',
+ 'xdtri;': '\u25bd',
+ 'xfr;': '\u{01d535}',
+ 'xhArr;': '\u27fa',
+ 'xharr;': '\u27f7',
+ 'xi;': '\u03be',
+ 'xlArr;': '\u27f8',
+ 'xlarr;': '\u27f5',
+ 'xmap;': '\u27fc',
+ 'xnis;': '\u22fb',
+ 'xodot;': '\u2a00',
+ 'xopf;': '\u{01d569}',
+ 'xoplus;': '\u2a01',
+ 'xotime;': '\u2a02',
+ 'xrArr;': '\u27f9',
+ 'xrarr;': '\u27f6',
+ 'xscr;': '\u{01d4cd}',
+ 'xsqcup;': '\u2a06',
+ 'xuplus;': '\u2a04',
+ 'xutri;': '\u25b3',
+ 'xvee;': '\u22c1',
+ 'xwedge;': '\u22c0',
+ 'yacute': '\xfd',
+ 'yacute;': '\xfd',
+ 'yacy;': '\u044f',
+ 'ycirc;': '\u0177',
+ 'ycy;': '\u044b',
+ 'yen': '\xa5',
+ 'yen;': '\xa5',
+ 'yfr;': '\u{01d536}',
+ 'yicy;': '\u0457',
+ 'yopf;': '\u{01d56a}',
+ 'yscr;': '\u{01d4ce}',
+ 'yucy;': '\u044e',
+ 'yuml': '\xff',
+ 'yuml;': '\xff',
+ 'zacute;': '\u017a',
+ 'zcaron;': '\u017e',
+ 'zcy;': '\u0437',
+ 'zdot;': '\u017c',
+ 'zeetrf;': '\u2128',
+ 'zeta;': '\u03b6',
+ 'zfr;': '\u{01d537}',
+ 'zhcy;': '\u0436',
+ 'zigrarr;': '\u21dd',
+ 'zopf;': '\u{01d56b}',
+ 'zscr;': '\u{01d4cf}',
+ 'zwj;': '\u200d',
+ 'zwnj;': '\u200c',
+};
+
+const Map<int, String> replacementCharacters = {
+ 0x00: '\uFFFD',
+ 0x0d: '\u000D',
+ 0x80: '\u20AC',
+ 0x81: '\u0081',
+ 0x82: '\u201A',
+ 0x83: '\u0192',
+ 0x84: '\u201E',
+ 0x85: '\u2026',
+ 0x86: '\u2020',
+ 0x87: '\u2021',
+ 0x88: '\u02C6',
+ 0x89: '\u2030',
+ 0x8A: '\u0160',
+ 0x8B: '\u2039',
+ 0x8C: '\u0152',
+ 0x8D: '\u008D',
+ 0x8E: '\u017D',
+ 0x8F: '\u008F',
+ 0x90: '\u0090',
+ 0x91: '\u2018',
+ 0x92: '\u2019',
+ 0x93: '\u201C',
+ 0x94: '\u201D',
+ 0x95: '\u2022',
+ 0x96: '\u2013',
+ 0x97: '\u2014',
+ 0x98: '\u02DC',
+ 0x99: '\u2122',
+ 0x9A: '\u0161',
+ 0x9B: '\u203A',
+ 0x9C: '\u0153',
+ 0x9D: '\u009D',
+ 0x9E: '\u017E',
+ 0x9F: '\u0178'
+};
+
+const Map<String, String> encodings = {
+ '437': 'cp437',
+ '850': 'cp850',
+ '852': 'cp852',
+ '855': 'cp855',
+ '857': 'cp857',
+ '860': 'cp860',
+ '861': 'cp861',
+ '862': 'cp862',
+ '863': 'cp863',
+ '865': 'cp865',
+ '866': 'cp866',
+ '869': 'cp869',
+ 'ansix341968': 'ascii',
+ 'ansix341986': 'ascii',
+ 'arabic': 'iso8859-6',
+ 'ascii': 'ascii',
+ 'asmo708': 'iso8859-6',
+ 'big5': 'big5',
+ 'big5hkscs': 'big5hkscs',
+ 'chinese': 'gbk',
+ 'cp037': 'cp037',
+ 'cp1026': 'cp1026',
+ 'cp154': 'ptcp154',
+ 'cp367': 'ascii',
+ 'cp424': 'cp424',
+ 'cp437': 'cp437',
+ 'cp500': 'cp500',
+ 'cp775': 'cp775',
+ 'cp819': 'windows-1252',
+ 'cp850': 'cp850',
+ 'cp852': 'cp852',
+ 'cp855': 'cp855',
+ 'cp857': 'cp857',
+ 'cp860': 'cp860',
+ 'cp861': 'cp861',
+ 'cp862': 'cp862',
+ 'cp863': 'cp863',
+ 'cp864': 'cp864',
+ 'cp865': 'cp865',
+ 'cp866': 'cp866',
+ 'cp869': 'cp869',
+ 'cp936': 'gbk',
+ 'cpgr': 'cp869',
+ 'cpis': 'cp861',
+ 'csascii': 'ascii',
+ 'csbig5': 'big5',
+ 'cseuckr': 'cp949',
+ 'cseucpkdfmtjapanese': 'euc_jp',
+ 'csgb2312': 'gbk',
+ 'cshproman8': 'hp-roman8',
+ 'csibm037': 'cp037',
+ 'csibm1026': 'cp1026',
+ 'csibm424': 'cp424',
+ 'csibm500': 'cp500',
+ 'csibm855': 'cp855',
+ 'csibm857': 'cp857',
+ 'csibm860': 'cp860',
+ 'csibm861': 'cp861',
+ 'csibm863': 'cp863',
+ 'csibm864': 'cp864',
+ 'csibm865': 'cp865',
+ 'csibm866': 'cp866',
+ 'csibm869': 'cp869',
+ 'csiso2022jp': 'iso2022_jp',
+ 'csiso2022jp2': 'iso2022_jp_2',
+ 'csiso2022kr': 'iso2022_kr',
+ 'csiso58gb231280': 'gbk',
+ 'csisolatin1': 'windows-1252',
+ 'csisolatin2': 'iso8859-2',
+ 'csisolatin3': 'iso8859-3',
+ 'csisolatin4': 'iso8859-4',
+ 'csisolatin5': 'windows-1254',
+ 'csisolatin6': 'iso8859-10',
+ 'csisolatinarabic': 'iso8859-6',
+ 'csisolatincyrillic': 'iso8859-5',
+ 'csisolatingreek': 'iso8859-7',
+ 'csisolatinhebrew': 'iso8859-8',
+ 'cskoi8r': 'koi8-r',
+ 'csksc56011987': 'cp949',
+ 'cspc775baltic': 'cp775',
+ 'cspc850multilingual': 'cp850',
+ 'cspc862latinhebrew': 'cp862',
+ 'cspc8codepage437': 'cp437',
+ 'cspcp852': 'cp852',
+ 'csptcp154': 'ptcp154',
+ 'csshiftjis': 'shift_jis',
+ 'csunicode11utf7': 'utf-7',
+ 'cyrillic': 'iso8859-5',
+ 'cyrillicasian': 'ptcp154',
+ 'ebcdiccpbe': 'cp500',
+ 'ebcdiccpca': 'cp037',
+ 'ebcdiccpch': 'cp500',
+ 'ebcdiccphe': 'cp424',
+ 'ebcdiccpnl': 'cp037',
+ 'ebcdiccpus': 'cp037',
+ 'ebcdiccpwt': 'cp037',
+ 'ecma114': 'iso8859-6',
+ 'ecma118': 'iso8859-7',
+ 'elot928': 'iso8859-7',
+ 'eucjp': 'euc_jp',
+ 'euckr': 'cp949',
+ 'extendedunixcodepackedformatforjapanese': 'euc_jp',
+ 'gb18030': 'gb18030',
+ 'gb2312': 'gbk',
+ 'gb231280': 'gbk',
+ 'gbk': 'gbk',
+ 'greek': 'iso8859-7',
+ 'greek8': 'iso8859-7',
+ 'hebrew': 'iso8859-8',
+ 'hproman8': 'hp-roman8',
+ 'hzgb2312': 'hz',
+ 'ibm037': 'cp037',
+ 'ibm1026': 'cp1026',
+ 'ibm367': 'ascii',
+ 'ibm424': 'cp424',
+ 'ibm437': 'cp437',
+ 'ibm500': 'cp500',
+ 'ibm775': 'cp775',
+ 'ibm819': 'windows-1252',
+ 'ibm850': 'cp850',
+ 'ibm852': 'cp852',
+ 'ibm855': 'cp855',
+ 'ibm857': 'cp857',
+ 'ibm860': 'cp860',
+ 'ibm861': 'cp861',
+ 'ibm862': 'cp862',
+ 'ibm863': 'cp863',
+ 'ibm864': 'cp864',
+ 'ibm865': 'cp865',
+ 'ibm866': 'cp866',
+ 'ibm869': 'cp869',
+ 'iso2022jp': 'iso2022_jp',
+ 'iso2022jp2': 'iso2022_jp_2',
+ 'iso2022kr': 'iso2022_kr',
+ 'iso646irv1991': 'ascii',
+ 'iso646us': 'ascii',
+ 'iso88591': 'windows-1252',
+ 'iso885910': 'iso8859-10',
+ 'iso8859101992': 'iso8859-10',
+ 'iso885911987': 'windows-1252',
+ 'iso885913': 'iso8859-13',
+ 'iso885914': 'iso8859-14',
+ 'iso8859141998': 'iso8859-14',
+ 'iso885915': 'iso8859-15',
+ 'iso885916': 'iso8859-16',
+ 'iso8859162001': 'iso8859-16',
+ 'iso88592': 'iso8859-2',
+ 'iso885921987': 'iso8859-2',
+ 'iso88593': 'iso8859-3',
+ 'iso885931988': 'iso8859-3',
+ 'iso88594': 'iso8859-4',
+ 'iso885941988': 'iso8859-4',
+ 'iso88595': 'iso8859-5',
+ 'iso885951988': 'iso8859-5',
+ 'iso88596': 'iso8859-6',
+ 'iso885961987': 'iso8859-6',
+ 'iso88597': 'iso8859-7',
+ 'iso885971987': 'iso8859-7',
+ 'iso88598': 'iso8859-8',
+ 'iso885981988': 'iso8859-8',
+ 'iso88599': 'windows-1254',
+ 'iso885991989': 'windows-1254',
+ 'isoceltic': 'iso8859-14',
+ 'isoir100': 'windows-1252',
+ 'isoir101': 'iso8859-2',
+ 'isoir109': 'iso8859-3',
+ 'isoir110': 'iso8859-4',
+ 'isoir126': 'iso8859-7',
+ 'isoir127': 'iso8859-6',
+ 'isoir138': 'iso8859-8',
+ 'isoir144': 'iso8859-5',
+ 'isoir148': 'windows-1254',
+ 'isoir149': 'cp949',
+ 'isoir157': 'iso8859-10',
+ 'isoir199': 'iso8859-14',
+ 'isoir226': 'iso8859-16',
+ 'isoir58': 'gbk',
+ 'isoir6': 'ascii',
+ 'koi8r': 'koi8-r',
+ 'koi8u': 'koi8-u',
+ 'korean': 'cp949',
+ 'ksc5601': 'cp949',
+ 'ksc56011987': 'cp949',
+ 'ksc56011989': 'cp949',
+ 'l1': 'windows-1252',
+ 'l10': 'iso8859-16',
+ 'l2': 'iso8859-2',
+ 'l3': 'iso8859-3',
+ 'l4': 'iso8859-4',
+ 'l5': 'windows-1254',
+ 'l6': 'iso8859-10',
+ 'l8': 'iso8859-14',
+ 'latin1': 'windows-1252',
+ 'latin10': 'iso8859-16',
+ 'latin2': 'iso8859-2',
+ 'latin3': 'iso8859-3',
+ 'latin4': 'iso8859-4',
+ 'latin5': 'windows-1254',
+ 'latin6': 'iso8859-10',
+ 'latin8': 'iso8859-14',
+ 'latin9': 'iso8859-15',
+ 'ms936': 'gbk',
+ 'mskanji': 'shift_jis',
+ 'pt154': 'ptcp154',
+ 'ptcp154': 'ptcp154',
+ 'r8': 'hp-roman8',
+ 'roman8': 'hp-roman8',
+ 'shiftjis': 'shift_jis',
+ 'tis620': 'cp874',
+ 'unicode11utf7': 'utf-7',
+ 'us': 'ascii',
+ 'usascii': 'ascii',
+ 'utf16': 'utf-16',
+ 'utf16be': 'utf-16-be',
+ 'utf16le': 'utf-16-le',
+ 'utf8': 'utf-8',
+ 'windows1250': 'cp1250',
+ 'windows1251': 'cp1251',
+ 'windows1252': 'cp1252',
+ 'windows1253': 'cp1253',
+ 'windows1254': 'cp1254',
+ 'windows1255': 'cp1255',
+ 'windows1256': 'cp1256',
+ 'windows1257': 'cp1257',
+ 'windows1258': 'cp1258',
+ 'windows936': 'gbk',
+ 'x-x-big5': 'big5'
+};
diff --git a/pkgs/html/lib/src/css_class_set.dart b/pkgs/html/lib/src/css_class_set.dart
new file mode 100644
index 0000000..deca7a5
--- /dev/null
+++ b/pkgs/html/lib/src/css_class_set.dart
@@ -0,0 +1,216 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): everything in this file is copied straight from "dart:html".
+
+import 'dart:collection';
+
+import '../dom.dart';
+
+class ElementCssClassSet extends _CssClassSetImpl {
+ final Element _element;
+
+ ElementCssClassSet(this._element);
+
+ @override
+ Set<String> readClasses() {
+ final s = LinkedHashSet<String>();
+ final classname = _element.className;
+
+ for (var name in classname.split(' ')) {
+ final trimmed = name.trim();
+ if (trimmed.isNotEmpty) {
+ s.add(trimmed);
+ }
+ }
+ return s;
+ }
+
+ @override
+ void writeClasses(Set<String> s) {
+ _element.className = s.join(' ');
+ }
+}
+
+/// A Set that stores the CSS class names for an element.
+abstract class CssClassSet implements Set<String> {
+ /// Adds the class [value] to the element if it is not on it, removes it if it
+ /// is.
+ ///
+ /// If [shouldAdd] is true, then we always add that [value] to the element. If
+ /// [shouldAdd] is false then we always remove [value] from the element.
+ bool toggle(String value, [bool? shouldAdd]);
+
+ /// Returns [:true:] if classes cannot be added or removed from this
+ /// [:CssClassSet:].
+ bool get frozen;
+
+ /// Determine if this element contains the class [value].
+ ///
+ /// This is the Dart equivalent of jQuery's
+ /// [hasClass](http://api.jquery.com/hasClass/).
+ @override
+ bool contains(Object? value);
+
+ /// Add the class [value] to element.
+ ///
+ /// This is the Dart equivalent of jQuery's
+ /// [addClass](http://api.jquery.com/addClass/).
+ ///
+ /// If this corresponds to one element. Returns true if [value] was added to
+ /// the set, otherwise false.
+ ///
+ /// If this corresponds to many elements, null is always returned.
+ @override
+ bool add(String value);
+
+ /// Remove the class [value] from element, and return true on successful
+ /// removal.
+ ///
+ /// This is the Dart equivalent of jQuery's
+ /// [removeClass](http://api.jquery.com/removeClass/).
+ @override
+ bool remove(Object? value);
+
+ /// Add all classes specified in [iterable] to element.
+ ///
+ /// This is the Dart equivalent of jQuery's
+ /// [addClass](http://api.jquery.com/addClass/).
+ @override
+ void addAll(Iterable<String> iterable);
+
+ /// Remove all classes specified in [iterable] from element.
+ ///
+ /// This is the Dart equivalent of jQuery's
+ /// [removeClass](http://api.jquery.com/removeClass/).
+ @override
+ void removeAll(Iterable<Object?> iterable);
+
+ /// Toggles all classes specified in [iterable] on element.
+ ///
+ /// Iterate through [iterable]'s items, and add it if it is not on it, or
+ /// remove it if it is. This is the Dart equivalent of jQuery's
+ /// [toggleClass](http://api.jquery.com/toggleClass/).
+ /// If [shouldAdd] is true, then we always add all the classes in [iterable]
+ /// element. If [shouldAdd] is false then we always remove all the classes in
+ /// [iterable] from the element.
+ void toggleAll(Iterable<String> iterable, [bool? shouldAdd]);
+}
+
+abstract class _CssClassSetImpl extends SetBase<String> implements CssClassSet {
+ @override
+ String toString() {
+ return readClasses().join(' ');
+ }
+
+ /// Adds the class [value] to the element if it is not on it, removes it if it
+ /// is.
+ ///
+ /// If [shouldAdd] is true, then we always add that [value] to the element. If
+ /// [shouldAdd] is false then we always remove [value] from the element.
+ @override
+ bool toggle(String value, [bool? shouldAdd]) {
+ final s = readClasses();
+ var result = false;
+ shouldAdd ??= !s.contains(value);
+ if (shouldAdd) {
+ s.add(value);
+ result = true;
+ } else {
+ s.remove(value);
+ }
+ writeClasses(s);
+ return result;
+ }
+
+ /// Returns [:true:] if classes cannot be added or removed from this
+ /// [:CssClassSet:].
+ @override
+ bool get frozen => false;
+
+ @override
+ Iterator<String> get iterator => readClasses().iterator;
+
+ @override
+ int get length => readClasses().length;
+
+ // interface Set - BEGIN
+ /// Determine if this element contains the class [value].
+ ///
+ /// This is the Dart equivalent of jQuery's
+ /// [hasClass](http://api.jquery.com/hasClass/).
+ @override
+ bool contains(Object? value) => readClasses().contains(value);
+
+ /// Lookup from the Set interface. Not interesting for a String set.
+ @override
+ String? lookup(Object? value) => contains(value) ? value as String? : null;
+
+ @override
+ Set<String> toSet() => readClasses().toSet();
+
+ /// Add the class [value] to element.
+ ///
+ /// This is the Dart equivalent of jQuery's
+ /// [addClass](http://api.jquery.com/addClass/).
+ @override
+ bool add(String value) {
+ // TODO - figure out if we need to do any validation here
+ // or if the browser natively does enough.
+ return _modify((s) => s.add(value));
+ }
+
+ /// Remove the class [value] from element, and return true on successful
+ /// removal.
+ ///
+ /// This is the Dart equivalent of jQuery's
+ /// [removeClass](http://api.jquery.com/removeClass/).
+ @override
+ bool remove(Object? value) {
+ if (value is! String) return false;
+ final s = readClasses();
+ final result = s.remove(value);
+ writeClasses(s);
+ return result;
+ }
+
+ /// Toggles all classes specified in [iterable] on element.
+ ///
+ /// Iterate through [iterable]'s items, and add it if it is not on it, or
+ /// remove it if it is. This is the Dart equivalent of jQuery's
+ /// [toggleClass](http://api.jquery.com/toggleClass/).
+ /// If [shouldAdd] is true, then we always add all the classes in [iterable]
+ /// element. If [shouldAdd] is false then we always remove all the classes in
+ /// [iterable] from the element.
+ @override
+ void toggleAll(Iterable<String> iterable, [bool? shouldAdd]) {
+ for (var e in iterable) {
+ toggle(e, shouldAdd);
+ }
+ }
+
+ /// Helper method used to modify the set of css classes on this element.
+ ///
+ /// f - callback with:
+ /// s - a Set of all the css class name currently on this element.
+ ///
+ /// After f returns, the modified set is written to the
+ /// className property of this element.
+ bool _modify(bool Function(Set<String>) f) {
+ final s = readClasses();
+ final ret = f(s);
+ writeClasses(s);
+ return ret;
+ }
+
+ /// Read the class names from the Element class property,
+ /// and put them into a set (duplicates are discarded).
+ /// This is intended to be overridden by specific implementations.
+ Set<String> readClasses();
+
+ /// Join all the elements of a set into one string and write
+ /// back to the element.
+ /// This is intended to be overridden by specific implementations.
+ void writeClasses(Set<String> s);
+}
diff --git a/pkgs/html/lib/src/encoding_parser.dart b/pkgs/html/lib/src/encoding_parser.dart
new file mode 100644
index 0000000..2ecd5c4
--- /dev/null
+++ b/pkgs/html/lib/src/encoding_parser.dart
@@ -0,0 +1,378 @@
+import 'constants.dart';
+import 'html_input_stream.dart';
+
+/// String-like object with an associated position and various extra methods.
+///
+/// If the position is ever greater than the string length then an exception is
+/// raised.
+class EncodingBytes {
+ final String _bytes;
+ int __position = -1;
+
+ EncodingBytes(this._bytes);
+
+ int get _length => _bytes.length;
+
+ String _next() {
+ final p = __position = __position + 1;
+ if (p >= _length) {
+ throw _EncodingRangeException('No more elements');
+ } else if (p < 0) {
+ throw RangeError(p);
+ }
+ return _bytes[p];
+ }
+
+ String _previous() {
+ var p = __position;
+ if (p >= _length) {
+ throw _EncodingRangeException('No more elements');
+ } else if (p < 0) {
+ throw RangeError(p);
+ }
+ __position = p = p - 1;
+ return _bytes[p];
+ }
+
+ set _position(int value) {
+ if (__position >= _length) {
+ throw _EncodingRangeException('No more elements');
+ }
+ __position = value;
+ }
+
+ int get _position {
+ if (__position >= _length) {
+ throw _EncodingRangeException('No more elements');
+ }
+ if (__position >= 0) {
+ return __position;
+ } else {
+ return 0;
+ }
+ }
+
+ String get _currentByte => _bytes[_position];
+
+ /// Skip past a list of characters. Defaults to skipping [isWhitespace].
+ String? _skipChars([_CharPredicate? skipChars]) {
+ skipChars ??= isWhitespace;
+ var p = _position; // use property for the error-checking
+ while (p < _length) {
+ final c = _bytes[p];
+ if (!skipChars(c)) {
+ __position = p;
+ return c;
+ }
+ p += 1;
+ }
+ __position = p;
+ return null;
+ }
+
+ String? _skipUntil(_CharPredicate untilChars) {
+ var p = _position;
+ while (p < _length) {
+ final c = _bytes[p];
+ if (untilChars(c)) {
+ __position = p;
+ return c;
+ }
+ p += 1;
+ }
+ return null;
+ }
+
+ /// Look for a sequence of bytes at the start of a string. If the bytes
+ /// are found return true and advance the position to the byte after the
+ /// match. Otherwise return false and leave the position alone.
+ bool _matchBytes(String bytes) {
+ final p = _position;
+ if (_bytes.length < p + bytes.length) {
+ return false;
+ }
+ final data = _bytes.substring(p, p + bytes.length);
+ if (data == bytes) {
+ _position += bytes.length;
+ return true;
+ }
+ return false;
+ }
+
+ /// Look for the next sequence of bytes matching a given sequence. If
+ /// a match is found advance the position to the last byte of the match
+ bool _jumpTo(String bytes) {
+ final newPosition = _bytes.indexOf(bytes, _position);
+ if (newPosition >= 0) {
+ __position = newPosition + bytes.length - 1;
+ return true;
+ } else {
+ throw _EncodingRangeException('No more elements');
+ }
+ }
+
+ String _slice(int start, [int? end]) {
+ end ??= _length;
+ if (end < 0) end += _length;
+ return _bytes.substring(start, end);
+ }
+}
+
+typedef _MethodHandler = bool Function();
+
+class _DispatchEntry {
+ final String pattern;
+ final _MethodHandler handler;
+
+ _DispatchEntry(this.pattern, this.handler);
+}
+
+/// Mini parser for detecting character encoding from meta elements.
+class EncodingParser {
+ final EncodingBytes _data;
+ String? _encoding;
+
+ /// [bytes] - the data to work on for encoding detection.
+ EncodingParser(List<int> bytes)
+ // Note: this is intentionally interpreting bytes as codepoints.
+ : _data = EncodingBytes(String.fromCharCodes(bytes).toLowerCase());
+
+ String? getEncoding() {
+ final methodDispatch = [
+ _DispatchEntry('<!--', _handleComment),
+ _DispatchEntry('<meta', _handleMeta),
+ _DispatchEntry('</', _handlePossibleEndTag),
+ _DispatchEntry('<!', _handleOther),
+ _DispatchEntry('<?', _handleOther),
+ _DispatchEntry('<', _handlePossibleStartTag),
+ ];
+
+ try {
+ for (;;) {
+ for (var dispatch in methodDispatch) {
+ if (_data._matchBytes(dispatch.pattern)) {
+ final keepParsing = dispatch.handler();
+ if (keepParsing) break;
+
+ // We found an encoding. Stop.
+ return _encoding;
+ }
+ }
+ _data._position += 1;
+ }
+ } on _EncodingRangeException catch (_) {
+ // Catch this here to match behavior of Python's StopIteration
+ // TODO(jmesserly): refactor to not use exceptions
+ }
+ return _encoding;
+ }
+
+ /// Skip over comments.
+ bool _handleComment() => _data._jumpTo('-->');
+
+ bool _handleMeta() {
+ if (!isWhitespace(_data._currentByte)) {
+ // if we have <meta not followed by a space so just keep going
+ return true;
+ }
+ // We have a valid meta element we want to search for attributes
+ while (true) {
+ // Try to find the next attribute after the current position
+ final attr = _getAttribute();
+ if (attr == null) return true;
+
+ if (attr[0] == 'charset') {
+ final tentativeEncoding = attr[1];
+ final codec = codecName(tentativeEncoding);
+ if (codec != null) {
+ _encoding = codec;
+ return false;
+ }
+ } else if (attr[0] == 'content') {
+ final contentParser = ContentAttrParser(EncodingBytes(attr[1]));
+ final tentativeEncoding = contentParser.parse();
+ final codec = codecName(tentativeEncoding);
+ if (codec != null) {
+ _encoding = codec;
+ return false;
+ }
+ }
+ }
+ }
+
+ bool _handlePossibleStartTag() => _handlePossibleTag(false);
+
+ bool _handlePossibleEndTag() {
+ _data._next();
+ return _handlePossibleTag(true);
+ }
+
+ bool _handlePossibleTag(bool endTag) {
+ if (!isLetter(_data._currentByte)) {
+ //If the next byte is not an ascii letter either ignore this
+ //fragment (possible start tag case) or treat it according to
+ //handleOther
+ if (endTag) {
+ _data._previous();
+ _handleOther();
+ }
+ return true;
+ }
+
+ final c = _data._skipUntil(_isSpaceOrAngleBracket);
+ if (c == '<') {
+ // return to the first step in the overall "two step" algorithm
+ // reprocessing the < byte
+ _data._previous();
+ } else {
+ //Read all attributes
+ var attr = _getAttribute();
+ while (attr != null) {
+ attr = _getAttribute();
+ }
+ }
+ return true;
+ }
+
+ bool _handleOther() => _data._jumpTo('>');
+
+ /// Return a name,value pair for the next attribute in the stream,
+ /// if one is found, or null
+ List<String>? _getAttribute() {
+ // Step 1 (skip chars)
+ var c = _data._skipChars((x) => x == '/' || isWhitespace(x));
+ // Step 2
+ if (c == '>' || c == null) {
+ return null;
+ }
+ // Step 3
+ final attrName = <String>[];
+ final attrValue = <String>[];
+ // Step 4 attribute name
+ while (true) {
+ if (c == null) {
+ return null;
+ } else if (c == '=' && attrName.isNotEmpty) {
+ break;
+ } else if (isWhitespace(c)) {
+ // Step 6!
+ c = _data._skipChars();
+ c = _data._next();
+ break;
+ } else if (c == '/' || c == '>') {
+ return [attrName.join(), ''];
+ } else if (isLetter(c)) {
+ attrName.add(c.toLowerCase());
+ } else {
+ attrName.add(c);
+ }
+ // Step 5
+ c = _data._next();
+ }
+ // Step 7
+ if (c != '=') {
+ _data._previous();
+ return [attrName.join(), ''];
+ }
+ // Step 8
+ _data._next();
+ // Step 9
+ c = _data._skipChars();
+ // Step 10
+ if (c == "'" || c == '"') {
+ // 10.1
+ final quoteChar = c;
+ while (true) {
+ // 10.2
+ c = _data._next();
+ if (c == quoteChar) {
+ // 10.3
+ _data._next();
+ return [attrName.join(), attrValue.join()];
+ } else if (isLetter(c)) {
+ // 10.4
+ attrValue.add(c.toLowerCase());
+ } else {
+ // 10.5
+ attrValue.add(c);
+ }
+ }
+ } else if (c == '>') {
+ return [attrName.join(), ''];
+ } else if (c == null) {
+ return null;
+ } else if (isLetter(c)) {
+ attrValue.add(c.toLowerCase());
+ } else {
+ attrValue.add(c);
+ }
+ // Step 11
+ while (true) {
+ c = _data._next();
+ if (_isSpaceOrAngleBracket(c)) {
+ return [attrName.join(), attrValue.join()];
+ } else if (isLetter(c)) {
+ attrValue.add(c.toLowerCase());
+ } else {
+ attrValue.add(c);
+ }
+ }
+ }
+}
+
+class ContentAttrParser {
+ final EncodingBytes data;
+
+ ContentAttrParser(this.data);
+
+ String? parse() {
+ try {
+ // Check if the attr name is charset
+ // otherwise return
+ data._jumpTo('charset');
+ data._position += 1;
+ data._skipChars();
+ if (data._currentByte != '=') {
+ // If there is no = sign keep looking for attrs
+ return null;
+ }
+ data._position += 1;
+ data._skipChars();
+ // Look for an encoding between matching quote marks
+ if (data._currentByte == '"' || data._currentByte == "'") {
+ final quoteMark = data._currentByte;
+ data._position += 1;
+ final oldPosition = data._position;
+ if (data._jumpTo(quoteMark)) {
+ return data._slice(oldPosition, data._position);
+ } else {
+ return null;
+ }
+ } else {
+ // Unquoted value
+ final oldPosition = data._position;
+ try {
+ data._skipUntil(isWhitespace);
+ return data._slice(oldPosition, data._position);
+ } on _EncodingRangeException catch (_) {
+ //Return the whole remaining value
+ return data._slice(oldPosition);
+ }
+ }
+ } on _EncodingRangeException catch (_) {
+ return null;
+ }
+ }
+}
+
+bool _isSpaceOrAngleBracket(String char) {
+ return char == '>' || char == '<' || isWhitespace(char);
+}
+
+typedef _CharPredicate = bool Function(String char);
+
+class _EncodingRangeException implements Exception {
+ final String message;
+
+ _EncodingRangeException(this.message);
+}
diff --git a/pkgs/html/lib/src/html_input_stream.dart b/pkgs/html/lib/src/html_input_stream.dart
new file mode 100644
index 0000000..b093d3c
--- /dev/null
+++ b/pkgs/html/lib/src/html_input_stream.dart
@@ -0,0 +1,340 @@
+import 'dart:collection';
+import 'dart:convert' show ascii, utf8;
+
+import 'package:source_span/source_span.dart';
+
+import 'constants.dart';
+import 'encoding_parser.dart';
+import 'utils.dart';
+
+/// Provides a unicode stream of characters to the HtmlTokenizer.
+///
+/// This class takes care of character encoding and removing or replacing
+/// incorrect byte-sequences and also provides column and line tracking.
+class HtmlInputStream {
+ /// Number of bytes to use when looking for a meta element with
+ /// encoding information.
+ static const int numBytesMeta = 512;
+
+ /// Encoding to use if no other information can be found.
+ static const String defaultEncoding = 'utf-8';
+
+ /// The name of the character encoding.
+ String? charEncodingName;
+
+ /// True if we are certain about [charEncodingName], false for tentative.
+ bool charEncodingCertain = true;
+
+ final bool generateSpans;
+
+ /// Location where the contents of the stream were found.
+ final String? sourceUrl;
+
+ List<int>? _rawBytes;
+
+ /// Raw UTF-16 codes, used if a Dart String is passed in.
+ List<int>? _rawChars;
+
+ Queue<String> errors = Queue<String>();
+
+ SourceFile? fileInfo;
+
+ var _chars = <int>[];
+
+ var _offset = 0;
+
+ /// Initialise an HtmlInputStream.
+ ///
+ /// HtmlInputStream(source, [encoding]) -> Normalized stream from source
+ /// for use by html5lib.
+ ///
+ /// [source] can be either a `String` or a `List<int>` containing the raw
+ /// bytes.
+ ///
+ /// The optional encoding parameter must be a string that indicates
+ /// the encoding. If specified, that encoding will be used,
+ /// regardless of any BOM or later declaration (such as in a meta
+ /// element)
+ ///
+ /// [parseMeta] - Look for a <meta> element containing encoding information
+ HtmlInputStream(dynamic source,
+ [String? encoding,
+ bool parseMeta = true,
+ this.generateSpans = false,
+ this.sourceUrl])
+ : charEncodingName = codecName(encoding) {
+ if (source is String) {
+ _rawChars = source.codeUnits;
+ charEncodingName = 'utf-8';
+ charEncodingCertain = true;
+ } else if (source is List<int>) {
+ _rawBytes = source;
+ } else {
+ throw ArgumentError.value(
+ source, 'source', 'Must be a String or List<int>.');
+ }
+
+ // Detect encoding iff no explicit "transport level" encoding is supplied
+ if (charEncodingName == null) {
+ detectEncoding(parseMeta);
+ }
+
+ reset();
+ }
+
+ void reset() {
+ errors = Queue<String>();
+
+ _offset = 0;
+ _chars = <int>[];
+
+ final rawChars = _rawChars ??= _decodeBytes(charEncodingName!, _rawBytes!);
+
+ var skipNewline = false;
+ var wasSurrogatePair = false;
+ for (var i = 0; i < rawChars.length; i++) {
+ var c = rawChars[i];
+ if (skipNewline) {
+ skipNewline = false;
+ if (c == newLine) continue;
+ }
+
+ final isSurrogatePair = _isSurrogatePair(rawChars, i);
+ if (!isSurrogatePair && !wasSurrogatePair) {
+ if (_invalidUnicode(c)) {
+ errors.add('invalid-codepoint');
+
+ if (0xD800 <= c && c <= 0xDFFF) {
+ c = 0xFFFD;
+ }
+ }
+ }
+ wasSurrogatePair = isSurrogatePair;
+
+ if (c == returnCode) {
+ skipNewline = true;
+ c = newLine;
+ }
+
+ _chars.add(c);
+ }
+
+ // Free decoded characters if they aren't needed anymore.
+ if (_rawBytes != null) _rawChars = null;
+
+ // TODO(sigmund): Don't parse the file at all if spans aren't being
+ // generated.
+ fileInfo = SourceFile.decoded(_chars, url: sourceUrl);
+ }
+
+ void detectEncoding([bool parseMeta = true]) {
+ // First look for a BOM
+ // This will also read past the BOM if present
+ charEncodingName = detectBOM();
+ charEncodingCertain = true;
+
+ // If there is no BOM need to look for meta elements with encoding
+ // information
+ if (charEncodingName == null && parseMeta) {
+ charEncodingName = detectEncodingMeta();
+ charEncodingCertain = false;
+ }
+ // If all else fails use the default encoding
+ if (charEncodingName == null) {
+ charEncodingCertain = false;
+ charEncodingName = defaultEncoding;
+ }
+
+ // Substitute for equivalent encodings:
+ if (charEncodingName!.toLowerCase() == 'iso-8859-1') {
+ charEncodingName = 'windows-1252';
+ }
+ }
+
+ void changeEncoding(String? newEncoding) {
+ if (_rawBytes == null) {
+ // We should never get here -- if encoding is certain we won't try to
+ // change it.
+ throw StateError('cannot change encoding when parsing a String.');
+ }
+
+ newEncoding = codecName(newEncoding);
+ if (const ['utf-16', 'utf-16-be', 'utf-16-le'].contains(newEncoding)) {
+ newEncoding = 'utf-8';
+ }
+ if (newEncoding == null) {
+ return;
+ } else if (newEncoding == charEncodingName) {
+ charEncodingCertain = true;
+ } else {
+ charEncodingName = newEncoding;
+ charEncodingCertain = true;
+ _rawChars = null;
+ reset();
+ throw ReparseException(
+ 'Encoding changed from $charEncodingName to $newEncoding');
+ }
+ }
+
+ /// Attempts to detect at BOM at the start of the stream. If
+ /// an encoding can be determined from the BOM return the name of the
+ /// encoding otherwise return null.
+ String? detectBOM() {
+ // Try detecting the BOM using bytes from the string
+ if (_hasUtf8Bom(_rawBytes!)) {
+ return 'utf-8';
+ }
+ return null;
+ }
+
+ /// Report the encoding declared by the meta element.
+ String? detectEncodingMeta() {
+ final parser = EncodingParser(slice(_rawBytes!, 0, numBytesMeta));
+ var encoding = parser.getEncoding();
+
+ if (const ['utf-16', 'utf-16-be', 'utf-16-le'].contains(encoding)) {
+ encoding = 'utf-8';
+ }
+
+ return encoding;
+ }
+
+ /// Returns the current offset in the stream, i.e. the number of codepoints
+ /// since the start of the file.
+ int get position => _offset;
+
+ /// Read one character from the stream or queue if available. Return
+ /// EOF when EOF is reached.
+ String? char() {
+ if (_offset >= _chars.length) return eof;
+ return _isSurrogatePair(_chars, _offset)
+ ? String.fromCharCodes([_chars[_offset++], _chars[_offset++]])
+ : String.fromCharCode(_chars[_offset++]);
+ }
+
+ String? peekChar() {
+ if (_offset >= _chars.length) return eof;
+ return _isSurrogatePair(_chars, _offset)
+ ? String.fromCharCodes([_chars[_offset], _chars[_offset + 1]])
+ : String.fromCharCode(_chars[_offset]);
+ }
+
+ // Whether the current and next chars indicate a surrogate pair.
+ bool _isSurrogatePair(List<int> chars, int i) {
+ return i + 1 < chars.length &&
+ _isLeadSurrogate(chars[i]) &&
+ _isTrailSurrogate(chars[i + 1]);
+ }
+
+ // Is then code (a 16-bit unsigned integer) a UTF-16 lead surrogate.
+ bool _isLeadSurrogate(int code) => (code & 0xFC00) == 0xD800;
+
+ // Is then code (a 16-bit unsigned integer) a UTF-16 trail surrogate.
+ bool _isTrailSurrogate(int code) => (code & 0xFC00) == 0xDC00;
+
+ /// Returns a string of characters from the stream up to but not
+ /// including any character in 'characters' or EOF.
+ String charsUntil(String characters, [bool opposite = false]) {
+ final start = _offset;
+ String? c;
+ while ((c = peekChar()) != null && characters.contains(c!) == opposite) {
+ _offset += c.codeUnits.length;
+ }
+
+ return String.fromCharCodes(_chars.sublist(start, _offset));
+ }
+
+ void unget(String? ch) {
+ // Only one character is allowed to be ungotten at once - it must
+ // be consumed again before any further call to unget
+ if (ch != null) {
+ _offset -= ch.length;
+ assert(peekChar() == ch);
+ }
+ }
+}
+
+// TODO(jmesserly): the Python code used a regex to check for this. But
+// Dart doesn't let you create a regexp with invalid characters.
+bool _invalidUnicode(int c) {
+ if (0x0001 <= c && c <= 0x0008) return true;
+ if (0x000E <= c && c <= 0x001F) return true;
+ if (0x007F <= c && c <= 0x009F) return true;
+ if (0xD800 <= c && c <= 0xDFFF) return true;
+ if (0xFDD0 <= c && c <= 0xFDEF) return true;
+ switch (c) {
+ case 0x000B:
+ case 0xFFFE:
+ case 0xFFFF:
+ case 0x01FFFE:
+ case 0x01FFFF:
+ case 0x02FFFE:
+ case 0x02FFFF:
+ case 0x03FFFE:
+ case 0x03FFFF:
+ case 0x04FFFE:
+ case 0x04FFFF:
+ case 0x05FFFE:
+ case 0x05FFFF:
+ case 0x06FFFE:
+ case 0x06FFFF:
+ case 0x07FFFE:
+ case 0x07FFFF:
+ case 0x08FFFE:
+ case 0x08FFFF:
+ case 0x09FFFE:
+ case 0x09FFFF:
+ case 0x0AFFFE:
+ case 0x0AFFFF:
+ case 0x0BFFFE:
+ case 0x0BFFFF:
+ case 0x0CFFFE:
+ case 0x0CFFFF:
+ case 0x0DFFFE:
+ case 0x0DFFFF:
+ case 0x0EFFFE:
+ case 0x0EFFFF:
+ case 0x0FFFFE:
+ case 0x0FFFFF:
+ case 0x10FFFE:
+ case 0x10FFFF:
+ return true;
+ }
+ return false;
+}
+
+/// Return the python codec name corresponding to an encoding or null if the
+/// string doesn't correspond to a valid encoding.
+String? codecName(String? encoding) {
+ final asciiPunctuation = RegExp(
+ '[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]');
+
+ if (encoding == null) return null;
+ final canonicalName = encoding.replaceAll(asciiPunctuation, '').toLowerCase();
+ return encodings[canonicalName];
+}
+
+/// Returns true if the [bytes] starts with a UTF-8 byte order mark.
+/// Since UTF-8 doesn't have byte order, it's somewhat of a misnomer, but it is
+/// used in HTML to detect the UTF-
+bool _hasUtf8Bom(List<int> bytes, [int offset = 0, int? length]) {
+ final end = length != null ? offset + length : bytes.length;
+ return (offset + 3) <= end &&
+ bytes[offset] == 0xEF &&
+ bytes[offset + 1] == 0xBB &&
+ bytes[offset + 2] == 0xBF;
+}
+
+/// Decodes the [bytes] with the provided [encoding] and returns a list for
+/// the codepoints. Supports the major unicode encodings as well as ascii and
+/// and windows-1252 encodings.
+List<int> _decodeBytes(String encoding, List<int> bytes) {
+ return switch (encoding) {
+ 'ascii' => ascii.decode(bytes).codeUnits,
+ 'utf-8' =>
+ // NOTE: To match the behavior of the other decode functions, we eat the
+ // UTF-8 BOM here. This is the default behavior of `utf8.decode`.
+ utf8.decode(bytes).codeUnits,
+ _ => throw ArgumentError('Encoding $encoding not supported')
+ };
+}
diff --git a/pkgs/html/lib/src/list_proxy.dart b/pkgs/html/lib/src/list_proxy.dart
new file mode 100644
index 0000000..f226d7f
--- /dev/null
+++ b/pkgs/html/lib/src/list_proxy.dart
@@ -0,0 +1,59 @@
+/// A [List] proxy that you can subclass.
+library;
+
+import 'dart:collection';
+
+abstract class ListProxy<E> extends ListBase<E> {
+ /// The proxied list with actual storage.
+ final List<E> _list = <E>[];
+
+ @override
+ bool remove(Object? element) => _list.remove(element);
+
+ @override
+ int get length => _list.length;
+
+ // From Iterable
+ @override
+ Iterator<E> get iterator => _list.iterator;
+
+ // From List
+ @override
+ E operator [](int index) => _list[index];
+
+ @override
+ void operator []=(int index, E value) {
+ _list[index] = value;
+ }
+
+ @override
+ set length(int value) {
+ _list.length = value;
+ }
+
+ @override
+ void add(E element) {
+ _list.add(element);
+ }
+
+ @override
+ void insert(int index, E element) => _list.insert(index, element);
+
+ @override
+ void addAll(Iterable<E> iterable) {
+ _list.addAll(iterable);
+ }
+
+ @override
+ void insertAll(int index, Iterable<E> iterable) {
+ _list.insertAll(index, iterable);
+ }
+
+ @override
+ E removeAt(int index) => _list.removeAt(index);
+
+ @override
+ void removeRange(int start, int end) {
+ _list.removeRange(start, end);
+ }
+}
diff --git a/pkgs/html/lib/src/query_selector.dart b/pkgs/html/lib/src/query_selector.dart
new file mode 100644
index 0000000..b57b811
--- /dev/null
+++ b/pkgs/html/lib/src/query_selector.dart
@@ -0,0 +1,300 @@
+/// Query selector implementation for our DOM.
+library;
+
+import 'package:csslib/parser.dart';
+import 'package:csslib/visitor.dart';
+
+import '../dom.dart';
+import 'constants.dart' show isWhitespaceCC;
+
+bool matches(Element node, String selector) =>
+ SelectorEvaluator().matches(node, _parseSelectorList(selector));
+
+Element? querySelector(Node node, String selector) =>
+ SelectorEvaluator().querySelector(node, _parseSelectorList(selector));
+
+List<Element> querySelectorAll(Node node, String selector) {
+ final results = <Element>[];
+ SelectorEvaluator()
+ .querySelectorAll(node, _parseSelectorList(selector), results);
+ return results;
+}
+
+// http://dev.w3.org/csswg/selectors-4/#grouping
+SelectorGroup _parseSelectorList(String selector) {
+ final errors = <Message>[];
+ final group = parseSelectorGroup(selector, errors: errors);
+ if (group == null || errors.isNotEmpty) {
+ throw FormatException("'$selector' is not a valid selector: $errors");
+ }
+ return group;
+}
+
+class SelectorEvaluator extends Visitor {
+ /// The current HTML element to match against.
+ Element? _element;
+
+ bool matches(Element element, SelectorGroup selector) {
+ _element = element;
+ return visitSelectorGroup(selector);
+ }
+
+ Element? querySelector(Node root, SelectorGroup selector) {
+ for (var element in root.nodes.whereType<Element>()) {
+ if (matches(element, selector)) return element;
+ final result = querySelector(element, selector);
+ if (result != null) return result;
+ }
+ return null;
+ }
+
+ void querySelectorAll(
+ Node root, SelectorGroup selector, List<Element> results) {
+ for (var element in root.nodes.whereType<Element>()) {
+ if (matches(element, selector)) results.add(element);
+ querySelectorAll(element, selector, results);
+ }
+ }
+
+ @override
+ bool visitSelectorGroup(SelectorGroup node) =>
+ node.selectors.any(visitSelector);
+
+ @override
+ bool visitSelector(Selector node) {
+ final old = _element;
+ var result = true;
+
+ // Note: evaluate selectors right-to-left as it's more efficient.
+ int? combinator;
+ for (var s in node.simpleSelectorSequences.reversed) {
+ if (combinator == null) {
+ result = s.simpleSelector.visit(this) as bool;
+ } else {
+ if (combinator == TokenKind.COMBINATOR_DESCENDANT) {
+ // descendant combinator
+ // http://dev.w3.org/csswg/selectors-4/#descendant-combinators
+ do {
+ _element = _element!.parent;
+ } while (_element != null && !(s.simpleSelector.visit(this) as bool));
+
+ if (_element == null) result = false;
+ } else if (combinator == TokenKind.COMBINATOR_TILDE) {
+ // Following-sibling combinator
+ // http://dev.w3.org/csswg/selectors-4/#general-sibling-combinators
+ do {
+ _element = _element!.previousElementSibling;
+ } while (_element != null && !(s.simpleSelector.visit(this) as bool));
+
+ if (_element == null) result = false;
+ }
+ combinator = null;
+ }
+
+ if (!result) break;
+
+ switch (s.combinator) {
+ case TokenKind.COMBINATOR_PLUS:
+ // Next-sibling combinator
+ // http://dev.w3.org/csswg/selectors-4/#adjacent-sibling-combinators
+ _element = _element!.previousElementSibling;
+ break;
+ case TokenKind.COMBINATOR_GREATER:
+ // Child combinator
+ // http://dev.w3.org/csswg/selectors-4/#child-combinators
+ _element = _element!.parent;
+ break;
+ case TokenKind.COMBINATOR_DESCENDANT:
+ case TokenKind.COMBINATOR_TILDE:
+ // We need to iterate through all siblings or parents.
+ // For now, just remember what the combinator was.
+ combinator = s.combinator;
+ break;
+ case TokenKind.COMBINATOR_NONE:
+ break;
+ default:
+ throw _unsupported(node);
+ }
+
+ if (_element == null) {
+ result = false;
+ break;
+ }
+ }
+
+ _element = old;
+ return result;
+ }
+
+ UnimplementedError _unimplemented(SimpleSelector selector) =>
+ UnimplementedError("'$selector' selector of type "
+ '${selector.runtimeType} is not implemented');
+
+ FormatException _unsupported(TreeNode selector) =>
+ FormatException("'$selector' is not a valid selector");
+
+ @override
+ bool visitPseudoClassSelector(PseudoClassSelector node) {
+ switch (node.name) {
+ // http://dev.w3.org/csswg/selectors-4/#structural-pseudos
+
+ // http://dev.w3.org/csswg/selectors-4/#the-root-pseudo
+ case 'root':
+ // TODO(jmesserly): fix when we have a .ownerDocument pointer
+ // return _element == _element.ownerDocument.rootElement;
+ return _element!.localName == 'html' && _element!.parentNode == null;
+
+ // http://dev.w3.org/csswg/selectors-4/#the-empty-pseudo
+ case 'empty':
+ return _element!.nodes
+ .any((n) => !(n is Element || n is Text && n.text.isNotEmpty));
+
+ // http://dev.w3.org/csswg/selectors-4/#the-blank-pseudo
+ case 'blank':
+ return _element!.nodes.any((n) => !(n is Element ||
+ n is Text && n.text.runes.any((r) => !isWhitespaceCC(r))));
+
+ // http://dev.w3.org/csswg/selectors-4/#the-first-child-pseudo
+ case 'first-child':
+ return _element!.previousElementSibling == null;
+
+ // http://dev.w3.org/csswg/selectors-4/#the-last-child-pseudo
+ case 'last-child':
+ return _element!.nextElementSibling == null;
+
+ // http://dev.w3.org/csswg/selectors-4/#the-only-child-pseudo
+ case 'only-child':
+ return _element!.previousElementSibling == null &&
+ _element!.nextElementSibling == null;
+
+ // http://dev.w3.org/csswg/selectors-4/#link
+ case 'link':
+ return _element!.attributes['href'] != null;
+
+ case 'visited':
+ // Always return false since we aren't a browser. This is allowed per:
+ // http://dev.w3.org/csswg/selectors-4/#visited-pseudo
+ return false;
+ }
+
+ // :before, :after, :first-letter/line can't match DOM elements.
+ if (_isLegacyPsuedoClass(node.name)) return false;
+
+ throw _unimplemented(node);
+ }
+
+ @override
+ bool visitPseudoElementSelector(PseudoElementSelector node) {
+ // :before, :after, :first-letter/line can't match DOM elements.
+ if (_isLegacyPsuedoClass(node.name)) return false;
+
+ throw _unimplemented(node);
+ }
+
+ static bool _isLegacyPsuedoClass(String name) {
+ switch (name) {
+ case 'before':
+ case 'after':
+ case 'first-line':
+ case 'first-letter':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @override
+ bool visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) =>
+ throw _unimplemented(node);
+
+ @override
+ bool visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) {
+ switch (node.name) {
+ // http://dev.w3.org/csswg/selectors-4/#child-index
+
+ // http://dev.w3.org/csswg/selectors-4/#the-nth-child-pseudo
+ case 'nth-child':
+ // TODO(jmesserly): support An+B syntax too.
+ final exprs = node.expression.expressions;
+ if (exprs.length == 1 && exprs[0] is LiteralTerm) {
+ final literal = exprs[0] as LiteralTerm;
+ final parent = _element!.parentNode;
+ return parent != null &&
+ (literal.value as num) > 0 &&
+ parent.nodes.indexOf(_element) == literal.value;
+ }
+ break;
+
+ // http://dev.w3.org/csswg/selectors-4/#the-lang-pseudo
+ case 'lang':
+ // TODO(jmesserly): shouldn't need to get the raw text here, but csslib
+ // gets confused by the "-" in the expression, such as in "es-AR".
+ final toMatch = node.expression.span.text;
+ final lang = _getInheritedLanguage(_element);
+ // TODO(jmesserly): implement wildcards in level 4
+ return lang != null && lang.startsWith(toMatch);
+ }
+ throw _unimplemented(node);
+ }
+
+ static String? _getInheritedLanguage(Node? node) {
+ while (node != null) {
+ final lang = node.attributes['lang'];
+ if (lang != null) return lang;
+ node = node.parent;
+ }
+ return null;
+ }
+
+ @override
+ bool visitNamespaceSelector(NamespaceSelector node) {
+ // Match element tag name
+ if (!(node.nameAsSimpleSelector!.visit(this) as bool)) return false;
+
+ if (node.isNamespaceWildcard) return true;
+
+ if (node.namespace == '') return _element!.namespaceUri == null;
+
+ throw _unimplemented(node);
+ }
+
+ @override
+ bool visitElementSelector(ElementSelector node) =>
+ node.isWildcard || _element!.localName == node.name.toLowerCase();
+
+ @override
+ bool visitIdSelector(IdSelector node) => _element!.id == node.name;
+
+ @override
+ bool visitClassSelector(ClassSelector node) =>
+ _element!.classes.contains(node.name);
+
+ // TODO(jmesserly): negation should support any selectors in level 4,
+ // not just simple selectors.
+ // http://dev.w3.org/csswg/selectors-4/#negation
+ @override
+ bool visitNegationSelector(NegationSelector node) =>
+ !(node.negationArg!.visit(this) as bool);
+
+ @override
+ bool visitAttributeSelector(AttributeSelector node) {
+ // Match name first
+ final value = _element!.attributes[node.name.toLowerCase()];
+ if (value == null) return false;
+
+ if (node.operatorKind == TokenKind.NO_MATCH) return true;
+
+ final select = '${node.value}';
+ return switch (node.operatorKind) {
+ TokenKind.EQUALS => value == select,
+ TokenKind.INCLUDES =>
+ value.split(' ').any((v) => v.isNotEmpty && v == select),
+ TokenKind.DASH_MATCH => value.startsWith(select) &&
+ (value.length == select.length || value[select.length] == '-'),
+ TokenKind.PREFIX_MATCH => value.startsWith(select),
+ TokenKind.SUFFIX_MATCH => value.endsWith(select),
+ TokenKind.SUBSTRING_MATCH => value.contains(select),
+ _ => throw _unsupported(node)
+ };
+ }
+}
diff --git a/pkgs/html/lib/src/token.dart b/pkgs/html/lib/src/token.dart
new file mode 100644
index 0000000..1ade790
--- /dev/null
+++ b/pkgs/html/lib/src/token.dart
@@ -0,0 +1,151 @@
+/// This library contains token types used by the html5 tokenizer.
+library;
+
+import 'dart:collection';
+
+import 'package:source_span/source_span.dart';
+
+/// An html5 token.
+abstract class Token {
+ FileSpan? span;
+
+ int get kind;
+}
+
+abstract class TagToken extends Token {
+ String? name;
+
+ bool selfClosing;
+
+ TagToken(this.name, this.selfClosing);
+}
+
+class StartTagToken extends TagToken {
+ /// The tag's attributes. A map from the name to the value, where the name
+ /// can be a [String] or `AttributeName`.
+ LinkedHashMap<Object, String> data;
+
+ /// The attribute spans if requested. Otherwise null.
+ List<TagAttribute>? attributeSpans;
+
+ bool selfClosingAcknowledged;
+
+ /// The namespace. This is filled in later during tree building.
+ String? namespace;
+
+ StartTagToken(String? name,
+ {LinkedHashMap<Object, String>? data,
+ bool selfClosing = false,
+ this.selfClosingAcknowledged = false,
+ this.namespace})
+ : data = data ?? LinkedHashMap(),
+ super(name, selfClosing);
+
+ @override
+ int get kind => TokenKind.startTag;
+}
+
+class EndTagToken extends TagToken {
+ EndTagToken(String? name, {bool selfClosing = false})
+ : super(name, selfClosing);
+
+ @override
+ int get kind => TokenKind.endTag;
+}
+
+abstract class StringToken extends Token {
+ StringBuffer? _buffer;
+
+ String? _string;
+ String get data {
+ if (_string == null) {
+ _string = _buffer.toString();
+ _buffer = null;
+ }
+ return _string!;
+ }
+
+ StringToken(this._string) : _buffer = _string == null ? StringBuffer() : null;
+
+ StringToken add(String data) {
+ _buffer!.write(data);
+ return this;
+ }
+}
+
+class ParseErrorToken extends StringToken {
+ /// Extra information that goes along with the error message.
+ Map<String, Object?>? messageParams;
+
+ ParseErrorToken(String super.data, {this.messageParams});
+
+ @override
+ int get kind => TokenKind.parseError;
+}
+
+class CharactersToken extends StringToken {
+ CharactersToken([super.data]);
+
+ @override
+ int get kind => TokenKind.characters;
+
+ /// Replaces the token's [data]. This should only be used to wholly replace
+ /// data, not to append data.
+ void replaceData(String newData) {
+ _string = newData;
+ _buffer = null;
+ }
+}
+
+class SpaceCharactersToken extends StringToken {
+ SpaceCharactersToken([super.data]);
+
+ @override
+ int get kind => TokenKind.spaceCharacters;
+}
+
+class CommentToken extends StringToken {
+ CommentToken([super.data]);
+
+ @override
+ int get kind => TokenKind.comment;
+}
+
+class DoctypeToken extends Token {
+ String? publicId;
+ String? systemId;
+ String? name = '';
+ bool correct;
+
+ DoctypeToken({this.publicId, this.systemId, this.correct = false});
+
+ @override
+ int get kind => TokenKind.doctype;
+}
+
+/// These are used by the tokenizer to build up the attribute map.
+/// They're also used by [StartTagToken.attributeSpans] if attribute spans are
+/// requested.
+class TagAttribute {
+ String? name;
+ late String value;
+
+ // The spans of the attribute. This is not used unless we are computing an
+ // attribute span on demand.
+ late int start;
+ late int end;
+ int? startValue;
+ late int endValue;
+
+ TagAttribute();
+}
+
+class TokenKind {
+ static const int spaceCharacters = 0;
+ static const int characters = 1;
+ static const int startTag = 2;
+ static const int endTag = 3;
+ static const int comment = 4;
+ static const int doctype = 5;
+ static const int parseError = 6;
+}
diff --git a/pkgs/html/lib/src/tokenizer.dart b/pkgs/html/lib/src/tokenizer.dart
new file mode 100644
index 0000000..3bed0b0
--- /dev/null
+++ b/pkgs/html/lib/src/tokenizer.dart
@@ -0,0 +1,1907 @@
+import 'dart:collection';
+
+import '../parser.dart' show HtmlParser;
+
+import 'constants.dart';
+import 'html_input_stream.dart';
+import 'token.dart';
+import 'utils.dart';
+
+// Group entities by their first character, for faster lookups
+
+// TODO(jmesserly): we could use a better data structure here like a trie, if
+// we had it implemented in Dart.
+Map<String, List<String>> entitiesByFirstChar = (() {
+ final result = <String, List<String>>{};
+ for (var k in entities.keys) {
+ result.putIfAbsent(k[0], () => []).add(k);
+ }
+ return result;
+})();
+
+// TODO(jmesserly): lots of ways to make this faster:
+// - use char codes everywhere instead of 1-char strings
+// - use switch instead of contains, indexOf
+// - use switch instead of the sequential if tests
+// - avoid string concat
+
+/// This class takes care of tokenizing HTML.
+class HtmlTokenizer implements Iterator<Token> {
+ // TODO(jmesserly): a lot of these could be made private
+
+ final HtmlInputStream stream;
+
+ final bool lowercaseElementName;
+
+ final bool lowercaseAttrName;
+
+ /// True to generate spans in for [Token.span].
+ final bool generateSpans;
+
+ /// True to generate spans for attributes.
+ final bool attributeSpans;
+
+ /// This reference to the parser is used for correct CDATA handling.
+ /// The [HtmlParser] will set this at construction time.
+ HtmlParser? parser;
+
+ final Queue<Token?> tokenQueue;
+
+ /// Holds the token that is currently being processed.
+ Token? currentToken;
+
+ /// Holds a reference to the method to be invoked for the next parser state.
+ late bool Function() state;
+
+ final StringBuffer _buffer = StringBuffer();
+
+ late int _lastOffset;
+
+ // TODO(jmesserly): ideally this would be a LinkedHashMap and we wouldn't add
+ // an item until it's ready. But the code doesn't have a clear notion of when
+ // it's "done" with the attribute.
+ List<TagAttribute>? _attributes;
+ Set<String>? _attributeNames;
+
+ HtmlTokenizer(dynamic doc,
+ {String? encoding,
+ bool parseMeta = true,
+ this.lowercaseElementName = true,
+ this.lowercaseAttrName = true,
+ this.generateSpans = false,
+ String? sourceUrl,
+ this.attributeSpans = false})
+ : stream =
+ HtmlInputStream(doc, encoding, parseMeta, generateSpans, sourceUrl),
+ tokenQueue = Queue() {
+ reset();
+ }
+
+ TagToken get currentTagToken => currentToken as TagToken;
+ DoctypeToken get currentDoctypeToken => currentToken as DoctypeToken;
+ StringToken get currentStringToken => currentToken as StringToken;
+
+ Token? _current;
+ @override
+ Token get current => _current!;
+
+ final StringBuffer _attributeName = StringBuffer();
+ final StringBuffer _attributeValue = StringBuffer();
+
+ void _markAttributeEnd(int offset) {
+ _attributes!.last.value = '$_attributeValue';
+ if (attributeSpans) _attributes!.last.end = stream.position + offset;
+ }
+
+ void _markAttributeValueStart(int offset) {
+ if (attributeSpans) _attributes!.last.startValue = stream.position + offset;
+ }
+
+ void _markAttributeValueEnd(int offset) {
+ if (attributeSpans) _attributes!.last.endValue = stream.position + offset;
+ _markAttributeEnd(offset);
+ }
+
+ // Note: we could track the name span here, if we need it.
+ void _markAttributeNameEnd(int offset) => _markAttributeEnd(offset);
+
+ void _addAttribute(String name) {
+ _attributes ??= [];
+ _attributeName.clear();
+ _attributeName.write(name);
+ _attributeValue.clear();
+ final attr = TagAttribute();
+ _attributes!.add(attr);
+ if (attributeSpans) attr.start = stream.position - name.length;
+ }
+
+ /// This is where the magic happens.
+ ///
+ /// We do our usually processing through the states and when we have a token
+ /// to return we yield the token which pauses processing until the next token
+ /// is requested.
+ @override
+ bool moveNext() {
+ // Start processing. When EOF is reached state will return false;
+ // instead of true and the loop will terminate.
+ while (stream.errors.isEmpty && tokenQueue.isEmpty) {
+ if (!state()) {
+ _current = null;
+ return false;
+ }
+ }
+ if (stream.errors.isNotEmpty) {
+ _current = ParseErrorToken(stream.errors.removeFirst());
+ } else {
+ assert(tokenQueue.isNotEmpty);
+ _current = tokenQueue.removeFirst();
+ }
+ return true;
+ }
+
+ /// Resets the tokenizer state. Calling this does not reset the [stream] or
+ /// the [parser].
+ void reset() {
+ _lastOffset = 0;
+ tokenQueue.clear();
+ currentToken = null;
+ _buffer.clear();
+ _attributes = null;
+ _attributeNames = null;
+ state = dataState;
+ }
+
+ /// Adds a token to the queue. Sets the span if needed.
+ void _addToken(Token token) {
+ if (generateSpans && token.span == null) {
+ final offset = stream.position;
+ token.span = stream.fileInfo!.span(_lastOffset, offset);
+ if (token is! ParseErrorToken) {
+ _lastOffset = offset;
+ }
+ }
+ tokenQueue.add(token);
+ }
+
+ /// This function returns either U+FFFD or the character based on the
+ /// decimal or hexadecimal representation. It also discards ";" if present.
+ /// If not present it will add a [ParseErrorToken].
+ String consumeNumberEntity(bool isHex) {
+ var allowed = isDigit;
+ var radix = 10;
+ if (isHex) {
+ allowed = isHexDigit;
+ radix = 16;
+ }
+
+ final charStack = <String?>[];
+
+ // Consume all the characters that are in range while making sure we
+ // don't hit an EOF.
+ var c = stream.char();
+ while (allowed(c) && c != eof) {
+ charStack.add(c);
+ c = stream.char();
+ }
+
+ // Convert the set of characters consumed to an int.
+ final charAsInt = int.parse(charStack.join(), radix: radix);
+
+ // Certain characters get replaced with others
+ var char = replacementCharacters[charAsInt];
+ if (char != null) {
+ _addToken(ParseErrorToken('illegal-codepoint-for-numeric-entity',
+ messageParams: {'charAsInt': charAsInt}));
+ } else if ((0xD800 <= charAsInt && charAsInt <= 0xDFFF) ||
+ (charAsInt > 0x10FFFF)) {
+ char = '\uFFFD';
+ _addToken(ParseErrorToken('illegal-codepoint-for-numeric-entity',
+ messageParams: {'charAsInt': charAsInt}));
+ } else {
+ // Should speed up this check somehow (e.g. move the set to a constant)
+ if ((0x0001 <= charAsInt && charAsInt <= 0x0008) ||
+ (0x000E <= charAsInt && charAsInt <= 0x001F) ||
+ (0x007F <= charAsInt && charAsInt <= 0x009F) ||
+ (0xFDD0 <= charAsInt && charAsInt <= 0xFDEF) ||
+ const [
+ 0x000B,
+ 0xFFFE,
+ 0xFFFF,
+ 0x1FFFE,
+ 0x1FFFF,
+ 0x2FFFE,
+ 0x2FFFF,
+ 0x3FFFE,
+ 0x3FFFF,
+ 0x4FFFE,
+ 0x4FFFF,
+ 0x5FFFE,
+ 0x5FFFF,
+ 0x6FFFE,
+ 0x6FFFF,
+ 0x7FFFE,
+ 0x7FFFF,
+ 0x8FFFE,
+ 0x8FFFF,
+ 0x9FFFE,
+ 0x9FFFF,
+ 0xAFFFE,
+ 0xAFFFF,
+ 0xBFFFE,
+ 0xBFFFF,
+ 0xCFFFE,
+ 0xCFFFF,
+ 0xDFFFE,
+ 0xDFFFF,
+ 0xEFFFE,
+ 0xEFFFF,
+ 0xFFFFE,
+ 0xFFFFF,
+ 0x10FFFE,
+ 0x10FFFF
+ ].contains(charAsInt)) {
+ _addToken(ParseErrorToken('illegal-codepoint-for-numeric-entity',
+ messageParams: {'charAsInt': charAsInt}));
+ }
+ char = String.fromCharCodes([charAsInt]);
+ }
+
+ // Discard the ; if present. Otherwise, put it back on the queue and
+ // invoke parseError on parser.
+ if (c != ';') {
+ _addToken(ParseErrorToken('numeric-entity-without-semicolon'));
+ stream.unget(c);
+ }
+ return char;
+ }
+
+ void consumeEntity({String? allowedChar, bool fromAttribute = false}) {
+ // Initialise to the default output for when no entity is matched
+ String? output = '&';
+
+ final charStack = [stream.char()];
+ if (isWhitespace(charStack[0]) ||
+ charStack[0] == '<' ||
+ charStack[0] == '&' ||
+ charStack[0] == eof ||
+ allowedChar == charStack[0]) {
+ stream.unget(charStack[0]);
+ } else if (charStack[0] == '#') {
+ // Read the next character to see if it's hex or decimal
+ var hex = false;
+ charStack.add(stream.char());
+ if (charStack.last == 'x' || charStack.last == 'X') {
+ hex = true;
+ charStack.add(stream.char());
+ }
+
+ // charStack.last should be the first digit
+ if (hex && isHexDigit(charStack.last) ||
+ (!hex && isDigit(charStack.last))) {
+ // At least one digit found, so consume the whole number
+ stream.unget(charStack.last);
+ output = consumeNumberEntity(hex);
+ } else {
+ // No digits found
+ _addToken(ParseErrorToken('expected-numeric-entity'));
+ stream.unget(charStack.removeLast());
+ output = '&${charStack.join()}';
+ }
+ } else {
+ // At this point in the process might have named entity. Entities
+ // are stored in the global variable "entities".
+ //
+ // Consume characters and compare to these to a substring of the
+ // entity names in the list until the substring no longer matches.
+ var filteredEntityList = entitiesByFirstChar[charStack[0]!] ?? const [];
+
+ while (charStack.last != eof) {
+ final name = charStack.join();
+ filteredEntityList = filteredEntityList
+ .where((e) => e.startsWith(name))
+ .toList(growable: false);
+
+ if (filteredEntityList.isEmpty) {
+ break;
+ }
+ charStack.add(stream.char());
+ }
+
+ // At this point we have a string that starts with some characters
+ // that may match an entity
+ String? entityName;
+
+ // Try to find the longest entity the string will match to take care
+ // of ¬i for instance.
+
+ int entityLen;
+ for (entityLen = charStack.length - 1; entityLen > 1; entityLen--) {
+ final possibleEntityName = charStack.sublist(0, entityLen).join();
+ if (entities.containsKey(possibleEntityName)) {
+ entityName = possibleEntityName;
+ break;
+ }
+ }
+
+ if (entityName != null) {
+ final lastChar = entityName[entityName.length - 1];
+ if (lastChar != ';') {
+ _addToken(ParseErrorToken('named-entity-without-semicolon'));
+ }
+ if (lastChar != ';' &&
+ fromAttribute &&
+ (isLetterOrDigit(charStack[entityLen]) ||
+ charStack[entityLen] == '=')) {
+ stream.unget(charStack.removeLast());
+ output = '&${charStack.join()}';
+ } else {
+ output = entities[entityName];
+ stream.unget(charStack.removeLast());
+ output = '$output${slice(charStack, entityLen).join()}';
+ }
+ } else {
+ _addToken(ParseErrorToken('expected-named-entity'));
+ stream.unget(charStack.removeLast());
+ output = '&${charStack.join()}';
+ }
+ }
+ if (fromAttribute) {
+ _attributeValue.write(output);
+ } else {
+ Token token;
+ if (isWhitespace(output)) {
+ token = SpaceCharactersToken(output);
+ } else {
+ token = CharactersToken(output);
+ }
+ _addToken(token);
+ }
+ }
+
+ /// This method replaces the need for "entityInAttributeValueState".
+ void processEntityInAttribute(String allowedChar) {
+ consumeEntity(allowedChar: allowedChar, fromAttribute: true);
+ }
+
+ /// This method is a generic handler for emitting the tags. It also sets
+ /// the state to "data" because that's what's needed after a token has been
+ /// emitted.
+ void emitCurrentToken() {
+ final token = currentToken!;
+ // Add token to the queue to be yielded
+ if (token is TagToken) {
+ if (lowercaseElementName) {
+ token.name = token.name?.toAsciiLowerCase();
+ }
+ if (token is EndTagToken) {
+ if (_attributes != null) {
+ _addToken(ParseErrorToken('attributes-in-end-tag'));
+ }
+ if (token.selfClosing) {
+ _addToken(ParseErrorToken('this-closing-flag-on-end-tag'));
+ }
+ } else if (token is StartTagToken) {
+ // HTML5 specific normalizations to the token stream.
+ // Convert the list into a map where first key wins.
+ token.data = LinkedHashMap<Object, String>();
+ if (_attributes != null) {
+ for (var attr in _attributes!) {
+ token.data.putIfAbsent(attr.name!, () => attr.value);
+ }
+ if (attributeSpans) token.attributeSpans = _attributes;
+ }
+ }
+ _attributes = null;
+ _attributeNames = null;
+ }
+ _addToken(token);
+ state = dataState;
+ }
+
+ // Below are the various tokenizer states worked out.
+
+ bool dataState() {
+ final data = stream.char();
+ if (data == '&') {
+ state = entityDataState;
+ } else if (data == '<') {
+ state = tagOpenState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\u0000'));
+ } else if (data == eof) {
+ // Tokenization ends.
+ return false;
+ } else if (isWhitespace(data)) {
+ // Directly after emitting a token you switch back to the "data
+ // state". At that point spaceCharacters are important so they are
+ // emitted separately.
+ _addToken(SpaceCharactersToken(
+ '$data${stream.charsUntil(spaceCharacters, true)}'));
+ // No need to update lastFourChars here, since the first space will
+ // have already been appended to lastFourChars and will have broken
+ // any <!-- or --> sequences
+ } else {
+ final chars = stream.charsUntil('&<\u0000');
+ _addToken(CharactersToken('$data$chars'));
+ }
+ return true;
+ }
+
+ bool entityDataState() {
+ consumeEntity();
+ state = dataState;
+ return true;
+ }
+
+ bool rcdataState() {
+ final data = stream.char();
+ if (data == '&') {
+ state = characterReferenceInRcdata;
+ } else if (data == '<') {
+ state = rcdataLessThanSignState;
+ } else if (data == eof) {
+ // Tokenization ends.
+ return false;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ } else if (isWhitespace(data)) {
+ // Directly after emitting a token you switch back to the "data
+ // state". At that point spaceCharacters are important so they are
+ // emitted separately.
+ _addToken(SpaceCharactersToken(
+ '$data${stream.charsUntil(spaceCharacters, true)}'));
+ } else {
+ final chars = stream.charsUntil('&<');
+ _addToken(CharactersToken('$data$chars'));
+ }
+ return true;
+ }
+
+ bool characterReferenceInRcdata() {
+ consumeEntity();
+ state = rcdataState;
+ return true;
+ }
+
+ bool rawtextState() {
+ final data = stream.char();
+ if (data == '<') {
+ state = rawtextLessThanSignState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ } else if (data == eof) {
+ // Tokenization ends.
+ return false;
+ } else {
+ final chars = stream.charsUntil('<\u0000');
+ _addToken(CharactersToken('$data$chars'));
+ }
+ return true;
+ }
+
+ bool scriptDataState() {
+ final data = stream.char();
+ if (data == '<') {
+ state = scriptDataLessThanSignState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ } else if (data == eof) {
+ // Tokenization ends.
+ return false;
+ } else {
+ final chars = stream.charsUntil('<\u0000');
+ _addToken(CharactersToken('$data$chars'));
+ }
+ return true;
+ }
+
+ bool plaintextState() {
+ final data = stream.char();
+ if (data == eof) {
+ // Tokenization ends.
+ return false;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ } else {
+ _addToken(CharactersToken('$data${stream.charsUntil("\u0000")}'));
+ }
+ return true;
+ }
+
+ bool tagOpenState() {
+ final data = stream.char();
+ if (data == '!') {
+ state = markupDeclarationOpenState;
+ } else if (data == '/') {
+ state = closeTagOpenState;
+ } else if (isLetter(data)) {
+ currentToken = StartTagToken(data);
+ state = tagNameState;
+ } else if (data == '>') {
+ // XXX In theory it could be something besides a tag name. But
+ // do we really care?
+ _addToken(ParseErrorToken('expected-tag-name-but-got-right-bracket'));
+ _addToken(CharactersToken('<>'));
+ state = dataState;
+ } else if (data == '?') {
+ // XXX In theory it could be something besides a tag name. But
+ // do we really care?
+ _addToken(ParseErrorToken('expected-tag-name-but-got-question-mark'));
+ stream.unget(data);
+ state = bogusCommentState;
+ } else {
+ // XXX
+ _addToken(ParseErrorToken('expected-tag-name'));
+ _addToken(CharactersToken('<'));
+ stream.unget(data);
+ state = dataState;
+ }
+ return true;
+ }
+
+ bool closeTagOpenState() {
+ final data = stream.char();
+ if (isLetter(data)) {
+ currentToken = EndTagToken(data);
+ state = tagNameState;
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('expected-closing-tag-but-got-right-bracket'));
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('expected-closing-tag-but-got-eof'));
+ _addToken(CharactersToken('</'));
+ state = dataState;
+ } else {
+ // XXX data can be _'_...
+ _addToken(ParseErrorToken('expected-closing-tag-but-got-char',
+ messageParams: {'data': data}));
+ stream.unget(data);
+ state = bogusCommentState;
+ }
+ return true;
+ }
+
+ bool tagNameState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ state = beforeAttributeNameState;
+ } else if (data == '>') {
+ emitCurrentToken();
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-tag-name'));
+ state = dataState;
+ } else if (data == '/') {
+ state = selfClosingStartTagState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentTagToken.name = '${currentTagToken.name}\uFFFD';
+ } else {
+ currentTagToken.name = '${currentTagToken.name}$data';
+ // (Don't use charsUntil here, because tag names are
+ // very short and it's faster to not do anything fancy)
+ }
+ return true;
+ }
+
+ bool rcdataLessThanSignState() {
+ final data = stream.char();
+ if (data == '/') {
+ _buffer.clear();
+ state = rcdataEndTagOpenState;
+ } else {
+ _addToken(CharactersToken('<'));
+ stream.unget(data);
+ state = rcdataState;
+ }
+ return true;
+ }
+
+ bool rcdataEndTagOpenState() {
+ final data = stream.char();
+ if (isLetter(data)) {
+ _buffer.write(data);
+ state = rcdataEndTagNameState;
+ } else {
+ _addToken(CharactersToken('</'));
+ stream.unget(data);
+ state = rcdataState;
+ }
+ return true;
+ }
+
+ bool _tokenIsAppropriate() {
+ // TODO(jmesserly): this should use case insensitive compare instead.
+ return currentToken is TagToken &&
+ currentTagToken.name!.toLowerCase() == '$_buffer'.toLowerCase();
+ }
+
+ bool rcdataEndTagNameState() {
+ final appropriate = _tokenIsAppropriate();
+ final data = stream.char();
+ if (isWhitespace(data) && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ state = beforeAttributeNameState;
+ } else if (data == '/' && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ state = selfClosingStartTagState;
+ } else if (data == '>' && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ emitCurrentToken();
+ state = dataState;
+ } else if (isLetter(data)) {
+ _buffer.write(data);
+ } else {
+ _addToken(CharactersToken('</$_buffer'));
+ stream.unget(data);
+ state = rcdataState;
+ }
+ return true;
+ }
+
+ bool rawtextLessThanSignState() {
+ final data = stream.char();
+ if (data == '/') {
+ _buffer.clear();
+ state = rawtextEndTagOpenState;
+ } else {
+ _addToken(CharactersToken('<'));
+ stream.unget(data);
+ state = rawtextState;
+ }
+ return true;
+ }
+
+ bool rawtextEndTagOpenState() {
+ final data = stream.char();
+ if (isLetter(data)) {
+ _buffer.write(data);
+ state = rawtextEndTagNameState;
+ } else {
+ _addToken(CharactersToken('</'));
+ stream.unget(data);
+ state = rawtextState;
+ }
+ return true;
+ }
+
+ bool rawtextEndTagNameState() {
+ final appropriate = _tokenIsAppropriate();
+ final data = stream.char();
+ if (isWhitespace(data) && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ state = beforeAttributeNameState;
+ } else if (data == '/' && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ state = selfClosingStartTagState;
+ } else if (data == '>' && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ emitCurrentToken();
+ state = dataState;
+ } else if (isLetter(data)) {
+ _buffer.write(data);
+ } else {
+ _addToken(CharactersToken('</$_buffer'));
+ stream.unget(data);
+ state = rawtextState;
+ }
+ return true;
+ }
+
+ bool scriptDataLessThanSignState() {
+ final data = stream.char();
+ if (data == '/') {
+ _buffer.clear();
+ state = scriptDataEndTagOpenState;
+ } else if (data == '!') {
+ _addToken(CharactersToken('<!'));
+ state = scriptDataEscapeStartState;
+ } else {
+ _addToken(CharactersToken('<'));
+ stream.unget(data);
+ state = scriptDataState;
+ }
+ return true;
+ }
+
+ bool scriptDataEndTagOpenState() {
+ final data = stream.char();
+ if (isLetter(data)) {
+ _buffer.write(data);
+ state = scriptDataEndTagNameState;
+ } else {
+ _addToken(CharactersToken('</'));
+ stream.unget(data);
+ state = scriptDataState;
+ }
+ return true;
+ }
+
+ bool scriptDataEndTagNameState() {
+ final appropriate = _tokenIsAppropriate();
+ final data = stream.char();
+ if (isWhitespace(data) && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ state = beforeAttributeNameState;
+ } else if (data == '/' && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ state = selfClosingStartTagState;
+ } else if (data == '>' && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ emitCurrentToken();
+ state = dataState;
+ } else if (isLetter(data)) {
+ _buffer.write(data);
+ } else {
+ _addToken(CharactersToken('</$_buffer'));
+ stream.unget(data);
+ state = scriptDataState;
+ }
+ return true;
+ }
+
+ bool scriptDataEscapeStartState() {
+ final data = stream.char();
+ if (data == '-') {
+ _addToken(CharactersToken('-'));
+ state = scriptDataEscapeStartDashState;
+ } else {
+ stream.unget(data);
+ state = scriptDataState;
+ }
+ return true;
+ }
+
+ bool scriptDataEscapeStartDashState() {
+ final data = stream.char();
+ if (data == '-') {
+ _addToken(CharactersToken('-'));
+ state = scriptDataEscapedDashDashState;
+ } else {
+ stream.unget(data);
+ state = scriptDataState;
+ }
+ return true;
+ }
+
+ bool scriptDataEscapedState() {
+ final data = stream.char();
+ if (data == '-') {
+ _addToken(CharactersToken('-'));
+ state = scriptDataEscapedDashState;
+ } else if (data == '<') {
+ state = scriptDataEscapedLessThanSignState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ } else if (data == eof) {
+ state = dataState;
+ } else {
+ final chars = stream.charsUntil('<-\u0000');
+ _addToken(CharactersToken('$data$chars'));
+ }
+ return true;
+ }
+
+ bool scriptDataEscapedDashState() {
+ final data = stream.char();
+ if (data == '-') {
+ _addToken(CharactersToken('-'));
+ state = scriptDataEscapedDashDashState;
+ } else if (data == '<') {
+ state = scriptDataEscapedLessThanSignState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ state = scriptDataEscapedState;
+ } else if (data == eof) {
+ state = dataState;
+ } else {
+ _addToken(CharactersToken(data));
+ state = scriptDataEscapedState;
+ }
+ return true;
+ }
+
+ bool scriptDataEscapedDashDashState() {
+ final data = stream.char();
+ if (data == '-') {
+ _addToken(CharactersToken('-'));
+ } else if (data == '<') {
+ state = scriptDataEscapedLessThanSignState;
+ } else if (data == '>') {
+ _addToken(CharactersToken('>'));
+ state = scriptDataState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ state = scriptDataEscapedState;
+ } else if (data == eof) {
+ state = dataState;
+ } else {
+ _addToken(CharactersToken(data));
+ state = scriptDataEscapedState;
+ }
+ return true;
+ }
+
+ bool scriptDataEscapedLessThanSignState() {
+ final data = stream.char();
+ if (data == '/') {
+ _buffer.clear();
+ state = scriptDataEscapedEndTagOpenState;
+ } else if (isLetter(data)) {
+ _addToken(CharactersToken('<$data'));
+ _buffer.clear();
+ _buffer.write(data);
+ state = scriptDataDoubleEscapeStartState;
+ } else {
+ _addToken(CharactersToken('<'));
+ stream.unget(data);
+ state = scriptDataEscapedState;
+ }
+ return true;
+ }
+
+ bool scriptDataEscapedEndTagOpenState() {
+ final data = stream.char();
+ if (isLetter(data)) {
+ _buffer.clear();
+ _buffer.write(data);
+ state = scriptDataEscapedEndTagNameState;
+ } else {
+ _addToken(CharactersToken('</'));
+ stream.unget(data);
+ state = scriptDataEscapedState;
+ }
+ return true;
+ }
+
+ bool scriptDataEscapedEndTagNameState() {
+ final appropriate = _tokenIsAppropriate();
+ final data = stream.char();
+ if (isWhitespace(data) && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ state = beforeAttributeNameState;
+ } else if (data == '/' && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ state = selfClosingStartTagState;
+ } else if (data == '>' && appropriate) {
+ currentToken = EndTagToken('$_buffer');
+ emitCurrentToken();
+ state = dataState;
+ } else if (isLetter(data)) {
+ _buffer.write(data);
+ } else {
+ _addToken(CharactersToken('</$_buffer'));
+ stream.unget(data);
+ state = scriptDataEscapedState;
+ }
+ return true;
+ }
+
+ bool scriptDataDoubleEscapeStartState() {
+ final data = stream.char();
+ if (isWhitespace(data) || data == '/' || data == '>') {
+ _addToken(CharactersToken(data));
+ if ('$_buffer'.toLowerCase() == 'script') {
+ state = scriptDataDoubleEscapedState;
+ } else {
+ state = scriptDataEscapedState;
+ }
+ } else if (isLetter(data)) {
+ _addToken(CharactersToken(data));
+ _buffer.write(data);
+ } else {
+ stream.unget(data);
+ state = scriptDataEscapedState;
+ }
+ return true;
+ }
+
+ bool scriptDataDoubleEscapedState() {
+ final data = stream.char();
+ if (data == '-') {
+ _addToken(CharactersToken('-'));
+ state = scriptDataDoubleEscapedDashState;
+ } else if (data == '<') {
+ _addToken(CharactersToken('<'));
+ state = scriptDataDoubleEscapedLessThanSignState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-script-in-script'));
+ state = dataState;
+ } else {
+ _addToken(CharactersToken(data));
+ }
+ return true;
+ }
+
+ bool scriptDataDoubleEscapedDashState() {
+ final data = stream.char();
+ if (data == '-') {
+ _addToken(CharactersToken('-'));
+ state = scriptDataDoubleEscapedDashDashState;
+ } else if (data == '<') {
+ _addToken(CharactersToken('<'));
+ state = scriptDataDoubleEscapedLessThanSignState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ state = scriptDataDoubleEscapedState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-script-in-script'));
+ state = dataState;
+ } else {
+ _addToken(CharactersToken(data));
+ state = scriptDataDoubleEscapedState;
+ }
+ return true;
+ }
+
+ // TODO(jmesserly): report bug in original code
+ // (was "Dash" instead of "DashDash")
+ bool scriptDataDoubleEscapedDashDashState() {
+ final data = stream.char();
+ if (data == '-') {
+ _addToken(CharactersToken('-'));
+ } else if (data == '<') {
+ _addToken(CharactersToken('<'));
+ state = scriptDataDoubleEscapedLessThanSignState;
+ } else if (data == '>') {
+ _addToken(CharactersToken('>'));
+ state = scriptDataState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addToken(CharactersToken('\uFFFD'));
+ state = scriptDataDoubleEscapedState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-script-in-script'));
+ state = dataState;
+ } else {
+ _addToken(CharactersToken(data));
+ state = scriptDataDoubleEscapedState;
+ }
+ return true;
+ }
+
+ bool scriptDataDoubleEscapedLessThanSignState() {
+ final data = stream.char();
+ if (data == '/') {
+ _addToken(CharactersToken('/'));
+ _buffer.clear();
+ state = scriptDataDoubleEscapeEndState;
+ } else {
+ stream.unget(data);
+ state = scriptDataDoubleEscapedState;
+ }
+ return true;
+ }
+
+ bool scriptDataDoubleEscapeEndState() {
+ final data = stream.char();
+ if (isWhitespace(data) || data == '/' || data == '>') {
+ _addToken(CharactersToken(data));
+ if ('$_buffer'.toLowerCase() == 'script') {
+ state = scriptDataEscapedState;
+ } else {
+ state = scriptDataDoubleEscapedState;
+ }
+ } else if (isLetter(data)) {
+ _addToken(CharactersToken(data));
+ _buffer.write(data);
+ } else {
+ stream.unget(data);
+ state = scriptDataDoubleEscapedState;
+ }
+ return true;
+ }
+
+ bool beforeAttributeNameState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ stream.charsUntil(spaceCharacters, true);
+ } else if (data != null && isLetter(data)) {
+ _addAttribute(data);
+ state = attributeNameState;
+ } else if (data == '>') {
+ emitCurrentToken();
+ } else if (data == '/') {
+ state = selfClosingStartTagState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('expected-attribute-name-but-got-eof'));
+ state = dataState;
+ } else if ("'\"=<".contains(data!)) {
+ _addToken(ParseErrorToken('invalid-character-in-attribute-name'));
+ _addAttribute(data);
+ state = attributeNameState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addAttribute('\uFFFD');
+ state = attributeNameState;
+ } else {
+ _addAttribute(data);
+ state = attributeNameState;
+ }
+ return true;
+ }
+
+ bool attributeNameState() {
+ final data = stream.char();
+ var leavingThisState = true;
+ var emitToken = false;
+ if (data == '=') {
+ state = beforeAttributeValueState;
+ } else if (isLetter(data)) {
+ _attributeName.write(data);
+ _attributeName.write(stream.charsUntil(asciiLetters, true));
+ leavingThisState = false;
+ } else if (data == '>') {
+ // XXX If we emit here the attributes are converted to a dict
+ // without being checked and when the code below runs we error
+ // because data is a dict not a list
+ emitToken = true;
+ } else if (isWhitespace(data)) {
+ state = afterAttributeNameState;
+ } else if (data == '/') {
+ state = selfClosingStartTagState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _attributeName.write('\uFFFD');
+ leavingThisState = false;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-attribute-name'));
+ state = dataState;
+ } else if ("'\"<".contains(data!)) {
+ _addToken(ParseErrorToken('invalid-character-in-attribute-name'));
+ _attributeName.write(data);
+ leavingThisState = false;
+ } else {
+ _attributeName.write(data);
+ leavingThisState = false;
+ }
+
+ if (leavingThisState) {
+ _markAttributeNameEnd(-1);
+
+ // Attributes are not dropped at this stage. That happens when the
+ // start tag token is emitted so values can still be safely appended
+ // to attributes, but we do want to report the parse error in time.
+ var attrName = _attributeName.toString();
+ if (lowercaseAttrName) {
+ attrName = attrName.toAsciiLowerCase();
+ }
+ _attributes!.last.name = attrName;
+ _attributeNames ??= {};
+ if (_attributeNames!.contains(attrName)) {
+ _addToken(ParseErrorToken('duplicate-attribute'));
+ }
+ _attributeNames!.add(attrName);
+
+ // XXX Fix for above XXX
+ if (emitToken) {
+ emitCurrentToken();
+ }
+ }
+ return true;
+ }
+
+ bool afterAttributeNameState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ stream.charsUntil(spaceCharacters, true);
+ } else if (data == '=') {
+ state = beforeAttributeValueState;
+ } else if (data == '>') {
+ emitCurrentToken();
+ } else if (data != null && isLetter(data)) {
+ _addAttribute(data);
+ state = attributeNameState;
+ } else if (data == '/') {
+ state = selfClosingStartTagState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _addAttribute('\uFFFD');
+ state = attributeNameState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('expected-end-of-tag-but-got-eof'));
+ state = dataState;
+ } else if ("'\"<".contains(data!)) {
+ _addToken(ParseErrorToken('invalid-character-after-attribute-name'));
+ _addAttribute(data);
+ state = attributeNameState;
+ } else {
+ _addAttribute(data);
+ state = attributeNameState;
+ }
+ return true;
+ }
+
+ bool beforeAttributeValueState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ stream.charsUntil(spaceCharacters, true);
+ } else if (data == '"') {
+ _markAttributeValueStart(0);
+ state = attributeValueDoubleQuotedState;
+ } else if (data == '&') {
+ state = attributeValueUnQuotedState;
+ stream.unget(data);
+ _markAttributeValueStart(0);
+ } else if (data == "'") {
+ _markAttributeValueStart(0);
+ state = attributeValueSingleQuotedState;
+ } else if (data == '>') {
+ _addToken(
+ ParseErrorToken('expected-attribute-value-but-got-right-bracket'));
+ emitCurrentToken();
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _markAttributeValueStart(-1);
+ _attributeValue.write('\uFFFD');
+ state = attributeValueUnQuotedState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('expected-attribute-value-but-got-eof'));
+ state = dataState;
+ } else if ('=<`'.contains(data!)) {
+ _addToken(ParseErrorToken('equals-in-unquoted-attribute-value'));
+ _markAttributeValueStart(-1);
+ _attributeValue.write(data);
+ state = attributeValueUnQuotedState;
+ } else {
+ _markAttributeValueStart(-1);
+ _attributeValue.write(data);
+ state = attributeValueUnQuotedState;
+ }
+ return true;
+ }
+
+ bool attributeValueDoubleQuotedState() {
+ final data = stream.char();
+ if (data == '"') {
+ _markAttributeValueEnd(-1);
+ _markAttributeEnd(0);
+ state = afterAttributeValueState;
+ } else if (data == '&') {
+ processEntityInAttribute('"');
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _attributeValue.write('\uFFFD');
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-attribute-value-double-quote'));
+ _markAttributeValueEnd(-1);
+ state = dataState;
+ } else {
+ _attributeValue.write(data);
+ _attributeValue.write(stream.charsUntil('"&'));
+ }
+ return true;
+ }
+
+ bool attributeValueSingleQuotedState() {
+ final data = stream.char();
+ if (data == "'") {
+ _markAttributeValueEnd(-1);
+ _markAttributeEnd(0);
+ state = afterAttributeValueState;
+ } else if (data == '&') {
+ processEntityInAttribute("'");
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _attributeValue.write('\uFFFD');
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-attribute-value-single-quote'));
+ _markAttributeValueEnd(-1);
+ state = dataState;
+ } else {
+ _attributeValue.write(data);
+ _attributeValue.write(stream.charsUntil("'&"));
+ }
+ return true;
+ }
+
+ bool attributeValueUnQuotedState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ _markAttributeValueEnd(-1);
+ state = beforeAttributeNameState;
+ } else if (data == '&') {
+ processEntityInAttribute('>');
+ } else if (data == '>') {
+ _markAttributeValueEnd(-1);
+ emitCurrentToken();
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-attribute-value-no-quotes'));
+ _markAttributeValueEnd(-1);
+ state = dataState;
+ } else if ('"\'=<`'.contains(data!)) {
+ _addToken(
+ ParseErrorToken('unexpected-character-in-unquoted-attribute-value'));
+ _attributeValue.write(data);
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ _attributeValue.write('\uFFFD');
+ } else {
+ _attributeValue.write(data);
+ _attributeValue.write(stream.charsUntil("&>\"'=<`$spaceCharacters"));
+ }
+ return true;
+ }
+
+ bool afterAttributeValueState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ state = beforeAttributeNameState;
+ } else if (data == '>') {
+ emitCurrentToken();
+ } else if (data == '/') {
+ state = selfClosingStartTagState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('unexpected-EOF-after-attribute-value'));
+ stream.unget(data);
+ state = dataState;
+ } else {
+ _addToken(ParseErrorToken('unexpected-character-after-attribute-value'));
+ stream.unget(data);
+ state = beforeAttributeNameState;
+ }
+ return true;
+ }
+
+ bool selfClosingStartTagState() {
+ final data = stream.char();
+ if (data == '>') {
+ currentTagToken.selfClosing = true;
+ emitCurrentToken();
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('unexpected-EOF-after-solidus-in-tag'));
+ stream.unget(data);
+ state = dataState;
+ } else {
+ _addToken(ParseErrorToken('unexpected-character-after-soldius-in-tag'));
+ stream.unget(data);
+ state = beforeAttributeNameState;
+ }
+ return true;
+ }
+
+ bool bogusCommentState() {
+ // Make a new comment token and give it as value all the characters
+ // until the first > or EOF (charsUntil checks for EOF automatically)
+ // and emit it.
+ var data = stream.charsUntil('>');
+ data = data.replaceAll('\u0000', '\uFFFD');
+ _addToken(CommentToken(data));
+
+ // Eat the character directly after the bogus comment which is either a
+ // ">" or an EOF.
+ stream.char();
+ state = dataState;
+ return true;
+ }
+
+ bool markupDeclarationOpenState() {
+ final charStack = [stream.char()];
+ if (charStack.last == '-') {
+ charStack.add(stream.char());
+ if (charStack.last == '-') {
+ currentToken = CommentToken();
+ state = commentStartState;
+ return true;
+ }
+ } else if (charStack.last == 'd' || charStack.last == 'D') {
+ var matched = true;
+ for (var expected in const ['oO', 'cC', 'tT', 'yY', 'pP', 'eE']) {
+ final char = stream.char();
+ charStack.add(char);
+ if (char == eof || !expected.contains(char!)) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ currentToken = DoctypeToken(correct: true);
+ state = doctypeState;
+ return true;
+ }
+ } else if (charStack.last == '[' &&
+ parser != null &&
+ parser!.tree.openElements.isNotEmpty &&
+ parser!.tree.openElements.last.namespaceUri !=
+ parser!.tree.defaultNamespace) {
+ var matched = true;
+ for (var expected in const ['C', 'D', 'A', 'T', 'A', '[']) {
+ charStack.add(stream.char());
+ if (charStack.last != expected) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ state = cdataSectionState;
+ return true;
+ }
+ }
+
+ _addToken(ParseErrorToken('expected-dashes-or-doctype'));
+
+ while (charStack.isNotEmpty) {
+ stream.unget(charStack.removeLast());
+ }
+ state = bogusCommentState;
+ return true;
+ }
+
+ bool commentStartState() {
+ final data = stream.char();
+ if (data == '-') {
+ state = commentStartDashState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentStringToken.add('\uFFFD');
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('incorrect-comment'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-comment'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentStringToken.add(data!);
+ state = commentState;
+ }
+ return true;
+ }
+
+ bool commentStartDashState() {
+ final data = stream.char();
+ if (data == '-') {
+ state = commentEndState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentStringToken.add('-\uFFFD');
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('incorrect-comment'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-comment'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentStringToken.add('-').add(data!);
+ state = commentState;
+ }
+ return true;
+ }
+
+ bool commentState() {
+ final data = stream.char();
+ if (data == '-') {
+ state = commentEndDashState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentStringToken.add('\uFFFD');
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-comment'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentStringToken.add(data!).add(stream.charsUntil('-\u0000'));
+ }
+ return true;
+ }
+
+ bool commentEndDashState() {
+ final data = stream.char();
+ if (data == '-') {
+ state = commentEndState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentStringToken.add('-\uFFFD');
+ state = commentState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-comment-end-dash'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentStringToken.add('-').add(data!);
+ state = commentState;
+ }
+ return true;
+ }
+
+ bool commentEndState() {
+ final data = stream.char();
+ if (data == '>') {
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentStringToken.add('--\uFFFD');
+ state = commentState;
+ } else if (data == '!') {
+ _addToken(
+ ParseErrorToken('unexpected-bang-after-double-dash-in-comment'));
+ state = commentEndBangState;
+ } else if (data == '-') {
+ _addToken(
+ ParseErrorToken('unexpected-dash-after-double-dash-in-comment'));
+ currentStringToken.add(data!);
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-comment-double-dash'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ // XXX
+ _addToken(ParseErrorToken('unexpected-char-in-comment'));
+ currentStringToken.add('--').add(data!);
+ state = commentState;
+ }
+ return true;
+ }
+
+ bool commentEndBangState() {
+ final data = stream.char();
+ if (data == '>') {
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == '-') {
+ currentStringToken.add('--!');
+ state = commentEndDashState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentStringToken.add('--!\uFFFD');
+ state = commentState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-comment-end-bang-state'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentStringToken.add('--!').add(data!);
+ state = commentState;
+ }
+ return true;
+ }
+
+ bool doctypeState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ state = beforeDoctypeNameState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('expected-doctype-name-but-got-eof'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ _addToken(ParseErrorToken('need-space-after-doctype'));
+ stream.unget(data);
+ state = beforeDoctypeNameState;
+ }
+ return true;
+ }
+
+ bool beforeDoctypeNameState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ return true;
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('expected-doctype-name-but-got-right-bracket'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentDoctypeToken.name = '\uFFFD';
+ state = doctypeNameState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('expected-doctype-name-but-got-eof'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentDoctypeToken.name = data;
+ state = doctypeNameState;
+ }
+ return true;
+ }
+
+ bool doctypeNameState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ currentDoctypeToken.name = currentDoctypeToken.name?.toAsciiLowerCase();
+ state = afterDoctypeNameState;
+ } else if (data == '>') {
+ currentDoctypeToken.name = currentDoctypeToken.name?.toAsciiLowerCase();
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentDoctypeToken.name = '${currentDoctypeToken.name}\uFFFD';
+ state = doctypeNameState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype-name'));
+ currentDoctypeToken.correct = false;
+ currentDoctypeToken.name = currentDoctypeToken.name?.toAsciiLowerCase();
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentDoctypeToken.name = '${currentDoctypeToken.name}$data';
+ }
+ return true;
+ }
+
+ bool afterDoctypeNameState() {
+ var data = stream.char();
+ if (isWhitespace(data)) {
+ return true;
+ } else if (data == '>') {
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ currentDoctypeToken.correct = false;
+ stream.unget(data);
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ if (data == 'p' || data == 'P') {
+ // TODO(jmesserly): would be nice to have a helper for this.
+ var matched = true;
+ for (var expected in const ['uU', 'bB', 'lL', 'iI', 'cC']) {
+ data = stream.char();
+ if (data == eof || !expected.contains(data!)) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ state = afterDoctypePublicKeywordState;
+ return true;
+ }
+ } else if (data == 's' || data == 'S') {
+ var matched = true;
+ for (var expected in const ['yY', 'sS', 'tT', 'eE', 'mM']) {
+ data = stream.char();
+ if (data == eof || !expected.contains(data!)) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ state = afterDoctypeSystemKeywordState;
+ return true;
+ }
+ }
+
+ // All the characters read before the current 'data' will be
+ // [a-zA-Z], so they're garbage in the bogus doctype and can be
+ // discarded; only the latest character might be '>' or EOF
+ // and needs to be ungetted
+ stream.unget(data);
+ _addToken(ParseErrorToken('expected-space-or-right-bracket-in-doctype',
+ messageParams: {'data': data}));
+ currentDoctypeToken.correct = false;
+ state = bogusDoctypeState;
+ }
+ return true;
+ }
+
+ bool afterDoctypePublicKeywordState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ state = beforeDoctypePublicIdentifierState;
+ } else if (data == "'" || data == '"') {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ stream.unget(data);
+ state = beforeDoctypePublicIdentifierState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ stream.unget(data);
+ state = beforeDoctypePublicIdentifierState;
+ }
+ return true;
+ }
+
+ bool beforeDoctypePublicIdentifierState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ return true;
+ } else if (data == '"') {
+ currentDoctypeToken.publicId = '';
+ state = doctypePublicIdentifierDoubleQuotedState;
+ } else if (data == "'") {
+ currentDoctypeToken.publicId = '';
+ state = doctypePublicIdentifierSingleQuotedState;
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ currentDoctypeToken.correct = false;
+ state = bogusDoctypeState;
+ }
+ return true;
+ }
+
+ bool doctypePublicIdentifierDoubleQuotedState() {
+ final data = stream.char();
+ if (data == '"') {
+ state = afterDoctypePublicIdentifierState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentDoctypeToken.publicId = '${currentDoctypeToken.publicId}\uFFFD';
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentDoctypeToken.publicId = '${currentDoctypeToken.publicId}$data';
+ }
+ return true;
+ }
+
+ bool doctypePublicIdentifierSingleQuotedState() {
+ final data = stream.char();
+ if (data == "'") {
+ state = afterDoctypePublicIdentifierState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentDoctypeToken.publicId = '${currentDoctypeToken.publicId}\uFFFD';
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentDoctypeToken.publicId = '${currentDoctypeToken.publicId}$data';
+ }
+ return true;
+ }
+
+ bool afterDoctypePublicIdentifierState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ state = betweenDoctypePublicAndSystemIdentifiersState;
+ } else if (data == '>') {
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == '"') {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ currentDoctypeToken.systemId = '';
+ state = doctypeSystemIdentifierDoubleQuotedState;
+ } else if (data == "'") {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ currentDoctypeToken.systemId = '';
+ state = doctypeSystemIdentifierSingleQuotedState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ currentDoctypeToken.correct = false;
+ state = bogusDoctypeState;
+ }
+ return true;
+ }
+
+ bool betweenDoctypePublicAndSystemIdentifiersState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ return true;
+ } else if (data == '>') {
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == '"') {
+ currentDoctypeToken.systemId = '';
+ state = doctypeSystemIdentifierDoubleQuotedState;
+ } else if (data == "'") {
+ currentDoctypeToken.systemId = '';
+ state = doctypeSystemIdentifierSingleQuotedState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ currentDoctypeToken.correct = false;
+ state = bogusDoctypeState;
+ }
+ return true;
+ }
+
+ bool afterDoctypeSystemKeywordState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ state = beforeDoctypeSystemIdentifierState;
+ } else if (data == "'" || data == '"') {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ stream.unget(data);
+ state = beforeDoctypeSystemIdentifierState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ stream.unget(data);
+ state = beforeDoctypeSystemIdentifierState;
+ }
+ return true;
+ }
+
+ bool beforeDoctypeSystemIdentifierState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ return true;
+ } else if (data == '"') {
+ currentDoctypeToken.systemId = '';
+ state = doctypeSystemIdentifierDoubleQuotedState;
+ } else if (data == "'") {
+ currentDoctypeToken.systemId = '';
+ state = doctypeSystemIdentifierSingleQuotedState;
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ currentDoctypeToken.correct = false;
+ state = bogusDoctypeState;
+ }
+ return true;
+ }
+
+ bool doctypeSystemIdentifierDoubleQuotedState() {
+ final data = stream.char();
+ if (data == '"') {
+ state = afterDoctypeSystemIdentifierState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentDoctypeToken.systemId = '${currentDoctypeToken.systemId}\uFFFD';
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentDoctypeToken.systemId = '${currentDoctypeToken.systemId}$data';
+ }
+ return true;
+ }
+
+ bool doctypeSystemIdentifierSingleQuotedState() {
+ final data = stream.char();
+ if (data == "'") {
+ state = afterDoctypeSystemIdentifierState;
+ } else if (data == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ currentDoctypeToken.systemId = '${currentDoctypeToken.systemId}\uFFFD';
+ } else if (data == '>') {
+ _addToken(ParseErrorToken('unexpected-end-of-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ currentDoctypeToken.systemId = '${currentDoctypeToken.systemId}$data';
+ }
+ return true;
+ }
+
+ bool afterDoctypeSystemIdentifierState() {
+ final data = stream.char();
+ if (isWhitespace(data)) {
+ return true;
+ } else if (data == '>') {
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ _addToken(ParseErrorToken('eof-in-doctype'));
+ currentDoctypeToken.correct = false;
+ _addToken(currentToken!);
+ state = dataState;
+ } else {
+ _addToken(ParseErrorToken('unexpected-char-in-doctype'));
+ state = bogusDoctypeState;
+ }
+ return true;
+ }
+
+ bool bogusDoctypeState() {
+ final data = stream.char();
+ if (data == '>') {
+ _addToken(currentToken!);
+ state = dataState;
+ } else if (data == eof) {
+ // XXX EMIT
+ stream.unget(data);
+ _addToken(currentToken!);
+ state = dataState;
+ }
+ return true;
+ }
+
+ bool cdataSectionState() {
+ final data = <String>[];
+ var matchedEnd = 0;
+ while (true) {
+ var ch = stream.char();
+ if (ch == null) {
+ break;
+ }
+ // Deal with null here rather than in the parser
+ if (ch == '\u0000') {
+ _addToken(ParseErrorToken('invalid-codepoint'));
+ ch = '\uFFFD';
+ }
+ data.add(ch);
+ // TODO(jmesserly): it'd be nice if we had an easier way to match the end,
+ // perhaps with a "peek" API.
+ if (ch == ']' && matchedEnd < 2) {
+ matchedEnd++;
+ } else if (ch == '>' && matchedEnd == 2) {
+ // Remove "]]>" from the end.
+ data.removeLast();
+ data.removeLast();
+ data.removeLast();
+ break;
+ } else {
+ matchedEnd = 0;
+ }
+ }
+
+ if (data.isNotEmpty) {
+ _addToken(CharactersToken(data.join()));
+ }
+ state = dataState;
+ return true;
+ }
+}
diff --git a/pkgs/html/lib/src/treebuilder.dart b/pkgs/html/lib/src/treebuilder.dart
new file mode 100644
index 0000000..781f3f6
--- /dev/null
+++ b/pkgs/html/lib/src/treebuilder.dart
@@ -0,0 +1,400 @@
+/// Internals to the tree builders.
+library;
+
+import 'dart:collection';
+
+import 'package:source_span/source_span.dart';
+
+import '../dom.dart';
+import '../parser.dart' show getElementNameTuple;
+import 'constants.dart';
+import 'list_proxy.dart';
+import 'token.dart';
+
+/// Open elements in the formatting category, most recent element last.
+///
+/// `null` is used as the "marker" entry to prevent style from leaking when
+/// entering some elements.
+///
+/// https://html.spec.whatwg.org/multipage/parsing.html#list-of-active-formatting-elements
+class ActiveFormattingElements extends ListProxy<Element?> {
+ /// Push an element into the active formatting elements.
+ ///
+ /// Prevents equivalent elements from appearing more than 3 times following
+ /// the last `null` marker. If adding [node] would cause there to be more than
+ /// 3 equivalent elements the earliest identical element is removed.
+ // TODO - Earliest equivalent following a marker, as opposed to earliest
+ // identical regardless of marker position, should be removed.
+ @override
+ void add(Element? node) {
+ var equalCount = 0;
+ if (node != null) {
+ for (var element in reversed) {
+ if (element == null) {
+ break;
+ }
+ if (_nodesEqual(element, node)) {
+ equalCount += 1;
+ }
+ if (equalCount == 3) {
+ // TODO - https://github.com/dart-lang/html/issues/135
+ remove(element);
+ break;
+ }
+ }
+ }
+ super.add(node);
+ }
+}
+
+// TODO(jmesserly): this should exist in corelib...
+bool _mapEquals(Map<Object, String> a, Map<Object, String> b) {
+ if (a.length != b.length) return false;
+ if (a.isEmpty) return true;
+
+ for (var keyA in a.keys) {
+ final valB = b[keyA];
+ if (valB == null && !b.containsKey(keyA)) {
+ return false;
+ }
+
+ if (a[keyA] != valB) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool _nodesEqual(Element node1, Element node2) {
+ return getElementNameTuple(node1) == getElementNameTuple(node2) &&
+ _mapEquals(node1.attributes, node2.attributes);
+}
+
+/// Basic treebuilder implementation.
+class TreeBuilder {
+ final String? defaultNamespace;
+
+ late Document document;
+
+ final List<Element> openElements = <Element>[];
+
+ final activeFormattingElements = ActiveFormattingElements();
+
+ Node? headPointer;
+
+ Element? formPointer;
+
+ /// Switch the function used to insert an element from the
+ /// normal one to the misnested table one and back again
+ bool insertFromTable = false;
+
+ TreeBuilder(bool namespaceHTMLElements)
+ : defaultNamespace = namespaceHTMLElements ? Namespaces.html : null {
+ reset();
+ }
+
+ void reset() {
+ openElements.clear();
+ activeFormattingElements.clear();
+
+ //XXX - rename these to headElement, formElement
+ headPointer = null;
+ formPointer = null;
+
+ insertFromTable = false;
+
+ document = Document();
+ }
+
+ bool elementInScope(dynamic target, {String? variant}) {
+ // If we pass a node in we match that. If we pass a string match any node
+ // with that name.
+ final exactNode = target is Node;
+
+ var listElements1 = scopingElements;
+ var listElements2 = const <(String, String)>[];
+ var invert = false;
+ if (variant != null) {
+ switch (variant) {
+ case 'button':
+ listElements2 = const [(Namespaces.html, 'button')];
+ break;
+ case 'list':
+ listElements2 = const [
+ (Namespaces.html, 'ol'),
+ (Namespaces.html, 'ul')
+ ];
+ break;
+ case 'table':
+ listElements1 = const [
+ (Namespaces.html, 'html'),
+ (Namespaces.html, 'table')
+ ];
+ break;
+ case 'select':
+ listElements1 = const [
+ (Namespaces.html, 'optgroup'),
+ (Namespaces.html, 'option')
+ ];
+ invert = true;
+ break;
+ default:
+ throw StateError('We should never reach this point');
+ }
+ }
+
+ for (var node in openElements.reversed) {
+ if (!exactNode && node.localName == target ||
+ exactNode && node == target) {
+ return true;
+ } else if (invert !=
+ (listElements1.contains(getElementNameTuple(node)) ||
+ listElements2.contains(getElementNameTuple(node)))) {
+ return false;
+ }
+ }
+
+ throw StateError('We should never reach this point');
+ }
+
+ void reconstructActiveFormattingElements() {
+ // Within this algorithm the order of steps described in the
+ // specification is not quite the same as the order of steps in the
+ // code. It should still do the same though.
+
+ // Step 1: stop the algorithm when there's nothing to do.
+ if (activeFormattingElements.isEmpty) {
+ return;
+ }
+
+ // Step 2 and step 3: we start with the last element. So i is -1.
+ var i = activeFormattingElements.length - 1;
+ var entry = activeFormattingElements[i];
+ if (entry == null || openElements.contains(entry)) {
+ return;
+ }
+
+ // Step 6
+ while (entry != null && !openElements.contains(entry)) {
+ if (i == 0) {
+ //This will be reset to 0 below
+ i = -1;
+ break;
+ }
+ i -= 1;
+ // Step 5: let entry be one earlier in the list.
+ entry = activeFormattingElements[i];
+ }
+
+ while (true) {
+ // Step 7
+ i += 1;
+
+ // Step 8
+ entry = activeFormattingElements[i];
+
+ // TODO(jmesserly): optimize this. No need to create a token.
+ final cloneToken = StartTagToken(entry!.localName,
+ namespace: entry.namespaceUri,
+ data: LinkedHashMap.from(entry.attributes))
+ ..span = entry.sourceSpan;
+
+ // Step 9
+ final element = insertElement(cloneToken);
+
+ // Step 10
+ activeFormattingElements[i] = element;
+
+ // Step 11
+ if (element == activeFormattingElements.last) {
+ break;
+ }
+ }
+ }
+
+ void clearActiveFormattingElements() {
+ var entry = activeFormattingElements.removeLast();
+ while (activeFormattingElements.isNotEmpty && entry != null) {
+ entry = activeFormattingElements.removeLast();
+ }
+ }
+
+ /// Check if an element exists between the end of the active
+ /// formatting elements and the last marker. If it does, return it, else
+ /// return null.
+ Element? elementInActiveFormattingElements(String? name) {
+ for (var item in activeFormattingElements.reversed) {
+ // Check for Marker first because if it's a Marker it doesn't have a
+ // name attribute.
+ if (item == null) {
+ break;
+ } else if (item.localName == name) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ void insertRoot(StartTagToken token) {
+ final element = createElement(token);
+ openElements.add(element);
+ document.nodes.add(element);
+ }
+
+ void insertDoctype(DoctypeToken token) {
+ final doctype = DocumentType(token.name, token.publicId, token.systemId)
+ ..sourceSpan = token.span;
+ document.nodes.add(doctype);
+ }
+
+ void insertComment(StringToken token, [Node? parent]) {
+ parent ??= openElements.last;
+ parent.nodes.add(Comment(token.data)..sourceSpan = token.span);
+ }
+
+ /// Create an element but don't insert it anywhere
+ Element createElement(StartTagToken token) {
+ final name = token.name;
+ final namespace = token.namespace ?? defaultNamespace;
+ final element = document.createElementNS(namespace, name)
+ ..attributes = token.data
+ ..sourceSpan = token.span;
+ return element;
+ }
+
+ Element insertElement(StartTagToken token) {
+ if (insertFromTable) return insertElementTable(token);
+ return insertElementNormal(token);
+ }
+
+ Element insertElementNormal(StartTagToken token) {
+ final name = token.name;
+ final namespace = token.namespace ?? defaultNamespace;
+ final element = document.createElementNS(namespace, name)
+ ..attributes = token.data
+ ..sourceSpan = token.span;
+ openElements.last.nodes.add(element);
+ openElements.add(element);
+ return element;
+ }
+
+ Element insertElementTable(StartTagToken token) {
+ /// Create an element and insert it into the tree
+ final element = createElement(token);
+ if (!tableInsertModeElements.contains(openElements.last.localName)) {
+ return insertElementNormal(token);
+ } else {
+ // We should be in the InTable mode. This means we want to do
+ // special magic element rearranging
+ final nodePos = getTableMisnestedNodePosition();
+ if (nodePos[1] == null) {
+ // TODO(jmesserly): I don't think this is reachable. If insertFromTable
+ // is true, there will be a <table> element open, and it always has a
+ // parent pointer.
+ nodePos[0]!.nodes.add(element);
+ } else {
+ nodePos[0]!.insertBefore(element, nodePos[1]);
+ }
+ openElements.add(element);
+ }
+ return element;
+ }
+
+ /// Insert text data.
+ void insertText(String data, FileSpan? span) {
+ final parent = openElements.last;
+
+ if (!insertFromTable ||
+ insertFromTable &&
+ !tableInsertModeElements.contains(openElements.last.localName)) {
+ _insertText(parent, data, span);
+ } else {
+ // We should be in the InTable mode. This means we want to do
+ // special magic element rearranging
+ final nodePos = getTableMisnestedNodePosition();
+ _insertText(nodePos[0]!, data, span, nodePos[1] as Element?);
+ }
+ }
+
+ /// Insert [data] as text in the current node, positioned before the
+ /// start of node [refNode] or to the end of the node's text.
+ static void _insertText(Node parent, String data, FileSpan? span,
+ [Element? refNode]) {
+ final nodes = parent.nodes;
+ if (refNode == null) {
+ if (nodes.isNotEmpty && nodes.last is Text) {
+ final last = nodes.last as Text;
+ last.appendData(data);
+
+ if (span != null) {
+ last.sourceSpan =
+ span.file.span(last.sourceSpan!.start.offset, span.end.offset);
+ }
+ } else {
+ nodes.add(Text(data)..sourceSpan = span);
+ }
+ } else {
+ final index = nodes.indexOf(refNode);
+ if (index > 0 && nodes[index - 1] is Text) {
+ final last = nodes[index - 1] as Text;
+ last.appendData(data);
+ } else {
+ nodes.insert(index, Text(data)..sourceSpan = span);
+ }
+ }
+ }
+
+ /// Get the foster parent element, and sibling to insert before
+ /// (or null) when inserting a misnested table node
+ List<Node?> getTableMisnestedNodePosition() {
+ // The foster parent element is the one which comes before the most
+ // recently opened table element
+ // XXX - this is really inelegant
+ Element? lastTable;
+ Node? fosterParent;
+ Node? insertBefore;
+ for (var elm in openElements.reversed) {
+ if (elm.localName == 'table') {
+ lastTable = elm;
+ break;
+ }
+ }
+ if (lastTable != null) {
+ // XXX - we should really check that this parent is actually a
+ // node here
+ if (lastTable.parentNode != null) {
+ fosterParent = lastTable.parentNode;
+ insertBefore = lastTable;
+ } else {
+ fosterParent = openElements[openElements.indexOf(lastTable) - 1];
+ }
+ } else {
+ fosterParent = openElements[0];
+ }
+ return [fosterParent, insertBefore];
+ }
+
+ void generateImpliedEndTags([String? exclude]) {
+ final name = openElements.last.localName;
+ // XXX td, th and tr are not actually needed
+ if (name != exclude &&
+ const ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt']
+ .contains(name)) {
+ openElements.removeLast();
+ // XXX This is not entirely what the specification says. We should
+ // investigate it more closely.
+ generateImpliedEndTags(exclude);
+ }
+ }
+
+ /// Return the final tree.
+ Document getDocument() => document;
+
+ /// Return the final fragment.
+ DocumentFragment getFragment() {
+ //XXX assert innerHTML
+ final fragment = DocumentFragment();
+ openElements[0].reparentChildren(fragment);
+ return fragment;
+ }
+}
diff --git a/pkgs/html/lib/src/utils.dart b/pkgs/html/lib/src/utils.dart
new file mode 100644
index 0000000..4f4bd1a
--- /dev/null
+++ b/pkgs/html/lib/src/utils.dart
@@ -0,0 +1,85 @@
+import 'constants.dart';
+
+bool startsWithAny(String str, List<String> prefixes) =>
+ prefixes.any(str.startsWith);
+
+// Like the python [:] operator.
+List<T> slice<T>(List<T> list, int start, [int? end]) {
+ end ??= list.length;
+ if (end < 0) end += list.length;
+
+ // Ensure the indexes are in bounds.
+ if (end < start) end = start;
+ if (end > list.length) end = list.length;
+ return list.sublist(start, end);
+}
+
+bool allWhitespace(String str) {
+ for (var i = 0; i < str.length; i++) {
+ if (!isWhitespaceCC(str.codeUnitAt(i))) return false;
+ }
+ return true;
+}
+
+String padWithZeros(String str, int size) {
+ if (str.length == size) return str;
+ final result = StringBuffer();
+ size -= str.length;
+ for (var i = 0; i < size; i++) {
+ result.write('0');
+ }
+ result.write(str);
+ return result.toString();
+}
+
+// TODO(jmesserly): this implementation is pretty wrong, but I need something
+// quick until dartbug.com/1694 is fixed.
+/// Format a string like Python's % string format operator. Right now this only
+/// supports a [data] dictionary used with %s or %08x. Those were the only
+/// things needed for [errorMessages].
+String formatStr(String format, Map<String, Object?>? data) {
+ if (data == null) return format;
+ data.forEach((key, value) {
+ final result = StringBuffer();
+ final search = '%($key)';
+ int last = 0, match;
+ while ((match = format.indexOf(search, last)) >= 0) {
+ result.write(format.substring(last, match));
+ match += search.length;
+
+ var digits = match;
+ while (isDigit(format[digits])) {
+ digits++;
+ }
+ var numberSize = 0;
+ if (digits > match) {
+ numberSize = int.parse(format.substring(match, digits));
+ match = digits;
+ }
+
+ switch (format[match]) {
+ case 's':
+ result.write(value);
+ break;
+ case 'd':
+ final number = value.toString();
+ result.write(padWithZeros(number, numberSize));
+ break;
+ case 'x':
+ final number = (value as int).toRadixString(16);
+ result.write(padWithZeros(number, numberSize));
+ break;
+ default:
+ throw UnsupportedError('formatStr does not support format '
+ 'character ${format[match]}');
+ }
+
+ last = match + 1;
+ }
+
+ result.write(format.substring(last, format.length));
+ format = result.toString();
+ });
+
+ return format;
+}
diff --git a/pkgs/html/pubspec.yaml b/pkgs/html/pubspec.yaml
new file mode 100644
index 0000000..447b98e
--- /dev/null
+++ b/pkgs/html/pubspec.yaml
@@ -0,0 +1,21 @@
+name: html
+version: 0.15.5
+description: APIs for parsing and manipulating HTML content outside the browser.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/html
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ahtml
+
+topics:
+ - html
+ - web
+
+environment:
+ sdk: ^3.2.0
+
+dependencies:
+ csslib: ^1.0.0
+ source_span: ^1.8.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ path: ^1.8.0
+ test: ^1.16.6
diff --git a/pkgs/html/test/data/tokenizer/contentModelFlags.test b/pkgs/html/test/data/tokenizer/contentModelFlags.test
new file mode 100644
index 0000000..a8b1695
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/contentModelFlags.test
@@ -0,0 +1,75 @@
+{"tests": [
+
+{"description":"PLAINTEXT content model flag",
+"initialStates":["PLAINTEXT state"],
+"lastStartTag":"plaintext",
+"input":"<head>&body;",
+"output":[["Character", "<head>&body;"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp>",
+"output":[["Character", "foo"], ["EndTag", "xmp"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT (case-insensitivity)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xMp>",
+"output":[["Character", "foo"], ["EndTag", "xmp"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT (ending with space)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp ",
+"output":[["Character", "foo"], "ParseError"]},
+
+{"description":"End tag closing RCDATA or RAWTEXT (ending with EOF)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp",
+"output":[["Character", "foo</xmp"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT (ending with slash)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp/",
+"output":[["Character", "foo"], "ParseError"]},
+
+{"description":"End tag not closing RCDATA or RAWTEXT (ending with left-angle-bracket)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp<",
+"output":[["Character", "foo</xmp<"]]},
+
+{"description":"End tag with incorrect name in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"</foo>bar</xmp>",
+"output":[["Character", "</foo>bar"], ["EndTag", "xmp"]]},
+
+{"description":"End tag with incorrect name in RCDATA or RAWTEXT (starting like correct name)",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"</foo>bar</xmpaar>",
+"output":[["Character", "</foo>bar</xmpaar>"]]},
+
+{"description":"End tag closing RCDATA or RAWTEXT, switching back to PCDATA",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo</xmp></baz>",
+"output":[["Character", "foo"], ["EndTag", "xmp"], ["EndTag", "baz"]]},
+
+{"description":"RAWTEXT w/ something looking like an entity",
+"initialStates":["RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"&foo;",
+"output":[["Character", "&foo;"]]},
+
+{"description":"RCDATA w/ an entity",
+"initialStates":["RCDATA state"],
+"lastStartTag":"textarea",
+"input":"<",
+"output":[["Character", "<"]]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/domjs.test b/pkgs/html/test/data/tokenizer/domjs.test
new file mode 100644
index 0000000..74771e2
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/domjs.test
@@ -0,0 +1,90 @@
+{
+ "tests": [
+ {
+ "description":"CR in bogus comment state",
+ "input":"<?\u000d",
+ "output":["ParseError", ["Comment", "?\u000a"]]
+ },
+ {
+ "description":"CRLF in bogus comment state",
+ "input":"<?\u000d\u000a",
+ "output":["ParseError", ["Comment", "?\u000a"]]
+ },
+ {
+ "description":"NUL in RCDATA and RAWTEXT",
+ "doubleEscaped":true,
+ "initialStates":["RCDATA state", "RAWTEXT state"],
+ "input":"\\u0000",
+ "output":["ParseError", ["Character", "\\uFFFD"]]
+ },
+ {
+ "description":"skip first BOM but not later ones",
+ "input":"\uFEFFfoo\uFEFFbar",
+ "output":[["Character", "foo\uFEFFbar"]]
+ },
+ {
+ "description":"Non BMP-charref in in RCDATA",
+ "initialStates":["RCDATA state"],
+ "input":"≂̸",
+ "output":[["Character", "\u2242\u0338"]]
+ },
+ {
+ "description":"Bad charref in in RCDATA",
+ "initialStates":["RCDATA state"],
+ "input":"&NotEqualTild;",
+ "output":["ParseError", ["Character", "&NotEqualTild;"]]
+ },
+ {
+ "description":"lowercase endtags in RCDATA and RAWTEXT",
+ "initialStates":["RCDATA state", "RAWTEXT state"],
+ "lastStartTag":"xmp",
+ "input":"</XMP>",
+ "output":[["EndTag","xmp"]]
+ },
+ {
+ "description":"bad endtag in RCDATA and RAWTEXT",
+ "initialStates":["RCDATA state", "RAWTEXT state"],
+ "lastStartTag":"xmp",
+ "input":"</ XMP>",
+ "output":[["Character","</ XMP>"]]
+ },
+ {
+ "description":"bad endtag in RCDATA and RAWTEXT",
+ "initialStates":["RCDATA state", "RAWTEXT state"],
+ "lastStartTag":"xmp",
+ "input":"</xm>",
+ "output":[["Character","</xm>"]]
+ },
+ {
+ "description":"bad endtag in RCDATA and RAWTEXT",
+ "initialStates":["RCDATA state", "RAWTEXT state"],
+ "lastStartTag":"xmp",
+ "input":"</xm ",
+ "output":[["Character","</xm "]]
+ },
+ {
+ "description":"bad endtag in RCDATA and RAWTEXT",
+ "initialStates":["RCDATA state", "RAWTEXT state"],
+ "lastStartTag":"xmp",
+ "input":"</xm/",
+ "output":[["Character","</xm/"]]
+ },
+ {
+ "description":"Non BMP-charref in attribute",
+ "input":"<p id=\"≂̸\">",
+ "output":[["StartTag", "p", {"id":"\u2242\u0338"}]]
+ },
+ {
+ "description":"--!NUL in comment ",
+ "doubleEscaped":true,
+ "input":"<!----!\\u0000-->",
+ "output":["ParseError", ["Comment", "--!\\uFFFD"]]
+ },
+ {
+ "description":"space EOF after doctype ",
+ "input":"<!DOCTYPE html ",
+ "output":["ParseError", ["DOCTYPE", "html", null, null , false]]
+ }
+
+ ]
+}
diff --git a/pkgs/html/test/data/tokenizer/entities.test b/pkgs/html/test/data/tokenizer/entities.test
new file mode 100644
index 0000000..1cb17a7
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/entities.test
@@ -0,0 +1,283 @@
+{"tests": [
+
+{"description": "Undefined named entity in attribute value ending in semicolon and whose name starts with a known entity name.",
+"input":"<h a='¬i;'>",
+"output": ["ParseError", ["StartTag", "h", {"a": "¬i;"}]]},
+
+{"description": "Entity name followed by the equals sign in an attribute value.",
+"input":"<h a='&lang='>",
+"output": ["ParseError", ["StartTag", "h", {"a": "&lang="}]]},
+
+{"description": "CR as numeric entity",
+"input":"
",
+"output": ["ParseError", ["Character", "\r"]]},
+
+{"description": "CR as hexadecimal numeric entity",
+"input":"
",
+"output": ["ParseError", ["Character", "\r"]]},
+
+{"description": "Windows-1252 EURO SIGN numeric entity.",
+"input":"€",
+"output": ["ParseError", ["Character", "\u20AC"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u0081"]]},
+
+{"description": "Windows-1252 SINGLE LOW-9 QUOTATION MARK numeric entity.",
+"input":"‚",
+"output": ["ParseError", ["Character", "\u201A"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER F WITH HOOK numeric entity.",
+"input":"ƒ",
+"output": ["ParseError", ["Character", "\u0192"]]},
+
+{"description": "Windows-1252 DOUBLE LOW-9 QUOTATION MARK numeric entity.",
+"input":"„",
+"output": ["ParseError", ["Character", "\u201E"]]},
+
+{"description": "Windows-1252 HORIZONTAL ELLIPSIS numeric entity.",
+"input":"…",
+"output": ["ParseError", ["Character", "\u2026"]]},
+
+{"description": "Windows-1252 DAGGER numeric entity.",
+"input":"†",
+"output": ["ParseError", ["Character", "\u2020"]]},
+
+{"description": "Windows-1252 DOUBLE DAGGER numeric entity.",
+"input":"‡",
+"output": ["ParseError", ["Character", "\u2021"]]},
+
+{"description": "Windows-1252 MODIFIER LETTER CIRCUMFLEX ACCENT numeric entity.",
+"input":"ˆ",
+"output": ["ParseError", ["Character", "\u02C6"]]},
+
+{"description": "Windows-1252 PER MILLE SIGN numeric entity.",
+"input":"‰",
+"output": ["ParseError", ["Character", "\u2030"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER S WITH CARON numeric entity.",
+"input":"Š",
+"output": ["ParseError", ["Character", "\u0160"]]},
+
+{"description": "Windows-1252 SINGLE LEFT-POINTING ANGLE QUOTATION MARK numeric entity.",
+"input":"‹",
+"output": ["ParseError", ["Character", "\u2039"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LIGATURE OE numeric entity.",
+"input":"Œ",
+"output": ["ParseError", ["Character", "\u0152"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u008D"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER Z WITH CARON numeric entity.",
+"input":"Ž",
+"output": ["ParseError", ["Character", "\u017D"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u008F"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u0090"]]},
+
+{"description": "Windows-1252 LEFT SINGLE QUOTATION MARK numeric entity.",
+"input":"‘",
+"output": ["ParseError", ["Character", "\u2018"]]},
+
+{"description": "Windows-1252 RIGHT SINGLE QUOTATION MARK numeric entity.",
+"input":"’",
+"output": ["ParseError", ["Character", "\u2019"]]},
+
+{"description": "Windows-1252 LEFT DOUBLE QUOTATION MARK numeric entity.",
+"input":"“",
+"output": ["ParseError", ["Character", "\u201C"]]},
+
+{"description": "Windows-1252 RIGHT DOUBLE QUOTATION MARK numeric entity.",
+"input":"”",
+"output": ["ParseError", ["Character", "\u201D"]]},
+
+{"description": "Windows-1252 BULLET numeric entity.",
+"input":"•",
+"output": ["ParseError", ["Character", "\u2022"]]},
+
+{"description": "Windows-1252 EN DASH numeric entity.",
+"input":"–",
+"output": ["ParseError", ["Character", "\u2013"]]},
+
+{"description": "Windows-1252 EM DASH numeric entity.",
+"input":"—",
+"output": ["ParseError", ["Character", "\u2014"]]},
+
+{"description": "Windows-1252 SMALL TILDE numeric entity.",
+"input":"˜",
+"output": ["ParseError", ["Character", "\u02DC"]]},
+
+{"description": "Windows-1252 TRADE MARK SIGN numeric entity.",
+"input":"™",
+"output": ["ParseError", ["Character", "\u2122"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER S WITH CARON numeric entity.",
+"input":"š",
+"output": ["ParseError", ["Character", "\u0161"]]},
+
+{"description": "Windows-1252 SINGLE RIGHT-POINTING ANGLE QUOTATION MARK numeric entity.",
+"input":"›",
+"output": ["ParseError", ["Character", "\u203A"]]},
+
+{"description": "Windows-1252 LATIN SMALL LIGATURE OE numeric entity.",
+"input":"œ",
+"output": ["ParseError", ["Character", "\u0153"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u009D"]]},
+
+{"description": "Windows-1252 EURO SIGN hexadecimal numeric entity.",
+"input":"€",
+"output": ["ParseError", ["Character", "\u20AC"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u0081"]]},
+
+{"description": "Windows-1252 SINGLE LOW-9 QUOTATION MARK hexadecimal numeric entity.",
+"input":"‚",
+"output": ["ParseError", ["Character", "\u201A"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER F WITH HOOK hexadecimal numeric entity.",
+"input":"ƒ",
+"output": ["ParseError", ["Character", "\u0192"]]},
+
+{"description": "Windows-1252 DOUBLE LOW-9 QUOTATION MARK hexadecimal numeric entity.",
+"input":"„",
+"output": ["ParseError", ["Character", "\u201E"]]},
+
+{"description": "Windows-1252 HORIZONTAL ELLIPSIS hexadecimal numeric entity.",
+"input":"…",
+"output": ["ParseError", ["Character", "\u2026"]]},
+
+{"description": "Windows-1252 DAGGER hexadecimal numeric entity.",
+"input":"†",
+"output": ["ParseError", ["Character", "\u2020"]]},
+
+{"description": "Windows-1252 DOUBLE DAGGER hexadecimal numeric entity.",
+"input":"‡",
+"output": ["ParseError", ["Character", "\u2021"]]},
+
+{"description": "Windows-1252 MODIFIER LETTER CIRCUMFLEX ACCENT hexadecimal numeric entity.",
+"input":"ˆ",
+"output": ["ParseError", ["Character", "\u02C6"]]},
+
+{"description": "Windows-1252 PER MILLE SIGN hexadecimal numeric entity.",
+"input":"‰",
+"output": ["ParseError", ["Character", "\u2030"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER S WITH CARON hexadecimal numeric entity.",
+"input":"Š",
+"output": ["ParseError", ["Character", "\u0160"]]},
+
+{"description": "Windows-1252 SINGLE LEFT-POINTING ANGLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"‹",
+"output": ["ParseError", ["Character", "\u2039"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LIGATURE OE hexadecimal numeric entity.",
+"input":"Œ",
+"output": ["ParseError", ["Character", "\u0152"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u008D"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER Z WITH CARON hexadecimal numeric entity.",
+"input":"Ž",
+"output": ["ParseError", ["Character", "\u017D"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u008F"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u0090"]]},
+
+{"description": "Windows-1252 LEFT SINGLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"‘",
+"output": ["ParseError", ["Character", "\u2018"]]},
+
+{"description": "Windows-1252 RIGHT SINGLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"’",
+"output": ["ParseError", ["Character", "\u2019"]]},
+
+{"description": "Windows-1252 LEFT DOUBLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"“",
+"output": ["ParseError", ["Character", "\u201C"]]},
+
+{"description": "Windows-1252 RIGHT DOUBLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"”",
+"output": ["ParseError", ["Character", "\u201D"]]},
+
+{"description": "Windows-1252 BULLET hexadecimal numeric entity.",
+"input":"•",
+"output": ["ParseError", ["Character", "\u2022"]]},
+
+{"description": "Windows-1252 EN DASH hexadecimal numeric entity.",
+"input":"–",
+"output": ["ParseError", ["Character", "\u2013"]]},
+
+{"description": "Windows-1252 EM DASH hexadecimal numeric entity.",
+"input":"—",
+"output": ["ParseError", ["Character", "\u2014"]]},
+
+{"description": "Windows-1252 SMALL TILDE hexadecimal numeric entity.",
+"input":"˜",
+"output": ["ParseError", ["Character", "\u02DC"]]},
+
+{"description": "Windows-1252 TRADE MARK SIGN hexadecimal numeric entity.",
+"input":"™",
+"output": ["ParseError", ["Character", "\u2122"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER S WITH CARON hexadecimal numeric entity.",
+"input":"š",
+"output": ["ParseError", ["Character", "\u0161"]]},
+
+{"description": "Windows-1252 SINGLE RIGHT-POINTING ANGLE QUOTATION MARK hexadecimal numeric entity.",
+"input":"›",
+"output": ["ParseError", ["Character", "\u203A"]]},
+
+{"description": "Windows-1252 LATIN SMALL LIGATURE OE hexadecimal numeric entity.",
+"input":"œ",
+"output": ["ParseError", ["Character", "\u0153"]]},
+
+{"description": "Windows-1252 REPLACEMENT CHAR hexadecimal numeric entity.",
+"input":"",
+"output": ["ParseError", ["Character", "\u009D"]]},
+
+{"description": "Windows-1252 LATIN SMALL LETTER Z WITH CARON hexadecimal numeric entity.",
+"input":"ž",
+"output": ["ParseError", ["Character", "\u017E"]]},
+
+{"description": "Windows-1252 LATIN CAPITAL LETTER Y WITH DIAERESIS hexadecimal numeric entity.",
+"input":"Ÿ",
+"output": ["ParseError", ["Character", "\u0178"]]},
+
+{"description": "Decimal numeric entity followed by hex character a.",
+"input":"aa",
+"output": ["ParseError", ["Character", "aa"]]},
+
+{"description": "Decimal numeric entity followed by hex character A.",
+"input":"aA",
+"output": ["ParseError", ["Character", "aA"]]},
+
+{"description": "Decimal numeric entity followed by hex character f.",
+"input":"af",
+"output": ["ParseError", ["Character", "af"]]},
+
+{"description": "Decimal numeric entity followed by hex character A.",
+"input":"aF",
+"output": ["ParseError", ["Character", "aF"]]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/escapeFlag.test b/pkgs/html/test/data/tokenizer/escapeFlag.test
new file mode 100644
index 0000000..18cb430
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/escapeFlag.test
@@ -0,0 +1,33 @@
+{"tests": [
+
+{"description":"Commented close tag in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo<!--</xmp>--></xmp>",
+"output":[["Character", "foo<!--"], ["EndTag", "xmp"], ["Character", "-->"], ["EndTag", "xmp"]]},
+
+{"description":"Bogus comment in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo<!-->baz</xmp>",
+"output":[["Character", "foo<!-->baz"], ["EndTag", "xmp"]]},
+
+{"description":"End tag surrounded by bogus comment in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo<!--></xmp><!-->baz</xmp>",
+"output":[["Character", "foo<!-->"], ["EndTag", "xmp"], "ParseError", ["Comment", ""], ["Character", "baz"], ["EndTag", "xmp"]]},
+
+{"description":"Commented entities in RCDATA",
+"initialStates":["RCDATA state"],
+"lastStartTag":"xmp",
+"input":" & <!-- & --> & </xmp>",
+"output":[["Character", " & <!-- & --> & "], ["EndTag", "xmp"]]},
+
+{"description":"Incorrect comment ending sequences in RCDATA or RAWTEXT",
+"initialStates":["RCDATA state", "RAWTEXT state"],
+"lastStartTag":"xmp",
+"input":"foo<!-- x --x>x-- >x--!>x--<></xmp>",
+"output":[["Character", "foo<!-- x --x>x-- >x--!>x--<>"], ["EndTag", "xmp"]]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/namedEntities.test b/pkgs/html/test/data/tokenizer/namedEntities.test
new file mode 100644
index 0000000..4a51c9c
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/namedEntities.test
@@ -0,0 +1,44189 @@
+{
+ "tests": [
+ {
+ "input": "Æ",
+ "description": "Named entity: AElig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c6"
+ ]
+ ]
+ },
+ {
+ "input": "Æ",
+ "description": "Named entity: AElig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c6"
+ ]
+ ]
+ },
+ {
+ "input": "&",
+ "description": "Named entity: AMP without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&"
+ ]
+ ]
+ },
+ {
+ "input": "&",
+ "description": "Named entity: AMP; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "&"
+ ]
+ ]
+ },
+ {
+ "input": "Á",
+ "description": "Named entity: Aacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c1"
+ ]
+ ]
+ },
+ {
+ "input": "Á",
+ "description": "Named entity: Aacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c1"
+ ]
+ ]
+ },
+ {
+ "input": "&Abreve",
+ "description": "Bad named entity: Abreve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Abreve"
+ ]
+ ]
+ },
+ {
+ "input": "Ă",
+ "description": "Named entity: Abreve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0102"
+ ]
+ ]
+ },
+ {
+ "input": "Â",
+ "description": "Named entity: Acirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c2"
+ ]
+ ]
+ },
+ {
+ "input": "Â",
+ "description": "Named entity: Acirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c2"
+ ]
+ ]
+ },
+ {
+ "input": "&Acy",
+ "description": "Bad named entity: Acy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Acy"
+ ]
+ ]
+ },
+ {
+ "input": "А",
+ "description": "Named entity: Acy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0410"
+ ]
+ ]
+ },
+ {
+ "input": "&Afr",
+ "description": "Bad named entity: Afr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Afr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔄",
+ "description": "Named entity: Afr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd04"
+ ]
+ ]
+ },
+ {
+ "input": "À",
+ "description": "Named entity: Agrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c0"
+ ]
+ ]
+ },
+ {
+ "input": "À",
+ "description": "Named entity: Agrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c0"
+ ]
+ ]
+ },
+ {
+ "input": "&Alpha",
+ "description": "Bad named entity: Alpha without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Alpha"
+ ]
+ ]
+ },
+ {
+ "input": "Α",
+ "description": "Named entity: Alpha; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0391"
+ ]
+ ]
+ },
+ {
+ "input": "&Amacr",
+ "description": "Bad named entity: Amacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Amacr"
+ ]
+ ]
+ },
+ {
+ "input": "Ā",
+ "description": "Named entity: Amacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0100"
+ ]
+ ]
+ },
+ {
+ "input": "&And",
+ "description": "Bad named entity: And without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&And"
+ ]
+ ]
+ },
+ {
+ "input": "⩓",
+ "description": "Named entity: And; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a53"
+ ]
+ ]
+ },
+ {
+ "input": "&Aogon",
+ "description": "Bad named entity: Aogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Aogon"
+ ]
+ ]
+ },
+ {
+ "input": "Ą",
+ "description": "Named entity: Aogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0104"
+ ]
+ ]
+ },
+ {
+ "input": "&Aopf",
+ "description": "Bad named entity: Aopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Aopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝔸",
+ "description": "Named entity: Aopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd38"
+ ]
+ ]
+ },
+ {
+ "input": "&ApplyFunction",
+ "description": "Bad named entity: ApplyFunction without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ApplyFunction"
+ ]
+ ]
+ },
+ {
+ "input": "⁡",
+ "description": "Named entity: ApplyFunction; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2061"
+ ]
+ ]
+ },
+ {
+ "input": "Å",
+ "description": "Named entity: Aring without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c5"
+ ]
+ ]
+ },
+ {
+ "input": "Å",
+ "description": "Named entity: Aring; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c5"
+ ]
+ ]
+ },
+ {
+ "input": "&Ascr",
+ "description": "Bad named entity: Ascr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ascr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒜",
+ "description": "Named entity: Ascr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udc9c"
+ ]
+ ]
+ },
+ {
+ "input": "&Assign",
+ "description": "Bad named entity: Assign without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Assign"
+ ]
+ ]
+ },
+ {
+ "input": "≔",
+ "description": "Named entity: Assign; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2254"
+ ]
+ ]
+ },
+ {
+ "input": "Ã",
+ "description": "Named entity: Atilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c3"
+ ]
+ ]
+ },
+ {
+ "input": "Ã",
+ "description": "Named entity: Atilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c3"
+ ]
+ ]
+ },
+ {
+ "input": "Ä",
+ "description": "Named entity: Auml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c4"
+ ]
+ ]
+ },
+ {
+ "input": "Ä",
+ "description": "Named entity: Auml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c4"
+ ]
+ ]
+ },
+ {
+ "input": "&Backslash",
+ "description": "Bad named entity: Backslash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Backslash"
+ ]
+ ]
+ },
+ {
+ "input": "∖",
+ "description": "Named entity: Backslash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2216"
+ ]
+ ]
+ },
+ {
+ "input": "&Barv",
+ "description": "Bad named entity: Barv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Barv"
+ ]
+ ]
+ },
+ {
+ "input": "⫧",
+ "description": "Named entity: Barv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ae7"
+ ]
+ ]
+ },
+ {
+ "input": "&Barwed",
+ "description": "Bad named entity: Barwed without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Barwed"
+ ]
+ ]
+ },
+ {
+ "input": "⌆",
+ "description": "Named entity: Barwed; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2306"
+ ]
+ ]
+ },
+ {
+ "input": "&Bcy",
+ "description": "Bad named entity: Bcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Bcy"
+ ]
+ ]
+ },
+ {
+ "input": "Б",
+ "description": "Named entity: Bcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0411"
+ ]
+ ]
+ },
+ {
+ "input": "&Because",
+ "description": "Bad named entity: Because without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Because"
+ ]
+ ]
+ },
+ {
+ "input": "∵",
+ "description": "Named entity: Because; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2235"
+ ]
+ ]
+ },
+ {
+ "input": "&Bernoullis",
+ "description": "Bad named entity: Bernoullis without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Bernoullis"
+ ]
+ ]
+ },
+ {
+ "input": "ℬ",
+ "description": "Named entity: Bernoullis; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u212c"
+ ]
+ ]
+ },
+ {
+ "input": "&Beta",
+ "description": "Bad named entity: Beta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Beta"
+ ]
+ ]
+ },
+ {
+ "input": "Β",
+ "description": "Named entity: Beta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0392"
+ ]
+ ]
+ },
+ {
+ "input": "&Bfr",
+ "description": "Bad named entity: Bfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Bfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔅",
+ "description": "Named entity: Bfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd05"
+ ]
+ ]
+ },
+ {
+ "input": "&Bopf",
+ "description": "Bad named entity: Bopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Bopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝔹",
+ "description": "Named entity: Bopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd39"
+ ]
+ ]
+ },
+ {
+ "input": "&Breve",
+ "description": "Bad named entity: Breve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Breve"
+ ]
+ ]
+ },
+ {
+ "input": "˘",
+ "description": "Named entity: Breve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02d8"
+ ]
+ ]
+ },
+ {
+ "input": "&Bscr",
+ "description": "Bad named entity: Bscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Bscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℬ",
+ "description": "Named entity: Bscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u212c"
+ ]
+ ]
+ },
+ {
+ "input": "&Bumpeq",
+ "description": "Bad named entity: Bumpeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Bumpeq"
+ ]
+ ]
+ },
+ {
+ "input": "≎",
+ "description": "Named entity: Bumpeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224e"
+ ]
+ ]
+ },
+ {
+ "input": "&CHcy",
+ "description": "Bad named entity: CHcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CHcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ч",
+ "description": "Named entity: CHcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0427"
+ ]
+ ]
+ },
+ {
+ "input": "©",
+ "description": "Named entity: COPY without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a9"
+ ]
+ ]
+ },
+ {
+ "input": "©",
+ "description": "Named entity: COPY; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a9"
+ ]
+ ]
+ },
+ {
+ "input": "&Cacute",
+ "description": "Bad named entity: Cacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cacute"
+ ]
+ ]
+ },
+ {
+ "input": "Ć",
+ "description": "Named entity: Cacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0106"
+ ]
+ ]
+ },
+ {
+ "input": "&Cap",
+ "description": "Bad named entity: Cap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cap"
+ ]
+ ]
+ },
+ {
+ "input": "⋒",
+ "description": "Named entity: Cap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d2"
+ ]
+ ]
+ },
+ {
+ "input": "&CapitalDifferentialD",
+ "description": "Bad named entity: CapitalDifferentialD without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CapitalDifferentialD"
+ ]
+ ]
+ },
+ {
+ "input": "ⅅ",
+ "description": "Named entity: CapitalDifferentialD; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2145"
+ ]
+ ]
+ },
+ {
+ "input": "&Cayleys",
+ "description": "Bad named entity: Cayleys without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cayleys"
+ ]
+ ]
+ },
+ {
+ "input": "ℭ",
+ "description": "Named entity: Cayleys; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u212d"
+ ]
+ ]
+ },
+ {
+ "input": "&Ccaron",
+ "description": "Bad named entity: Ccaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ccaron"
+ ]
+ ]
+ },
+ {
+ "input": "Č",
+ "description": "Named entity: Ccaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u010c"
+ ]
+ ]
+ },
+ {
+ "input": "Ç",
+ "description": "Named entity: Ccedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c7"
+ ]
+ ]
+ },
+ {
+ "input": "Ç",
+ "description": "Named entity: Ccedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c7"
+ ]
+ ]
+ },
+ {
+ "input": "&Ccirc",
+ "description": "Bad named entity: Ccirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ccirc"
+ ]
+ ]
+ },
+ {
+ "input": "Ĉ",
+ "description": "Named entity: Ccirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0108"
+ ]
+ ]
+ },
+ {
+ "input": "&Cconint",
+ "description": "Bad named entity: Cconint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cconint"
+ ]
+ ]
+ },
+ {
+ "input": "∰",
+ "description": "Named entity: Cconint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2230"
+ ]
+ ]
+ },
+ {
+ "input": "&Cdot",
+ "description": "Bad named entity: Cdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cdot"
+ ]
+ ]
+ },
+ {
+ "input": "Ċ",
+ "description": "Named entity: Cdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u010a"
+ ]
+ ]
+ },
+ {
+ "input": "&Cedilla",
+ "description": "Bad named entity: Cedilla without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cedilla"
+ ]
+ ]
+ },
+ {
+ "input": "¸",
+ "description": "Named entity: Cedilla; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b8"
+ ]
+ ]
+ },
+ {
+ "input": "&CenterDot",
+ "description": "Bad named entity: CenterDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CenterDot"
+ ]
+ ]
+ },
+ {
+ "input": "·",
+ "description": "Named entity: CenterDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b7"
+ ]
+ ]
+ },
+ {
+ "input": "&Cfr",
+ "description": "Bad named entity: Cfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cfr"
+ ]
+ ]
+ },
+ {
+ "input": "ℭ",
+ "description": "Named entity: Cfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u212d"
+ ]
+ ]
+ },
+ {
+ "input": "&Chi",
+ "description": "Bad named entity: Chi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Chi"
+ ]
+ ]
+ },
+ {
+ "input": "Χ",
+ "description": "Named entity: Chi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a7"
+ ]
+ ]
+ },
+ {
+ "input": "&CircleDot",
+ "description": "Bad named entity: CircleDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CircleDot"
+ ]
+ ]
+ },
+ {
+ "input": "⊙",
+ "description": "Named entity: CircleDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2299"
+ ]
+ ]
+ },
+ {
+ "input": "&CircleMinus",
+ "description": "Bad named entity: CircleMinus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CircleMinus"
+ ]
+ ]
+ },
+ {
+ "input": "⊖",
+ "description": "Named entity: CircleMinus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2296"
+ ]
+ ]
+ },
+ {
+ "input": "&CirclePlus",
+ "description": "Bad named entity: CirclePlus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CirclePlus"
+ ]
+ ]
+ },
+ {
+ "input": "⊕",
+ "description": "Named entity: CirclePlus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2295"
+ ]
+ ]
+ },
+ {
+ "input": "&CircleTimes",
+ "description": "Bad named entity: CircleTimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CircleTimes"
+ ]
+ ]
+ },
+ {
+ "input": "⊗",
+ "description": "Named entity: CircleTimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2297"
+ ]
+ ]
+ },
+ {
+ "input": "&ClockwiseContourIntegral",
+ "description": "Bad named entity: ClockwiseContourIntegral without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ClockwiseContourIntegral"
+ ]
+ ]
+ },
+ {
+ "input": "∲",
+ "description": "Named entity: ClockwiseContourIntegral; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2232"
+ ]
+ ]
+ },
+ {
+ "input": "&CloseCurlyDoubleQuote",
+ "description": "Bad named entity: CloseCurlyDoubleQuote without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CloseCurlyDoubleQuote"
+ ]
+ ]
+ },
+ {
+ "input": "”",
+ "description": "Named entity: CloseCurlyDoubleQuote; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201d"
+ ]
+ ]
+ },
+ {
+ "input": "&CloseCurlyQuote",
+ "description": "Bad named entity: CloseCurlyQuote without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CloseCurlyQuote"
+ ]
+ ]
+ },
+ {
+ "input": "’",
+ "description": "Named entity: CloseCurlyQuote; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2019"
+ ]
+ ]
+ },
+ {
+ "input": "&Colon",
+ "description": "Bad named entity: Colon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Colon"
+ ]
+ ]
+ },
+ {
+ "input": "∷",
+ "description": "Named entity: Colon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2237"
+ ]
+ ]
+ },
+ {
+ "input": "&Colone",
+ "description": "Bad named entity: Colone without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Colone"
+ ]
+ ]
+ },
+ {
+ "input": "⩴",
+ "description": "Named entity: Colone; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a74"
+ ]
+ ]
+ },
+ {
+ "input": "&Congruent",
+ "description": "Bad named entity: Congruent without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Congruent"
+ ]
+ ]
+ },
+ {
+ "input": "≡",
+ "description": "Named entity: Congruent; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2261"
+ ]
+ ]
+ },
+ {
+ "input": "&Conint",
+ "description": "Bad named entity: Conint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Conint"
+ ]
+ ]
+ },
+ {
+ "input": "∯",
+ "description": "Named entity: Conint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222f"
+ ]
+ ]
+ },
+ {
+ "input": "&ContourIntegral",
+ "description": "Bad named entity: ContourIntegral without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ContourIntegral"
+ ]
+ ]
+ },
+ {
+ "input": "∮",
+ "description": "Named entity: ContourIntegral; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222e"
+ ]
+ ]
+ },
+ {
+ "input": "&Copf",
+ "description": "Bad named entity: Copf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Copf"
+ ]
+ ]
+ },
+ {
+ "input": "ℂ",
+ "description": "Named entity: Copf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2102"
+ ]
+ ]
+ },
+ {
+ "input": "&Coproduct",
+ "description": "Bad named entity: Coproduct without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Coproduct"
+ ]
+ ]
+ },
+ {
+ "input": "∐",
+ "description": "Named entity: Coproduct; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2210"
+ ]
+ ]
+ },
+ {
+ "input": "&CounterClockwiseContourIntegral",
+ "description": "Bad named entity: CounterClockwiseContourIntegral without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CounterClockwiseContourIntegral"
+ ]
+ ]
+ },
+ {
+ "input": "∳",
+ "description": "Named entity: CounterClockwiseContourIntegral; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2233"
+ ]
+ ]
+ },
+ {
+ "input": "&Cross",
+ "description": "Bad named entity: Cross without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cross"
+ ]
+ ]
+ },
+ {
+ "input": "⨯",
+ "description": "Named entity: Cross; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a2f"
+ ]
+ ]
+ },
+ {
+ "input": "&Cscr",
+ "description": "Bad named entity: Cscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒞",
+ "description": "Named entity: Cscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udc9e"
+ ]
+ ]
+ },
+ {
+ "input": "&Cup",
+ "description": "Bad named entity: Cup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Cup"
+ ]
+ ]
+ },
+ {
+ "input": "⋓",
+ "description": "Named entity: Cup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d3"
+ ]
+ ]
+ },
+ {
+ "input": "&CupCap",
+ "description": "Bad named entity: CupCap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&CupCap"
+ ]
+ ]
+ },
+ {
+ "input": "≍",
+ "description": "Named entity: CupCap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224d"
+ ]
+ ]
+ },
+ {
+ "input": "&DD",
+ "description": "Bad named entity: DD without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DD"
+ ]
+ ]
+ },
+ {
+ "input": "ⅅ",
+ "description": "Named entity: DD; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2145"
+ ]
+ ]
+ },
+ {
+ "input": "&DDotrahd",
+ "description": "Bad named entity: DDotrahd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DDotrahd"
+ ]
+ ]
+ },
+ {
+ "input": "⤑",
+ "description": "Named entity: DDotrahd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2911"
+ ]
+ ]
+ },
+ {
+ "input": "&DJcy",
+ "description": "Bad named entity: DJcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DJcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ђ",
+ "description": "Named entity: DJcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0402"
+ ]
+ ]
+ },
+ {
+ "input": "&DScy",
+ "description": "Bad named entity: DScy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DScy"
+ ]
+ ]
+ },
+ {
+ "input": "Ѕ",
+ "description": "Named entity: DScy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0405"
+ ]
+ ]
+ },
+ {
+ "input": "&DZcy",
+ "description": "Bad named entity: DZcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DZcy"
+ ]
+ ]
+ },
+ {
+ "input": "Џ",
+ "description": "Named entity: DZcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u040f"
+ ]
+ ]
+ },
+ {
+ "input": "&Dagger",
+ "description": "Bad named entity: Dagger without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dagger"
+ ]
+ ]
+ },
+ {
+ "input": "‡",
+ "description": "Named entity: Dagger; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2021"
+ ]
+ ]
+ },
+ {
+ "input": "&Darr",
+ "description": "Bad named entity: Darr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Darr"
+ ]
+ ]
+ },
+ {
+ "input": "↡",
+ "description": "Named entity: Darr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a1"
+ ]
+ ]
+ },
+ {
+ "input": "&Dashv",
+ "description": "Bad named entity: Dashv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dashv"
+ ]
+ ]
+ },
+ {
+ "input": "⫤",
+ "description": "Named entity: Dashv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ae4"
+ ]
+ ]
+ },
+ {
+ "input": "&Dcaron",
+ "description": "Bad named entity: Dcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dcaron"
+ ]
+ ]
+ },
+ {
+ "input": "Ď",
+ "description": "Named entity: Dcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u010e"
+ ]
+ ]
+ },
+ {
+ "input": "&Dcy",
+ "description": "Bad named entity: Dcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dcy"
+ ]
+ ]
+ },
+ {
+ "input": "Д",
+ "description": "Named entity: Dcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0414"
+ ]
+ ]
+ },
+ {
+ "input": "&Del",
+ "description": "Bad named entity: Del without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Del"
+ ]
+ ]
+ },
+ {
+ "input": "∇",
+ "description": "Named entity: Del; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2207"
+ ]
+ ]
+ },
+ {
+ "input": "&Delta",
+ "description": "Bad named entity: Delta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Delta"
+ ]
+ ]
+ },
+ {
+ "input": "Δ",
+ "description": "Named entity: Delta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0394"
+ ]
+ ]
+ },
+ {
+ "input": "&Dfr",
+ "description": "Bad named entity: Dfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔇",
+ "description": "Named entity: Dfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd07"
+ ]
+ ]
+ },
+ {
+ "input": "&DiacriticalAcute",
+ "description": "Bad named entity: DiacriticalAcute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DiacriticalAcute"
+ ]
+ ]
+ },
+ {
+ "input": "´",
+ "description": "Named entity: DiacriticalAcute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b4"
+ ]
+ ]
+ },
+ {
+ "input": "&DiacriticalDot",
+ "description": "Bad named entity: DiacriticalDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DiacriticalDot"
+ ]
+ ]
+ },
+ {
+ "input": "˙",
+ "description": "Named entity: DiacriticalDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02d9"
+ ]
+ ]
+ },
+ {
+ "input": "&DiacriticalDoubleAcute",
+ "description": "Bad named entity: DiacriticalDoubleAcute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DiacriticalDoubleAcute"
+ ]
+ ]
+ },
+ {
+ "input": "˝",
+ "description": "Named entity: DiacriticalDoubleAcute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02dd"
+ ]
+ ]
+ },
+ {
+ "input": "&DiacriticalGrave",
+ "description": "Bad named entity: DiacriticalGrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DiacriticalGrave"
+ ]
+ ]
+ },
+ {
+ "input": "`",
+ "description": "Named entity: DiacriticalGrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "`"
+ ]
+ ]
+ },
+ {
+ "input": "&DiacriticalTilde",
+ "description": "Bad named entity: DiacriticalTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DiacriticalTilde"
+ ]
+ ]
+ },
+ {
+ "input": "˜",
+ "description": "Named entity: DiacriticalTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02dc"
+ ]
+ ]
+ },
+ {
+ "input": "&Diamond",
+ "description": "Bad named entity: Diamond without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Diamond"
+ ]
+ ]
+ },
+ {
+ "input": "⋄",
+ "description": "Named entity: Diamond; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c4"
+ ]
+ ]
+ },
+ {
+ "input": "&DifferentialD",
+ "description": "Bad named entity: DifferentialD without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DifferentialD"
+ ]
+ ]
+ },
+ {
+ "input": "ⅆ",
+ "description": "Named entity: DifferentialD; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2146"
+ ]
+ ]
+ },
+ {
+ "input": "&Dopf",
+ "description": "Bad named entity: Dopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝔻",
+ "description": "Named entity: Dopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd3b"
+ ]
+ ]
+ },
+ {
+ "input": "&Dot",
+ "description": "Bad named entity: Dot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dot"
+ ]
+ ]
+ },
+ {
+ "input": "¨",
+ "description": "Named entity: Dot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a8"
+ ]
+ ]
+ },
+ {
+ "input": "&DotDot",
+ "description": "Bad named entity: DotDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DotDot"
+ ]
+ ]
+ },
+ {
+ "input": "⃜",
+ "description": "Named entity: DotDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u20dc"
+ ]
+ ]
+ },
+ {
+ "input": "&DotEqual",
+ "description": "Bad named entity: DotEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DotEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≐",
+ "description": "Named entity: DotEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2250"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleContourIntegral",
+ "description": "Bad named entity: DoubleContourIntegral without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleContourIntegral"
+ ]
+ ]
+ },
+ {
+ "input": "∯",
+ "description": "Named entity: DoubleContourIntegral; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222f"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleDot",
+ "description": "Bad named entity: DoubleDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleDot"
+ ]
+ ]
+ },
+ {
+ "input": "¨",
+ "description": "Named entity: DoubleDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a8"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleDownArrow",
+ "description": "Bad named entity: DoubleDownArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleDownArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇓",
+ "description": "Named entity: DoubleDownArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d3"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleLeftArrow",
+ "description": "Bad named entity: DoubleLeftArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleLeftArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇐",
+ "description": "Named entity: DoubleLeftArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d0"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleLeftRightArrow",
+ "description": "Bad named entity: DoubleLeftRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleLeftRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇔",
+ "description": "Named entity: DoubleLeftRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d4"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleLeftTee",
+ "description": "Bad named entity: DoubleLeftTee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleLeftTee"
+ ]
+ ]
+ },
+ {
+ "input": "⫤",
+ "description": "Named entity: DoubleLeftTee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ae4"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleLongLeftArrow",
+ "description": "Bad named entity: DoubleLongLeftArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleLongLeftArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟸",
+ "description": "Named entity: DoubleLongLeftArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f8"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleLongLeftRightArrow",
+ "description": "Bad named entity: DoubleLongLeftRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleLongLeftRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟺",
+ "description": "Named entity: DoubleLongLeftRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27fa"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleLongRightArrow",
+ "description": "Bad named entity: DoubleLongRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleLongRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟹",
+ "description": "Named entity: DoubleLongRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f9"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleRightArrow",
+ "description": "Bad named entity: DoubleRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇒",
+ "description": "Named entity: DoubleRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d2"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleRightTee",
+ "description": "Bad named entity: DoubleRightTee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleRightTee"
+ ]
+ ]
+ },
+ {
+ "input": "⊨",
+ "description": "Named entity: DoubleRightTee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a8"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleUpArrow",
+ "description": "Bad named entity: DoubleUpArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleUpArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇑",
+ "description": "Named entity: DoubleUpArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d1"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleUpDownArrow",
+ "description": "Bad named entity: DoubleUpDownArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleUpDownArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇕",
+ "description": "Named entity: DoubleUpDownArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d5"
+ ]
+ ]
+ },
+ {
+ "input": "&DoubleVerticalBar",
+ "description": "Bad named entity: DoubleVerticalBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DoubleVerticalBar"
+ ]
+ ]
+ },
+ {
+ "input": "∥",
+ "description": "Named entity: DoubleVerticalBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2225"
+ ]
+ ]
+ },
+ {
+ "input": "&DownArrow",
+ "description": "Bad named entity: DownArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↓",
+ "description": "Named entity: DownArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2193"
+ ]
+ ]
+ },
+ {
+ "input": "&DownArrowBar",
+ "description": "Bad named entity: DownArrowBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownArrowBar"
+ ]
+ ]
+ },
+ {
+ "input": "⤓",
+ "description": "Named entity: DownArrowBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2913"
+ ]
+ ]
+ },
+ {
+ "input": "&DownArrowUpArrow",
+ "description": "Bad named entity: DownArrowUpArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownArrowUpArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇵",
+ "description": "Named entity: DownArrowUpArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21f5"
+ ]
+ ]
+ },
+ {
+ "input": "&DownBreve",
+ "description": "Bad named entity: DownBreve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownBreve"
+ ]
+ ]
+ },
+ {
+ "input": "̑",
+ "description": "Named entity: DownBreve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0311"
+ ]
+ ]
+ },
+ {
+ "input": "&DownLeftRightVector",
+ "description": "Bad named entity: DownLeftRightVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownLeftRightVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥐",
+ "description": "Named entity: DownLeftRightVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2950"
+ ]
+ ]
+ },
+ {
+ "input": "&DownLeftTeeVector",
+ "description": "Bad named entity: DownLeftTeeVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownLeftTeeVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥞",
+ "description": "Named entity: DownLeftTeeVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u295e"
+ ]
+ ]
+ },
+ {
+ "input": "&DownLeftVector",
+ "description": "Bad named entity: DownLeftVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownLeftVector"
+ ]
+ ]
+ },
+ {
+ "input": "↽",
+ "description": "Named entity: DownLeftVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bd"
+ ]
+ ]
+ },
+ {
+ "input": "&DownLeftVectorBar",
+ "description": "Bad named entity: DownLeftVectorBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownLeftVectorBar"
+ ]
+ ]
+ },
+ {
+ "input": "⥖",
+ "description": "Named entity: DownLeftVectorBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2956"
+ ]
+ ]
+ },
+ {
+ "input": "&DownRightTeeVector",
+ "description": "Bad named entity: DownRightTeeVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownRightTeeVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥟",
+ "description": "Named entity: DownRightTeeVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u295f"
+ ]
+ ]
+ },
+ {
+ "input": "&DownRightVector",
+ "description": "Bad named entity: DownRightVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownRightVector"
+ ]
+ ]
+ },
+ {
+ "input": "⇁",
+ "description": "Named entity: DownRightVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c1"
+ ]
+ ]
+ },
+ {
+ "input": "&DownRightVectorBar",
+ "description": "Bad named entity: DownRightVectorBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownRightVectorBar"
+ ]
+ ]
+ },
+ {
+ "input": "⥗",
+ "description": "Named entity: DownRightVectorBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2957"
+ ]
+ ]
+ },
+ {
+ "input": "&DownTee",
+ "description": "Bad named entity: DownTee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownTee"
+ ]
+ ]
+ },
+ {
+ "input": "⊤",
+ "description": "Named entity: DownTee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a4"
+ ]
+ ]
+ },
+ {
+ "input": "&DownTeeArrow",
+ "description": "Bad named entity: DownTeeArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&DownTeeArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↧",
+ "description": "Named entity: DownTeeArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a7"
+ ]
+ ]
+ },
+ {
+ "input": "&Downarrow",
+ "description": "Bad named entity: Downarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Downarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇓",
+ "description": "Named entity: Downarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d3"
+ ]
+ ]
+ },
+ {
+ "input": "&Dscr",
+ "description": "Bad named entity: Dscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒟",
+ "description": "Named entity: Dscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udc9f"
+ ]
+ ]
+ },
+ {
+ "input": "&Dstrok",
+ "description": "Bad named entity: Dstrok without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Dstrok"
+ ]
+ ]
+ },
+ {
+ "input": "Đ",
+ "description": "Named entity: Dstrok; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0110"
+ ]
+ ]
+ },
+ {
+ "input": "&ENG",
+ "description": "Bad named entity: ENG without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ENG"
+ ]
+ ]
+ },
+ {
+ "input": "Ŋ",
+ "description": "Named entity: ENG; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u014a"
+ ]
+ ]
+ },
+ {
+ "input": "Ð",
+ "description": "Named entity: ETH without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d0"
+ ]
+ ]
+ },
+ {
+ "input": "Ð",
+ "description": "Named entity: ETH; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d0"
+ ]
+ ]
+ },
+ {
+ "input": "É",
+ "description": "Named entity: Eacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c9"
+ ]
+ ]
+ },
+ {
+ "input": "É",
+ "description": "Named entity: Eacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c9"
+ ]
+ ]
+ },
+ {
+ "input": "&Ecaron",
+ "description": "Bad named entity: Ecaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ecaron"
+ ]
+ ]
+ },
+ {
+ "input": "Ě",
+ "description": "Named entity: Ecaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u011a"
+ ]
+ ]
+ },
+ {
+ "input": "Ê",
+ "description": "Named entity: Ecirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ca"
+ ]
+ ]
+ },
+ {
+ "input": "Ê",
+ "description": "Named entity: Ecirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ca"
+ ]
+ ]
+ },
+ {
+ "input": "&Ecy",
+ "description": "Bad named entity: Ecy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ecy"
+ ]
+ ]
+ },
+ {
+ "input": "Э",
+ "description": "Named entity: Ecy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u042d"
+ ]
+ ]
+ },
+ {
+ "input": "&Edot",
+ "description": "Bad named entity: Edot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Edot"
+ ]
+ ]
+ },
+ {
+ "input": "Ė",
+ "description": "Named entity: Edot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0116"
+ ]
+ ]
+ },
+ {
+ "input": "&Efr",
+ "description": "Bad named entity: Efr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Efr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔈",
+ "description": "Named entity: Efr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd08"
+ ]
+ ]
+ },
+ {
+ "input": "È",
+ "description": "Named entity: Egrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00c8"
+ ]
+ ]
+ },
+ {
+ "input": "È",
+ "description": "Named entity: Egrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c8"
+ ]
+ ]
+ },
+ {
+ "input": "&Element",
+ "description": "Bad named entity: Element without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Element"
+ ]
+ ]
+ },
+ {
+ "input": "∈",
+ "description": "Named entity: Element; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2208"
+ ]
+ ]
+ },
+ {
+ "input": "&Emacr",
+ "description": "Bad named entity: Emacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Emacr"
+ ]
+ ]
+ },
+ {
+ "input": "Ē",
+ "description": "Named entity: Emacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0112"
+ ]
+ ]
+ },
+ {
+ "input": "&EmptySmallSquare",
+ "description": "Bad named entity: EmptySmallSquare without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&EmptySmallSquare"
+ ]
+ ]
+ },
+ {
+ "input": "◻",
+ "description": "Named entity: EmptySmallSquare; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25fb"
+ ]
+ ]
+ },
+ {
+ "input": "&EmptyVerySmallSquare",
+ "description": "Bad named entity: EmptyVerySmallSquare without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&EmptyVerySmallSquare"
+ ]
+ ]
+ },
+ {
+ "input": "▫",
+ "description": "Named entity: EmptyVerySmallSquare; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25ab"
+ ]
+ ]
+ },
+ {
+ "input": "&Eogon",
+ "description": "Bad named entity: Eogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Eogon"
+ ]
+ ]
+ },
+ {
+ "input": "Ę",
+ "description": "Named entity: Eogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0118"
+ ]
+ ]
+ },
+ {
+ "input": "&Eopf",
+ "description": "Bad named entity: Eopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Eopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝔼",
+ "description": "Named entity: Eopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd3c"
+ ]
+ ]
+ },
+ {
+ "input": "&Epsilon",
+ "description": "Bad named entity: Epsilon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Epsilon"
+ ]
+ ]
+ },
+ {
+ "input": "Ε",
+ "description": "Named entity: Epsilon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0395"
+ ]
+ ]
+ },
+ {
+ "input": "&Equal",
+ "description": "Bad named entity: Equal without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Equal"
+ ]
+ ]
+ },
+ {
+ "input": "⩵",
+ "description": "Named entity: Equal; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a75"
+ ]
+ ]
+ },
+ {
+ "input": "&EqualTilde",
+ "description": "Bad named entity: EqualTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&EqualTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≂",
+ "description": "Named entity: EqualTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2242"
+ ]
+ ]
+ },
+ {
+ "input": "&Equilibrium",
+ "description": "Bad named entity: Equilibrium without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Equilibrium"
+ ]
+ ]
+ },
+ {
+ "input": "⇌",
+ "description": "Named entity: Equilibrium; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cc"
+ ]
+ ]
+ },
+ {
+ "input": "&Escr",
+ "description": "Bad named entity: Escr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Escr"
+ ]
+ ]
+ },
+ {
+ "input": "ℰ",
+ "description": "Named entity: Escr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2130"
+ ]
+ ]
+ },
+ {
+ "input": "&Esim",
+ "description": "Bad named entity: Esim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Esim"
+ ]
+ ]
+ },
+ {
+ "input": "⩳",
+ "description": "Named entity: Esim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a73"
+ ]
+ ]
+ },
+ {
+ "input": "&Eta",
+ "description": "Bad named entity: Eta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Eta"
+ ]
+ ]
+ },
+ {
+ "input": "Η",
+ "description": "Named entity: Eta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0397"
+ ]
+ ]
+ },
+ {
+ "input": "Ë",
+ "description": "Named entity: Euml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00cb"
+ ]
+ ]
+ },
+ {
+ "input": "Ë",
+ "description": "Named entity: Euml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00cb"
+ ]
+ ]
+ },
+ {
+ "input": "&Exists",
+ "description": "Bad named entity: Exists without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Exists"
+ ]
+ ]
+ },
+ {
+ "input": "∃",
+ "description": "Named entity: Exists; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2203"
+ ]
+ ]
+ },
+ {
+ "input": "&ExponentialE",
+ "description": "Bad named entity: ExponentialE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ExponentialE"
+ ]
+ ]
+ },
+ {
+ "input": "ⅇ",
+ "description": "Named entity: ExponentialE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2147"
+ ]
+ ]
+ },
+ {
+ "input": "&Fcy",
+ "description": "Bad named entity: Fcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Fcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ф",
+ "description": "Named entity: Fcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0424"
+ ]
+ ]
+ },
+ {
+ "input": "&Ffr",
+ "description": "Bad named entity: Ffr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ffr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔉",
+ "description": "Named entity: Ffr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd09"
+ ]
+ ]
+ },
+ {
+ "input": "&FilledSmallSquare",
+ "description": "Bad named entity: FilledSmallSquare without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&FilledSmallSquare"
+ ]
+ ]
+ },
+ {
+ "input": "◼",
+ "description": "Named entity: FilledSmallSquare; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25fc"
+ ]
+ ]
+ },
+ {
+ "input": "&FilledVerySmallSquare",
+ "description": "Bad named entity: FilledVerySmallSquare without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&FilledVerySmallSquare"
+ ]
+ ]
+ },
+ {
+ "input": "▪",
+ "description": "Named entity: FilledVerySmallSquare; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25aa"
+ ]
+ ]
+ },
+ {
+ "input": "&Fopf",
+ "description": "Bad named entity: Fopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Fopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝔽",
+ "description": "Named entity: Fopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd3d"
+ ]
+ ]
+ },
+ {
+ "input": "&ForAll",
+ "description": "Bad named entity: ForAll without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ForAll"
+ ]
+ ]
+ },
+ {
+ "input": "∀",
+ "description": "Named entity: ForAll; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2200"
+ ]
+ ]
+ },
+ {
+ "input": "&Fouriertrf",
+ "description": "Bad named entity: Fouriertrf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Fouriertrf"
+ ]
+ ]
+ },
+ {
+ "input": "ℱ",
+ "description": "Named entity: Fouriertrf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2131"
+ ]
+ ]
+ },
+ {
+ "input": "&Fscr",
+ "description": "Bad named entity: Fscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Fscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℱ",
+ "description": "Named entity: Fscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2131"
+ ]
+ ]
+ },
+ {
+ "input": "&GJcy",
+ "description": "Bad named entity: GJcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&GJcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ѓ",
+ "description": "Named entity: GJcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0403"
+ ]
+ ]
+ },
+ {
+ "input": ">",
+ "description": "Named entity: GT without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ ">"
+ ]
+ ]
+ },
+ {
+ "input": ">",
+ "description": "Named entity: GT; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ ">"
+ ]
+ ]
+ },
+ {
+ "input": "&Gamma",
+ "description": "Bad named entity: Gamma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gamma"
+ ]
+ ]
+ },
+ {
+ "input": "Γ",
+ "description": "Named entity: Gamma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0393"
+ ]
+ ]
+ },
+ {
+ "input": "&Gammad",
+ "description": "Bad named entity: Gammad without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gammad"
+ ]
+ ]
+ },
+ {
+ "input": "Ϝ",
+ "description": "Named entity: Gammad; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03dc"
+ ]
+ ]
+ },
+ {
+ "input": "&Gbreve",
+ "description": "Bad named entity: Gbreve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gbreve"
+ ]
+ ]
+ },
+ {
+ "input": "Ğ",
+ "description": "Named entity: Gbreve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u011e"
+ ]
+ ]
+ },
+ {
+ "input": "&Gcedil",
+ "description": "Bad named entity: Gcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gcedil"
+ ]
+ ]
+ },
+ {
+ "input": "Ģ",
+ "description": "Named entity: Gcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0122"
+ ]
+ ]
+ },
+ {
+ "input": "&Gcirc",
+ "description": "Bad named entity: Gcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gcirc"
+ ]
+ ]
+ },
+ {
+ "input": "Ĝ",
+ "description": "Named entity: Gcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u011c"
+ ]
+ ]
+ },
+ {
+ "input": "&Gcy",
+ "description": "Bad named entity: Gcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gcy"
+ ]
+ ]
+ },
+ {
+ "input": "Г",
+ "description": "Named entity: Gcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0413"
+ ]
+ ]
+ },
+ {
+ "input": "&Gdot",
+ "description": "Bad named entity: Gdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gdot"
+ ]
+ ]
+ },
+ {
+ "input": "Ġ",
+ "description": "Named entity: Gdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0120"
+ ]
+ ]
+ },
+ {
+ "input": "&Gfr",
+ "description": "Bad named entity: Gfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔊",
+ "description": "Named entity: Gfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd0a"
+ ]
+ ]
+ },
+ {
+ "input": "&Gg",
+ "description": "Bad named entity: Gg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gg"
+ ]
+ ]
+ },
+ {
+ "input": "⋙",
+ "description": "Named entity: Gg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d9"
+ ]
+ ]
+ },
+ {
+ "input": "&Gopf",
+ "description": "Bad named entity: Gopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝔾",
+ "description": "Named entity: Gopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd3e"
+ ]
+ ]
+ },
+ {
+ "input": "&GreaterEqual",
+ "description": "Bad named entity: GreaterEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&GreaterEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≥",
+ "description": "Named entity: GreaterEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2265"
+ ]
+ ]
+ },
+ {
+ "input": "&GreaterEqualLess",
+ "description": "Bad named entity: GreaterEqualLess without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&GreaterEqualLess"
+ ]
+ ]
+ },
+ {
+ "input": "⋛",
+ "description": "Named entity: GreaterEqualLess; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22db"
+ ]
+ ]
+ },
+ {
+ "input": "&GreaterFullEqual",
+ "description": "Bad named entity: GreaterFullEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&GreaterFullEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≧",
+ "description": "Named entity: GreaterFullEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2267"
+ ]
+ ]
+ },
+ {
+ "input": "&GreaterGreater",
+ "description": "Bad named entity: GreaterGreater without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&GreaterGreater"
+ ]
+ ]
+ },
+ {
+ "input": "⪢",
+ "description": "Named entity: GreaterGreater; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa2"
+ ]
+ ]
+ },
+ {
+ "input": "&GreaterLess",
+ "description": "Bad named entity: GreaterLess without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&GreaterLess"
+ ]
+ ]
+ },
+ {
+ "input": "≷",
+ "description": "Named entity: GreaterLess; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2277"
+ ]
+ ]
+ },
+ {
+ "input": "&GreaterSlantEqual",
+ "description": "Bad named entity: GreaterSlantEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&GreaterSlantEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⩾",
+ "description": "Named entity: GreaterSlantEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7e"
+ ]
+ ]
+ },
+ {
+ "input": "&GreaterTilde",
+ "description": "Bad named entity: GreaterTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&GreaterTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≳",
+ "description": "Named entity: GreaterTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2273"
+ ]
+ ]
+ },
+ {
+ "input": "&Gscr",
+ "description": "Bad named entity: Gscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒢",
+ "description": "Named entity: Gscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udca2"
+ ]
+ ]
+ },
+ {
+ "input": "&Gt",
+ "description": "Bad named entity: Gt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Gt"
+ ]
+ ]
+ },
+ {
+ "input": "≫",
+ "description": "Named entity: Gt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226b"
+ ]
+ ]
+ },
+ {
+ "input": "&HARDcy",
+ "description": "Bad named entity: HARDcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&HARDcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ъ",
+ "description": "Named entity: HARDcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u042a"
+ ]
+ ]
+ },
+ {
+ "input": "&Hacek",
+ "description": "Bad named entity: Hacek without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Hacek"
+ ]
+ ]
+ },
+ {
+ "input": "ˇ",
+ "description": "Named entity: Hacek; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02c7"
+ ]
+ ]
+ },
+ {
+ "input": "&Hat",
+ "description": "Bad named entity: Hat without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Hat"
+ ]
+ ]
+ },
+ {
+ "input": "^",
+ "description": "Named entity: Hat; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "^"
+ ]
+ ]
+ },
+ {
+ "input": "&Hcirc",
+ "description": "Bad named entity: Hcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Hcirc"
+ ]
+ ]
+ },
+ {
+ "input": "Ĥ",
+ "description": "Named entity: Hcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0124"
+ ]
+ ]
+ },
+ {
+ "input": "&Hfr",
+ "description": "Bad named entity: Hfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Hfr"
+ ]
+ ]
+ },
+ {
+ "input": "ℌ",
+ "description": "Named entity: Hfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210c"
+ ]
+ ]
+ },
+ {
+ "input": "&HilbertSpace",
+ "description": "Bad named entity: HilbertSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&HilbertSpace"
+ ]
+ ]
+ },
+ {
+ "input": "ℋ",
+ "description": "Named entity: HilbertSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210b"
+ ]
+ ]
+ },
+ {
+ "input": "&Hopf",
+ "description": "Bad named entity: Hopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Hopf"
+ ]
+ ]
+ },
+ {
+ "input": "ℍ",
+ "description": "Named entity: Hopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210d"
+ ]
+ ]
+ },
+ {
+ "input": "&HorizontalLine",
+ "description": "Bad named entity: HorizontalLine without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&HorizontalLine"
+ ]
+ ]
+ },
+ {
+ "input": "─",
+ "description": "Named entity: HorizontalLine; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2500"
+ ]
+ ]
+ },
+ {
+ "input": "&Hscr",
+ "description": "Bad named entity: Hscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Hscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℋ",
+ "description": "Named entity: Hscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210b"
+ ]
+ ]
+ },
+ {
+ "input": "&Hstrok",
+ "description": "Bad named entity: Hstrok without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Hstrok"
+ ]
+ ]
+ },
+ {
+ "input": "Ħ",
+ "description": "Named entity: Hstrok; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0126"
+ ]
+ ]
+ },
+ {
+ "input": "&HumpDownHump",
+ "description": "Bad named entity: HumpDownHump without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&HumpDownHump"
+ ]
+ ]
+ },
+ {
+ "input": "≎",
+ "description": "Named entity: HumpDownHump; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224e"
+ ]
+ ]
+ },
+ {
+ "input": "&HumpEqual",
+ "description": "Bad named entity: HumpEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&HumpEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≏",
+ "description": "Named entity: HumpEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224f"
+ ]
+ ]
+ },
+ {
+ "input": "&IEcy",
+ "description": "Bad named entity: IEcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&IEcy"
+ ]
+ ]
+ },
+ {
+ "input": "Е",
+ "description": "Named entity: IEcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0415"
+ ]
+ ]
+ },
+ {
+ "input": "&IJlig",
+ "description": "Bad named entity: IJlig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&IJlig"
+ ]
+ ]
+ },
+ {
+ "input": "IJ",
+ "description": "Named entity: IJlig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0132"
+ ]
+ ]
+ },
+ {
+ "input": "&IOcy",
+ "description": "Bad named entity: IOcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&IOcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ё",
+ "description": "Named entity: IOcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0401"
+ ]
+ ]
+ },
+ {
+ "input": "Í",
+ "description": "Named entity: Iacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00cd"
+ ]
+ ]
+ },
+ {
+ "input": "Í",
+ "description": "Named entity: Iacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00cd"
+ ]
+ ]
+ },
+ {
+ "input": "Î",
+ "description": "Named entity: Icirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ce"
+ ]
+ ]
+ },
+ {
+ "input": "Î",
+ "description": "Named entity: Icirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ce"
+ ]
+ ]
+ },
+ {
+ "input": "&Icy",
+ "description": "Bad named entity: Icy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Icy"
+ ]
+ ]
+ },
+ {
+ "input": "И",
+ "description": "Named entity: Icy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0418"
+ ]
+ ]
+ },
+ {
+ "input": "&Idot",
+ "description": "Bad named entity: Idot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Idot"
+ ]
+ ]
+ },
+ {
+ "input": "İ",
+ "description": "Named entity: Idot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0130"
+ ]
+ ]
+ },
+ {
+ "input": "&Ifr",
+ "description": "Bad named entity: Ifr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ifr"
+ ]
+ ]
+ },
+ {
+ "input": "ℑ",
+ "description": "Named entity: Ifr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2111"
+ ]
+ ]
+ },
+ {
+ "input": "Ì",
+ "description": "Named entity: Igrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00cc"
+ ]
+ ]
+ },
+ {
+ "input": "Ì",
+ "description": "Named entity: Igrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00cc"
+ ]
+ ]
+ },
+ {
+ "input": "&Im",
+ "description": "Bad named entity: Im without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Im"
+ ]
+ ]
+ },
+ {
+ "input": "ℑ",
+ "description": "Named entity: Im; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2111"
+ ]
+ ]
+ },
+ {
+ "input": "&Imacr",
+ "description": "Bad named entity: Imacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Imacr"
+ ]
+ ]
+ },
+ {
+ "input": "Ī",
+ "description": "Named entity: Imacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u012a"
+ ]
+ ]
+ },
+ {
+ "input": "&ImaginaryI",
+ "description": "Bad named entity: ImaginaryI without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ImaginaryI"
+ ]
+ ]
+ },
+ {
+ "input": "ⅈ",
+ "description": "Named entity: ImaginaryI; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2148"
+ ]
+ ]
+ },
+ {
+ "input": "&Implies",
+ "description": "Bad named entity: Implies without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Implies"
+ ]
+ ]
+ },
+ {
+ "input": "⇒",
+ "description": "Named entity: Implies; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d2"
+ ]
+ ]
+ },
+ {
+ "input": "&Int",
+ "description": "Bad named entity: Int without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Int"
+ ]
+ ]
+ },
+ {
+ "input": "∬",
+ "description": "Named entity: Int; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222c"
+ ]
+ ]
+ },
+ {
+ "input": "&Integral",
+ "description": "Bad named entity: Integral without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Integral"
+ ]
+ ]
+ },
+ {
+ "input": "∫",
+ "description": "Named entity: Integral; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222b"
+ ]
+ ]
+ },
+ {
+ "input": "&Intersection",
+ "description": "Bad named entity: Intersection without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Intersection"
+ ]
+ ]
+ },
+ {
+ "input": "⋂",
+ "description": "Named entity: Intersection; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c2"
+ ]
+ ]
+ },
+ {
+ "input": "&InvisibleComma",
+ "description": "Bad named entity: InvisibleComma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&InvisibleComma"
+ ]
+ ]
+ },
+ {
+ "input": "⁣",
+ "description": "Named entity: InvisibleComma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2063"
+ ]
+ ]
+ },
+ {
+ "input": "&InvisibleTimes",
+ "description": "Bad named entity: InvisibleTimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&InvisibleTimes"
+ ]
+ ]
+ },
+ {
+ "input": "⁢",
+ "description": "Named entity: InvisibleTimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2062"
+ ]
+ ]
+ },
+ {
+ "input": "&Iogon",
+ "description": "Bad named entity: Iogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Iogon"
+ ]
+ ]
+ },
+ {
+ "input": "Į",
+ "description": "Named entity: Iogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u012e"
+ ]
+ ]
+ },
+ {
+ "input": "&Iopf",
+ "description": "Bad named entity: Iopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Iopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕀",
+ "description": "Named entity: Iopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd40"
+ ]
+ ]
+ },
+ {
+ "input": "&Iota",
+ "description": "Bad named entity: Iota without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Iota"
+ ]
+ ]
+ },
+ {
+ "input": "Ι",
+ "description": "Named entity: Iota; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0399"
+ ]
+ ]
+ },
+ {
+ "input": "&Iscr",
+ "description": "Bad named entity: Iscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Iscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℐ",
+ "description": "Named entity: Iscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2110"
+ ]
+ ]
+ },
+ {
+ "input": "&Itilde",
+ "description": "Bad named entity: Itilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Itilde"
+ ]
+ ]
+ },
+ {
+ "input": "Ĩ",
+ "description": "Named entity: Itilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0128"
+ ]
+ ]
+ },
+ {
+ "input": "&Iukcy",
+ "description": "Bad named entity: Iukcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Iukcy"
+ ]
+ ]
+ },
+ {
+ "input": "І",
+ "description": "Named entity: Iukcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0406"
+ ]
+ ]
+ },
+ {
+ "input": "Ï",
+ "description": "Named entity: Iuml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00cf"
+ ]
+ ]
+ },
+ {
+ "input": "Ï",
+ "description": "Named entity: Iuml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00cf"
+ ]
+ ]
+ },
+ {
+ "input": "&Jcirc",
+ "description": "Bad named entity: Jcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Jcirc"
+ ]
+ ]
+ },
+ {
+ "input": "Ĵ",
+ "description": "Named entity: Jcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0134"
+ ]
+ ]
+ },
+ {
+ "input": "&Jcy",
+ "description": "Bad named entity: Jcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Jcy"
+ ]
+ ]
+ },
+ {
+ "input": "Й",
+ "description": "Named entity: Jcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0419"
+ ]
+ ]
+ },
+ {
+ "input": "&Jfr",
+ "description": "Bad named entity: Jfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Jfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔍",
+ "description": "Named entity: Jfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd0d"
+ ]
+ ]
+ },
+ {
+ "input": "&Jopf",
+ "description": "Bad named entity: Jopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Jopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕁",
+ "description": "Named entity: Jopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd41"
+ ]
+ ]
+ },
+ {
+ "input": "&Jscr",
+ "description": "Bad named entity: Jscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Jscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒥",
+ "description": "Named entity: Jscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udca5"
+ ]
+ ]
+ },
+ {
+ "input": "&Jsercy",
+ "description": "Bad named entity: Jsercy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Jsercy"
+ ]
+ ]
+ },
+ {
+ "input": "Ј",
+ "description": "Named entity: Jsercy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0408"
+ ]
+ ]
+ },
+ {
+ "input": "&Jukcy",
+ "description": "Bad named entity: Jukcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Jukcy"
+ ]
+ ]
+ },
+ {
+ "input": "Є",
+ "description": "Named entity: Jukcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0404"
+ ]
+ ]
+ },
+ {
+ "input": "&KHcy",
+ "description": "Bad named entity: KHcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&KHcy"
+ ]
+ ]
+ },
+ {
+ "input": "Х",
+ "description": "Named entity: KHcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0425"
+ ]
+ ]
+ },
+ {
+ "input": "&KJcy",
+ "description": "Bad named entity: KJcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&KJcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ќ",
+ "description": "Named entity: KJcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u040c"
+ ]
+ ]
+ },
+ {
+ "input": "&Kappa",
+ "description": "Bad named entity: Kappa without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Kappa"
+ ]
+ ]
+ },
+ {
+ "input": "Κ",
+ "description": "Named entity: Kappa; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u039a"
+ ]
+ ]
+ },
+ {
+ "input": "&Kcedil",
+ "description": "Bad named entity: Kcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Kcedil"
+ ]
+ ]
+ },
+ {
+ "input": "Ķ",
+ "description": "Named entity: Kcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0136"
+ ]
+ ]
+ },
+ {
+ "input": "&Kcy",
+ "description": "Bad named entity: Kcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Kcy"
+ ]
+ ]
+ },
+ {
+ "input": "К",
+ "description": "Named entity: Kcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u041a"
+ ]
+ ]
+ },
+ {
+ "input": "&Kfr",
+ "description": "Bad named entity: Kfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Kfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔎",
+ "description": "Named entity: Kfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd0e"
+ ]
+ ]
+ },
+ {
+ "input": "&Kopf",
+ "description": "Bad named entity: Kopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Kopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕂",
+ "description": "Named entity: Kopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd42"
+ ]
+ ]
+ },
+ {
+ "input": "&Kscr",
+ "description": "Bad named entity: Kscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Kscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒦",
+ "description": "Named entity: Kscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udca6"
+ ]
+ ]
+ },
+ {
+ "input": "&LJcy",
+ "description": "Bad named entity: LJcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LJcy"
+ ]
+ ]
+ },
+ {
+ "input": "Љ",
+ "description": "Named entity: LJcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0409"
+ ]
+ ]
+ },
+ {
+ "input": "<",
+ "description": "Named entity: LT without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "<"
+ ]
+ ]
+ },
+ {
+ "input": "<",
+ "description": "Named entity: LT; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "<"
+ ]
+ ]
+ },
+ {
+ "input": "&Lacute",
+ "description": "Bad named entity: Lacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lacute"
+ ]
+ ]
+ },
+ {
+ "input": "Ĺ",
+ "description": "Named entity: Lacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0139"
+ ]
+ ]
+ },
+ {
+ "input": "&Lambda",
+ "description": "Bad named entity: Lambda without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lambda"
+ ]
+ ]
+ },
+ {
+ "input": "Λ",
+ "description": "Named entity: Lambda; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u039b"
+ ]
+ ]
+ },
+ {
+ "input": "&Lang",
+ "description": "Bad named entity: Lang without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lang"
+ ]
+ ]
+ },
+ {
+ "input": "⟪",
+ "description": "Named entity: Lang; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27ea"
+ ]
+ ]
+ },
+ {
+ "input": "&Laplacetrf",
+ "description": "Bad named entity: Laplacetrf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Laplacetrf"
+ ]
+ ]
+ },
+ {
+ "input": "ℒ",
+ "description": "Named entity: Laplacetrf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2112"
+ ]
+ ]
+ },
+ {
+ "input": "&Larr",
+ "description": "Bad named entity: Larr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Larr"
+ ]
+ ]
+ },
+ {
+ "input": "↞",
+ "description": "Named entity: Larr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219e"
+ ]
+ ]
+ },
+ {
+ "input": "&Lcaron",
+ "description": "Bad named entity: Lcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lcaron"
+ ]
+ ]
+ },
+ {
+ "input": "Ľ",
+ "description": "Named entity: Lcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u013d"
+ ]
+ ]
+ },
+ {
+ "input": "&Lcedil",
+ "description": "Bad named entity: Lcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lcedil"
+ ]
+ ]
+ },
+ {
+ "input": "Ļ",
+ "description": "Named entity: Lcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u013b"
+ ]
+ ]
+ },
+ {
+ "input": "&Lcy",
+ "description": "Bad named entity: Lcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lcy"
+ ]
+ ]
+ },
+ {
+ "input": "Л",
+ "description": "Named entity: Lcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u041b"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftAngleBracket",
+ "description": "Bad named entity: LeftAngleBracket without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftAngleBracket"
+ ]
+ ]
+ },
+ {
+ "input": "⟨",
+ "description": "Named entity: LeftAngleBracket; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e8"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftArrow",
+ "description": "Bad named entity: LeftArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftArrow"
+ ]
+ ]
+ },
+ {
+ "input": "←",
+ "description": "Named entity: LeftArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2190"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftArrowBar",
+ "description": "Bad named entity: LeftArrowBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftArrowBar"
+ ]
+ ]
+ },
+ {
+ "input": "⇤",
+ "description": "Named entity: LeftArrowBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21e4"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftArrowRightArrow",
+ "description": "Bad named entity: LeftArrowRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftArrowRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇆",
+ "description": "Named entity: LeftArrowRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c6"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftCeiling",
+ "description": "Bad named entity: LeftCeiling without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftCeiling"
+ ]
+ ]
+ },
+ {
+ "input": "⌈",
+ "description": "Named entity: LeftCeiling; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2308"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftDoubleBracket",
+ "description": "Bad named entity: LeftDoubleBracket without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftDoubleBracket"
+ ]
+ ]
+ },
+ {
+ "input": "⟦",
+ "description": "Named entity: LeftDoubleBracket; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e6"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftDownTeeVector",
+ "description": "Bad named entity: LeftDownTeeVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftDownTeeVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥡",
+ "description": "Named entity: LeftDownTeeVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2961"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftDownVector",
+ "description": "Bad named entity: LeftDownVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftDownVector"
+ ]
+ ]
+ },
+ {
+ "input": "⇃",
+ "description": "Named entity: LeftDownVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c3"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftDownVectorBar",
+ "description": "Bad named entity: LeftDownVectorBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftDownVectorBar"
+ ]
+ ]
+ },
+ {
+ "input": "⥙",
+ "description": "Named entity: LeftDownVectorBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2959"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftFloor",
+ "description": "Bad named entity: LeftFloor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftFloor"
+ ]
+ ]
+ },
+ {
+ "input": "⌊",
+ "description": "Named entity: LeftFloor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u230a"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftRightArrow",
+ "description": "Bad named entity: LeftRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↔",
+ "description": "Named entity: LeftRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2194"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftRightVector",
+ "description": "Bad named entity: LeftRightVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftRightVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥎",
+ "description": "Named entity: LeftRightVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u294e"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftTee",
+ "description": "Bad named entity: LeftTee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftTee"
+ ]
+ ]
+ },
+ {
+ "input": "⊣",
+ "description": "Named entity: LeftTee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a3"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftTeeArrow",
+ "description": "Bad named entity: LeftTeeArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftTeeArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↤",
+ "description": "Named entity: LeftTeeArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a4"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftTeeVector",
+ "description": "Bad named entity: LeftTeeVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftTeeVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥚",
+ "description": "Named entity: LeftTeeVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u295a"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftTriangle",
+ "description": "Bad named entity: LeftTriangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftTriangle"
+ ]
+ ]
+ },
+ {
+ "input": "⊲",
+ "description": "Named entity: LeftTriangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b2"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftTriangleBar",
+ "description": "Bad named entity: LeftTriangleBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftTriangleBar"
+ ]
+ ]
+ },
+ {
+ "input": "⧏",
+ "description": "Named entity: LeftTriangleBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29cf"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftTriangleEqual",
+ "description": "Bad named entity: LeftTriangleEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftTriangleEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⊴",
+ "description": "Named entity: LeftTriangleEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b4"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftUpDownVector",
+ "description": "Bad named entity: LeftUpDownVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftUpDownVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥑",
+ "description": "Named entity: LeftUpDownVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2951"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftUpTeeVector",
+ "description": "Bad named entity: LeftUpTeeVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftUpTeeVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥠",
+ "description": "Named entity: LeftUpTeeVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2960"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftUpVector",
+ "description": "Bad named entity: LeftUpVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftUpVector"
+ ]
+ ]
+ },
+ {
+ "input": "↿",
+ "description": "Named entity: LeftUpVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bf"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftUpVectorBar",
+ "description": "Bad named entity: LeftUpVectorBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftUpVectorBar"
+ ]
+ ]
+ },
+ {
+ "input": "⥘",
+ "description": "Named entity: LeftUpVectorBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2958"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftVector",
+ "description": "Bad named entity: LeftVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftVector"
+ ]
+ ]
+ },
+ {
+ "input": "↼",
+ "description": "Named entity: LeftVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bc"
+ ]
+ ]
+ },
+ {
+ "input": "&LeftVectorBar",
+ "description": "Bad named entity: LeftVectorBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LeftVectorBar"
+ ]
+ ]
+ },
+ {
+ "input": "⥒",
+ "description": "Named entity: LeftVectorBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2952"
+ ]
+ ]
+ },
+ {
+ "input": "&Leftarrow",
+ "description": "Bad named entity: Leftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Leftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇐",
+ "description": "Named entity: Leftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d0"
+ ]
+ ]
+ },
+ {
+ "input": "&Leftrightarrow",
+ "description": "Bad named entity: Leftrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Leftrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇔",
+ "description": "Named entity: Leftrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d4"
+ ]
+ ]
+ },
+ {
+ "input": "&LessEqualGreater",
+ "description": "Bad named entity: LessEqualGreater without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LessEqualGreater"
+ ]
+ ]
+ },
+ {
+ "input": "⋚",
+ "description": "Named entity: LessEqualGreater; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22da"
+ ]
+ ]
+ },
+ {
+ "input": "&LessFullEqual",
+ "description": "Bad named entity: LessFullEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LessFullEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≦",
+ "description": "Named entity: LessFullEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2266"
+ ]
+ ]
+ },
+ {
+ "input": "&LessGreater",
+ "description": "Bad named entity: LessGreater without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LessGreater"
+ ]
+ ]
+ },
+ {
+ "input": "≶",
+ "description": "Named entity: LessGreater; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2276"
+ ]
+ ]
+ },
+ {
+ "input": "&LessLess",
+ "description": "Bad named entity: LessLess without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LessLess"
+ ]
+ ]
+ },
+ {
+ "input": "⪡",
+ "description": "Named entity: LessLess; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa1"
+ ]
+ ]
+ },
+ {
+ "input": "&LessSlantEqual",
+ "description": "Bad named entity: LessSlantEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LessSlantEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⩽",
+ "description": "Named entity: LessSlantEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7d"
+ ]
+ ]
+ },
+ {
+ "input": "&LessTilde",
+ "description": "Bad named entity: LessTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LessTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≲",
+ "description": "Named entity: LessTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2272"
+ ]
+ ]
+ },
+ {
+ "input": "&Lfr",
+ "description": "Bad named entity: Lfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔏",
+ "description": "Named entity: Lfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd0f"
+ ]
+ ]
+ },
+ {
+ "input": "&Ll",
+ "description": "Bad named entity: Ll without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ll"
+ ]
+ ]
+ },
+ {
+ "input": "⋘",
+ "description": "Named entity: Ll; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d8"
+ ]
+ ]
+ },
+ {
+ "input": "&Lleftarrow",
+ "description": "Bad named entity: Lleftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lleftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇚",
+ "description": "Named entity: Lleftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21da"
+ ]
+ ]
+ },
+ {
+ "input": "&Lmidot",
+ "description": "Bad named entity: Lmidot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lmidot"
+ ]
+ ]
+ },
+ {
+ "input": "Ŀ",
+ "description": "Named entity: Lmidot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u013f"
+ ]
+ ]
+ },
+ {
+ "input": "&LongLeftArrow",
+ "description": "Bad named entity: LongLeftArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LongLeftArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟵",
+ "description": "Named entity: LongLeftArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f5"
+ ]
+ ]
+ },
+ {
+ "input": "&LongLeftRightArrow",
+ "description": "Bad named entity: LongLeftRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LongLeftRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟷",
+ "description": "Named entity: LongLeftRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f7"
+ ]
+ ]
+ },
+ {
+ "input": "&LongRightArrow",
+ "description": "Bad named entity: LongRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LongRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟶",
+ "description": "Named entity: LongRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f6"
+ ]
+ ]
+ },
+ {
+ "input": "&Longleftarrow",
+ "description": "Bad named entity: Longleftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Longleftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟸",
+ "description": "Named entity: Longleftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f8"
+ ]
+ ]
+ },
+ {
+ "input": "&Longleftrightarrow",
+ "description": "Bad named entity: Longleftrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Longleftrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟺",
+ "description": "Named entity: Longleftrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27fa"
+ ]
+ ]
+ },
+ {
+ "input": "&Longrightarrow",
+ "description": "Bad named entity: Longrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Longrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟹",
+ "description": "Named entity: Longrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f9"
+ ]
+ ]
+ },
+ {
+ "input": "&Lopf",
+ "description": "Bad named entity: Lopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕃",
+ "description": "Named entity: Lopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd43"
+ ]
+ ]
+ },
+ {
+ "input": "&LowerLeftArrow",
+ "description": "Bad named entity: LowerLeftArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LowerLeftArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↙",
+ "description": "Named entity: LowerLeftArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2199"
+ ]
+ ]
+ },
+ {
+ "input": "&LowerRightArrow",
+ "description": "Bad named entity: LowerRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&LowerRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↘",
+ "description": "Named entity: LowerRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2198"
+ ]
+ ]
+ },
+ {
+ "input": "&Lscr",
+ "description": "Bad named entity: Lscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℒ",
+ "description": "Named entity: Lscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2112"
+ ]
+ ]
+ },
+ {
+ "input": "&Lsh",
+ "description": "Bad named entity: Lsh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lsh"
+ ]
+ ]
+ },
+ {
+ "input": "↰",
+ "description": "Named entity: Lsh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b0"
+ ]
+ ]
+ },
+ {
+ "input": "&Lstrok",
+ "description": "Bad named entity: Lstrok without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lstrok"
+ ]
+ ]
+ },
+ {
+ "input": "Ł",
+ "description": "Named entity: Lstrok; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0141"
+ ]
+ ]
+ },
+ {
+ "input": "&Lt",
+ "description": "Bad named entity: Lt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Lt"
+ ]
+ ]
+ },
+ {
+ "input": "≪",
+ "description": "Named entity: Lt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226a"
+ ]
+ ]
+ },
+ {
+ "input": "&Map",
+ "description": "Bad named entity: Map without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Map"
+ ]
+ ]
+ },
+ {
+ "input": "⤅",
+ "description": "Named entity: Map; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2905"
+ ]
+ ]
+ },
+ {
+ "input": "&Mcy",
+ "description": "Bad named entity: Mcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Mcy"
+ ]
+ ]
+ },
+ {
+ "input": "М",
+ "description": "Named entity: Mcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u041c"
+ ]
+ ]
+ },
+ {
+ "input": "&MediumSpace",
+ "description": "Bad named entity: MediumSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&MediumSpace"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: MediumSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u205f"
+ ]
+ ]
+ },
+ {
+ "input": "&Mellintrf",
+ "description": "Bad named entity: Mellintrf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Mellintrf"
+ ]
+ ]
+ },
+ {
+ "input": "ℳ",
+ "description": "Named entity: Mellintrf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2133"
+ ]
+ ]
+ },
+ {
+ "input": "&Mfr",
+ "description": "Bad named entity: Mfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Mfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔐",
+ "description": "Named entity: Mfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd10"
+ ]
+ ]
+ },
+ {
+ "input": "&MinusPlus",
+ "description": "Bad named entity: MinusPlus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&MinusPlus"
+ ]
+ ]
+ },
+ {
+ "input": "∓",
+ "description": "Named entity: MinusPlus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2213"
+ ]
+ ]
+ },
+ {
+ "input": "&Mopf",
+ "description": "Bad named entity: Mopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Mopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕄",
+ "description": "Named entity: Mopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd44"
+ ]
+ ]
+ },
+ {
+ "input": "&Mscr",
+ "description": "Bad named entity: Mscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Mscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℳ",
+ "description": "Named entity: Mscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2133"
+ ]
+ ]
+ },
+ {
+ "input": "&Mu",
+ "description": "Bad named entity: Mu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Mu"
+ ]
+ ]
+ },
+ {
+ "input": "Μ",
+ "description": "Named entity: Mu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u039c"
+ ]
+ ]
+ },
+ {
+ "input": "&NJcy",
+ "description": "Bad named entity: NJcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NJcy"
+ ]
+ ]
+ },
+ {
+ "input": "Њ",
+ "description": "Named entity: NJcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u040a"
+ ]
+ ]
+ },
+ {
+ "input": "&Nacute",
+ "description": "Bad named entity: Nacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Nacute"
+ ]
+ ]
+ },
+ {
+ "input": "Ń",
+ "description": "Named entity: Nacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0143"
+ ]
+ ]
+ },
+ {
+ "input": "&Ncaron",
+ "description": "Bad named entity: Ncaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ncaron"
+ ]
+ ]
+ },
+ {
+ "input": "Ň",
+ "description": "Named entity: Ncaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0147"
+ ]
+ ]
+ },
+ {
+ "input": "&Ncedil",
+ "description": "Bad named entity: Ncedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ncedil"
+ ]
+ ]
+ },
+ {
+ "input": "Ņ",
+ "description": "Named entity: Ncedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0145"
+ ]
+ ]
+ },
+ {
+ "input": "&Ncy",
+ "description": "Bad named entity: Ncy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ncy"
+ ]
+ ]
+ },
+ {
+ "input": "Н",
+ "description": "Named entity: Ncy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u041d"
+ ]
+ ]
+ },
+ {
+ "input": "&NegativeMediumSpace",
+ "description": "Bad named entity: NegativeMediumSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NegativeMediumSpace"
+ ]
+ ]
+ },
+ {
+ "input": "​",
+ "description": "Named entity: NegativeMediumSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200b"
+ ]
+ ]
+ },
+ {
+ "input": "&NegativeThickSpace",
+ "description": "Bad named entity: NegativeThickSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NegativeThickSpace"
+ ]
+ ]
+ },
+ {
+ "input": "​",
+ "description": "Named entity: NegativeThickSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200b"
+ ]
+ ]
+ },
+ {
+ "input": "&NegativeThinSpace",
+ "description": "Bad named entity: NegativeThinSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NegativeThinSpace"
+ ]
+ ]
+ },
+ {
+ "input": "​",
+ "description": "Named entity: NegativeThinSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200b"
+ ]
+ ]
+ },
+ {
+ "input": "&NegativeVeryThinSpace",
+ "description": "Bad named entity: NegativeVeryThinSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NegativeVeryThinSpace"
+ ]
+ ]
+ },
+ {
+ "input": "​",
+ "description": "Named entity: NegativeVeryThinSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200b"
+ ]
+ ]
+ },
+ {
+ "input": "&NestedGreaterGreater",
+ "description": "Bad named entity: NestedGreaterGreater without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NestedGreaterGreater"
+ ]
+ ]
+ },
+ {
+ "input": "≫",
+ "description": "Named entity: NestedGreaterGreater; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226b"
+ ]
+ ]
+ },
+ {
+ "input": "&NestedLessLess",
+ "description": "Bad named entity: NestedLessLess without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NestedLessLess"
+ ]
+ ]
+ },
+ {
+ "input": "≪",
+ "description": "Named entity: NestedLessLess; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226a"
+ ]
+ ]
+ },
+ {
+ "input": "&NewLine",
+ "description": "Bad named entity: NewLine without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NewLine"
+ ]
+ ]
+ },
+ {
+ "input": "
",
+ "description": "Named entity: NewLine; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\n"
+ ]
+ ]
+ },
+ {
+ "input": "&Nfr",
+ "description": "Bad named entity: Nfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Nfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔑",
+ "description": "Named entity: Nfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd11"
+ ]
+ ]
+ },
+ {
+ "input": "&NoBreak",
+ "description": "Bad named entity: NoBreak without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NoBreak"
+ ]
+ ]
+ },
+ {
+ "input": "⁠",
+ "description": "Named entity: NoBreak; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2060"
+ ]
+ ]
+ },
+ {
+ "input": "&NonBreakingSpace",
+ "description": "Bad named entity: NonBreakingSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NonBreakingSpace"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: NonBreakingSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a0"
+ ]
+ ]
+ },
+ {
+ "input": "&Nopf",
+ "description": "Bad named entity: Nopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Nopf"
+ ]
+ ]
+ },
+ {
+ "input": "ℕ",
+ "description": "Named entity: Nopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2115"
+ ]
+ ]
+ },
+ {
+ "input": "&Not",
+ "description": "Bad named entity: Not without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Not"
+ ]
+ ]
+ },
+ {
+ "input": "⫬",
+ "description": "Named entity: Not; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aec"
+ ]
+ ]
+ },
+ {
+ "input": "&NotCongruent",
+ "description": "Bad named entity: NotCongruent without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotCongruent"
+ ]
+ ]
+ },
+ {
+ "input": "≢",
+ "description": "Named entity: NotCongruent; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2262"
+ ]
+ ]
+ },
+ {
+ "input": "&NotCupCap",
+ "description": "Bad named entity: NotCupCap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotCupCap"
+ ]
+ ]
+ },
+ {
+ "input": "≭",
+ "description": "Named entity: NotCupCap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226d"
+ ]
+ ]
+ },
+ {
+ "input": "&NotDoubleVerticalBar",
+ "description": "Bad named entity: NotDoubleVerticalBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotDoubleVerticalBar"
+ ]
+ ]
+ },
+ {
+ "input": "∦",
+ "description": "Named entity: NotDoubleVerticalBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2226"
+ ]
+ ]
+ },
+ {
+ "input": "&NotElement",
+ "description": "Bad named entity: NotElement without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotElement"
+ ]
+ ]
+ },
+ {
+ "input": "∉",
+ "description": "Named entity: NotElement; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2209"
+ ]
+ ]
+ },
+ {
+ "input": "&NotEqual",
+ "description": "Bad named entity: NotEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≠",
+ "description": "Named entity: NotEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2260"
+ ]
+ ]
+ },
+ {
+ "input": "&NotEqualTilde",
+ "description": "Bad named entity: NotEqualTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotEqualTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≂̸",
+ "description": "Named entity: NotEqualTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2242\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotExists",
+ "description": "Bad named entity: NotExists without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotExists"
+ ]
+ ]
+ },
+ {
+ "input": "∄",
+ "description": "Named entity: NotExists; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2204"
+ ]
+ ]
+ },
+ {
+ "input": "&NotGreater",
+ "description": "Bad named entity: NotGreater without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotGreater"
+ ]
+ ]
+ },
+ {
+ "input": "≯",
+ "description": "Named entity: NotGreater; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226f"
+ ]
+ ]
+ },
+ {
+ "input": "&NotGreaterEqual",
+ "description": "Bad named entity: NotGreaterEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotGreaterEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≱",
+ "description": "Named entity: NotGreaterEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2271"
+ ]
+ ]
+ },
+ {
+ "input": "&NotGreaterFullEqual",
+ "description": "Bad named entity: NotGreaterFullEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotGreaterFullEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≧̸",
+ "description": "Named entity: NotGreaterFullEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2267\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotGreaterGreater",
+ "description": "Bad named entity: NotGreaterGreater without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotGreaterGreater"
+ ]
+ ]
+ },
+ {
+ "input": "≫̸",
+ "description": "Named entity: NotGreaterGreater; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226b\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotGreaterLess",
+ "description": "Bad named entity: NotGreaterLess without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotGreaterLess"
+ ]
+ ]
+ },
+ {
+ "input": "≹",
+ "description": "Named entity: NotGreaterLess; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2279"
+ ]
+ ]
+ },
+ {
+ "input": "&NotGreaterSlantEqual",
+ "description": "Bad named entity: NotGreaterSlantEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotGreaterSlantEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⩾̸",
+ "description": "Named entity: NotGreaterSlantEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7e\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotGreaterTilde",
+ "description": "Bad named entity: NotGreaterTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotGreaterTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≵",
+ "description": "Named entity: NotGreaterTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2275"
+ ]
+ ]
+ },
+ {
+ "input": "&NotHumpDownHump",
+ "description": "Bad named entity: NotHumpDownHump without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotHumpDownHump"
+ ]
+ ]
+ },
+ {
+ "input": "≎̸",
+ "description": "Named entity: NotHumpDownHump; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224e\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotHumpEqual",
+ "description": "Bad named entity: NotHumpEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotHumpEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≏̸",
+ "description": "Named entity: NotHumpEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224f\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLeftTriangle",
+ "description": "Bad named entity: NotLeftTriangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLeftTriangle"
+ ]
+ ]
+ },
+ {
+ "input": "⋪",
+ "description": "Named entity: NotLeftTriangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ea"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLeftTriangleBar",
+ "description": "Bad named entity: NotLeftTriangleBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLeftTriangleBar"
+ ]
+ ]
+ },
+ {
+ "input": "⧏̸",
+ "description": "Named entity: NotLeftTriangleBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29cf\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLeftTriangleEqual",
+ "description": "Bad named entity: NotLeftTriangleEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLeftTriangleEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⋬",
+ "description": "Named entity: NotLeftTriangleEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ec"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLess",
+ "description": "Bad named entity: NotLess without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLess"
+ ]
+ ]
+ },
+ {
+ "input": "≮",
+ "description": "Named entity: NotLess; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226e"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLessEqual",
+ "description": "Bad named entity: NotLessEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLessEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≰",
+ "description": "Named entity: NotLessEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2270"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLessGreater",
+ "description": "Bad named entity: NotLessGreater without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLessGreater"
+ ]
+ ]
+ },
+ {
+ "input": "≸",
+ "description": "Named entity: NotLessGreater; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2278"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLessLess",
+ "description": "Bad named entity: NotLessLess without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLessLess"
+ ]
+ ]
+ },
+ {
+ "input": "≪̸",
+ "description": "Named entity: NotLessLess; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226a\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLessSlantEqual",
+ "description": "Bad named entity: NotLessSlantEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLessSlantEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⩽̸",
+ "description": "Named entity: NotLessSlantEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7d\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotLessTilde",
+ "description": "Bad named entity: NotLessTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotLessTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≴",
+ "description": "Named entity: NotLessTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2274"
+ ]
+ ]
+ },
+ {
+ "input": "&NotNestedGreaterGreater",
+ "description": "Bad named entity: NotNestedGreaterGreater without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotNestedGreaterGreater"
+ ]
+ ]
+ },
+ {
+ "input": "⪢̸",
+ "description": "Named entity: NotNestedGreaterGreater; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa2\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotNestedLessLess",
+ "description": "Bad named entity: NotNestedLessLess without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotNestedLessLess"
+ ]
+ ]
+ },
+ {
+ "input": "⪡̸",
+ "description": "Named entity: NotNestedLessLess; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa1\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotPrecedes",
+ "description": "Bad named entity: NotPrecedes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotPrecedes"
+ ]
+ ]
+ },
+ {
+ "input": "⊀",
+ "description": "Named entity: NotPrecedes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2280"
+ ]
+ ]
+ },
+ {
+ "input": "&NotPrecedesEqual",
+ "description": "Bad named entity: NotPrecedesEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotPrecedesEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⪯̸",
+ "description": "Named entity: NotPrecedesEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aaf\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotPrecedesSlantEqual",
+ "description": "Bad named entity: NotPrecedesSlantEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotPrecedesSlantEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⋠",
+ "description": "Named entity: NotPrecedesSlantEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e0"
+ ]
+ ]
+ },
+ {
+ "input": "&NotReverseElement",
+ "description": "Bad named entity: NotReverseElement without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotReverseElement"
+ ]
+ ]
+ },
+ {
+ "input": "∌",
+ "description": "Named entity: NotReverseElement; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220c"
+ ]
+ ]
+ },
+ {
+ "input": "&NotRightTriangle",
+ "description": "Bad named entity: NotRightTriangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotRightTriangle"
+ ]
+ ]
+ },
+ {
+ "input": "⋫",
+ "description": "Named entity: NotRightTriangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22eb"
+ ]
+ ]
+ },
+ {
+ "input": "&NotRightTriangleBar",
+ "description": "Bad named entity: NotRightTriangleBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotRightTriangleBar"
+ ]
+ ]
+ },
+ {
+ "input": "⧐̸",
+ "description": "Named entity: NotRightTriangleBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29d0\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotRightTriangleEqual",
+ "description": "Bad named entity: NotRightTriangleEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotRightTriangleEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⋭",
+ "description": "Named entity: NotRightTriangleEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ed"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSquareSubset",
+ "description": "Bad named entity: NotSquareSubset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSquareSubset"
+ ]
+ ]
+ },
+ {
+ "input": "⊏̸",
+ "description": "Named entity: NotSquareSubset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228f\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSquareSubsetEqual",
+ "description": "Bad named entity: NotSquareSubsetEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSquareSubsetEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⋢",
+ "description": "Named entity: NotSquareSubsetEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e2"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSquareSuperset",
+ "description": "Bad named entity: NotSquareSuperset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSquareSuperset"
+ ]
+ ]
+ },
+ {
+ "input": "⊐̸",
+ "description": "Named entity: NotSquareSuperset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2290\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSquareSupersetEqual",
+ "description": "Bad named entity: NotSquareSupersetEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSquareSupersetEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⋣",
+ "description": "Named entity: NotSquareSupersetEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e3"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSubset",
+ "description": "Bad named entity: NotSubset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSubset"
+ ]
+ ]
+ },
+ {
+ "input": "⊂⃒",
+ "description": "Named entity: NotSubset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2282\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSubsetEqual",
+ "description": "Bad named entity: NotSubsetEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSubsetEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⊈",
+ "description": "Named entity: NotSubsetEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2288"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSucceeds",
+ "description": "Bad named entity: NotSucceeds without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSucceeds"
+ ]
+ ]
+ },
+ {
+ "input": "⊁",
+ "description": "Named entity: NotSucceeds; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2281"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSucceedsEqual",
+ "description": "Bad named entity: NotSucceedsEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSucceedsEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⪰̸",
+ "description": "Named entity: NotSucceedsEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab0\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSucceedsSlantEqual",
+ "description": "Bad named entity: NotSucceedsSlantEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSucceedsSlantEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⋡",
+ "description": "Named entity: NotSucceedsSlantEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e1"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSucceedsTilde",
+ "description": "Bad named entity: NotSucceedsTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSucceedsTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≿̸",
+ "description": "Named entity: NotSucceedsTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227f\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSuperset",
+ "description": "Bad named entity: NotSuperset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSuperset"
+ ]
+ ]
+ },
+ {
+ "input": "⊃⃒",
+ "description": "Named entity: NotSuperset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2283\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&NotSupersetEqual",
+ "description": "Bad named entity: NotSupersetEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotSupersetEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⊉",
+ "description": "Named entity: NotSupersetEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2289"
+ ]
+ ]
+ },
+ {
+ "input": "&NotTilde",
+ "description": "Bad named entity: NotTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≁",
+ "description": "Named entity: NotTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2241"
+ ]
+ ]
+ },
+ {
+ "input": "&NotTildeEqual",
+ "description": "Bad named entity: NotTildeEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotTildeEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≄",
+ "description": "Named entity: NotTildeEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2244"
+ ]
+ ]
+ },
+ {
+ "input": "&NotTildeFullEqual",
+ "description": "Bad named entity: NotTildeFullEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotTildeFullEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≇",
+ "description": "Named entity: NotTildeFullEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2247"
+ ]
+ ]
+ },
+ {
+ "input": "&NotTildeTilde",
+ "description": "Bad named entity: NotTildeTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotTildeTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≉",
+ "description": "Named entity: NotTildeTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2249"
+ ]
+ ]
+ },
+ {
+ "input": "&NotVerticalBar",
+ "description": "Bad named entity: NotVerticalBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&NotVerticalBar"
+ ]
+ ]
+ },
+ {
+ "input": "∤",
+ "description": "Named entity: NotVerticalBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2224"
+ ]
+ ]
+ },
+ {
+ "input": "&Nscr",
+ "description": "Bad named entity: Nscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Nscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒩",
+ "description": "Named entity: Nscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udca9"
+ ]
+ ]
+ },
+ {
+ "input": "Ñ",
+ "description": "Named entity: Ntilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d1"
+ ]
+ ]
+ },
+ {
+ "input": "Ñ",
+ "description": "Named entity: Ntilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d1"
+ ]
+ ]
+ },
+ {
+ "input": "&Nu",
+ "description": "Bad named entity: Nu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Nu"
+ ]
+ ]
+ },
+ {
+ "input": "Ν",
+ "description": "Named entity: Nu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u039d"
+ ]
+ ]
+ },
+ {
+ "input": "&OElig",
+ "description": "Bad named entity: OElig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&OElig"
+ ]
+ ]
+ },
+ {
+ "input": "Œ",
+ "description": "Named entity: OElig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0152"
+ ]
+ ]
+ },
+ {
+ "input": "Ó",
+ "description": "Named entity: Oacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d3"
+ ]
+ ]
+ },
+ {
+ "input": "Ó",
+ "description": "Named entity: Oacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d3"
+ ]
+ ]
+ },
+ {
+ "input": "Ô",
+ "description": "Named entity: Ocirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d4"
+ ]
+ ]
+ },
+ {
+ "input": "Ô",
+ "description": "Named entity: Ocirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d4"
+ ]
+ ]
+ },
+ {
+ "input": "&Ocy",
+ "description": "Bad named entity: Ocy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ocy"
+ ]
+ ]
+ },
+ {
+ "input": "О",
+ "description": "Named entity: Ocy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u041e"
+ ]
+ ]
+ },
+ {
+ "input": "&Odblac",
+ "description": "Bad named entity: Odblac without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Odblac"
+ ]
+ ]
+ },
+ {
+ "input": "Ő",
+ "description": "Named entity: Odblac; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0150"
+ ]
+ ]
+ },
+ {
+ "input": "&Ofr",
+ "description": "Bad named entity: Ofr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ofr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔒",
+ "description": "Named entity: Ofr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd12"
+ ]
+ ]
+ },
+ {
+ "input": "Ò",
+ "description": "Named entity: Ograve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d2"
+ ]
+ ]
+ },
+ {
+ "input": "Ò",
+ "description": "Named entity: Ograve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d2"
+ ]
+ ]
+ },
+ {
+ "input": "&Omacr",
+ "description": "Bad named entity: Omacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Omacr"
+ ]
+ ]
+ },
+ {
+ "input": "Ō",
+ "description": "Named entity: Omacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u014c"
+ ]
+ ]
+ },
+ {
+ "input": "&Omega",
+ "description": "Bad named entity: Omega without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Omega"
+ ]
+ ]
+ },
+ {
+ "input": "Ω",
+ "description": "Named entity: Omega; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a9"
+ ]
+ ]
+ },
+ {
+ "input": "&Omicron",
+ "description": "Bad named entity: Omicron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Omicron"
+ ]
+ ]
+ },
+ {
+ "input": "Ο",
+ "description": "Named entity: Omicron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u039f"
+ ]
+ ]
+ },
+ {
+ "input": "&Oopf",
+ "description": "Bad named entity: Oopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Oopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕆",
+ "description": "Named entity: Oopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd46"
+ ]
+ ]
+ },
+ {
+ "input": "&OpenCurlyDoubleQuote",
+ "description": "Bad named entity: OpenCurlyDoubleQuote without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&OpenCurlyDoubleQuote"
+ ]
+ ]
+ },
+ {
+ "input": "“",
+ "description": "Named entity: OpenCurlyDoubleQuote; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201c"
+ ]
+ ]
+ },
+ {
+ "input": "&OpenCurlyQuote",
+ "description": "Bad named entity: OpenCurlyQuote without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&OpenCurlyQuote"
+ ]
+ ]
+ },
+ {
+ "input": "‘",
+ "description": "Named entity: OpenCurlyQuote; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2018"
+ ]
+ ]
+ },
+ {
+ "input": "&Or",
+ "description": "Bad named entity: Or without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Or"
+ ]
+ ]
+ },
+ {
+ "input": "⩔",
+ "description": "Named entity: Or; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a54"
+ ]
+ ]
+ },
+ {
+ "input": "&Oscr",
+ "description": "Bad named entity: Oscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Oscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒪",
+ "description": "Named entity: Oscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcaa"
+ ]
+ ]
+ },
+ {
+ "input": "Ø",
+ "description": "Named entity: Oslash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d8"
+ ]
+ ]
+ },
+ {
+ "input": "Ø",
+ "description": "Named entity: Oslash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d8"
+ ]
+ ]
+ },
+ {
+ "input": "Õ",
+ "description": "Named entity: Otilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d5"
+ ]
+ ]
+ },
+ {
+ "input": "Õ",
+ "description": "Named entity: Otilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d5"
+ ]
+ ]
+ },
+ {
+ "input": "&Otimes",
+ "description": "Bad named entity: Otimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Otimes"
+ ]
+ ]
+ },
+ {
+ "input": "⨷",
+ "description": "Named entity: Otimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a37"
+ ]
+ ]
+ },
+ {
+ "input": "Ö",
+ "description": "Named entity: Ouml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d6"
+ ]
+ ]
+ },
+ {
+ "input": "Ö",
+ "description": "Named entity: Ouml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d6"
+ ]
+ ]
+ },
+ {
+ "input": "&OverBar",
+ "description": "Bad named entity: OverBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&OverBar"
+ ]
+ ]
+ },
+ {
+ "input": "‾",
+ "description": "Named entity: OverBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u203e"
+ ]
+ ]
+ },
+ {
+ "input": "&OverBrace",
+ "description": "Bad named entity: OverBrace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&OverBrace"
+ ]
+ ]
+ },
+ {
+ "input": "⏞",
+ "description": "Named entity: OverBrace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23de"
+ ]
+ ]
+ },
+ {
+ "input": "&OverBracket",
+ "description": "Bad named entity: OverBracket without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&OverBracket"
+ ]
+ ]
+ },
+ {
+ "input": "⎴",
+ "description": "Named entity: OverBracket; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b4"
+ ]
+ ]
+ },
+ {
+ "input": "&OverParenthesis",
+ "description": "Bad named entity: OverParenthesis without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&OverParenthesis"
+ ]
+ ]
+ },
+ {
+ "input": "⏜",
+ "description": "Named entity: OverParenthesis; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23dc"
+ ]
+ ]
+ },
+ {
+ "input": "&PartialD",
+ "description": "Bad named entity: PartialD without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&PartialD"
+ ]
+ ]
+ },
+ {
+ "input": "∂",
+ "description": "Named entity: PartialD; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2202"
+ ]
+ ]
+ },
+ {
+ "input": "&Pcy",
+ "description": "Bad named entity: Pcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Pcy"
+ ]
+ ]
+ },
+ {
+ "input": "П",
+ "description": "Named entity: Pcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u041f"
+ ]
+ ]
+ },
+ {
+ "input": "&Pfr",
+ "description": "Bad named entity: Pfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Pfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔓",
+ "description": "Named entity: Pfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd13"
+ ]
+ ]
+ },
+ {
+ "input": "&Phi",
+ "description": "Bad named entity: Phi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Phi"
+ ]
+ ]
+ },
+ {
+ "input": "Φ",
+ "description": "Named entity: Phi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a6"
+ ]
+ ]
+ },
+ {
+ "input": "&Pi",
+ "description": "Bad named entity: Pi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Pi"
+ ]
+ ]
+ },
+ {
+ "input": "Π",
+ "description": "Named entity: Pi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a0"
+ ]
+ ]
+ },
+ {
+ "input": "&PlusMinus",
+ "description": "Bad named entity: PlusMinus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&PlusMinus"
+ ]
+ ]
+ },
+ {
+ "input": "±",
+ "description": "Named entity: PlusMinus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b1"
+ ]
+ ]
+ },
+ {
+ "input": "&Poincareplane",
+ "description": "Bad named entity: Poincareplane without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Poincareplane"
+ ]
+ ]
+ },
+ {
+ "input": "ℌ",
+ "description": "Named entity: Poincareplane; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210c"
+ ]
+ ]
+ },
+ {
+ "input": "&Popf",
+ "description": "Bad named entity: Popf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Popf"
+ ]
+ ]
+ },
+ {
+ "input": "ℙ",
+ "description": "Named entity: Popf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2119"
+ ]
+ ]
+ },
+ {
+ "input": "&Pr",
+ "description": "Bad named entity: Pr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Pr"
+ ]
+ ]
+ },
+ {
+ "input": "⪻",
+ "description": "Named entity: Pr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2abb"
+ ]
+ ]
+ },
+ {
+ "input": "&Precedes",
+ "description": "Bad named entity: Precedes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Precedes"
+ ]
+ ]
+ },
+ {
+ "input": "≺",
+ "description": "Named entity: Precedes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227a"
+ ]
+ ]
+ },
+ {
+ "input": "&PrecedesEqual",
+ "description": "Bad named entity: PrecedesEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&PrecedesEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⪯",
+ "description": "Named entity: PrecedesEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aaf"
+ ]
+ ]
+ },
+ {
+ "input": "&PrecedesSlantEqual",
+ "description": "Bad named entity: PrecedesSlantEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&PrecedesSlantEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≼",
+ "description": "Named entity: PrecedesSlantEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227c"
+ ]
+ ]
+ },
+ {
+ "input": "&PrecedesTilde",
+ "description": "Bad named entity: PrecedesTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&PrecedesTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≾",
+ "description": "Named entity: PrecedesTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227e"
+ ]
+ ]
+ },
+ {
+ "input": "&Prime",
+ "description": "Bad named entity: Prime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Prime"
+ ]
+ ]
+ },
+ {
+ "input": "″",
+ "description": "Named entity: Prime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2033"
+ ]
+ ]
+ },
+ {
+ "input": "&Product",
+ "description": "Bad named entity: Product without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Product"
+ ]
+ ]
+ },
+ {
+ "input": "∏",
+ "description": "Named entity: Product; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220f"
+ ]
+ ]
+ },
+ {
+ "input": "&Proportion",
+ "description": "Bad named entity: Proportion without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Proportion"
+ ]
+ ]
+ },
+ {
+ "input": "∷",
+ "description": "Named entity: Proportion; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2237"
+ ]
+ ]
+ },
+ {
+ "input": "&Proportional",
+ "description": "Bad named entity: Proportional without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Proportional"
+ ]
+ ]
+ },
+ {
+ "input": "∝",
+ "description": "Named entity: Proportional; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221d"
+ ]
+ ]
+ },
+ {
+ "input": "&Pscr",
+ "description": "Bad named entity: Pscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Pscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒫",
+ "description": "Named entity: Pscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcab"
+ ]
+ ]
+ },
+ {
+ "input": "&Psi",
+ "description": "Bad named entity: Psi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Psi"
+ ]
+ ]
+ },
+ {
+ "input": "Ψ",
+ "description": "Named entity: Psi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a8"
+ ]
+ ]
+ },
+ {
+ "input": """,
+ "description": "Named entity: QUOT without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\""
+ ]
+ ]
+ },
+ {
+ "input": """,
+ "description": "Named entity: QUOT; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\""
+ ]
+ ]
+ },
+ {
+ "input": "&Qfr",
+ "description": "Bad named entity: Qfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Qfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔔",
+ "description": "Named entity: Qfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd14"
+ ]
+ ]
+ },
+ {
+ "input": "&Qopf",
+ "description": "Bad named entity: Qopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Qopf"
+ ]
+ ]
+ },
+ {
+ "input": "ℚ",
+ "description": "Named entity: Qopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211a"
+ ]
+ ]
+ },
+ {
+ "input": "&Qscr",
+ "description": "Bad named entity: Qscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Qscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒬",
+ "description": "Named entity: Qscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcac"
+ ]
+ ]
+ },
+ {
+ "input": "&RBarr",
+ "description": "Bad named entity: RBarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RBarr"
+ ]
+ ]
+ },
+ {
+ "input": "⤐",
+ "description": "Named entity: RBarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2910"
+ ]
+ ]
+ },
+ {
+ "input": "®",
+ "description": "Named entity: REG without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ae"
+ ]
+ ]
+ },
+ {
+ "input": "®",
+ "description": "Named entity: REG; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ae"
+ ]
+ ]
+ },
+ {
+ "input": "&Racute",
+ "description": "Bad named entity: Racute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Racute"
+ ]
+ ]
+ },
+ {
+ "input": "Ŕ",
+ "description": "Named entity: Racute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0154"
+ ]
+ ]
+ },
+ {
+ "input": "&Rang",
+ "description": "Bad named entity: Rang without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rang"
+ ]
+ ]
+ },
+ {
+ "input": "⟫",
+ "description": "Named entity: Rang; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27eb"
+ ]
+ ]
+ },
+ {
+ "input": "&Rarr",
+ "description": "Bad named entity: Rarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rarr"
+ ]
+ ]
+ },
+ {
+ "input": "↠",
+ "description": "Named entity: Rarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a0"
+ ]
+ ]
+ },
+ {
+ "input": "&Rarrtl",
+ "description": "Bad named entity: Rarrtl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rarrtl"
+ ]
+ ]
+ },
+ {
+ "input": "⤖",
+ "description": "Named entity: Rarrtl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2916"
+ ]
+ ]
+ },
+ {
+ "input": "&Rcaron",
+ "description": "Bad named entity: Rcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rcaron"
+ ]
+ ]
+ },
+ {
+ "input": "Ř",
+ "description": "Named entity: Rcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0158"
+ ]
+ ]
+ },
+ {
+ "input": "&Rcedil",
+ "description": "Bad named entity: Rcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rcedil"
+ ]
+ ]
+ },
+ {
+ "input": "Ŗ",
+ "description": "Named entity: Rcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0156"
+ ]
+ ]
+ },
+ {
+ "input": "&Rcy",
+ "description": "Bad named entity: Rcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rcy"
+ ]
+ ]
+ },
+ {
+ "input": "Р",
+ "description": "Named entity: Rcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0420"
+ ]
+ ]
+ },
+ {
+ "input": "&Re",
+ "description": "Bad named entity: Re without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Re"
+ ]
+ ]
+ },
+ {
+ "input": "ℜ",
+ "description": "Named entity: Re; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211c"
+ ]
+ ]
+ },
+ {
+ "input": "&ReverseElement",
+ "description": "Bad named entity: ReverseElement without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ReverseElement"
+ ]
+ ]
+ },
+ {
+ "input": "∋",
+ "description": "Named entity: ReverseElement; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220b"
+ ]
+ ]
+ },
+ {
+ "input": "&ReverseEquilibrium",
+ "description": "Bad named entity: ReverseEquilibrium without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ReverseEquilibrium"
+ ]
+ ]
+ },
+ {
+ "input": "⇋",
+ "description": "Named entity: ReverseEquilibrium; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cb"
+ ]
+ ]
+ },
+ {
+ "input": "&ReverseUpEquilibrium",
+ "description": "Bad named entity: ReverseUpEquilibrium without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ReverseUpEquilibrium"
+ ]
+ ]
+ },
+ {
+ "input": "⥯",
+ "description": "Named entity: ReverseUpEquilibrium; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u296f"
+ ]
+ ]
+ },
+ {
+ "input": "&Rfr",
+ "description": "Bad named entity: Rfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rfr"
+ ]
+ ]
+ },
+ {
+ "input": "ℜ",
+ "description": "Named entity: Rfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211c"
+ ]
+ ]
+ },
+ {
+ "input": "&Rho",
+ "description": "Bad named entity: Rho without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rho"
+ ]
+ ]
+ },
+ {
+ "input": "Ρ",
+ "description": "Named entity: Rho; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a1"
+ ]
+ ]
+ },
+ {
+ "input": "&RightAngleBracket",
+ "description": "Bad named entity: RightAngleBracket without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightAngleBracket"
+ ]
+ ]
+ },
+ {
+ "input": "⟩",
+ "description": "Named entity: RightAngleBracket; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e9"
+ ]
+ ]
+ },
+ {
+ "input": "&RightArrow",
+ "description": "Bad named entity: RightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "→",
+ "description": "Named entity: RightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2192"
+ ]
+ ]
+ },
+ {
+ "input": "&RightArrowBar",
+ "description": "Bad named entity: RightArrowBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightArrowBar"
+ ]
+ ]
+ },
+ {
+ "input": "⇥",
+ "description": "Named entity: RightArrowBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21e5"
+ ]
+ ]
+ },
+ {
+ "input": "&RightArrowLeftArrow",
+ "description": "Bad named entity: RightArrowLeftArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightArrowLeftArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇄",
+ "description": "Named entity: RightArrowLeftArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c4"
+ ]
+ ]
+ },
+ {
+ "input": "&RightCeiling",
+ "description": "Bad named entity: RightCeiling without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightCeiling"
+ ]
+ ]
+ },
+ {
+ "input": "⌉",
+ "description": "Named entity: RightCeiling; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2309"
+ ]
+ ]
+ },
+ {
+ "input": "&RightDoubleBracket",
+ "description": "Bad named entity: RightDoubleBracket without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightDoubleBracket"
+ ]
+ ]
+ },
+ {
+ "input": "⟧",
+ "description": "Named entity: RightDoubleBracket; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e7"
+ ]
+ ]
+ },
+ {
+ "input": "&RightDownTeeVector",
+ "description": "Bad named entity: RightDownTeeVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightDownTeeVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥝",
+ "description": "Named entity: RightDownTeeVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u295d"
+ ]
+ ]
+ },
+ {
+ "input": "&RightDownVector",
+ "description": "Bad named entity: RightDownVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightDownVector"
+ ]
+ ]
+ },
+ {
+ "input": "⇂",
+ "description": "Named entity: RightDownVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c2"
+ ]
+ ]
+ },
+ {
+ "input": "&RightDownVectorBar",
+ "description": "Bad named entity: RightDownVectorBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightDownVectorBar"
+ ]
+ ]
+ },
+ {
+ "input": "⥕",
+ "description": "Named entity: RightDownVectorBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2955"
+ ]
+ ]
+ },
+ {
+ "input": "&RightFloor",
+ "description": "Bad named entity: RightFloor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightFloor"
+ ]
+ ]
+ },
+ {
+ "input": "⌋",
+ "description": "Named entity: RightFloor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u230b"
+ ]
+ ]
+ },
+ {
+ "input": "&RightTee",
+ "description": "Bad named entity: RightTee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightTee"
+ ]
+ ]
+ },
+ {
+ "input": "⊢",
+ "description": "Named entity: RightTee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a2"
+ ]
+ ]
+ },
+ {
+ "input": "&RightTeeArrow",
+ "description": "Bad named entity: RightTeeArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightTeeArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↦",
+ "description": "Named entity: RightTeeArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a6"
+ ]
+ ]
+ },
+ {
+ "input": "&RightTeeVector",
+ "description": "Bad named entity: RightTeeVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightTeeVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥛",
+ "description": "Named entity: RightTeeVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u295b"
+ ]
+ ]
+ },
+ {
+ "input": "&RightTriangle",
+ "description": "Bad named entity: RightTriangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightTriangle"
+ ]
+ ]
+ },
+ {
+ "input": "⊳",
+ "description": "Named entity: RightTriangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b3"
+ ]
+ ]
+ },
+ {
+ "input": "&RightTriangleBar",
+ "description": "Bad named entity: RightTriangleBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightTriangleBar"
+ ]
+ ]
+ },
+ {
+ "input": "⧐",
+ "description": "Named entity: RightTriangleBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29d0"
+ ]
+ ]
+ },
+ {
+ "input": "&RightTriangleEqual",
+ "description": "Bad named entity: RightTriangleEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightTriangleEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⊵",
+ "description": "Named entity: RightTriangleEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b5"
+ ]
+ ]
+ },
+ {
+ "input": "&RightUpDownVector",
+ "description": "Bad named entity: RightUpDownVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightUpDownVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥏",
+ "description": "Named entity: RightUpDownVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u294f"
+ ]
+ ]
+ },
+ {
+ "input": "&RightUpTeeVector",
+ "description": "Bad named entity: RightUpTeeVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightUpTeeVector"
+ ]
+ ]
+ },
+ {
+ "input": "⥜",
+ "description": "Named entity: RightUpTeeVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u295c"
+ ]
+ ]
+ },
+ {
+ "input": "&RightUpVector",
+ "description": "Bad named entity: RightUpVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightUpVector"
+ ]
+ ]
+ },
+ {
+ "input": "↾",
+ "description": "Named entity: RightUpVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21be"
+ ]
+ ]
+ },
+ {
+ "input": "&RightUpVectorBar",
+ "description": "Bad named entity: RightUpVectorBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightUpVectorBar"
+ ]
+ ]
+ },
+ {
+ "input": "⥔",
+ "description": "Named entity: RightUpVectorBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2954"
+ ]
+ ]
+ },
+ {
+ "input": "&RightVector",
+ "description": "Bad named entity: RightVector without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightVector"
+ ]
+ ]
+ },
+ {
+ "input": "⇀",
+ "description": "Named entity: RightVector; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c0"
+ ]
+ ]
+ },
+ {
+ "input": "&RightVectorBar",
+ "description": "Bad named entity: RightVectorBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RightVectorBar"
+ ]
+ ]
+ },
+ {
+ "input": "⥓",
+ "description": "Named entity: RightVectorBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2953"
+ ]
+ ]
+ },
+ {
+ "input": "&Rightarrow",
+ "description": "Bad named entity: Rightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇒",
+ "description": "Named entity: Rightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d2"
+ ]
+ ]
+ },
+ {
+ "input": "&Ropf",
+ "description": "Bad named entity: Ropf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ropf"
+ ]
+ ]
+ },
+ {
+ "input": "ℝ",
+ "description": "Named entity: Ropf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211d"
+ ]
+ ]
+ },
+ {
+ "input": "&RoundImplies",
+ "description": "Bad named entity: RoundImplies without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RoundImplies"
+ ]
+ ]
+ },
+ {
+ "input": "⥰",
+ "description": "Named entity: RoundImplies; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2970"
+ ]
+ ]
+ },
+ {
+ "input": "&Rrightarrow",
+ "description": "Bad named entity: Rrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇛",
+ "description": "Named entity: Rrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21db"
+ ]
+ ]
+ },
+ {
+ "input": "&Rscr",
+ "description": "Bad named entity: Rscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℛ",
+ "description": "Named entity: Rscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211b"
+ ]
+ ]
+ },
+ {
+ "input": "&Rsh",
+ "description": "Bad named entity: Rsh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Rsh"
+ ]
+ ]
+ },
+ {
+ "input": "↱",
+ "description": "Named entity: Rsh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b1"
+ ]
+ ]
+ },
+ {
+ "input": "&RuleDelayed",
+ "description": "Bad named entity: RuleDelayed without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&RuleDelayed"
+ ]
+ ]
+ },
+ {
+ "input": "⧴",
+ "description": "Named entity: RuleDelayed; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29f4"
+ ]
+ ]
+ },
+ {
+ "input": "&SHCHcy",
+ "description": "Bad named entity: SHCHcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SHCHcy"
+ ]
+ ]
+ },
+ {
+ "input": "Щ",
+ "description": "Named entity: SHCHcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0429"
+ ]
+ ]
+ },
+ {
+ "input": "&SHcy",
+ "description": "Bad named entity: SHcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SHcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ш",
+ "description": "Named entity: SHcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0428"
+ ]
+ ]
+ },
+ {
+ "input": "&SOFTcy",
+ "description": "Bad named entity: SOFTcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SOFTcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ь",
+ "description": "Named entity: SOFTcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u042c"
+ ]
+ ]
+ },
+ {
+ "input": "&Sacute",
+ "description": "Bad named entity: Sacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sacute"
+ ]
+ ]
+ },
+ {
+ "input": "Ś",
+ "description": "Named entity: Sacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u015a"
+ ]
+ ]
+ },
+ {
+ "input": "&Sc",
+ "description": "Bad named entity: Sc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sc"
+ ]
+ ]
+ },
+ {
+ "input": "⪼",
+ "description": "Named entity: Sc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2abc"
+ ]
+ ]
+ },
+ {
+ "input": "&Scaron",
+ "description": "Bad named entity: Scaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Scaron"
+ ]
+ ]
+ },
+ {
+ "input": "Š",
+ "description": "Named entity: Scaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0160"
+ ]
+ ]
+ },
+ {
+ "input": "&Scedil",
+ "description": "Bad named entity: Scedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Scedil"
+ ]
+ ]
+ },
+ {
+ "input": "Ş",
+ "description": "Named entity: Scedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u015e"
+ ]
+ ]
+ },
+ {
+ "input": "&Scirc",
+ "description": "Bad named entity: Scirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Scirc"
+ ]
+ ]
+ },
+ {
+ "input": "Ŝ",
+ "description": "Named entity: Scirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u015c"
+ ]
+ ]
+ },
+ {
+ "input": "&Scy",
+ "description": "Bad named entity: Scy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Scy"
+ ]
+ ]
+ },
+ {
+ "input": "С",
+ "description": "Named entity: Scy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0421"
+ ]
+ ]
+ },
+ {
+ "input": "&Sfr",
+ "description": "Bad named entity: Sfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔖",
+ "description": "Named entity: Sfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd16"
+ ]
+ ]
+ },
+ {
+ "input": "&ShortDownArrow",
+ "description": "Bad named entity: ShortDownArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ShortDownArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↓",
+ "description": "Named entity: ShortDownArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2193"
+ ]
+ ]
+ },
+ {
+ "input": "&ShortLeftArrow",
+ "description": "Bad named entity: ShortLeftArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ShortLeftArrow"
+ ]
+ ]
+ },
+ {
+ "input": "←",
+ "description": "Named entity: ShortLeftArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2190"
+ ]
+ ]
+ },
+ {
+ "input": "&ShortRightArrow",
+ "description": "Bad named entity: ShortRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ShortRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "→",
+ "description": "Named entity: ShortRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2192"
+ ]
+ ]
+ },
+ {
+ "input": "&ShortUpArrow",
+ "description": "Bad named entity: ShortUpArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ShortUpArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↑",
+ "description": "Named entity: ShortUpArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2191"
+ ]
+ ]
+ },
+ {
+ "input": "&Sigma",
+ "description": "Bad named entity: Sigma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sigma"
+ ]
+ ]
+ },
+ {
+ "input": "Σ",
+ "description": "Named entity: Sigma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a3"
+ ]
+ ]
+ },
+ {
+ "input": "&SmallCircle",
+ "description": "Bad named entity: SmallCircle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SmallCircle"
+ ]
+ ]
+ },
+ {
+ "input": "∘",
+ "description": "Named entity: SmallCircle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2218"
+ ]
+ ]
+ },
+ {
+ "input": "&Sopf",
+ "description": "Bad named entity: Sopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕊",
+ "description": "Named entity: Sopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd4a"
+ ]
+ ]
+ },
+ {
+ "input": "&Sqrt",
+ "description": "Bad named entity: Sqrt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sqrt"
+ ]
+ ]
+ },
+ {
+ "input": "√",
+ "description": "Named entity: Sqrt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221a"
+ ]
+ ]
+ },
+ {
+ "input": "&Square",
+ "description": "Bad named entity: Square without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Square"
+ ]
+ ]
+ },
+ {
+ "input": "□",
+ "description": "Named entity: Square; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25a1"
+ ]
+ ]
+ },
+ {
+ "input": "&SquareIntersection",
+ "description": "Bad named entity: SquareIntersection without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SquareIntersection"
+ ]
+ ]
+ },
+ {
+ "input": "⊓",
+ "description": "Named entity: SquareIntersection; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2293"
+ ]
+ ]
+ },
+ {
+ "input": "&SquareSubset",
+ "description": "Bad named entity: SquareSubset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SquareSubset"
+ ]
+ ]
+ },
+ {
+ "input": "⊏",
+ "description": "Named entity: SquareSubset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228f"
+ ]
+ ]
+ },
+ {
+ "input": "&SquareSubsetEqual",
+ "description": "Bad named entity: SquareSubsetEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SquareSubsetEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⊑",
+ "description": "Named entity: SquareSubsetEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2291"
+ ]
+ ]
+ },
+ {
+ "input": "&SquareSuperset",
+ "description": "Bad named entity: SquareSuperset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SquareSuperset"
+ ]
+ ]
+ },
+ {
+ "input": "⊐",
+ "description": "Named entity: SquareSuperset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2290"
+ ]
+ ]
+ },
+ {
+ "input": "&SquareSupersetEqual",
+ "description": "Bad named entity: SquareSupersetEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SquareSupersetEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⊒",
+ "description": "Named entity: SquareSupersetEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2292"
+ ]
+ ]
+ },
+ {
+ "input": "&SquareUnion",
+ "description": "Bad named entity: SquareUnion without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SquareUnion"
+ ]
+ ]
+ },
+ {
+ "input": "⊔",
+ "description": "Named entity: SquareUnion; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2294"
+ ]
+ ]
+ },
+ {
+ "input": "&Sscr",
+ "description": "Bad named entity: Sscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒮",
+ "description": "Named entity: Sscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcae"
+ ]
+ ]
+ },
+ {
+ "input": "&Star",
+ "description": "Bad named entity: Star without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Star"
+ ]
+ ]
+ },
+ {
+ "input": "⋆",
+ "description": "Named entity: Star; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c6"
+ ]
+ ]
+ },
+ {
+ "input": "&Sub",
+ "description": "Bad named entity: Sub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sub"
+ ]
+ ]
+ },
+ {
+ "input": "⋐",
+ "description": "Named entity: Sub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d0"
+ ]
+ ]
+ },
+ {
+ "input": "&Subset",
+ "description": "Bad named entity: Subset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Subset"
+ ]
+ ]
+ },
+ {
+ "input": "⋐",
+ "description": "Named entity: Subset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d0"
+ ]
+ ]
+ },
+ {
+ "input": "&SubsetEqual",
+ "description": "Bad named entity: SubsetEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SubsetEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⊆",
+ "description": "Named entity: SubsetEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2286"
+ ]
+ ]
+ },
+ {
+ "input": "&Succeeds",
+ "description": "Bad named entity: Succeeds without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Succeeds"
+ ]
+ ]
+ },
+ {
+ "input": "≻",
+ "description": "Named entity: Succeeds; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227b"
+ ]
+ ]
+ },
+ {
+ "input": "&SucceedsEqual",
+ "description": "Bad named entity: SucceedsEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SucceedsEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⪰",
+ "description": "Named entity: SucceedsEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab0"
+ ]
+ ]
+ },
+ {
+ "input": "&SucceedsSlantEqual",
+ "description": "Bad named entity: SucceedsSlantEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SucceedsSlantEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≽",
+ "description": "Named entity: SucceedsSlantEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227d"
+ ]
+ ]
+ },
+ {
+ "input": "&SucceedsTilde",
+ "description": "Bad named entity: SucceedsTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SucceedsTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≿",
+ "description": "Named entity: SucceedsTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227f"
+ ]
+ ]
+ },
+ {
+ "input": "&SuchThat",
+ "description": "Bad named entity: SuchThat without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SuchThat"
+ ]
+ ]
+ },
+ {
+ "input": "∋",
+ "description": "Named entity: SuchThat; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220b"
+ ]
+ ]
+ },
+ {
+ "input": "&Sum",
+ "description": "Bad named entity: Sum without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sum"
+ ]
+ ]
+ },
+ {
+ "input": "∑",
+ "description": "Named entity: Sum; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2211"
+ ]
+ ]
+ },
+ {
+ "input": "&Sup",
+ "description": "Bad named entity: Sup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Sup"
+ ]
+ ]
+ },
+ {
+ "input": "⋑",
+ "description": "Named entity: Sup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d1"
+ ]
+ ]
+ },
+ {
+ "input": "&Superset",
+ "description": "Bad named entity: Superset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Superset"
+ ]
+ ]
+ },
+ {
+ "input": "⊃",
+ "description": "Named entity: Superset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2283"
+ ]
+ ]
+ },
+ {
+ "input": "&SupersetEqual",
+ "description": "Bad named entity: SupersetEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&SupersetEqual"
+ ]
+ ]
+ },
+ {
+ "input": "⊇",
+ "description": "Named entity: SupersetEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2287"
+ ]
+ ]
+ },
+ {
+ "input": "&Supset",
+ "description": "Bad named entity: Supset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Supset"
+ ]
+ ]
+ },
+ {
+ "input": "⋑",
+ "description": "Named entity: Supset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d1"
+ ]
+ ]
+ },
+ {
+ "input": "Þ",
+ "description": "Named entity: THORN without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00de"
+ ]
+ ]
+ },
+ {
+ "input": "Þ",
+ "description": "Named entity: THORN; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00de"
+ ]
+ ]
+ },
+ {
+ "input": "&TRADE",
+ "description": "Bad named entity: TRADE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&TRADE"
+ ]
+ ]
+ },
+ {
+ "input": "™",
+ "description": "Named entity: TRADE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2122"
+ ]
+ ]
+ },
+ {
+ "input": "&TSHcy",
+ "description": "Bad named entity: TSHcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&TSHcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ћ",
+ "description": "Named entity: TSHcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u040b"
+ ]
+ ]
+ },
+ {
+ "input": "&TScy",
+ "description": "Bad named entity: TScy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&TScy"
+ ]
+ ]
+ },
+ {
+ "input": "Ц",
+ "description": "Named entity: TScy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0426"
+ ]
+ ]
+ },
+ {
+ "input": "&Tab",
+ "description": "Bad named entity: Tab without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tab"
+ ]
+ ]
+ },
+ {
+ "input": "	",
+ "description": "Named entity: Tab; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\t"
+ ]
+ ]
+ },
+ {
+ "input": "&Tau",
+ "description": "Bad named entity: Tau without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tau"
+ ]
+ ]
+ },
+ {
+ "input": "Τ",
+ "description": "Named entity: Tau; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a4"
+ ]
+ ]
+ },
+ {
+ "input": "&Tcaron",
+ "description": "Bad named entity: Tcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tcaron"
+ ]
+ ]
+ },
+ {
+ "input": "Ť",
+ "description": "Named entity: Tcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0164"
+ ]
+ ]
+ },
+ {
+ "input": "&Tcedil",
+ "description": "Bad named entity: Tcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tcedil"
+ ]
+ ]
+ },
+ {
+ "input": "Ţ",
+ "description": "Named entity: Tcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0162"
+ ]
+ ]
+ },
+ {
+ "input": "&Tcy",
+ "description": "Bad named entity: Tcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tcy"
+ ]
+ ]
+ },
+ {
+ "input": "Т",
+ "description": "Named entity: Tcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0422"
+ ]
+ ]
+ },
+ {
+ "input": "&Tfr",
+ "description": "Bad named entity: Tfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔗",
+ "description": "Named entity: Tfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd17"
+ ]
+ ]
+ },
+ {
+ "input": "&Therefore",
+ "description": "Bad named entity: Therefore without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Therefore"
+ ]
+ ]
+ },
+ {
+ "input": "∴",
+ "description": "Named entity: Therefore; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2234"
+ ]
+ ]
+ },
+ {
+ "input": "&Theta",
+ "description": "Bad named entity: Theta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Theta"
+ ]
+ ]
+ },
+ {
+ "input": "Θ",
+ "description": "Named entity: Theta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0398"
+ ]
+ ]
+ },
+ {
+ "input": "&ThickSpace",
+ "description": "Bad named entity: ThickSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ThickSpace"
+ ]
+ ]
+ },
+ {
+ "input": "  ",
+ "description": "Named entity: ThickSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u205f\u200a"
+ ]
+ ]
+ },
+ {
+ "input": "&ThinSpace",
+ "description": "Bad named entity: ThinSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ThinSpace"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: ThinSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2009"
+ ]
+ ]
+ },
+ {
+ "input": "&Tilde",
+ "description": "Bad named entity: Tilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tilde"
+ ]
+ ]
+ },
+ {
+ "input": "∼",
+ "description": "Named entity: Tilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223c"
+ ]
+ ]
+ },
+ {
+ "input": "&TildeEqual",
+ "description": "Bad named entity: TildeEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&TildeEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≃",
+ "description": "Named entity: TildeEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2243"
+ ]
+ ]
+ },
+ {
+ "input": "&TildeFullEqual",
+ "description": "Bad named entity: TildeFullEqual without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&TildeFullEqual"
+ ]
+ ]
+ },
+ {
+ "input": "≅",
+ "description": "Named entity: TildeFullEqual; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2245"
+ ]
+ ]
+ },
+ {
+ "input": "&TildeTilde",
+ "description": "Bad named entity: TildeTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&TildeTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≈",
+ "description": "Named entity: TildeTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2248"
+ ]
+ ]
+ },
+ {
+ "input": "&Topf",
+ "description": "Bad named entity: Topf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Topf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕋",
+ "description": "Named entity: Topf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd4b"
+ ]
+ ]
+ },
+ {
+ "input": "&TripleDot",
+ "description": "Bad named entity: TripleDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&TripleDot"
+ ]
+ ]
+ },
+ {
+ "input": "⃛",
+ "description": "Named entity: TripleDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u20db"
+ ]
+ ]
+ },
+ {
+ "input": "&Tscr",
+ "description": "Bad named entity: Tscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒯",
+ "description": "Named entity: Tscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcaf"
+ ]
+ ]
+ },
+ {
+ "input": "&Tstrok",
+ "description": "Bad named entity: Tstrok without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Tstrok"
+ ]
+ ]
+ },
+ {
+ "input": "Ŧ",
+ "description": "Named entity: Tstrok; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0166"
+ ]
+ ]
+ },
+ {
+ "input": "Ú",
+ "description": "Named entity: Uacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00da"
+ ]
+ ]
+ },
+ {
+ "input": "Ú",
+ "description": "Named entity: Uacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00da"
+ ]
+ ]
+ },
+ {
+ "input": "&Uarr",
+ "description": "Bad named entity: Uarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Uarr"
+ ]
+ ]
+ },
+ {
+ "input": "↟",
+ "description": "Named entity: Uarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219f"
+ ]
+ ]
+ },
+ {
+ "input": "&Uarrocir",
+ "description": "Bad named entity: Uarrocir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Uarrocir"
+ ]
+ ]
+ },
+ {
+ "input": "⥉",
+ "description": "Named entity: Uarrocir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2949"
+ ]
+ ]
+ },
+ {
+ "input": "&Ubrcy",
+ "description": "Bad named entity: Ubrcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ubrcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ў",
+ "description": "Named entity: Ubrcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u040e"
+ ]
+ ]
+ },
+ {
+ "input": "&Ubreve",
+ "description": "Bad named entity: Ubreve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ubreve"
+ ]
+ ]
+ },
+ {
+ "input": "Ŭ",
+ "description": "Named entity: Ubreve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u016c"
+ ]
+ ]
+ },
+ {
+ "input": "Û",
+ "description": "Named entity: Ucirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00db"
+ ]
+ ]
+ },
+ {
+ "input": "Û",
+ "description": "Named entity: Ucirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00db"
+ ]
+ ]
+ },
+ {
+ "input": "&Ucy",
+ "description": "Bad named entity: Ucy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ucy"
+ ]
+ ]
+ },
+ {
+ "input": "У",
+ "description": "Named entity: Ucy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0423"
+ ]
+ ]
+ },
+ {
+ "input": "&Udblac",
+ "description": "Bad named entity: Udblac without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Udblac"
+ ]
+ ]
+ },
+ {
+ "input": "Ű",
+ "description": "Named entity: Udblac; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0170"
+ ]
+ ]
+ },
+ {
+ "input": "&Ufr",
+ "description": "Bad named entity: Ufr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ufr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔘",
+ "description": "Named entity: Ufr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd18"
+ ]
+ ]
+ },
+ {
+ "input": "Ù",
+ "description": "Named entity: Ugrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d9"
+ ]
+ ]
+ },
+ {
+ "input": "Ù",
+ "description": "Named entity: Ugrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d9"
+ ]
+ ]
+ },
+ {
+ "input": "&Umacr",
+ "description": "Bad named entity: Umacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Umacr"
+ ]
+ ]
+ },
+ {
+ "input": "Ū",
+ "description": "Named entity: Umacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u016a"
+ ]
+ ]
+ },
+ {
+ "input": "&UnderBar",
+ "description": "Bad named entity: UnderBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UnderBar"
+ ]
+ ]
+ },
+ {
+ "input": "_",
+ "description": "Named entity: UnderBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "_"
+ ]
+ ]
+ },
+ {
+ "input": "&UnderBrace",
+ "description": "Bad named entity: UnderBrace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UnderBrace"
+ ]
+ ]
+ },
+ {
+ "input": "⏟",
+ "description": "Named entity: UnderBrace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23df"
+ ]
+ ]
+ },
+ {
+ "input": "&UnderBracket",
+ "description": "Bad named entity: UnderBracket without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UnderBracket"
+ ]
+ ]
+ },
+ {
+ "input": "⎵",
+ "description": "Named entity: UnderBracket; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b5"
+ ]
+ ]
+ },
+ {
+ "input": "&UnderParenthesis",
+ "description": "Bad named entity: UnderParenthesis without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UnderParenthesis"
+ ]
+ ]
+ },
+ {
+ "input": "⏝",
+ "description": "Named entity: UnderParenthesis; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23dd"
+ ]
+ ]
+ },
+ {
+ "input": "&Union",
+ "description": "Bad named entity: Union without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Union"
+ ]
+ ]
+ },
+ {
+ "input": "⋃",
+ "description": "Named entity: Union; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c3"
+ ]
+ ]
+ },
+ {
+ "input": "&UnionPlus",
+ "description": "Bad named entity: UnionPlus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UnionPlus"
+ ]
+ ]
+ },
+ {
+ "input": "⊎",
+ "description": "Named entity: UnionPlus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228e"
+ ]
+ ]
+ },
+ {
+ "input": "&Uogon",
+ "description": "Bad named entity: Uogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Uogon"
+ ]
+ ]
+ },
+ {
+ "input": "Ų",
+ "description": "Named entity: Uogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0172"
+ ]
+ ]
+ },
+ {
+ "input": "&Uopf",
+ "description": "Bad named entity: Uopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Uopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕌",
+ "description": "Named entity: Uopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd4c"
+ ]
+ ]
+ },
+ {
+ "input": "&UpArrow",
+ "description": "Bad named entity: UpArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↑",
+ "description": "Named entity: UpArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2191"
+ ]
+ ]
+ },
+ {
+ "input": "&UpArrowBar",
+ "description": "Bad named entity: UpArrowBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpArrowBar"
+ ]
+ ]
+ },
+ {
+ "input": "⤒",
+ "description": "Named entity: UpArrowBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2912"
+ ]
+ ]
+ },
+ {
+ "input": "&UpArrowDownArrow",
+ "description": "Bad named entity: UpArrowDownArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpArrowDownArrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇅",
+ "description": "Named entity: UpArrowDownArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c5"
+ ]
+ ]
+ },
+ {
+ "input": "&UpDownArrow",
+ "description": "Bad named entity: UpDownArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpDownArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↕",
+ "description": "Named entity: UpDownArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2195"
+ ]
+ ]
+ },
+ {
+ "input": "&UpEquilibrium",
+ "description": "Bad named entity: UpEquilibrium without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpEquilibrium"
+ ]
+ ]
+ },
+ {
+ "input": "⥮",
+ "description": "Named entity: UpEquilibrium; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u296e"
+ ]
+ ]
+ },
+ {
+ "input": "&UpTee",
+ "description": "Bad named entity: UpTee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpTee"
+ ]
+ ]
+ },
+ {
+ "input": "⊥",
+ "description": "Named entity: UpTee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a5"
+ ]
+ ]
+ },
+ {
+ "input": "&UpTeeArrow",
+ "description": "Bad named entity: UpTeeArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpTeeArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↥",
+ "description": "Named entity: UpTeeArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a5"
+ ]
+ ]
+ },
+ {
+ "input": "&Uparrow",
+ "description": "Bad named entity: Uparrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Uparrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇑",
+ "description": "Named entity: Uparrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d1"
+ ]
+ ]
+ },
+ {
+ "input": "&Updownarrow",
+ "description": "Bad named entity: Updownarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Updownarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇕",
+ "description": "Named entity: Updownarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d5"
+ ]
+ ]
+ },
+ {
+ "input": "&UpperLeftArrow",
+ "description": "Bad named entity: UpperLeftArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpperLeftArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↖",
+ "description": "Named entity: UpperLeftArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2196"
+ ]
+ ]
+ },
+ {
+ "input": "&UpperRightArrow",
+ "description": "Bad named entity: UpperRightArrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&UpperRightArrow"
+ ]
+ ]
+ },
+ {
+ "input": "↗",
+ "description": "Named entity: UpperRightArrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2197"
+ ]
+ ]
+ },
+ {
+ "input": "&Upsi",
+ "description": "Bad named entity: Upsi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Upsi"
+ ]
+ ]
+ },
+ {
+ "input": "ϒ",
+ "description": "Named entity: Upsi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d2"
+ ]
+ ]
+ },
+ {
+ "input": "&Upsilon",
+ "description": "Bad named entity: Upsilon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Upsilon"
+ ]
+ ]
+ },
+ {
+ "input": "Υ",
+ "description": "Named entity: Upsilon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a5"
+ ]
+ ]
+ },
+ {
+ "input": "&Uring",
+ "description": "Bad named entity: Uring without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Uring"
+ ]
+ ]
+ },
+ {
+ "input": "Ů",
+ "description": "Named entity: Uring; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u016e"
+ ]
+ ]
+ },
+ {
+ "input": "&Uscr",
+ "description": "Bad named entity: Uscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Uscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒰",
+ "description": "Named entity: Uscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb0"
+ ]
+ ]
+ },
+ {
+ "input": "&Utilde",
+ "description": "Bad named entity: Utilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Utilde"
+ ]
+ ]
+ },
+ {
+ "input": "Ũ",
+ "description": "Named entity: Utilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0168"
+ ]
+ ]
+ },
+ {
+ "input": "Ü",
+ "description": "Named entity: Uuml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00dc"
+ ]
+ ]
+ },
+ {
+ "input": "Ü",
+ "description": "Named entity: Uuml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00dc"
+ ]
+ ]
+ },
+ {
+ "input": "&VDash",
+ "description": "Bad named entity: VDash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&VDash"
+ ]
+ ]
+ },
+ {
+ "input": "⊫",
+ "description": "Named entity: VDash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ab"
+ ]
+ ]
+ },
+ {
+ "input": "&Vbar",
+ "description": "Bad named entity: Vbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vbar"
+ ]
+ ]
+ },
+ {
+ "input": "⫫",
+ "description": "Named entity: Vbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aeb"
+ ]
+ ]
+ },
+ {
+ "input": "&Vcy",
+ "description": "Bad named entity: Vcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vcy"
+ ]
+ ]
+ },
+ {
+ "input": "В",
+ "description": "Named entity: Vcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0412"
+ ]
+ ]
+ },
+ {
+ "input": "&Vdash",
+ "description": "Bad named entity: Vdash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vdash"
+ ]
+ ]
+ },
+ {
+ "input": "⊩",
+ "description": "Named entity: Vdash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a9"
+ ]
+ ]
+ },
+ {
+ "input": "&Vdashl",
+ "description": "Bad named entity: Vdashl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vdashl"
+ ]
+ ]
+ },
+ {
+ "input": "⫦",
+ "description": "Named entity: Vdashl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ae6"
+ ]
+ ]
+ },
+ {
+ "input": "&Vee",
+ "description": "Bad named entity: Vee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vee"
+ ]
+ ]
+ },
+ {
+ "input": "⋁",
+ "description": "Named entity: Vee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c1"
+ ]
+ ]
+ },
+ {
+ "input": "&Verbar",
+ "description": "Bad named entity: Verbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Verbar"
+ ]
+ ]
+ },
+ {
+ "input": "‖",
+ "description": "Named entity: Verbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2016"
+ ]
+ ]
+ },
+ {
+ "input": "&Vert",
+ "description": "Bad named entity: Vert without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vert"
+ ]
+ ]
+ },
+ {
+ "input": "‖",
+ "description": "Named entity: Vert; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2016"
+ ]
+ ]
+ },
+ {
+ "input": "&VerticalBar",
+ "description": "Bad named entity: VerticalBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&VerticalBar"
+ ]
+ ]
+ },
+ {
+ "input": "∣",
+ "description": "Named entity: VerticalBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2223"
+ ]
+ ]
+ },
+ {
+ "input": "&VerticalLine",
+ "description": "Bad named entity: VerticalLine without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&VerticalLine"
+ ]
+ ]
+ },
+ {
+ "input": "|",
+ "description": "Named entity: VerticalLine; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "|"
+ ]
+ ]
+ },
+ {
+ "input": "&VerticalSeparator",
+ "description": "Bad named entity: VerticalSeparator without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&VerticalSeparator"
+ ]
+ ]
+ },
+ {
+ "input": "❘",
+ "description": "Named entity: VerticalSeparator; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2758"
+ ]
+ ]
+ },
+ {
+ "input": "&VerticalTilde",
+ "description": "Bad named entity: VerticalTilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&VerticalTilde"
+ ]
+ ]
+ },
+ {
+ "input": "≀",
+ "description": "Named entity: VerticalTilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2240"
+ ]
+ ]
+ },
+ {
+ "input": "&VeryThinSpace",
+ "description": "Bad named entity: VeryThinSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&VeryThinSpace"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: VeryThinSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200a"
+ ]
+ ]
+ },
+ {
+ "input": "&Vfr",
+ "description": "Bad named entity: Vfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔙",
+ "description": "Named entity: Vfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd19"
+ ]
+ ]
+ },
+ {
+ "input": "&Vopf",
+ "description": "Bad named entity: Vopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕍",
+ "description": "Named entity: Vopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd4d"
+ ]
+ ]
+ },
+ {
+ "input": "&Vscr",
+ "description": "Bad named entity: Vscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒱",
+ "description": "Named entity: Vscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb1"
+ ]
+ ]
+ },
+ {
+ "input": "&Vvdash",
+ "description": "Bad named entity: Vvdash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Vvdash"
+ ]
+ ]
+ },
+ {
+ "input": "⊪",
+ "description": "Named entity: Vvdash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22aa"
+ ]
+ ]
+ },
+ {
+ "input": "&Wcirc",
+ "description": "Bad named entity: Wcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Wcirc"
+ ]
+ ]
+ },
+ {
+ "input": "Ŵ",
+ "description": "Named entity: Wcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0174"
+ ]
+ ]
+ },
+ {
+ "input": "&Wedge",
+ "description": "Bad named entity: Wedge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Wedge"
+ ]
+ ]
+ },
+ {
+ "input": "⋀",
+ "description": "Named entity: Wedge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c0"
+ ]
+ ]
+ },
+ {
+ "input": "&Wfr",
+ "description": "Bad named entity: Wfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Wfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔚",
+ "description": "Named entity: Wfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd1a"
+ ]
+ ]
+ },
+ {
+ "input": "&Wopf",
+ "description": "Bad named entity: Wopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Wopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕎",
+ "description": "Named entity: Wopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd4e"
+ ]
+ ]
+ },
+ {
+ "input": "&Wscr",
+ "description": "Bad named entity: Wscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Wscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒲",
+ "description": "Named entity: Wscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb2"
+ ]
+ ]
+ },
+ {
+ "input": "&Xfr",
+ "description": "Bad named entity: Xfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Xfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔛",
+ "description": "Named entity: Xfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd1b"
+ ]
+ ]
+ },
+ {
+ "input": "&Xi",
+ "description": "Bad named entity: Xi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Xi"
+ ]
+ ]
+ },
+ {
+ "input": "Ξ",
+ "description": "Named entity: Xi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u039e"
+ ]
+ ]
+ },
+ {
+ "input": "&Xopf",
+ "description": "Bad named entity: Xopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Xopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕏",
+ "description": "Named entity: Xopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd4f"
+ ]
+ ]
+ },
+ {
+ "input": "&Xscr",
+ "description": "Bad named entity: Xscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Xscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒳",
+ "description": "Named entity: Xscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb3"
+ ]
+ ]
+ },
+ {
+ "input": "&YAcy",
+ "description": "Bad named entity: YAcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&YAcy"
+ ]
+ ]
+ },
+ {
+ "input": "Я",
+ "description": "Named entity: YAcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u042f"
+ ]
+ ]
+ },
+ {
+ "input": "&YIcy",
+ "description": "Bad named entity: YIcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&YIcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ї",
+ "description": "Named entity: YIcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0407"
+ ]
+ ]
+ },
+ {
+ "input": "&YUcy",
+ "description": "Bad named entity: YUcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&YUcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ю",
+ "description": "Named entity: YUcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u042e"
+ ]
+ ]
+ },
+ {
+ "input": "Ý",
+ "description": "Named entity: Yacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00dd"
+ ]
+ ]
+ },
+ {
+ "input": "Ý",
+ "description": "Named entity: Yacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00dd"
+ ]
+ ]
+ },
+ {
+ "input": "&Ycirc",
+ "description": "Bad named entity: Ycirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ycirc"
+ ]
+ ]
+ },
+ {
+ "input": "Ŷ",
+ "description": "Named entity: Ycirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0176"
+ ]
+ ]
+ },
+ {
+ "input": "&Ycy",
+ "description": "Bad named entity: Ycy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Ycy"
+ ]
+ ]
+ },
+ {
+ "input": "Ы",
+ "description": "Named entity: Ycy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u042b"
+ ]
+ ]
+ },
+ {
+ "input": "&Yfr",
+ "description": "Bad named entity: Yfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Yfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔜",
+ "description": "Named entity: Yfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd1c"
+ ]
+ ]
+ },
+ {
+ "input": "&Yopf",
+ "description": "Bad named entity: Yopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Yopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕐",
+ "description": "Named entity: Yopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd50"
+ ]
+ ]
+ },
+ {
+ "input": "&Yscr",
+ "description": "Bad named entity: Yscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Yscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒴",
+ "description": "Named entity: Yscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb4"
+ ]
+ ]
+ },
+ {
+ "input": "&Yuml",
+ "description": "Bad named entity: Yuml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Yuml"
+ ]
+ ]
+ },
+ {
+ "input": "Ÿ",
+ "description": "Named entity: Yuml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0178"
+ ]
+ ]
+ },
+ {
+ "input": "&ZHcy",
+ "description": "Bad named entity: ZHcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ZHcy"
+ ]
+ ]
+ },
+ {
+ "input": "Ж",
+ "description": "Named entity: ZHcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0416"
+ ]
+ ]
+ },
+ {
+ "input": "&Zacute",
+ "description": "Bad named entity: Zacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Zacute"
+ ]
+ ]
+ },
+ {
+ "input": "Ź",
+ "description": "Named entity: Zacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0179"
+ ]
+ ]
+ },
+ {
+ "input": "&Zcaron",
+ "description": "Bad named entity: Zcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Zcaron"
+ ]
+ ]
+ },
+ {
+ "input": "Ž",
+ "description": "Named entity: Zcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u017d"
+ ]
+ ]
+ },
+ {
+ "input": "&Zcy",
+ "description": "Bad named entity: Zcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Zcy"
+ ]
+ ]
+ },
+ {
+ "input": "З",
+ "description": "Named entity: Zcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0417"
+ ]
+ ]
+ },
+ {
+ "input": "&Zdot",
+ "description": "Bad named entity: Zdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Zdot"
+ ]
+ ]
+ },
+ {
+ "input": "Ż",
+ "description": "Named entity: Zdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u017b"
+ ]
+ ]
+ },
+ {
+ "input": "&ZeroWidthSpace",
+ "description": "Bad named entity: ZeroWidthSpace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ZeroWidthSpace"
+ ]
+ ]
+ },
+ {
+ "input": "​",
+ "description": "Named entity: ZeroWidthSpace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200b"
+ ]
+ ]
+ },
+ {
+ "input": "&Zeta",
+ "description": "Bad named entity: Zeta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Zeta"
+ ]
+ ]
+ },
+ {
+ "input": "Ζ",
+ "description": "Named entity: Zeta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0396"
+ ]
+ ]
+ },
+ {
+ "input": "&Zfr",
+ "description": "Bad named entity: Zfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Zfr"
+ ]
+ ]
+ },
+ {
+ "input": "ℨ",
+ "description": "Named entity: Zfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2128"
+ ]
+ ]
+ },
+ {
+ "input": "&Zopf",
+ "description": "Bad named entity: Zopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Zopf"
+ ]
+ ]
+ },
+ {
+ "input": "ℤ",
+ "description": "Named entity: Zopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2124"
+ ]
+ ]
+ },
+ {
+ "input": "&Zscr",
+ "description": "Bad named entity: Zscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&Zscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒵",
+ "description": "Named entity: Zscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb5"
+ ]
+ ]
+ },
+ {
+ "input": "á",
+ "description": "Named entity: aacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e1"
+ ]
+ ]
+ },
+ {
+ "input": "á",
+ "description": "Named entity: aacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e1"
+ ]
+ ]
+ },
+ {
+ "input": "&abreve",
+ "description": "Bad named entity: abreve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&abreve"
+ ]
+ ]
+ },
+ {
+ "input": "ă",
+ "description": "Named entity: abreve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0103"
+ ]
+ ]
+ },
+ {
+ "input": "&ac",
+ "description": "Bad named entity: ac without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ac"
+ ]
+ ]
+ },
+ {
+ "input": "∾",
+ "description": "Named entity: ac; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223e"
+ ]
+ ]
+ },
+ {
+ "input": "&acE",
+ "description": "Bad named entity: acE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&acE"
+ ]
+ ]
+ },
+ {
+ "input": "∾̳",
+ "description": "Named entity: acE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223e\u0333"
+ ]
+ ]
+ },
+ {
+ "input": "&acd",
+ "description": "Bad named entity: acd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&acd"
+ ]
+ ]
+ },
+ {
+ "input": "∿",
+ "description": "Named entity: acd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223f"
+ ]
+ ]
+ },
+ {
+ "input": "â",
+ "description": "Named entity: acirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e2"
+ ]
+ ]
+ },
+ {
+ "input": "â",
+ "description": "Named entity: acirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e2"
+ ]
+ ]
+ },
+ {
+ "input": "´",
+ "description": "Named entity: acute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b4"
+ ]
+ ]
+ },
+ {
+ "input": "´",
+ "description": "Named entity: acute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b4"
+ ]
+ ]
+ },
+ {
+ "input": "&acy",
+ "description": "Bad named entity: acy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&acy"
+ ]
+ ]
+ },
+ {
+ "input": "а",
+ "description": "Named entity: acy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0430"
+ ]
+ ]
+ },
+ {
+ "input": "æ",
+ "description": "Named entity: aelig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e6"
+ ]
+ ]
+ },
+ {
+ "input": "æ",
+ "description": "Named entity: aelig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e6"
+ ]
+ ]
+ },
+ {
+ "input": "&af",
+ "description": "Bad named entity: af without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&af"
+ ]
+ ]
+ },
+ {
+ "input": "⁡",
+ "description": "Named entity: af; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2061"
+ ]
+ ]
+ },
+ {
+ "input": "&afr",
+ "description": "Bad named entity: afr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&afr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔞",
+ "description": "Named entity: afr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd1e"
+ ]
+ ]
+ },
+ {
+ "input": "à",
+ "description": "Named entity: agrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e0"
+ ]
+ ]
+ },
+ {
+ "input": "à",
+ "description": "Named entity: agrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e0"
+ ]
+ ]
+ },
+ {
+ "input": "&alefsym",
+ "description": "Bad named entity: alefsym without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&alefsym"
+ ]
+ ]
+ },
+ {
+ "input": "ℵ",
+ "description": "Named entity: alefsym; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2135"
+ ]
+ ]
+ },
+ {
+ "input": "&aleph",
+ "description": "Bad named entity: aleph without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&aleph"
+ ]
+ ]
+ },
+ {
+ "input": "ℵ",
+ "description": "Named entity: aleph; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2135"
+ ]
+ ]
+ },
+ {
+ "input": "&alpha",
+ "description": "Bad named entity: alpha without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&alpha"
+ ]
+ ]
+ },
+ {
+ "input": "α",
+ "description": "Named entity: alpha; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b1"
+ ]
+ ]
+ },
+ {
+ "input": "&amacr",
+ "description": "Bad named entity: amacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&amacr"
+ ]
+ ]
+ },
+ {
+ "input": "ā",
+ "description": "Named entity: amacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0101"
+ ]
+ ]
+ },
+ {
+ "input": "&amalg",
+ "description": "Bad named entity: amalg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&amalg"
+ ]
+ ]
+ },
+ {
+ "input": "⨿",
+ "description": "Named entity: amalg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a3f"
+ ]
+ ]
+ },
+ {
+ "input": "&",
+ "description": "Named entity: amp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&"
+ ]
+ ]
+ },
+ {
+ "input": "&",
+ "description": "Named entity: amp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "&"
+ ]
+ ]
+ },
+ {
+ "input": "&and",
+ "description": "Bad named entity: and without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&and"
+ ]
+ ]
+ },
+ {
+ "input": "∧",
+ "description": "Named entity: and; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2227"
+ ]
+ ]
+ },
+ {
+ "input": "&andand",
+ "description": "Bad named entity: andand without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&andand"
+ ]
+ ]
+ },
+ {
+ "input": "⩕",
+ "description": "Named entity: andand; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a55"
+ ]
+ ]
+ },
+ {
+ "input": "&andd",
+ "description": "Bad named entity: andd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&andd"
+ ]
+ ]
+ },
+ {
+ "input": "⩜",
+ "description": "Named entity: andd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a5c"
+ ]
+ ]
+ },
+ {
+ "input": "&andslope",
+ "description": "Bad named entity: andslope without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&andslope"
+ ]
+ ]
+ },
+ {
+ "input": "⩘",
+ "description": "Named entity: andslope; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a58"
+ ]
+ ]
+ },
+ {
+ "input": "&andv",
+ "description": "Bad named entity: andv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&andv"
+ ]
+ ]
+ },
+ {
+ "input": "⩚",
+ "description": "Named entity: andv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a5a"
+ ]
+ ]
+ },
+ {
+ "input": "&ang",
+ "description": "Bad named entity: ang without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ang"
+ ]
+ ]
+ },
+ {
+ "input": "∠",
+ "description": "Named entity: ang; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2220"
+ ]
+ ]
+ },
+ {
+ "input": "&ange",
+ "description": "Bad named entity: ange without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ange"
+ ]
+ ]
+ },
+ {
+ "input": "⦤",
+ "description": "Named entity: ange; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29a4"
+ ]
+ ]
+ },
+ {
+ "input": "&angle",
+ "description": "Bad named entity: angle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angle"
+ ]
+ ]
+ },
+ {
+ "input": "∠",
+ "description": "Named entity: angle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2220"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsd",
+ "description": "Bad named entity: angmsd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsd"
+ ]
+ ]
+ },
+ {
+ "input": "∡",
+ "description": "Named entity: angmsd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2221"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsdaa",
+ "description": "Bad named entity: angmsdaa without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsdaa"
+ ]
+ ]
+ },
+ {
+ "input": "⦨",
+ "description": "Named entity: angmsdaa; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29a8"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsdab",
+ "description": "Bad named entity: angmsdab without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsdab"
+ ]
+ ]
+ },
+ {
+ "input": "⦩",
+ "description": "Named entity: angmsdab; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29a9"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsdac",
+ "description": "Bad named entity: angmsdac without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsdac"
+ ]
+ ]
+ },
+ {
+ "input": "⦪",
+ "description": "Named entity: angmsdac; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29aa"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsdad",
+ "description": "Bad named entity: angmsdad without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsdad"
+ ]
+ ]
+ },
+ {
+ "input": "⦫",
+ "description": "Named entity: angmsdad; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29ab"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsdae",
+ "description": "Bad named entity: angmsdae without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsdae"
+ ]
+ ]
+ },
+ {
+ "input": "⦬",
+ "description": "Named entity: angmsdae; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29ac"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsdaf",
+ "description": "Bad named entity: angmsdaf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsdaf"
+ ]
+ ]
+ },
+ {
+ "input": "⦭",
+ "description": "Named entity: angmsdaf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29ad"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsdag",
+ "description": "Bad named entity: angmsdag without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsdag"
+ ]
+ ]
+ },
+ {
+ "input": "⦮",
+ "description": "Named entity: angmsdag; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29ae"
+ ]
+ ]
+ },
+ {
+ "input": "&angmsdah",
+ "description": "Bad named entity: angmsdah without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angmsdah"
+ ]
+ ]
+ },
+ {
+ "input": "⦯",
+ "description": "Named entity: angmsdah; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29af"
+ ]
+ ]
+ },
+ {
+ "input": "&angrt",
+ "description": "Bad named entity: angrt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angrt"
+ ]
+ ]
+ },
+ {
+ "input": "∟",
+ "description": "Named entity: angrt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221f"
+ ]
+ ]
+ },
+ {
+ "input": "&angrtvb",
+ "description": "Bad named entity: angrtvb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angrtvb"
+ ]
+ ]
+ },
+ {
+ "input": "⊾",
+ "description": "Named entity: angrtvb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22be"
+ ]
+ ]
+ },
+ {
+ "input": "&angrtvbd",
+ "description": "Bad named entity: angrtvbd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angrtvbd"
+ ]
+ ]
+ },
+ {
+ "input": "⦝",
+ "description": "Named entity: angrtvbd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u299d"
+ ]
+ ]
+ },
+ {
+ "input": "&angsph",
+ "description": "Bad named entity: angsph without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angsph"
+ ]
+ ]
+ },
+ {
+ "input": "∢",
+ "description": "Named entity: angsph; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2222"
+ ]
+ ]
+ },
+ {
+ "input": "&angst",
+ "description": "Bad named entity: angst without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angst"
+ ]
+ ]
+ },
+ {
+ "input": "Å",
+ "description": "Named entity: angst; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00c5"
+ ]
+ ]
+ },
+ {
+ "input": "&angzarr",
+ "description": "Bad named entity: angzarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&angzarr"
+ ]
+ ]
+ },
+ {
+ "input": "⍼",
+ "description": "Named entity: angzarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u237c"
+ ]
+ ]
+ },
+ {
+ "input": "&aogon",
+ "description": "Bad named entity: aogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&aogon"
+ ]
+ ]
+ },
+ {
+ "input": "ą",
+ "description": "Named entity: aogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0105"
+ ]
+ ]
+ },
+ {
+ "input": "&aopf",
+ "description": "Bad named entity: aopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&aopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕒",
+ "description": "Named entity: aopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd52"
+ ]
+ ]
+ },
+ {
+ "input": "&ap",
+ "description": "Bad named entity: ap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ap"
+ ]
+ ]
+ },
+ {
+ "input": "≈",
+ "description": "Named entity: ap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2248"
+ ]
+ ]
+ },
+ {
+ "input": "&apE",
+ "description": "Bad named entity: apE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&apE"
+ ]
+ ]
+ },
+ {
+ "input": "⩰",
+ "description": "Named entity: apE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a70"
+ ]
+ ]
+ },
+ {
+ "input": "&apacir",
+ "description": "Bad named entity: apacir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&apacir"
+ ]
+ ]
+ },
+ {
+ "input": "⩯",
+ "description": "Named entity: apacir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a6f"
+ ]
+ ]
+ },
+ {
+ "input": "&ape",
+ "description": "Bad named entity: ape without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ape"
+ ]
+ ]
+ },
+ {
+ "input": "≊",
+ "description": "Named entity: ape; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224a"
+ ]
+ ]
+ },
+ {
+ "input": "&apid",
+ "description": "Bad named entity: apid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&apid"
+ ]
+ ]
+ },
+ {
+ "input": "≋",
+ "description": "Named entity: apid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224b"
+ ]
+ ]
+ },
+ {
+ "input": "&apos",
+ "description": "Bad named entity: apos without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&apos"
+ ]
+ ]
+ },
+ {
+ "input": "'",
+ "description": "Named entity: apos; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "'"
+ ]
+ ]
+ },
+ {
+ "input": "&approx",
+ "description": "Bad named entity: approx without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&approx"
+ ]
+ ]
+ },
+ {
+ "input": "≈",
+ "description": "Named entity: approx; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2248"
+ ]
+ ]
+ },
+ {
+ "input": "&approxeq",
+ "description": "Bad named entity: approxeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&approxeq"
+ ]
+ ]
+ },
+ {
+ "input": "≊",
+ "description": "Named entity: approxeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224a"
+ ]
+ ]
+ },
+ {
+ "input": "å",
+ "description": "Named entity: aring without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e5"
+ ]
+ ]
+ },
+ {
+ "input": "å",
+ "description": "Named entity: aring; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e5"
+ ]
+ ]
+ },
+ {
+ "input": "&ascr",
+ "description": "Bad named entity: ascr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ascr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒶",
+ "description": "Named entity: ascr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb6"
+ ]
+ ]
+ },
+ {
+ "input": "&ast",
+ "description": "Bad named entity: ast without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ast"
+ ]
+ ]
+ },
+ {
+ "input": "*",
+ "description": "Named entity: ast; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "*"
+ ]
+ ]
+ },
+ {
+ "input": "&asymp",
+ "description": "Bad named entity: asymp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&asymp"
+ ]
+ ]
+ },
+ {
+ "input": "≈",
+ "description": "Named entity: asymp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2248"
+ ]
+ ]
+ },
+ {
+ "input": "&asympeq",
+ "description": "Bad named entity: asympeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&asympeq"
+ ]
+ ]
+ },
+ {
+ "input": "≍",
+ "description": "Named entity: asympeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224d"
+ ]
+ ]
+ },
+ {
+ "input": "ã",
+ "description": "Named entity: atilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e3"
+ ]
+ ]
+ },
+ {
+ "input": "ã",
+ "description": "Named entity: atilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e3"
+ ]
+ ]
+ },
+ {
+ "input": "ä",
+ "description": "Named entity: auml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e4"
+ ]
+ ]
+ },
+ {
+ "input": "ä",
+ "description": "Named entity: auml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e4"
+ ]
+ ]
+ },
+ {
+ "input": "&awconint",
+ "description": "Bad named entity: awconint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&awconint"
+ ]
+ ]
+ },
+ {
+ "input": "∳",
+ "description": "Named entity: awconint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2233"
+ ]
+ ]
+ },
+ {
+ "input": "&awint",
+ "description": "Bad named entity: awint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&awint"
+ ]
+ ]
+ },
+ {
+ "input": "⨑",
+ "description": "Named entity: awint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a11"
+ ]
+ ]
+ },
+ {
+ "input": "&bNot",
+ "description": "Bad named entity: bNot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bNot"
+ ]
+ ]
+ },
+ {
+ "input": "⫭",
+ "description": "Named entity: bNot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aed"
+ ]
+ ]
+ },
+ {
+ "input": "&backcong",
+ "description": "Bad named entity: backcong without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&backcong"
+ ]
+ ]
+ },
+ {
+ "input": "≌",
+ "description": "Named entity: backcong; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224c"
+ ]
+ ]
+ },
+ {
+ "input": "&backepsilon",
+ "description": "Bad named entity: backepsilon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&backepsilon"
+ ]
+ ]
+ },
+ {
+ "input": "϶",
+ "description": "Named entity: backepsilon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f6"
+ ]
+ ]
+ },
+ {
+ "input": "&backprime",
+ "description": "Bad named entity: backprime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&backprime"
+ ]
+ ]
+ },
+ {
+ "input": "‵",
+ "description": "Named entity: backprime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2035"
+ ]
+ ]
+ },
+ {
+ "input": "&backsim",
+ "description": "Bad named entity: backsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&backsim"
+ ]
+ ]
+ },
+ {
+ "input": "∽",
+ "description": "Named entity: backsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223d"
+ ]
+ ]
+ },
+ {
+ "input": "&backsimeq",
+ "description": "Bad named entity: backsimeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&backsimeq"
+ ]
+ ]
+ },
+ {
+ "input": "⋍",
+ "description": "Named entity: backsimeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22cd"
+ ]
+ ]
+ },
+ {
+ "input": "&barvee",
+ "description": "Bad named entity: barvee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&barvee"
+ ]
+ ]
+ },
+ {
+ "input": "⊽",
+ "description": "Named entity: barvee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22bd"
+ ]
+ ]
+ },
+ {
+ "input": "&barwed",
+ "description": "Bad named entity: barwed without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&barwed"
+ ]
+ ]
+ },
+ {
+ "input": "⌅",
+ "description": "Named entity: barwed; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2305"
+ ]
+ ]
+ },
+ {
+ "input": "&barwedge",
+ "description": "Bad named entity: barwedge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&barwedge"
+ ]
+ ]
+ },
+ {
+ "input": "⌅",
+ "description": "Named entity: barwedge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2305"
+ ]
+ ]
+ },
+ {
+ "input": "&bbrk",
+ "description": "Bad named entity: bbrk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bbrk"
+ ]
+ ]
+ },
+ {
+ "input": "⎵",
+ "description": "Named entity: bbrk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b5"
+ ]
+ ]
+ },
+ {
+ "input": "&bbrktbrk",
+ "description": "Bad named entity: bbrktbrk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bbrktbrk"
+ ]
+ ]
+ },
+ {
+ "input": "⎶",
+ "description": "Named entity: bbrktbrk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b6"
+ ]
+ ]
+ },
+ {
+ "input": "&bcong",
+ "description": "Bad named entity: bcong without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bcong"
+ ]
+ ]
+ },
+ {
+ "input": "≌",
+ "description": "Named entity: bcong; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224c"
+ ]
+ ]
+ },
+ {
+ "input": "&bcy",
+ "description": "Bad named entity: bcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bcy"
+ ]
+ ]
+ },
+ {
+ "input": "б",
+ "description": "Named entity: bcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0431"
+ ]
+ ]
+ },
+ {
+ "input": "&bdquo",
+ "description": "Bad named entity: bdquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bdquo"
+ ]
+ ]
+ },
+ {
+ "input": "„",
+ "description": "Named entity: bdquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201e"
+ ]
+ ]
+ },
+ {
+ "input": "&becaus",
+ "description": "Bad named entity: becaus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&becaus"
+ ]
+ ]
+ },
+ {
+ "input": "∵",
+ "description": "Named entity: becaus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2235"
+ ]
+ ]
+ },
+ {
+ "input": "&because",
+ "description": "Bad named entity: because without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&because"
+ ]
+ ]
+ },
+ {
+ "input": "∵",
+ "description": "Named entity: because; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2235"
+ ]
+ ]
+ },
+ {
+ "input": "&bemptyv",
+ "description": "Bad named entity: bemptyv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bemptyv"
+ ]
+ ]
+ },
+ {
+ "input": "⦰",
+ "description": "Named entity: bemptyv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b0"
+ ]
+ ]
+ },
+ {
+ "input": "&bepsi",
+ "description": "Bad named entity: bepsi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bepsi"
+ ]
+ ]
+ },
+ {
+ "input": "϶",
+ "description": "Named entity: bepsi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f6"
+ ]
+ ]
+ },
+ {
+ "input": "&bernou",
+ "description": "Bad named entity: bernou without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bernou"
+ ]
+ ]
+ },
+ {
+ "input": "ℬ",
+ "description": "Named entity: bernou; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u212c"
+ ]
+ ]
+ },
+ {
+ "input": "&beta",
+ "description": "Bad named entity: beta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&beta"
+ ]
+ ]
+ },
+ {
+ "input": "β",
+ "description": "Named entity: beta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b2"
+ ]
+ ]
+ },
+ {
+ "input": "&beth",
+ "description": "Bad named entity: beth without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&beth"
+ ]
+ ]
+ },
+ {
+ "input": "ℶ",
+ "description": "Named entity: beth; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2136"
+ ]
+ ]
+ },
+ {
+ "input": "&between",
+ "description": "Bad named entity: between without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&between"
+ ]
+ ]
+ },
+ {
+ "input": "≬",
+ "description": "Named entity: between; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226c"
+ ]
+ ]
+ },
+ {
+ "input": "&bfr",
+ "description": "Bad named entity: bfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔟",
+ "description": "Named entity: bfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd1f"
+ ]
+ ]
+ },
+ {
+ "input": "&bigcap",
+ "description": "Bad named entity: bigcap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigcap"
+ ]
+ ]
+ },
+ {
+ "input": "⋂",
+ "description": "Named entity: bigcap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c2"
+ ]
+ ]
+ },
+ {
+ "input": "&bigcirc",
+ "description": "Bad named entity: bigcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigcirc"
+ ]
+ ]
+ },
+ {
+ "input": "◯",
+ "description": "Named entity: bigcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25ef"
+ ]
+ ]
+ },
+ {
+ "input": "&bigcup",
+ "description": "Bad named entity: bigcup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigcup"
+ ]
+ ]
+ },
+ {
+ "input": "⋃",
+ "description": "Named entity: bigcup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c3"
+ ]
+ ]
+ },
+ {
+ "input": "&bigodot",
+ "description": "Bad named entity: bigodot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigodot"
+ ]
+ ]
+ },
+ {
+ "input": "⨀",
+ "description": "Named entity: bigodot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a00"
+ ]
+ ]
+ },
+ {
+ "input": "&bigoplus",
+ "description": "Bad named entity: bigoplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigoplus"
+ ]
+ ]
+ },
+ {
+ "input": "⨁",
+ "description": "Named entity: bigoplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a01"
+ ]
+ ]
+ },
+ {
+ "input": "&bigotimes",
+ "description": "Bad named entity: bigotimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigotimes"
+ ]
+ ]
+ },
+ {
+ "input": "⨂",
+ "description": "Named entity: bigotimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a02"
+ ]
+ ]
+ },
+ {
+ "input": "&bigsqcup",
+ "description": "Bad named entity: bigsqcup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigsqcup"
+ ]
+ ]
+ },
+ {
+ "input": "⨆",
+ "description": "Named entity: bigsqcup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a06"
+ ]
+ ]
+ },
+ {
+ "input": "&bigstar",
+ "description": "Bad named entity: bigstar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigstar"
+ ]
+ ]
+ },
+ {
+ "input": "★",
+ "description": "Named entity: bigstar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2605"
+ ]
+ ]
+ },
+ {
+ "input": "&bigtriangledown",
+ "description": "Bad named entity: bigtriangledown without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigtriangledown"
+ ]
+ ]
+ },
+ {
+ "input": "▽",
+ "description": "Named entity: bigtriangledown; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25bd"
+ ]
+ ]
+ },
+ {
+ "input": "&bigtriangleup",
+ "description": "Bad named entity: bigtriangleup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigtriangleup"
+ ]
+ ]
+ },
+ {
+ "input": "△",
+ "description": "Named entity: bigtriangleup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b3"
+ ]
+ ]
+ },
+ {
+ "input": "&biguplus",
+ "description": "Bad named entity: biguplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&biguplus"
+ ]
+ ]
+ },
+ {
+ "input": "⨄",
+ "description": "Named entity: biguplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a04"
+ ]
+ ]
+ },
+ {
+ "input": "&bigvee",
+ "description": "Bad named entity: bigvee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigvee"
+ ]
+ ]
+ },
+ {
+ "input": "⋁",
+ "description": "Named entity: bigvee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c1"
+ ]
+ ]
+ },
+ {
+ "input": "&bigwedge",
+ "description": "Bad named entity: bigwedge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bigwedge"
+ ]
+ ]
+ },
+ {
+ "input": "⋀",
+ "description": "Named entity: bigwedge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c0"
+ ]
+ ]
+ },
+ {
+ "input": "&bkarow",
+ "description": "Bad named entity: bkarow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bkarow"
+ ]
+ ]
+ },
+ {
+ "input": "⤍",
+ "description": "Named entity: bkarow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u290d"
+ ]
+ ]
+ },
+ {
+ "input": "&blacklozenge",
+ "description": "Bad named entity: blacklozenge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blacklozenge"
+ ]
+ ]
+ },
+ {
+ "input": "⧫",
+ "description": "Named entity: blacklozenge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29eb"
+ ]
+ ]
+ },
+ {
+ "input": "&blacksquare",
+ "description": "Bad named entity: blacksquare without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blacksquare"
+ ]
+ ]
+ },
+ {
+ "input": "▪",
+ "description": "Named entity: blacksquare; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25aa"
+ ]
+ ]
+ },
+ {
+ "input": "&blacktriangle",
+ "description": "Bad named entity: blacktriangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blacktriangle"
+ ]
+ ]
+ },
+ {
+ "input": "▴",
+ "description": "Named entity: blacktriangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b4"
+ ]
+ ]
+ },
+ {
+ "input": "&blacktriangledown",
+ "description": "Bad named entity: blacktriangledown without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blacktriangledown"
+ ]
+ ]
+ },
+ {
+ "input": "▾",
+ "description": "Named entity: blacktriangledown; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25be"
+ ]
+ ]
+ },
+ {
+ "input": "&blacktriangleleft",
+ "description": "Bad named entity: blacktriangleleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blacktriangleleft"
+ ]
+ ]
+ },
+ {
+ "input": "◂",
+ "description": "Named entity: blacktriangleleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25c2"
+ ]
+ ]
+ },
+ {
+ "input": "&blacktriangleright",
+ "description": "Bad named entity: blacktriangleright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blacktriangleright"
+ ]
+ ]
+ },
+ {
+ "input": "▸",
+ "description": "Named entity: blacktriangleright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b8"
+ ]
+ ]
+ },
+ {
+ "input": "&blank",
+ "description": "Bad named entity: blank without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blank"
+ ]
+ ]
+ },
+ {
+ "input": "␣",
+ "description": "Named entity: blank; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2423"
+ ]
+ ]
+ },
+ {
+ "input": "&blk12",
+ "description": "Bad named entity: blk12 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blk12"
+ ]
+ ]
+ },
+ {
+ "input": "▒",
+ "description": "Named entity: blk12; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2592"
+ ]
+ ]
+ },
+ {
+ "input": "&blk14",
+ "description": "Bad named entity: blk14 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blk14"
+ ]
+ ]
+ },
+ {
+ "input": "░",
+ "description": "Named entity: blk14; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2591"
+ ]
+ ]
+ },
+ {
+ "input": "&blk34",
+ "description": "Bad named entity: blk34 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&blk34"
+ ]
+ ]
+ },
+ {
+ "input": "▓",
+ "description": "Named entity: blk34; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2593"
+ ]
+ ]
+ },
+ {
+ "input": "&block",
+ "description": "Bad named entity: block without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&block"
+ ]
+ ]
+ },
+ {
+ "input": "█",
+ "description": "Named entity: block; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2588"
+ ]
+ ]
+ },
+ {
+ "input": "&bne",
+ "description": "Bad named entity: bne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bne"
+ ]
+ ]
+ },
+ {
+ "input": "=⃥",
+ "description": "Named entity: bne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "=\u20e5"
+ ]
+ ]
+ },
+ {
+ "input": "&bnequiv",
+ "description": "Bad named entity: bnequiv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bnequiv"
+ ]
+ ]
+ },
+ {
+ "input": "≡⃥",
+ "description": "Named entity: bnequiv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2261\u20e5"
+ ]
+ ]
+ },
+ {
+ "input": "&bnot",
+ "description": "Bad named entity: bnot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bnot"
+ ]
+ ]
+ },
+ {
+ "input": "⌐",
+ "description": "Named entity: bnot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2310"
+ ]
+ ]
+ },
+ {
+ "input": "&bopf",
+ "description": "Bad named entity: bopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕓",
+ "description": "Named entity: bopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd53"
+ ]
+ ]
+ },
+ {
+ "input": "&bot",
+ "description": "Bad named entity: bot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bot"
+ ]
+ ]
+ },
+ {
+ "input": "⊥",
+ "description": "Named entity: bot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a5"
+ ]
+ ]
+ },
+ {
+ "input": "&bottom",
+ "description": "Bad named entity: bottom without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bottom"
+ ]
+ ]
+ },
+ {
+ "input": "⊥",
+ "description": "Named entity: bottom; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a5"
+ ]
+ ]
+ },
+ {
+ "input": "&bowtie",
+ "description": "Bad named entity: bowtie without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bowtie"
+ ]
+ ]
+ },
+ {
+ "input": "⋈",
+ "description": "Named entity: bowtie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c8"
+ ]
+ ]
+ },
+ {
+ "input": "&boxDL",
+ "description": "Bad named entity: boxDL without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxDL"
+ ]
+ ]
+ },
+ {
+ "input": "╗",
+ "description": "Named entity: boxDL; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2557"
+ ]
+ ]
+ },
+ {
+ "input": "&boxDR",
+ "description": "Bad named entity: boxDR without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxDR"
+ ]
+ ]
+ },
+ {
+ "input": "╔",
+ "description": "Named entity: boxDR; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2554"
+ ]
+ ]
+ },
+ {
+ "input": "&boxDl",
+ "description": "Bad named entity: boxDl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxDl"
+ ]
+ ]
+ },
+ {
+ "input": "╖",
+ "description": "Named entity: boxDl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2556"
+ ]
+ ]
+ },
+ {
+ "input": "&boxDr",
+ "description": "Bad named entity: boxDr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxDr"
+ ]
+ ]
+ },
+ {
+ "input": "╓",
+ "description": "Named entity: boxDr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2553"
+ ]
+ ]
+ },
+ {
+ "input": "&boxH",
+ "description": "Bad named entity: boxH without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxH"
+ ]
+ ]
+ },
+ {
+ "input": "═",
+ "description": "Named entity: boxH; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2550"
+ ]
+ ]
+ },
+ {
+ "input": "&boxHD",
+ "description": "Bad named entity: boxHD without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxHD"
+ ]
+ ]
+ },
+ {
+ "input": "╦",
+ "description": "Named entity: boxHD; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2566"
+ ]
+ ]
+ },
+ {
+ "input": "&boxHU",
+ "description": "Bad named entity: boxHU without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxHU"
+ ]
+ ]
+ },
+ {
+ "input": "╩",
+ "description": "Named entity: boxHU; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2569"
+ ]
+ ]
+ },
+ {
+ "input": "&boxHd",
+ "description": "Bad named entity: boxHd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxHd"
+ ]
+ ]
+ },
+ {
+ "input": "╤",
+ "description": "Named entity: boxHd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2564"
+ ]
+ ]
+ },
+ {
+ "input": "&boxHu",
+ "description": "Bad named entity: boxHu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxHu"
+ ]
+ ]
+ },
+ {
+ "input": "╧",
+ "description": "Named entity: boxHu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2567"
+ ]
+ ]
+ },
+ {
+ "input": "&boxUL",
+ "description": "Bad named entity: boxUL without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxUL"
+ ]
+ ]
+ },
+ {
+ "input": "╝",
+ "description": "Named entity: boxUL; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u255d"
+ ]
+ ]
+ },
+ {
+ "input": "&boxUR",
+ "description": "Bad named entity: boxUR without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxUR"
+ ]
+ ]
+ },
+ {
+ "input": "╚",
+ "description": "Named entity: boxUR; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u255a"
+ ]
+ ]
+ },
+ {
+ "input": "&boxUl",
+ "description": "Bad named entity: boxUl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxUl"
+ ]
+ ]
+ },
+ {
+ "input": "╜",
+ "description": "Named entity: boxUl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u255c"
+ ]
+ ]
+ },
+ {
+ "input": "&boxUr",
+ "description": "Bad named entity: boxUr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxUr"
+ ]
+ ]
+ },
+ {
+ "input": "╙",
+ "description": "Named entity: boxUr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2559"
+ ]
+ ]
+ },
+ {
+ "input": "&boxV",
+ "description": "Bad named entity: boxV without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxV"
+ ]
+ ]
+ },
+ {
+ "input": "║",
+ "description": "Named entity: boxV; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2551"
+ ]
+ ]
+ },
+ {
+ "input": "&boxVH",
+ "description": "Bad named entity: boxVH without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxVH"
+ ]
+ ]
+ },
+ {
+ "input": "╬",
+ "description": "Named entity: boxVH; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u256c"
+ ]
+ ]
+ },
+ {
+ "input": "&boxVL",
+ "description": "Bad named entity: boxVL without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxVL"
+ ]
+ ]
+ },
+ {
+ "input": "╣",
+ "description": "Named entity: boxVL; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2563"
+ ]
+ ]
+ },
+ {
+ "input": "&boxVR",
+ "description": "Bad named entity: boxVR without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxVR"
+ ]
+ ]
+ },
+ {
+ "input": "╠",
+ "description": "Named entity: boxVR; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2560"
+ ]
+ ]
+ },
+ {
+ "input": "&boxVh",
+ "description": "Bad named entity: boxVh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxVh"
+ ]
+ ]
+ },
+ {
+ "input": "╫",
+ "description": "Named entity: boxVh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u256b"
+ ]
+ ]
+ },
+ {
+ "input": "&boxVl",
+ "description": "Bad named entity: boxVl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxVl"
+ ]
+ ]
+ },
+ {
+ "input": "╢",
+ "description": "Named entity: boxVl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2562"
+ ]
+ ]
+ },
+ {
+ "input": "&boxVr",
+ "description": "Bad named entity: boxVr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxVr"
+ ]
+ ]
+ },
+ {
+ "input": "╟",
+ "description": "Named entity: boxVr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u255f"
+ ]
+ ]
+ },
+ {
+ "input": "&boxbox",
+ "description": "Bad named entity: boxbox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxbox"
+ ]
+ ]
+ },
+ {
+ "input": "⧉",
+ "description": "Named entity: boxbox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29c9"
+ ]
+ ]
+ },
+ {
+ "input": "&boxdL",
+ "description": "Bad named entity: boxdL without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxdL"
+ ]
+ ]
+ },
+ {
+ "input": "╕",
+ "description": "Named entity: boxdL; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2555"
+ ]
+ ]
+ },
+ {
+ "input": "&boxdR",
+ "description": "Bad named entity: boxdR without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxdR"
+ ]
+ ]
+ },
+ {
+ "input": "╒",
+ "description": "Named entity: boxdR; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2552"
+ ]
+ ]
+ },
+ {
+ "input": "&boxdl",
+ "description": "Bad named entity: boxdl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxdl"
+ ]
+ ]
+ },
+ {
+ "input": "┐",
+ "description": "Named entity: boxdl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2510"
+ ]
+ ]
+ },
+ {
+ "input": "&boxdr",
+ "description": "Bad named entity: boxdr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxdr"
+ ]
+ ]
+ },
+ {
+ "input": "┌",
+ "description": "Named entity: boxdr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u250c"
+ ]
+ ]
+ },
+ {
+ "input": "&boxh",
+ "description": "Bad named entity: boxh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxh"
+ ]
+ ]
+ },
+ {
+ "input": "─",
+ "description": "Named entity: boxh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2500"
+ ]
+ ]
+ },
+ {
+ "input": "&boxhD",
+ "description": "Bad named entity: boxhD without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxhD"
+ ]
+ ]
+ },
+ {
+ "input": "╥",
+ "description": "Named entity: boxhD; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2565"
+ ]
+ ]
+ },
+ {
+ "input": "&boxhU",
+ "description": "Bad named entity: boxhU without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxhU"
+ ]
+ ]
+ },
+ {
+ "input": "╨",
+ "description": "Named entity: boxhU; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2568"
+ ]
+ ]
+ },
+ {
+ "input": "&boxhd",
+ "description": "Bad named entity: boxhd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxhd"
+ ]
+ ]
+ },
+ {
+ "input": "┬",
+ "description": "Named entity: boxhd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u252c"
+ ]
+ ]
+ },
+ {
+ "input": "&boxhu",
+ "description": "Bad named entity: boxhu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxhu"
+ ]
+ ]
+ },
+ {
+ "input": "┴",
+ "description": "Named entity: boxhu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2534"
+ ]
+ ]
+ },
+ {
+ "input": "&boxminus",
+ "description": "Bad named entity: boxminus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxminus"
+ ]
+ ]
+ },
+ {
+ "input": "⊟",
+ "description": "Named entity: boxminus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229f"
+ ]
+ ]
+ },
+ {
+ "input": "&boxplus",
+ "description": "Bad named entity: boxplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxplus"
+ ]
+ ]
+ },
+ {
+ "input": "⊞",
+ "description": "Named entity: boxplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229e"
+ ]
+ ]
+ },
+ {
+ "input": "&boxtimes",
+ "description": "Bad named entity: boxtimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxtimes"
+ ]
+ ]
+ },
+ {
+ "input": "⊠",
+ "description": "Named entity: boxtimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a0"
+ ]
+ ]
+ },
+ {
+ "input": "&boxuL",
+ "description": "Bad named entity: boxuL without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxuL"
+ ]
+ ]
+ },
+ {
+ "input": "╛",
+ "description": "Named entity: boxuL; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u255b"
+ ]
+ ]
+ },
+ {
+ "input": "&boxuR",
+ "description": "Bad named entity: boxuR without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxuR"
+ ]
+ ]
+ },
+ {
+ "input": "╘",
+ "description": "Named entity: boxuR; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2558"
+ ]
+ ]
+ },
+ {
+ "input": "&boxul",
+ "description": "Bad named entity: boxul without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxul"
+ ]
+ ]
+ },
+ {
+ "input": "┘",
+ "description": "Named entity: boxul; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2518"
+ ]
+ ]
+ },
+ {
+ "input": "&boxur",
+ "description": "Bad named entity: boxur without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxur"
+ ]
+ ]
+ },
+ {
+ "input": "└",
+ "description": "Named entity: boxur; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2514"
+ ]
+ ]
+ },
+ {
+ "input": "&boxv",
+ "description": "Bad named entity: boxv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxv"
+ ]
+ ]
+ },
+ {
+ "input": "│",
+ "description": "Named entity: boxv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2502"
+ ]
+ ]
+ },
+ {
+ "input": "&boxvH",
+ "description": "Bad named entity: boxvH without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxvH"
+ ]
+ ]
+ },
+ {
+ "input": "╪",
+ "description": "Named entity: boxvH; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u256a"
+ ]
+ ]
+ },
+ {
+ "input": "&boxvL",
+ "description": "Bad named entity: boxvL without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxvL"
+ ]
+ ]
+ },
+ {
+ "input": "╡",
+ "description": "Named entity: boxvL; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2561"
+ ]
+ ]
+ },
+ {
+ "input": "&boxvR",
+ "description": "Bad named entity: boxvR without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxvR"
+ ]
+ ]
+ },
+ {
+ "input": "╞",
+ "description": "Named entity: boxvR; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u255e"
+ ]
+ ]
+ },
+ {
+ "input": "&boxvh",
+ "description": "Bad named entity: boxvh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxvh"
+ ]
+ ]
+ },
+ {
+ "input": "┼",
+ "description": "Named entity: boxvh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u253c"
+ ]
+ ]
+ },
+ {
+ "input": "&boxvl",
+ "description": "Bad named entity: boxvl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxvl"
+ ]
+ ]
+ },
+ {
+ "input": "┤",
+ "description": "Named entity: boxvl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2524"
+ ]
+ ]
+ },
+ {
+ "input": "&boxvr",
+ "description": "Bad named entity: boxvr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&boxvr"
+ ]
+ ]
+ },
+ {
+ "input": "├",
+ "description": "Named entity: boxvr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u251c"
+ ]
+ ]
+ },
+ {
+ "input": "&bprime",
+ "description": "Bad named entity: bprime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bprime"
+ ]
+ ]
+ },
+ {
+ "input": "‵",
+ "description": "Named entity: bprime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2035"
+ ]
+ ]
+ },
+ {
+ "input": "&breve",
+ "description": "Bad named entity: breve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&breve"
+ ]
+ ]
+ },
+ {
+ "input": "˘",
+ "description": "Named entity: breve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02d8"
+ ]
+ ]
+ },
+ {
+ "input": "¦",
+ "description": "Named entity: brvbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a6"
+ ]
+ ]
+ },
+ {
+ "input": "¦",
+ "description": "Named entity: brvbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a6"
+ ]
+ ]
+ },
+ {
+ "input": "&bscr",
+ "description": "Bad named entity: bscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒷",
+ "description": "Named entity: bscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb7"
+ ]
+ ]
+ },
+ {
+ "input": "&bsemi",
+ "description": "Bad named entity: bsemi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bsemi"
+ ]
+ ]
+ },
+ {
+ "input": "⁏",
+ "description": "Named entity: bsemi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u204f"
+ ]
+ ]
+ },
+ {
+ "input": "&bsim",
+ "description": "Bad named entity: bsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bsim"
+ ]
+ ]
+ },
+ {
+ "input": "∽",
+ "description": "Named entity: bsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223d"
+ ]
+ ]
+ },
+ {
+ "input": "&bsime",
+ "description": "Bad named entity: bsime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bsime"
+ ]
+ ]
+ },
+ {
+ "input": "⋍",
+ "description": "Named entity: bsime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22cd"
+ ]
+ ]
+ },
+ {
+ "input": "&bsol",
+ "description": "Bad named entity: bsol without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bsol"
+ ]
+ ]
+ },
+ {
+ "input": "\",
+ "description": "Named entity: bsol; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\\"
+ ]
+ ]
+ },
+ {
+ "input": "&bsolb",
+ "description": "Bad named entity: bsolb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bsolb"
+ ]
+ ]
+ },
+ {
+ "input": "⧅",
+ "description": "Named entity: bsolb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29c5"
+ ]
+ ]
+ },
+ {
+ "input": "&bsolhsub",
+ "description": "Bad named entity: bsolhsub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bsolhsub"
+ ]
+ ]
+ },
+ {
+ "input": "⟈",
+ "description": "Named entity: bsolhsub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27c8"
+ ]
+ ]
+ },
+ {
+ "input": "&bull",
+ "description": "Bad named entity: bull without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bull"
+ ]
+ ]
+ },
+ {
+ "input": "•",
+ "description": "Named entity: bull; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2022"
+ ]
+ ]
+ },
+ {
+ "input": "&bullet",
+ "description": "Bad named entity: bullet without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bullet"
+ ]
+ ]
+ },
+ {
+ "input": "•",
+ "description": "Named entity: bullet; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2022"
+ ]
+ ]
+ },
+ {
+ "input": "&bump",
+ "description": "Bad named entity: bump without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bump"
+ ]
+ ]
+ },
+ {
+ "input": "≎",
+ "description": "Named entity: bump; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224e"
+ ]
+ ]
+ },
+ {
+ "input": "&bumpE",
+ "description": "Bad named entity: bumpE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bumpE"
+ ]
+ ]
+ },
+ {
+ "input": "⪮",
+ "description": "Named entity: bumpE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aae"
+ ]
+ ]
+ },
+ {
+ "input": "&bumpe",
+ "description": "Bad named entity: bumpe without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bumpe"
+ ]
+ ]
+ },
+ {
+ "input": "≏",
+ "description": "Named entity: bumpe; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224f"
+ ]
+ ]
+ },
+ {
+ "input": "&bumpeq",
+ "description": "Bad named entity: bumpeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&bumpeq"
+ ]
+ ]
+ },
+ {
+ "input": "≏",
+ "description": "Named entity: bumpeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224f"
+ ]
+ ]
+ },
+ {
+ "input": "&cacute",
+ "description": "Bad named entity: cacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cacute"
+ ]
+ ]
+ },
+ {
+ "input": "ć",
+ "description": "Named entity: cacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0107"
+ ]
+ ]
+ },
+ {
+ "input": "&cap",
+ "description": "Bad named entity: cap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cap"
+ ]
+ ]
+ },
+ {
+ "input": "∩",
+ "description": "Named entity: cap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2229"
+ ]
+ ]
+ },
+ {
+ "input": "&capand",
+ "description": "Bad named entity: capand without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&capand"
+ ]
+ ]
+ },
+ {
+ "input": "⩄",
+ "description": "Named entity: capand; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a44"
+ ]
+ ]
+ },
+ {
+ "input": "&capbrcup",
+ "description": "Bad named entity: capbrcup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&capbrcup"
+ ]
+ ]
+ },
+ {
+ "input": "⩉",
+ "description": "Named entity: capbrcup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a49"
+ ]
+ ]
+ },
+ {
+ "input": "&capcap",
+ "description": "Bad named entity: capcap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&capcap"
+ ]
+ ]
+ },
+ {
+ "input": "⩋",
+ "description": "Named entity: capcap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a4b"
+ ]
+ ]
+ },
+ {
+ "input": "&capcup",
+ "description": "Bad named entity: capcup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&capcup"
+ ]
+ ]
+ },
+ {
+ "input": "⩇",
+ "description": "Named entity: capcup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a47"
+ ]
+ ]
+ },
+ {
+ "input": "&capdot",
+ "description": "Bad named entity: capdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&capdot"
+ ]
+ ]
+ },
+ {
+ "input": "⩀",
+ "description": "Named entity: capdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a40"
+ ]
+ ]
+ },
+ {
+ "input": "&caps",
+ "description": "Bad named entity: caps without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&caps"
+ ]
+ ]
+ },
+ {
+ "input": "∩︀",
+ "description": "Named entity: caps; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2229\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&caret",
+ "description": "Bad named entity: caret without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&caret"
+ ]
+ ]
+ },
+ {
+ "input": "⁁",
+ "description": "Named entity: caret; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2041"
+ ]
+ ]
+ },
+ {
+ "input": "&caron",
+ "description": "Bad named entity: caron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&caron"
+ ]
+ ]
+ },
+ {
+ "input": "ˇ",
+ "description": "Named entity: caron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02c7"
+ ]
+ ]
+ },
+ {
+ "input": "&ccaps",
+ "description": "Bad named entity: ccaps without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ccaps"
+ ]
+ ]
+ },
+ {
+ "input": "⩍",
+ "description": "Named entity: ccaps; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a4d"
+ ]
+ ]
+ },
+ {
+ "input": "&ccaron",
+ "description": "Bad named entity: ccaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ccaron"
+ ]
+ ]
+ },
+ {
+ "input": "č",
+ "description": "Named entity: ccaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u010d"
+ ]
+ ]
+ },
+ {
+ "input": "ç",
+ "description": "Named entity: ccedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e7"
+ ]
+ ]
+ },
+ {
+ "input": "ç",
+ "description": "Named entity: ccedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e7"
+ ]
+ ]
+ },
+ {
+ "input": "&ccirc",
+ "description": "Bad named entity: ccirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ccirc"
+ ]
+ ]
+ },
+ {
+ "input": "ĉ",
+ "description": "Named entity: ccirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0109"
+ ]
+ ]
+ },
+ {
+ "input": "&ccups",
+ "description": "Bad named entity: ccups without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ccups"
+ ]
+ ]
+ },
+ {
+ "input": "⩌",
+ "description": "Named entity: ccups; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a4c"
+ ]
+ ]
+ },
+ {
+ "input": "&ccupssm",
+ "description": "Bad named entity: ccupssm without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ccupssm"
+ ]
+ ]
+ },
+ {
+ "input": "⩐",
+ "description": "Named entity: ccupssm; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a50"
+ ]
+ ]
+ },
+ {
+ "input": "&cdot",
+ "description": "Bad named entity: cdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cdot"
+ ]
+ ]
+ },
+ {
+ "input": "ċ",
+ "description": "Named entity: cdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u010b"
+ ]
+ ]
+ },
+ {
+ "input": "¸",
+ "description": "Named entity: cedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b8"
+ ]
+ ]
+ },
+ {
+ "input": "¸",
+ "description": "Named entity: cedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b8"
+ ]
+ ]
+ },
+ {
+ "input": "&cemptyv",
+ "description": "Bad named entity: cemptyv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cemptyv"
+ ]
+ ]
+ },
+ {
+ "input": "⦲",
+ "description": "Named entity: cemptyv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b2"
+ ]
+ ]
+ },
+ {
+ "input": "¢",
+ "description": "Named entity: cent without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a2"
+ ]
+ ]
+ },
+ {
+ "input": "¢",
+ "description": "Named entity: cent; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a2"
+ ]
+ ]
+ },
+ {
+ "input": "·",
+ "description": "Named entity: centerdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b7"
+ ]
+ ]
+ },
+ {
+ "input": "&cfr",
+ "description": "Bad named entity: cfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔠",
+ "description": "Named entity: cfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd20"
+ ]
+ ]
+ },
+ {
+ "input": "&chcy",
+ "description": "Bad named entity: chcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&chcy"
+ ]
+ ]
+ },
+ {
+ "input": "ч",
+ "description": "Named entity: chcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0447"
+ ]
+ ]
+ },
+ {
+ "input": "&check",
+ "description": "Bad named entity: check without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&check"
+ ]
+ ]
+ },
+ {
+ "input": "✓",
+ "description": "Named entity: check; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2713"
+ ]
+ ]
+ },
+ {
+ "input": "&checkmark",
+ "description": "Bad named entity: checkmark without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&checkmark"
+ ]
+ ]
+ },
+ {
+ "input": "✓",
+ "description": "Named entity: checkmark; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2713"
+ ]
+ ]
+ },
+ {
+ "input": "&chi",
+ "description": "Bad named entity: chi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&chi"
+ ]
+ ]
+ },
+ {
+ "input": "χ",
+ "description": "Named entity: chi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c7"
+ ]
+ ]
+ },
+ {
+ "input": "&cir",
+ "description": "Bad named entity: cir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cir"
+ ]
+ ]
+ },
+ {
+ "input": "○",
+ "description": "Named entity: cir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25cb"
+ ]
+ ]
+ },
+ {
+ "input": "&cirE",
+ "description": "Bad named entity: cirE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cirE"
+ ]
+ ]
+ },
+ {
+ "input": "⧃",
+ "description": "Named entity: cirE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29c3"
+ ]
+ ]
+ },
+ {
+ "input": "&circ",
+ "description": "Bad named entity: circ without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circ"
+ ]
+ ]
+ },
+ {
+ "input": "ˆ",
+ "description": "Named entity: circ; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02c6"
+ ]
+ ]
+ },
+ {
+ "input": "&circeq",
+ "description": "Bad named entity: circeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circeq"
+ ]
+ ]
+ },
+ {
+ "input": "≗",
+ "description": "Named entity: circeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2257"
+ ]
+ ]
+ },
+ {
+ "input": "&circlearrowleft",
+ "description": "Bad named entity: circlearrowleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circlearrowleft"
+ ]
+ ]
+ },
+ {
+ "input": "↺",
+ "description": "Named entity: circlearrowleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ba"
+ ]
+ ]
+ },
+ {
+ "input": "&circlearrowright",
+ "description": "Bad named entity: circlearrowright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circlearrowright"
+ ]
+ ]
+ },
+ {
+ "input": "↻",
+ "description": "Named entity: circlearrowright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bb"
+ ]
+ ]
+ },
+ {
+ "input": "&circledR",
+ "description": "Bad named entity: circledR without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circledR"
+ ]
+ ]
+ },
+ {
+ "input": "®",
+ "description": "Named entity: circledR; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ae"
+ ]
+ ]
+ },
+ {
+ "input": "&circledS",
+ "description": "Bad named entity: circledS without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circledS"
+ ]
+ ]
+ },
+ {
+ "input": "Ⓢ",
+ "description": "Named entity: circledS; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u24c8"
+ ]
+ ]
+ },
+ {
+ "input": "&circledast",
+ "description": "Bad named entity: circledast without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circledast"
+ ]
+ ]
+ },
+ {
+ "input": "⊛",
+ "description": "Named entity: circledast; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229b"
+ ]
+ ]
+ },
+ {
+ "input": "&circledcirc",
+ "description": "Bad named entity: circledcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circledcirc"
+ ]
+ ]
+ },
+ {
+ "input": "⊚",
+ "description": "Named entity: circledcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229a"
+ ]
+ ]
+ },
+ {
+ "input": "&circleddash",
+ "description": "Bad named entity: circleddash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&circleddash"
+ ]
+ ]
+ },
+ {
+ "input": "⊝",
+ "description": "Named entity: circleddash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229d"
+ ]
+ ]
+ },
+ {
+ "input": "&cire",
+ "description": "Bad named entity: cire without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cire"
+ ]
+ ]
+ },
+ {
+ "input": "≗",
+ "description": "Named entity: cire; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2257"
+ ]
+ ]
+ },
+ {
+ "input": "&cirfnint",
+ "description": "Bad named entity: cirfnint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cirfnint"
+ ]
+ ]
+ },
+ {
+ "input": "⨐",
+ "description": "Named entity: cirfnint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a10"
+ ]
+ ]
+ },
+ {
+ "input": "&cirmid",
+ "description": "Bad named entity: cirmid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cirmid"
+ ]
+ ]
+ },
+ {
+ "input": "⫯",
+ "description": "Named entity: cirmid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aef"
+ ]
+ ]
+ },
+ {
+ "input": "&cirscir",
+ "description": "Bad named entity: cirscir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cirscir"
+ ]
+ ]
+ },
+ {
+ "input": "⧂",
+ "description": "Named entity: cirscir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29c2"
+ ]
+ ]
+ },
+ {
+ "input": "&clubs",
+ "description": "Bad named entity: clubs without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&clubs"
+ ]
+ ]
+ },
+ {
+ "input": "♣",
+ "description": "Named entity: clubs; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2663"
+ ]
+ ]
+ },
+ {
+ "input": "&clubsuit",
+ "description": "Bad named entity: clubsuit without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&clubsuit"
+ ]
+ ]
+ },
+ {
+ "input": "♣",
+ "description": "Named entity: clubsuit; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2663"
+ ]
+ ]
+ },
+ {
+ "input": "&colon",
+ "description": "Bad named entity: colon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&colon"
+ ]
+ ]
+ },
+ {
+ "input": ":",
+ "description": "Named entity: colon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ ":"
+ ]
+ ]
+ },
+ {
+ "input": "&colone",
+ "description": "Bad named entity: colone without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&colone"
+ ]
+ ]
+ },
+ {
+ "input": "≔",
+ "description": "Named entity: colone; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2254"
+ ]
+ ]
+ },
+ {
+ "input": "&coloneq",
+ "description": "Bad named entity: coloneq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&coloneq"
+ ]
+ ]
+ },
+ {
+ "input": "≔",
+ "description": "Named entity: coloneq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2254"
+ ]
+ ]
+ },
+ {
+ "input": "&comma",
+ "description": "Bad named entity: comma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&comma"
+ ]
+ ]
+ },
+ {
+ "input": ",",
+ "description": "Named entity: comma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ ","
+ ]
+ ]
+ },
+ {
+ "input": "&commat",
+ "description": "Bad named entity: commat without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&commat"
+ ]
+ ]
+ },
+ {
+ "input": "@",
+ "description": "Named entity: commat; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "@"
+ ]
+ ]
+ },
+ {
+ "input": "&comp",
+ "description": "Bad named entity: comp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&comp"
+ ]
+ ]
+ },
+ {
+ "input": "∁",
+ "description": "Named entity: comp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2201"
+ ]
+ ]
+ },
+ {
+ "input": "&compfn",
+ "description": "Bad named entity: compfn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&compfn"
+ ]
+ ]
+ },
+ {
+ "input": "∘",
+ "description": "Named entity: compfn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2218"
+ ]
+ ]
+ },
+ {
+ "input": "&complement",
+ "description": "Bad named entity: complement without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&complement"
+ ]
+ ]
+ },
+ {
+ "input": "∁",
+ "description": "Named entity: complement; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2201"
+ ]
+ ]
+ },
+ {
+ "input": "&complexes",
+ "description": "Bad named entity: complexes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&complexes"
+ ]
+ ]
+ },
+ {
+ "input": "ℂ",
+ "description": "Named entity: complexes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2102"
+ ]
+ ]
+ },
+ {
+ "input": "&cong",
+ "description": "Bad named entity: cong without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cong"
+ ]
+ ]
+ },
+ {
+ "input": "≅",
+ "description": "Named entity: cong; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2245"
+ ]
+ ]
+ },
+ {
+ "input": "&congdot",
+ "description": "Bad named entity: congdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&congdot"
+ ]
+ ]
+ },
+ {
+ "input": "⩭",
+ "description": "Named entity: congdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a6d"
+ ]
+ ]
+ },
+ {
+ "input": "&conint",
+ "description": "Bad named entity: conint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&conint"
+ ]
+ ]
+ },
+ {
+ "input": "∮",
+ "description": "Named entity: conint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222e"
+ ]
+ ]
+ },
+ {
+ "input": "&copf",
+ "description": "Bad named entity: copf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&copf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕔",
+ "description": "Named entity: copf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd54"
+ ]
+ ]
+ },
+ {
+ "input": "&coprod",
+ "description": "Bad named entity: coprod without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&coprod"
+ ]
+ ]
+ },
+ {
+ "input": "∐",
+ "description": "Named entity: coprod; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2210"
+ ]
+ ]
+ },
+ {
+ "input": "©",
+ "description": "Named entity: copy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a9"
+ ]
+ ]
+ },
+ {
+ "input": "©",
+ "description": "Named entity: copy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a9"
+ ]
+ ]
+ },
+ {
+ "input": "℗",
+ "description": "Named entity: copysr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2117"
+ ]
+ ]
+ },
+ {
+ "input": "&crarr",
+ "description": "Bad named entity: crarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&crarr"
+ ]
+ ]
+ },
+ {
+ "input": "↵",
+ "description": "Named entity: crarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b5"
+ ]
+ ]
+ },
+ {
+ "input": "&cross",
+ "description": "Bad named entity: cross without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cross"
+ ]
+ ]
+ },
+ {
+ "input": "✗",
+ "description": "Named entity: cross; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2717"
+ ]
+ ]
+ },
+ {
+ "input": "&cscr",
+ "description": "Bad named entity: cscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒸",
+ "description": "Named entity: cscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb8"
+ ]
+ ]
+ },
+ {
+ "input": "&csub",
+ "description": "Bad named entity: csub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&csub"
+ ]
+ ]
+ },
+ {
+ "input": "⫏",
+ "description": "Named entity: csub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acf"
+ ]
+ ]
+ },
+ {
+ "input": "&csube",
+ "description": "Bad named entity: csube without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&csube"
+ ]
+ ]
+ },
+ {
+ "input": "⫑",
+ "description": "Named entity: csube; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad1"
+ ]
+ ]
+ },
+ {
+ "input": "&csup",
+ "description": "Bad named entity: csup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&csup"
+ ]
+ ]
+ },
+ {
+ "input": "⫐",
+ "description": "Named entity: csup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad0"
+ ]
+ ]
+ },
+ {
+ "input": "&csupe",
+ "description": "Bad named entity: csupe without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&csupe"
+ ]
+ ]
+ },
+ {
+ "input": "⫒",
+ "description": "Named entity: csupe; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad2"
+ ]
+ ]
+ },
+ {
+ "input": "&ctdot",
+ "description": "Bad named entity: ctdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ctdot"
+ ]
+ ]
+ },
+ {
+ "input": "⋯",
+ "description": "Named entity: ctdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ef"
+ ]
+ ]
+ },
+ {
+ "input": "&cudarrl",
+ "description": "Bad named entity: cudarrl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cudarrl"
+ ]
+ ]
+ },
+ {
+ "input": "⤸",
+ "description": "Named entity: cudarrl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2938"
+ ]
+ ]
+ },
+ {
+ "input": "&cudarrr",
+ "description": "Bad named entity: cudarrr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cudarrr"
+ ]
+ ]
+ },
+ {
+ "input": "⤵",
+ "description": "Named entity: cudarrr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2935"
+ ]
+ ]
+ },
+ {
+ "input": "&cuepr",
+ "description": "Bad named entity: cuepr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cuepr"
+ ]
+ ]
+ },
+ {
+ "input": "⋞",
+ "description": "Named entity: cuepr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22de"
+ ]
+ ]
+ },
+ {
+ "input": "&cuesc",
+ "description": "Bad named entity: cuesc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cuesc"
+ ]
+ ]
+ },
+ {
+ "input": "⋟",
+ "description": "Named entity: cuesc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22df"
+ ]
+ ]
+ },
+ {
+ "input": "&cularr",
+ "description": "Bad named entity: cularr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cularr"
+ ]
+ ]
+ },
+ {
+ "input": "↶",
+ "description": "Named entity: cularr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b6"
+ ]
+ ]
+ },
+ {
+ "input": "&cularrp",
+ "description": "Bad named entity: cularrp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cularrp"
+ ]
+ ]
+ },
+ {
+ "input": "⤽",
+ "description": "Named entity: cularrp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u293d"
+ ]
+ ]
+ },
+ {
+ "input": "&cup",
+ "description": "Bad named entity: cup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cup"
+ ]
+ ]
+ },
+ {
+ "input": "∪",
+ "description": "Named entity: cup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222a"
+ ]
+ ]
+ },
+ {
+ "input": "&cupbrcap",
+ "description": "Bad named entity: cupbrcap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cupbrcap"
+ ]
+ ]
+ },
+ {
+ "input": "⩈",
+ "description": "Named entity: cupbrcap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a48"
+ ]
+ ]
+ },
+ {
+ "input": "&cupcap",
+ "description": "Bad named entity: cupcap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cupcap"
+ ]
+ ]
+ },
+ {
+ "input": "⩆",
+ "description": "Named entity: cupcap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a46"
+ ]
+ ]
+ },
+ {
+ "input": "&cupcup",
+ "description": "Bad named entity: cupcup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cupcup"
+ ]
+ ]
+ },
+ {
+ "input": "⩊",
+ "description": "Named entity: cupcup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a4a"
+ ]
+ ]
+ },
+ {
+ "input": "&cupdot",
+ "description": "Bad named entity: cupdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cupdot"
+ ]
+ ]
+ },
+ {
+ "input": "⊍",
+ "description": "Named entity: cupdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228d"
+ ]
+ ]
+ },
+ {
+ "input": "&cupor",
+ "description": "Bad named entity: cupor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cupor"
+ ]
+ ]
+ },
+ {
+ "input": "⩅",
+ "description": "Named entity: cupor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a45"
+ ]
+ ]
+ },
+ {
+ "input": "&cups",
+ "description": "Bad named entity: cups without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cups"
+ ]
+ ]
+ },
+ {
+ "input": "∪︀",
+ "description": "Named entity: cups; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222a\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&curarr",
+ "description": "Bad named entity: curarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&curarr"
+ ]
+ ]
+ },
+ {
+ "input": "↷",
+ "description": "Named entity: curarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b7"
+ ]
+ ]
+ },
+ {
+ "input": "&curarrm",
+ "description": "Bad named entity: curarrm without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&curarrm"
+ ]
+ ]
+ },
+ {
+ "input": "⤼",
+ "description": "Named entity: curarrm; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u293c"
+ ]
+ ]
+ },
+ {
+ "input": "&curlyeqprec",
+ "description": "Bad named entity: curlyeqprec without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&curlyeqprec"
+ ]
+ ]
+ },
+ {
+ "input": "⋞",
+ "description": "Named entity: curlyeqprec; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22de"
+ ]
+ ]
+ },
+ {
+ "input": "&curlyeqsucc",
+ "description": "Bad named entity: curlyeqsucc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&curlyeqsucc"
+ ]
+ ]
+ },
+ {
+ "input": "⋟",
+ "description": "Named entity: curlyeqsucc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22df"
+ ]
+ ]
+ },
+ {
+ "input": "&curlyvee",
+ "description": "Bad named entity: curlyvee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&curlyvee"
+ ]
+ ]
+ },
+ {
+ "input": "⋎",
+ "description": "Named entity: curlyvee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ce"
+ ]
+ ]
+ },
+ {
+ "input": "&curlywedge",
+ "description": "Bad named entity: curlywedge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&curlywedge"
+ ]
+ ]
+ },
+ {
+ "input": "⋏",
+ "description": "Named entity: curlywedge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22cf"
+ ]
+ ]
+ },
+ {
+ "input": "¤",
+ "description": "Named entity: curren without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a4"
+ ]
+ ]
+ },
+ {
+ "input": "¤",
+ "description": "Named entity: curren; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a4"
+ ]
+ ]
+ },
+ {
+ "input": "&curvearrowleft",
+ "description": "Bad named entity: curvearrowleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&curvearrowleft"
+ ]
+ ]
+ },
+ {
+ "input": "↶",
+ "description": "Named entity: curvearrowleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b6"
+ ]
+ ]
+ },
+ {
+ "input": "&curvearrowright",
+ "description": "Bad named entity: curvearrowright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&curvearrowright"
+ ]
+ ]
+ },
+ {
+ "input": "↷",
+ "description": "Named entity: curvearrowright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b7"
+ ]
+ ]
+ },
+ {
+ "input": "&cuvee",
+ "description": "Bad named entity: cuvee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cuvee"
+ ]
+ ]
+ },
+ {
+ "input": "⋎",
+ "description": "Named entity: cuvee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ce"
+ ]
+ ]
+ },
+ {
+ "input": "&cuwed",
+ "description": "Bad named entity: cuwed without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cuwed"
+ ]
+ ]
+ },
+ {
+ "input": "⋏",
+ "description": "Named entity: cuwed; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22cf"
+ ]
+ ]
+ },
+ {
+ "input": "&cwconint",
+ "description": "Bad named entity: cwconint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cwconint"
+ ]
+ ]
+ },
+ {
+ "input": "∲",
+ "description": "Named entity: cwconint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2232"
+ ]
+ ]
+ },
+ {
+ "input": "&cwint",
+ "description": "Bad named entity: cwint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cwint"
+ ]
+ ]
+ },
+ {
+ "input": "∱",
+ "description": "Named entity: cwint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2231"
+ ]
+ ]
+ },
+ {
+ "input": "&cylcty",
+ "description": "Bad named entity: cylcty without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&cylcty"
+ ]
+ ]
+ },
+ {
+ "input": "⌭",
+ "description": "Named entity: cylcty; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u232d"
+ ]
+ ]
+ },
+ {
+ "input": "&dArr",
+ "description": "Bad named entity: dArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇓",
+ "description": "Named entity: dArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d3"
+ ]
+ ]
+ },
+ {
+ "input": "&dHar",
+ "description": "Bad named entity: dHar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dHar"
+ ]
+ ]
+ },
+ {
+ "input": "⥥",
+ "description": "Named entity: dHar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2965"
+ ]
+ ]
+ },
+ {
+ "input": "&dagger",
+ "description": "Bad named entity: dagger without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dagger"
+ ]
+ ]
+ },
+ {
+ "input": "†",
+ "description": "Named entity: dagger; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2020"
+ ]
+ ]
+ },
+ {
+ "input": "&daleth",
+ "description": "Bad named entity: daleth without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&daleth"
+ ]
+ ]
+ },
+ {
+ "input": "ℸ",
+ "description": "Named entity: daleth; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2138"
+ ]
+ ]
+ },
+ {
+ "input": "&darr",
+ "description": "Bad named entity: darr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&darr"
+ ]
+ ]
+ },
+ {
+ "input": "↓",
+ "description": "Named entity: darr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2193"
+ ]
+ ]
+ },
+ {
+ "input": "&dash",
+ "description": "Bad named entity: dash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dash"
+ ]
+ ]
+ },
+ {
+ "input": "‐",
+ "description": "Named entity: dash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2010"
+ ]
+ ]
+ },
+ {
+ "input": "&dashv",
+ "description": "Bad named entity: dashv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dashv"
+ ]
+ ]
+ },
+ {
+ "input": "⊣",
+ "description": "Named entity: dashv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a3"
+ ]
+ ]
+ },
+ {
+ "input": "&dbkarow",
+ "description": "Bad named entity: dbkarow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dbkarow"
+ ]
+ ]
+ },
+ {
+ "input": "⤏",
+ "description": "Named entity: dbkarow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u290f"
+ ]
+ ]
+ },
+ {
+ "input": "&dblac",
+ "description": "Bad named entity: dblac without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dblac"
+ ]
+ ]
+ },
+ {
+ "input": "˝",
+ "description": "Named entity: dblac; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02dd"
+ ]
+ ]
+ },
+ {
+ "input": "&dcaron",
+ "description": "Bad named entity: dcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dcaron"
+ ]
+ ]
+ },
+ {
+ "input": "ď",
+ "description": "Named entity: dcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u010f"
+ ]
+ ]
+ },
+ {
+ "input": "&dcy",
+ "description": "Bad named entity: dcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dcy"
+ ]
+ ]
+ },
+ {
+ "input": "д",
+ "description": "Named entity: dcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0434"
+ ]
+ ]
+ },
+ {
+ "input": "&dd",
+ "description": "Bad named entity: dd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dd"
+ ]
+ ]
+ },
+ {
+ "input": "ⅆ",
+ "description": "Named entity: dd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2146"
+ ]
+ ]
+ },
+ {
+ "input": "&ddagger",
+ "description": "Bad named entity: ddagger without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ddagger"
+ ]
+ ]
+ },
+ {
+ "input": "‡",
+ "description": "Named entity: ddagger; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2021"
+ ]
+ ]
+ },
+ {
+ "input": "&ddarr",
+ "description": "Bad named entity: ddarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ddarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇊",
+ "description": "Named entity: ddarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ca"
+ ]
+ ]
+ },
+ {
+ "input": "&ddotseq",
+ "description": "Bad named entity: ddotseq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ddotseq"
+ ]
+ ]
+ },
+ {
+ "input": "⩷",
+ "description": "Named entity: ddotseq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a77"
+ ]
+ ]
+ },
+ {
+ "input": "°",
+ "description": "Named entity: deg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b0"
+ ]
+ ]
+ },
+ {
+ "input": "°",
+ "description": "Named entity: deg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b0"
+ ]
+ ]
+ },
+ {
+ "input": "&delta",
+ "description": "Bad named entity: delta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&delta"
+ ]
+ ]
+ },
+ {
+ "input": "δ",
+ "description": "Named entity: delta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b4"
+ ]
+ ]
+ },
+ {
+ "input": "&demptyv",
+ "description": "Bad named entity: demptyv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&demptyv"
+ ]
+ ]
+ },
+ {
+ "input": "⦱",
+ "description": "Named entity: demptyv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b1"
+ ]
+ ]
+ },
+ {
+ "input": "&dfisht",
+ "description": "Bad named entity: dfisht without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dfisht"
+ ]
+ ]
+ },
+ {
+ "input": "⥿",
+ "description": "Named entity: dfisht; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u297f"
+ ]
+ ]
+ },
+ {
+ "input": "&dfr",
+ "description": "Bad named entity: dfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔡",
+ "description": "Named entity: dfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd21"
+ ]
+ ]
+ },
+ {
+ "input": "&dharl",
+ "description": "Bad named entity: dharl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dharl"
+ ]
+ ]
+ },
+ {
+ "input": "⇃",
+ "description": "Named entity: dharl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c3"
+ ]
+ ]
+ },
+ {
+ "input": "&dharr",
+ "description": "Bad named entity: dharr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dharr"
+ ]
+ ]
+ },
+ {
+ "input": "⇂",
+ "description": "Named entity: dharr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c2"
+ ]
+ ]
+ },
+ {
+ "input": "&diam",
+ "description": "Bad named entity: diam without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&diam"
+ ]
+ ]
+ },
+ {
+ "input": "⋄",
+ "description": "Named entity: diam; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c4"
+ ]
+ ]
+ },
+ {
+ "input": "&diamond",
+ "description": "Bad named entity: diamond without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&diamond"
+ ]
+ ]
+ },
+ {
+ "input": "⋄",
+ "description": "Named entity: diamond; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c4"
+ ]
+ ]
+ },
+ {
+ "input": "&diamondsuit",
+ "description": "Bad named entity: diamondsuit without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&diamondsuit"
+ ]
+ ]
+ },
+ {
+ "input": "♦",
+ "description": "Named entity: diamondsuit; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2666"
+ ]
+ ]
+ },
+ {
+ "input": "&diams",
+ "description": "Bad named entity: diams without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&diams"
+ ]
+ ]
+ },
+ {
+ "input": "♦",
+ "description": "Named entity: diams; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2666"
+ ]
+ ]
+ },
+ {
+ "input": "&die",
+ "description": "Bad named entity: die without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&die"
+ ]
+ ]
+ },
+ {
+ "input": "¨",
+ "description": "Named entity: die; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a8"
+ ]
+ ]
+ },
+ {
+ "input": "&digamma",
+ "description": "Bad named entity: digamma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&digamma"
+ ]
+ ]
+ },
+ {
+ "input": "ϝ",
+ "description": "Named entity: digamma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03dd"
+ ]
+ ]
+ },
+ {
+ "input": "&disin",
+ "description": "Bad named entity: disin without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&disin"
+ ]
+ ]
+ },
+ {
+ "input": "⋲",
+ "description": "Named entity: disin; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f2"
+ ]
+ ]
+ },
+ {
+ "input": "&div",
+ "description": "Bad named entity: div without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&div"
+ ]
+ ]
+ },
+ {
+ "input": "÷",
+ "description": "Named entity: div; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f7"
+ ]
+ ]
+ },
+ {
+ "input": "÷",
+ "description": "Named entity: divide without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f7"
+ ]
+ ]
+ },
+ {
+ "input": "÷",
+ "description": "Named entity: divide; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f7"
+ ]
+ ]
+ },
+ {
+ "input": "⋇",
+ "description": "Named entity: divideontimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c7"
+ ]
+ ]
+ },
+ {
+ "input": "&divonx",
+ "description": "Bad named entity: divonx without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&divonx"
+ ]
+ ]
+ },
+ {
+ "input": "⋇",
+ "description": "Named entity: divonx; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c7"
+ ]
+ ]
+ },
+ {
+ "input": "&djcy",
+ "description": "Bad named entity: djcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&djcy"
+ ]
+ ]
+ },
+ {
+ "input": "ђ",
+ "description": "Named entity: djcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0452"
+ ]
+ ]
+ },
+ {
+ "input": "&dlcorn",
+ "description": "Bad named entity: dlcorn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dlcorn"
+ ]
+ ]
+ },
+ {
+ "input": "⌞",
+ "description": "Named entity: dlcorn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u231e"
+ ]
+ ]
+ },
+ {
+ "input": "&dlcrop",
+ "description": "Bad named entity: dlcrop without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dlcrop"
+ ]
+ ]
+ },
+ {
+ "input": "⌍",
+ "description": "Named entity: dlcrop; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u230d"
+ ]
+ ]
+ },
+ {
+ "input": "&dollar",
+ "description": "Bad named entity: dollar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dollar"
+ ]
+ ]
+ },
+ {
+ "input": "$",
+ "description": "Named entity: dollar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "$"
+ ]
+ ]
+ },
+ {
+ "input": "&dopf",
+ "description": "Bad named entity: dopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕕",
+ "description": "Named entity: dopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd55"
+ ]
+ ]
+ },
+ {
+ "input": "&dot",
+ "description": "Bad named entity: dot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dot"
+ ]
+ ]
+ },
+ {
+ "input": "˙",
+ "description": "Named entity: dot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02d9"
+ ]
+ ]
+ },
+ {
+ "input": "&doteq",
+ "description": "Bad named entity: doteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&doteq"
+ ]
+ ]
+ },
+ {
+ "input": "≐",
+ "description": "Named entity: doteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2250"
+ ]
+ ]
+ },
+ {
+ "input": "&doteqdot",
+ "description": "Bad named entity: doteqdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&doteqdot"
+ ]
+ ]
+ },
+ {
+ "input": "≑",
+ "description": "Named entity: doteqdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2251"
+ ]
+ ]
+ },
+ {
+ "input": "&dotminus",
+ "description": "Bad named entity: dotminus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dotminus"
+ ]
+ ]
+ },
+ {
+ "input": "∸",
+ "description": "Named entity: dotminus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2238"
+ ]
+ ]
+ },
+ {
+ "input": "&dotplus",
+ "description": "Bad named entity: dotplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dotplus"
+ ]
+ ]
+ },
+ {
+ "input": "∔",
+ "description": "Named entity: dotplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2214"
+ ]
+ ]
+ },
+ {
+ "input": "&dotsquare",
+ "description": "Bad named entity: dotsquare without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dotsquare"
+ ]
+ ]
+ },
+ {
+ "input": "⊡",
+ "description": "Named entity: dotsquare; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a1"
+ ]
+ ]
+ },
+ {
+ "input": "&doublebarwedge",
+ "description": "Bad named entity: doublebarwedge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&doublebarwedge"
+ ]
+ ]
+ },
+ {
+ "input": "⌆",
+ "description": "Named entity: doublebarwedge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2306"
+ ]
+ ]
+ },
+ {
+ "input": "&downarrow",
+ "description": "Bad named entity: downarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&downarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↓",
+ "description": "Named entity: downarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2193"
+ ]
+ ]
+ },
+ {
+ "input": "&downdownarrows",
+ "description": "Bad named entity: downdownarrows without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&downdownarrows"
+ ]
+ ]
+ },
+ {
+ "input": "⇊",
+ "description": "Named entity: downdownarrows; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ca"
+ ]
+ ]
+ },
+ {
+ "input": "&downharpoonleft",
+ "description": "Bad named entity: downharpoonleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&downharpoonleft"
+ ]
+ ]
+ },
+ {
+ "input": "⇃",
+ "description": "Named entity: downharpoonleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c3"
+ ]
+ ]
+ },
+ {
+ "input": "&downharpoonright",
+ "description": "Bad named entity: downharpoonright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&downharpoonright"
+ ]
+ ]
+ },
+ {
+ "input": "⇂",
+ "description": "Named entity: downharpoonright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c2"
+ ]
+ ]
+ },
+ {
+ "input": "&drbkarow",
+ "description": "Bad named entity: drbkarow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&drbkarow"
+ ]
+ ]
+ },
+ {
+ "input": "⤐",
+ "description": "Named entity: drbkarow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2910"
+ ]
+ ]
+ },
+ {
+ "input": "&drcorn",
+ "description": "Bad named entity: drcorn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&drcorn"
+ ]
+ ]
+ },
+ {
+ "input": "⌟",
+ "description": "Named entity: drcorn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u231f"
+ ]
+ ]
+ },
+ {
+ "input": "&drcrop",
+ "description": "Bad named entity: drcrop without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&drcrop"
+ ]
+ ]
+ },
+ {
+ "input": "⌌",
+ "description": "Named entity: drcrop; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u230c"
+ ]
+ ]
+ },
+ {
+ "input": "&dscr",
+ "description": "Bad named entity: dscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒹",
+ "description": "Named entity: dscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcb9"
+ ]
+ ]
+ },
+ {
+ "input": "&dscy",
+ "description": "Bad named entity: dscy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dscy"
+ ]
+ ]
+ },
+ {
+ "input": "ѕ",
+ "description": "Named entity: dscy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0455"
+ ]
+ ]
+ },
+ {
+ "input": "&dsol",
+ "description": "Bad named entity: dsol without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dsol"
+ ]
+ ]
+ },
+ {
+ "input": "⧶",
+ "description": "Named entity: dsol; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29f6"
+ ]
+ ]
+ },
+ {
+ "input": "&dstrok",
+ "description": "Bad named entity: dstrok without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dstrok"
+ ]
+ ]
+ },
+ {
+ "input": "đ",
+ "description": "Named entity: dstrok; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0111"
+ ]
+ ]
+ },
+ {
+ "input": "&dtdot",
+ "description": "Bad named entity: dtdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dtdot"
+ ]
+ ]
+ },
+ {
+ "input": "⋱",
+ "description": "Named entity: dtdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f1"
+ ]
+ ]
+ },
+ {
+ "input": "&dtri",
+ "description": "Bad named entity: dtri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dtri"
+ ]
+ ]
+ },
+ {
+ "input": "▿",
+ "description": "Named entity: dtri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25bf"
+ ]
+ ]
+ },
+ {
+ "input": "&dtrif",
+ "description": "Bad named entity: dtrif without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dtrif"
+ ]
+ ]
+ },
+ {
+ "input": "▾",
+ "description": "Named entity: dtrif; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25be"
+ ]
+ ]
+ },
+ {
+ "input": "&duarr",
+ "description": "Bad named entity: duarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&duarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇵",
+ "description": "Named entity: duarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21f5"
+ ]
+ ]
+ },
+ {
+ "input": "&duhar",
+ "description": "Bad named entity: duhar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&duhar"
+ ]
+ ]
+ },
+ {
+ "input": "⥯",
+ "description": "Named entity: duhar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u296f"
+ ]
+ ]
+ },
+ {
+ "input": "&dwangle",
+ "description": "Bad named entity: dwangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dwangle"
+ ]
+ ]
+ },
+ {
+ "input": "⦦",
+ "description": "Named entity: dwangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29a6"
+ ]
+ ]
+ },
+ {
+ "input": "&dzcy",
+ "description": "Bad named entity: dzcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dzcy"
+ ]
+ ]
+ },
+ {
+ "input": "џ",
+ "description": "Named entity: dzcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u045f"
+ ]
+ ]
+ },
+ {
+ "input": "&dzigrarr",
+ "description": "Bad named entity: dzigrarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&dzigrarr"
+ ]
+ ]
+ },
+ {
+ "input": "⟿",
+ "description": "Named entity: dzigrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27ff"
+ ]
+ ]
+ },
+ {
+ "input": "&eDDot",
+ "description": "Bad named entity: eDDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eDDot"
+ ]
+ ]
+ },
+ {
+ "input": "⩷",
+ "description": "Named entity: eDDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a77"
+ ]
+ ]
+ },
+ {
+ "input": "&eDot",
+ "description": "Bad named entity: eDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eDot"
+ ]
+ ]
+ },
+ {
+ "input": "≑",
+ "description": "Named entity: eDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2251"
+ ]
+ ]
+ },
+ {
+ "input": "é",
+ "description": "Named entity: eacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e9"
+ ]
+ ]
+ },
+ {
+ "input": "é",
+ "description": "Named entity: eacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e9"
+ ]
+ ]
+ },
+ {
+ "input": "&easter",
+ "description": "Bad named entity: easter without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&easter"
+ ]
+ ]
+ },
+ {
+ "input": "⩮",
+ "description": "Named entity: easter; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a6e"
+ ]
+ ]
+ },
+ {
+ "input": "&ecaron",
+ "description": "Bad named entity: ecaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ecaron"
+ ]
+ ]
+ },
+ {
+ "input": "ě",
+ "description": "Named entity: ecaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u011b"
+ ]
+ ]
+ },
+ {
+ "input": "&ecir",
+ "description": "Bad named entity: ecir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ecir"
+ ]
+ ]
+ },
+ {
+ "input": "≖",
+ "description": "Named entity: ecir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2256"
+ ]
+ ]
+ },
+ {
+ "input": "ê",
+ "description": "Named entity: ecirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ea"
+ ]
+ ]
+ },
+ {
+ "input": "ê",
+ "description": "Named entity: ecirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ea"
+ ]
+ ]
+ },
+ {
+ "input": "&ecolon",
+ "description": "Bad named entity: ecolon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ecolon"
+ ]
+ ]
+ },
+ {
+ "input": "≕",
+ "description": "Named entity: ecolon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2255"
+ ]
+ ]
+ },
+ {
+ "input": "&ecy",
+ "description": "Bad named entity: ecy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ecy"
+ ]
+ ]
+ },
+ {
+ "input": "э",
+ "description": "Named entity: ecy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u044d"
+ ]
+ ]
+ },
+ {
+ "input": "&edot",
+ "description": "Bad named entity: edot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&edot"
+ ]
+ ]
+ },
+ {
+ "input": "ė",
+ "description": "Named entity: edot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0117"
+ ]
+ ]
+ },
+ {
+ "input": "&ee",
+ "description": "Bad named entity: ee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ee"
+ ]
+ ]
+ },
+ {
+ "input": "ⅇ",
+ "description": "Named entity: ee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2147"
+ ]
+ ]
+ },
+ {
+ "input": "&efDot",
+ "description": "Bad named entity: efDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&efDot"
+ ]
+ ]
+ },
+ {
+ "input": "≒",
+ "description": "Named entity: efDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2252"
+ ]
+ ]
+ },
+ {
+ "input": "&efr",
+ "description": "Bad named entity: efr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&efr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔢",
+ "description": "Named entity: efr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd22"
+ ]
+ ]
+ },
+ {
+ "input": "&eg",
+ "description": "Bad named entity: eg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eg"
+ ]
+ ]
+ },
+ {
+ "input": "⪚",
+ "description": "Named entity: eg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a9a"
+ ]
+ ]
+ },
+ {
+ "input": "è",
+ "description": "Named entity: egrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00e8"
+ ]
+ ]
+ },
+ {
+ "input": "è",
+ "description": "Named entity: egrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00e8"
+ ]
+ ]
+ },
+ {
+ "input": "&egs",
+ "description": "Bad named entity: egs without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&egs"
+ ]
+ ]
+ },
+ {
+ "input": "⪖",
+ "description": "Named entity: egs; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a96"
+ ]
+ ]
+ },
+ {
+ "input": "&egsdot",
+ "description": "Bad named entity: egsdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&egsdot"
+ ]
+ ]
+ },
+ {
+ "input": "⪘",
+ "description": "Named entity: egsdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a98"
+ ]
+ ]
+ },
+ {
+ "input": "&el",
+ "description": "Bad named entity: el without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&el"
+ ]
+ ]
+ },
+ {
+ "input": "⪙",
+ "description": "Named entity: el; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a99"
+ ]
+ ]
+ },
+ {
+ "input": "&elinters",
+ "description": "Bad named entity: elinters without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&elinters"
+ ]
+ ]
+ },
+ {
+ "input": "⏧",
+ "description": "Named entity: elinters; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23e7"
+ ]
+ ]
+ },
+ {
+ "input": "&ell",
+ "description": "Bad named entity: ell without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ell"
+ ]
+ ]
+ },
+ {
+ "input": "ℓ",
+ "description": "Named entity: ell; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2113"
+ ]
+ ]
+ },
+ {
+ "input": "&els",
+ "description": "Bad named entity: els without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&els"
+ ]
+ ]
+ },
+ {
+ "input": "⪕",
+ "description": "Named entity: els; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a95"
+ ]
+ ]
+ },
+ {
+ "input": "&elsdot",
+ "description": "Bad named entity: elsdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&elsdot"
+ ]
+ ]
+ },
+ {
+ "input": "⪗",
+ "description": "Named entity: elsdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a97"
+ ]
+ ]
+ },
+ {
+ "input": "&emacr",
+ "description": "Bad named entity: emacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&emacr"
+ ]
+ ]
+ },
+ {
+ "input": "ē",
+ "description": "Named entity: emacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0113"
+ ]
+ ]
+ },
+ {
+ "input": "&empty",
+ "description": "Bad named entity: empty without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&empty"
+ ]
+ ]
+ },
+ {
+ "input": "∅",
+ "description": "Named entity: empty; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2205"
+ ]
+ ]
+ },
+ {
+ "input": "&emptyset",
+ "description": "Bad named entity: emptyset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&emptyset"
+ ]
+ ]
+ },
+ {
+ "input": "∅",
+ "description": "Named entity: emptyset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2205"
+ ]
+ ]
+ },
+ {
+ "input": "&emptyv",
+ "description": "Bad named entity: emptyv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&emptyv"
+ ]
+ ]
+ },
+ {
+ "input": "∅",
+ "description": "Named entity: emptyv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2205"
+ ]
+ ]
+ },
+ {
+ "input": "&emsp",
+ "description": "Bad named entity: emsp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&emsp"
+ ]
+ ]
+ },
+ {
+ "input": "&emsp13",
+ "description": "Bad named entity: emsp13 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&emsp13"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: emsp13; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2004"
+ ]
+ ]
+ },
+ {
+ "input": "&emsp14",
+ "description": "Bad named entity: emsp14 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&emsp14"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: emsp14; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2005"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: emsp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2003"
+ ]
+ ]
+ },
+ {
+ "input": "&eng",
+ "description": "Bad named entity: eng without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eng"
+ ]
+ ]
+ },
+ {
+ "input": "ŋ",
+ "description": "Named entity: eng; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u014b"
+ ]
+ ]
+ },
+ {
+ "input": "&ensp",
+ "description": "Bad named entity: ensp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ensp"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: ensp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2002"
+ ]
+ ]
+ },
+ {
+ "input": "&eogon",
+ "description": "Bad named entity: eogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eogon"
+ ]
+ ]
+ },
+ {
+ "input": "ę",
+ "description": "Named entity: eogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0119"
+ ]
+ ]
+ },
+ {
+ "input": "&eopf",
+ "description": "Bad named entity: eopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕖",
+ "description": "Named entity: eopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd56"
+ ]
+ ]
+ },
+ {
+ "input": "&epar",
+ "description": "Bad named entity: epar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&epar"
+ ]
+ ]
+ },
+ {
+ "input": "⋕",
+ "description": "Named entity: epar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d5"
+ ]
+ ]
+ },
+ {
+ "input": "&eparsl",
+ "description": "Bad named entity: eparsl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eparsl"
+ ]
+ ]
+ },
+ {
+ "input": "⧣",
+ "description": "Named entity: eparsl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29e3"
+ ]
+ ]
+ },
+ {
+ "input": "&eplus",
+ "description": "Bad named entity: eplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eplus"
+ ]
+ ]
+ },
+ {
+ "input": "⩱",
+ "description": "Named entity: eplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a71"
+ ]
+ ]
+ },
+ {
+ "input": "&epsi",
+ "description": "Bad named entity: epsi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&epsi"
+ ]
+ ]
+ },
+ {
+ "input": "ε",
+ "description": "Named entity: epsi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b5"
+ ]
+ ]
+ },
+ {
+ "input": "&epsilon",
+ "description": "Bad named entity: epsilon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&epsilon"
+ ]
+ ]
+ },
+ {
+ "input": "ε",
+ "description": "Named entity: epsilon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b5"
+ ]
+ ]
+ },
+ {
+ "input": "&epsiv",
+ "description": "Bad named entity: epsiv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&epsiv"
+ ]
+ ]
+ },
+ {
+ "input": "ϵ",
+ "description": "Named entity: epsiv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f5"
+ ]
+ ]
+ },
+ {
+ "input": "&eqcirc",
+ "description": "Bad named entity: eqcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eqcirc"
+ ]
+ ]
+ },
+ {
+ "input": "≖",
+ "description": "Named entity: eqcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2256"
+ ]
+ ]
+ },
+ {
+ "input": "&eqcolon",
+ "description": "Bad named entity: eqcolon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eqcolon"
+ ]
+ ]
+ },
+ {
+ "input": "≕",
+ "description": "Named entity: eqcolon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2255"
+ ]
+ ]
+ },
+ {
+ "input": "&eqsim",
+ "description": "Bad named entity: eqsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eqsim"
+ ]
+ ]
+ },
+ {
+ "input": "≂",
+ "description": "Named entity: eqsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2242"
+ ]
+ ]
+ },
+ {
+ "input": "&eqslantgtr",
+ "description": "Bad named entity: eqslantgtr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eqslantgtr"
+ ]
+ ]
+ },
+ {
+ "input": "⪖",
+ "description": "Named entity: eqslantgtr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a96"
+ ]
+ ]
+ },
+ {
+ "input": "&eqslantless",
+ "description": "Bad named entity: eqslantless without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eqslantless"
+ ]
+ ]
+ },
+ {
+ "input": "⪕",
+ "description": "Named entity: eqslantless; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a95"
+ ]
+ ]
+ },
+ {
+ "input": "&equals",
+ "description": "Bad named entity: equals without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&equals"
+ ]
+ ]
+ },
+ {
+ "input": "=",
+ "description": "Named entity: equals; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "="
+ ]
+ ]
+ },
+ {
+ "input": "&equest",
+ "description": "Bad named entity: equest without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&equest"
+ ]
+ ]
+ },
+ {
+ "input": "≟",
+ "description": "Named entity: equest; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u225f"
+ ]
+ ]
+ },
+ {
+ "input": "&equiv",
+ "description": "Bad named entity: equiv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&equiv"
+ ]
+ ]
+ },
+ {
+ "input": "≡",
+ "description": "Named entity: equiv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2261"
+ ]
+ ]
+ },
+ {
+ "input": "&equivDD",
+ "description": "Bad named entity: equivDD without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&equivDD"
+ ]
+ ]
+ },
+ {
+ "input": "⩸",
+ "description": "Named entity: equivDD; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a78"
+ ]
+ ]
+ },
+ {
+ "input": "&eqvparsl",
+ "description": "Bad named entity: eqvparsl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eqvparsl"
+ ]
+ ]
+ },
+ {
+ "input": "⧥",
+ "description": "Named entity: eqvparsl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29e5"
+ ]
+ ]
+ },
+ {
+ "input": "&erDot",
+ "description": "Bad named entity: erDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&erDot"
+ ]
+ ]
+ },
+ {
+ "input": "≓",
+ "description": "Named entity: erDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2253"
+ ]
+ ]
+ },
+ {
+ "input": "&erarr",
+ "description": "Bad named entity: erarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&erarr"
+ ]
+ ]
+ },
+ {
+ "input": "⥱",
+ "description": "Named entity: erarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2971"
+ ]
+ ]
+ },
+ {
+ "input": "&escr",
+ "description": "Bad named entity: escr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&escr"
+ ]
+ ]
+ },
+ {
+ "input": "ℯ",
+ "description": "Named entity: escr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u212f"
+ ]
+ ]
+ },
+ {
+ "input": "&esdot",
+ "description": "Bad named entity: esdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&esdot"
+ ]
+ ]
+ },
+ {
+ "input": "≐",
+ "description": "Named entity: esdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2250"
+ ]
+ ]
+ },
+ {
+ "input": "&esim",
+ "description": "Bad named entity: esim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&esim"
+ ]
+ ]
+ },
+ {
+ "input": "≂",
+ "description": "Named entity: esim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2242"
+ ]
+ ]
+ },
+ {
+ "input": "&eta",
+ "description": "Bad named entity: eta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&eta"
+ ]
+ ]
+ },
+ {
+ "input": "η",
+ "description": "Named entity: eta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b7"
+ ]
+ ]
+ },
+ {
+ "input": "ð",
+ "description": "Named entity: eth without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f0"
+ ]
+ ]
+ },
+ {
+ "input": "ð",
+ "description": "Named entity: eth; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f0"
+ ]
+ ]
+ },
+ {
+ "input": "ë",
+ "description": "Named entity: euml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00eb"
+ ]
+ ]
+ },
+ {
+ "input": "ë",
+ "description": "Named entity: euml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00eb"
+ ]
+ ]
+ },
+ {
+ "input": "&euro",
+ "description": "Bad named entity: euro without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&euro"
+ ]
+ ]
+ },
+ {
+ "input": "€",
+ "description": "Named entity: euro; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u20ac"
+ ]
+ ]
+ },
+ {
+ "input": "&excl",
+ "description": "Bad named entity: excl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&excl"
+ ]
+ ]
+ },
+ {
+ "input": "!",
+ "description": "Named entity: excl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "!"
+ ]
+ ]
+ },
+ {
+ "input": "&exist",
+ "description": "Bad named entity: exist without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&exist"
+ ]
+ ]
+ },
+ {
+ "input": "∃",
+ "description": "Named entity: exist; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2203"
+ ]
+ ]
+ },
+ {
+ "input": "&expectation",
+ "description": "Bad named entity: expectation without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&expectation"
+ ]
+ ]
+ },
+ {
+ "input": "ℰ",
+ "description": "Named entity: expectation; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2130"
+ ]
+ ]
+ },
+ {
+ "input": "&exponentiale",
+ "description": "Bad named entity: exponentiale without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&exponentiale"
+ ]
+ ]
+ },
+ {
+ "input": "ⅇ",
+ "description": "Named entity: exponentiale; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2147"
+ ]
+ ]
+ },
+ {
+ "input": "&fallingdotseq",
+ "description": "Bad named entity: fallingdotseq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fallingdotseq"
+ ]
+ ]
+ },
+ {
+ "input": "≒",
+ "description": "Named entity: fallingdotseq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2252"
+ ]
+ ]
+ },
+ {
+ "input": "&fcy",
+ "description": "Bad named entity: fcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fcy"
+ ]
+ ]
+ },
+ {
+ "input": "ф",
+ "description": "Named entity: fcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0444"
+ ]
+ ]
+ },
+ {
+ "input": "&female",
+ "description": "Bad named entity: female without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&female"
+ ]
+ ]
+ },
+ {
+ "input": "♀",
+ "description": "Named entity: female; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2640"
+ ]
+ ]
+ },
+ {
+ "input": "&ffilig",
+ "description": "Bad named entity: ffilig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ffilig"
+ ]
+ ]
+ },
+ {
+ "input": "ffi",
+ "description": "Named entity: ffilig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ufb03"
+ ]
+ ]
+ },
+ {
+ "input": "&fflig",
+ "description": "Bad named entity: fflig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fflig"
+ ]
+ ]
+ },
+ {
+ "input": "ff",
+ "description": "Named entity: fflig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ufb00"
+ ]
+ ]
+ },
+ {
+ "input": "&ffllig",
+ "description": "Bad named entity: ffllig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ffllig"
+ ]
+ ]
+ },
+ {
+ "input": "ffl",
+ "description": "Named entity: ffllig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ufb04"
+ ]
+ ]
+ },
+ {
+ "input": "&ffr",
+ "description": "Bad named entity: ffr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ffr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔣",
+ "description": "Named entity: ffr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd23"
+ ]
+ ]
+ },
+ {
+ "input": "&filig",
+ "description": "Bad named entity: filig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&filig"
+ ]
+ ]
+ },
+ {
+ "input": "fi",
+ "description": "Named entity: filig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ufb01"
+ ]
+ ]
+ },
+ {
+ "input": "&fjlig",
+ "description": "Bad named entity: fjlig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fjlig"
+ ]
+ ]
+ },
+ {
+ "input": "fj",
+ "description": "Named entity: fjlig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "fj"
+ ]
+ ]
+ },
+ {
+ "input": "&flat",
+ "description": "Bad named entity: flat without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&flat"
+ ]
+ ]
+ },
+ {
+ "input": "♭",
+ "description": "Named entity: flat; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u266d"
+ ]
+ ]
+ },
+ {
+ "input": "&fllig",
+ "description": "Bad named entity: fllig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fllig"
+ ]
+ ]
+ },
+ {
+ "input": "fl",
+ "description": "Named entity: fllig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ufb02"
+ ]
+ ]
+ },
+ {
+ "input": "&fltns",
+ "description": "Bad named entity: fltns without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fltns"
+ ]
+ ]
+ },
+ {
+ "input": "▱",
+ "description": "Named entity: fltns; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b1"
+ ]
+ ]
+ },
+ {
+ "input": "&fnof",
+ "description": "Bad named entity: fnof without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fnof"
+ ]
+ ]
+ },
+ {
+ "input": "ƒ",
+ "description": "Named entity: fnof; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0192"
+ ]
+ ]
+ },
+ {
+ "input": "&fopf",
+ "description": "Bad named entity: fopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕗",
+ "description": "Named entity: fopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd57"
+ ]
+ ]
+ },
+ {
+ "input": "&forall",
+ "description": "Bad named entity: forall without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&forall"
+ ]
+ ]
+ },
+ {
+ "input": "∀",
+ "description": "Named entity: forall; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2200"
+ ]
+ ]
+ },
+ {
+ "input": "&fork",
+ "description": "Bad named entity: fork without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fork"
+ ]
+ ]
+ },
+ {
+ "input": "⋔",
+ "description": "Named entity: fork; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d4"
+ ]
+ ]
+ },
+ {
+ "input": "&forkv",
+ "description": "Bad named entity: forkv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&forkv"
+ ]
+ ]
+ },
+ {
+ "input": "⫙",
+ "description": "Named entity: forkv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad9"
+ ]
+ ]
+ },
+ {
+ "input": "&fpartint",
+ "description": "Bad named entity: fpartint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fpartint"
+ ]
+ ]
+ },
+ {
+ "input": "⨍",
+ "description": "Named entity: fpartint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a0d"
+ ]
+ ]
+ },
+ {
+ "input": "½",
+ "description": "Named entity: frac12 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00bd"
+ ]
+ ]
+ },
+ {
+ "input": "½",
+ "description": "Named entity: frac12; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00bd"
+ ]
+ ]
+ },
+ {
+ "input": "&frac13",
+ "description": "Bad named entity: frac13 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac13"
+ ]
+ ]
+ },
+ {
+ "input": "⅓",
+ "description": "Named entity: frac13; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2153"
+ ]
+ ]
+ },
+ {
+ "input": "¼",
+ "description": "Named entity: frac14 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00bc"
+ ]
+ ]
+ },
+ {
+ "input": "¼",
+ "description": "Named entity: frac14; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00bc"
+ ]
+ ]
+ },
+ {
+ "input": "&frac15",
+ "description": "Bad named entity: frac15 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac15"
+ ]
+ ]
+ },
+ {
+ "input": "⅕",
+ "description": "Named entity: frac15; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2155"
+ ]
+ ]
+ },
+ {
+ "input": "&frac16",
+ "description": "Bad named entity: frac16 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac16"
+ ]
+ ]
+ },
+ {
+ "input": "⅙",
+ "description": "Named entity: frac16; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2159"
+ ]
+ ]
+ },
+ {
+ "input": "&frac18",
+ "description": "Bad named entity: frac18 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac18"
+ ]
+ ]
+ },
+ {
+ "input": "⅛",
+ "description": "Named entity: frac18; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u215b"
+ ]
+ ]
+ },
+ {
+ "input": "&frac23",
+ "description": "Bad named entity: frac23 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac23"
+ ]
+ ]
+ },
+ {
+ "input": "⅔",
+ "description": "Named entity: frac23; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2154"
+ ]
+ ]
+ },
+ {
+ "input": "&frac25",
+ "description": "Bad named entity: frac25 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac25"
+ ]
+ ]
+ },
+ {
+ "input": "⅖",
+ "description": "Named entity: frac25; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2156"
+ ]
+ ]
+ },
+ {
+ "input": "¾",
+ "description": "Named entity: frac34 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00be"
+ ]
+ ]
+ },
+ {
+ "input": "¾",
+ "description": "Named entity: frac34; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00be"
+ ]
+ ]
+ },
+ {
+ "input": "&frac35",
+ "description": "Bad named entity: frac35 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac35"
+ ]
+ ]
+ },
+ {
+ "input": "⅗",
+ "description": "Named entity: frac35; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2157"
+ ]
+ ]
+ },
+ {
+ "input": "&frac38",
+ "description": "Bad named entity: frac38 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac38"
+ ]
+ ]
+ },
+ {
+ "input": "⅜",
+ "description": "Named entity: frac38; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u215c"
+ ]
+ ]
+ },
+ {
+ "input": "&frac45",
+ "description": "Bad named entity: frac45 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac45"
+ ]
+ ]
+ },
+ {
+ "input": "⅘",
+ "description": "Named entity: frac45; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2158"
+ ]
+ ]
+ },
+ {
+ "input": "&frac56",
+ "description": "Bad named entity: frac56 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac56"
+ ]
+ ]
+ },
+ {
+ "input": "⅚",
+ "description": "Named entity: frac56; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u215a"
+ ]
+ ]
+ },
+ {
+ "input": "&frac58",
+ "description": "Bad named entity: frac58 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac58"
+ ]
+ ]
+ },
+ {
+ "input": "⅝",
+ "description": "Named entity: frac58; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u215d"
+ ]
+ ]
+ },
+ {
+ "input": "&frac78",
+ "description": "Bad named entity: frac78 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frac78"
+ ]
+ ]
+ },
+ {
+ "input": "⅞",
+ "description": "Named entity: frac78; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u215e"
+ ]
+ ]
+ },
+ {
+ "input": "&frasl",
+ "description": "Bad named entity: frasl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frasl"
+ ]
+ ]
+ },
+ {
+ "input": "⁄",
+ "description": "Named entity: frasl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2044"
+ ]
+ ]
+ },
+ {
+ "input": "&frown",
+ "description": "Bad named entity: frown without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&frown"
+ ]
+ ]
+ },
+ {
+ "input": "⌢",
+ "description": "Named entity: frown; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2322"
+ ]
+ ]
+ },
+ {
+ "input": "&fscr",
+ "description": "Bad named entity: fscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&fscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒻",
+ "description": "Named entity: fscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcbb"
+ ]
+ ]
+ },
+ {
+ "input": "&gE",
+ "description": "Bad named entity: gE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gE"
+ ]
+ ]
+ },
+ {
+ "input": "≧",
+ "description": "Named entity: gE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2267"
+ ]
+ ]
+ },
+ {
+ "input": "&gEl",
+ "description": "Bad named entity: gEl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gEl"
+ ]
+ ]
+ },
+ {
+ "input": "⪌",
+ "description": "Named entity: gEl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8c"
+ ]
+ ]
+ },
+ {
+ "input": "&gacute",
+ "description": "Bad named entity: gacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gacute"
+ ]
+ ]
+ },
+ {
+ "input": "ǵ",
+ "description": "Named entity: gacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u01f5"
+ ]
+ ]
+ },
+ {
+ "input": "&gamma",
+ "description": "Bad named entity: gamma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gamma"
+ ]
+ ]
+ },
+ {
+ "input": "γ",
+ "description": "Named entity: gamma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b3"
+ ]
+ ]
+ },
+ {
+ "input": "&gammad",
+ "description": "Bad named entity: gammad without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gammad"
+ ]
+ ]
+ },
+ {
+ "input": "ϝ",
+ "description": "Named entity: gammad; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03dd"
+ ]
+ ]
+ },
+ {
+ "input": "&gap",
+ "description": "Bad named entity: gap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gap"
+ ]
+ ]
+ },
+ {
+ "input": "⪆",
+ "description": "Named entity: gap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a86"
+ ]
+ ]
+ },
+ {
+ "input": "&gbreve",
+ "description": "Bad named entity: gbreve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gbreve"
+ ]
+ ]
+ },
+ {
+ "input": "ğ",
+ "description": "Named entity: gbreve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u011f"
+ ]
+ ]
+ },
+ {
+ "input": "&gcirc",
+ "description": "Bad named entity: gcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gcirc"
+ ]
+ ]
+ },
+ {
+ "input": "ĝ",
+ "description": "Named entity: gcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u011d"
+ ]
+ ]
+ },
+ {
+ "input": "&gcy",
+ "description": "Bad named entity: gcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gcy"
+ ]
+ ]
+ },
+ {
+ "input": "г",
+ "description": "Named entity: gcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0433"
+ ]
+ ]
+ },
+ {
+ "input": "&gdot",
+ "description": "Bad named entity: gdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gdot"
+ ]
+ ]
+ },
+ {
+ "input": "ġ",
+ "description": "Named entity: gdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0121"
+ ]
+ ]
+ },
+ {
+ "input": "&ge",
+ "description": "Bad named entity: ge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ge"
+ ]
+ ]
+ },
+ {
+ "input": "≥",
+ "description": "Named entity: ge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2265"
+ ]
+ ]
+ },
+ {
+ "input": "&gel",
+ "description": "Bad named entity: gel without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gel"
+ ]
+ ]
+ },
+ {
+ "input": "⋛",
+ "description": "Named entity: gel; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22db"
+ ]
+ ]
+ },
+ {
+ "input": "&geq",
+ "description": "Bad named entity: geq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&geq"
+ ]
+ ]
+ },
+ {
+ "input": "≥",
+ "description": "Named entity: geq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2265"
+ ]
+ ]
+ },
+ {
+ "input": "&geqq",
+ "description": "Bad named entity: geqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&geqq"
+ ]
+ ]
+ },
+ {
+ "input": "≧",
+ "description": "Named entity: geqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2267"
+ ]
+ ]
+ },
+ {
+ "input": "&geqslant",
+ "description": "Bad named entity: geqslant without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&geqslant"
+ ]
+ ]
+ },
+ {
+ "input": "⩾",
+ "description": "Named entity: geqslant; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7e"
+ ]
+ ]
+ },
+ {
+ "input": "&ges",
+ "description": "Bad named entity: ges without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ges"
+ ]
+ ]
+ },
+ {
+ "input": "⩾",
+ "description": "Named entity: ges; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7e"
+ ]
+ ]
+ },
+ {
+ "input": "&gescc",
+ "description": "Bad named entity: gescc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gescc"
+ ]
+ ]
+ },
+ {
+ "input": "⪩",
+ "description": "Named entity: gescc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa9"
+ ]
+ ]
+ },
+ {
+ "input": "&gesdot",
+ "description": "Bad named entity: gesdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gesdot"
+ ]
+ ]
+ },
+ {
+ "input": "⪀",
+ "description": "Named entity: gesdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a80"
+ ]
+ ]
+ },
+ {
+ "input": "&gesdoto",
+ "description": "Bad named entity: gesdoto without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gesdoto"
+ ]
+ ]
+ },
+ {
+ "input": "⪂",
+ "description": "Named entity: gesdoto; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a82"
+ ]
+ ]
+ },
+ {
+ "input": "&gesdotol",
+ "description": "Bad named entity: gesdotol without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gesdotol"
+ ]
+ ]
+ },
+ {
+ "input": "⪄",
+ "description": "Named entity: gesdotol; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a84"
+ ]
+ ]
+ },
+ {
+ "input": "&gesl",
+ "description": "Bad named entity: gesl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gesl"
+ ]
+ ]
+ },
+ {
+ "input": "⋛︀",
+ "description": "Named entity: gesl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22db\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&gesles",
+ "description": "Bad named entity: gesles without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gesles"
+ ]
+ ]
+ },
+ {
+ "input": "⪔",
+ "description": "Named entity: gesles; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a94"
+ ]
+ ]
+ },
+ {
+ "input": "&gfr",
+ "description": "Bad named entity: gfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔤",
+ "description": "Named entity: gfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd24"
+ ]
+ ]
+ },
+ {
+ "input": "&gg",
+ "description": "Bad named entity: gg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gg"
+ ]
+ ]
+ },
+ {
+ "input": "≫",
+ "description": "Named entity: gg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226b"
+ ]
+ ]
+ },
+ {
+ "input": "&ggg",
+ "description": "Bad named entity: ggg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ggg"
+ ]
+ ]
+ },
+ {
+ "input": "⋙",
+ "description": "Named entity: ggg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d9"
+ ]
+ ]
+ },
+ {
+ "input": "&gimel",
+ "description": "Bad named entity: gimel without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gimel"
+ ]
+ ]
+ },
+ {
+ "input": "ℷ",
+ "description": "Named entity: gimel; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2137"
+ ]
+ ]
+ },
+ {
+ "input": "&gjcy",
+ "description": "Bad named entity: gjcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gjcy"
+ ]
+ ]
+ },
+ {
+ "input": "ѓ",
+ "description": "Named entity: gjcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0453"
+ ]
+ ]
+ },
+ {
+ "input": "&gl",
+ "description": "Bad named entity: gl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gl"
+ ]
+ ]
+ },
+ {
+ "input": "≷",
+ "description": "Named entity: gl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2277"
+ ]
+ ]
+ },
+ {
+ "input": "&glE",
+ "description": "Bad named entity: glE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&glE"
+ ]
+ ]
+ },
+ {
+ "input": "⪒",
+ "description": "Named entity: glE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a92"
+ ]
+ ]
+ },
+ {
+ "input": "&gla",
+ "description": "Bad named entity: gla without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gla"
+ ]
+ ]
+ },
+ {
+ "input": "⪥",
+ "description": "Named entity: gla; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa5"
+ ]
+ ]
+ },
+ {
+ "input": "&glj",
+ "description": "Bad named entity: glj without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&glj"
+ ]
+ ]
+ },
+ {
+ "input": "⪤",
+ "description": "Named entity: glj; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa4"
+ ]
+ ]
+ },
+ {
+ "input": "&gnE",
+ "description": "Bad named entity: gnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gnE"
+ ]
+ ]
+ },
+ {
+ "input": "≩",
+ "description": "Named entity: gnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2269"
+ ]
+ ]
+ },
+ {
+ "input": "&gnap",
+ "description": "Bad named entity: gnap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gnap"
+ ]
+ ]
+ },
+ {
+ "input": "⪊",
+ "description": "Named entity: gnap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8a"
+ ]
+ ]
+ },
+ {
+ "input": "&gnapprox",
+ "description": "Bad named entity: gnapprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gnapprox"
+ ]
+ ]
+ },
+ {
+ "input": "⪊",
+ "description": "Named entity: gnapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8a"
+ ]
+ ]
+ },
+ {
+ "input": "&gne",
+ "description": "Bad named entity: gne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gne"
+ ]
+ ]
+ },
+ {
+ "input": "⪈",
+ "description": "Named entity: gne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a88"
+ ]
+ ]
+ },
+ {
+ "input": "&gneq",
+ "description": "Bad named entity: gneq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gneq"
+ ]
+ ]
+ },
+ {
+ "input": "⪈",
+ "description": "Named entity: gneq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a88"
+ ]
+ ]
+ },
+ {
+ "input": "&gneqq",
+ "description": "Bad named entity: gneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gneqq"
+ ]
+ ]
+ },
+ {
+ "input": "≩",
+ "description": "Named entity: gneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2269"
+ ]
+ ]
+ },
+ {
+ "input": "&gnsim",
+ "description": "Bad named entity: gnsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gnsim"
+ ]
+ ]
+ },
+ {
+ "input": "⋧",
+ "description": "Named entity: gnsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e7"
+ ]
+ ]
+ },
+ {
+ "input": "&gopf",
+ "description": "Bad named entity: gopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕘",
+ "description": "Named entity: gopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd58"
+ ]
+ ]
+ },
+ {
+ "input": "&grave",
+ "description": "Bad named entity: grave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&grave"
+ ]
+ ]
+ },
+ {
+ "input": "`",
+ "description": "Named entity: grave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "`"
+ ]
+ ]
+ },
+ {
+ "input": "&gscr",
+ "description": "Bad named entity: gscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℊ",
+ "description": "Named entity: gscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210a"
+ ]
+ ]
+ },
+ {
+ "input": "&gsim",
+ "description": "Bad named entity: gsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gsim"
+ ]
+ ]
+ },
+ {
+ "input": "≳",
+ "description": "Named entity: gsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2273"
+ ]
+ ]
+ },
+ {
+ "input": "&gsime",
+ "description": "Bad named entity: gsime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gsime"
+ ]
+ ]
+ },
+ {
+ "input": "⪎",
+ "description": "Named entity: gsime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8e"
+ ]
+ ]
+ },
+ {
+ "input": "&gsiml",
+ "description": "Bad named entity: gsiml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gsiml"
+ ]
+ ]
+ },
+ {
+ "input": "⪐",
+ "description": "Named entity: gsiml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a90"
+ ]
+ ]
+ },
+ {
+ "input": ">",
+ "description": "Named entity: gt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ ">"
+ ]
+ ]
+ },
+ {
+ "input": ">",
+ "description": "Named entity: gt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ ">"
+ ]
+ ]
+ },
+ {
+ "input": "⪧",
+ "description": "Named entity: gtcc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa7"
+ ]
+ ]
+ },
+ {
+ "input": "⩺",
+ "description": "Named entity: gtcir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7a"
+ ]
+ ]
+ },
+ {
+ "input": "⋗",
+ "description": "Named entity: gtdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d7"
+ ]
+ ]
+ },
+ {
+ "input": "⦕",
+ "description": "Named entity: gtlPar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2995"
+ ]
+ ]
+ },
+ {
+ "input": "⩼",
+ "description": "Named entity: gtquest; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7c"
+ ]
+ ]
+ },
+ {
+ "input": "⪆",
+ "description": "Named entity: gtrapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a86"
+ ]
+ ]
+ },
+ {
+ "input": "⥸",
+ "description": "Named entity: gtrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2978"
+ ]
+ ]
+ },
+ {
+ "input": "⋗",
+ "description": "Named entity: gtrdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d7"
+ ]
+ ]
+ },
+ {
+ "input": "⋛",
+ "description": "Named entity: gtreqless; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22db"
+ ]
+ ]
+ },
+ {
+ "input": "⪌",
+ "description": "Named entity: gtreqqless; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8c"
+ ]
+ ]
+ },
+ {
+ "input": "≷",
+ "description": "Named entity: gtrless; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2277"
+ ]
+ ]
+ },
+ {
+ "input": "≳",
+ "description": "Named entity: gtrsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2273"
+ ]
+ ]
+ },
+ {
+ "input": "&gvertneqq",
+ "description": "Bad named entity: gvertneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gvertneqq"
+ ]
+ ]
+ },
+ {
+ "input": "≩︀",
+ "description": "Named entity: gvertneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2269\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&gvnE",
+ "description": "Bad named entity: gvnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&gvnE"
+ ]
+ ]
+ },
+ {
+ "input": "≩︀",
+ "description": "Named entity: gvnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2269\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&hArr",
+ "description": "Bad named entity: hArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇔",
+ "description": "Named entity: hArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d4"
+ ]
+ ]
+ },
+ {
+ "input": "&hairsp",
+ "description": "Bad named entity: hairsp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hairsp"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: hairsp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200a"
+ ]
+ ]
+ },
+ {
+ "input": "&half",
+ "description": "Bad named entity: half without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&half"
+ ]
+ ]
+ },
+ {
+ "input": "½",
+ "description": "Named entity: half; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00bd"
+ ]
+ ]
+ },
+ {
+ "input": "&hamilt",
+ "description": "Bad named entity: hamilt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hamilt"
+ ]
+ ]
+ },
+ {
+ "input": "ℋ",
+ "description": "Named entity: hamilt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210b"
+ ]
+ ]
+ },
+ {
+ "input": "&hardcy",
+ "description": "Bad named entity: hardcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hardcy"
+ ]
+ ]
+ },
+ {
+ "input": "ъ",
+ "description": "Named entity: hardcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u044a"
+ ]
+ ]
+ },
+ {
+ "input": "&harr",
+ "description": "Bad named entity: harr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&harr"
+ ]
+ ]
+ },
+ {
+ "input": "↔",
+ "description": "Named entity: harr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2194"
+ ]
+ ]
+ },
+ {
+ "input": "&harrcir",
+ "description": "Bad named entity: harrcir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&harrcir"
+ ]
+ ]
+ },
+ {
+ "input": "⥈",
+ "description": "Named entity: harrcir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2948"
+ ]
+ ]
+ },
+ {
+ "input": "&harrw",
+ "description": "Bad named entity: harrw without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&harrw"
+ ]
+ ]
+ },
+ {
+ "input": "↭",
+ "description": "Named entity: harrw; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ad"
+ ]
+ ]
+ },
+ {
+ "input": "&hbar",
+ "description": "Bad named entity: hbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hbar"
+ ]
+ ]
+ },
+ {
+ "input": "ℏ",
+ "description": "Named entity: hbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210f"
+ ]
+ ]
+ },
+ {
+ "input": "&hcirc",
+ "description": "Bad named entity: hcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hcirc"
+ ]
+ ]
+ },
+ {
+ "input": "ĥ",
+ "description": "Named entity: hcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0125"
+ ]
+ ]
+ },
+ {
+ "input": "&hearts",
+ "description": "Bad named entity: hearts without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hearts"
+ ]
+ ]
+ },
+ {
+ "input": "♥",
+ "description": "Named entity: hearts; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2665"
+ ]
+ ]
+ },
+ {
+ "input": "&heartsuit",
+ "description": "Bad named entity: heartsuit without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&heartsuit"
+ ]
+ ]
+ },
+ {
+ "input": "♥",
+ "description": "Named entity: heartsuit; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2665"
+ ]
+ ]
+ },
+ {
+ "input": "&hellip",
+ "description": "Bad named entity: hellip without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hellip"
+ ]
+ ]
+ },
+ {
+ "input": "…",
+ "description": "Named entity: hellip; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2026"
+ ]
+ ]
+ },
+ {
+ "input": "&hercon",
+ "description": "Bad named entity: hercon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hercon"
+ ]
+ ]
+ },
+ {
+ "input": "⊹",
+ "description": "Named entity: hercon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b9"
+ ]
+ ]
+ },
+ {
+ "input": "&hfr",
+ "description": "Bad named entity: hfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔥",
+ "description": "Named entity: hfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd25"
+ ]
+ ]
+ },
+ {
+ "input": "&hksearow",
+ "description": "Bad named entity: hksearow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hksearow"
+ ]
+ ]
+ },
+ {
+ "input": "⤥",
+ "description": "Named entity: hksearow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2925"
+ ]
+ ]
+ },
+ {
+ "input": "&hkswarow",
+ "description": "Bad named entity: hkswarow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hkswarow"
+ ]
+ ]
+ },
+ {
+ "input": "⤦",
+ "description": "Named entity: hkswarow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2926"
+ ]
+ ]
+ },
+ {
+ "input": "&hoarr",
+ "description": "Bad named entity: hoarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hoarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇿",
+ "description": "Named entity: hoarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ff"
+ ]
+ ]
+ },
+ {
+ "input": "&homtht",
+ "description": "Bad named entity: homtht without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&homtht"
+ ]
+ ]
+ },
+ {
+ "input": "∻",
+ "description": "Named entity: homtht; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223b"
+ ]
+ ]
+ },
+ {
+ "input": "&hookleftarrow",
+ "description": "Bad named entity: hookleftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hookleftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↩",
+ "description": "Named entity: hookleftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a9"
+ ]
+ ]
+ },
+ {
+ "input": "&hookrightarrow",
+ "description": "Bad named entity: hookrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hookrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↪",
+ "description": "Named entity: hookrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21aa"
+ ]
+ ]
+ },
+ {
+ "input": "&hopf",
+ "description": "Bad named entity: hopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕙",
+ "description": "Named entity: hopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd59"
+ ]
+ ]
+ },
+ {
+ "input": "&horbar",
+ "description": "Bad named entity: horbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&horbar"
+ ]
+ ]
+ },
+ {
+ "input": "―",
+ "description": "Named entity: horbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2015"
+ ]
+ ]
+ },
+ {
+ "input": "&hscr",
+ "description": "Bad named entity: hscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒽",
+ "description": "Named entity: hscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcbd"
+ ]
+ ]
+ },
+ {
+ "input": "&hslash",
+ "description": "Bad named entity: hslash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hslash"
+ ]
+ ]
+ },
+ {
+ "input": "ℏ",
+ "description": "Named entity: hslash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210f"
+ ]
+ ]
+ },
+ {
+ "input": "&hstrok",
+ "description": "Bad named entity: hstrok without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hstrok"
+ ]
+ ]
+ },
+ {
+ "input": "ħ",
+ "description": "Named entity: hstrok; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0127"
+ ]
+ ]
+ },
+ {
+ "input": "&hybull",
+ "description": "Bad named entity: hybull without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hybull"
+ ]
+ ]
+ },
+ {
+ "input": "⁃",
+ "description": "Named entity: hybull; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2043"
+ ]
+ ]
+ },
+ {
+ "input": "&hyphen",
+ "description": "Bad named entity: hyphen without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&hyphen"
+ ]
+ ]
+ },
+ {
+ "input": "‐",
+ "description": "Named entity: hyphen; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2010"
+ ]
+ ]
+ },
+ {
+ "input": "í",
+ "description": "Named entity: iacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ed"
+ ]
+ ]
+ },
+ {
+ "input": "í",
+ "description": "Named entity: iacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ed"
+ ]
+ ]
+ },
+ {
+ "input": "&ic",
+ "description": "Bad named entity: ic without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ic"
+ ]
+ ]
+ },
+ {
+ "input": "⁣",
+ "description": "Named entity: ic; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2063"
+ ]
+ ]
+ },
+ {
+ "input": "î",
+ "description": "Named entity: icirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ee"
+ ]
+ ]
+ },
+ {
+ "input": "î",
+ "description": "Named entity: icirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ee"
+ ]
+ ]
+ },
+ {
+ "input": "&icy",
+ "description": "Bad named entity: icy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&icy"
+ ]
+ ]
+ },
+ {
+ "input": "и",
+ "description": "Named entity: icy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0438"
+ ]
+ ]
+ },
+ {
+ "input": "&iecy",
+ "description": "Bad named entity: iecy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iecy"
+ ]
+ ]
+ },
+ {
+ "input": "е",
+ "description": "Named entity: iecy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0435"
+ ]
+ ]
+ },
+ {
+ "input": "¡",
+ "description": "Named entity: iexcl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a1"
+ ]
+ ]
+ },
+ {
+ "input": "¡",
+ "description": "Named entity: iexcl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a1"
+ ]
+ ]
+ },
+ {
+ "input": "&iff",
+ "description": "Bad named entity: iff without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iff"
+ ]
+ ]
+ },
+ {
+ "input": "⇔",
+ "description": "Named entity: iff; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d4"
+ ]
+ ]
+ },
+ {
+ "input": "&ifr",
+ "description": "Bad named entity: ifr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ifr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔦",
+ "description": "Named entity: ifr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd26"
+ ]
+ ]
+ },
+ {
+ "input": "ì",
+ "description": "Named entity: igrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ec"
+ ]
+ ]
+ },
+ {
+ "input": "ì",
+ "description": "Named entity: igrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ec"
+ ]
+ ]
+ },
+ {
+ "input": "&ii",
+ "description": "Bad named entity: ii without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ii"
+ ]
+ ]
+ },
+ {
+ "input": "ⅈ",
+ "description": "Named entity: ii; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2148"
+ ]
+ ]
+ },
+ {
+ "input": "&iiiint",
+ "description": "Bad named entity: iiiint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iiiint"
+ ]
+ ]
+ },
+ {
+ "input": "⨌",
+ "description": "Named entity: iiiint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a0c"
+ ]
+ ]
+ },
+ {
+ "input": "&iiint",
+ "description": "Bad named entity: iiint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iiint"
+ ]
+ ]
+ },
+ {
+ "input": "∭",
+ "description": "Named entity: iiint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222d"
+ ]
+ ]
+ },
+ {
+ "input": "&iinfin",
+ "description": "Bad named entity: iinfin without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iinfin"
+ ]
+ ]
+ },
+ {
+ "input": "⧜",
+ "description": "Named entity: iinfin; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29dc"
+ ]
+ ]
+ },
+ {
+ "input": "&iiota",
+ "description": "Bad named entity: iiota without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iiota"
+ ]
+ ]
+ },
+ {
+ "input": "℩",
+ "description": "Named entity: iiota; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2129"
+ ]
+ ]
+ },
+ {
+ "input": "&ijlig",
+ "description": "Bad named entity: ijlig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ijlig"
+ ]
+ ]
+ },
+ {
+ "input": "ij",
+ "description": "Named entity: ijlig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0133"
+ ]
+ ]
+ },
+ {
+ "input": "&imacr",
+ "description": "Bad named entity: imacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&imacr"
+ ]
+ ]
+ },
+ {
+ "input": "ī",
+ "description": "Named entity: imacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u012b"
+ ]
+ ]
+ },
+ {
+ "input": "&image",
+ "description": "Bad named entity: image without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&image"
+ ]
+ ]
+ },
+ {
+ "input": "ℑ",
+ "description": "Named entity: image; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2111"
+ ]
+ ]
+ },
+ {
+ "input": "&imagline",
+ "description": "Bad named entity: imagline without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&imagline"
+ ]
+ ]
+ },
+ {
+ "input": "ℐ",
+ "description": "Named entity: imagline; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2110"
+ ]
+ ]
+ },
+ {
+ "input": "&imagpart",
+ "description": "Bad named entity: imagpart without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&imagpart"
+ ]
+ ]
+ },
+ {
+ "input": "ℑ",
+ "description": "Named entity: imagpart; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2111"
+ ]
+ ]
+ },
+ {
+ "input": "&imath",
+ "description": "Bad named entity: imath without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&imath"
+ ]
+ ]
+ },
+ {
+ "input": "ı",
+ "description": "Named entity: imath; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0131"
+ ]
+ ]
+ },
+ {
+ "input": "&imof",
+ "description": "Bad named entity: imof without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&imof"
+ ]
+ ]
+ },
+ {
+ "input": "⊷",
+ "description": "Named entity: imof; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b7"
+ ]
+ ]
+ },
+ {
+ "input": "&imped",
+ "description": "Bad named entity: imped without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&imped"
+ ]
+ ]
+ },
+ {
+ "input": "Ƶ",
+ "description": "Named entity: imped; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u01b5"
+ ]
+ ]
+ },
+ {
+ "input": "&in",
+ "description": "Bad named entity: in without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&in"
+ ]
+ ]
+ },
+ {
+ "input": "∈",
+ "description": "Named entity: in; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2208"
+ ]
+ ]
+ },
+ {
+ "input": "&incare",
+ "description": "Bad named entity: incare without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&incare"
+ ]
+ ]
+ },
+ {
+ "input": "℅",
+ "description": "Named entity: incare; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2105"
+ ]
+ ]
+ },
+ {
+ "input": "&infin",
+ "description": "Bad named entity: infin without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&infin"
+ ]
+ ]
+ },
+ {
+ "input": "∞",
+ "description": "Named entity: infin; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221e"
+ ]
+ ]
+ },
+ {
+ "input": "&infintie",
+ "description": "Bad named entity: infintie without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&infintie"
+ ]
+ ]
+ },
+ {
+ "input": "⧝",
+ "description": "Named entity: infintie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29dd"
+ ]
+ ]
+ },
+ {
+ "input": "&inodot",
+ "description": "Bad named entity: inodot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&inodot"
+ ]
+ ]
+ },
+ {
+ "input": "ı",
+ "description": "Named entity: inodot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0131"
+ ]
+ ]
+ },
+ {
+ "input": "&int",
+ "description": "Bad named entity: int without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&int"
+ ]
+ ]
+ },
+ {
+ "input": "∫",
+ "description": "Named entity: int; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222b"
+ ]
+ ]
+ },
+ {
+ "input": "&intcal",
+ "description": "Bad named entity: intcal without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&intcal"
+ ]
+ ]
+ },
+ {
+ "input": "⊺",
+ "description": "Named entity: intcal; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ba"
+ ]
+ ]
+ },
+ {
+ "input": "&integers",
+ "description": "Bad named entity: integers without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&integers"
+ ]
+ ]
+ },
+ {
+ "input": "ℤ",
+ "description": "Named entity: integers; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2124"
+ ]
+ ]
+ },
+ {
+ "input": "&intercal",
+ "description": "Bad named entity: intercal without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&intercal"
+ ]
+ ]
+ },
+ {
+ "input": "⊺",
+ "description": "Named entity: intercal; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ba"
+ ]
+ ]
+ },
+ {
+ "input": "&intlarhk",
+ "description": "Bad named entity: intlarhk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&intlarhk"
+ ]
+ ]
+ },
+ {
+ "input": "⨗",
+ "description": "Named entity: intlarhk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a17"
+ ]
+ ]
+ },
+ {
+ "input": "&intprod",
+ "description": "Bad named entity: intprod without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&intprod"
+ ]
+ ]
+ },
+ {
+ "input": "⨼",
+ "description": "Named entity: intprod; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a3c"
+ ]
+ ]
+ },
+ {
+ "input": "&iocy",
+ "description": "Bad named entity: iocy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iocy"
+ ]
+ ]
+ },
+ {
+ "input": "ё",
+ "description": "Named entity: iocy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0451"
+ ]
+ ]
+ },
+ {
+ "input": "&iogon",
+ "description": "Bad named entity: iogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iogon"
+ ]
+ ]
+ },
+ {
+ "input": "į",
+ "description": "Named entity: iogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u012f"
+ ]
+ ]
+ },
+ {
+ "input": "&iopf",
+ "description": "Bad named entity: iopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕚",
+ "description": "Named entity: iopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd5a"
+ ]
+ ]
+ },
+ {
+ "input": "&iota",
+ "description": "Bad named entity: iota without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iota"
+ ]
+ ]
+ },
+ {
+ "input": "ι",
+ "description": "Named entity: iota; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b9"
+ ]
+ ]
+ },
+ {
+ "input": "&iprod",
+ "description": "Bad named entity: iprod without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iprod"
+ ]
+ ]
+ },
+ {
+ "input": "⨼",
+ "description": "Named entity: iprod; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a3c"
+ ]
+ ]
+ },
+ {
+ "input": "¿",
+ "description": "Named entity: iquest without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00bf"
+ ]
+ ]
+ },
+ {
+ "input": "¿",
+ "description": "Named entity: iquest; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00bf"
+ ]
+ ]
+ },
+ {
+ "input": "&iscr",
+ "description": "Bad named entity: iscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒾",
+ "description": "Named entity: iscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcbe"
+ ]
+ ]
+ },
+ {
+ "input": "&isin",
+ "description": "Bad named entity: isin without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&isin"
+ ]
+ ]
+ },
+ {
+ "input": "∈",
+ "description": "Named entity: isin; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2208"
+ ]
+ ]
+ },
+ {
+ "input": "&isinE",
+ "description": "Bad named entity: isinE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&isinE"
+ ]
+ ]
+ },
+ {
+ "input": "⋹",
+ "description": "Named entity: isinE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f9"
+ ]
+ ]
+ },
+ {
+ "input": "&isindot",
+ "description": "Bad named entity: isindot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&isindot"
+ ]
+ ]
+ },
+ {
+ "input": "⋵",
+ "description": "Named entity: isindot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f5"
+ ]
+ ]
+ },
+ {
+ "input": "&isins",
+ "description": "Bad named entity: isins without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&isins"
+ ]
+ ]
+ },
+ {
+ "input": "⋴",
+ "description": "Named entity: isins; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f4"
+ ]
+ ]
+ },
+ {
+ "input": "&isinsv",
+ "description": "Bad named entity: isinsv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&isinsv"
+ ]
+ ]
+ },
+ {
+ "input": "⋳",
+ "description": "Named entity: isinsv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f3"
+ ]
+ ]
+ },
+ {
+ "input": "&isinv",
+ "description": "Bad named entity: isinv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&isinv"
+ ]
+ ]
+ },
+ {
+ "input": "∈",
+ "description": "Named entity: isinv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2208"
+ ]
+ ]
+ },
+ {
+ "input": "&it",
+ "description": "Bad named entity: it without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&it"
+ ]
+ ]
+ },
+ {
+ "input": "⁢",
+ "description": "Named entity: it; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2062"
+ ]
+ ]
+ },
+ {
+ "input": "&itilde",
+ "description": "Bad named entity: itilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&itilde"
+ ]
+ ]
+ },
+ {
+ "input": "ĩ",
+ "description": "Named entity: itilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0129"
+ ]
+ ]
+ },
+ {
+ "input": "&iukcy",
+ "description": "Bad named entity: iukcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&iukcy"
+ ]
+ ]
+ },
+ {
+ "input": "і",
+ "description": "Named entity: iukcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0456"
+ ]
+ ]
+ },
+ {
+ "input": "ï",
+ "description": "Named entity: iuml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ef"
+ ]
+ ]
+ },
+ {
+ "input": "ï",
+ "description": "Named entity: iuml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ef"
+ ]
+ ]
+ },
+ {
+ "input": "&jcirc",
+ "description": "Bad named entity: jcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&jcirc"
+ ]
+ ]
+ },
+ {
+ "input": "ĵ",
+ "description": "Named entity: jcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0135"
+ ]
+ ]
+ },
+ {
+ "input": "&jcy",
+ "description": "Bad named entity: jcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&jcy"
+ ]
+ ]
+ },
+ {
+ "input": "й",
+ "description": "Named entity: jcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0439"
+ ]
+ ]
+ },
+ {
+ "input": "&jfr",
+ "description": "Bad named entity: jfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&jfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔧",
+ "description": "Named entity: jfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd27"
+ ]
+ ]
+ },
+ {
+ "input": "&jmath",
+ "description": "Bad named entity: jmath without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&jmath"
+ ]
+ ]
+ },
+ {
+ "input": "ȷ",
+ "description": "Named entity: jmath; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0237"
+ ]
+ ]
+ },
+ {
+ "input": "&jopf",
+ "description": "Bad named entity: jopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&jopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕛",
+ "description": "Named entity: jopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd5b"
+ ]
+ ]
+ },
+ {
+ "input": "&jscr",
+ "description": "Bad named entity: jscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&jscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝒿",
+ "description": "Named entity: jscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcbf"
+ ]
+ ]
+ },
+ {
+ "input": "&jsercy",
+ "description": "Bad named entity: jsercy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&jsercy"
+ ]
+ ]
+ },
+ {
+ "input": "ј",
+ "description": "Named entity: jsercy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0458"
+ ]
+ ]
+ },
+ {
+ "input": "&jukcy",
+ "description": "Bad named entity: jukcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&jukcy"
+ ]
+ ]
+ },
+ {
+ "input": "є",
+ "description": "Named entity: jukcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0454"
+ ]
+ ]
+ },
+ {
+ "input": "&kappa",
+ "description": "Bad named entity: kappa without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kappa"
+ ]
+ ]
+ },
+ {
+ "input": "κ",
+ "description": "Named entity: kappa; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03ba"
+ ]
+ ]
+ },
+ {
+ "input": "&kappav",
+ "description": "Bad named entity: kappav without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kappav"
+ ]
+ ]
+ },
+ {
+ "input": "ϰ",
+ "description": "Named entity: kappav; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f0"
+ ]
+ ]
+ },
+ {
+ "input": "&kcedil",
+ "description": "Bad named entity: kcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kcedil"
+ ]
+ ]
+ },
+ {
+ "input": "ķ",
+ "description": "Named entity: kcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0137"
+ ]
+ ]
+ },
+ {
+ "input": "&kcy",
+ "description": "Bad named entity: kcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kcy"
+ ]
+ ]
+ },
+ {
+ "input": "к",
+ "description": "Named entity: kcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u043a"
+ ]
+ ]
+ },
+ {
+ "input": "&kfr",
+ "description": "Bad named entity: kfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔨",
+ "description": "Named entity: kfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd28"
+ ]
+ ]
+ },
+ {
+ "input": "&kgreen",
+ "description": "Bad named entity: kgreen without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kgreen"
+ ]
+ ]
+ },
+ {
+ "input": "ĸ",
+ "description": "Named entity: kgreen; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0138"
+ ]
+ ]
+ },
+ {
+ "input": "&khcy",
+ "description": "Bad named entity: khcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&khcy"
+ ]
+ ]
+ },
+ {
+ "input": "х",
+ "description": "Named entity: khcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0445"
+ ]
+ ]
+ },
+ {
+ "input": "&kjcy",
+ "description": "Bad named entity: kjcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kjcy"
+ ]
+ ]
+ },
+ {
+ "input": "ќ",
+ "description": "Named entity: kjcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u045c"
+ ]
+ ]
+ },
+ {
+ "input": "&kopf",
+ "description": "Bad named entity: kopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕜",
+ "description": "Named entity: kopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd5c"
+ ]
+ ]
+ },
+ {
+ "input": "&kscr",
+ "description": "Bad named entity: kscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&kscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓀",
+ "description": "Named entity: kscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc0"
+ ]
+ ]
+ },
+ {
+ "input": "&lAarr",
+ "description": "Bad named entity: lAarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lAarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇚",
+ "description": "Named entity: lAarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21da"
+ ]
+ ]
+ },
+ {
+ "input": "&lArr",
+ "description": "Bad named entity: lArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇐",
+ "description": "Named entity: lArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d0"
+ ]
+ ]
+ },
+ {
+ "input": "&lAtail",
+ "description": "Bad named entity: lAtail without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lAtail"
+ ]
+ ]
+ },
+ {
+ "input": "⤛",
+ "description": "Named entity: lAtail; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u291b"
+ ]
+ ]
+ },
+ {
+ "input": "&lBarr",
+ "description": "Bad named entity: lBarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lBarr"
+ ]
+ ]
+ },
+ {
+ "input": "⤎",
+ "description": "Named entity: lBarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u290e"
+ ]
+ ]
+ },
+ {
+ "input": "&lE",
+ "description": "Bad named entity: lE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lE"
+ ]
+ ]
+ },
+ {
+ "input": "≦",
+ "description": "Named entity: lE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2266"
+ ]
+ ]
+ },
+ {
+ "input": "&lEg",
+ "description": "Bad named entity: lEg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lEg"
+ ]
+ ]
+ },
+ {
+ "input": "⪋",
+ "description": "Named entity: lEg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8b"
+ ]
+ ]
+ },
+ {
+ "input": "&lHar",
+ "description": "Bad named entity: lHar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lHar"
+ ]
+ ]
+ },
+ {
+ "input": "⥢",
+ "description": "Named entity: lHar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2962"
+ ]
+ ]
+ },
+ {
+ "input": "&lacute",
+ "description": "Bad named entity: lacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lacute"
+ ]
+ ]
+ },
+ {
+ "input": "ĺ",
+ "description": "Named entity: lacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u013a"
+ ]
+ ]
+ },
+ {
+ "input": "&laemptyv",
+ "description": "Bad named entity: laemptyv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&laemptyv"
+ ]
+ ]
+ },
+ {
+ "input": "⦴",
+ "description": "Named entity: laemptyv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b4"
+ ]
+ ]
+ },
+ {
+ "input": "&lagran",
+ "description": "Bad named entity: lagran without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lagran"
+ ]
+ ]
+ },
+ {
+ "input": "ℒ",
+ "description": "Named entity: lagran; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2112"
+ ]
+ ]
+ },
+ {
+ "input": "&lambda",
+ "description": "Bad named entity: lambda without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lambda"
+ ]
+ ]
+ },
+ {
+ "input": "λ",
+ "description": "Named entity: lambda; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03bb"
+ ]
+ ]
+ },
+ {
+ "input": "&lang",
+ "description": "Bad named entity: lang without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lang"
+ ]
+ ]
+ },
+ {
+ "input": "⟨",
+ "description": "Named entity: lang; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e8"
+ ]
+ ]
+ },
+ {
+ "input": "&langd",
+ "description": "Bad named entity: langd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&langd"
+ ]
+ ]
+ },
+ {
+ "input": "⦑",
+ "description": "Named entity: langd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2991"
+ ]
+ ]
+ },
+ {
+ "input": "&langle",
+ "description": "Bad named entity: langle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&langle"
+ ]
+ ]
+ },
+ {
+ "input": "⟨",
+ "description": "Named entity: langle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e8"
+ ]
+ ]
+ },
+ {
+ "input": "&lap",
+ "description": "Bad named entity: lap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lap"
+ ]
+ ]
+ },
+ {
+ "input": "⪅",
+ "description": "Named entity: lap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a85"
+ ]
+ ]
+ },
+ {
+ "input": "«",
+ "description": "Named entity: laquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ab"
+ ]
+ ]
+ },
+ {
+ "input": "«",
+ "description": "Named entity: laquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ab"
+ ]
+ ]
+ },
+ {
+ "input": "&larr",
+ "description": "Bad named entity: larr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larr"
+ ]
+ ]
+ },
+ {
+ "input": "←",
+ "description": "Named entity: larr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2190"
+ ]
+ ]
+ },
+ {
+ "input": "&larrb",
+ "description": "Bad named entity: larrb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larrb"
+ ]
+ ]
+ },
+ {
+ "input": "⇤",
+ "description": "Named entity: larrb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21e4"
+ ]
+ ]
+ },
+ {
+ "input": "&larrbfs",
+ "description": "Bad named entity: larrbfs without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larrbfs"
+ ]
+ ]
+ },
+ {
+ "input": "⤟",
+ "description": "Named entity: larrbfs; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u291f"
+ ]
+ ]
+ },
+ {
+ "input": "&larrfs",
+ "description": "Bad named entity: larrfs without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larrfs"
+ ]
+ ]
+ },
+ {
+ "input": "⤝",
+ "description": "Named entity: larrfs; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u291d"
+ ]
+ ]
+ },
+ {
+ "input": "&larrhk",
+ "description": "Bad named entity: larrhk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larrhk"
+ ]
+ ]
+ },
+ {
+ "input": "↩",
+ "description": "Named entity: larrhk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a9"
+ ]
+ ]
+ },
+ {
+ "input": "&larrlp",
+ "description": "Bad named entity: larrlp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larrlp"
+ ]
+ ]
+ },
+ {
+ "input": "↫",
+ "description": "Named entity: larrlp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ab"
+ ]
+ ]
+ },
+ {
+ "input": "&larrpl",
+ "description": "Bad named entity: larrpl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larrpl"
+ ]
+ ]
+ },
+ {
+ "input": "⤹",
+ "description": "Named entity: larrpl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2939"
+ ]
+ ]
+ },
+ {
+ "input": "&larrsim",
+ "description": "Bad named entity: larrsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larrsim"
+ ]
+ ]
+ },
+ {
+ "input": "⥳",
+ "description": "Named entity: larrsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2973"
+ ]
+ ]
+ },
+ {
+ "input": "&larrtl",
+ "description": "Bad named entity: larrtl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&larrtl"
+ ]
+ ]
+ },
+ {
+ "input": "↢",
+ "description": "Named entity: larrtl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a2"
+ ]
+ ]
+ },
+ {
+ "input": "&lat",
+ "description": "Bad named entity: lat without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lat"
+ ]
+ ]
+ },
+ {
+ "input": "⪫",
+ "description": "Named entity: lat; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aab"
+ ]
+ ]
+ },
+ {
+ "input": "&latail",
+ "description": "Bad named entity: latail without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&latail"
+ ]
+ ]
+ },
+ {
+ "input": "⤙",
+ "description": "Named entity: latail; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2919"
+ ]
+ ]
+ },
+ {
+ "input": "&late",
+ "description": "Bad named entity: late without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&late"
+ ]
+ ]
+ },
+ {
+ "input": "⪭",
+ "description": "Named entity: late; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aad"
+ ]
+ ]
+ },
+ {
+ "input": "&lates",
+ "description": "Bad named entity: lates without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lates"
+ ]
+ ]
+ },
+ {
+ "input": "⪭︀",
+ "description": "Named entity: lates; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aad\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&lbarr",
+ "description": "Bad named entity: lbarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lbarr"
+ ]
+ ]
+ },
+ {
+ "input": "⤌",
+ "description": "Named entity: lbarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u290c"
+ ]
+ ]
+ },
+ {
+ "input": "&lbbrk",
+ "description": "Bad named entity: lbbrk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lbbrk"
+ ]
+ ]
+ },
+ {
+ "input": "❲",
+ "description": "Named entity: lbbrk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2772"
+ ]
+ ]
+ },
+ {
+ "input": "&lbrace",
+ "description": "Bad named entity: lbrace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lbrace"
+ ]
+ ]
+ },
+ {
+ "input": "{",
+ "description": "Named entity: lbrace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "{"
+ ]
+ ]
+ },
+ {
+ "input": "&lbrack",
+ "description": "Bad named entity: lbrack without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lbrack"
+ ]
+ ]
+ },
+ {
+ "input": "[",
+ "description": "Named entity: lbrack; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "["
+ ]
+ ]
+ },
+ {
+ "input": "&lbrke",
+ "description": "Bad named entity: lbrke without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lbrke"
+ ]
+ ]
+ },
+ {
+ "input": "⦋",
+ "description": "Named entity: lbrke; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u298b"
+ ]
+ ]
+ },
+ {
+ "input": "&lbrksld",
+ "description": "Bad named entity: lbrksld without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lbrksld"
+ ]
+ ]
+ },
+ {
+ "input": "⦏",
+ "description": "Named entity: lbrksld; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u298f"
+ ]
+ ]
+ },
+ {
+ "input": "&lbrkslu",
+ "description": "Bad named entity: lbrkslu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lbrkslu"
+ ]
+ ]
+ },
+ {
+ "input": "⦍",
+ "description": "Named entity: lbrkslu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u298d"
+ ]
+ ]
+ },
+ {
+ "input": "&lcaron",
+ "description": "Bad named entity: lcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lcaron"
+ ]
+ ]
+ },
+ {
+ "input": "ľ",
+ "description": "Named entity: lcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u013e"
+ ]
+ ]
+ },
+ {
+ "input": "&lcedil",
+ "description": "Bad named entity: lcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lcedil"
+ ]
+ ]
+ },
+ {
+ "input": "ļ",
+ "description": "Named entity: lcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u013c"
+ ]
+ ]
+ },
+ {
+ "input": "&lceil",
+ "description": "Bad named entity: lceil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lceil"
+ ]
+ ]
+ },
+ {
+ "input": "⌈",
+ "description": "Named entity: lceil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2308"
+ ]
+ ]
+ },
+ {
+ "input": "&lcub",
+ "description": "Bad named entity: lcub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lcub"
+ ]
+ ]
+ },
+ {
+ "input": "{",
+ "description": "Named entity: lcub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "{"
+ ]
+ ]
+ },
+ {
+ "input": "&lcy",
+ "description": "Bad named entity: lcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lcy"
+ ]
+ ]
+ },
+ {
+ "input": "л",
+ "description": "Named entity: lcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u043b"
+ ]
+ ]
+ },
+ {
+ "input": "&ldca",
+ "description": "Bad named entity: ldca without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ldca"
+ ]
+ ]
+ },
+ {
+ "input": "⤶",
+ "description": "Named entity: ldca; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2936"
+ ]
+ ]
+ },
+ {
+ "input": "&ldquo",
+ "description": "Bad named entity: ldquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ldquo"
+ ]
+ ]
+ },
+ {
+ "input": "“",
+ "description": "Named entity: ldquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201c"
+ ]
+ ]
+ },
+ {
+ "input": "&ldquor",
+ "description": "Bad named entity: ldquor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ldquor"
+ ]
+ ]
+ },
+ {
+ "input": "„",
+ "description": "Named entity: ldquor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201e"
+ ]
+ ]
+ },
+ {
+ "input": "&ldrdhar",
+ "description": "Bad named entity: ldrdhar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ldrdhar"
+ ]
+ ]
+ },
+ {
+ "input": "⥧",
+ "description": "Named entity: ldrdhar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2967"
+ ]
+ ]
+ },
+ {
+ "input": "&ldrushar",
+ "description": "Bad named entity: ldrushar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ldrushar"
+ ]
+ ]
+ },
+ {
+ "input": "⥋",
+ "description": "Named entity: ldrushar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u294b"
+ ]
+ ]
+ },
+ {
+ "input": "&ldsh",
+ "description": "Bad named entity: ldsh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ldsh"
+ ]
+ ]
+ },
+ {
+ "input": "↲",
+ "description": "Named entity: ldsh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b2"
+ ]
+ ]
+ },
+ {
+ "input": "&le",
+ "description": "Bad named entity: le without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&le"
+ ]
+ ]
+ },
+ {
+ "input": "≤",
+ "description": "Named entity: le; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2264"
+ ]
+ ]
+ },
+ {
+ "input": "&leftarrow",
+ "description": "Bad named entity: leftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "←",
+ "description": "Named entity: leftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2190"
+ ]
+ ]
+ },
+ {
+ "input": "&leftarrowtail",
+ "description": "Bad named entity: leftarrowtail without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftarrowtail"
+ ]
+ ]
+ },
+ {
+ "input": "↢",
+ "description": "Named entity: leftarrowtail; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a2"
+ ]
+ ]
+ },
+ {
+ "input": "&leftharpoondown",
+ "description": "Bad named entity: leftharpoondown without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftharpoondown"
+ ]
+ ]
+ },
+ {
+ "input": "↽",
+ "description": "Named entity: leftharpoondown; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bd"
+ ]
+ ]
+ },
+ {
+ "input": "&leftharpoonup",
+ "description": "Bad named entity: leftharpoonup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftharpoonup"
+ ]
+ ]
+ },
+ {
+ "input": "↼",
+ "description": "Named entity: leftharpoonup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bc"
+ ]
+ ]
+ },
+ {
+ "input": "&leftleftarrows",
+ "description": "Bad named entity: leftleftarrows without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftleftarrows"
+ ]
+ ]
+ },
+ {
+ "input": "⇇",
+ "description": "Named entity: leftleftarrows; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c7"
+ ]
+ ]
+ },
+ {
+ "input": "&leftrightarrow",
+ "description": "Bad named entity: leftrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↔",
+ "description": "Named entity: leftrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2194"
+ ]
+ ]
+ },
+ {
+ "input": "&leftrightarrows",
+ "description": "Bad named entity: leftrightarrows without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftrightarrows"
+ ]
+ ]
+ },
+ {
+ "input": "⇆",
+ "description": "Named entity: leftrightarrows; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c6"
+ ]
+ ]
+ },
+ {
+ "input": "&leftrightharpoons",
+ "description": "Bad named entity: leftrightharpoons without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftrightharpoons"
+ ]
+ ]
+ },
+ {
+ "input": "⇋",
+ "description": "Named entity: leftrightharpoons; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cb"
+ ]
+ ]
+ },
+ {
+ "input": "&leftrightsquigarrow",
+ "description": "Bad named entity: leftrightsquigarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftrightsquigarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↭",
+ "description": "Named entity: leftrightsquigarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ad"
+ ]
+ ]
+ },
+ {
+ "input": "&leftthreetimes",
+ "description": "Bad named entity: leftthreetimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leftthreetimes"
+ ]
+ ]
+ },
+ {
+ "input": "⋋",
+ "description": "Named entity: leftthreetimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22cb"
+ ]
+ ]
+ },
+ {
+ "input": "&leg",
+ "description": "Bad named entity: leg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leg"
+ ]
+ ]
+ },
+ {
+ "input": "⋚",
+ "description": "Named entity: leg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22da"
+ ]
+ ]
+ },
+ {
+ "input": "&leq",
+ "description": "Bad named entity: leq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leq"
+ ]
+ ]
+ },
+ {
+ "input": "≤",
+ "description": "Named entity: leq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2264"
+ ]
+ ]
+ },
+ {
+ "input": "&leqq",
+ "description": "Bad named entity: leqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leqq"
+ ]
+ ]
+ },
+ {
+ "input": "≦",
+ "description": "Named entity: leqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2266"
+ ]
+ ]
+ },
+ {
+ "input": "&leqslant",
+ "description": "Bad named entity: leqslant without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&leqslant"
+ ]
+ ]
+ },
+ {
+ "input": "⩽",
+ "description": "Named entity: leqslant; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7d"
+ ]
+ ]
+ },
+ {
+ "input": "&les",
+ "description": "Bad named entity: les without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&les"
+ ]
+ ]
+ },
+ {
+ "input": "⩽",
+ "description": "Named entity: les; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7d"
+ ]
+ ]
+ },
+ {
+ "input": "&lescc",
+ "description": "Bad named entity: lescc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lescc"
+ ]
+ ]
+ },
+ {
+ "input": "⪨",
+ "description": "Named entity: lescc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa8"
+ ]
+ ]
+ },
+ {
+ "input": "&lesdot",
+ "description": "Bad named entity: lesdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lesdot"
+ ]
+ ]
+ },
+ {
+ "input": "⩿",
+ "description": "Named entity: lesdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7f"
+ ]
+ ]
+ },
+ {
+ "input": "&lesdoto",
+ "description": "Bad named entity: lesdoto without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lesdoto"
+ ]
+ ]
+ },
+ {
+ "input": "⪁",
+ "description": "Named entity: lesdoto; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a81"
+ ]
+ ]
+ },
+ {
+ "input": "&lesdotor",
+ "description": "Bad named entity: lesdotor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lesdotor"
+ ]
+ ]
+ },
+ {
+ "input": "⪃",
+ "description": "Named entity: lesdotor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a83"
+ ]
+ ]
+ },
+ {
+ "input": "&lesg",
+ "description": "Bad named entity: lesg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lesg"
+ ]
+ ]
+ },
+ {
+ "input": "⋚︀",
+ "description": "Named entity: lesg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22da\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&lesges",
+ "description": "Bad named entity: lesges without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lesges"
+ ]
+ ]
+ },
+ {
+ "input": "⪓",
+ "description": "Named entity: lesges; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a93"
+ ]
+ ]
+ },
+ {
+ "input": "&lessapprox",
+ "description": "Bad named entity: lessapprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lessapprox"
+ ]
+ ]
+ },
+ {
+ "input": "⪅",
+ "description": "Named entity: lessapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a85"
+ ]
+ ]
+ },
+ {
+ "input": "&lessdot",
+ "description": "Bad named entity: lessdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lessdot"
+ ]
+ ]
+ },
+ {
+ "input": "⋖",
+ "description": "Named entity: lessdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d6"
+ ]
+ ]
+ },
+ {
+ "input": "&lesseqgtr",
+ "description": "Bad named entity: lesseqgtr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lesseqgtr"
+ ]
+ ]
+ },
+ {
+ "input": "⋚",
+ "description": "Named entity: lesseqgtr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22da"
+ ]
+ ]
+ },
+ {
+ "input": "&lesseqqgtr",
+ "description": "Bad named entity: lesseqqgtr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lesseqqgtr"
+ ]
+ ]
+ },
+ {
+ "input": "⪋",
+ "description": "Named entity: lesseqqgtr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8b"
+ ]
+ ]
+ },
+ {
+ "input": "&lessgtr",
+ "description": "Bad named entity: lessgtr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lessgtr"
+ ]
+ ]
+ },
+ {
+ "input": "≶",
+ "description": "Named entity: lessgtr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2276"
+ ]
+ ]
+ },
+ {
+ "input": "&lesssim",
+ "description": "Bad named entity: lesssim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lesssim"
+ ]
+ ]
+ },
+ {
+ "input": "≲",
+ "description": "Named entity: lesssim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2272"
+ ]
+ ]
+ },
+ {
+ "input": "&lfisht",
+ "description": "Bad named entity: lfisht without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lfisht"
+ ]
+ ]
+ },
+ {
+ "input": "⥼",
+ "description": "Named entity: lfisht; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u297c"
+ ]
+ ]
+ },
+ {
+ "input": "&lfloor",
+ "description": "Bad named entity: lfloor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lfloor"
+ ]
+ ]
+ },
+ {
+ "input": "⌊",
+ "description": "Named entity: lfloor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u230a"
+ ]
+ ]
+ },
+ {
+ "input": "&lfr",
+ "description": "Bad named entity: lfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔩",
+ "description": "Named entity: lfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd29"
+ ]
+ ]
+ },
+ {
+ "input": "&lg",
+ "description": "Bad named entity: lg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lg"
+ ]
+ ]
+ },
+ {
+ "input": "≶",
+ "description": "Named entity: lg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2276"
+ ]
+ ]
+ },
+ {
+ "input": "&lgE",
+ "description": "Bad named entity: lgE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lgE"
+ ]
+ ]
+ },
+ {
+ "input": "⪑",
+ "description": "Named entity: lgE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a91"
+ ]
+ ]
+ },
+ {
+ "input": "&lhard",
+ "description": "Bad named entity: lhard without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lhard"
+ ]
+ ]
+ },
+ {
+ "input": "↽",
+ "description": "Named entity: lhard; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bd"
+ ]
+ ]
+ },
+ {
+ "input": "&lharu",
+ "description": "Bad named entity: lharu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lharu"
+ ]
+ ]
+ },
+ {
+ "input": "↼",
+ "description": "Named entity: lharu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bc"
+ ]
+ ]
+ },
+ {
+ "input": "&lharul",
+ "description": "Bad named entity: lharul without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lharul"
+ ]
+ ]
+ },
+ {
+ "input": "⥪",
+ "description": "Named entity: lharul; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u296a"
+ ]
+ ]
+ },
+ {
+ "input": "&lhblk",
+ "description": "Bad named entity: lhblk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lhblk"
+ ]
+ ]
+ },
+ {
+ "input": "▄",
+ "description": "Named entity: lhblk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2584"
+ ]
+ ]
+ },
+ {
+ "input": "&ljcy",
+ "description": "Bad named entity: ljcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ljcy"
+ ]
+ ]
+ },
+ {
+ "input": "љ",
+ "description": "Named entity: ljcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0459"
+ ]
+ ]
+ },
+ {
+ "input": "&ll",
+ "description": "Bad named entity: ll without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ll"
+ ]
+ ]
+ },
+ {
+ "input": "≪",
+ "description": "Named entity: ll; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226a"
+ ]
+ ]
+ },
+ {
+ "input": "&llarr",
+ "description": "Bad named entity: llarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&llarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇇",
+ "description": "Named entity: llarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c7"
+ ]
+ ]
+ },
+ {
+ "input": "&llcorner",
+ "description": "Bad named entity: llcorner without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&llcorner"
+ ]
+ ]
+ },
+ {
+ "input": "⌞",
+ "description": "Named entity: llcorner; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u231e"
+ ]
+ ]
+ },
+ {
+ "input": "&llhard",
+ "description": "Bad named entity: llhard without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&llhard"
+ ]
+ ]
+ },
+ {
+ "input": "⥫",
+ "description": "Named entity: llhard; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u296b"
+ ]
+ ]
+ },
+ {
+ "input": "&lltri",
+ "description": "Bad named entity: lltri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lltri"
+ ]
+ ]
+ },
+ {
+ "input": "◺",
+ "description": "Named entity: lltri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25fa"
+ ]
+ ]
+ },
+ {
+ "input": "&lmidot",
+ "description": "Bad named entity: lmidot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lmidot"
+ ]
+ ]
+ },
+ {
+ "input": "ŀ",
+ "description": "Named entity: lmidot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0140"
+ ]
+ ]
+ },
+ {
+ "input": "&lmoust",
+ "description": "Bad named entity: lmoust without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lmoust"
+ ]
+ ]
+ },
+ {
+ "input": "⎰",
+ "description": "Named entity: lmoust; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b0"
+ ]
+ ]
+ },
+ {
+ "input": "&lmoustache",
+ "description": "Bad named entity: lmoustache without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lmoustache"
+ ]
+ ]
+ },
+ {
+ "input": "⎰",
+ "description": "Named entity: lmoustache; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b0"
+ ]
+ ]
+ },
+ {
+ "input": "&lnE",
+ "description": "Bad named entity: lnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lnE"
+ ]
+ ]
+ },
+ {
+ "input": "≨",
+ "description": "Named entity: lnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2268"
+ ]
+ ]
+ },
+ {
+ "input": "&lnap",
+ "description": "Bad named entity: lnap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lnap"
+ ]
+ ]
+ },
+ {
+ "input": "⪉",
+ "description": "Named entity: lnap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a89"
+ ]
+ ]
+ },
+ {
+ "input": "&lnapprox",
+ "description": "Bad named entity: lnapprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lnapprox"
+ ]
+ ]
+ },
+ {
+ "input": "⪉",
+ "description": "Named entity: lnapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a89"
+ ]
+ ]
+ },
+ {
+ "input": "&lne",
+ "description": "Bad named entity: lne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lne"
+ ]
+ ]
+ },
+ {
+ "input": "⪇",
+ "description": "Named entity: lne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a87"
+ ]
+ ]
+ },
+ {
+ "input": "&lneq",
+ "description": "Bad named entity: lneq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lneq"
+ ]
+ ]
+ },
+ {
+ "input": "⪇",
+ "description": "Named entity: lneq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a87"
+ ]
+ ]
+ },
+ {
+ "input": "&lneqq",
+ "description": "Bad named entity: lneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lneqq"
+ ]
+ ]
+ },
+ {
+ "input": "≨",
+ "description": "Named entity: lneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2268"
+ ]
+ ]
+ },
+ {
+ "input": "&lnsim",
+ "description": "Bad named entity: lnsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lnsim"
+ ]
+ ]
+ },
+ {
+ "input": "⋦",
+ "description": "Named entity: lnsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e6"
+ ]
+ ]
+ },
+ {
+ "input": "&loang",
+ "description": "Bad named entity: loang without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&loang"
+ ]
+ ]
+ },
+ {
+ "input": "⟬",
+ "description": "Named entity: loang; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27ec"
+ ]
+ ]
+ },
+ {
+ "input": "&loarr",
+ "description": "Bad named entity: loarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&loarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇽",
+ "description": "Named entity: loarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21fd"
+ ]
+ ]
+ },
+ {
+ "input": "&lobrk",
+ "description": "Bad named entity: lobrk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lobrk"
+ ]
+ ]
+ },
+ {
+ "input": "⟦",
+ "description": "Named entity: lobrk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e6"
+ ]
+ ]
+ },
+ {
+ "input": "&longleftarrow",
+ "description": "Bad named entity: longleftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&longleftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟵",
+ "description": "Named entity: longleftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f5"
+ ]
+ ]
+ },
+ {
+ "input": "&longleftrightarrow",
+ "description": "Bad named entity: longleftrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&longleftrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟷",
+ "description": "Named entity: longleftrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f7"
+ ]
+ ]
+ },
+ {
+ "input": "&longmapsto",
+ "description": "Bad named entity: longmapsto without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&longmapsto"
+ ]
+ ]
+ },
+ {
+ "input": "⟼",
+ "description": "Named entity: longmapsto; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27fc"
+ ]
+ ]
+ },
+ {
+ "input": "&longrightarrow",
+ "description": "Bad named entity: longrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&longrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⟶",
+ "description": "Named entity: longrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f6"
+ ]
+ ]
+ },
+ {
+ "input": "&looparrowleft",
+ "description": "Bad named entity: looparrowleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&looparrowleft"
+ ]
+ ]
+ },
+ {
+ "input": "↫",
+ "description": "Named entity: looparrowleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ab"
+ ]
+ ]
+ },
+ {
+ "input": "&looparrowright",
+ "description": "Bad named entity: looparrowright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&looparrowright"
+ ]
+ ]
+ },
+ {
+ "input": "↬",
+ "description": "Named entity: looparrowright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ac"
+ ]
+ ]
+ },
+ {
+ "input": "&lopar",
+ "description": "Bad named entity: lopar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lopar"
+ ]
+ ]
+ },
+ {
+ "input": "⦅",
+ "description": "Named entity: lopar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2985"
+ ]
+ ]
+ },
+ {
+ "input": "&lopf",
+ "description": "Bad named entity: lopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕝",
+ "description": "Named entity: lopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd5d"
+ ]
+ ]
+ },
+ {
+ "input": "&loplus",
+ "description": "Bad named entity: loplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&loplus"
+ ]
+ ]
+ },
+ {
+ "input": "⨭",
+ "description": "Named entity: loplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a2d"
+ ]
+ ]
+ },
+ {
+ "input": "&lotimes",
+ "description": "Bad named entity: lotimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lotimes"
+ ]
+ ]
+ },
+ {
+ "input": "⨴",
+ "description": "Named entity: lotimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a34"
+ ]
+ ]
+ },
+ {
+ "input": "&lowast",
+ "description": "Bad named entity: lowast without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lowast"
+ ]
+ ]
+ },
+ {
+ "input": "∗",
+ "description": "Named entity: lowast; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2217"
+ ]
+ ]
+ },
+ {
+ "input": "&lowbar",
+ "description": "Bad named entity: lowbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lowbar"
+ ]
+ ]
+ },
+ {
+ "input": "_",
+ "description": "Named entity: lowbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "_"
+ ]
+ ]
+ },
+ {
+ "input": "&loz",
+ "description": "Bad named entity: loz without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&loz"
+ ]
+ ]
+ },
+ {
+ "input": "◊",
+ "description": "Named entity: loz; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25ca"
+ ]
+ ]
+ },
+ {
+ "input": "&lozenge",
+ "description": "Bad named entity: lozenge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lozenge"
+ ]
+ ]
+ },
+ {
+ "input": "◊",
+ "description": "Named entity: lozenge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25ca"
+ ]
+ ]
+ },
+ {
+ "input": "&lozf",
+ "description": "Bad named entity: lozf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lozf"
+ ]
+ ]
+ },
+ {
+ "input": "⧫",
+ "description": "Named entity: lozf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29eb"
+ ]
+ ]
+ },
+ {
+ "input": "&lpar",
+ "description": "Bad named entity: lpar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lpar"
+ ]
+ ]
+ },
+ {
+ "input": "(",
+ "description": "Named entity: lpar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "("
+ ]
+ ]
+ },
+ {
+ "input": "&lparlt",
+ "description": "Bad named entity: lparlt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lparlt"
+ ]
+ ]
+ },
+ {
+ "input": "⦓",
+ "description": "Named entity: lparlt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2993"
+ ]
+ ]
+ },
+ {
+ "input": "&lrarr",
+ "description": "Bad named entity: lrarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lrarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇆",
+ "description": "Named entity: lrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c6"
+ ]
+ ]
+ },
+ {
+ "input": "&lrcorner",
+ "description": "Bad named entity: lrcorner without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lrcorner"
+ ]
+ ]
+ },
+ {
+ "input": "⌟",
+ "description": "Named entity: lrcorner; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u231f"
+ ]
+ ]
+ },
+ {
+ "input": "&lrhar",
+ "description": "Bad named entity: lrhar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lrhar"
+ ]
+ ]
+ },
+ {
+ "input": "⇋",
+ "description": "Named entity: lrhar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cb"
+ ]
+ ]
+ },
+ {
+ "input": "&lrhard",
+ "description": "Bad named entity: lrhard without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lrhard"
+ ]
+ ]
+ },
+ {
+ "input": "⥭",
+ "description": "Named entity: lrhard; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u296d"
+ ]
+ ]
+ },
+ {
+ "input": "&lrm",
+ "description": "Bad named entity: lrm without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lrm"
+ ]
+ ]
+ },
+ {
+ "input": "‎",
+ "description": "Named entity: lrm; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200e"
+ ]
+ ]
+ },
+ {
+ "input": "&lrtri",
+ "description": "Bad named entity: lrtri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lrtri"
+ ]
+ ]
+ },
+ {
+ "input": "⊿",
+ "description": "Named entity: lrtri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22bf"
+ ]
+ ]
+ },
+ {
+ "input": "&lsaquo",
+ "description": "Bad named entity: lsaquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lsaquo"
+ ]
+ ]
+ },
+ {
+ "input": "‹",
+ "description": "Named entity: lsaquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2039"
+ ]
+ ]
+ },
+ {
+ "input": "&lscr",
+ "description": "Bad named entity: lscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓁",
+ "description": "Named entity: lscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc1"
+ ]
+ ]
+ },
+ {
+ "input": "&lsh",
+ "description": "Bad named entity: lsh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lsh"
+ ]
+ ]
+ },
+ {
+ "input": "↰",
+ "description": "Named entity: lsh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b0"
+ ]
+ ]
+ },
+ {
+ "input": "&lsim",
+ "description": "Bad named entity: lsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lsim"
+ ]
+ ]
+ },
+ {
+ "input": "≲",
+ "description": "Named entity: lsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2272"
+ ]
+ ]
+ },
+ {
+ "input": "&lsime",
+ "description": "Bad named entity: lsime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lsime"
+ ]
+ ]
+ },
+ {
+ "input": "⪍",
+ "description": "Named entity: lsime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8d"
+ ]
+ ]
+ },
+ {
+ "input": "&lsimg",
+ "description": "Bad named entity: lsimg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lsimg"
+ ]
+ ]
+ },
+ {
+ "input": "⪏",
+ "description": "Named entity: lsimg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a8f"
+ ]
+ ]
+ },
+ {
+ "input": "&lsqb",
+ "description": "Bad named entity: lsqb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lsqb"
+ ]
+ ]
+ },
+ {
+ "input": "[",
+ "description": "Named entity: lsqb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "["
+ ]
+ ]
+ },
+ {
+ "input": "&lsquo",
+ "description": "Bad named entity: lsquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lsquo"
+ ]
+ ]
+ },
+ {
+ "input": "‘",
+ "description": "Named entity: lsquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2018"
+ ]
+ ]
+ },
+ {
+ "input": "&lsquor",
+ "description": "Bad named entity: lsquor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lsquor"
+ ]
+ ]
+ },
+ {
+ "input": "‚",
+ "description": "Named entity: lsquor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201a"
+ ]
+ ]
+ },
+ {
+ "input": "&lstrok",
+ "description": "Bad named entity: lstrok without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lstrok"
+ ]
+ ]
+ },
+ {
+ "input": "ł",
+ "description": "Named entity: lstrok; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0142"
+ ]
+ ]
+ },
+ {
+ "input": "<",
+ "description": "Named entity: lt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "<"
+ ]
+ ]
+ },
+ {
+ "input": "<",
+ "description": "Named entity: lt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "<"
+ ]
+ ]
+ },
+ {
+ "input": "⪦",
+ "description": "Named entity: ltcc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa6"
+ ]
+ ]
+ },
+ {
+ "input": "⩹",
+ "description": "Named entity: ltcir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a79"
+ ]
+ ]
+ },
+ {
+ "input": "⋖",
+ "description": "Named entity: ltdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d6"
+ ]
+ ]
+ },
+ {
+ "input": "⋋",
+ "description": "Named entity: lthree; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22cb"
+ ]
+ ]
+ },
+ {
+ "input": "⋉",
+ "description": "Named entity: ltimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c9"
+ ]
+ ]
+ },
+ {
+ "input": "⥶",
+ "description": "Named entity: ltlarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2976"
+ ]
+ ]
+ },
+ {
+ "input": "⩻",
+ "description": "Named entity: ltquest; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7b"
+ ]
+ ]
+ },
+ {
+ "input": "⦖",
+ "description": "Named entity: ltrPar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2996"
+ ]
+ ]
+ },
+ {
+ "input": "◃",
+ "description": "Named entity: ltri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25c3"
+ ]
+ ]
+ },
+ {
+ "input": "⊴",
+ "description": "Named entity: ltrie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b4"
+ ]
+ ]
+ },
+ {
+ "input": "◂",
+ "description": "Named entity: ltrif; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25c2"
+ ]
+ ]
+ },
+ {
+ "input": "&lurdshar",
+ "description": "Bad named entity: lurdshar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lurdshar"
+ ]
+ ]
+ },
+ {
+ "input": "⥊",
+ "description": "Named entity: lurdshar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u294a"
+ ]
+ ]
+ },
+ {
+ "input": "&luruhar",
+ "description": "Bad named entity: luruhar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&luruhar"
+ ]
+ ]
+ },
+ {
+ "input": "⥦",
+ "description": "Named entity: luruhar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2966"
+ ]
+ ]
+ },
+ {
+ "input": "&lvertneqq",
+ "description": "Bad named entity: lvertneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lvertneqq"
+ ]
+ ]
+ },
+ {
+ "input": "≨︀",
+ "description": "Named entity: lvertneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2268\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&lvnE",
+ "description": "Bad named entity: lvnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&lvnE"
+ ]
+ ]
+ },
+ {
+ "input": "≨︀",
+ "description": "Named entity: lvnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2268\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&mDDot",
+ "description": "Bad named entity: mDDot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mDDot"
+ ]
+ ]
+ },
+ {
+ "input": "∺",
+ "description": "Named entity: mDDot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223a"
+ ]
+ ]
+ },
+ {
+ "input": "¯",
+ "description": "Named entity: macr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00af"
+ ]
+ ]
+ },
+ {
+ "input": "¯",
+ "description": "Named entity: macr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00af"
+ ]
+ ]
+ },
+ {
+ "input": "&male",
+ "description": "Bad named entity: male without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&male"
+ ]
+ ]
+ },
+ {
+ "input": "♂",
+ "description": "Named entity: male; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2642"
+ ]
+ ]
+ },
+ {
+ "input": "&malt",
+ "description": "Bad named entity: malt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&malt"
+ ]
+ ]
+ },
+ {
+ "input": "✠",
+ "description": "Named entity: malt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2720"
+ ]
+ ]
+ },
+ {
+ "input": "&maltese",
+ "description": "Bad named entity: maltese without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&maltese"
+ ]
+ ]
+ },
+ {
+ "input": "✠",
+ "description": "Named entity: maltese; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2720"
+ ]
+ ]
+ },
+ {
+ "input": "&map",
+ "description": "Bad named entity: map without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&map"
+ ]
+ ]
+ },
+ {
+ "input": "↦",
+ "description": "Named entity: map; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a6"
+ ]
+ ]
+ },
+ {
+ "input": "&mapsto",
+ "description": "Bad named entity: mapsto without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mapsto"
+ ]
+ ]
+ },
+ {
+ "input": "↦",
+ "description": "Named entity: mapsto; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a6"
+ ]
+ ]
+ },
+ {
+ "input": "&mapstodown",
+ "description": "Bad named entity: mapstodown without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mapstodown"
+ ]
+ ]
+ },
+ {
+ "input": "↧",
+ "description": "Named entity: mapstodown; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a7"
+ ]
+ ]
+ },
+ {
+ "input": "&mapstoleft",
+ "description": "Bad named entity: mapstoleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mapstoleft"
+ ]
+ ]
+ },
+ {
+ "input": "↤",
+ "description": "Named entity: mapstoleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a4"
+ ]
+ ]
+ },
+ {
+ "input": "&mapstoup",
+ "description": "Bad named entity: mapstoup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mapstoup"
+ ]
+ ]
+ },
+ {
+ "input": "↥",
+ "description": "Named entity: mapstoup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a5"
+ ]
+ ]
+ },
+ {
+ "input": "&marker",
+ "description": "Bad named entity: marker without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&marker"
+ ]
+ ]
+ },
+ {
+ "input": "▮",
+ "description": "Named entity: marker; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25ae"
+ ]
+ ]
+ },
+ {
+ "input": "&mcomma",
+ "description": "Bad named entity: mcomma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mcomma"
+ ]
+ ]
+ },
+ {
+ "input": "⨩",
+ "description": "Named entity: mcomma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a29"
+ ]
+ ]
+ },
+ {
+ "input": "&mcy",
+ "description": "Bad named entity: mcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mcy"
+ ]
+ ]
+ },
+ {
+ "input": "м",
+ "description": "Named entity: mcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u043c"
+ ]
+ ]
+ },
+ {
+ "input": "&mdash",
+ "description": "Bad named entity: mdash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mdash"
+ ]
+ ]
+ },
+ {
+ "input": "—",
+ "description": "Named entity: mdash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2014"
+ ]
+ ]
+ },
+ {
+ "input": "&measuredangle",
+ "description": "Bad named entity: measuredangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&measuredangle"
+ ]
+ ]
+ },
+ {
+ "input": "∡",
+ "description": "Named entity: measuredangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2221"
+ ]
+ ]
+ },
+ {
+ "input": "&mfr",
+ "description": "Bad named entity: mfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔪",
+ "description": "Named entity: mfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd2a"
+ ]
+ ]
+ },
+ {
+ "input": "&mho",
+ "description": "Bad named entity: mho without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mho"
+ ]
+ ]
+ },
+ {
+ "input": "℧",
+ "description": "Named entity: mho; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2127"
+ ]
+ ]
+ },
+ {
+ "input": "µ",
+ "description": "Named entity: micro without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b5"
+ ]
+ ]
+ },
+ {
+ "input": "µ",
+ "description": "Named entity: micro; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b5"
+ ]
+ ]
+ },
+ {
+ "input": "&mid",
+ "description": "Bad named entity: mid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mid"
+ ]
+ ]
+ },
+ {
+ "input": "∣",
+ "description": "Named entity: mid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2223"
+ ]
+ ]
+ },
+ {
+ "input": "&midast",
+ "description": "Bad named entity: midast without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&midast"
+ ]
+ ]
+ },
+ {
+ "input": "*",
+ "description": "Named entity: midast; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "*"
+ ]
+ ]
+ },
+ {
+ "input": "&midcir",
+ "description": "Bad named entity: midcir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&midcir"
+ ]
+ ]
+ },
+ {
+ "input": "⫰",
+ "description": "Named entity: midcir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2af0"
+ ]
+ ]
+ },
+ {
+ "input": "·",
+ "description": "Named entity: middot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b7"
+ ]
+ ]
+ },
+ {
+ "input": "·",
+ "description": "Named entity: middot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b7"
+ ]
+ ]
+ },
+ {
+ "input": "&minus",
+ "description": "Bad named entity: minus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&minus"
+ ]
+ ]
+ },
+ {
+ "input": "−",
+ "description": "Named entity: minus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2212"
+ ]
+ ]
+ },
+ {
+ "input": "&minusb",
+ "description": "Bad named entity: minusb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&minusb"
+ ]
+ ]
+ },
+ {
+ "input": "⊟",
+ "description": "Named entity: minusb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229f"
+ ]
+ ]
+ },
+ {
+ "input": "&minusd",
+ "description": "Bad named entity: minusd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&minusd"
+ ]
+ ]
+ },
+ {
+ "input": "∸",
+ "description": "Named entity: minusd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2238"
+ ]
+ ]
+ },
+ {
+ "input": "&minusdu",
+ "description": "Bad named entity: minusdu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&minusdu"
+ ]
+ ]
+ },
+ {
+ "input": "⨪",
+ "description": "Named entity: minusdu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a2a"
+ ]
+ ]
+ },
+ {
+ "input": "&mlcp",
+ "description": "Bad named entity: mlcp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mlcp"
+ ]
+ ]
+ },
+ {
+ "input": "⫛",
+ "description": "Named entity: mlcp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2adb"
+ ]
+ ]
+ },
+ {
+ "input": "&mldr",
+ "description": "Bad named entity: mldr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mldr"
+ ]
+ ]
+ },
+ {
+ "input": "…",
+ "description": "Named entity: mldr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2026"
+ ]
+ ]
+ },
+ {
+ "input": "&mnplus",
+ "description": "Bad named entity: mnplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mnplus"
+ ]
+ ]
+ },
+ {
+ "input": "∓",
+ "description": "Named entity: mnplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2213"
+ ]
+ ]
+ },
+ {
+ "input": "&models",
+ "description": "Bad named entity: models without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&models"
+ ]
+ ]
+ },
+ {
+ "input": "⊧",
+ "description": "Named entity: models; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a7"
+ ]
+ ]
+ },
+ {
+ "input": "&mopf",
+ "description": "Bad named entity: mopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕞",
+ "description": "Named entity: mopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd5e"
+ ]
+ ]
+ },
+ {
+ "input": "&mp",
+ "description": "Bad named entity: mp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mp"
+ ]
+ ]
+ },
+ {
+ "input": "∓",
+ "description": "Named entity: mp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2213"
+ ]
+ ]
+ },
+ {
+ "input": "&mscr",
+ "description": "Bad named entity: mscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓂",
+ "description": "Named entity: mscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc2"
+ ]
+ ]
+ },
+ {
+ "input": "&mstpos",
+ "description": "Bad named entity: mstpos without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mstpos"
+ ]
+ ]
+ },
+ {
+ "input": "∾",
+ "description": "Named entity: mstpos; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223e"
+ ]
+ ]
+ },
+ {
+ "input": "&mu",
+ "description": "Bad named entity: mu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mu"
+ ]
+ ]
+ },
+ {
+ "input": "μ",
+ "description": "Named entity: mu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03bc"
+ ]
+ ]
+ },
+ {
+ "input": "&multimap",
+ "description": "Bad named entity: multimap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&multimap"
+ ]
+ ]
+ },
+ {
+ "input": "⊸",
+ "description": "Named entity: multimap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b8"
+ ]
+ ]
+ },
+ {
+ "input": "&mumap",
+ "description": "Bad named entity: mumap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&mumap"
+ ]
+ ]
+ },
+ {
+ "input": "⊸",
+ "description": "Named entity: mumap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b8"
+ ]
+ ]
+ },
+ {
+ "input": "&nGg",
+ "description": "Bad named entity: nGg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nGg"
+ ]
+ ]
+ },
+ {
+ "input": "⋙̸",
+ "description": "Named entity: nGg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d9\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nGt",
+ "description": "Bad named entity: nGt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nGt"
+ ]
+ ]
+ },
+ {
+ "input": "≫⃒",
+ "description": "Named entity: nGt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226b\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nGtv",
+ "description": "Bad named entity: nGtv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nGtv"
+ ]
+ ]
+ },
+ {
+ "input": "≫̸",
+ "description": "Named entity: nGtv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226b\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nLeftarrow",
+ "description": "Bad named entity: nLeftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nLeftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇍",
+ "description": "Named entity: nLeftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cd"
+ ]
+ ]
+ },
+ {
+ "input": "&nLeftrightarrow",
+ "description": "Bad named entity: nLeftrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nLeftrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇎",
+ "description": "Named entity: nLeftrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ce"
+ ]
+ ]
+ },
+ {
+ "input": "&nLl",
+ "description": "Bad named entity: nLl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nLl"
+ ]
+ ]
+ },
+ {
+ "input": "⋘̸",
+ "description": "Named entity: nLl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d8\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nLt",
+ "description": "Bad named entity: nLt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nLt"
+ ]
+ ]
+ },
+ {
+ "input": "≪⃒",
+ "description": "Named entity: nLt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226a\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nLtv",
+ "description": "Bad named entity: nLtv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nLtv"
+ ]
+ ]
+ },
+ {
+ "input": "≪̸",
+ "description": "Named entity: nLtv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226a\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nRightarrow",
+ "description": "Bad named entity: nRightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nRightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "⇏",
+ "description": "Named entity: nRightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cf"
+ ]
+ ]
+ },
+ {
+ "input": "&nVDash",
+ "description": "Bad named entity: nVDash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nVDash"
+ ]
+ ]
+ },
+ {
+ "input": "⊯",
+ "description": "Named entity: nVDash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22af"
+ ]
+ ]
+ },
+ {
+ "input": "&nVdash",
+ "description": "Bad named entity: nVdash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nVdash"
+ ]
+ ]
+ },
+ {
+ "input": "⊮",
+ "description": "Named entity: nVdash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ae"
+ ]
+ ]
+ },
+ {
+ "input": "&nabla",
+ "description": "Bad named entity: nabla without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nabla"
+ ]
+ ]
+ },
+ {
+ "input": "∇",
+ "description": "Named entity: nabla; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2207"
+ ]
+ ]
+ },
+ {
+ "input": "&nacute",
+ "description": "Bad named entity: nacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nacute"
+ ]
+ ]
+ },
+ {
+ "input": "ń",
+ "description": "Named entity: nacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0144"
+ ]
+ ]
+ },
+ {
+ "input": "&nang",
+ "description": "Bad named entity: nang without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nang"
+ ]
+ ]
+ },
+ {
+ "input": "∠⃒",
+ "description": "Named entity: nang; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2220\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nap",
+ "description": "Bad named entity: nap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nap"
+ ]
+ ]
+ },
+ {
+ "input": "≉",
+ "description": "Named entity: nap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2249"
+ ]
+ ]
+ },
+ {
+ "input": "&napE",
+ "description": "Bad named entity: napE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&napE"
+ ]
+ ]
+ },
+ {
+ "input": "⩰̸",
+ "description": "Named entity: napE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a70\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&napid",
+ "description": "Bad named entity: napid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&napid"
+ ]
+ ]
+ },
+ {
+ "input": "≋̸",
+ "description": "Named entity: napid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224b\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&napos",
+ "description": "Bad named entity: napos without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&napos"
+ ]
+ ]
+ },
+ {
+ "input": "ʼn",
+ "description": "Named entity: napos; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0149"
+ ]
+ ]
+ },
+ {
+ "input": "&napprox",
+ "description": "Bad named entity: napprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&napprox"
+ ]
+ ]
+ },
+ {
+ "input": "≉",
+ "description": "Named entity: napprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2249"
+ ]
+ ]
+ },
+ {
+ "input": "&natur",
+ "description": "Bad named entity: natur without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&natur"
+ ]
+ ]
+ },
+ {
+ "input": "♮",
+ "description": "Named entity: natur; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u266e"
+ ]
+ ]
+ },
+ {
+ "input": "&natural",
+ "description": "Bad named entity: natural without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&natural"
+ ]
+ ]
+ },
+ {
+ "input": "♮",
+ "description": "Named entity: natural; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u266e"
+ ]
+ ]
+ },
+ {
+ "input": "&naturals",
+ "description": "Bad named entity: naturals without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&naturals"
+ ]
+ ]
+ },
+ {
+ "input": "ℕ",
+ "description": "Named entity: naturals; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2115"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: nbsp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a0"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: nbsp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a0"
+ ]
+ ]
+ },
+ {
+ "input": "&nbump",
+ "description": "Bad named entity: nbump without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nbump"
+ ]
+ ]
+ },
+ {
+ "input": "≎̸",
+ "description": "Named entity: nbump; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224e\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nbumpe",
+ "description": "Bad named entity: nbumpe without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nbumpe"
+ ]
+ ]
+ },
+ {
+ "input": "≏̸",
+ "description": "Named entity: nbumpe; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224f\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&ncap",
+ "description": "Bad named entity: ncap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ncap"
+ ]
+ ]
+ },
+ {
+ "input": "⩃",
+ "description": "Named entity: ncap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a43"
+ ]
+ ]
+ },
+ {
+ "input": "&ncaron",
+ "description": "Bad named entity: ncaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ncaron"
+ ]
+ ]
+ },
+ {
+ "input": "ň",
+ "description": "Named entity: ncaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0148"
+ ]
+ ]
+ },
+ {
+ "input": "&ncedil",
+ "description": "Bad named entity: ncedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ncedil"
+ ]
+ ]
+ },
+ {
+ "input": "ņ",
+ "description": "Named entity: ncedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0146"
+ ]
+ ]
+ },
+ {
+ "input": "&ncong",
+ "description": "Bad named entity: ncong without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ncong"
+ ]
+ ]
+ },
+ {
+ "input": "≇",
+ "description": "Named entity: ncong; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2247"
+ ]
+ ]
+ },
+ {
+ "input": "&ncongdot",
+ "description": "Bad named entity: ncongdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ncongdot"
+ ]
+ ]
+ },
+ {
+ "input": "⩭̸",
+ "description": "Named entity: ncongdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a6d\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&ncup",
+ "description": "Bad named entity: ncup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ncup"
+ ]
+ ]
+ },
+ {
+ "input": "⩂",
+ "description": "Named entity: ncup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a42"
+ ]
+ ]
+ },
+ {
+ "input": "&ncy",
+ "description": "Bad named entity: ncy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ncy"
+ ]
+ ]
+ },
+ {
+ "input": "н",
+ "description": "Named entity: ncy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u043d"
+ ]
+ ]
+ },
+ {
+ "input": "&ndash",
+ "description": "Bad named entity: ndash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ndash"
+ ]
+ ]
+ },
+ {
+ "input": "–",
+ "description": "Named entity: ndash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2013"
+ ]
+ ]
+ },
+ {
+ "input": "&ne",
+ "description": "Bad named entity: ne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ne"
+ ]
+ ]
+ },
+ {
+ "input": "≠",
+ "description": "Named entity: ne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2260"
+ ]
+ ]
+ },
+ {
+ "input": "&neArr",
+ "description": "Bad named entity: neArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&neArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇗",
+ "description": "Named entity: neArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d7"
+ ]
+ ]
+ },
+ {
+ "input": "&nearhk",
+ "description": "Bad named entity: nearhk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nearhk"
+ ]
+ ]
+ },
+ {
+ "input": "⤤",
+ "description": "Named entity: nearhk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2924"
+ ]
+ ]
+ },
+ {
+ "input": "&nearr",
+ "description": "Bad named entity: nearr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nearr"
+ ]
+ ]
+ },
+ {
+ "input": "↗",
+ "description": "Named entity: nearr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2197"
+ ]
+ ]
+ },
+ {
+ "input": "&nearrow",
+ "description": "Bad named entity: nearrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nearrow"
+ ]
+ ]
+ },
+ {
+ "input": "↗",
+ "description": "Named entity: nearrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2197"
+ ]
+ ]
+ },
+ {
+ "input": "&nedot",
+ "description": "Bad named entity: nedot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nedot"
+ ]
+ ]
+ },
+ {
+ "input": "≐̸",
+ "description": "Named entity: nedot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2250\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nequiv",
+ "description": "Bad named entity: nequiv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nequiv"
+ ]
+ ]
+ },
+ {
+ "input": "≢",
+ "description": "Named entity: nequiv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2262"
+ ]
+ ]
+ },
+ {
+ "input": "&nesear",
+ "description": "Bad named entity: nesear without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nesear"
+ ]
+ ]
+ },
+ {
+ "input": "⤨",
+ "description": "Named entity: nesear; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2928"
+ ]
+ ]
+ },
+ {
+ "input": "&nesim",
+ "description": "Bad named entity: nesim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nesim"
+ ]
+ ]
+ },
+ {
+ "input": "≂̸",
+ "description": "Named entity: nesim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2242\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nexist",
+ "description": "Bad named entity: nexist without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nexist"
+ ]
+ ]
+ },
+ {
+ "input": "∄",
+ "description": "Named entity: nexist; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2204"
+ ]
+ ]
+ },
+ {
+ "input": "&nexists",
+ "description": "Bad named entity: nexists without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nexists"
+ ]
+ ]
+ },
+ {
+ "input": "∄",
+ "description": "Named entity: nexists; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2204"
+ ]
+ ]
+ },
+ {
+ "input": "&nfr",
+ "description": "Bad named entity: nfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔫",
+ "description": "Named entity: nfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd2b"
+ ]
+ ]
+ },
+ {
+ "input": "&ngE",
+ "description": "Bad named entity: ngE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ngE"
+ ]
+ ]
+ },
+ {
+ "input": "≧̸",
+ "description": "Named entity: ngE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2267\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nge",
+ "description": "Bad named entity: nge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nge"
+ ]
+ ]
+ },
+ {
+ "input": "≱",
+ "description": "Named entity: nge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2271"
+ ]
+ ]
+ },
+ {
+ "input": "&ngeq",
+ "description": "Bad named entity: ngeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ngeq"
+ ]
+ ]
+ },
+ {
+ "input": "≱",
+ "description": "Named entity: ngeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2271"
+ ]
+ ]
+ },
+ {
+ "input": "&ngeqq",
+ "description": "Bad named entity: ngeqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ngeqq"
+ ]
+ ]
+ },
+ {
+ "input": "≧̸",
+ "description": "Named entity: ngeqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2267\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&ngeqslant",
+ "description": "Bad named entity: ngeqslant without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ngeqslant"
+ ]
+ ]
+ },
+ {
+ "input": "⩾̸",
+ "description": "Named entity: ngeqslant; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7e\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nges",
+ "description": "Bad named entity: nges without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nges"
+ ]
+ ]
+ },
+ {
+ "input": "⩾̸",
+ "description": "Named entity: nges; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7e\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&ngsim",
+ "description": "Bad named entity: ngsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ngsim"
+ ]
+ ]
+ },
+ {
+ "input": "≵",
+ "description": "Named entity: ngsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2275"
+ ]
+ ]
+ },
+ {
+ "input": "&ngt",
+ "description": "Bad named entity: ngt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ngt"
+ ]
+ ]
+ },
+ {
+ "input": "≯",
+ "description": "Named entity: ngt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226f"
+ ]
+ ]
+ },
+ {
+ "input": "&ngtr",
+ "description": "Bad named entity: ngtr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ngtr"
+ ]
+ ]
+ },
+ {
+ "input": "≯",
+ "description": "Named entity: ngtr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226f"
+ ]
+ ]
+ },
+ {
+ "input": "&nhArr",
+ "description": "Bad named entity: nhArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nhArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇎",
+ "description": "Named entity: nhArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ce"
+ ]
+ ]
+ },
+ {
+ "input": "&nharr",
+ "description": "Bad named entity: nharr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nharr"
+ ]
+ ]
+ },
+ {
+ "input": "↮",
+ "description": "Named entity: nharr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ae"
+ ]
+ ]
+ },
+ {
+ "input": "&nhpar",
+ "description": "Bad named entity: nhpar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nhpar"
+ ]
+ ]
+ },
+ {
+ "input": "⫲",
+ "description": "Named entity: nhpar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2af2"
+ ]
+ ]
+ },
+ {
+ "input": "&ni",
+ "description": "Bad named entity: ni without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ni"
+ ]
+ ]
+ },
+ {
+ "input": "∋",
+ "description": "Named entity: ni; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220b"
+ ]
+ ]
+ },
+ {
+ "input": "&nis",
+ "description": "Bad named entity: nis without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nis"
+ ]
+ ]
+ },
+ {
+ "input": "⋼",
+ "description": "Named entity: nis; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22fc"
+ ]
+ ]
+ },
+ {
+ "input": "&nisd",
+ "description": "Bad named entity: nisd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nisd"
+ ]
+ ]
+ },
+ {
+ "input": "⋺",
+ "description": "Named entity: nisd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22fa"
+ ]
+ ]
+ },
+ {
+ "input": "&niv",
+ "description": "Bad named entity: niv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&niv"
+ ]
+ ]
+ },
+ {
+ "input": "∋",
+ "description": "Named entity: niv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220b"
+ ]
+ ]
+ },
+ {
+ "input": "&njcy",
+ "description": "Bad named entity: njcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&njcy"
+ ]
+ ]
+ },
+ {
+ "input": "њ",
+ "description": "Named entity: njcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u045a"
+ ]
+ ]
+ },
+ {
+ "input": "&nlArr",
+ "description": "Bad named entity: nlArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nlArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇍",
+ "description": "Named entity: nlArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cd"
+ ]
+ ]
+ },
+ {
+ "input": "&nlE",
+ "description": "Bad named entity: nlE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nlE"
+ ]
+ ]
+ },
+ {
+ "input": "≦̸",
+ "description": "Named entity: nlE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2266\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nlarr",
+ "description": "Bad named entity: nlarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nlarr"
+ ]
+ ]
+ },
+ {
+ "input": "↚",
+ "description": "Named entity: nlarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219a"
+ ]
+ ]
+ },
+ {
+ "input": "&nldr",
+ "description": "Bad named entity: nldr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nldr"
+ ]
+ ]
+ },
+ {
+ "input": "‥",
+ "description": "Named entity: nldr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2025"
+ ]
+ ]
+ },
+ {
+ "input": "&nle",
+ "description": "Bad named entity: nle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nle"
+ ]
+ ]
+ },
+ {
+ "input": "≰",
+ "description": "Named entity: nle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2270"
+ ]
+ ]
+ },
+ {
+ "input": "&nleftarrow",
+ "description": "Bad named entity: nleftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nleftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↚",
+ "description": "Named entity: nleftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219a"
+ ]
+ ]
+ },
+ {
+ "input": "&nleftrightarrow",
+ "description": "Bad named entity: nleftrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nleftrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↮",
+ "description": "Named entity: nleftrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ae"
+ ]
+ ]
+ },
+ {
+ "input": "&nleq",
+ "description": "Bad named entity: nleq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nleq"
+ ]
+ ]
+ },
+ {
+ "input": "≰",
+ "description": "Named entity: nleq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2270"
+ ]
+ ]
+ },
+ {
+ "input": "&nleqq",
+ "description": "Bad named entity: nleqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nleqq"
+ ]
+ ]
+ },
+ {
+ "input": "≦̸",
+ "description": "Named entity: nleqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2266\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nleqslant",
+ "description": "Bad named entity: nleqslant without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nleqslant"
+ ]
+ ]
+ },
+ {
+ "input": "⩽̸",
+ "description": "Named entity: nleqslant; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7d\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nles",
+ "description": "Bad named entity: nles without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nles"
+ ]
+ ]
+ },
+ {
+ "input": "⩽̸",
+ "description": "Named entity: nles; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a7d\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nless",
+ "description": "Bad named entity: nless without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nless"
+ ]
+ ]
+ },
+ {
+ "input": "≮",
+ "description": "Named entity: nless; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226e"
+ ]
+ ]
+ },
+ {
+ "input": "&nlsim",
+ "description": "Bad named entity: nlsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nlsim"
+ ]
+ ]
+ },
+ {
+ "input": "≴",
+ "description": "Named entity: nlsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2274"
+ ]
+ ]
+ },
+ {
+ "input": "&nlt",
+ "description": "Bad named entity: nlt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nlt"
+ ]
+ ]
+ },
+ {
+ "input": "≮",
+ "description": "Named entity: nlt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226e"
+ ]
+ ]
+ },
+ {
+ "input": "&nltri",
+ "description": "Bad named entity: nltri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nltri"
+ ]
+ ]
+ },
+ {
+ "input": "⋪",
+ "description": "Named entity: nltri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ea"
+ ]
+ ]
+ },
+ {
+ "input": "&nltrie",
+ "description": "Bad named entity: nltrie without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nltrie"
+ ]
+ ]
+ },
+ {
+ "input": "⋬",
+ "description": "Named entity: nltrie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ec"
+ ]
+ ]
+ },
+ {
+ "input": "&nmid",
+ "description": "Bad named entity: nmid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nmid"
+ ]
+ ]
+ },
+ {
+ "input": "∤",
+ "description": "Named entity: nmid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2224"
+ ]
+ ]
+ },
+ {
+ "input": "&nopf",
+ "description": "Bad named entity: nopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕟",
+ "description": "Named entity: nopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd5f"
+ ]
+ ]
+ },
+ {
+ "input": "¬",
+ "description": "Named entity: not without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ac"
+ ]
+ ]
+ },
+ {
+ "input": "¬",
+ "description": "Named entity: not; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ac"
+ ]
+ ]
+ },
+ {
+ "input": "∉",
+ "description": "Named entity: notin; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2209"
+ ]
+ ]
+ },
+ {
+ "input": "⋹̸",
+ "description": "Named entity: notinE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f9\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "⋵̸",
+ "description": "Named entity: notindot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f5\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "∉",
+ "description": "Named entity: notinva; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2209"
+ ]
+ ]
+ },
+ {
+ "input": "⋷",
+ "description": "Named entity: notinvb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f7"
+ ]
+ ]
+ },
+ {
+ "input": "⋶",
+ "description": "Named entity: notinvc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f6"
+ ]
+ ]
+ },
+ {
+ "input": "∌",
+ "description": "Named entity: notni; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220c"
+ ]
+ ]
+ },
+ {
+ "input": "∌",
+ "description": "Named entity: notniva; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220c"
+ ]
+ ]
+ },
+ {
+ "input": "⋾",
+ "description": "Named entity: notnivb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22fe"
+ ]
+ ]
+ },
+ {
+ "input": "⋽",
+ "description": "Named entity: notnivc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22fd"
+ ]
+ ]
+ },
+ {
+ "input": "&npar",
+ "description": "Bad named entity: npar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&npar"
+ ]
+ ]
+ },
+ {
+ "input": "∦",
+ "description": "Named entity: npar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2226"
+ ]
+ ]
+ },
+ {
+ "input": "&nparallel",
+ "description": "Bad named entity: nparallel without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nparallel"
+ ]
+ ]
+ },
+ {
+ "input": "∦",
+ "description": "Named entity: nparallel; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2226"
+ ]
+ ]
+ },
+ {
+ "input": "&nparsl",
+ "description": "Bad named entity: nparsl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nparsl"
+ ]
+ ]
+ },
+ {
+ "input": "⫽⃥",
+ "description": "Named entity: nparsl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2afd\u20e5"
+ ]
+ ]
+ },
+ {
+ "input": "&npart",
+ "description": "Bad named entity: npart without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&npart"
+ ]
+ ]
+ },
+ {
+ "input": "∂̸",
+ "description": "Named entity: npart; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2202\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&npolint",
+ "description": "Bad named entity: npolint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&npolint"
+ ]
+ ]
+ },
+ {
+ "input": "⨔",
+ "description": "Named entity: npolint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a14"
+ ]
+ ]
+ },
+ {
+ "input": "&npr",
+ "description": "Bad named entity: npr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&npr"
+ ]
+ ]
+ },
+ {
+ "input": "⊀",
+ "description": "Named entity: npr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2280"
+ ]
+ ]
+ },
+ {
+ "input": "&nprcue",
+ "description": "Bad named entity: nprcue without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nprcue"
+ ]
+ ]
+ },
+ {
+ "input": "⋠",
+ "description": "Named entity: nprcue; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e0"
+ ]
+ ]
+ },
+ {
+ "input": "&npre",
+ "description": "Bad named entity: npre without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&npre"
+ ]
+ ]
+ },
+ {
+ "input": "⪯̸",
+ "description": "Named entity: npre; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aaf\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nprec",
+ "description": "Bad named entity: nprec without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nprec"
+ ]
+ ]
+ },
+ {
+ "input": "⊀",
+ "description": "Named entity: nprec; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2280"
+ ]
+ ]
+ },
+ {
+ "input": "&npreceq",
+ "description": "Bad named entity: npreceq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&npreceq"
+ ]
+ ]
+ },
+ {
+ "input": "⪯̸",
+ "description": "Named entity: npreceq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aaf\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nrArr",
+ "description": "Bad named entity: nrArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nrArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇏",
+ "description": "Named entity: nrArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cf"
+ ]
+ ]
+ },
+ {
+ "input": "&nrarr",
+ "description": "Bad named entity: nrarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nrarr"
+ ]
+ ]
+ },
+ {
+ "input": "↛",
+ "description": "Named entity: nrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219b"
+ ]
+ ]
+ },
+ {
+ "input": "&nrarrc",
+ "description": "Bad named entity: nrarrc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nrarrc"
+ ]
+ ]
+ },
+ {
+ "input": "⤳̸",
+ "description": "Named entity: nrarrc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2933\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nrarrw",
+ "description": "Bad named entity: nrarrw without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nrarrw"
+ ]
+ ]
+ },
+ {
+ "input": "↝̸",
+ "description": "Named entity: nrarrw; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219d\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nrightarrow",
+ "description": "Bad named entity: nrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↛",
+ "description": "Named entity: nrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219b"
+ ]
+ ]
+ },
+ {
+ "input": "&nrtri",
+ "description": "Bad named entity: nrtri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nrtri"
+ ]
+ ]
+ },
+ {
+ "input": "⋫",
+ "description": "Named entity: nrtri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22eb"
+ ]
+ ]
+ },
+ {
+ "input": "&nrtrie",
+ "description": "Bad named entity: nrtrie without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nrtrie"
+ ]
+ ]
+ },
+ {
+ "input": "⋭",
+ "description": "Named entity: nrtrie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ed"
+ ]
+ ]
+ },
+ {
+ "input": "&nsc",
+ "description": "Bad named entity: nsc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsc"
+ ]
+ ]
+ },
+ {
+ "input": "⊁",
+ "description": "Named entity: nsc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2281"
+ ]
+ ]
+ },
+ {
+ "input": "&nsccue",
+ "description": "Bad named entity: nsccue without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsccue"
+ ]
+ ]
+ },
+ {
+ "input": "⋡",
+ "description": "Named entity: nsccue; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e1"
+ ]
+ ]
+ },
+ {
+ "input": "&nsce",
+ "description": "Bad named entity: nsce without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsce"
+ ]
+ ]
+ },
+ {
+ "input": "⪰̸",
+ "description": "Named entity: nsce; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab0\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nscr",
+ "description": "Bad named entity: nscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓃",
+ "description": "Named entity: nscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc3"
+ ]
+ ]
+ },
+ {
+ "input": "&nshortmid",
+ "description": "Bad named entity: nshortmid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nshortmid"
+ ]
+ ]
+ },
+ {
+ "input": "∤",
+ "description": "Named entity: nshortmid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2224"
+ ]
+ ]
+ },
+ {
+ "input": "&nshortparallel",
+ "description": "Bad named entity: nshortparallel without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nshortparallel"
+ ]
+ ]
+ },
+ {
+ "input": "∦",
+ "description": "Named entity: nshortparallel; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2226"
+ ]
+ ]
+ },
+ {
+ "input": "&nsim",
+ "description": "Bad named entity: nsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsim"
+ ]
+ ]
+ },
+ {
+ "input": "≁",
+ "description": "Named entity: nsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2241"
+ ]
+ ]
+ },
+ {
+ "input": "&nsime",
+ "description": "Bad named entity: nsime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsime"
+ ]
+ ]
+ },
+ {
+ "input": "≄",
+ "description": "Named entity: nsime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2244"
+ ]
+ ]
+ },
+ {
+ "input": "&nsimeq",
+ "description": "Bad named entity: nsimeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsimeq"
+ ]
+ ]
+ },
+ {
+ "input": "≄",
+ "description": "Named entity: nsimeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2244"
+ ]
+ ]
+ },
+ {
+ "input": "&nsmid",
+ "description": "Bad named entity: nsmid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsmid"
+ ]
+ ]
+ },
+ {
+ "input": "∤",
+ "description": "Named entity: nsmid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2224"
+ ]
+ ]
+ },
+ {
+ "input": "&nspar",
+ "description": "Bad named entity: nspar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nspar"
+ ]
+ ]
+ },
+ {
+ "input": "∦",
+ "description": "Named entity: nspar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2226"
+ ]
+ ]
+ },
+ {
+ "input": "&nsqsube",
+ "description": "Bad named entity: nsqsube without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsqsube"
+ ]
+ ]
+ },
+ {
+ "input": "⋢",
+ "description": "Named entity: nsqsube; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e2"
+ ]
+ ]
+ },
+ {
+ "input": "&nsqsupe",
+ "description": "Bad named entity: nsqsupe without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsqsupe"
+ ]
+ ]
+ },
+ {
+ "input": "⋣",
+ "description": "Named entity: nsqsupe; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e3"
+ ]
+ ]
+ },
+ {
+ "input": "&nsub",
+ "description": "Bad named entity: nsub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsub"
+ ]
+ ]
+ },
+ {
+ "input": "⊄",
+ "description": "Named entity: nsub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2284"
+ ]
+ ]
+ },
+ {
+ "input": "&nsubE",
+ "description": "Bad named entity: nsubE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsubE"
+ ]
+ ]
+ },
+ {
+ "input": "⫅̸",
+ "description": "Named entity: nsubE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac5\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nsube",
+ "description": "Bad named entity: nsube without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsube"
+ ]
+ ]
+ },
+ {
+ "input": "⊈",
+ "description": "Named entity: nsube; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2288"
+ ]
+ ]
+ },
+ {
+ "input": "&nsubset",
+ "description": "Bad named entity: nsubset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsubset"
+ ]
+ ]
+ },
+ {
+ "input": "⊂⃒",
+ "description": "Named entity: nsubset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2282\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nsubseteq",
+ "description": "Bad named entity: nsubseteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsubseteq"
+ ]
+ ]
+ },
+ {
+ "input": "⊈",
+ "description": "Named entity: nsubseteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2288"
+ ]
+ ]
+ },
+ {
+ "input": "&nsubseteqq",
+ "description": "Bad named entity: nsubseteqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsubseteqq"
+ ]
+ ]
+ },
+ {
+ "input": "⫅̸",
+ "description": "Named entity: nsubseteqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac5\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nsucc",
+ "description": "Bad named entity: nsucc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsucc"
+ ]
+ ]
+ },
+ {
+ "input": "⊁",
+ "description": "Named entity: nsucc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2281"
+ ]
+ ]
+ },
+ {
+ "input": "&nsucceq",
+ "description": "Bad named entity: nsucceq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsucceq"
+ ]
+ ]
+ },
+ {
+ "input": "⪰̸",
+ "description": "Named entity: nsucceq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab0\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nsup",
+ "description": "Bad named entity: nsup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsup"
+ ]
+ ]
+ },
+ {
+ "input": "⊅",
+ "description": "Named entity: nsup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2285"
+ ]
+ ]
+ },
+ {
+ "input": "&nsupE",
+ "description": "Bad named entity: nsupE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsupE"
+ ]
+ ]
+ },
+ {
+ "input": "⫆̸",
+ "description": "Named entity: nsupE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac6\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&nsupe",
+ "description": "Bad named entity: nsupe without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsupe"
+ ]
+ ]
+ },
+ {
+ "input": "⊉",
+ "description": "Named entity: nsupe; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2289"
+ ]
+ ]
+ },
+ {
+ "input": "&nsupset",
+ "description": "Bad named entity: nsupset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsupset"
+ ]
+ ]
+ },
+ {
+ "input": "⊃⃒",
+ "description": "Named entity: nsupset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2283\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nsupseteq",
+ "description": "Bad named entity: nsupseteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsupseteq"
+ ]
+ ]
+ },
+ {
+ "input": "⊉",
+ "description": "Named entity: nsupseteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2289"
+ ]
+ ]
+ },
+ {
+ "input": "&nsupseteqq",
+ "description": "Bad named entity: nsupseteqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nsupseteqq"
+ ]
+ ]
+ },
+ {
+ "input": "⫆̸",
+ "description": "Named entity: nsupseteqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac6\u0338"
+ ]
+ ]
+ },
+ {
+ "input": "&ntgl",
+ "description": "Bad named entity: ntgl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ntgl"
+ ]
+ ]
+ },
+ {
+ "input": "≹",
+ "description": "Named entity: ntgl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2279"
+ ]
+ ]
+ },
+ {
+ "input": "ñ",
+ "description": "Named entity: ntilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f1"
+ ]
+ ]
+ },
+ {
+ "input": "ñ",
+ "description": "Named entity: ntilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f1"
+ ]
+ ]
+ },
+ {
+ "input": "&ntlg",
+ "description": "Bad named entity: ntlg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ntlg"
+ ]
+ ]
+ },
+ {
+ "input": "≸",
+ "description": "Named entity: ntlg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2278"
+ ]
+ ]
+ },
+ {
+ "input": "&ntriangleleft",
+ "description": "Bad named entity: ntriangleleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ntriangleleft"
+ ]
+ ]
+ },
+ {
+ "input": "⋪",
+ "description": "Named entity: ntriangleleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ea"
+ ]
+ ]
+ },
+ {
+ "input": "&ntrianglelefteq",
+ "description": "Bad named entity: ntrianglelefteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ntrianglelefteq"
+ ]
+ ]
+ },
+ {
+ "input": "⋬",
+ "description": "Named entity: ntrianglelefteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ec"
+ ]
+ ]
+ },
+ {
+ "input": "&ntriangleright",
+ "description": "Bad named entity: ntriangleright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ntriangleright"
+ ]
+ ]
+ },
+ {
+ "input": "⋫",
+ "description": "Named entity: ntriangleright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22eb"
+ ]
+ ]
+ },
+ {
+ "input": "&ntrianglerighteq",
+ "description": "Bad named entity: ntrianglerighteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ntrianglerighteq"
+ ]
+ ]
+ },
+ {
+ "input": "⋭",
+ "description": "Named entity: ntrianglerighteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ed"
+ ]
+ ]
+ },
+ {
+ "input": "&nu",
+ "description": "Bad named entity: nu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nu"
+ ]
+ ]
+ },
+ {
+ "input": "ν",
+ "description": "Named entity: nu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03bd"
+ ]
+ ]
+ },
+ {
+ "input": "&num",
+ "description": "Bad named entity: num without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&num"
+ ]
+ ]
+ },
+ {
+ "input": "#",
+ "description": "Named entity: num; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "#"
+ ]
+ ]
+ },
+ {
+ "input": "&numero",
+ "description": "Bad named entity: numero without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&numero"
+ ]
+ ]
+ },
+ {
+ "input": "№",
+ "description": "Named entity: numero; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2116"
+ ]
+ ]
+ },
+ {
+ "input": "&numsp",
+ "description": "Bad named entity: numsp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&numsp"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: numsp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2007"
+ ]
+ ]
+ },
+ {
+ "input": "&nvDash",
+ "description": "Bad named entity: nvDash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvDash"
+ ]
+ ]
+ },
+ {
+ "input": "⊭",
+ "description": "Named entity: nvDash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ad"
+ ]
+ ]
+ },
+ {
+ "input": "&nvHarr",
+ "description": "Bad named entity: nvHarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvHarr"
+ ]
+ ]
+ },
+ {
+ "input": "⤄",
+ "description": "Named entity: nvHarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2904"
+ ]
+ ]
+ },
+ {
+ "input": "&nvap",
+ "description": "Bad named entity: nvap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvap"
+ ]
+ ]
+ },
+ {
+ "input": "≍⃒",
+ "description": "Named entity: nvap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u224d\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nvdash",
+ "description": "Bad named entity: nvdash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvdash"
+ ]
+ ]
+ },
+ {
+ "input": "⊬",
+ "description": "Named entity: nvdash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ac"
+ ]
+ ]
+ },
+ {
+ "input": "&nvge",
+ "description": "Bad named entity: nvge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvge"
+ ]
+ ]
+ },
+ {
+ "input": "≥⃒",
+ "description": "Named entity: nvge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2265\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nvgt",
+ "description": "Bad named entity: nvgt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvgt"
+ ]
+ ]
+ },
+ {
+ "input": ">⃒",
+ "description": "Named entity: nvgt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ ">\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nvinfin",
+ "description": "Bad named entity: nvinfin without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvinfin"
+ ]
+ ]
+ },
+ {
+ "input": "⧞",
+ "description": "Named entity: nvinfin; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29de"
+ ]
+ ]
+ },
+ {
+ "input": "&nvlArr",
+ "description": "Bad named entity: nvlArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvlArr"
+ ]
+ ]
+ },
+ {
+ "input": "⤂",
+ "description": "Named entity: nvlArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2902"
+ ]
+ ]
+ },
+ {
+ "input": "&nvle",
+ "description": "Bad named entity: nvle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvle"
+ ]
+ ]
+ },
+ {
+ "input": "≤⃒",
+ "description": "Named entity: nvle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2264\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nvlt",
+ "description": "Bad named entity: nvlt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvlt"
+ ]
+ ]
+ },
+ {
+ "input": "<⃒",
+ "description": "Named entity: nvlt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "<\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nvltrie",
+ "description": "Bad named entity: nvltrie without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvltrie"
+ ]
+ ]
+ },
+ {
+ "input": "⊴⃒",
+ "description": "Named entity: nvltrie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b4\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nvrArr",
+ "description": "Bad named entity: nvrArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvrArr"
+ ]
+ ]
+ },
+ {
+ "input": "⤃",
+ "description": "Named entity: nvrArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2903"
+ ]
+ ]
+ },
+ {
+ "input": "&nvrtrie",
+ "description": "Bad named entity: nvrtrie without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvrtrie"
+ ]
+ ]
+ },
+ {
+ "input": "⊵⃒",
+ "description": "Named entity: nvrtrie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b5\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nvsim",
+ "description": "Bad named entity: nvsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nvsim"
+ ]
+ ]
+ },
+ {
+ "input": "∼⃒",
+ "description": "Named entity: nvsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223c\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&nwArr",
+ "description": "Bad named entity: nwArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nwArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇖",
+ "description": "Named entity: nwArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d6"
+ ]
+ ]
+ },
+ {
+ "input": "&nwarhk",
+ "description": "Bad named entity: nwarhk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nwarhk"
+ ]
+ ]
+ },
+ {
+ "input": "⤣",
+ "description": "Named entity: nwarhk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2923"
+ ]
+ ]
+ },
+ {
+ "input": "&nwarr",
+ "description": "Bad named entity: nwarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nwarr"
+ ]
+ ]
+ },
+ {
+ "input": "↖",
+ "description": "Named entity: nwarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2196"
+ ]
+ ]
+ },
+ {
+ "input": "&nwarrow",
+ "description": "Bad named entity: nwarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nwarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↖",
+ "description": "Named entity: nwarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2196"
+ ]
+ ]
+ },
+ {
+ "input": "&nwnear",
+ "description": "Bad named entity: nwnear without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&nwnear"
+ ]
+ ]
+ },
+ {
+ "input": "⤧",
+ "description": "Named entity: nwnear; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2927"
+ ]
+ ]
+ },
+ {
+ "input": "&oS",
+ "description": "Bad named entity: oS without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oS"
+ ]
+ ]
+ },
+ {
+ "input": "Ⓢ",
+ "description": "Named entity: oS; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u24c8"
+ ]
+ ]
+ },
+ {
+ "input": "ó",
+ "description": "Named entity: oacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f3"
+ ]
+ ]
+ },
+ {
+ "input": "ó",
+ "description": "Named entity: oacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f3"
+ ]
+ ]
+ },
+ {
+ "input": "&oast",
+ "description": "Bad named entity: oast without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oast"
+ ]
+ ]
+ },
+ {
+ "input": "⊛",
+ "description": "Named entity: oast; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229b"
+ ]
+ ]
+ },
+ {
+ "input": "&ocir",
+ "description": "Bad named entity: ocir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ocir"
+ ]
+ ]
+ },
+ {
+ "input": "⊚",
+ "description": "Named entity: ocir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229a"
+ ]
+ ]
+ },
+ {
+ "input": "ô",
+ "description": "Named entity: ocirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f4"
+ ]
+ ]
+ },
+ {
+ "input": "ô",
+ "description": "Named entity: ocirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f4"
+ ]
+ ]
+ },
+ {
+ "input": "&ocy",
+ "description": "Bad named entity: ocy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ocy"
+ ]
+ ]
+ },
+ {
+ "input": "о",
+ "description": "Named entity: ocy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u043e"
+ ]
+ ]
+ },
+ {
+ "input": "&odash",
+ "description": "Bad named entity: odash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&odash"
+ ]
+ ]
+ },
+ {
+ "input": "⊝",
+ "description": "Named entity: odash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229d"
+ ]
+ ]
+ },
+ {
+ "input": "&odblac",
+ "description": "Bad named entity: odblac without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&odblac"
+ ]
+ ]
+ },
+ {
+ "input": "ő",
+ "description": "Named entity: odblac; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0151"
+ ]
+ ]
+ },
+ {
+ "input": "&odiv",
+ "description": "Bad named entity: odiv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&odiv"
+ ]
+ ]
+ },
+ {
+ "input": "⨸",
+ "description": "Named entity: odiv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a38"
+ ]
+ ]
+ },
+ {
+ "input": "&odot",
+ "description": "Bad named entity: odot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&odot"
+ ]
+ ]
+ },
+ {
+ "input": "⊙",
+ "description": "Named entity: odot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2299"
+ ]
+ ]
+ },
+ {
+ "input": "&odsold",
+ "description": "Bad named entity: odsold without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&odsold"
+ ]
+ ]
+ },
+ {
+ "input": "⦼",
+ "description": "Named entity: odsold; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29bc"
+ ]
+ ]
+ },
+ {
+ "input": "&oelig",
+ "description": "Bad named entity: oelig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oelig"
+ ]
+ ]
+ },
+ {
+ "input": "œ",
+ "description": "Named entity: oelig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0153"
+ ]
+ ]
+ },
+ {
+ "input": "&ofcir",
+ "description": "Bad named entity: ofcir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ofcir"
+ ]
+ ]
+ },
+ {
+ "input": "⦿",
+ "description": "Named entity: ofcir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29bf"
+ ]
+ ]
+ },
+ {
+ "input": "&ofr",
+ "description": "Bad named entity: ofr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ofr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔬",
+ "description": "Named entity: ofr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd2c"
+ ]
+ ]
+ },
+ {
+ "input": "&ogon",
+ "description": "Bad named entity: ogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ogon"
+ ]
+ ]
+ },
+ {
+ "input": "˛",
+ "description": "Named entity: ogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02db"
+ ]
+ ]
+ },
+ {
+ "input": "ò",
+ "description": "Named entity: ograve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f2"
+ ]
+ ]
+ },
+ {
+ "input": "ò",
+ "description": "Named entity: ograve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f2"
+ ]
+ ]
+ },
+ {
+ "input": "&ogt",
+ "description": "Bad named entity: ogt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ogt"
+ ]
+ ]
+ },
+ {
+ "input": "⧁",
+ "description": "Named entity: ogt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29c1"
+ ]
+ ]
+ },
+ {
+ "input": "&ohbar",
+ "description": "Bad named entity: ohbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ohbar"
+ ]
+ ]
+ },
+ {
+ "input": "⦵",
+ "description": "Named entity: ohbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b5"
+ ]
+ ]
+ },
+ {
+ "input": "&ohm",
+ "description": "Bad named entity: ohm without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ohm"
+ ]
+ ]
+ },
+ {
+ "input": "Ω",
+ "description": "Named entity: ohm; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03a9"
+ ]
+ ]
+ },
+ {
+ "input": "&oint",
+ "description": "Bad named entity: oint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oint"
+ ]
+ ]
+ },
+ {
+ "input": "∮",
+ "description": "Named entity: oint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222e"
+ ]
+ ]
+ },
+ {
+ "input": "&olarr",
+ "description": "Bad named entity: olarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&olarr"
+ ]
+ ]
+ },
+ {
+ "input": "↺",
+ "description": "Named entity: olarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ba"
+ ]
+ ]
+ },
+ {
+ "input": "&olcir",
+ "description": "Bad named entity: olcir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&olcir"
+ ]
+ ]
+ },
+ {
+ "input": "⦾",
+ "description": "Named entity: olcir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29be"
+ ]
+ ]
+ },
+ {
+ "input": "&olcross",
+ "description": "Bad named entity: olcross without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&olcross"
+ ]
+ ]
+ },
+ {
+ "input": "⦻",
+ "description": "Named entity: olcross; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29bb"
+ ]
+ ]
+ },
+ {
+ "input": "&oline",
+ "description": "Bad named entity: oline without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oline"
+ ]
+ ]
+ },
+ {
+ "input": "‾",
+ "description": "Named entity: oline; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u203e"
+ ]
+ ]
+ },
+ {
+ "input": "&olt",
+ "description": "Bad named entity: olt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&olt"
+ ]
+ ]
+ },
+ {
+ "input": "⧀",
+ "description": "Named entity: olt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29c0"
+ ]
+ ]
+ },
+ {
+ "input": "&omacr",
+ "description": "Bad named entity: omacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&omacr"
+ ]
+ ]
+ },
+ {
+ "input": "ō",
+ "description": "Named entity: omacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u014d"
+ ]
+ ]
+ },
+ {
+ "input": "&omega",
+ "description": "Bad named entity: omega without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&omega"
+ ]
+ ]
+ },
+ {
+ "input": "ω",
+ "description": "Named entity: omega; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c9"
+ ]
+ ]
+ },
+ {
+ "input": "&omicron",
+ "description": "Bad named entity: omicron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&omicron"
+ ]
+ ]
+ },
+ {
+ "input": "ο",
+ "description": "Named entity: omicron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03bf"
+ ]
+ ]
+ },
+ {
+ "input": "&omid",
+ "description": "Bad named entity: omid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&omid"
+ ]
+ ]
+ },
+ {
+ "input": "⦶",
+ "description": "Named entity: omid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b6"
+ ]
+ ]
+ },
+ {
+ "input": "&ominus",
+ "description": "Bad named entity: ominus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ominus"
+ ]
+ ]
+ },
+ {
+ "input": "⊖",
+ "description": "Named entity: ominus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2296"
+ ]
+ ]
+ },
+ {
+ "input": "&oopf",
+ "description": "Bad named entity: oopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕠",
+ "description": "Named entity: oopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd60"
+ ]
+ ]
+ },
+ {
+ "input": "&opar",
+ "description": "Bad named entity: opar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&opar"
+ ]
+ ]
+ },
+ {
+ "input": "⦷",
+ "description": "Named entity: opar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b7"
+ ]
+ ]
+ },
+ {
+ "input": "&operp",
+ "description": "Bad named entity: operp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&operp"
+ ]
+ ]
+ },
+ {
+ "input": "⦹",
+ "description": "Named entity: operp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b9"
+ ]
+ ]
+ },
+ {
+ "input": "&oplus",
+ "description": "Bad named entity: oplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oplus"
+ ]
+ ]
+ },
+ {
+ "input": "⊕",
+ "description": "Named entity: oplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2295"
+ ]
+ ]
+ },
+ {
+ "input": "&or",
+ "description": "Bad named entity: or without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&or"
+ ]
+ ]
+ },
+ {
+ "input": "∨",
+ "description": "Named entity: or; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2228"
+ ]
+ ]
+ },
+ {
+ "input": "&orarr",
+ "description": "Bad named entity: orarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&orarr"
+ ]
+ ]
+ },
+ {
+ "input": "↻",
+ "description": "Named entity: orarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bb"
+ ]
+ ]
+ },
+ {
+ "input": "&ord",
+ "description": "Bad named entity: ord without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ord"
+ ]
+ ]
+ },
+ {
+ "input": "⩝",
+ "description": "Named entity: ord; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a5d"
+ ]
+ ]
+ },
+ {
+ "input": "&order",
+ "description": "Bad named entity: order without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&order"
+ ]
+ ]
+ },
+ {
+ "input": "ℴ",
+ "description": "Named entity: order; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2134"
+ ]
+ ]
+ },
+ {
+ "input": "&orderof",
+ "description": "Bad named entity: orderof without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&orderof"
+ ]
+ ]
+ },
+ {
+ "input": "ℴ",
+ "description": "Named entity: orderof; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2134"
+ ]
+ ]
+ },
+ {
+ "input": "ª",
+ "description": "Named entity: ordf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00aa"
+ ]
+ ]
+ },
+ {
+ "input": "ª",
+ "description": "Named entity: ordf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00aa"
+ ]
+ ]
+ },
+ {
+ "input": "º",
+ "description": "Named entity: ordm without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ba"
+ ]
+ ]
+ },
+ {
+ "input": "º",
+ "description": "Named entity: ordm; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ba"
+ ]
+ ]
+ },
+ {
+ "input": "&origof",
+ "description": "Bad named entity: origof without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&origof"
+ ]
+ ]
+ },
+ {
+ "input": "⊶",
+ "description": "Named entity: origof; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b6"
+ ]
+ ]
+ },
+ {
+ "input": "&oror",
+ "description": "Bad named entity: oror without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oror"
+ ]
+ ]
+ },
+ {
+ "input": "⩖",
+ "description": "Named entity: oror; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a56"
+ ]
+ ]
+ },
+ {
+ "input": "&orslope",
+ "description": "Bad named entity: orslope without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&orslope"
+ ]
+ ]
+ },
+ {
+ "input": "⩗",
+ "description": "Named entity: orslope; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a57"
+ ]
+ ]
+ },
+ {
+ "input": "&orv",
+ "description": "Bad named entity: orv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&orv"
+ ]
+ ]
+ },
+ {
+ "input": "⩛",
+ "description": "Named entity: orv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a5b"
+ ]
+ ]
+ },
+ {
+ "input": "&oscr",
+ "description": "Bad named entity: oscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&oscr"
+ ]
+ ]
+ },
+ {
+ "input": "ℴ",
+ "description": "Named entity: oscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2134"
+ ]
+ ]
+ },
+ {
+ "input": "ø",
+ "description": "Named entity: oslash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f8"
+ ]
+ ]
+ },
+ {
+ "input": "ø",
+ "description": "Named entity: oslash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f8"
+ ]
+ ]
+ },
+ {
+ "input": "&osol",
+ "description": "Bad named entity: osol without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&osol"
+ ]
+ ]
+ },
+ {
+ "input": "⊘",
+ "description": "Named entity: osol; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2298"
+ ]
+ ]
+ },
+ {
+ "input": "õ",
+ "description": "Named entity: otilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f5"
+ ]
+ ]
+ },
+ {
+ "input": "õ",
+ "description": "Named entity: otilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f5"
+ ]
+ ]
+ },
+ {
+ "input": "&otimes",
+ "description": "Bad named entity: otimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&otimes"
+ ]
+ ]
+ },
+ {
+ "input": "⊗",
+ "description": "Named entity: otimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2297"
+ ]
+ ]
+ },
+ {
+ "input": "&otimesas",
+ "description": "Bad named entity: otimesas without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&otimesas"
+ ]
+ ]
+ },
+ {
+ "input": "⨶",
+ "description": "Named entity: otimesas; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a36"
+ ]
+ ]
+ },
+ {
+ "input": "ö",
+ "description": "Named entity: ouml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f6"
+ ]
+ ]
+ },
+ {
+ "input": "ö",
+ "description": "Named entity: ouml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f6"
+ ]
+ ]
+ },
+ {
+ "input": "&ovbar",
+ "description": "Bad named entity: ovbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ovbar"
+ ]
+ ]
+ },
+ {
+ "input": "⌽",
+ "description": "Named entity: ovbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u233d"
+ ]
+ ]
+ },
+ {
+ "input": "&par",
+ "description": "Bad named entity: par without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&par"
+ ]
+ ]
+ },
+ {
+ "input": "∥",
+ "description": "Named entity: par; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2225"
+ ]
+ ]
+ },
+ {
+ "input": "¶",
+ "description": "Named entity: para without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b6"
+ ]
+ ]
+ },
+ {
+ "input": "¶",
+ "description": "Named entity: para; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b6"
+ ]
+ ]
+ },
+ {
+ "input": "∥",
+ "description": "Named entity: parallel; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2225"
+ ]
+ ]
+ },
+ {
+ "input": "&parsim",
+ "description": "Bad named entity: parsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&parsim"
+ ]
+ ]
+ },
+ {
+ "input": "⫳",
+ "description": "Named entity: parsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2af3"
+ ]
+ ]
+ },
+ {
+ "input": "&parsl",
+ "description": "Bad named entity: parsl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&parsl"
+ ]
+ ]
+ },
+ {
+ "input": "⫽",
+ "description": "Named entity: parsl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2afd"
+ ]
+ ]
+ },
+ {
+ "input": "&part",
+ "description": "Bad named entity: part without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&part"
+ ]
+ ]
+ },
+ {
+ "input": "∂",
+ "description": "Named entity: part; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2202"
+ ]
+ ]
+ },
+ {
+ "input": "&pcy",
+ "description": "Bad named entity: pcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pcy"
+ ]
+ ]
+ },
+ {
+ "input": "п",
+ "description": "Named entity: pcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u043f"
+ ]
+ ]
+ },
+ {
+ "input": "&percnt",
+ "description": "Bad named entity: percnt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&percnt"
+ ]
+ ]
+ },
+ {
+ "input": "%",
+ "description": "Named entity: percnt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "%"
+ ]
+ ]
+ },
+ {
+ "input": "&period",
+ "description": "Bad named entity: period without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&period"
+ ]
+ ]
+ },
+ {
+ "input": ".",
+ "description": "Named entity: period; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "."
+ ]
+ ]
+ },
+ {
+ "input": "&permil",
+ "description": "Bad named entity: permil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&permil"
+ ]
+ ]
+ },
+ {
+ "input": "‰",
+ "description": "Named entity: permil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2030"
+ ]
+ ]
+ },
+ {
+ "input": "&perp",
+ "description": "Bad named entity: perp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&perp"
+ ]
+ ]
+ },
+ {
+ "input": "⊥",
+ "description": "Named entity: perp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a5"
+ ]
+ ]
+ },
+ {
+ "input": "&pertenk",
+ "description": "Bad named entity: pertenk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pertenk"
+ ]
+ ]
+ },
+ {
+ "input": "‱",
+ "description": "Named entity: pertenk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2031"
+ ]
+ ]
+ },
+ {
+ "input": "&pfr",
+ "description": "Bad named entity: pfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔭",
+ "description": "Named entity: pfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd2d"
+ ]
+ ]
+ },
+ {
+ "input": "&phi",
+ "description": "Bad named entity: phi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&phi"
+ ]
+ ]
+ },
+ {
+ "input": "φ",
+ "description": "Named entity: phi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c6"
+ ]
+ ]
+ },
+ {
+ "input": "&phiv",
+ "description": "Bad named entity: phiv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&phiv"
+ ]
+ ]
+ },
+ {
+ "input": "ϕ",
+ "description": "Named entity: phiv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d5"
+ ]
+ ]
+ },
+ {
+ "input": "&phmmat",
+ "description": "Bad named entity: phmmat without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&phmmat"
+ ]
+ ]
+ },
+ {
+ "input": "ℳ",
+ "description": "Named entity: phmmat; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2133"
+ ]
+ ]
+ },
+ {
+ "input": "&phone",
+ "description": "Bad named entity: phone without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&phone"
+ ]
+ ]
+ },
+ {
+ "input": "☎",
+ "description": "Named entity: phone; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u260e"
+ ]
+ ]
+ },
+ {
+ "input": "&pi",
+ "description": "Bad named entity: pi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pi"
+ ]
+ ]
+ },
+ {
+ "input": "π",
+ "description": "Named entity: pi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c0"
+ ]
+ ]
+ },
+ {
+ "input": "&pitchfork",
+ "description": "Bad named entity: pitchfork without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pitchfork"
+ ]
+ ]
+ },
+ {
+ "input": "⋔",
+ "description": "Named entity: pitchfork; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22d4"
+ ]
+ ]
+ },
+ {
+ "input": "&piv",
+ "description": "Bad named entity: piv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&piv"
+ ]
+ ]
+ },
+ {
+ "input": "ϖ",
+ "description": "Named entity: piv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d6"
+ ]
+ ]
+ },
+ {
+ "input": "&planck",
+ "description": "Bad named entity: planck without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&planck"
+ ]
+ ]
+ },
+ {
+ "input": "ℏ",
+ "description": "Named entity: planck; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210f"
+ ]
+ ]
+ },
+ {
+ "input": "&planckh",
+ "description": "Bad named entity: planckh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&planckh"
+ ]
+ ]
+ },
+ {
+ "input": "ℎ",
+ "description": "Named entity: planckh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210e"
+ ]
+ ]
+ },
+ {
+ "input": "&plankv",
+ "description": "Bad named entity: plankv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&plankv"
+ ]
+ ]
+ },
+ {
+ "input": "ℏ",
+ "description": "Named entity: plankv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210f"
+ ]
+ ]
+ },
+ {
+ "input": "&plus",
+ "description": "Bad named entity: plus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&plus"
+ ]
+ ]
+ },
+ {
+ "input": "+",
+ "description": "Named entity: plus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "+"
+ ]
+ ]
+ },
+ {
+ "input": "&plusacir",
+ "description": "Bad named entity: plusacir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&plusacir"
+ ]
+ ]
+ },
+ {
+ "input": "⨣",
+ "description": "Named entity: plusacir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a23"
+ ]
+ ]
+ },
+ {
+ "input": "&plusb",
+ "description": "Bad named entity: plusb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&plusb"
+ ]
+ ]
+ },
+ {
+ "input": "⊞",
+ "description": "Named entity: plusb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u229e"
+ ]
+ ]
+ },
+ {
+ "input": "&pluscir",
+ "description": "Bad named entity: pluscir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pluscir"
+ ]
+ ]
+ },
+ {
+ "input": "⨢",
+ "description": "Named entity: pluscir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a22"
+ ]
+ ]
+ },
+ {
+ "input": "&plusdo",
+ "description": "Bad named entity: plusdo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&plusdo"
+ ]
+ ]
+ },
+ {
+ "input": "∔",
+ "description": "Named entity: plusdo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2214"
+ ]
+ ]
+ },
+ {
+ "input": "&plusdu",
+ "description": "Bad named entity: plusdu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&plusdu"
+ ]
+ ]
+ },
+ {
+ "input": "⨥",
+ "description": "Named entity: plusdu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a25"
+ ]
+ ]
+ },
+ {
+ "input": "&pluse",
+ "description": "Bad named entity: pluse without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pluse"
+ ]
+ ]
+ },
+ {
+ "input": "⩲",
+ "description": "Named entity: pluse; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a72"
+ ]
+ ]
+ },
+ {
+ "input": "±",
+ "description": "Named entity: plusmn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b1"
+ ]
+ ]
+ },
+ {
+ "input": "±",
+ "description": "Named entity: plusmn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b1"
+ ]
+ ]
+ },
+ {
+ "input": "&plussim",
+ "description": "Bad named entity: plussim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&plussim"
+ ]
+ ]
+ },
+ {
+ "input": "⨦",
+ "description": "Named entity: plussim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a26"
+ ]
+ ]
+ },
+ {
+ "input": "&plustwo",
+ "description": "Bad named entity: plustwo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&plustwo"
+ ]
+ ]
+ },
+ {
+ "input": "⨧",
+ "description": "Named entity: plustwo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a27"
+ ]
+ ]
+ },
+ {
+ "input": "&pm",
+ "description": "Bad named entity: pm without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pm"
+ ]
+ ]
+ },
+ {
+ "input": "±",
+ "description": "Named entity: pm; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b1"
+ ]
+ ]
+ },
+ {
+ "input": "&pointint",
+ "description": "Bad named entity: pointint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pointint"
+ ]
+ ]
+ },
+ {
+ "input": "⨕",
+ "description": "Named entity: pointint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a15"
+ ]
+ ]
+ },
+ {
+ "input": "&popf",
+ "description": "Bad named entity: popf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&popf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕡",
+ "description": "Named entity: popf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd61"
+ ]
+ ]
+ },
+ {
+ "input": "£",
+ "description": "Named entity: pound without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a3"
+ ]
+ ]
+ },
+ {
+ "input": "£",
+ "description": "Named entity: pound; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a3"
+ ]
+ ]
+ },
+ {
+ "input": "&pr",
+ "description": "Bad named entity: pr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pr"
+ ]
+ ]
+ },
+ {
+ "input": "≺",
+ "description": "Named entity: pr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227a"
+ ]
+ ]
+ },
+ {
+ "input": "&prE",
+ "description": "Bad named entity: prE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prE"
+ ]
+ ]
+ },
+ {
+ "input": "⪳",
+ "description": "Named entity: prE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab3"
+ ]
+ ]
+ },
+ {
+ "input": "&prap",
+ "description": "Bad named entity: prap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prap"
+ ]
+ ]
+ },
+ {
+ "input": "⪷",
+ "description": "Named entity: prap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab7"
+ ]
+ ]
+ },
+ {
+ "input": "&prcue",
+ "description": "Bad named entity: prcue without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prcue"
+ ]
+ ]
+ },
+ {
+ "input": "≼",
+ "description": "Named entity: prcue; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227c"
+ ]
+ ]
+ },
+ {
+ "input": "&pre",
+ "description": "Bad named entity: pre without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pre"
+ ]
+ ]
+ },
+ {
+ "input": "⪯",
+ "description": "Named entity: pre; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aaf"
+ ]
+ ]
+ },
+ {
+ "input": "&prec",
+ "description": "Bad named entity: prec without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prec"
+ ]
+ ]
+ },
+ {
+ "input": "≺",
+ "description": "Named entity: prec; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227a"
+ ]
+ ]
+ },
+ {
+ "input": "&precapprox",
+ "description": "Bad named entity: precapprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&precapprox"
+ ]
+ ]
+ },
+ {
+ "input": "⪷",
+ "description": "Named entity: precapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab7"
+ ]
+ ]
+ },
+ {
+ "input": "&preccurlyeq",
+ "description": "Bad named entity: preccurlyeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&preccurlyeq"
+ ]
+ ]
+ },
+ {
+ "input": "≼",
+ "description": "Named entity: preccurlyeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227c"
+ ]
+ ]
+ },
+ {
+ "input": "&preceq",
+ "description": "Bad named entity: preceq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&preceq"
+ ]
+ ]
+ },
+ {
+ "input": "⪯",
+ "description": "Named entity: preceq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aaf"
+ ]
+ ]
+ },
+ {
+ "input": "&precnapprox",
+ "description": "Bad named entity: precnapprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&precnapprox"
+ ]
+ ]
+ },
+ {
+ "input": "⪹",
+ "description": "Named entity: precnapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab9"
+ ]
+ ]
+ },
+ {
+ "input": "&precneqq",
+ "description": "Bad named entity: precneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&precneqq"
+ ]
+ ]
+ },
+ {
+ "input": "⪵",
+ "description": "Named entity: precneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab5"
+ ]
+ ]
+ },
+ {
+ "input": "&precnsim",
+ "description": "Bad named entity: precnsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&precnsim"
+ ]
+ ]
+ },
+ {
+ "input": "⋨",
+ "description": "Named entity: precnsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e8"
+ ]
+ ]
+ },
+ {
+ "input": "&precsim",
+ "description": "Bad named entity: precsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&precsim"
+ ]
+ ]
+ },
+ {
+ "input": "≾",
+ "description": "Named entity: precsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227e"
+ ]
+ ]
+ },
+ {
+ "input": "&prime",
+ "description": "Bad named entity: prime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prime"
+ ]
+ ]
+ },
+ {
+ "input": "′",
+ "description": "Named entity: prime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2032"
+ ]
+ ]
+ },
+ {
+ "input": "&primes",
+ "description": "Bad named entity: primes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&primes"
+ ]
+ ]
+ },
+ {
+ "input": "ℙ",
+ "description": "Named entity: primes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2119"
+ ]
+ ]
+ },
+ {
+ "input": "&prnE",
+ "description": "Bad named entity: prnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prnE"
+ ]
+ ]
+ },
+ {
+ "input": "⪵",
+ "description": "Named entity: prnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab5"
+ ]
+ ]
+ },
+ {
+ "input": "&prnap",
+ "description": "Bad named entity: prnap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prnap"
+ ]
+ ]
+ },
+ {
+ "input": "⪹",
+ "description": "Named entity: prnap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab9"
+ ]
+ ]
+ },
+ {
+ "input": "&prnsim",
+ "description": "Bad named entity: prnsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prnsim"
+ ]
+ ]
+ },
+ {
+ "input": "⋨",
+ "description": "Named entity: prnsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e8"
+ ]
+ ]
+ },
+ {
+ "input": "&prod",
+ "description": "Bad named entity: prod without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prod"
+ ]
+ ]
+ },
+ {
+ "input": "∏",
+ "description": "Named entity: prod; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u220f"
+ ]
+ ]
+ },
+ {
+ "input": "&profalar",
+ "description": "Bad named entity: profalar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&profalar"
+ ]
+ ]
+ },
+ {
+ "input": "⌮",
+ "description": "Named entity: profalar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u232e"
+ ]
+ ]
+ },
+ {
+ "input": "&profline",
+ "description": "Bad named entity: profline without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&profline"
+ ]
+ ]
+ },
+ {
+ "input": "⌒",
+ "description": "Named entity: profline; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2312"
+ ]
+ ]
+ },
+ {
+ "input": "&profsurf",
+ "description": "Bad named entity: profsurf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&profsurf"
+ ]
+ ]
+ },
+ {
+ "input": "⌓",
+ "description": "Named entity: profsurf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2313"
+ ]
+ ]
+ },
+ {
+ "input": "&prop",
+ "description": "Bad named entity: prop without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prop"
+ ]
+ ]
+ },
+ {
+ "input": "∝",
+ "description": "Named entity: prop; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221d"
+ ]
+ ]
+ },
+ {
+ "input": "&propto",
+ "description": "Bad named entity: propto without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&propto"
+ ]
+ ]
+ },
+ {
+ "input": "∝",
+ "description": "Named entity: propto; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221d"
+ ]
+ ]
+ },
+ {
+ "input": "&prsim",
+ "description": "Bad named entity: prsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prsim"
+ ]
+ ]
+ },
+ {
+ "input": "≾",
+ "description": "Named entity: prsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227e"
+ ]
+ ]
+ },
+ {
+ "input": "&prurel",
+ "description": "Bad named entity: prurel without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&prurel"
+ ]
+ ]
+ },
+ {
+ "input": "⊰",
+ "description": "Named entity: prurel; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b0"
+ ]
+ ]
+ },
+ {
+ "input": "&pscr",
+ "description": "Bad named entity: pscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&pscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓅",
+ "description": "Named entity: pscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc5"
+ ]
+ ]
+ },
+ {
+ "input": "&psi",
+ "description": "Bad named entity: psi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&psi"
+ ]
+ ]
+ },
+ {
+ "input": "ψ",
+ "description": "Named entity: psi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c8"
+ ]
+ ]
+ },
+ {
+ "input": "&puncsp",
+ "description": "Bad named entity: puncsp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&puncsp"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: puncsp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2008"
+ ]
+ ]
+ },
+ {
+ "input": "&qfr",
+ "description": "Bad named entity: qfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&qfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔮",
+ "description": "Named entity: qfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd2e"
+ ]
+ ]
+ },
+ {
+ "input": "&qint",
+ "description": "Bad named entity: qint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&qint"
+ ]
+ ]
+ },
+ {
+ "input": "⨌",
+ "description": "Named entity: qint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a0c"
+ ]
+ ]
+ },
+ {
+ "input": "&qopf",
+ "description": "Bad named entity: qopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&qopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕢",
+ "description": "Named entity: qopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd62"
+ ]
+ ]
+ },
+ {
+ "input": "&qprime",
+ "description": "Bad named entity: qprime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&qprime"
+ ]
+ ]
+ },
+ {
+ "input": "⁗",
+ "description": "Named entity: qprime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2057"
+ ]
+ ]
+ },
+ {
+ "input": "&qscr",
+ "description": "Bad named entity: qscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&qscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓆",
+ "description": "Named entity: qscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc6"
+ ]
+ ]
+ },
+ {
+ "input": "&quaternions",
+ "description": "Bad named entity: quaternions without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&quaternions"
+ ]
+ ]
+ },
+ {
+ "input": "ℍ",
+ "description": "Named entity: quaternions; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u210d"
+ ]
+ ]
+ },
+ {
+ "input": "&quatint",
+ "description": "Bad named entity: quatint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&quatint"
+ ]
+ ]
+ },
+ {
+ "input": "⨖",
+ "description": "Named entity: quatint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a16"
+ ]
+ ]
+ },
+ {
+ "input": "&quest",
+ "description": "Bad named entity: quest without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&quest"
+ ]
+ ]
+ },
+ {
+ "input": "?",
+ "description": "Named entity: quest; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "?"
+ ]
+ ]
+ },
+ {
+ "input": "&questeq",
+ "description": "Bad named entity: questeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&questeq"
+ ]
+ ]
+ },
+ {
+ "input": "≟",
+ "description": "Named entity: questeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u225f"
+ ]
+ ]
+ },
+ {
+ "input": """,
+ "description": "Named entity: quot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\""
+ ]
+ ]
+ },
+ {
+ "input": """,
+ "description": "Named entity: quot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\""
+ ]
+ ]
+ },
+ {
+ "input": "&rAarr",
+ "description": "Bad named entity: rAarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rAarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇛",
+ "description": "Named entity: rAarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21db"
+ ]
+ ]
+ },
+ {
+ "input": "&rArr",
+ "description": "Bad named entity: rArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇒",
+ "description": "Named entity: rArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d2"
+ ]
+ ]
+ },
+ {
+ "input": "&rAtail",
+ "description": "Bad named entity: rAtail without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rAtail"
+ ]
+ ]
+ },
+ {
+ "input": "⤜",
+ "description": "Named entity: rAtail; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u291c"
+ ]
+ ]
+ },
+ {
+ "input": "&rBarr",
+ "description": "Bad named entity: rBarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rBarr"
+ ]
+ ]
+ },
+ {
+ "input": "⤏",
+ "description": "Named entity: rBarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u290f"
+ ]
+ ]
+ },
+ {
+ "input": "&rHar",
+ "description": "Bad named entity: rHar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rHar"
+ ]
+ ]
+ },
+ {
+ "input": "⥤",
+ "description": "Named entity: rHar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2964"
+ ]
+ ]
+ },
+ {
+ "input": "&race",
+ "description": "Bad named entity: race without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&race"
+ ]
+ ]
+ },
+ {
+ "input": "∽̱",
+ "description": "Named entity: race; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223d\u0331"
+ ]
+ ]
+ },
+ {
+ "input": "&racute",
+ "description": "Bad named entity: racute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&racute"
+ ]
+ ]
+ },
+ {
+ "input": "ŕ",
+ "description": "Named entity: racute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0155"
+ ]
+ ]
+ },
+ {
+ "input": "&radic",
+ "description": "Bad named entity: radic without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&radic"
+ ]
+ ]
+ },
+ {
+ "input": "√",
+ "description": "Named entity: radic; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221a"
+ ]
+ ]
+ },
+ {
+ "input": "&raemptyv",
+ "description": "Bad named entity: raemptyv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&raemptyv"
+ ]
+ ]
+ },
+ {
+ "input": "⦳",
+ "description": "Named entity: raemptyv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29b3"
+ ]
+ ]
+ },
+ {
+ "input": "&rang",
+ "description": "Bad named entity: rang without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rang"
+ ]
+ ]
+ },
+ {
+ "input": "⟩",
+ "description": "Named entity: rang; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e9"
+ ]
+ ]
+ },
+ {
+ "input": "&rangd",
+ "description": "Bad named entity: rangd without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rangd"
+ ]
+ ]
+ },
+ {
+ "input": "⦒",
+ "description": "Named entity: rangd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2992"
+ ]
+ ]
+ },
+ {
+ "input": "&range",
+ "description": "Bad named entity: range without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&range"
+ ]
+ ]
+ },
+ {
+ "input": "⦥",
+ "description": "Named entity: range; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29a5"
+ ]
+ ]
+ },
+ {
+ "input": "&rangle",
+ "description": "Bad named entity: rangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rangle"
+ ]
+ ]
+ },
+ {
+ "input": "⟩",
+ "description": "Named entity: rangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e9"
+ ]
+ ]
+ },
+ {
+ "input": "»",
+ "description": "Named entity: raquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00bb"
+ ]
+ ]
+ },
+ {
+ "input": "»",
+ "description": "Named entity: raquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00bb"
+ ]
+ ]
+ },
+ {
+ "input": "&rarr",
+ "description": "Bad named entity: rarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarr"
+ ]
+ ]
+ },
+ {
+ "input": "→",
+ "description": "Named entity: rarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2192"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrap",
+ "description": "Bad named entity: rarrap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrap"
+ ]
+ ]
+ },
+ {
+ "input": "⥵",
+ "description": "Named entity: rarrap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2975"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrb",
+ "description": "Bad named entity: rarrb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrb"
+ ]
+ ]
+ },
+ {
+ "input": "⇥",
+ "description": "Named entity: rarrb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21e5"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrbfs",
+ "description": "Bad named entity: rarrbfs without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrbfs"
+ ]
+ ]
+ },
+ {
+ "input": "⤠",
+ "description": "Named entity: rarrbfs; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2920"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrc",
+ "description": "Bad named entity: rarrc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrc"
+ ]
+ ]
+ },
+ {
+ "input": "⤳",
+ "description": "Named entity: rarrc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2933"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrfs",
+ "description": "Bad named entity: rarrfs without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrfs"
+ ]
+ ]
+ },
+ {
+ "input": "⤞",
+ "description": "Named entity: rarrfs; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u291e"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrhk",
+ "description": "Bad named entity: rarrhk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrhk"
+ ]
+ ]
+ },
+ {
+ "input": "↪",
+ "description": "Named entity: rarrhk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21aa"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrlp",
+ "description": "Bad named entity: rarrlp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrlp"
+ ]
+ ]
+ },
+ {
+ "input": "↬",
+ "description": "Named entity: rarrlp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21ac"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrpl",
+ "description": "Bad named entity: rarrpl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrpl"
+ ]
+ ]
+ },
+ {
+ "input": "⥅",
+ "description": "Named entity: rarrpl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2945"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrsim",
+ "description": "Bad named entity: rarrsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrsim"
+ ]
+ ]
+ },
+ {
+ "input": "⥴",
+ "description": "Named entity: rarrsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2974"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrtl",
+ "description": "Bad named entity: rarrtl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrtl"
+ ]
+ ]
+ },
+ {
+ "input": "↣",
+ "description": "Named entity: rarrtl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a3"
+ ]
+ ]
+ },
+ {
+ "input": "&rarrw",
+ "description": "Bad named entity: rarrw without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rarrw"
+ ]
+ ]
+ },
+ {
+ "input": "↝",
+ "description": "Named entity: rarrw; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219d"
+ ]
+ ]
+ },
+ {
+ "input": "&ratail",
+ "description": "Bad named entity: ratail without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ratail"
+ ]
+ ]
+ },
+ {
+ "input": "⤚",
+ "description": "Named entity: ratail; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u291a"
+ ]
+ ]
+ },
+ {
+ "input": "&ratio",
+ "description": "Bad named entity: ratio without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ratio"
+ ]
+ ]
+ },
+ {
+ "input": "∶",
+ "description": "Named entity: ratio; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2236"
+ ]
+ ]
+ },
+ {
+ "input": "&rationals",
+ "description": "Bad named entity: rationals without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rationals"
+ ]
+ ]
+ },
+ {
+ "input": "ℚ",
+ "description": "Named entity: rationals; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211a"
+ ]
+ ]
+ },
+ {
+ "input": "&rbarr",
+ "description": "Bad named entity: rbarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rbarr"
+ ]
+ ]
+ },
+ {
+ "input": "⤍",
+ "description": "Named entity: rbarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u290d"
+ ]
+ ]
+ },
+ {
+ "input": "&rbbrk",
+ "description": "Bad named entity: rbbrk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rbbrk"
+ ]
+ ]
+ },
+ {
+ "input": "❳",
+ "description": "Named entity: rbbrk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2773"
+ ]
+ ]
+ },
+ {
+ "input": "&rbrace",
+ "description": "Bad named entity: rbrace without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rbrace"
+ ]
+ ]
+ },
+ {
+ "input": "}",
+ "description": "Named entity: rbrace; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "}"
+ ]
+ ]
+ },
+ {
+ "input": "&rbrack",
+ "description": "Bad named entity: rbrack without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rbrack"
+ ]
+ ]
+ },
+ {
+ "input": "]",
+ "description": "Named entity: rbrack; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "]"
+ ]
+ ]
+ },
+ {
+ "input": "&rbrke",
+ "description": "Bad named entity: rbrke without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rbrke"
+ ]
+ ]
+ },
+ {
+ "input": "⦌",
+ "description": "Named entity: rbrke; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u298c"
+ ]
+ ]
+ },
+ {
+ "input": "&rbrksld",
+ "description": "Bad named entity: rbrksld without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rbrksld"
+ ]
+ ]
+ },
+ {
+ "input": "⦎",
+ "description": "Named entity: rbrksld; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u298e"
+ ]
+ ]
+ },
+ {
+ "input": "&rbrkslu",
+ "description": "Bad named entity: rbrkslu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rbrkslu"
+ ]
+ ]
+ },
+ {
+ "input": "⦐",
+ "description": "Named entity: rbrkslu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2990"
+ ]
+ ]
+ },
+ {
+ "input": "&rcaron",
+ "description": "Bad named entity: rcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rcaron"
+ ]
+ ]
+ },
+ {
+ "input": "ř",
+ "description": "Named entity: rcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0159"
+ ]
+ ]
+ },
+ {
+ "input": "&rcedil",
+ "description": "Bad named entity: rcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rcedil"
+ ]
+ ]
+ },
+ {
+ "input": "ŗ",
+ "description": "Named entity: rcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0157"
+ ]
+ ]
+ },
+ {
+ "input": "&rceil",
+ "description": "Bad named entity: rceil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rceil"
+ ]
+ ]
+ },
+ {
+ "input": "⌉",
+ "description": "Named entity: rceil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2309"
+ ]
+ ]
+ },
+ {
+ "input": "&rcub",
+ "description": "Bad named entity: rcub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rcub"
+ ]
+ ]
+ },
+ {
+ "input": "}",
+ "description": "Named entity: rcub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "}"
+ ]
+ ]
+ },
+ {
+ "input": "&rcy",
+ "description": "Bad named entity: rcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rcy"
+ ]
+ ]
+ },
+ {
+ "input": "р",
+ "description": "Named entity: rcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0440"
+ ]
+ ]
+ },
+ {
+ "input": "&rdca",
+ "description": "Bad named entity: rdca without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rdca"
+ ]
+ ]
+ },
+ {
+ "input": "⤷",
+ "description": "Named entity: rdca; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2937"
+ ]
+ ]
+ },
+ {
+ "input": "&rdldhar",
+ "description": "Bad named entity: rdldhar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rdldhar"
+ ]
+ ]
+ },
+ {
+ "input": "⥩",
+ "description": "Named entity: rdldhar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2969"
+ ]
+ ]
+ },
+ {
+ "input": "&rdquo",
+ "description": "Bad named entity: rdquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rdquo"
+ ]
+ ]
+ },
+ {
+ "input": "”",
+ "description": "Named entity: rdquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201d"
+ ]
+ ]
+ },
+ {
+ "input": "&rdquor",
+ "description": "Bad named entity: rdquor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rdquor"
+ ]
+ ]
+ },
+ {
+ "input": "”",
+ "description": "Named entity: rdquor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201d"
+ ]
+ ]
+ },
+ {
+ "input": "&rdsh",
+ "description": "Bad named entity: rdsh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rdsh"
+ ]
+ ]
+ },
+ {
+ "input": "↳",
+ "description": "Named entity: rdsh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b3"
+ ]
+ ]
+ },
+ {
+ "input": "&real",
+ "description": "Bad named entity: real without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&real"
+ ]
+ ]
+ },
+ {
+ "input": "ℜ",
+ "description": "Named entity: real; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211c"
+ ]
+ ]
+ },
+ {
+ "input": "&realine",
+ "description": "Bad named entity: realine without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&realine"
+ ]
+ ]
+ },
+ {
+ "input": "ℛ",
+ "description": "Named entity: realine; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211b"
+ ]
+ ]
+ },
+ {
+ "input": "&realpart",
+ "description": "Bad named entity: realpart without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&realpart"
+ ]
+ ]
+ },
+ {
+ "input": "ℜ",
+ "description": "Named entity: realpart; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211c"
+ ]
+ ]
+ },
+ {
+ "input": "&reals",
+ "description": "Bad named entity: reals without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&reals"
+ ]
+ ]
+ },
+ {
+ "input": "ℝ",
+ "description": "Named entity: reals; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211d"
+ ]
+ ]
+ },
+ {
+ "input": "&rect",
+ "description": "Bad named entity: rect without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rect"
+ ]
+ ]
+ },
+ {
+ "input": "▭",
+ "description": "Named entity: rect; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25ad"
+ ]
+ ]
+ },
+ {
+ "input": "®",
+ "description": "Named entity: reg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ae"
+ ]
+ ]
+ },
+ {
+ "input": "®",
+ "description": "Named entity: reg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ae"
+ ]
+ ]
+ },
+ {
+ "input": "&rfisht",
+ "description": "Bad named entity: rfisht without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rfisht"
+ ]
+ ]
+ },
+ {
+ "input": "⥽",
+ "description": "Named entity: rfisht; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u297d"
+ ]
+ ]
+ },
+ {
+ "input": "&rfloor",
+ "description": "Bad named entity: rfloor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rfloor"
+ ]
+ ]
+ },
+ {
+ "input": "⌋",
+ "description": "Named entity: rfloor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u230b"
+ ]
+ ]
+ },
+ {
+ "input": "&rfr",
+ "description": "Bad named entity: rfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔯",
+ "description": "Named entity: rfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd2f"
+ ]
+ ]
+ },
+ {
+ "input": "&rhard",
+ "description": "Bad named entity: rhard without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rhard"
+ ]
+ ]
+ },
+ {
+ "input": "⇁",
+ "description": "Named entity: rhard; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c1"
+ ]
+ ]
+ },
+ {
+ "input": "&rharu",
+ "description": "Bad named entity: rharu without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rharu"
+ ]
+ ]
+ },
+ {
+ "input": "⇀",
+ "description": "Named entity: rharu; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c0"
+ ]
+ ]
+ },
+ {
+ "input": "&rharul",
+ "description": "Bad named entity: rharul without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rharul"
+ ]
+ ]
+ },
+ {
+ "input": "⥬",
+ "description": "Named entity: rharul; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u296c"
+ ]
+ ]
+ },
+ {
+ "input": "&rho",
+ "description": "Bad named entity: rho without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rho"
+ ]
+ ]
+ },
+ {
+ "input": "ρ",
+ "description": "Named entity: rho; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c1"
+ ]
+ ]
+ },
+ {
+ "input": "&rhov",
+ "description": "Bad named entity: rhov without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rhov"
+ ]
+ ]
+ },
+ {
+ "input": "ϱ",
+ "description": "Named entity: rhov; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f1"
+ ]
+ ]
+ },
+ {
+ "input": "&rightarrow",
+ "description": "Bad named entity: rightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "→",
+ "description": "Named entity: rightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2192"
+ ]
+ ]
+ },
+ {
+ "input": "&rightarrowtail",
+ "description": "Bad named entity: rightarrowtail without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightarrowtail"
+ ]
+ ]
+ },
+ {
+ "input": "↣",
+ "description": "Named entity: rightarrowtail; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a3"
+ ]
+ ]
+ },
+ {
+ "input": "&rightharpoondown",
+ "description": "Bad named entity: rightharpoondown without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightharpoondown"
+ ]
+ ]
+ },
+ {
+ "input": "⇁",
+ "description": "Named entity: rightharpoondown; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c1"
+ ]
+ ]
+ },
+ {
+ "input": "&rightharpoonup",
+ "description": "Bad named entity: rightharpoonup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightharpoonup"
+ ]
+ ]
+ },
+ {
+ "input": "⇀",
+ "description": "Named entity: rightharpoonup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c0"
+ ]
+ ]
+ },
+ {
+ "input": "&rightleftarrows",
+ "description": "Bad named entity: rightleftarrows without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightleftarrows"
+ ]
+ ]
+ },
+ {
+ "input": "⇄",
+ "description": "Named entity: rightleftarrows; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c4"
+ ]
+ ]
+ },
+ {
+ "input": "&rightleftharpoons",
+ "description": "Bad named entity: rightleftharpoons without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightleftharpoons"
+ ]
+ ]
+ },
+ {
+ "input": "⇌",
+ "description": "Named entity: rightleftharpoons; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cc"
+ ]
+ ]
+ },
+ {
+ "input": "&rightrightarrows",
+ "description": "Bad named entity: rightrightarrows without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightrightarrows"
+ ]
+ ]
+ },
+ {
+ "input": "⇉",
+ "description": "Named entity: rightrightarrows; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c9"
+ ]
+ ]
+ },
+ {
+ "input": "&rightsquigarrow",
+ "description": "Bad named entity: rightsquigarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightsquigarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↝",
+ "description": "Named entity: rightsquigarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219d"
+ ]
+ ]
+ },
+ {
+ "input": "&rightthreetimes",
+ "description": "Bad named entity: rightthreetimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rightthreetimes"
+ ]
+ ]
+ },
+ {
+ "input": "⋌",
+ "description": "Named entity: rightthreetimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22cc"
+ ]
+ ]
+ },
+ {
+ "input": "&ring",
+ "description": "Bad named entity: ring without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ring"
+ ]
+ ]
+ },
+ {
+ "input": "˚",
+ "description": "Named entity: ring; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02da"
+ ]
+ ]
+ },
+ {
+ "input": "&risingdotseq",
+ "description": "Bad named entity: risingdotseq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&risingdotseq"
+ ]
+ ]
+ },
+ {
+ "input": "≓",
+ "description": "Named entity: risingdotseq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2253"
+ ]
+ ]
+ },
+ {
+ "input": "&rlarr",
+ "description": "Bad named entity: rlarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rlarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇄",
+ "description": "Named entity: rlarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c4"
+ ]
+ ]
+ },
+ {
+ "input": "&rlhar",
+ "description": "Bad named entity: rlhar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rlhar"
+ ]
+ ]
+ },
+ {
+ "input": "⇌",
+ "description": "Named entity: rlhar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21cc"
+ ]
+ ]
+ },
+ {
+ "input": "&rlm",
+ "description": "Bad named entity: rlm without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rlm"
+ ]
+ ]
+ },
+ {
+ "input": "‏",
+ "description": "Named entity: rlm; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200f"
+ ]
+ ]
+ },
+ {
+ "input": "&rmoust",
+ "description": "Bad named entity: rmoust without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rmoust"
+ ]
+ ]
+ },
+ {
+ "input": "⎱",
+ "description": "Named entity: rmoust; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b1"
+ ]
+ ]
+ },
+ {
+ "input": "&rmoustache",
+ "description": "Bad named entity: rmoustache without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rmoustache"
+ ]
+ ]
+ },
+ {
+ "input": "⎱",
+ "description": "Named entity: rmoustache; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b1"
+ ]
+ ]
+ },
+ {
+ "input": "&rnmid",
+ "description": "Bad named entity: rnmid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rnmid"
+ ]
+ ]
+ },
+ {
+ "input": "⫮",
+ "description": "Named entity: rnmid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aee"
+ ]
+ ]
+ },
+ {
+ "input": "&roang",
+ "description": "Bad named entity: roang without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&roang"
+ ]
+ ]
+ },
+ {
+ "input": "⟭",
+ "description": "Named entity: roang; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27ed"
+ ]
+ ]
+ },
+ {
+ "input": "&roarr",
+ "description": "Bad named entity: roarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&roarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇾",
+ "description": "Named entity: roarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21fe"
+ ]
+ ]
+ },
+ {
+ "input": "&robrk",
+ "description": "Bad named entity: robrk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&robrk"
+ ]
+ ]
+ },
+ {
+ "input": "⟧",
+ "description": "Named entity: robrk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27e7"
+ ]
+ ]
+ },
+ {
+ "input": "&ropar",
+ "description": "Bad named entity: ropar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ropar"
+ ]
+ ]
+ },
+ {
+ "input": "⦆",
+ "description": "Named entity: ropar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2986"
+ ]
+ ]
+ },
+ {
+ "input": "&ropf",
+ "description": "Bad named entity: ropf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ropf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕣",
+ "description": "Named entity: ropf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd63"
+ ]
+ ]
+ },
+ {
+ "input": "&roplus",
+ "description": "Bad named entity: roplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&roplus"
+ ]
+ ]
+ },
+ {
+ "input": "⨮",
+ "description": "Named entity: roplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a2e"
+ ]
+ ]
+ },
+ {
+ "input": "&rotimes",
+ "description": "Bad named entity: rotimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rotimes"
+ ]
+ ]
+ },
+ {
+ "input": "⨵",
+ "description": "Named entity: rotimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a35"
+ ]
+ ]
+ },
+ {
+ "input": "&rpar",
+ "description": "Bad named entity: rpar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rpar"
+ ]
+ ]
+ },
+ {
+ "input": ")",
+ "description": "Named entity: rpar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ ")"
+ ]
+ ]
+ },
+ {
+ "input": "&rpargt",
+ "description": "Bad named entity: rpargt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rpargt"
+ ]
+ ]
+ },
+ {
+ "input": "⦔",
+ "description": "Named entity: rpargt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2994"
+ ]
+ ]
+ },
+ {
+ "input": "&rppolint",
+ "description": "Bad named entity: rppolint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rppolint"
+ ]
+ ]
+ },
+ {
+ "input": "⨒",
+ "description": "Named entity: rppolint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a12"
+ ]
+ ]
+ },
+ {
+ "input": "&rrarr",
+ "description": "Bad named entity: rrarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rrarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇉",
+ "description": "Named entity: rrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c9"
+ ]
+ ]
+ },
+ {
+ "input": "&rsaquo",
+ "description": "Bad named entity: rsaquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rsaquo"
+ ]
+ ]
+ },
+ {
+ "input": "›",
+ "description": "Named entity: rsaquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u203a"
+ ]
+ ]
+ },
+ {
+ "input": "&rscr",
+ "description": "Bad named entity: rscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓇",
+ "description": "Named entity: rscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc7"
+ ]
+ ]
+ },
+ {
+ "input": "&rsh",
+ "description": "Bad named entity: rsh without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rsh"
+ ]
+ ]
+ },
+ {
+ "input": "↱",
+ "description": "Named entity: rsh; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21b1"
+ ]
+ ]
+ },
+ {
+ "input": "&rsqb",
+ "description": "Bad named entity: rsqb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rsqb"
+ ]
+ ]
+ },
+ {
+ "input": "]",
+ "description": "Named entity: rsqb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "]"
+ ]
+ ]
+ },
+ {
+ "input": "&rsquo",
+ "description": "Bad named entity: rsquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rsquo"
+ ]
+ ]
+ },
+ {
+ "input": "’",
+ "description": "Named entity: rsquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2019"
+ ]
+ ]
+ },
+ {
+ "input": "&rsquor",
+ "description": "Bad named entity: rsquor without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rsquor"
+ ]
+ ]
+ },
+ {
+ "input": "’",
+ "description": "Named entity: rsquor; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2019"
+ ]
+ ]
+ },
+ {
+ "input": "&rthree",
+ "description": "Bad named entity: rthree without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rthree"
+ ]
+ ]
+ },
+ {
+ "input": "⋌",
+ "description": "Named entity: rthree; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22cc"
+ ]
+ ]
+ },
+ {
+ "input": "&rtimes",
+ "description": "Bad named entity: rtimes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rtimes"
+ ]
+ ]
+ },
+ {
+ "input": "⋊",
+ "description": "Named entity: rtimes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ca"
+ ]
+ ]
+ },
+ {
+ "input": "&rtri",
+ "description": "Bad named entity: rtri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rtri"
+ ]
+ ]
+ },
+ {
+ "input": "▹",
+ "description": "Named entity: rtri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b9"
+ ]
+ ]
+ },
+ {
+ "input": "&rtrie",
+ "description": "Bad named entity: rtrie without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rtrie"
+ ]
+ ]
+ },
+ {
+ "input": "⊵",
+ "description": "Named entity: rtrie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b5"
+ ]
+ ]
+ },
+ {
+ "input": "&rtrif",
+ "description": "Bad named entity: rtrif without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rtrif"
+ ]
+ ]
+ },
+ {
+ "input": "▸",
+ "description": "Named entity: rtrif; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b8"
+ ]
+ ]
+ },
+ {
+ "input": "&rtriltri",
+ "description": "Bad named entity: rtriltri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rtriltri"
+ ]
+ ]
+ },
+ {
+ "input": "⧎",
+ "description": "Named entity: rtriltri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29ce"
+ ]
+ ]
+ },
+ {
+ "input": "&ruluhar",
+ "description": "Bad named entity: ruluhar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ruluhar"
+ ]
+ ]
+ },
+ {
+ "input": "⥨",
+ "description": "Named entity: ruluhar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2968"
+ ]
+ ]
+ },
+ {
+ "input": "&rx",
+ "description": "Bad named entity: rx without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&rx"
+ ]
+ ]
+ },
+ {
+ "input": "℞",
+ "description": "Named entity: rx; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u211e"
+ ]
+ ]
+ },
+ {
+ "input": "&sacute",
+ "description": "Bad named entity: sacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sacute"
+ ]
+ ]
+ },
+ {
+ "input": "ś",
+ "description": "Named entity: sacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u015b"
+ ]
+ ]
+ },
+ {
+ "input": "&sbquo",
+ "description": "Bad named entity: sbquo without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sbquo"
+ ]
+ ]
+ },
+ {
+ "input": "‚",
+ "description": "Named entity: sbquo; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u201a"
+ ]
+ ]
+ },
+ {
+ "input": "&sc",
+ "description": "Bad named entity: sc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sc"
+ ]
+ ]
+ },
+ {
+ "input": "≻",
+ "description": "Named entity: sc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227b"
+ ]
+ ]
+ },
+ {
+ "input": "&scE",
+ "description": "Bad named entity: scE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scE"
+ ]
+ ]
+ },
+ {
+ "input": "⪴",
+ "description": "Named entity: scE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab4"
+ ]
+ ]
+ },
+ {
+ "input": "&scap",
+ "description": "Bad named entity: scap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scap"
+ ]
+ ]
+ },
+ {
+ "input": "⪸",
+ "description": "Named entity: scap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab8"
+ ]
+ ]
+ },
+ {
+ "input": "&scaron",
+ "description": "Bad named entity: scaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scaron"
+ ]
+ ]
+ },
+ {
+ "input": "š",
+ "description": "Named entity: scaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0161"
+ ]
+ ]
+ },
+ {
+ "input": "&sccue",
+ "description": "Bad named entity: sccue without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sccue"
+ ]
+ ]
+ },
+ {
+ "input": "≽",
+ "description": "Named entity: sccue; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227d"
+ ]
+ ]
+ },
+ {
+ "input": "&sce",
+ "description": "Bad named entity: sce without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sce"
+ ]
+ ]
+ },
+ {
+ "input": "⪰",
+ "description": "Named entity: sce; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab0"
+ ]
+ ]
+ },
+ {
+ "input": "&scedil",
+ "description": "Bad named entity: scedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scedil"
+ ]
+ ]
+ },
+ {
+ "input": "ş",
+ "description": "Named entity: scedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u015f"
+ ]
+ ]
+ },
+ {
+ "input": "&scirc",
+ "description": "Bad named entity: scirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scirc"
+ ]
+ ]
+ },
+ {
+ "input": "ŝ",
+ "description": "Named entity: scirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u015d"
+ ]
+ ]
+ },
+ {
+ "input": "&scnE",
+ "description": "Bad named entity: scnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scnE"
+ ]
+ ]
+ },
+ {
+ "input": "⪶",
+ "description": "Named entity: scnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab6"
+ ]
+ ]
+ },
+ {
+ "input": "&scnap",
+ "description": "Bad named entity: scnap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scnap"
+ ]
+ ]
+ },
+ {
+ "input": "⪺",
+ "description": "Named entity: scnap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aba"
+ ]
+ ]
+ },
+ {
+ "input": "&scnsim",
+ "description": "Bad named entity: scnsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scnsim"
+ ]
+ ]
+ },
+ {
+ "input": "⋩",
+ "description": "Named entity: scnsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e9"
+ ]
+ ]
+ },
+ {
+ "input": "&scpolint",
+ "description": "Bad named entity: scpolint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scpolint"
+ ]
+ ]
+ },
+ {
+ "input": "⨓",
+ "description": "Named entity: scpolint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a13"
+ ]
+ ]
+ },
+ {
+ "input": "&scsim",
+ "description": "Bad named entity: scsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scsim"
+ ]
+ ]
+ },
+ {
+ "input": "≿",
+ "description": "Named entity: scsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227f"
+ ]
+ ]
+ },
+ {
+ "input": "&scy",
+ "description": "Bad named entity: scy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&scy"
+ ]
+ ]
+ },
+ {
+ "input": "с",
+ "description": "Named entity: scy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0441"
+ ]
+ ]
+ },
+ {
+ "input": "&sdot",
+ "description": "Bad named entity: sdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sdot"
+ ]
+ ]
+ },
+ {
+ "input": "⋅",
+ "description": "Named entity: sdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c5"
+ ]
+ ]
+ },
+ {
+ "input": "&sdotb",
+ "description": "Bad named entity: sdotb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sdotb"
+ ]
+ ]
+ },
+ {
+ "input": "⊡",
+ "description": "Named entity: sdotb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a1"
+ ]
+ ]
+ },
+ {
+ "input": "&sdote",
+ "description": "Bad named entity: sdote without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sdote"
+ ]
+ ]
+ },
+ {
+ "input": "⩦",
+ "description": "Named entity: sdote; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a66"
+ ]
+ ]
+ },
+ {
+ "input": "&seArr",
+ "description": "Bad named entity: seArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&seArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇘",
+ "description": "Named entity: seArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d8"
+ ]
+ ]
+ },
+ {
+ "input": "&searhk",
+ "description": "Bad named entity: searhk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&searhk"
+ ]
+ ]
+ },
+ {
+ "input": "⤥",
+ "description": "Named entity: searhk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2925"
+ ]
+ ]
+ },
+ {
+ "input": "&searr",
+ "description": "Bad named entity: searr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&searr"
+ ]
+ ]
+ },
+ {
+ "input": "↘",
+ "description": "Named entity: searr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2198"
+ ]
+ ]
+ },
+ {
+ "input": "&searrow",
+ "description": "Bad named entity: searrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&searrow"
+ ]
+ ]
+ },
+ {
+ "input": "↘",
+ "description": "Named entity: searrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2198"
+ ]
+ ]
+ },
+ {
+ "input": "§",
+ "description": "Named entity: sect without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a7"
+ ]
+ ]
+ },
+ {
+ "input": "§",
+ "description": "Named entity: sect; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a7"
+ ]
+ ]
+ },
+ {
+ "input": "&semi",
+ "description": "Bad named entity: semi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&semi"
+ ]
+ ]
+ },
+ {
+ "input": ";",
+ "description": "Named entity: semi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ ";"
+ ]
+ ]
+ },
+ {
+ "input": "&seswar",
+ "description": "Bad named entity: seswar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&seswar"
+ ]
+ ]
+ },
+ {
+ "input": "⤩",
+ "description": "Named entity: seswar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2929"
+ ]
+ ]
+ },
+ {
+ "input": "&setminus",
+ "description": "Bad named entity: setminus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&setminus"
+ ]
+ ]
+ },
+ {
+ "input": "∖",
+ "description": "Named entity: setminus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2216"
+ ]
+ ]
+ },
+ {
+ "input": "&setmn",
+ "description": "Bad named entity: setmn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&setmn"
+ ]
+ ]
+ },
+ {
+ "input": "∖",
+ "description": "Named entity: setmn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2216"
+ ]
+ ]
+ },
+ {
+ "input": "&sext",
+ "description": "Bad named entity: sext without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sext"
+ ]
+ ]
+ },
+ {
+ "input": "✶",
+ "description": "Named entity: sext; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2736"
+ ]
+ ]
+ },
+ {
+ "input": "&sfr",
+ "description": "Bad named entity: sfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔰",
+ "description": "Named entity: sfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd30"
+ ]
+ ]
+ },
+ {
+ "input": "&sfrown",
+ "description": "Bad named entity: sfrown without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sfrown"
+ ]
+ ]
+ },
+ {
+ "input": "⌢",
+ "description": "Named entity: sfrown; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2322"
+ ]
+ ]
+ },
+ {
+ "input": "&sharp",
+ "description": "Bad named entity: sharp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sharp"
+ ]
+ ]
+ },
+ {
+ "input": "♯",
+ "description": "Named entity: sharp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u266f"
+ ]
+ ]
+ },
+ {
+ "input": "&shchcy",
+ "description": "Bad named entity: shchcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&shchcy"
+ ]
+ ]
+ },
+ {
+ "input": "щ",
+ "description": "Named entity: shchcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0449"
+ ]
+ ]
+ },
+ {
+ "input": "&shcy",
+ "description": "Bad named entity: shcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&shcy"
+ ]
+ ]
+ },
+ {
+ "input": "ш",
+ "description": "Named entity: shcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0448"
+ ]
+ ]
+ },
+ {
+ "input": "&shortmid",
+ "description": "Bad named entity: shortmid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&shortmid"
+ ]
+ ]
+ },
+ {
+ "input": "∣",
+ "description": "Named entity: shortmid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2223"
+ ]
+ ]
+ },
+ {
+ "input": "&shortparallel",
+ "description": "Bad named entity: shortparallel without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&shortparallel"
+ ]
+ ]
+ },
+ {
+ "input": "∥",
+ "description": "Named entity: shortparallel; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2225"
+ ]
+ ]
+ },
+ {
+ "input": "­",
+ "description": "Named entity: shy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ad"
+ ]
+ ]
+ },
+ {
+ "input": "­",
+ "description": "Named entity: shy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ad"
+ ]
+ ]
+ },
+ {
+ "input": "&sigma",
+ "description": "Bad named entity: sigma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sigma"
+ ]
+ ]
+ },
+ {
+ "input": "σ",
+ "description": "Named entity: sigma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c3"
+ ]
+ ]
+ },
+ {
+ "input": "&sigmaf",
+ "description": "Bad named entity: sigmaf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sigmaf"
+ ]
+ ]
+ },
+ {
+ "input": "ς",
+ "description": "Named entity: sigmaf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c2"
+ ]
+ ]
+ },
+ {
+ "input": "&sigmav",
+ "description": "Bad named entity: sigmav without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sigmav"
+ ]
+ ]
+ },
+ {
+ "input": "ς",
+ "description": "Named entity: sigmav; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c2"
+ ]
+ ]
+ },
+ {
+ "input": "&sim",
+ "description": "Bad named entity: sim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sim"
+ ]
+ ]
+ },
+ {
+ "input": "∼",
+ "description": "Named entity: sim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223c"
+ ]
+ ]
+ },
+ {
+ "input": "&simdot",
+ "description": "Bad named entity: simdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&simdot"
+ ]
+ ]
+ },
+ {
+ "input": "⩪",
+ "description": "Named entity: simdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a6a"
+ ]
+ ]
+ },
+ {
+ "input": "&sime",
+ "description": "Bad named entity: sime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sime"
+ ]
+ ]
+ },
+ {
+ "input": "≃",
+ "description": "Named entity: sime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2243"
+ ]
+ ]
+ },
+ {
+ "input": "&simeq",
+ "description": "Bad named entity: simeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&simeq"
+ ]
+ ]
+ },
+ {
+ "input": "≃",
+ "description": "Named entity: simeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2243"
+ ]
+ ]
+ },
+ {
+ "input": "&simg",
+ "description": "Bad named entity: simg without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&simg"
+ ]
+ ]
+ },
+ {
+ "input": "⪞",
+ "description": "Named entity: simg; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a9e"
+ ]
+ ]
+ },
+ {
+ "input": "&simgE",
+ "description": "Bad named entity: simgE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&simgE"
+ ]
+ ]
+ },
+ {
+ "input": "⪠",
+ "description": "Named entity: simgE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aa0"
+ ]
+ ]
+ },
+ {
+ "input": "&siml",
+ "description": "Bad named entity: siml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&siml"
+ ]
+ ]
+ },
+ {
+ "input": "⪝",
+ "description": "Named entity: siml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a9d"
+ ]
+ ]
+ },
+ {
+ "input": "&simlE",
+ "description": "Bad named entity: simlE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&simlE"
+ ]
+ ]
+ },
+ {
+ "input": "⪟",
+ "description": "Named entity: simlE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a9f"
+ ]
+ ]
+ },
+ {
+ "input": "&simne",
+ "description": "Bad named entity: simne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&simne"
+ ]
+ ]
+ },
+ {
+ "input": "≆",
+ "description": "Named entity: simne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2246"
+ ]
+ ]
+ },
+ {
+ "input": "&simplus",
+ "description": "Bad named entity: simplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&simplus"
+ ]
+ ]
+ },
+ {
+ "input": "⨤",
+ "description": "Named entity: simplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a24"
+ ]
+ ]
+ },
+ {
+ "input": "&simrarr",
+ "description": "Bad named entity: simrarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&simrarr"
+ ]
+ ]
+ },
+ {
+ "input": "⥲",
+ "description": "Named entity: simrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2972"
+ ]
+ ]
+ },
+ {
+ "input": "&slarr",
+ "description": "Bad named entity: slarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&slarr"
+ ]
+ ]
+ },
+ {
+ "input": "←",
+ "description": "Named entity: slarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2190"
+ ]
+ ]
+ },
+ {
+ "input": "&smallsetminus",
+ "description": "Bad named entity: smallsetminus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&smallsetminus"
+ ]
+ ]
+ },
+ {
+ "input": "∖",
+ "description": "Named entity: smallsetminus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2216"
+ ]
+ ]
+ },
+ {
+ "input": "&smashp",
+ "description": "Bad named entity: smashp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&smashp"
+ ]
+ ]
+ },
+ {
+ "input": "⨳",
+ "description": "Named entity: smashp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a33"
+ ]
+ ]
+ },
+ {
+ "input": "&smeparsl",
+ "description": "Bad named entity: smeparsl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&smeparsl"
+ ]
+ ]
+ },
+ {
+ "input": "⧤",
+ "description": "Named entity: smeparsl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29e4"
+ ]
+ ]
+ },
+ {
+ "input": "&smid",
+ "description": "Bad named entity: smid without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&smid"
+ ]
+ ]
+ },
+ {
+ "input": "∣",
+ "description": "Named entity: smid; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2223"
+ ]
+ ]
+ },
+ {
+ "input": "&smile",
+ "description": "Bad named entity: smile without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&smile"
+ ]
+ ]
+ },
+ {
+ "input": "⌣",
+ "description": "Named entity: smile; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2323"
+ ]
+ ]
+ },
+ {
+ "input": "&smt",
+ "description": "Bad named entity: smt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&smt"
+ ]
+ ]
+ },
+ {
+ "input": "⪪",
+ "description": "Named entity: smt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aaa"
+ ]
+ ]
+ },
+ {
+ "input": "&smte",
+ "description": "Bad named entity: smte without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&smte"
+ ]
+ ]
+ },
+ {
+ "input": "⪬",
+ "description": "Named entity: smte; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aac"
+ ]
+ ]
+ },
+ {
+ "input": "&smtes",
+ "description": "Bad named entity: smtes without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&smtes"
+ ]
+ ]
+ },
+ {
+ "input": "⪬︀",
+ "description": "Named entity: smtes; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aac\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&softcy",
+ "description": "Bad named entity: softcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&softcy"
+ ]
+ ]
+ },
+ {
+ "input": "ь",
+ "description": "Named entity: softcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u044c"
+ ]
+ ]
+ },
+ {
+ "input": "&sol",
+ "description": "Bad named entity: sol without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sol"
+ ]
+ ]
+ },
+ {
+ "input": "/",
+ "description": "Named entity: sol; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "/"
+ ]
+ ]
+ },
+ {
+ "input": "&solb",
+ "description": "Bad named entity: solb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&solb"
+ ]
+ ]
+ },
+ {
+ "input": "⧄",
+ "description": "Named entity: solb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29c4"
+ ]
+ ]
+ },
+ {
+ "input": "&solbar",
+ "description": "Bad named entity: solbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&solbar"
+ ]
+ ]
+ },
+ {
+ "input": "⌿",
+ "description": "Named entity: solbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u233f"
+ ]
+ ]
+ },
+ {
+ "input": "&sopf",
+ "description": "Bad named entity: sopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕤",
+ "description": "Named entity: sopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd64"
+ ]
+ ]
+ },
+ {
+ "input": "&spades",
+ "description": "Bad named entity: spades without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&spades"
+ ]
+ ]
+ },
+ {
+ "input": "♠",
+ "description": "Named entity: spades; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2660"
+ ]
+ ]
+ },
+ {
+ "input": "&spadesuit",
+ "description": "Bad named entity: spadesuit without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&spadesuit"
+ ]
+ ]
+ },
+ {
+ "input": "♠",
+ "description": "Named entity: spadesuit; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2660"
+ ]
+ ]
+ },
+ {
+ "input": "&spar",
+ "description": "Bad named entity: spar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&spar"
+ ]
+ ]
+ },
+ {
+ "input": "∥",
+ "description": "Named entity: spar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2225"
+ ]
+ ]
+ },
+ {
+ "input": "&sqcap",
+ "description": "Bad named entity: sqcap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqcap"
+ ]
+ ]
+ },
+ {
+ "input": "⊓",
+ "description": "Named entity: sqcap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2293"
+ ]
+ ]
+ },
+ {
+ "input": "&sqcaps",
+ "description": "Bad named entity: sqcaps without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqcaps"
+ ]
+ ]
+ },
+ {
+ "input": "⊓︀",
+ "description": "Named entity: sqcaps; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2293\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&sqcup",
+ "description": "Bad named entity: sqcup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqcup"
+ ]
+ ]
+ },
+ {
+ "input": "⊔",
+ "description": "Named entity: sqcup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2294"
+ ]
+ ]
+ },
+ {
+ "input": "&sqcups",
+ "description": "Bad named entity: sqcups without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqcups"
+ ]
+ ]
+ },
+ {
+ "input": "⊔︀",
+ "description": "Named entity: sqcups; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2294\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&sqsub",
+ "description": "Bad named entity: sqsub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqsub"
+ ]
+ ]
+ },
+ {
+ "input": "⊏",
+ "description": "Named entity: sqsub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228f"
+ ]
+ ]
+ },
+ {
+ "input": "&sqsube",
+ "description": "Bad named entity: sqsube without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqsube"
+ ]
+ ]
+ },
+ {
+ "input": "⊑",
+ "description": "Named entity: sqsube; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2291"
+ ]
+ ]
+ },
+ {
+ "input": "&sqsubset",
+ "description": "Bad named entity: sqsubset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqsubset"
+ ]
+ ]
+ },
+ {
+ "input": "⊏",
+ "description": "Named entity: sqsubset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228f"
+ ]
+ ]
+ },
+ {
+ "input": "&sqsubseteq",
+ "description": "Bad named entity: sqsubseteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqsubseteq"
+ ]
+ ]
+ },
+ {
+ "input": "⊑",
+ "description": "Named entity: sqsubseteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2291"
+ ]
+ ]
+ },
+ {
+ "input": "&sqsup",
+ "description": "Bad named entity: sqsup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqsup"
+ ]
+ ]
+ },
+ {
+ "input": "⊐",
+ "description": "Named entity: sqsup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2290"
+ ]
+ ]
+ },
+ {
+ "input": "&sqsupe",
+ "description": "Bad named entity: sqsupe without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqsupe"
+ ]
+ ]
+ },
+ {
+ "input": "⊒",
+ "description": "Named entity: sqsupe; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2292"
+ ]
+ ]
+ },
+ {
+ "input": "&sqsupset",
+ "description": "Bad named entity: sqsupset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqsupset"
+ ]
+ ]
+ },
+ {
+ "input": "⊐",
+ "description": "Named entity: sqsupset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2290"
+ ]
+ ]
+ },
+ {
+ "input": "&sqsupseteq",
+ "description": "Bad named entity: sqsupseteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sqsupseteq"
+ ]
+ ]
+ },
+ {
+ "input": "⊒",
+ "description": "Named entity: sqsupseteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2292"
+ ]
+ ]
+ },
+ {
+ "input": "&squ",
+ "description": "Bad named entity: squ without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&squ"
+ ]
+ ]
+ },
+ {
+ "input": "□",
+ "description": "Named entity: squ; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25a1"
+ ]
+ ]
+ },
+ {
+ "input": "&square",
+ "description": "Bad named entity: square without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&square"
+ ]
+ ]
+ },
+ {
+ "input": "□",
+ "description": "Named entity: square; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25a1"
+ ]
+ ]
+ },
+ {
+ "input": "&squarf",
+ "description": "Bad named entity: squarf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&squarf"
+ ]
+ ]
+ },
+ {
+ "input": "▪",
+ "description": "Named entity: squarf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25aa"
+ ]
+ ]
+ },
+ {
+ "input": "&squf",
+ "description": "Bad named entity: squf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&squf"
+ ]
+ ]
+ },
+ {
+ "input": "▪",
+ "description": "Named entity: squf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25aa"
+ ]
+ ]
+ },
+ {
+ "input": "&srarr",
+ "description": "Bad named entity: srarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&srarr"
+ ]
+ ]
+ },
+ {
+ "input": "→",
+ "description": "Named entity: srarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2192"
+ ]
+ ]
+ },
+ {
+ "input": "&sscr",
+ "description": "Bad named entity: sscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓈",
+ "description": "Named entity: sscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc8"
+ ]
+ ]
+ },
+ {
+ "input": "&ssetmn",
+ "description": "Bad named entity: ssetmn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ssetmn"
+ ]
+ ]
+ },
+ {
+ "input": "∖",
+ "description": "Named entity: ssetmn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2216"
+ ]
+ ]
+ },
+ {
+ "input": "&ssmile",
+ "description": "Bad named entity: ssmile without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ssmile"
+ ]
+ ]
+ },
+ {
+ "input": "⌣",
+ "description": "Named entity: ssmile; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2323"
+ ]
+ ]
+ },
+ {
+ "input": "&sstarf",
+ "description": "Bad named entity: sstarf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sstarf"
+ ]
+ ]
+ },
+ {
+ "input": "⋆",
+ "description": "Named entity: sstarf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c6"
+ ]
+ ]
+ },
+ {
+ "input": "&star",
+ "description": "Bad named entity: star without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&star"
+ ]
+ ]
+ },
+ {
+ "input": "☆",
+ "description": "Named entity: star; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2606"
+ ]
+ ]
+ },
+ {
+ "input": "&starf",
+ "description": "Bad named entity: starf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&starf"
+ ]
+ ]
+ },
+ {
+ "input": "★",
+ "description": "Named entity: starf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2605"
+ ]
+ ]
+ },
+ {
+ "input": "&straightepsilon",
+ "description": "Bad named entity: straightepsilon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&straightepsilon"
+ ]
+ ]
+ },
+ {
+ "input": "ϵ",
+ "description": "Named entity: straightepsilon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f5"
+ ]
+ ]
+ },
+ {
+ "input": "&straightphi",
+ "description": "Bad named entity: straightphi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&straightphi"
+ ]
+ ]
+ },
+ {
+ "input": "ϕ",
+ "description": "Named entity: straightphi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d5"
+ ]
+ ]
+ },
+ {
+ "input": "&strns",
+ "description": "Bad named entity: strns without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&strns"
+ ]
+ ]
+ },
+ {
+ "input": "¯",
+ "description": "Named entity: strns; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00af"
+ ]
+ ]
+ },
+ {
+ "input": "&sub",
+ "description": "Bad named entity: sub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sub"
+ ]
+ ]
+ },
+ {
+ "input": "⊂",
+ "description": "Named entity: sub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2282"
+ ]
+ ]
+ },
+ {
+ "input": "&subE",
+ "description": "Bad named entity: subE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subE"
+ ]
+ ]
+ },
+ {
+ "input": "⫅",
+ "description": "Named entity: subE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac5"
+ ]
+ ]
+ },
+ {
+ "input": "&subdot",
+ "description": "Bad named entity: subdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subdot"
+ ]
+ ]
+ },
+ {
+ "input": "⪽",
+ "description": "Named entity: subdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2abd"
+ ]
+ ]
+ },
+ {
+ "input": "&sube",
+ "description": "Bad named entity: sube without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sube"
+ ]
+ ]
+ },
+ {
+ "input": "⊆",
+ "description": "Named entity: sube; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2286"
+ ]
+ ]
+ },
+ {
+ "input": "&subedot",
+ "description": "Bad named entity: subedot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subedot"
+ ]
+ ]
+ },
+ {
+ "input": "⫃",
+ "description": "Named entity: subedot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac3"
+ ]
+ ]
+ },
+ {
+ "input": "&submult",
+ "description": "Bad named entity: submult without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&submult"
+ ]
+ ]
+ },
+ {
+ "input": "⫁",
+ "description": "Named entity: submult; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac1"
+ ]
+ ]
+ },
+ {
+ "input": "&subnE",
+ "description": "Bad named entity: subnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subnE"
+ ]
+ ]
+ },
+ {
+ "input": "⫋",
+ "description": "Named entity: subnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acb"
+ ]
+ ]
+ },
+ {
+ "input": "&subne",
+ "description": "Bad named entity: subne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subne"
+ ]
+ ]
+ },
+ {
+ "input": "⊊",
+ "description": "Named entity: subne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228a"
+ ]
+ ]
+ },
+ {
+ "input": "&subplus",
+ "description": "Bad named entity: subplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subplus"
+ ]
+ ]
+ },
+ {
+ "input": "⪿",
+ "description": "Named entity: subplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2abf"
+ ]
+ ]
+ },
+ {
+ "input": "&subrarr",
+ "description": "Bad named entity: subrarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subrarr"
+ ]
+ ]
+ },
+ {
+ "input": "⥹",
+ "description": "Named entity: subrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2979"
+ ]
+ ]
+ },
+ {
+ "input": "&subset",
+ "description": "Bad named entity: subset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subset"
+ ]
+ ]
+ },
+ {
+ "input": "⊂",
+ "description": "Named entity: subset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2282"
+ ]
+ ]
+ },
+ {
+ "input": "&subseteq",
+ "description": "Bad named entity: subseteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subseteq"
+ ]
+ ]
+ },
+ {
+ "input": "⊆",
+ "description": "Named entity: subseteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2286"
+ ]
+ ]
+ },
+ {
+ "input": "&subseteqq",
+ "description": "Bad named entity: subseteqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subseteqq"
+ ]
+ ]
+ },
+ {
+ "input": "⫅",
+ "description": "Named entity: subseteqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac5"
+ ]
+ ]
+ },
+ {
+ "input": "&subsetneq",
+ "description": "Bad named entity: subsetneq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subsetneq"
+ ]
+ ]
+ },
+ {
+ "input": "⊊",
+ "description": "Named entity: subsetneq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228a"
+ ]
+ ]
+ },
+ {
+ "input": "&subsetneqq",
+ "description": "Bad named entity: subsetneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subsetneqq"
+ ]
+ ]
+ },
+ {
+ "input": "⫋",
+ "description": "Named entity: subsetneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acb"
+ ]
+ ]
+ },
+ {
+ "input": "&subsim",
+ "description": "Bad named entity: subsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subsim"
+ ]
+ ]
+ },
+ {
+ "input": "⫇",
+ "description": "Named entity: subsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac7"
+ ]
+ ]
+ },
+ {
+ "input": "&subsub",
+ "description": "Bad named entity: subsub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subsub"
+ ]
+ ]
+ },
+ {
+ "input": "⫕",
+ "description": "Named entity: subsub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad5"
+ ]
+ ]
+ },
+ {
+ "input": "&subsup",
+ "description": "Bad named entity: subsup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&subsup"
+ ]
+ ]
+ },
+ {
+ "input": "⫓",
+ "description": "Named entity: subsup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad3"
+ ]
+ ]
+ },
+ {
+ "input": "&succ",
+ "description": "Bad named entity: succ without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&succ"
+ ]
+ ]
+ },
+ {
+ "input": "≻",
+ "description": "Named entity: succ; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227b"
+ ]
+ ]
+ },
+ {
+ "input": "&succapprox",
+ "description": "Bad named entity: succapprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&succapprox"
+ ]
+ ]
+ },
+ {
+ "input": "⪸",
+ "description": "Named entity: succapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab8"
+ ]
+ ]
+ },
+ {
+ "input": "&succcurlyeq",
+ "description": "Bad named entity: succcurlyeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&succcurlyeq"
+ ]
+ ]
+ },
+ {
+ "input": "≽",
+ "description": "Named entity: succcurlyeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227d"
+ ]
+ ]
+ },
+ {
+ "input": "&succeq",
+ "description": "Bad named entity: succeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&succeq"
+ ]
+ ]
+ },
+ {
+ "input": "⪰",
+ "description": "Named entity: succeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab0"
+ ]
+ ]
+ },
+ {
+ "input": "&succnapprox",
+ "description": "Bad named entity: succnapprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&succnapprox"
+ ]
+ ]
+ },
+ {
+ "input": "⪺",
+ "description": "Named entity: succnapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2aba"
+ ]
+ ]
+ },
+ {
+ "input": "&succneqq",
+ "description": "Bad named entity: succneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&succneqq"
+ ]
+ ]
+ },
+ {
+ "input": "⪶",
+ "description": "Named entity: succneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ab6"
+ ]
+ ]
+ },
+ {
+ "input": "&succnsim",
+ "description": "Bad named entity: succnsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&succnsim"
+ ]
+ ]
+ },
+ {
+ "input": "⋩",
+ "description": "Named entity: succnsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22e9"
+ ]
+ ]
+ },
+ {
+ "input": "&succsim",
+ "description": "Bad named entity: succsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&succsim"
+ ]
+ ]
+ },
+ {
+ "input": "≿",
+ "description": "Named entity: succsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u227f"
+ ]
+ ]
+ },
+ {
+ "input": "&sum",
+ "description": "Bad named entity: sum without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sum"
+ ]
+ ]
+ },
+ {
+ "input": "∑",
+ "description": "Named entity: sum; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2211"
+ ]
+ ]
+ },
+ {
+ "input": "&sung",
+ "description": "Bad named entity: sung without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sung"
+ ]
+ ]
+ },
+ {
+ "input": "♪",
+ "description": "Named entity: sung; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u266a"
+ ]
+ ]
+ },
+ {
+ "input": "&sup",
+ "description": "Bad named entity: sup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&sup"
+ ]
+ ]
+ },
+ {
+ "input": "¹",
+ "description": "Named entity: sup1 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b9"
+ ]
+ ]
+ },
+ {
+ "input": "¹",
+ "description": "Named entity: sup1; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b9"
+ ]
+ ]
+ },
+ {
+ "input": "²",
+ "description": "Named entity: sup2 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b2"
+ ]
+ ]
+ },
+ {
+ "input": "²",
+ "description": "Named entity: sup2; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b2"
+ ]
+ ]
+ },
+ {
+ "input": "³",
+ "description": "Named entity: sup3 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00b3"
+ ]
+ ]
+ },
+ {
+ "input": "³",
+ "description": "Named entity: sup3; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00b3"
+ ]
+ ]
+ },
+ {
+ "input": "⊃",
+ "description": "Named entity: sup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2283"
+ ]
+ ]
+ },
+ {
+ "input": "&supE",
+ "description": "Bad named entity: supE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supE"
+ ]
+ ]
+ },
+ {
+ "input": "⫆",
+ "description": "Named entity: supE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac6"
+ ]
+ ]
+ },
+ {
+ "input": "&supdot",
+ "description": "Bad named entity: supdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supdot"
+ ]
+ ]
+ },
+ {
+ "input": "⪾",
+ "description": "Named entity: supdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2abe"
+ ]
+ ]
+ },
+ {
+ "input": "&supdsub",
+ "description": "Bad named entity: supdsub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supdsub"
+ ]
+ ]
+ },
+ {
+ "input": "⫘",
+ "description": "Named entity: supdsub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad8"
+ ]
+ ]
+ },
+ {
+ "input": "&supe",
+ "description": "Bad named entity: supe without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supe"
+ ]
+ ]
+ },
+ {
+ "input": "⊇",
+ "description": "Named entity: supe; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2287"
+ ]
+ ]
+ },
+ {
+ "input": "&supedot",
+ "description": "Bad named entity: supedot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supedot"
+ ]
+ ]
+ },
+ {
+ "input": "⫄",
+ "description": "Named entity: supedot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac4"
+ ]
+ ]
+ },
+ {
+ "input": "&suphsol",
+ "description": "Bad named entity: suphsol without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&suphsol"
+ ]
+ ]
+ },
+ {
+ "input": "⟉",
+ "description": "Named entity: suphsol; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27c9"
+ ]
+ ]
+ },
+ {
+ "input": "&suphsub",
+ "description": "Bad named entity: suphsub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&suphsub"
+ ]
+ ]
+ },
+ {
+ "input": "⫗",
+ "description": "Named entity: suphsub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad7"
+ ]
+ ]
+ },
+ {
+ "input": "&suplarr",
+ "description": "Bad named entity: suplarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&suplarr"
+ ]
+ ]
+ },
+ {
+ "input": "⥻",
+ "description": "Named entity: suplarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u297b"
+ ]
+ ]
+ },
+ {
+ "input": "&supmult",
+ "description": "Bad named entity: supmult without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supmult"
+ ]
+ ]
+ },
+ {
+ "input": "⫂",
+ "description": "Named entity: supmult; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac2"
+ ]
+ ]
+ },
+ {
+ "input": "&supnE",
+ "description": "Bad named entity: supnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supnE"
+ ]
+ ]
+ },
+ {
+ "input": "⫌",
+ "description": "Named entity: supnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acc"
+ ]
+ ]
+ },
+ {
+ "input": "&supne",
+ "description": "Bad named entity: supne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supne"
+ ]
+ ]
+ },
+ {
+ "input": "⊋",
+ "description": "Named entity: supne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228b"
+ ]
+ ]
+ },
+ {
+ "input": "&supplus",
+ "description": "Bad named entity: supplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supplus"
+ ]
+ ]
+ },
+ {
+ "input": "⫀",
+ "description": "Named entity: supplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac0"
+ ]
+ ]
+ },
+ {
+ "input": "&supset",
+ "description": "Bad named entity: supset without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supset"
+ ]
+ ]
+ },
+ {
+ "input": "⊃",
+ "description": "Named entity: supset; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2283"
+ ]
+ ]
+ },
+ {
+ "input": "&supseteq",
+ "description": "Bad named entity: supseteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supseteq"
+ ]
+ ]
+ },
+ {
+ "input": "⊇",
+ "description": "Named entity: supseteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2287"
+ ]
+ ]
+ },
+ {
+ "input": "&supseteqq",
+ "description": "Bad named entity: supseteqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supseteqq"
+ ]
+ ]
+ },
+ {
+ "input": "⫆",
+ "description": "Named entity: supseteqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac6"
+ ]
+ ]
+ },
+ {
+ "input": "&supsetneq",
+ "description": "Bad named entity: supsetneq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supsetneq"
+ ]
+ ]
+ },
+ {
+ "input": "⊋",
+ "description": "Named entity: supsetneq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228b"
+ ]
+ ]
+ },
+ {
+ "input": "&supsetneqq",
+ "description": "Bad named entity: supsetneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supsetneqq"
+ ]
+ ]
+ },
+ {
+ "input": "⫌",
+ "description": "Named entity: supsetneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acc"
+ ]
+ ]
+ },
+ {
+ "input": "&supsim",
+ "description": "Bad named entity: supsim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supsim"
+ ]
+ ]
+ },
+ {
+ "input": "⫈",
+ "description": "Named entity: supsim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ac8"
+ ]
+ ]
+ },
+ {
+ "input": "&supsub",
+ "description": "Bad named entity: supsub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supsub"
+ ]
+ ]
+ },
+ {
+ "input": "⫔",
+ "description": "Named entity: supsub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad4"
+ ]
+ ]
+ },
+ {
+ "input": "&supsup",
+ "description": "Bad named entity: supsup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&supsup"
+ ]
+ ]
+ },
+ {
+ "input": "⫖",
+ "description": "Named entity: supsup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ad6"
+ ]
+ ]
+ },
+ {
+ "input": "&swArr",
+ "description": "Bad named entity: swArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&swArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇙",
+ "description": "Named entity: swArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d9"
+ ]
+ ]
+ },
+ {
+ "input": "&swarhk",
+ "description": "Bad named entity: swarhk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&swarhk"
+ ]
+ ]
+ },
+ {
+ "input": "⤦",
+ "description": "Named entity: swarhk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2926"
+ ]
+ ]
+ },
+ {
+ "input": "&swarr",
+ "description": "Bad named entity: swarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&swarr"
+ ]
+ ]
+ },
+ {
+ "input": "↙",
+ "description": "Named entity: swarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2199"
+ ]
+ ]
+ },
+ {
+ "input": "&swarrow",
+ "description": "Bad named entity: swarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&swarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↙",
+ "description": "Named entity: swarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2199"
+ ]
+ ]
+ },
+ {
+ "input": "&swnwar",
+ "description": "Bad named entity: swnwar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&swnwar"
+ ]
+ ]
+ },
+ {
+ "input": "⤪",
+ "description": "Named entity: swnwar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u292a"
+ ]
+ ]
+ },
+ {
+ "input": "ß",
+ "description": "Named entity: szlig without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00df"
+ ]
+ ]
+ },
+ {
+ "input": "ß",
+ "description": "Named entity: szlig; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00df"
+ ]
+ ]
+ },
+ {
+ "input": "&target",
+ "description": "Bad named entity: target without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&target"
+ ]
+ ]
+ },
+ {
+ "input": "⌖",
+ "description": "Named entity: target; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2316"
+ ]
+ ]
+ },
+ {
+ "input": "&tau",
+ "description": "Bad named entity: tau without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tau"
+ ]
+ ]
+ },
+ {
+ "input": "τ",
+ "description": "Named entity: tau; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c4"
+ ]
+ ]
+ },
+ {
+ "input": "&tbrk",
+ "description": "Bad named entity: tbrk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tbrk"
+ ]
+ ]
+ },
+ {
+ "input": "⎴",
+ "description": "Named entity: tbrk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23b4"
+ ]
+ ]
+ },
+ {
+ "input": "&tcaron",
+ "description": "Bad named entity: tcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tcaron"
+ ]
+ ]
+ },
+ {
+ "input": "ť",
+ "description": "Named entity: tcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0165"
+ ]
+ ]
+ },
+ {
+ "input": "&tcedil",
+ "description": "Bad named entity: tcedil without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tcedil"
+ ]
+ ]
+ },
+ {
+ "input": "ţ",
+ "description": "Named entity: tcedil; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0163"
+ ]
+ ]
+ },
+ {
+ "input": "&tcy",
+ "description": "Bad named entity: tcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tcy"
+ ]
+ ]
+ },
+ {
+ "input": "т",
+ "description": "Named entity: tcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0442"
+ ]
+ ]
+ },
+ {
+ "input": "&tdot",
+ "description": "Bad named entity: tdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tdot"
+ ]
+ ]
+ },
+ {
+ "input": "⃛",
+ "description": "Named entity: tdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u20db"
+ ]
+ ]
+ },
+ {
+ "input": "&telrec",
+ "description": "Bad named entity: telrec without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&telrec"
+ ]
+ ]
+ },
+ {
+ "input": "⌕",
+ "description": "Named entity: telrec; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2315"
+ ]
+ ]
+ },
+ {
+ "input": "&tfr",
+ "description": "Bad named entity: tfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔱",
+ "description": "Named entity: tfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd31"
+ ]
+ ]
+ },
+ {
+ "input": "&there4",
+ "description": "Bad named entity: there4 without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&there4"
+ ]
+ ]
+ },
+ {
+ "input": "∴",
+ "description": "Named entity: there4; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2234"
+ ]
+ ]
+ },
+ {
+ "input": "&therefore",
+ "description": "Bad named entity: therefore without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&therefore"
+ ]
+ ]
+ },
+ {
+ "input": "∴",
+ "description": "Named entity: therefore; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2234"
+ ]
+ ]
+ },
+ {
+ "input": "&theta",
+ "description": "Bad named entity: theta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&theta"
+ ]
+ ]
+ },
+ {
+ "input": "θ",
+ "description": "Named entity: theta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b8"
+ ]
+ ]
+ },
+ {
+ "input": "&thetasym",
+ "description": "Bad named entity: thetasym without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&thetasym"
+ ]
+ ]
+ },
+ {
+ "input": "ϑ",
+ "description": "Named entity: thetasym; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d1"
+ ]
+ ]
+ },
+ {
+ "input": "&thetav",
+ "description": "Bad named entity: thetav without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&thetav"
+ ]
+ ]
+ },
+ {
+ "input": "ϑ",
+ "description": "Named entity: thetav; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d1"
+ ]
+ ]
+ },
+ {
+ "input": "&thickapprox",
+ "description": "Bad named entity: thickapprox without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&thickapprox"
+ ]
+ ]
+ },
+ {
+ "input": "≈",
+ "description": "Named entity: thickapprox; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2248"
+ ]
+ ]
+ },
+ {
+ "input": "&thicksim",
+ "description": "Bad named entity: thicksim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&thicksim"
+ ]
+ ]
+ },
+ {
+ "input": "∼",
+ "description": "Named entity: thicksim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223c"
+ ]
+ ]
+ },
+ {
+ "input": "&thinsp",
+ "description": "Bad named entity: thinsp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&thinsp"
+ ]
+ ]
+ },
+ {
+ "input": " ",
+ "description": "Named entity: thinsp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2009"
+ ]
+ ]
+ },
+ {
+ "input": "&thkap",
+ "description": "Bad named entity: thkap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&thkap"
+ ]
+ ]
+ },
+ {
+ "input": "≈",
+ "description": "Named entity: thkap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2248"
+ ]
+ ]
+ },
+ {
+ "input": "&thksim",
+ "description": "Bad named entity: thksim without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&thksim"
+ ]
+ ]
+ },
+ {
+ "input": "∼",
+ "description": "Named entity: thksim; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u223c"
+ ]
+ ]
+ },
+ {
+ "input": "þ",
+ "description": "Named entity: thorn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00fe"
+ ]
+ ]
+ },
+ {
+ "input": "þ",
+ "description": "Named entity: thorn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00fe"
+ ]
+ ]
+ },
+ {
+ "input": "&tilde",
+ "description": "Bad named entity: tilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tilde"
+ ]
+ ]
+ },
+ {
+ "input": "˜",
+ "description": "Named entity: tilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u02dc"
+ ]
+ ]
+ },
+ {
+ "input": "×",
+ "description": "Named entity: times without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00d7"
+ ]
+ ]
+ },
+ {
+ "input": "×",
+ "description": "Named entity: times; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00d7"
+ ]
+ ]
+ },
+ {
+ "input": "⊠",
+ "description": "Named entity: timesb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a0"
+ ]
+ ]
+ },
+ {
+ "input": "⨱",
+ "description": "Named entity: timesbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a31"
+ ]
+ ]
+ },
+ {
+ "input": "⨰",
+ "description": "Named entity: timesd; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a30"
+ ]
+ ]
+ },
+ {
+ "input": "&tint",
+ "description": "Bad named entity: tint without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tint"
+ ]
+ ]
+ },
+ {
+ "input": "∭",
+ "description": "Named entity: tint; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u222d"
+ ]
+ ]
+ },
+ {
+ "input": "&toea",
+ "description": "Bad named entity: toea without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&toea"
+ ]
+ ]
+ },
+ {
+ "input": "⤨",
+ "description": "Named entity: toea; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2928"
+ ]
+ ]
+ },
+ {
+ "input": "&top",
+ "description": "Bad named entity: top without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&top"
+ ]
+ ]
+ },
+ {
+ "input": "⊤",
+ "description": "Named entity: top; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a4"
+ ]
+ ]
+ },
+ {
+ "input": "&topbot",
+ "description": "Bad named entity: topbot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&topbot"
+ ]
+ ]
+ },
+ {
+ "input": "⌶",
+ "description": "Named entity: topbot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2336"
+ ]
+ ]
+ },
+ {
+ "input": "&topcir",
+ "description": "Bad named entity: topcir without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&topcir"
+ ]
+ ]
+ },
+ {
+ "input": "⫱",
+ "description": "Named entity: topcir; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2af1"
+ ]
+ ]
+ },
+ {
+ "input": "&topf",
+ "description": "Bad named entity: topf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&topf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕥",
+ "description": "Named entity: topf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd65"
+ ]
+ ]
+ },
+ {
+ "input": "&topfork",
+ "description": "Bad named entity: topfork without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&topfork"
+ ]
+ ]
+ },
+ {
+ "input": "⫚",
+ "description": "Named entity: topfork; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ada"
+ ]
+ ]
+ },
+ {
+ "input": "&tosa",
+ "description": "Bad named entity: tosa without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tosa"
+ ]
+ ]
+ },
+ {
+ "input": "⤩",
+ "description": "Named entity: tosa; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2929"
+ ]
+ ]
+ },
+ {
+ "input": "&tprime",
+ "description": "Bad named entity: tprime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tprime"
+ ]
+ ]
+ },
+ {
+ "input": "‴",
+ "description": "Named entity: tprime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2034"
+ ]
+ ]
+ },
+ {
+ "input": "&trade",
+ "description": "Bad named entity: trade without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&trade"
+ ]
+ ]
+ },
+ {
+ "input": "™",
+ "description": "Named entity: trade; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2122"
+ ]
+ ]
+ },
+ {
+ "input": "&triangle",
+ "description": "Bad named entity: triangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&triangle"
+ ]
+ ]
+ },
+ {
+ "input": "▵",
+ "description": "Named entity: triangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b5"
+ ]
+ ]
+ },
+ {
+ "input": "&triangledown",
+ "description": "Bad named entity: triangledown without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&triangledown"
+ ]
+ ]
+ },
+ {
+ "input": "▿",
+ "description": "Named entity: triangledown; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25bf"
+ ]
+ ]
+ },
+ {
+ "input": "&triangleleft",
+ "description": "Bad named entity: triangleleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&triangleleft"
+ ]
+ ]
+ },
+ {
+ "input": "◃",
+ "description": "Named entity: triangleleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25c3"
+ ]
+ ]
+ },
+ {
+ "input": "&trianglelefteq",
+ "description": "Bad named entity: trianglelefteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&trianglelefteq"
+ ]
+ ]
+ },
+ {
+ "input": "⊴",
+ "description": "Named entity: trianglelefteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b4"
+ ]
+ ]
+ },
+ {
+ "input": "&triangleq",
+ "description": "Bad named entity: triangleq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&triangleq"
+ ]
+ ]
+ },
+ {
+ "input": "≜",
+ "description": "Named entity: triangleq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u225c"
+ ]
+ ]
+ },
+ {
+ "input": "&triangleright",
+ "description": "Bad named entity: triangleright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&triangleright"
+ ]
+ ]
+ },
+ {
+ "input": "▹",
+ "description": "Named entity: triangleright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b9"
+ ]
+ ]
+ },
+ {
+ "input": "&trianglerighteq",
+ "description": "Bad named entity: trianglerighteq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&trianglerighteq"
+ ]
+ ]
+ },
+ {
+ "input": "⊵",
+ "description": "Named entity: trianglerighteq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b5"
+ ]
+ ]
+ },
+ {
+ "input": "&tridot",
+ "description": "Bad named entity: tridot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tridot"
+ ]
+ ]
+ },
+ {
+ "input": "◬",
+ "description": "Named entity: tridot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25ec"
+ ]
+ ]
+ },
+ {
+ "input": "&trie",
+ "description": "Bad named entity: trie without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&trie"
+ ]
+ ]
+ },
+ {
+ "input": "≜",
+ "description": "Named entity: trie; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u225c"
+ ]
+ ]
+ },
+ {
+ "input": "&triminus",
+ "description": "Bad named entity: triminus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&triminus"
+ ]
+ ]
+ },
+ {
+ "input": "⨺",
+ "description": "Named entity: triminus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a3a"
+ ]
+ ]
+ },
+ {
+ "input": "&triplus",
+ "description": "Bad named entity: triplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&triplus"
+ ]
+ ]
+ },
+ {
+ "input": "⨹",
+ "description": "Named entity: triplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a39"
+ ]
+ ]
+ },
+ {
+ "input": "&trisb",
+ "description": "Bad named entity: trisb without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&trisb"
+ ]
+ ]
+ },
+ {
+ "input": "⧍",
+ "description": "Named entity: trisb; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29cd"
+ ]
+ ]
+ },
+ {
+ "input": "&tritime",
+ "description": "Bad named entity: tritime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tritime"
+ ]
+ ]
+ },
+ {
+ "input": "⨻",
+ "description": "Named entity: tritime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a3b"
+ ]
+ ]
+ },
+ {
+ "input": "&trpezium",
+ "description": "Bad named entity: trpezium without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&trpezium"
+ ]
+ ]
+ },
+ {
+ "input": "⏢",
+ "description": "Named entity: trpezium; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u23e2"
+ ]
+ ]
+ },
+ {
+ "input": "&tscr",
+ "description": "Bad named entity: tscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓉",
+ "description": "Named entity: tscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcc9"
+ ]
+ ]
+ },
+ {
+ "input": "&tscy",
+ "description": "Bad named entity: tscy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tscy"
+ ]
+ ]
+ },
+ {
+ "input": "ц",
+ "description": "Named entity: tscy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0446"
+ ]
+ ]
+ },
+ {
+ "input": "&tshcy",
+ "description": "Bad named entity: tshcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tshcy"
+ ]
+ ]
+ },
+ {
+ "input": "ћ",
+ "description": "Named entity: tshcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u045b"
+ ]
+ ]
+ },
+ {
+ "input": "&tstrok",
+ "description": "Bad named entity: tstrok without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&tstrok"
+ ]
+ ]
+ },
+ {
+ "input": "ŧ",
+ "description": "Named entity: tstrok; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0167"
+ ]
+ ]
+ },
+ {
+ "input": "&twixt",
+ "description": "Bad named entity: twixt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&twixt"
+ ]
+ ]
+ },
+ {
+ "input": "≬",
+ "description": "Named entity: twixt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u226c"
+ ]
+ ]
+ },
+ {
+ "input": "&twoheadleftarrow",
+ "description": "Bad named entity: twoheadleftarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&twoheadleftarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↞",
+ "description": "Named entity: twoheadleftarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u219e"
+ ]
+ ]
+ },
+ {
+ "input": "&twoheadrightarrow",
+ "description": "Bad named entity: twoheadrightarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&twoheadrightarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↠",
+ "description": "Named entity: twoheadrightarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21a0"
+ ]
+ ]
+ },
+ {
+ "input": "&uArr",
+ "description": "Bad named entity: uArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇑",
+ "description": "Named entity: uArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d1"
+ ]
+ ]
+ },
+ {
+ "input": "&uHar",
+ "description": "Bad named entity: uHar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uHar"
+ ]
+ ]
+ },
+ {
+ "input": "⥣",
+ "description": "Named entity: uHar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2963"
+ ]
+ ]
+ },
+ {
+ "input": "ú",
+ "description": "Named entity: uacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00fa"
+ ]
+ ]
+ },
+ {
+ "input": "ú",
+ "description": "Named entity: uacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00fa"
+ ]
+ ]
+ },
+ {
+ "input": "&uarr",
+ "description": "Bad named entity: uarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uarr"
+ ]
+ ]
+ },
+ {
+ "input": "↑",
+ "description": "Named entity: uarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2191"
+ ]
+ ]
+ },
+ {
+ "input": "&ubrcy",
+ "description": "Bad named entity: ubrcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ubrcy"
+ ]
+ ]
+ },
+ {
+ "input": "ў",
+ "description": "Named entity: ubrcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u045e"
+ ]
+ ]
+ },
+ {
+ "input": "&ubreve",
+ "description": "Bad named entity: ubreve without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ubreve"
+ ]
+ ]
+ },
+ {
+ "input": "ŭ",
+ "description": "Named entity: ubreve; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u016d"
+ ]
+ ]
+ },
+ {
+ "input": "û",
+ "description": "Named entity: ucirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00fb"
+ ]
+ ]
+ },
+ {
+ "input": "û",
+ "description": "Named entity: ucirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00fb"
+ ]
+ ]
+ },
+ {
+ "input": "&ucy",
+ "description": "Bad named entity: ucy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ucy"
+ ]
+ ]
+ },
+ {
+ "input": "у",
+ "description": "Named entity: ucy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0443"
+ ]
+ ]
+ },
+ {
+ "input": "&udarr",
+ "description": "Bad named entity: udarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&udarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇅",
+ "description": "Named entity: udarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c5"
+ ]
+ ]
+ },
+ {
+ "input": "&udblac",
+ "description": "Bad named entity: udblac without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&udblac"
+ ]
+ ]
+ },
+ {
+ "input": "ű",
+ "description": "Named entity: udblac; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0171"
+ ]
+ ]
+ },
+ {
+ "input": "&udhar",
+ "description": "Bad named entity: udhar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&udhar"
+ ]
+ ]
+ },
+ {
+ "input": "⥮",
+ "description": "Named entity: udhar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u296e"
+ ]
+ ]
+ },
+ {
+ "input": "&ufisht",
+ "description": "Bad named entity: ufisht without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ufisht"
+ ]
+ ]
+ },
+ {
+ "input": "⥾",
+ "description": "Named entity: ufisht; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u297e"
+ ]
+ ]
+ },
+ {
+ "input": "&ufr",
+ "description": "Bad named entity: ufr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ufr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔲",
+ "description": "Named entity: ufr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd32"
+ ]
+ ]
+ },
+ {
+ "input": "ù",
+ "description": "Named entity: ugrave without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00f9"
+ ]
+ ]
+ },
+ {
+ "input": "ù",
+ "description": "Named entity: ugrave; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00f9"
+ ]
+ ]
+ },
+ {
+ "input": "&uharl",
+ "description": "Bad named entity: uharl without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uharl"
+ ]
+ ]
+ },
+ {
+ "input": "↿",
+ "description": "Named entity: uharl; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bf"
+ ]
+ ]
+ },
+ {
+ "input": "&uharr",
+ "description": "Bad named entity: uharr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uharr"
+ ]
+ ]
+ },
+ {
+ "input": "↾",
+ "description": "Named entity: uharr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21be"
+ ]
+ ]
+ },
+ {
+ "input": "&uhblk",
+ "description": "Bad named entity: uhblk without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uhblk"
+ ]
+ ]
+ },
+ {
+ "input": "▀",
+ "description": "Named entity: uhblk; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2580"
+ ]
+ ]
+ },
+ {
+ "input": "&ulcorn",
+ "description": "Bad named entity: ulcorn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ulcorn"
+ ]
+ ]
+ },
+ {
+ "input": "⌜",
+ "description": "Named entity: ulcorn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u231c"
+ ]
+ ]
+ },
+ {
+ "input": "&ulcorner",
+ "description": "Bad named entity: ulcorner without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ulcorner"
+ ]
+ ]
+ },
+ {
+ "input": "⌜",
+ "description": "Named entity: ulcorner; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u231c"
+ ]
+ ]
+ },
+ {
+ "input": "&ulcrop",
+ "description": "Bad named entity: ulcrop without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ulcrop"
+ ]
+ ]
+ },
+ {
+ "input": "⌏",
+ "description": "Named entity: ulcrop; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u230f"
+ ]
+ ]
+ },
+ {
+ "input": "&ultri",
+ "description": "Bad named entity: ultri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ultri"
+ ]
+ ]
+ },
+ {
+ "input": "◸",
+ "description": "Named entity: ultri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25f8"
+ ]
+ ]
+ },
+ {
+ "input": "&umacr",
+ "description": "Bad named entity: umacr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&umacr"
+ ]
+ ]
+ },
+ {
+ "input": "ū",
+ "description": "Named entity: umacr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u016b"
+ ]
+ ]
+ },
+ {
+ "input": "¨",
+ "description": "Named entity: uml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a8"
+ ]
+ ]
+ },
+ {
+ "input": "¨",
+ "description": "Named entity: uml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a8"
+ ]
+ ]
+ },
+ {
+ "input": "&uogon",
+ "description": "Bad named entity: uogon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uogon"
+ ]
+ ]
+ },
+ {
+ "input": "ų",
+ "description": "Named entity: uogon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0173"
+ ]
+ ]
+ },
+ {
+ "input": "&uopf",
+ "description": "Bad named entity: uopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕦",
+ "description": "Named entity: uopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd66"
+ ]
+ ]
+ },
+ {
+ "input": "&uparrow",
+ "description": "Bad named entity: uparrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uparrow"
+ ]
+ ]
+ },
+ {
+ "input": "↑",
+ "description": "Named entity: uparrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2191"
+ ]
+ ]
+ },
+ {
+ "input": "&updownarrow",
+ "description": "Bad named entity: updownarrow without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&updownarrow"
+ ]
+ ]
+ },
+ {
+ "input": "↕",
+ "description": "Named entity: updownarrow; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2195"
+ ]
+ ]
+ },
+ {
+ "input": "&upharpoonleft",
+ "description": "Bad named entity: upharpoonleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&upharpoonleft"
+ ]
+ ]
+ },
+ {
+ "input": "↿",
+ "description": "Named entity: upharpoonleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21bf"
+ ]
+ ]
+ },
+ {
+ "input": "&upharpoonright",
+ "description": "Bad named entity: upharpoonright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&upharpoonright"
+ ]
+ ]
+ },
+ {
+ "input": "↾",
+ "description": "Named entity: upharpoonright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21be"
+ ]
+ ]
+ },
+ {
+ "input": "&uplus",
+ "description": "Bad named entity: uplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uplus"
+ ]
+ ]
+ },
+ {
+ "input": "⊎",
+ "description": "Named entity: uplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228e"
+ ]
+ ]
+ },
+ {
+ "input": "&upsi",
+ "description": "Bad named entity: upsi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&upsi"
+ ]
+ ]
+ },
+ {
+ "input": "υ",
+ "description": "Named entity: upsi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c5"
+ ]
+ ]
+ },
+ {
+ "input": "&upsih",
+ "description": "Bad named entity: upsih without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&upsih"
+ ]
+ ]
+ },
+ {
+ "input": "ϒ",
+ "description": "Named entity: upsih; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d2"
+ ]
+ ]
+ },
+ {
+ "input": "&upsilon",
+ "description": "Bad named entity: upsilon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&upsilon"
+ ]
+ ]
+ },
+ {
+ "input": "υ",
+ "description": "Named entity: upsilon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c5"
+ ]
+ ]
+ },
+ {
+ "input": "&upuparrows",
+ "description": "Bad named entity: upuparrows without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&upuparrows"
+ ]
+ ]
+ },
+ {
+ "input": "⇈",
+ "description": "Named entity: upuparrows; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c8"
+ ]
+ ]
+ },
+ {
+ "input": "&urcorn",
+ "description": "Bad named entity: urcorn without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&urcorn"
+ ]
+ ]
+ },
+ {
+ "input": "⌝",
+ "description": "Named entity: urcorn; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u231d"
+ ]
+ ]
+ },
+ {
+ "input": "&urcorner",
+ "description": "Bad named entity: urcorner without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&urcorner"
+ ]
+ ]
+ },
+ {
+ "input": "⌝",
+ "description": "Named entity: urcorner; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u231d"
+ ]
+ ]
+ },
+ {
+ "input": "&urcrop",
+ "description": "Bad named entity: urcrop without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&urcrop"
+ ]
+ ]
+ },
+ {
+ "input": "⌎",
+ "description": "Named entity: urcrop; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u230e"
+ ]
+ ]
+ },
+ {
+ "input": "&uring",
+ "description": "Bad named entity: uring without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uring"
+ ]
+ ]
+ },
+ {
+ "input": "ů",
+ "description": "Named entity: uring; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u016f"
+ ]
+ ]
+ },
+ {
+ "input": "&urtri",
+ "description": "Bad named entity: urtri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&urtri"
+ ]
+ ]
+ },
+ {
+ "input": "◹",
+ "description": "Named entity: urtri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25f9"
+ ]
+ ]
+ },
+ {
+ "input": "&uscr",
+ "description": "Bad named entity: uscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓊",
+ "description": "Named entity: uscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcca"
+ ]
+ ]
+ },
+ {
+ "input": "&utdot",
+ "description": "Bad named entity: utdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&utdot"
+ ]
+ ]
+ },
+ {
+ "input": "⋰",
+ "description": "Named entity: utdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22f0"
+ ]
+ ]
+ },
+ {
+ "input": "&utilde",
+ "description": "Bad named entity: utilde without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&utilde"
+ ]
+ ]
+ },
+ {
+ "input": "ũ",
+ "description": "Named entity: utilde; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0169"
+ ]
+ ]
+ },
+ {
+ "input": "&utri",
+ "description": "Bad named entity: utri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&utri"
+ ]
+ ]
+ },
+ {
+ "input": "▵",
+ "description": "Named entity: utri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b5"
+ ]
+ ]
+ },
+ {
+ "input": "&utrif",
+ "description": "Bad named entity: utrif without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&utrif"
+ ]
+ ]
+ },
+ {
+ "input": "▴",
+ "description": "Named entity: utrif; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b4"
+ ]
+ ]
+ },
+ {
+ "input": "&uuarr",
+ "description": "Bad named entity: uuarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uuarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇈",
+ "description": "Named entity: uuarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21c8"
+ ]
+ ]
+ },
+ {
+ "input": "ü",
+ "description": "Named entity: uuml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00fc"
+ ]
+ ]
+ },
+ {
+ "input": "ü",
+ "description": "Named entity: uuml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00fc"
+ ]
+ ]
+ },
+ {
+ "input": "&uwangle",
+ "description": "Bad named entity: uwangle without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&uwangle"
+ ]
+ ]
+ },
+ {
+ "input": "⦧",
+ "description": "Named entity: uwangle; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u29a7"
+ ]
+ ]
+ },
+ {
+ "input": "&vArr",
+ "description": "Bad named entity: vArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vArr"
+ ]
+ ]
+ },
+ {
+ "input": "⇕",
+ "description": "Named entity: vArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21d5"
+ ]
+ ]
+ },
+ {
+ "input": "&vBar",
+ "description": "Bad named entity: vBar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vBar"
+ ]
+ ]
+ },
+ {
+ "input": "⫨",
+ "description": "Named entity: vBar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ae8"
+ ]
+ ]
+ },
+ {
+ "input": "&vBarv",
+ "description": "Bad named entity: vBarv without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vBarv"
+ ]
+ ]
+ },
+ {
+ "input": "⫩",
+ "description": "Named entity: vBarv; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2ae9"
+ ]
+ ]
+ },
+ {
+ "input": "&vDash",
+ "description": "Bad named entity: vDash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vDash"
+ ]
+ ]
+ },
+ {
+ "input": "⊨",
+ "description": "Named entity: vDash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a8"
+ ]
+ ]
+ },
+ {
+ "input": "&vangrt",
+ "description": "Bad named entity: vangrt without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vangrt"
+ ]
+ ]
+ },
+ {
+ "input": "⦜",
+ "description": "Named entity: vangrt; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u299c"
+ ]
+ ]
+ },
+ {
+ "input": "&varepsilon",
+ "description": "Bad named entity: varepsilon without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varepsilon"
+ ]
+ ]
+ },
+ {
+ "input": "ϵ",
+ "description": "Named entity: varepsilon; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f5"
+ ]
+ ]
+ },
+ {
+ "input": "&varkappa",
+ "description": "Bad named entity: varkappa without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varkappa"
+ ]
+ ]
+ },
+ {
+ "input": "ϰ",
+ "description": "Named entity: varkappa; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f0"
+ ]
+ ]
+ },
+ {
+ "input": "&varnothing",
+ "description": "Bad named entity: varnothing without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varnothing"
+ ]
+ ]
+ },
+ {
+ "input": "∅",
+ "description": "Named entity: varnothing; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2205"
+ ]
+ ]
+ },
+ {
+ "input": "&varphi",
+ "description": "Bad named entity: varphi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varphi"
+ ]
+ ]
+ },
+ {
+ "input": "ϕ",
+ "description": "Named entity: varphi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d5"
+ ]
+ ]
+ },
+ {
+ "input": "&varpi",
+ "description": "Bad named entity: varpi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varpi"
+ ]
+ ]
+ },
+ {
+ "input": "ϖ",
+ "description": "Named entity: varpi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d6"
+ ]
+ ]
+ },
+ {
+ "input": "&varpropto",
+ "description": "Bad named entity: varpropto without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varpropto"
+ ]
+ ]
+ },
+ {
+ "input": "∝",
+ "description": "Named entity: varpropto; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221d"
+ ]
+ ]
+ },
+ {
+ "input": "&varr",
+ "description": "Bad named entity: varr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varr"
+ ]
+ ]
+ },
+ {
+ "input": "↕",
+ "description": "Named entity: varr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2195"
+ ]
+ ]
+ },
+ {
+ "input": "&varrho",
+ "description": "Bad named entity: varrho without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varrho"
+ ]
+ ]
+ },
+ {
+ "input": "ϱ",
+ "description": "Named entity: varrho; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03f1"
+ ]
+ ]
+ },
+ {
+ "input": "&varsigma",
+ "description": "Bad named entity: varsigma without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varsigma"
+ ]
+ ]
+ },
+ {
+ "input": "ς",
+ "description": "Named entity: varsigma; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03c2"
+ ]
+ ]
+ },
+ {
+ "input": "&varsubsetneq",
+ "description": "Bad named entity: varsubsetneq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varsubsetneq"
+ ]
+ ]
+ },
+ {
+ "input": "⊊︀",
+ "description": "Named entity: varsubsetneq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228a\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&varsubsetneqq",
+ "description": "Bad named entity: varsubsetneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varsubsetneqq"
+ ]
+ ]
+ },
+ {
+ "input": "⫋︀",
+ "description": "Named entity: varsubsetneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acb\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&varsupsetneq",
+ "description": "Bad named entity: varsupsetneq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varsupsetneq"
+ ]
+ ]
+ },
+ {
+ "input": "⊋︀",
+ "description": "Named entity: varsupsetneq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228b\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&varsupsetneqq",
+ "description": "Bad named entity: varsupsetneqq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&varsupsetneqq"
+ ]
+ ]
+ },
+ {
+ "input": "⫌︀",
+ "description": "Named entity: varsupsetneqq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acc\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&vartheta",
+ "description": "Bad named entity: vartheta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vartheta"
+ ]
+ ]
+ },
+ {
+ "input": "ϑ",
+ "description": "Named entity: vartheta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03d1"
+ ]
+ ]
+ },
+ {
+ "input": "&vartriangleleft",
+ "description": "Bad named entity: vartriangleleft without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vartriangleleft"
+ ]
+ ]
+ },
+ {
+ "input": "⊲",
+ "description": "Named entity: vartriangleleft; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b2"
+ ]
+ ]
+ },
+ {
+ "input": "&vartriangleright",
+ "description": "Bad named entity: vartriangleright without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vartriangleright"
+ ]
+ ]
+ },
+ {
+ "input": "⊳",
+ "description": "Named entity: vartriangleright; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b3"
+ ]
+ ]
+ },
+ {
+ "input": "&vcy",
+ "description": "Bad named entity: vcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vcy"
+ ]
+ ]
+ },
+ {
+ "input": "в",
+ "description": "Named entity: vcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0432"
+ ]
+ ]
+ },
+ {
+ "input": "&vdash",
+ "description": "Bad named entity: vdash without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vdash"
+ ]
+ ]
+ },
+ {
+ "input": "⊢",
+ "description": "Named entity: vdash; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22a2"
+ ]
+ ]
+ },
+ {
+ "input": "&vee",
+ "description": "Bad named entity: vee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vee"
+ ]
+ ]
+ },
+ {
+ "input": "∨",
+ "description": "Named entity: vee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2228"
+ ]
+ ]
+ },
+ {
+ "input": "&veebar",
+ "description": "Bad named entity: veebar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&veebar"
+ ]
+ ]
+ },
+ {
+ "input": "⊻",
+ "description": "Named entity: veebar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22bb"
+ ]
+ ]
+ },
+ {
+ "input": "&veeeq",
+ "description": "Bad named entity: veeeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&veeeq"
+ ]
+ ]
+ },
+ {
+ "input": "≚",
+ "description": "Named entity: veeeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u225a"
+ ]
+ ]
+ },
+ {
+ "input": "&vellip",
+ "description": "Bad named entity: vellip without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vellip"
+ ]
+ ]
+ },
+ {
+ "input": "⋮",
+ "description": "Named entity: vellip; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22ee"
+ ]
+ ]
+ },
+ {
+ "input": "&verbar",
+ "description": "Bad named entity: verbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&verbar"
+ ]
+ ]
+ },
+ {
+ "input": "|",
+ "description": "Named entity: verbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "|"
+ ]
+ ]
+ },
+ {
+ "input": "&vert",
+ "description": "Bad named entity: vert without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vert"
+ ]
+ ]
+ },
+ {
+ "input": "|",
+ "description": "Named entity: vert; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "|"
+ ]
+ ]
+ },
+ {
+ "input": "&vfr",
+ "description": "Bad named entity: vfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔳",
+ "description": "Named entity: vfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd33"
+ ]
+ ]
+ },
+ {
+ "input": "&vltri",
+ "description": "Bad named entity: vltri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vltri"
+ ]
+ ]
+ },
+ {
+ "input": "⊲",
+ "description": "Named entity: vltri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b2"
+ ]
+ ]
+ },
+ {
+ "input": "&vnsub",
+ "description": "Bad named entity: vnsub without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vnsub"
+ ]
+ ]
+ },
+ {
+ "input": "⊂⃒",
+ "description": "Named entity: vnsub; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2282\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&vnsup",
+ "description": "Bad named entity: vnsup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vnsup"
+ ]
+ ]
+ },
+ {
+ "input": "⊃⃒",
+ "description": "Named entity: vnsup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2283\u20d2"
+ ]
+ ]
+ },
+ {
+ "input": "&vopf",
+ "description": "Bad named entity: vopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕧",
+ "description": "Named entity: vopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd67"
+ ]
+ ]
+ },
+ {
+ "input": "&vprop",
+ "description": "Bad named entity: vprop without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vprop"
+ ]
+ ]
+ },
+ {
+ "input": "∝",
+ "description": "Named entity: vprop; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u221d"
+ ]
+ ]
+ },
+ {
+ "input": "&vrtri",
+ "description": "Bad named entity: vrtri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vrtri"
+ ]
+ ]
+ },
+ {
+ "input": "⊳",
+ "description": "Named entity: vrtri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22b3"
+ ]
+ ]
+ },
+ {
+ "input": "&vscr",
+ "description": "Bad named entity: vscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓋",
+ "description": "Named entity: vscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udccb"
+ ]
+ ]
+ },
+ {
+ "input": "&vsubnE",
+ "description": "Bad named entity: vsubnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vsubnE"
+ ]
+ ]
+ },
+ {
+ "input": "⫋︀",
+ "description": "Named entity: vsubnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acb\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&vsubne",
+ "description": "Bad named entity: vsubne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vsubne"
+ ]
+ ]
+ },
+ {
+ "input": "⊊︀",
+ "description": "Named entity: vsubne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228a\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&vsupnE",
+ "description": "Bad named entity: vsupnE without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vsupnE"
+ ]
+ ]
+ },
+ {
+ "input": "⫌︀",
+ "description": "Named entity: vsupnE; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2acc\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&vsupne",
+ "description": "Bad named entity: vsupne without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vsupne"
+ ]
+ ]
+ },
+ {
+ "input": "⊋︀",
+ "description": "Named entity: vsupne; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u228b\ufe00"
+ ]
+ ]
+ },
+ {
+ "input": "&vzigzag",
+ "description": "Bad named entity: vzigzag without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&vzigzag"
+ ]
+ ]
+ },
+ {
+ "input": "⦚",
+ "description": "Named entity: vzigzag; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u299a"
+ ]
+ ]
+ },
+ {
+ "input": "&wcirc",
+ "description": "Bad named entity: wcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wcirc"
+ ]
+ ]
+ },
+ {
+ "input": "ŵ",
+ "description": "Named entity: wcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0175"
+ ]
+ ]
+ },
+ {
+ "input": "&wedbar",
+ "description": "Bad named entity: wedbar without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wedbar"
+ ]
+ ]
+ },
+ {
+ "input": "⩟",
+ "description": "Named entity: wedbar; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a5f"
+ ]
+ ]
+ },
+ {
+ "input": "&wedge",
+ "description": "Bad named entity: wedge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wedge"
+ ]
+ ]
+ },
+ {
+ "input": "∧",
+ "description": "Named entity: wedge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2227"
+ ]
+ ]
+ },
+ {
+ "input": "&wedgeq",
+ "description": "Bad named entity: wedgeq without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wedgeq"
+ ]
+ ]
+ },
+ {
+ "input": "≙",
+ "description": "Named entity: wedgeq; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2259"
+ ]
+ ]
+ },
+ {
+ "input": "&weierp",
+ "description": "Bad named entity: weierp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&weierp"
+ ]
+ ]
+ },
+ {
+ "input": "℘",
+ "description": "Named entity: weierp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2118"
+ ]
+ ]
+ },
+ {
+ "input": "&wfr",
+ "description": "Bad named entity: wfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔴",
+ "description": "Named entity: wfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd34"
+ ]
+ ]
+ },
+ {
+ "input": "&wopf",
+ "description": "Bad named entity: wopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕨",
+ "description": "Named entity: wopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd68"
+ ]
+ ]
+ },
+ {
+ "input": "&wp",
+ "description": "Bad named entity: wp without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wp"
+ ]
+ ]
+ },
+ {
+ "input": "℘",
+ "description": "Named entity: wp; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2118"
+ ]
+ ]
+ },
+ {
+ "input": "&wr",
+ "description": "Bad named entity: wr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wr"
+ ]
+ ]
+ },
+ {
+ "input": "≀",
+ "description": "Named entity: wr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2240"
+ ]
+ ]
+ },
+ {
+ "input": "&wreath",
+ "description": "Bad named entity: wreath without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wreath"
+ ]
+ ]
+ },
+ {
+ "input": "≀",
+ "description": "Named entity: wreath; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2240"
+ ]
+ ]
+ },
+ {
+ "input": "&wscr",
+ "description": "Bad named entity: wscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&wscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓌",
+ "description": "Named entity: wscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udccc"
+ ]
+ ]
+ },
+ {
+ "input": "&xcap",
+ "description": "Bad named entity: xcap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xcap"
+ ]
+ ]
+ },
+ {
+ "input": "⋂",
+ "description": "Named entity: xcap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c2"
+ ]
+ ]
+ },
+ {
+ "input": "&xcirc",
+ "description": "Bad named entity: xcirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xcirc"
+ ]
+ ]
+ },
+ {
+ "input": "◯",
+ "description": "Named entity: xcirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25ef"
+ ]
+ ]
+ },
+ {
+ "input": "&xcup",
+ "description": "Bad named entity: xcup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xcup"
+ ]
+ ]
+ },
+ {
+ "input": "⋃",
+ "description": "Named entity: xcup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c3"
+ ]
+ ]
+ },
+ {
+ "input": "&xdtri",
+ "description": "Bad named entity: xdtri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xdtri"
+ ]
+ ]
+ },
+ {
+ "input": "▽",
+ "description": "Named entity: xdtri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25bd"
+ ]
+ ]
+ },
+ {
+ "input": "&xfr",
+ "description": "Bad named entity: xfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔵",
+ "description": "Named entity: xfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd35"
+ ]
+ ]
+ },
+ {
+ "input": "&xhArr",
+ "description": "Bad named entity: xhArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xhArr"
+ ]
+ ]
+ },
+ {
+ "input": "⟺",
+ "description": "Named entity: xhArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27fa"
+ ]
+ ]
+ },
+ {
+ "input": "&xharr",
+ "description": "Bad named entity: xharr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xharr"
+ ]
+ ]
+ },
+ {
+ "input": "⟷",
+ "description": "Named entity: xharr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f7"
+ ]
+ ]
+ },
+ {
+ "input": "&xi",
+ "description": "Bad named entity: xi without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xi"
+ ]
+ ]
+ },
+ {
+ "input": "ξ",
+ "description": "Named entity: xi; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03be"
+ ]
+ ]
+ },
+ {
+ "input": "&xlArr",
+ "description": "Bad named entity: xlArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xlArr"
+ ]
+ ]
+ },
+ {
+ "input": "⟸",
+ "description": "Named entity: xlArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f8"
+ ]
+ ]
+ },
+ {
+ "input": "&xlarr",
+ "description": "Bad named entity: xlarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xlarr"
+ ]
+ ]
+ },
+ {
+ "input": "⟵",
+ "description": "Named entity: xlarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f5"
+ ]
+ ]
+ },
+ {
+ "input": "&xmap",
+ "description": "Bad named entity: xmap without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xmap"
+ ]
+ ]
+ },
+ {
+ "input": "⟼",
+ "description": "Named entity: xmap; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27fc"
+ ]
+ ]
+ },
+ {
+ "input": "&xnis",
+ "description": "Bad named entity: xnis without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xnis"
+ ]
+ ]
+ },
+ {
+ "input": "⋻",
+ "description": "Named entity: xnis; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22fb"
+ ]
+ ]
+ },
+ {
+ "input": "&xodot",
+ "description": "Bad named entity: xodot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xodot"
+ ]
+ ]
+ },
+ {
+ "input": "⨀",
+ "description": "Named entity: xodot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a00"
+ ]
+ ]
+ },
+ {
+ "input": "&xopf",
+ "description": "Bad named entity: xopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕩",
+ "description": "Named entity: xopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd69"
+ ]
+ ]
+ },
+ {
+ "input": "&xoplus",
+ "description": "Bad named entity: xoplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xoplus"
+ ]
+ ]
+ },
+ {
+ "input": "⨁",
+ "description": "Named entity: xoplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a01"
+ ]
+ ]
+ },
+ {
+ "input": "&xotime",
+ "description": "Bad named entity: xotime without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xotime"
+ ]
+ ]
+ },
+ {
+ "input": "⨂",
+ "description": "Named entity: xotime; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a02"
+ ]
+ ]
+ },
+ {
+ "input": "&xrArr",
+ "description": "Bad named entity: xrArr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xrArr"
+ ]
+ ]
+ },
+ {
+ "input": "⟹",
+ "description": "Named entity: xrArr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f9"
+ ]
+ ]
+ },
+ {
+ "input": "&xrarr",
+ "description": "Bad named entity: xrarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xrarr"
+ ]
+ ]
+ },
+ {
+ "input": "⟶",
+ "description": "Named entity: xrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u27f6"
+ ]
+ ]
+ },
+ {
+ "input": "&xscr",
+ "description": "Bad named entity: xscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓍",
+ "description": "Named entity: xscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udccd"
+ ]
+ ]
+ },
+ {
+ "input": "&xsqcup",
+ "description": "Bad named entity: xsqcup without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xsqcup"
+ ]
+ ]
+ },
+ {
+ "input": "⨆",
+ "description": "Named entity: xsqcup; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a06"
+ ]
+ ]
+ },
+ {
+ "input": "&xuplus",
+ "description": "Bad named entity: xuplus without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xuplus"
+ ]
+ ]
+ },
+ {
+ "input": "⨄",
+ "description": "Named entity: xuplus; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2a04"
+ ]
+ ]
+ },
+ {
+ "input": "&xutri",
+ "description": "Bad named entity: xutri without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xutri"
+ ]
+ ]
+ },
+ {
+ "input": "△",
+ "description": "Named entity: xutri; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u25b3"
+ ]
+ ]
+ },
+ {
+ "input": "&xvee",
+ "description": "Bad named entity: xvee without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xvee"
+ ]
+ ]
+ },
+ {
+ "input": "⋁",
+ "description": "Named entity: xvee; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c1"
+ ]
+ ]
+ },
+ {
+ "input": "&xwedge",
+ "description": "Bad named entity: xwedge without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&xwedge"
+ ]
+ ]
+ },
+ {
+ "input": "⋀",
+ "description": "Named entity: xwedge; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u22c0"
+ ]
+ ]
+ },
+ {
+ "input": "ý",
+ "description": "Named entity: yacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00fd"
+ ]
+ ]
+ },
+ {
+ "input": "ý",
+ "description": "Named entity: yacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00fd"
+ ]
+ ]
+ },
+ {
+ "input": "&yacy",
+ "description": "Bad named entity: yacy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&yacy"
+ ]
+ ]
+ },
+ {
+ "input": "я",
+ "description": "Named entity: yacy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u044f"
+ ]
+ ]
+ },
+ {
+ "input": "&ycirc",
+ "description": "Bad named entity: ycirc without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ycirc"
+ ]
+ ]
+ },
+ {
+ "input": "ŷ",
+ "description": "Named entity: ycirc; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0177"
+ ]
+ ]
+ },
+ {
+ "input": "&ycy",
+ "description": "Bad named entity: ycy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&ycy"
+ ]
+ ]
+ },
+ {
+ "input": "ы",
+ "description": "Named entity: ycy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u044b"
+ ]
+ ]
+ },
+ {
+ "input": "¥",
+ "description": "Named entity: yen without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00a5"
+ ]
+ ]
+ },
+ {
+ "input": "¥",
+ "description": "Named entity: yen; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00a5"
+ ]
+ ]
+ },
+ {
+ "input": "&yfr",
+ "description": "Bad named entity: yfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&yfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔶",
+ "description": "Named entity: yfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd36"
+ ]
+ ]
+ },
+ {
+ "input": "&yicy",
+ "description": "Bad named entity: yicy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&yicy"
+ ]
+ ]
+ },
+ {
+ "input": "ї",
+ "description": "Named entity: yicy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0457"
+ ]
+ ]
+ },
+ {
+ "input": "&yopf",
+ "description": "Bad named entity: yopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&yopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕪",
+ "description": "Named entity: yopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd6a"
+ ]
+ ]
+ },
+ {
+ "input": "&yscr",
+ "description": "Bad named entity: yscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&yscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓎",
+ "description": "Named entity: yscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udcce"
+ ]
+ ]
+ },
+ {
+ "input": "&yucy",
+ "description": "Bad named entity: yucy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&yucy"
+ ]
+ ]
+ },
+ {
+ "input": "ю",
+ "description": "Named entity: yucy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u044e"
+ ]
+ ]
+ },
+ {
+ "input": "ÿ",
+ "description": "Named entity: yuml without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "\u00ff"
+ ]
+ ]
+ },
+ {
+ "input": "ÿ",
+ "description": "Named entity: yuml; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u00ff"
+ ]
+ ]
+ },
+ {
+ "input": "&zacute",
+ "description": "Bad named entity: zacute without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zacute"
+ ]
+ ]
+ },
+ {
+ "input": "ź",
+ "description": "Named entity: zacute; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u017a"
+ ]
+ ]
+ },
+ {
+ "input": "&zcaron",
+ "description": "Bad named entity: zcaron without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zcaron"
+ ]
+ ]
+ },
+ {
+ "input": "ž",
+ "description": "Named entity: zcaron; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u017e"
+ ]
+ ]
+ },
+ {
+ "input": "&zcy",
+ "description": "Bad named entity: zcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zcy"
+ ]
+ ]
+ },
+ {
+ "input": "з",
+ "description": "Named entity: zcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0437"
+ ]
+ ]
+ },
+ {
+ "input": "&zdot",
+ "description": "Bad named entity: zdot without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zdot"
+ ]
+ ]
+ },
+ {
+ "input": "ż",
+ "description": "Named entity: zdot; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u017c"
+ ]
+ ]
+ },
+ {
+ "input": "&zeetrf",
+ "description": "Bad named entity: zeetrf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zeetrf"
+ ]
+ ]
+ },
+ {
+ "input": "ℨ",
+ "description": "Named entity: zeetrf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u2128"
+ ]
+ ]
+ },
+ {
+ "input": "&zeta",
+ "description": "Bad named entity: zeta without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zeta"
+ ]
+ ]
+ },
+ {
+ "input": "ζ",
+ "description": "Named entity: zeta; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u03b6"
+ ]
+ ]
+ },
+ {
+ "input": "&zfr",
+ "description": "Bad named entity: zfr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zfr"
+ ]
+ ]
+ },
+ {
+ "input": "𝔷",
+ "description": "Named entity: zfr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd37"
+ ]
+ ]
+ },
+ {
+ "input": "&zhcy",
+ "description": "Bad named entity: zhcy without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zhcy"
+ ]
+ ]
+ },
+ {
+ "input": "ж",
+ "description": "Named entity: zhcy; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u0436"
+ ]
+ ]
+ },
+ {
+ "input": "&zigrarr",
+ "description": "Bad named entity: zigrarr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zigrarr"
+ ]
+ ]
+ },
+ {
+ "input": "⇝",
+ "description": "Named entity: zigrarr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u21dd"
+ ]
+ ]
+ },
+ {
+ "input": "&zopf",
+ "description": "Bad named entity: zopf without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zopf"
+ ]
+ ]
+ },
+ {
+ "input": "𝕫",
+ "description": "Named entity: zopf; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udd6b"
+ ]
+ ]
+ },
+ {
+ "input": "&zscr",
+ "description": "Bad named entity: zscr without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zscr"
+ ]
+ ]
+ },
+ {
+ "input": "𝓏",
+ "description": "Named entity: zscr; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\ud835\udccf"
+ ]
+ ]
+ },
+ {
+ "input": "&zwj",
+ "description": "Bad named entity: zwj without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zwj"
+ ]
+ ]
+ },
+ {
+ "input": "‍",
+ "description": "Named entity: zwj; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200d"
+ ]
+ ]
+ },
+ {
+ "input": "&zwnj",
+ "description": "Bad named entity: zwnj without a semi-colon",
+ "output": [
+ "ParseError",
+ [
+ "Character",
+ "&zwnj"
+ ]
+ ]
+ },
+ {
+ "input": "‌",
+ "description": "Named entity: zwnj; with a semi-colon",
+ "output": [
+ [
+ "Character",
+ "\u200c"
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/pkgs/html/test/data/tokenizer/numericEntities.test b/pkgs/html/test/data/tokenizer/numericEntities.test
new file mode 100644
index 0000000..36c8228
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/numericEntities.test
@@ -0,0 +1,1313 @@
+{"tests": [
+
+{"description": "Invalid numeric entity character U+0000",
+"input": "�",
+"output": ["ParseError", ["Character", "\uFFFD"]]},
+
+{"description": "Invalid numeric entity character U+0001",
+"input": "",
+"output": ["ParseError", ["Character", "\u0001"]]},
+
+{"description": "Invalid numeric entity character U+0002",
+"input": "",
+"output": ["ParseError", ["Character", "\u0002"]]},
+
+{"description": "Invalid numeric entity character U+0003",
+"input": "",
+"output": ["ParseError", ["Character", "\u0003"]]},
+
+{"description": "Invalid numeric entity character U+0004",
+"input": "",
+"output": ["ParseError", ["Character", "\u0004"]]},
+
+{"description": "Invalid numeric entity character U+0005",
+"input": "",
+"output": ["ParseError", ["Character", "\u0005"]]},
+
+{"description": "Invalid numeric entity character U+0006",
+"input": "",
+"output": ["ParseError", ["Character", "\u0006"]]},
+
+{"description": "Invalid numeric entity character U+0007",
+"input": "",
+"output": ["ParseError", ["Character", "\u0007"]]},
+
+{"description": "Invalid numeric entity character U+0008",
+"input": "",
+"output": ["ParseError", ["Character", "\u0008"]]},
+
+{"description": "Invalid numeric entity character U+000B",
+"input": "",
+"output": ["ParseError", ["Character", "\u000b"]]},
+
+{"description": "Invalid numeric entity character U+000E",
+"input": "",
+"output": ["ParseError", ["Character", "\u000e"]]},
+
+{"description": "Invalid numeric entity character U+000F",
+"input": "",
+"output": ["ParseError", ["Character", "\u000f"]]},
+
+{"description": "Invalid numeric entity character U+0010",
+"input": "",
+"output": ["ParseError", ["Character", "\u0010"]]},
+
+{"description": "Invalid numeric entity character U+0011",
+"input": "",
+"output": ["ParseError", ["Character", "\u0011"]]},
+
+{"description": "Invalid numeric entity character U+0012",
+"input": "",
+"output": ["ParseError", ["Character", "\u0012"]]},
+
+{"description": "Invalid numeric entity character U+0013",
+"input": "",
+"output": ["ParseError", ["Character", "\u0013"]]},
+
+{"description": "Invalid numeric entity character U+0014",
+"input": "",
+"output": ["ParseError", ["Character", "\u0014"]]},
+
+{"description": "Invalid numeric entity character U+0015",
+"input": "",
+"output": ["ParseError", ["Character", "\u0015"]]},
+
+{"description": "Invalid numeric entity character U+0016",
+"input": "",
+"output": ["ParseError", ["Character", "\u0016"]]},
+
+{"description": "Invalid numeric entity character U+0017",
+"input": "",
+"output": ["ParseError", ["Character", "\u0017"]]},
+
+{"description": "Invalid numeric entity character U+0018",
+"input": "",
+"output": ["ParseError", ["Character", "\u0018"]]},
+
+{"description": "Invalid numeric entity character U+0019",
+"input": "",
+"output": ["ParseError", ["Character", "\u0019"]]},
+
+{"description": "Invalid numeric entity character U+001A",
+"input": "",
+"output": ["ParseError", ["Character", "\u001a"]]},
+
+{"description": "Invalid numeric entity character U+001B",
+"input": "",
+"output": ["ParseError", ["Character", "\u001b"]]},
+
+{"description": "Invalid numeric entity character U+001C",
+"input": "",
+"output": ["ParseError", ["Character", "\u001c"]]},
+
+{"description": "Invalid numeric entity character U+001D",
+"input": "",
+"output": ["ParseError", ["Character", "\u001d"]]},
+
+{"description": "Invalid numeric entity character U+001E",
+"input": "",
+"output": ["ParseError", ["Character", "\u001e"]]},
+
+{"description": "Invalid numeric entity character U+001F",
+"input": "",
+"output": ["ParseError", ["Character", "\u001f"]]},
+
+{"description": "Invalid numeric entity character U+007F",
+"input": "",
+"output": ["ParseError", ["Character", "\u007f"]]},
+
+{"description": "Invalid numeric entity character U+D800",
+"input": "�",
+"output": ["ParseError", ["Character", "\uFFFD"]]},
+
+{"description": "Invalid numeric entity character U+DFFF",
+"input": "�",
+"output": ["ParseError", ["Character", "\uFFFD"]]},
+
+{"description": "Invalid numeric entity character U+FDD0",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd0"]]},
+
+{"description": "Invalid numeric entity character U+FDD1",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd1"]]},
+
+{"description": "Invalid numeric entity character U+FDD2",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd2"]]},
+
+{"description": "Invalid numeric entity character U+FDD3",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd3"]]},
+
+{"description": "Invalid numeric entity character U+FDD4",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd4"]]},
+
+{"description": "Invalid numeric entity character U+FDD5",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd5"]]},
+
+{"description": "Invalid numeric entity character U+FDD6",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd6"]]},
+
+{"description": "Invalid numeric entity character U+FDD7",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd7"]]},
+
+{"description": "Invalid numeric entity character U+FDD8",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd8"]]},
+
+{"description": "Invalid numeric entity character U+FDD9",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdd9"]]},
+
+{"description": "Invalid numeric entity character U+FDDA",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdda"]]},
+
+{"description": "Invalid numeric entity character U+FDDB",
+"input": "",
+"output": ["ParseError", ["Character", "\ufddb"]]},
+
+{"description": "Invalid numeric entity character U+FDDC",
+"input": "",
+"output": ["ParseError", ["Character", "\ufddc"]]},
+
+{"description": "Invalid numeric entity character U+FDDD",
+"input": "",
+"output": ["ParseError", ["Character", "\ufddd"]]},
+
+{"description": "Invalid numeric entity character U+FDDE",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdde"]]},
+
+{"description": "Invalid numeric entity character U+FDDF",
+"input": "",
+"output": ["ParseError", ["Character", "\ufddf"]]},
+
+{"description": "Invalid numeric entity character U+FDE0",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde0"]]},
+
+{"description": "Invalid numeric entity character U+FDE1",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde1"]]},
+
+{"description": "Invalid numeric entity character U+FDE2",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde2"]]},
+
+{"description": "Invalid numeric entity character U+FDE3",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde3"]]},
+
+{"description": "Invalid numeric entity character U+FDE4",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde4"]]},
+
+{"description": "Invalid numeric entity character U+FDE5",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde5"]]},
+
+{"description": "Invalid numeric entity character U+FDE6",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde6"]]},
+
+{"description": "Invalid numeric entity character U+FDE7",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde7"]]},
+
+{"description": "Invalid numeric entity character U+FDE8",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde8"]]},
+
+{"description": "Invalid numeric entity character U+FDE9",
+"input": "",
+"output": ["ParseError", ["Character", "\ufde9"]]},
+
+{"description": "Invalid numeric entity character U+FDEA",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdea"]]},
+
+{"description": "Invalid numeric entity character U+FDEB",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdeb"]]},
+
+{"description": "Invalid numeric entity character U+FDEC",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdec"]]},
+
+{"description": "Invalid numeric entity character U+FDED",
+"input": "",
+"output": ["ParseError", ["Character", "\ufded"]]},
+
+{"description": "Invalid numeric entity character U+FDEE",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdee"]]},
+
+{"description": "Invalid numeric entity character U+FDEF",
+"input": "",
+"output": ["ParseError", ["Character", "\ufdef"]]},
+
+{"description": "Invalid numeric entity character U+FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\ufffe"]]},
+
+{"description": "Invalid numeric entity character U+FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uffff"]]},
+
+{"description": "Invalid numeric entity character U+1FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uD83F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+1FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uD83F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+2FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uD87F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+2FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uD87F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+3FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uD8BF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+3FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uD8BF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+4FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uD8FF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+4FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uD8FF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+5FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uD93F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+5FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uD93F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+6FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uD97F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+6FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uD97F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+7FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uD9BF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+7FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uD9BF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+8FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uD9FF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+8FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uD9FF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+9FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uDA3F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+9FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uDA3F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+AFFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uDA7F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+AFFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uDA7F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+BFFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uDABF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+BFFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uDABF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+CFFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uDAFF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+CFFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uDAFF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+DFFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uDB3F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+DFFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uDB3F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+EFFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uDB7F\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+EFFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uDB7F\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+FFFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uDBBF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+FFFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uDBBF\uDFFF"]]},
+
+{"description": "Invalid numeric entity character U+10FFFE",
+"input": "",
+"output": ["ParseError", ["Character", "\uDBFF\uDFFE"]]},
+
+{"description": "Invalid numeric entity character U+10FFFF",
+"input": "",
+"output": ["ParseError", ["Character", "\uDBFF\uDFFF"]]},
+
+{"description": "Valid numeric entity character U+0009",
+"input": "	",
+"output": [["Character", "\u0009"]]},
+
+{"description": "Valid numeric entity character U+000A",
+"input": "
",
+"output": [["Character", "\u000A"]]},
+
+{"description": "Valid numeric entity character U+0020",
+"input": " ",
+"output": [["Character", "\u0020"]]},
+
+{"description": "Valid numeric entity character U+0021",
+"input": "!",
+"output": [["Character", "\u0021"]]},
+
+{"description": "Valid numeric entity character U+0022",
+"input": """,
+"output": [["Character", "\u0022"]]},
+
+{"description": "Valid numeric entity character U+0023",
+"input": "#",
+"output": [["Character", "\u0023"]]},
+
+{"description": "Valid numeric entity character U+0024",
+"input": "$",
+"output": [["Character", "\u0024"]]},
+
+{"description": "Valid numeric entity character U+0025",
+"input": "%",
+"output": [["Character", "\u0025"]]},
+
+{"description": "Valid numeric entity character U+0026",
+"input": "&",
+"output": [["Character", "\u0026"]]},
+
+{"description": "Valid numeric entity character U+0027",
+"input": "'",
+"output": [["Character", "\u0027"]]},
+
+{"description": "Valid numeric entity character U+0028",
+"input": "(",
+"output": [["Character", "\u0028"]]},
+
+{"description": "Valid numeric entity character U+0029",
+"input": ")",
+"output": [["Character", "\u0029"]]},
+
+{"description": "Valid numeric entity character U+002A",
+"input": "*",
+"output": [["Character", "\u002A"]]},
+
+{"description": "Valid numeric entity character U+002B",
+"input": "+",
+"output": [["Character", "\u002B"]]},
+
+{"description": "Valid numeric entity character U+002C",
+"input": ",",
+"output": [["Character", "\u002C"]]},
+
+{"description": "Valid numeric entity character U+002D",
+"input": "-",
+"output": [["Character", "\u002D"]]},
+
+{"description": "Valid numeric entity character U+002E",
+"input": ".",
+"output": [["Character", "\u002E"]]},
+
+{"description": "Valid numeric entity character U+002F",
+"input": "/",
+"output": [["Character", "\u002F"]]},
+
+{"description": "Valid numeric entity character U+0030",
+"input": "0",
+"output": [["Character", "\u0030"]]},
+
+{"description": "Valid numeric entity character U+0031",
+"input": "1",
+"output": [["Character", "\u0031"]]},
+
+{"description": "Valid numeric entity character U+0032",
+"input": "2",
+"output": [["Character", "\u0032"]]},
+
+{"description": "Valid numeric entity character U+0033",
+"input": "3",
+"output": [["Character", "\u0033"]]},
+
+{"description": "Valid numeric entity character U+0034",
+"input": "4",
+"output": [["Character", "\u0034"]]},
+
+{"description": "Valid numeric entity character U+0035",
+"input": "5",
+"output": [["Character", "\u0035"]]},
+
+{"description": "Valid numeric entity character U+0036",
+"input": "6",
+"output": [["Character", "\u0036"]]},
+
+{"description": "Valid numeric entity character U+0037",
+"input": "7",
+"output": [["Character", "\u0037"]]},
+
+{"description": "Valid numeric entity character U+0038",
+"input": "8",
+"output": [["Character", "\u0038"]]},
+
+{"description": "Valid numeric entity character U+0039",
+"input": "9",
+"output": [["Character", "\u0039"]]},
+
+{"description": "Valid numeric entity character U+003A",
+"input": ":",
+"output": [["Character", "\u003A"]]},
+
+{"description": "Valid numeric entity character U+003B",
+"input": ";",
+"output": [["Character", "\u003B"]]},
+
+{"description": "Valid numeric entity character U+003C",
+"input": "<",
+"output": [["Character", "\u003C"]]},
+
+{"description": "Valid numeric entity character U+003D",
+"input": "=",
+"output": [["Character", "\u003D"]]},
+
+{"description": "Valid numeric entity character U+003E",
+"input": ">",
+"output": [["Character", "\u003E"]]},
+
+{"description": "Valid numeric entity character U+003F",
+"input": "?",
+"output": [["Character", "\u003F"]]},
+
+{"description": "Valid numeric entity character U+0040",
+"input": "@",
+"output": [["Character", "\u0040"]]},
+
+{"description": "Valid numeric entity character U+0041",
+"input": "A",
+"output": [["Character", "\u0041"]]},
+
+{"description": "Valid numeric entity character U+0042",
+"input": "B",
+"output": [["Character", "\u0042"]]},
+
+{"description": "Valid numeric entity character U+0043",
+"input": "C",
+"output": [["Character", "\u0043"]]},
+
+{"description": "Valid numeric entity character U+0044",
+"input": "D",
+"output": [["Character", "\u0044"]]},
+
+{"description": "Valid numeric entity character U+0045",
+"input": "E",
+"output": [["Character", "\u0045"]]},
+
+{"description": "Valid numeric entity character U+0046",
+"input": "F",
+"output": [["Character", "\u0046"]]},
+
+{"description": "Valid numeric entity character U+0047",
+"input": "G",
+"output": [["Character", "\u0047"]]},
+
+{"description": "Valid numeric entity character U+0048",
+"input": "H",
+"output": [["Character", "\u0048"]]},
+
+{"description": "Valid numeric entity character U+0049",
+"input": "I",
+"output": [["Character", "\u0049"]]},
+
+{"description": "Valid numeric entity character U+004A",
+"input": "J",
+"output": [["Character", "\u004A"]]},
+
+{"description": "Valid numeric entity character U+004B",
+"input": "K",
+"output": [["Character", "\u004B"]]},
+
+{"description": "Valid numeric entity character U+004C",
+"input": "L",
+"output": [["Character", "\u004C"]]},
+
+{"description": "Valid numeric entity character U+004D",
+"input": "M",
+"output": [["Character", "\u004D"]]},
+
+{"description": "Valid numeric entity character U+004E",
+"input": "N",
+"output": [["Character", "\u004E"]]},
+
+{"description": "Valid numeric entity character U+004F",
+"input": "O",
+"output": [["Character", "\u004F"]]},
+
+{"description": "Valid numeric entity character U+0050",
+"input": "P",
+"output": [["Character", "\u0050"]]},
+
+{"description": "Valid numeric entity character U+0051",
+"input": "Q",
+"output": [["Character", "\u0051"]]},
+
+{"description": "Valid numeric entity character U+0052",
+"input": "R",
+"output": [["Character", "\u0052"]]},
+
+{"description": "Valid numeric entity character U+0053",
+"input": "S",
+"output": [["Character", "\u0053"]]},
+
+{"description": "Valid numeric entity character U+0054",
+"input": "T",
+"output": [["Character", "\u0054"]]},
+
+{"description": "Valid numeric entity character U+0055",
+"input": "U",
+"output": [["Character", "\u0055"]]},
+
+{"description": "Valid numeric entity character U+0056",
+"input": "V",
+"output": [["Character", "\u0056"]]},
+
+{"description": "Valid numeric entity character U+0057",
+"input": "W",
+"output": [["Character", "\u0057"]]},
+
+{"description": "Valid numeric entity character U+0058",
+"input": "X",
+"output": [["Character", "\u0058"]]},
+
+{"description": "Valid numeric entity character U+0059",
+"input": "Y",
+"output": [["Character", "\u0059"]]},
+
+{"description": "Valid numeric entity character U+005A",
+"input": "Z",
+"output": [["Character", "\u005A"]]},
+
+{"description": "Valid numeric entity character U+005B",
+"input": "[",
+"output": [["Character", "\u005B"]]},
+
+{"description": "Valid numeric entity character U+005C",
+"input": "\",
+"output": [["Character", "\u005C"]]},
+
+{"description": "Valid numeric entity character U+005D",
+"input": "]",
+"output": [["Character", "\u005D"]]},
+
+{"description": "Valid numeric entity character U+005E",
+"input": "^",
+"output": [["Character", "\u005E"]]},
+
+{"description": "Valid numeric entity character U+005F",
+"input": "_",
+"output": [["Character", "\u005F"]]},
+
+{"description": "Valid numeric entity character U+0060",
+"input": "`",
+"output": [["Character", "\u0060"]]},
+
+{"description": "Valid numeric entity character U+0061",
+"input": "a",
+"output": [["Character", "\u0061"]]},
+
+{"description": "Valid numeric entity character U+0062",
+"input": "b",
+"output": [["Character", "\u0062"]]},
+
+{"description": "Valid numeric entity character U+0063",
+"input": "c",
+"output": [["Character", "\u0063"]]},
+
+{"description": "Valid numeric entity character U+0064",
+"input": "d",
+"output": [["Character", "\u0064"]]},
+
+{"description": "Valid numeric entity character U+0065",
+"input": "e",
+"output": [["Character", "\u0065"]]},
+
+{"description": "Valid numeric entity character U+0066",
+"input": "f",
+"output": [["Character", "\u0066"]]},
+
+{"description": "Valid numeric entity character U+0067",
+"input": "g",
+"output": [["Character", "\u0067"]]},
+
+{"description": "Valid numeric entity character U+0068",
+"input": "h",
+"output": [["Character", "\u0068"]]},
+
+{"description": "Valid numeric entity character U+0069",
+"input": "i",
+"output": [["Character", "\u0069"]]},
+
+{"description": "Valid numeric entity character U+006A",
+"input": "j",
+"output": [["Character", "\u006A"]]},
+
+{"description": "Valid numeric entity character U+006B",
+"input": "k",
+"output": [["Character", "\u006B"]]},
+
+{"description": "Valid numeric entity character U+006C",
+"input": "l",
+"output": [["Character", "\u006C"]]},
+
+{"description": "Valid numeric entity character U+006D",
+"input": "m",
+"output": [["Character", "\u006D"]]},
+
+{"description": "Valid numeric entity character U+006E",
+"input": "n",
+"output": [["Character", "\u006E"]]},
+
+{"description": "Valid numeric entity character U+006F",
+"input": "o",
+"output": [["Character", "\u006F"]]},
+
+{"description": "Valid numeric entity character U+0070",
+"input": "p",
+"output": [["Character", "\u0070"]]},
+
+{"description": "Valid numeric entity character U+0071",
+"input": "q",
+"output": [["Character", "\u0071"]]},
+
+{"description": "Valid numeric entity character U+0072",
+"input": "r",
+"output": [["Character", "\u0072"]]},
+
+{"description": "Valid numeric entity character U+0073",
+"input": "s",
+"output": [["Character", "\u0073"]]},
+
+{"description": "Valid numeric entity character U+0074",
+"input": "t",
+"output": [["Character", "\u0074"]]},
+
+{"description": "Valid numeric entity character U+0075",
+"input": "u",
+"output": [["Character", "\u0075"]]},
+
+{"description": "Valid numeric entity character U+0076",
+"input": "v",
+"output": [["Character", "\u0076"]]},
+
+{"description": "Valid numeric entity character U+0077",
+"input": "w",
+"output": [["Character", "\u0077"]]},
+
+{"description": "Valid numeric entity character U+0078",
+"input": "x",
+"output": [["Character", "\u0078"]]},
+
+{"description": "Valid numeric entity character U+0079",
+"input": "y",
+"output": [["Character", "\u0079"]]},
+
+{"description": "Valid numeric entity character U+007A",
+"input": "z",
+"output": [["Character", "\u007A"]]},
+
+{"description": "Valid numeric entity character U+007B",
+"input": "{",
+"output": [["Character", "\u007B"]]},
+
+{"description": "Valid numeric entity character U+007C",
+"input": "|",
+"output": [["Character", "\u007C"]]},
+
+{"description": "Valid numeric entity character U+007D",
+"input": "}",
+"output": [["Character", "\u007D"]]},
+
+{"description": "Valid numeric entity character U+007E",
+"input": "~",
+"output": [["Character", "\u007E"]]},
+
+{"description": "Valid numeric entity character U+00A0",
+"input": " ",
+"output": [["Character", "\u00A0"]]},
+
+{"description": "Valid numeric entity character U+00A1",
+"input": "¡",
+"output": [["Character", "\u00A1"]]},
+
+{"description": "Valid numeric entity character U+00A2",
+"input": "¢",
+"output": [["Character", "\u00A2"]]},
+
+{"description": "Valid numeric entity character U+00A3",
+"input": "£",
+"output": [["Character", "\u00A3"]]},
+
+{"description": "Valid numeric entity character U+00A4",
+"input": "¤",
+"output": [["Character", "\u00A4"]]},
+
+{"description": "Valid numeric entity character U+00A5",
+"input": "¥",
+"output": [["Character", "\u00A5"]]},
+
+{"description": "Valid numeric entity character U+00A6",
+"input": "¦",
+"output": [["Character", "\u00A6"]]},
+
+{"description": "Valid numeric entity character U+00A7",
+"input": "§",
+"output": [["Character", "\u00A7"]]},
+
+{"description": "Valid numeric entity character U+00A8",
+"input": "¨",
+"output": [["Character", "\u00A8"]]},
+
+{"description": "Valid numeric entity character U+00A9",
+"input": "©",
+"output": [["Character", "\u00A9"]]},
+
+{"description": "Valid numeric entity character U+00AA",
+"input": "ª",
+"output": [["Character", "\u00AA"]]},
+
+{"description": "Valid numeric entity character U+00AB",
+"input": "«",
+"output": [["Character", "\u00AB"]]},
+
+{"description": "Valid numeric entity character U+00AC",
+"input": "¬",
+"output": [["Character", "\u00AC"]]},
+
+{"description": "Valid numeric entity character U+00AD",
+"input": "­",
+"output": [["Character", "\u00AD"]]},
+
+{"description": "Valid numeric entity character U+00AE",
+"input": "®",
+"output": [["Character", "\u00AE"]]},
+
+{"description": "Valid numeric entity character U+00AF",
+"input": "¯",
+"output": [["Character", "\u00AF"]]},
+
+{"description": "Valid numeric entity character U+00B0",
+"input": "°",
+"output": [["Character", "\u00B0"]]},
+
+{"description": "Valid numeric entity character U+00B1",
+"input": "±",
+"output": [["Character", "\u00B1"]]},
+
+{"description": "Valid numeric entity character U+00B2",
+"input": "²",
+"output": [["Character", "\u00B2"]]},
+
+{"description": "Valid numeric entity character U+00B3",
+"input": "³",
+"output": [["Character", "\u00B3"]]},
+
+{"description": "Valid numeric entity character U+00B4",
+"input": "´",
+"output": [["Character", "\u00B4"]]},
+
+{"description": "Valid numeric entity character U+00B5",
+"input": "µ",
+"output": [["Character", "\u00B5"]]},
+
+{"description": "Valid numeric entity character U+00B6",
+"input": "¶",
+"output": [["Character", "\u00B6"]]},
+
+{"description": "Valid numeric entity character U+00B7",
+"input": "·",
+"output": [["Character", "\u00B7"]]},
+
+{"description": "Valid numeric entity character U+00B8",
+"input": "¸",
+"output": [["Character", "\u00B8"]]},
+
+{"description": "Valid numeric entity character U+00B9",
+"input": "¹",
+"output": [["Character", "\u00B9"]]},
+
+{"description": "Valid numeric entity character U+00BA",
+"input": "º",
+"output": [["Character", "\u00BA"]]},
+
+{"description": "Valid numeric entity character U+00BB",
+"input": "»",
+"output": [["Character", "\u00BB"]]},
+
+{"description": "Valid numeric entity character U+00BC",
+"input": "¼",
+"output": [["Character", "\u00BC"]]},
+
+{"description": "Valid numeric entity character U+00BD",
+"input": "½",
+"output": [["Character", "\u00BD"]]},
+
+{"description": "Valid numeric entity character U+00BE",
+"input": "¾",
+"output": [["Character", "\u00BE"]]},
+
+{"description": "Valid numeric entity character U+00BF",
+"input": "¿",
+"output": [["Character", "\u00BF"]]},
+
+{"description": "Valid numeric entity character U+00C0",
+"input": "À",
+"output": [["Character", "\u00C0"]]},
+
+{"description": "Valid numeric entity character U+00C1",
+"input": "Á",
+"output": [["Character", "\u00C1"]]},
+
+{"description": "Valid numeric entity character U+00C2",
+"input": "Â",
+"output": [["Character", "\u00C2"]]},
+
+{"description": "Valid numeric entity character U+00C3",
+"input": "Ã",
+"output": [["Character", "\u00C3"]]},
+
+{"description": "Valid numeric entity character U+00C4",
+"input": "Ä",
+"output": [["Character", "\u00C4"]]},
+
+{"description": "Valid numeric entity character U+00C5",
+"input": "Å",
+"output": [["Character", "\u00C5"]]},
+
+{"description": "Valid numeric entity character U+00C6",
+"input": "Æ",
+"output": [["Character", "\u00C6"]]},
+
+{"description": "Valid numeric entity character U+00C7",
+"input": "Ç",
+"output": [["Character", "\u00C7"]]},
+
+{"description": "Valid numeric entity character U+00C8",
+"input": "È",
+"output": [["Character", "\u00C8"]]},
+
+{"description": "Valid numeric entity character U+00C9",
+"input": "É",
+"output": [["Character", "\u00C9"]]},
+
+{"description": "Valid numeric entity character U+00CA",
+"input": "Ê",
+"output": [["Character", "\u00CA"]]},
+
+{"description": "Valid numeric entity character U+00CB",
+"input": "Ë",
+"output": [["Character", "\u00CB"]]},
+
+{"description": "Valid numeric entity character U+00CC",
+"input": "Ì",
+"output": [["Character", "\u00CC"]]},
+
+{"description": "Valid numeric entity character U+00CD",
+"input": "Í",
+"output": [["Character", "\u00CD"]]},
+
+{"description": "Valid numeric entity character U+00CE",
+"input": "Î",
+"output": [["Character", "\u00CE"]]},
+
+{"description": "Valid numeric entity character U+00CF",
+"input": "Ï",
+"output": [["Character", "\u00CF"]]},
+
+{"description": "Valid numeric entity character U+00D0",
+"input": "Ð",
+"output": [["Character", "\u00D0"]]},
+
+{"description": "Valid numeric entity character U+00D1",
+"input": "Ñ",
+"output": [["Character", "\u00D1"]]},
+
+{"description": "Valid numeric entity character U+00D2",
+"input": "Ò",
+"output": [["Character", "\u00D2"]]},
+
+{"description": "Valid numeric entity character U+00D3",
+"input": "Ó",
+"output": [["Character", "\u00D3"]]},
+
+{"description": "Valid numeric entity character U+00D4",
+"input": "Ô",
+"output": [["Character", "\u00D4"]]},
+
+{"description": "Valid numeric entity character U+00D5",
+"input": "Õ",
+"output": [["Character", "\u00D5"]]},
+
+{"description": "Valid numeric entity character U+00D6",
+"input": "Ö",
+"output": [["Character", "\u00D6"]]},
+
+{"description": "Valid numeric entity character U+00D7",
+"input": "×",
+"output": [["Character", "\u00D7"]]},
+
+{"description": "Valid numeric entity character U+00D8",
+"input": "Ø",
+"output": [["Character", "\u00D8"]]},
+
+{"description": "Valid numeric entity character U+00D9",
+"input": "Ù",
+"output": [["Character", "\u00D9"]]},
+
+{"description": "Valid numeric entity character U+00DA",
+"input": "Ú",
+"output": [["Character", "\u00DA"]]},
+
+{"description": "Valid numeric entity character U+00DB",
+"input": "Û",
+"output": [["Character", "\u00DB"]]},
+
+{"description": "Valid numeric entity character U+00DC",
+"input": "Ü",
+"output": [["Character", "\u00DC"]]},
+
+{"description": "Valid numeric entity character U+00DD",
+"input": "Ý",
+"output": [["Character", "\u00DD"]]},
+
+{"description": "Valid numeric entity character U+00DE",
+"input": "Þ",
+"output": [["Character", "\u00DE"]]},
+
+{"description": "Valid numeric entity character U+00DF",
+"input": "ß",
+"output": [["Character", "\u00DF"]]},
+
+{"description": "Valid numeric entity character U+00E0",
+"input": "à",
+"output": [["Character", "\u00E0"]]},
+
+{"description": "Valid numeric entity character U+00E1",
+"input": "á",
+"output": [["Character", "\u00E1"]]},
+
+{"description": "Valid numeric entity character U+00E2",
+"input": "â",
+"output": [["Character", "\u00E2"]]},
+
+{"description": "Valid numeric entity character U+00E3",
+"input": "ã",
+"output": [["Character", "\u00E3"]]},
+
+{"description": "Valid numeric entity character U+00E4",
+"input": "ä",
+"output": [["Character", "\u00E4"]]},
+
+{"description": "Valid numeric entity character U+00E5",
+"input": "å",
+"output": [["Character", "\u00E5"]]},
+
+{"description": "Valid numeric entity character U+00E6",
+"input": "æ",
+"output": [["Character", "\u00E6"]]},
+
+{"description": "Valid numeric entity character U+00E7",
+"input": "ç",
+"output": [["Character", "\u00E7"]]},
+
+{"description": "Valid numeric entity character U+00E8",
+"input": "è",
+"output": [["Character", "\u00E8"]]},
+
+{"description": "Valid numeric entity character U+00E9",
+"input": "é",
+"output": [["Character", "\u00E9"]]},
+
+{"description": "Valid numeric entity character U+00EA",
+"input": "ê",
+"output": [["Character", "\u00EA"]]},
+
+{"description": "Valid numeric entity character U+00EB",
+"input": "ë",
+"output": [["Character", "\u00EB"]]},
+
+{"description": "Valid numeric entity character U+00EC",
+"input": "ì",
+"output": [["Character", "\u00EC"]]},
+
+{"description": "Valid numeric entity character U+00ED",
+"input": "í",
+"output": [["Character", "\u00ED"]]},
+
+{"description": "Valid numeric entity character U+00EE",
+"input": "î",
+"output": [["Character", "\u00EE"]]},
+
+{"description": "Valid numeric entity character U+00EF",
+"input": "ï",
+"output": [["Character", "\u00EF"]]},
+
+{"description": "Valid numeric entity character U+00F0",
+"input": "ð",
+"output": [["Character", "\u00F0"]]},
+
+{"description": "Valid numeric entity character U+00F1",
+"input": "ñ",
+"output": [["Character", "\u00F1"]]},
+
+{"description": "Valid numeric entity character U+00F2",
+"input": "ò",
+"output": [["Character", "\u00F2"]]},
+
+{"description": "Valid numeric entity character U+00F3",
+"input": "ó",
+"output": [["Character", "\u00F3"]]},
+
+{"description": "Valid numeric entity character U+00F4",
+"input": "ô",
+"output": [["Character", "\u00F4"]]},
+
+{"description": "Valid numeric entity character U+00F5",
+"input": "õ",
+"output": [["Character", "\u00F5"]]},
+
+{"description": "Valid numeric entity character U+00F6",
+"input": "ö",
+"output": [["Character", "\u00F6"]]},
+
+{"description": "Valid numeric entity character U+00F7",
+"input": "÷",
+"output": [["Character", "\u00F7"]]},
+
+{"description": "Valid numeric entity character U+00F8",
+"input": "ø",
+"output": [["Character", "\u00F8"]]},
+
+{"description": "Valid numeric entity character U+00F9",
+"input": "ù",
+"output": [["Character", "\u00F9"]]},
+
+{"description": "Valid numeric entity character U+00FA",
+"input": "ú",
+"output": [["Character", "\u00FA"]]},
+
+{"description": "Valid numeric entity character U+00FB",
+"input": "û",
+"output": [["Character", "\u00FB"]]},
+
+{"description": "Valid numeric entity character U+00FC",
+"input": "ü",
+"output": [["Character", "\u00FC"]]},
+
+{"description": "Valid numeric entity character U+00FD",
+"input": "ý",
+"output": [["Character", "\u00FD"]]},
+
+{"description": "Valid numeric entity character U+00FE",
+"input": "þ",
+"output": [["Character", "\u00FE"]]},
+
+{"description": "Valid numeric entity character U+00FF",
+"input": "ÿ",
+"output": [["Character", "\u00FF"]]},
+
+{"description": "Valid numeric entity character U+D7FF",
+"input": "퟿",
+"output": [["Character", "\uD7FF"]]},
+
+{"description": "Valid numeric entity character U+E000",
+"input": "",
+"output": [["Character", "\uE000"]]},
+
+{"description": "Valid numeric entity character U+FDCF",
+"input": "﷏",
+"output": [["Character", "\uFDCF"]]},
+
+{"description": "Valid numeric entity character U+FDF0",
+"input": "ﷰ",
+"output": [["Character", "\uFDF0"]]},
+
+{"description": "Valid numeric entity character U+FFFD",
+"input": "�",
+"output": [["Character", "\uFFFD"]]},
+
+{"description": "Valid numeric entity character U+10000",
+"input": "𐀀",
+"output": [["Character", "\uD800\uDC00"]]},
+
+{"description": "Valid numeric entity character U+1FFFD",
+"input": "🿽",
+"output": [["Character", "\uD83F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+20000",
+"input": "𠀀",
+"output": [["Character", "\uD840\uDC00"]]},
+
+{"description": "Valid numeric entity character U+2FFFD",
+"input": "𯿽",
+"output": [["Character", "\uD87F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+30000",
+"input": "𰀀",
+"output": [["Character", "\uD880\uDC00"]]},
+
+{"description": "Valid numeric entity character U+3FFFD",
+"input": "𿿽",
+"output": [["Character", "\uD8BF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+40000",
+"input": "񀀀",
+"output": [["Character", "\uD8C0\uDC00"]]},
+
+{"description": "Valid numeric entity character U+4FFFD",
+"input": "񏿽",
+"output": [["Character", "\uD8FF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+50000",
+"input": "񐀀",
+"output": [["Character", "\uD900\uDC00"]]},
+
+{"description": "Valid numeric entity character U+5FFFD",
+"input": "񟿽",
+"output": [["Character", "\uD93F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+60000",
+"input": "񠀀",
+"output": [["Character", "\uD940\uDC00"]]},
+
+{"description": "Valid numeric entity character U+6FFFD",
+"input": "񯿽",
+"output": [["Character", "\uD97F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+70000",
+"input": "񰀀",
+"output": [["Character", "\uD980\uDC00"]]},
+
+{"description": "Valid numeric entity character U+7FFFD",
+"input": "񿿽",
+"output": [["Character", "\uD9BF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+80000",
+"input": "򀀀",
+"output": [["Character", "\uD9C0\uDC00"]]},
+
+{"description": "Valid numeric entity character U+8FFFD",
+"input": "򏿽",
+"output": [["Character", "\uD9FF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+90000",
+"input": "򐀀",
+"output": [["Character", "\uDA00\uDC00"]]},
+
+{"description": "Valid numeric entity character U+9FFFD",
+"input": "򟿽",
+"output": [["Character", "\uDA3F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+A0000",
+"input": "򠀀",
+"output": [["Character", "\uDA40\uDC00"]]},
+
+{"description": "Valid numeric entity character U+AFFFD",
+"input": "򯿽",
+"output": [["Character", "\uDA7F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+B0000",
+"input": "򰀀",
+"output": [["Character", "\uDA80\uDC00"]]},
+
+{"description": "Valid numeric entity character U+BFFFD",
+"input": "򿿽",
+"output": [["Character", "\uDABF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+C0000",
+"input": "󀀀",
+"output": [["Character", "\uDAC0\uDC00"]]},
+
+{"description": "Valid numeric entity character U+CFFFD",
+"input": "󏿽",
+"output": [["Character", "\uDAFF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+D0000",
+"input": "󐀀",
+"output": [["Character", "\uDB00\uDC00"]]},
+
+{"description": "Valid numeric entity character U+DFFFD",
+"input": "󟿽",
+"output": [["Character", "\uDB3F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+E0000",
+"input": "󠀀",
+"output": [["Character", "\uDB40\uDC00"]]},
+
+{"description": "Valid numeric entity character U+EFFFD",
+"input": "󯿽",
+"output": [["Character", "\uDB7F\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+F0000",
+"input": "󰀀",
+"output": [["Character", "\uDB80\uDC00"]]},
+
+{"description": "Valid numeric entity character U+FFFFD",
+"input": "󿿽",
+"output": [["Character", "\uDBBF\uDFFD"]]},
+
+{"description": "Valid numeric entity character U+100000",
+"input": "􀀀",
+"output": [["Character", "\uDBC0\uDC00"]]},
+
+{"description": "Valid numeric entity character U+10FFFD",
+"input": "􏿽",
+"output": [["Character", "\uDBFF\uDFFD"]]}
+
+]}
+
+
diff --git a/pkgs/html/test/data/tokenizer/pendingSpecChanges.test b/pkgs/html/test/data/tokenizer/pendingSpecChanges.test
new file mode 100644
index 0000000..1b7dc3c
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/pendingSpecChanges.test
@@ -0,0 +1,7 @@
+{"tests": [
+
+{"description":"<!---- >",
+"input":"<!---- >",
+"output":["ParseError", "ParseError", ["Comment","-- >"]]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/test1.test b/pkgs/html/test/data/tokenizer/test1.test
new file mode 100644
index 0000000..5de66f5
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/test1.test
@@ -0,0 +1,196 @@
+{"tests": [
+
+{"description":"Correct Doctype lowercase",
+"input":"<!DOCTYPE html>",
+"output":[["DOCTYPE", "html", null, null, true]]},
+
+{"description":"Correct Doctype uppercase",
+"input":"<!DOCTYPE HTML>",
+"output":[["DOCTYPE", "html", null, null, true]]},
+
+{"description":"Correct Doctype mixed case",
+"input":"<!DOCTYPE HtMl>",
+"output":[["DOCTYPE", "html", null, null, true]]},
+
+{"description":"Correct Doctype case with EOF",
+"input":"<!DOCTYPE HtMl",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Truncated doctype start",
+"input":"<!DOC>",
+"output":["ParseError", ["Comment", "DOC"]]},
+
+{"description":"Doctype in error",
+"input":"<!DOCTYPE foo>",
+"output":[["DOCTYPE", "foo", null, null, true]]},
+
+{"description":"Single Start Tag",
+"input":"<h>",
+"output":[["StartTag", "h", {}]]},
+
+{"description":"Empty end tag",
+"input":"</>",
+"output":["ParseError"]},
+
+{"description":"Empty start tag",
+"input":"<>",
+"output":["ParseError", ["Character", "<>"]]},
+
+{"description":"Start Tag w/attribute",
+"input":"<h a='b'>",
+"output":[["StartTag", "h", {"a":"b"}]]},
+
+{"description":"Start Tag w/attribute no quotes",
+"input":"<h a=b>",
+"output":[["StartTag", "h", {"a":"b"}]]},
+
+{"description":"Start/End Tag",
+"input":"<h></h>",
+"output":[["StartTag", "h", {}], ["EndTag", "h"]]},
+
+{"description":"Two unclosed start tags",
+"input":"<p>One<p>Two",
+"output":[["StartTag", "p", {}], ["Character", "One"], ["StartTag", "p", {}], ["Character", "Two"]]},
+
+{"description":"End Tag w/attribute",
+"input":"<h></h a='b'>",
+"output":[["StartTag", "h", {}], "ParseError", ["EndTag", "h"]]},
+
+{"description":"Multiple atts",
+"input":"<h a='b' c='d'>",
+"output":[["StartTag", "h", {"a":"b", "c":"d"}]]},
+
+{"description":"Multiple atts no space",
+"input":"<h a='b'c='d'>",
+"output":["ParseError", ["StartTag", "h", {"a":"b", "c":"d"}]]},
+
+{"description":"Repeated attr",
+ "input":"<h a='b' a='d'>",
+ "output":["ParseError", ["StartTag", "h", {"a":"b"}]]},
+
+{"description":"Simple comment",
+ "input":"<!--comment-->",
+ "output":[["Comment", "comment"]]},
+
+{"description":"Comment, Central dash no space",
+ "input":"<!----->",
+ "output":["ParseError", ["Comment", "-"]]},
+
+{"description":"Comment, two central dashes",
+"input":"<!-- --comment -->",
+"output":["ParseError", ["Comment", " --comment "]]},
+
+{"description":"Unfinished comment",
+"input":"<!--comment",
+"output":["ParseError", ["Comment", "comment"]]},
+
+{"description":"Start of a comment",
+"input":"<!-",
+"output":["ParseError", ["Comment", "-"]]},
+
+{"description":"Short comment",
+ "input":"<!-->",
+ "output":["ParseError", ["Comment", ""]]},
+
+{"description":"Short comment two",
+ "input":"<!--->",
+ "output":["ParseError", ["Comment", ""]]},
+
+{"description":"Short comment three",
+ "input":"<!---->",
+ "output":[["Comment", ""]]},
+
+
+{"description":"Ampersand EOF",
+"input":"&",
+"output":[["Character", "&"]]},
+
+{"description":"Ampersand ampersand EOF",
+"input":"&&",
+"output":[["Character", "&&"]]},
+
+{"description":"Ampersand space EOF",
+"input":"& ",
+"output":[["Character", "& "]]},
+
+{"description":"Unfinished entity",
+"input":"&f",
+"output":["ParseError", ["Character", "&f"]]},
+
+{"description":"Ampersand, number sign",
+"input":"&#",
+"output":["ParseError", ["Character", "&#"]]},
+
+{"description":"Unfinished numeric entity",
+"input":"&#x",
+"output":["ParseError", ["Character", "&#x"]]},
+
+{"description":"Entity with trailing semicolon (1)",
+"input":"I'm ¬it",
+"output":[["Character","I'm \u00ACit"]]},
+
+{"description":"Entity with trailing semicolon (2)",
+"input":"I'm ∉",
+"output":[["Character","I'm \u2209"]]},
+
+{"description":"Entity without trailing semicolon (1)",
+"input":"I'm ¬it",
+"output":[["Character","I'm "], "ParseError", ["Character", "\u00ACit"]]},
+
+{"description":"Entity without trailing semicolon (2)",
+"input":"I'm ¬in",
+"output":[["Character","I'm "], "ParseError", ["Character", "\u00ACin"]]},
+
+{"description":"Partial entity match at end of file",
+"input":"I'm &no",
+"output":[["Character","I'm "], "ParseError", ["Character", "&no"]]},
+
+{"description":"Non-ASCII character reference name",
+"input":"&\u00AC;",
+"output":["ParseError", ["Character", "&\u00AC;"]]},
+
+{"description":"ASCII decimal entity",
+"input":"$",
+"output":[["Character","$"]]},
+
+{"description":"ASCII hexadecimal entity",
+"input":"?",
+"output":[["Character","?"]]},
+
+{"description":"Hexadecimal entity in attribute",
+"input":"<h a='?'></h>",
+"output":[["StartTag", "h", {"a":"?"}], ["EndTag", "h"]]},
+
+{"description":"Entity in attribute without semicolon ending in x",
+"input":"<h a='¬x'>",
+"output":["ParseError", ["StartTag", "h", {"a":"¬x"}]]},
+
+{"description":"Entity in attribute without semicolon ending in 1",
+"input":"<h a='¬1'>",
+"output":["ParseError", ["StartTag", "h", {"a":"¬1"}]]},
+
+{"description":"Entity in attribute without semicolon ending in i",
+"input":"<h a='¬i'>",
+"output":["ParseError", ["StartTag", "h", {"a":"¬i"}]]},
+
+{"description":"Entity in attribute without semicolon",
+"input":"<h a='©'>",
+"output":["ParseError", ["StartTag", "h", {"a":"\u00A9"}]]},
+
+{"description":"Unquoted attribute ending in ampersand",
+"input":"<s o=& t>",
+"output":[["StartTag","s",{"o":"&","t":""}]]},
+
+{"description":"Unquoted attribute at end of tag with final character of &, with tag followed by characters",
+"input":"<a a=a&>foo",
+"output":[["StartTag", "a", {"a":"a&"}], ["Character", "foo"]]},
+
+{"description":"plaintext element",
+ "input":"<plaintext>foobar",
+ "output":[["StartTag","plaintext",{}], ["Character","foobar"]]},
+
+{"description":"Open angled bracket in unquoted attribute value state",
+ "input":"<a a=f<>",
+ "output":["ParseError", ["StartTag", "a", {"a":"f<"}]]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/test2.test b/pkgs/html/test/data/tokenizer/test2.test
new file mode 100644
index 0000000..e157514
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/test2.test
@@ -0,0 +1,179 @@
+{"tests": [
+
+{"description":"DOCTYPE without name",
+"input":"<!DOCTYPE>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"DOCTYPE without space before name",
+"input":"<!DOCTYPEhtml>",
+"output":["ParseError", ["DOCTYPE", "html", null, null, true]]},
+
+{"description":"Incorrect DOCTYPE without a space before name",
+"input":"<!DOCTYPEfoo>",
+"output":["ParseError", ["DOCTYPE", "foo", null, null, true]]},
+
+{"description":"DOCTYPE with publicId",
+"input":"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML Transitional 4.01//EN\">",
+"output":[["DOCTYPE", "html", "-//W3C//DTD HTML Transitional 4.01//EN", null, true]]},
+
+{"description":"DOCTYPE with EOF after PUBLIC",
+"input":"<!DOCTYPE html PUBLIC",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"DOCTYPE with EOF after PUBLIC '",
+"input":"<!DOCTYPE html PUBLIC '",
+"output":["ParseError", ["DOCTYPE", "html", "", null, false]]},
+
+{"description":"DOCTYPE with EOF after PUBLIC 'x",
+"input":"<!DOCTYPE html PUBLIC 'x",
+"output":["ParseError", ["DOCTYPE", "html", "x", null, false]]},
+
+{"description":"DOCTYPE with systemId",
+"input":"<!DOCTYPE html SYSTEM \"-//W3C//DTD HTML Transitional 4.01//EN\">",
+"output":[["DOCTYPE", "html", null, "-//W3C//DTD HTML Transitional 4.01//EN", true]]},
+
+{"description":"DOCTYPE with publicId and systemId",
+"input":"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML Transitional 4.01//EN\" \"-//W3C//DTD HTML Transitional 4.01//EN\">",
+"output":[["DOCTYPE", "html", "-//W3C//DTD HTML Transitional 4.01//EN", "-//W3C//DTD HTML Transitional 4.01//EN", true]]},
+
+{"description":"DOCTYPE with > in double-quoted publicId",
+"input":"<!DOCTYPE html PUBLIC \">x",
+"output":["ParseError", ["DOCTYPE", "html", "", null, false], ["Character", "x"]]},
+
+{"description":"DOCTYPE with > in single-quoted publicId",
+"input":"<!DOCTYPE html PUBLIC '>x",
+"output":["ParseError", ["DOCTYPE", "html", "", null, false], ["Character", "x"]]},
+
+{"description":"DOCTYPE with > in double-quoted systemId",
+"input":"<!DOCTYPE html PUBLIC \"foo\" \">x",
+"output":["ParseError", ["DOCTYPE", "html", "foo", "", false], ["Character", "x"]]},
+
+{"description":"DOCTYPE with > in single-quoted systemId",
+"input":"<!DOCTYPE html PUBLIC 'foo' '>x",
+"output":["ParseError", ["DOCTYPE", "html", "foo", "", false], ["Character", "x"]]},
+
+{"description":"Incomplete doctype",
+"input":"<!DOCTYPE html ",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Numeric entity representing the NUL character",
+"input":"�",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Hexadecimal entity representing the NUL character",
+"input":"�",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Numeric entity representing a codepoint after 1114111 (U+10FFFF)",
+"input":"�",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Hexadecimal entity representing a codepoint after 1114111 (U+10FFFF)",
+"input":"�",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Hexadecimal entity pair representing a surrogate pair",
+"input":"��",
+"output":["ParseError", ["Character", "\uFFFD"], "ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Hexadecimal entity with mixed uppercase and lowercase",
+"input":"ꯍ",
+"output":[["Character", "\uABCD"]]},
+
+{"description":"Entity without a name",
+"input":"&;",
+"output":["ParseError", ["Character", "&;"]]},
+
+{"description":"Unescaped ampersand in attribute value",
+"input":"<h a='&'>",
+"output":[["StartTag", "h", { "a":"&" }]]},
+
+{"description":"StartTag containing <",
+"input":"<a<b>",
+"output":[["StartTag", "a<b", { }]]},
+
+{"description":"Non-void element containing trailing /",
+"input":"<h/>",
+"output":[["StartTag","h",{},true]]},
+
+{"description":"Void element with permitted slash",
+"input":"<br/>",
+"output":[["StartTag","br",{},true]]},
+
+{"description":"Void element with permitted slash (with attribute)",
+"input":"<br foo='bar'/>",
+"output":[["StartTag","br",{"foo":"bar"},true]]},
+
+{"description":"StartTag containing /",
+"input":"<h/a='b'>",
+"output":["ParseError", ["StartTag", "h", { "a":"b" }]]},
+
+{"description":"Double-quoted attribute value",
+"input":"<h a=\"b\">",
+"output":[["StartTag", "h", { "a":"b" }]]},
+
+{"description":"Unescaped </",
+"input":"</",
+"output":["ParseError", ["Character", "</"]]},
+
+{"description":"Illegal end tag name",
+"input":"</1>",
+"output":["ParseError", ["Comment", "1"]]},
+
+{"description":"Simili processing instruction",
+"input":"<?namespace>",
+"output":["ParseError", ["Comment", "?namespace"]]},
+
+{"description":"A bogus comment stops at >, even if preceeded by two dashes",
+"input":"<?foo-->",
+"output":["ParseError", ["Comment", "?foo--"]]},
+
+{"description":"Unescaped <",
+"input":"foo < bar",
+"output":[["Character", "foo "], "ParseError", ["Character", "< bar"]]},
+
+{"description":"Null Byte Replacement",
+"input":"\u0000",
+"output":["ParseError", ["Character", "\u0000"]]},
+
+{"description":"Comment with dash",
+"input":"<!---x",
+"output":["ParseError", ["Comment", "-x"]]},
+
+{"description":"Entity + newline",
+"input":"\nx\n>\n",
+"output":[["Character","\nx\n>\n"]]},
+
+{"description":"Start tag with no attributes but space before the greater-than sign",
+"input":"<h >",
+"output":[["StartTag", "h", {}]]},
+
+{"description":"Empty attribute followed by uppercase attribute",
+"input":"<h a B=''>",
+"output":[["StartTag", "h", {"a":"", "b":""}]]},
+
+{"description":"Double-quote after attribute name",
+"input":"<h a \">",
+"output":["ParseError", ["StartTag", "h", {"a":"", "\"":""}]]},
+
+{"description":"Single-quote after attribute name",
+"input":"<h a '>",
+"output":["ParseError", ["StartTag", "h", {"a":"", "'":""}]]},
+
+{"description":"Empty end tag with following characters",
+"input":"a</>bc",
+"output":[["Character", "a"], "ParseError", ["Character", "bc"]]},
+
+{"description":"Empty end tag with following tag",
+"input":"a</><b>c",
+"output":[["Character", "a"], "ParseError", ["StartTag", "b", {}], ["Character", "c"]]},
+
+{"description":"Empty end tag with following comment",
+"input":"a</><!--b-->c",
+"output":[["Character", "a"], "ParseError", ["Comment", "b"], ["Character", "c"]]},
+
+{"description":"Empty end tag with following end tag",
+"input":"a</></b>c",
+"output":[["Character", "a"], "ParseError", ["EndTag", "b"], ["Character", "c"]]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/test3.test b/pkgs/html/test/data/tokenizer/test3.test
new file mode 100644
index 0000000..58519e8
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/test3.test
@@ -0,0 +1,6047 @@
+{"tests": [
+
+{"description":"",
+"input":"",
+"output":[]},
+
+{"description":"\\u0009",
+"input":"\u0009",
+"output":[["Character", "\u0009"]]},
+
+{"description":"\\u000A",
+"input":"\u000A",
+"output":[["Character", "\u000A"]]},
+
+{"description":"\\u000B",
+"input":"\u000B",
+"output":["ParseError", ["Character", "\u000B"]]},
+
+{"description":"\\u000C",
+"input":"\u000C",
+"output":[["Character", "\u000C"]]},
+
+{"description":" ",
+"input":" ",
+"output":[["Character", " "]]},
+
+{"description":"!",
+"input":"!",
+"output":[["Character", "!"]]},
+
+{"description":"\"",
+"input":"\"",
+"output":[["Character", "\""]]},
+
+{"description":"%",
+"input":"%",
+"output":[["Character", "%"]]},
+
+{"description":"&",
+"input":"&",
+"output":[["Character", "&"]]},
+
+{"description":"'",
+"input":"'",
+"output":[["Character", "'"]]},
+
+{"description":",",
+"input":",",
+"output":[["Character", ","]]},
+
+{"description":"-",
+"input":"-",
+"output":[["Character", "-"]]},
+
+{"description":".",
+"input":".",
+"output":[["Character", "."]]},
+
+{"description":"/",
+"input":"/",
+"output":[["Character", "/"]]},
+
+{"description":"0",
+"input":"0",
+"output":[["Character", "0"]]},
+
+{"description":"1",
+"input":"1",
+"output":[["Character", "1"]]},
+
+{"description":"9",
+"input":"9",
+"output":[["Character", "9"]]},
+
+{"description":";",
+"input":";",
+"output":[["Character", ";"]]},
+
+{"description":"<",
+"input":"<",
+"output":["ParseError", ["Character", "<"]]},
+
+{"description":"<\\u0000",
+"input":"<\u0000",
+"output":["ParseError", ["Character", "<"], "ParseError", ["Character", "\u0000"]]},
+
+{"description":"<\\u0009",
+"input":"<\u0009",
+"output":["ParseError", ["Character", "<\u0009"]]},
+
+{"description":"<\\u000A",
+"input":"<\u000A",
+"output":["ParseError", ["Character", "<\u000A"]]},
+
+{"description":"<\\u000B",
+"input":"<\u000B",
+"output":["ParseError", "ParseError", ["Character", "<\u000B"]]},
+
+{"description":"<\\u000C",
+"input":"<\u000C",
+"output":["ParseError", ["Character", "<\u000C"]]},
+
+{"description":"< ",
+"input":"< ",
+"output":["ParseError", ["Character", "< "]]},
+
+{"description":"<!",
+"input":"<!",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!\\u0000",
+"input":"<!\u0000",
+"output":["ParseError", ["Comment", "\uFFFD"]]},
+
+{"description":"<!\\u0009",
+"input":"<!\u0009",
+"output":["ParseError", ["Comment", "\u0009"]]},
+
+{"description":"<!\\u000A",
+"input":"<!\u000A",
+"output":["ParseError", ["Comment", "\u000A"]]},
+
+{"description":"<!\\u000B",
+"input":"<!\u000B",
+"output":["ParseError", "ParseError", ["Comment", "\u000B"]]},
+
+{"description":"<!\\u000C",
+"input":"<!\u000C",
+"output":["ParseError", ["Comment", "\u000C"]]},
+
+{"description":"<! ",
+"input":"<! ",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!!",
+"input":"<!!",
+"output":["ParseError", ["Comment", "!"]]},
+
+{"description":"<!\"",
+"input":"<!\"",
+"output":["ParseError", ["Comment", "\""]]},
+
+{"description":"<!&",
+"input":"<!&",
+"output":["ParseError", ["Comment", "&"]]},
+
+{"description":"<!'",
+"input":"<!'",
+"output":["ParseError", ["Comment", "'"]]},
+
+{"description":"<!-",
+"input":"<!-",
+"output":["ParseError", ["Comment", "-"]]},
+
+{"description":"<!--",
+"input":"<!--",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!--\\u0000",
+"input":"<!--\u0000",
+"output":["ParseError", "ParseError", ["Comment", "\uFFFD"]]},
+
+{"description":"<!--\\u0009",
+"input":"<!--\u0009",
+"output":["ParseError", ["Comment", "\u0009"]]},
+
+{"description":"<!--\\u000A",
+"input":"<!--\u000A",
+"output":["ParseError", ["Comment", "\u000A"]]},
+
+{"description":"<!--\\u000B",
+"input":"<!--\u000B",
+"output":["ParseError", "ParseError", ["Comment", "\u000B"]]},
+
+{"description":"<!--\\u000C",
+"input":"<!--\u000C",
+"output":["ParseError", ["Comment", "\u000C"]]},
+
+{"description":"<!-- ",
+"input":"<!-- ",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!-- \\u0000",
+"input":"<!-- \u0000",
+"output":["ParseError", "ParseError", ["Comment", " \uFFFD"]]},
+
+{"description":"<!-- \\u0009",
+"input":"<!-- \u0009",
+"output":["ParseError", ["Comment", " \u0009"]]},
+
+{"description":"<!-- \\u000A",
+"input":"<!-- \u000A",
+"output":["ParseError", ["Comment", " \u000A"]]},
+
+{"description":"<!-- \\u000B",
+"input":"<!-- \u000B",
+"output":["ParseError", "ParseError", ["Comment", " \u000B"]]},
+
+{"description":"<!-- \\u000C",
+"input":"<!-- \u000C",
+"output":["ParseError", ["Comment", " \u000C"]]},
+
+{"description":"<!-- ",
+"input":"<!-- ",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!-- !",
+"input":"<!-- !",
+"output":["ParseError", ["Comment", " !"]]},
+
+{"description":"<!-- \"",
+"input":"<!-- \"",
+"output":["ParseError", ["Comment", " \""]]},
+
+{"description":"<!-- &",
+"input":"<!-- &",
+"output":["ParseError", ["Comment", " &"]]},
+
+{"description":"<!-- '",
+"input":"<!-- '",
+"output":["ParseError", ["Comment", " '"]]},
+
+{"description":"<!-- ,",
+"input":"<!-- ,",
+"output":["ParseError", ["Comment", " ,"]]},
+
+{"description":"<!-- -",
+"input":"<!-- -",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!-- -\\u0000",
+"input":"<!-- -\u0000",
+"output":["ParseError", "ParseError", ["Comment", " -\uFFFD"]]},
+
+{"description":"<!-- -\\u0009",
+"input":"<!-- -\u0009",
+"output":["ParseError", ["Comment", " -\u0009"]]},
+
+{"description":"<!-- -\\u000A",
+"input":"<!-- -\u000A",
+"output":["ParseError", ["Comment", " -\u000A"]]},
+
+{"description":"<!-- -\\u000B",
+"input":"<!-- -\u000B",
+"output":["ParseError", "ParseError", ["Comment", " -\u000B"]]},
+
+{"description":"<!-- -\\u000C",
+"input":"<!-- -\u000C",
+"output":["ParseError", ["Comment", " -\u000C"]]},
+
+{"description":"<!-- - ",
+"input":"<!-- - ",
+"output":["ParseError", ["Comment", " - "]]},
+
+{"description":"<!-- -!",
+"input":"<!-- -!",
+"output":["ParseError", ["Comment", " -!"]]},
+
+{"description":"<!-- -\"",
+"input":"<!-- -\"",
+"output":["ParseError", ["Comment", " -\""]]},
+
+{"description":"<!-- -&",
+"input":"<!-- -&",
+"output":["ParseError", ["Comment", " -&"]]},
+
+{"description":"<!-- -'",
+"input":"<!-- -'",
+"output":["ParseError", ["Comment", " -'"]]},
+
+{"description":"<!-- -,",
+"input":"<!-- -,",
+"output":["ParseError", ["Comment", " -,"]]},
+
+{"description":"<!-- --",
+"input":"<!-- --",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"<!-- -.",
+"input":"<!-- -.",
+"output":["ParseError", ["Comment", " -."]]},
+
+{"description":"<!-- -/",
+"input":"<!-- -/",
+"output":["ParseError", ["Comment", " -/"]]},
+
+{"description":"<!-- -0",
+"input":"<!-- -0",
+"output":["ParseError", ["Comment", " -0"]]},
+
+{"description":"<!-- -1",
+"input":"<!-- -1",
+"output":["ParseError", ["Comment", " -1"]]},
+
+{"description":"<!-- -9",
+"input":"<!-- -9",
+"output":["ParseError", ["Comment", " -9"]]},
+
+{"description":"<!-- -<",
+"input":"<!-- -<",
+"output":["ParseError", ["Comment", " -<"]]},
+
+{"description":"<!-- -=",
+"input":"<!-- -=",
+"output":["ParseError", ["Comment", " -="]]},
+
+{"description":"<!-- ->",
+"input":"<!-- ->",
+"output":["ParseError", ["Comment", " ->"]]},
+
+{"description":"<!-- -?",
+"input":"<!-- -?",
+"output":["ParseError", ["Comment", " -?"]]},
+
+{"description":"<!-- -@",
+"input":"<!-- -@",
+"output":["ParseError", ["Comment", " -@"]]},
+
+{"description":"<!-- -A",
+"input":"<!-- -A",
+"output":["ParseError", ["Comment", " -A"]]},
+
+{"description":"<!-- -B",
+"input":"<!-- -B",
+"output":["ParseError", ["Comment", " -B"]]},
+
+{"description":"<!-- -Y",
+"input":"<!-- -Y",
+"output":["ParseError", ["Comment", " -Y"]]},
+
+{"description":"<!-- -Z",
+"input":"<!-- -Z",
+"output":["ParseError", ["Comment", " -Z"]]},
+
+{"description":"<!-- -`",
+"input":"<!-- -`",
+"output":["ParseError", ["Comment", " -`"]]},
+
+{"description":"<!-- -a",
+"input":"<!-- -a",
+"output":["ParseError", ["Comment", " -a"]]},
+
+{"description":"<!-- -b",
+"input":"<!-- -b",
+"output":["ParseError", ["Comment", " -b"]]},
+
+{"description":"<!-- -y",
+"input":"<!-- -y",
+"output":["ParseError", ["Comment", " -y"]]},
+
+{"description":"<!-- -z",
+"input":"<!-- -z",
+"output":["ParseError", ["Comment", " -z"]]},
+
+{"description":"<!-- -{",
+"input":"<!-- -{",
+"output":["ParseError", ["Comment", " -{"]]},
+
+{"description":"<!-- -\\uDBC0\\uDC00",
+"input":"<!-- -\uDBC0\uDC00",
+"output":["ParseError", ["Comment", " -\uDBC0\uDC00"]]},
+
+{"description":"<!-- .",
+"input":"<!-- .",
+"output":["ParseError", ["Comment", " ."]]},
+
+{"description":"<!-- /",
+"input":"<!-- /",
+"output":["ParseError", ["Comment", " /"]]},
+
+{"description":"<!-- 0",
+"input":"<!-- 0",
+"output":["ParseError", ["Comment", " 0"]]},
+
+{"description":"<!-- 1",
+"input":"<!-- 1",
+"output":["ParseError", ["Comment", " 1"]]},
+
+{"description":"<!-- 9",
+"input":"<!-- 9",
+"output":["ParseError", ["Comment", " 9"]]},
+
+{"description":"<!-- <",
+"input":"<!-- <",
+"output":["ParseError", ["Comment", " <"]]},
+
+{"description":"<!-- =",
+"input":"<!-- =",
+"output":["ParseError", ["Comment", " ="]]},
+
+{"description":"<!-- >",
+"input":"<!-- >",
+"output":["ParseError", ["Comment", " >"]]},
+
+{"description":"<!-- ?",
+"input":"<!-- ?",
+"output":["ParseError", ["Comment", " ?"]]},
+
+{"description":"<!-- @",
+"input":"<!-- @",
+"output":["ParseError", ["Comment", " @"]]},
+
+{"description":"<!-- A",
+"input":"<!-- A",
+"output":["ParseError", ["Comment", " A"]]},
+
+{"description":"<!-- B",
+"input":"<!-- B",
+"output":["ParseError", ["Comment", " B"]]},
+
+{"description":"<!-- Y",
+"input":"<!-- Y",
+"output":["ParseError", ["Comment", " Y"]]},
+
+{"description":"<!-- Z",
+"input":"<!-- Z",
+"output":["ParseError", ["Comment", " Z"]]},
+
+{"description":"<!-- `",
+"input":"<!-- `",
+"output":["ParseError", ["Comment", " `"]]},
+
+{"description":"<!-- a",
+"input":"<!-- a",
+"output":["ParseError", ["Comment", " a"]]},
+
+{"description":"<!-- b",
+"input":"<!-- b",
+"output":["ParseError", ["Comment", " b"]]},
+
+{"description":"<!-- y",
+"input":"<!-- y",
+"output":["ParseError", ["Comment", " y"]]},
+
+{"description":"<!-- z",
+"input":"<!-- z",
+"output":["ParseError", ["Comment", " z"]]},
+
+{"description":"<!-- {",
+"input":"<!-- {",
+"output":["ParseError", ["Comment", " {"]]},
+
+{"description":"<!-- \\uDBC0\\uDC00",
+"input":"<!-- \uDBC0\uDC00",
+"output":["ParseError", ["Comment", " \uDBC0\uDC00"]]},
+
+{"description":"<!--!",
+"input":"<!--!",
+"output":["ParseError", ["Comment", "!"]]},
+
+{"description":"<!--\"",
+"input":"<!--\"",
+"output":["ParseError", ["Comment", "\""]]},
+
+{"description":"<!--&",
+"input":"<!--&",
+"output":["ParseError", ["Comment", "&"]]},
+
+{"description":"<!--'",
+"input":"<!--'",
+"output":["ParseError", ["Comment", "'"]]},
+
+{"description":"<!--,",
+"input":"<!--,",
+"output":["ParseError", ["Comment", ","]]},
+
+{"description":"<!---",
+"input":"<!---",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!---\\u0000",
+"input":"<!---\u0000",
+"output":["ParseError", "ParseError", ["Comment", "-\uFFFD"]]},
+
+{"description":"<!---\\u0009",
+"input":"<!---\u0009",
+"output":["ParseError", ["Comment", "-\u0009"]]},
+
+{"description":"<!---\\u000A",
+"input":"<!---\u000A",
+"output":["ParseError", ["Comment", "-\u000A"]]},
+
+{"description":"<!---\\u000B",
+"input":"<!---\u000B",
+"output":["ParseError", "ParseError", ["Comment", "-\u000B"]]},
+
+{"description":"<!---\\u000C",
+"input":"<!---\u000C",
+"output":["ParseError", ["Comment", "-\u000C"]]},
+
+{"description":"<!--- ",
+"input":"<!--- ",
+"output":["ParseError", ["Comment", "- "]]},
+
+{"description":"<!---!",
+"input":"<!---!",
+"output":["ParseError", ["Comment", "-!"]]},
+
+{"description":"<!---\"",
+"input":"<!---\"",
+"output":["ParseError", ["Comment", "-\""]]},
+
+{"description":"<!---&",
+"input":"<!---&",
+"output":["ParseError", ["Comment", "-&"]]},
+
+{"description":"<!---'",
+"input":"<!---'",
+"output":["ParseError", ["Comment", "-'"]]},
+
+{"description":"<!---,",
+"input":"<!---,",
+"output":["ParseError", ["Comment", "-,"]]},
+
+{"description":"<!----",
+"input":"<!----",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!----\\u0000",
+"input":"<!----\u0000",
+"output":["ParseError", "ParseError", ["Comment", "--\uFFFD"]]},
+
+{"description":"<!----\\u0009",
+"input":"<!----\u0009",
+"output":["ParseError", "ParseError", ["Comment", "--\u0009"]]},
+
+{"description":"<!----\\u000A",
+"input":"<!----\u000A",
+"output":["ParseError", "ParseError", ["Comment", "--\u000A"]]},
+
+{"description":"<!----\\u000B",
+"input":"<!----\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["Comment", "--\u000B"]]},
+
+{"description":"<!----\\u000C",
+"input":"<!----\u000C",
+"output":["ParseError", "ParseError", ["Comment", "--\u000C"]]},
+
+{"description":"<!---- ",
+"input":"<!---- ",
+"output":["ParseError", "ParseError", ["Comment", "-- "]]},
+
+{"description":"<!---- -",
+"input":"<!---- -",
+"output":["ParseError", "ParseError", ["Comment", "-- "]]},
+
+{"description":"<!---- --",
+"input":"<!---- --",
+"output":["ParseError", "ParseError", ["Comment", "-- "]]},
+
+{"description":"<!---- -->",
+"input":"<!---- -->",
+"output":["ParseError", ["Comment", "-- "]]},
+
+{"description":"<!---- -->",
+"input":"<!---- -->",
+"output":["ParseError", ["Comment", "-- "]]},
+
+{"description":"<!---- a-->",
+"input":"<!---- a-->",
+"output":["ParseError", ["Comment", "-- a"]]},
+
+{"description":"<!----!",
+"input":"<!----!",
+"output":["ParseError", "ParseError", ["Comment", ""]]},
+
+{"description":"<!----!>",
+"input":"<!----!>",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!----!a",
+"input":"<!----!a",
+"output":["ParseError", "ParseError", ["Comment", "--!a"]]},
+
+{"description":"<!----!a-",
+"input":"<!----!a-",
+"output":["ParseError", "ParseError", ["Comment", "--!a"]]},
+
+{"description":"<!----!a--",
+"input":"<!----!a--",
+"output":["ParseError", "ParseError", ["Comment", "--!a"]]},
+
+{"description":"<!----!a-->",
+"input":"<!----!a-->",
+"output":["ParseError", ["Comment", "--!a"]]},
+
+{"description":"<!----!-",
+"input":"<!----!-",
+"output":["ParseError", "ParseError", ["Comment", "--!"]]},
+
+{"description":"<!----!--",
+"input":"<!----!--",
+"output":["ParseError", "ParseError", ["Comment", "--!"]]},
+
+{"description":"<!----!-->",
+"input":"<!----!-->",
+"output":["ParseError", ["Comment", "--!"]]},
+
+{"description":"<!----\"",
+"input":"<!----\"",
+"output":["ParseError", "ParseError", ["Comment", "--\""]]},
+
+{"description":"<!----&",
+"input":"<!----&",
+"output":["ParseError", "ParseError", ["Comment", "--&"]]},
+
+{"description":"<!----'",
+"input":"<!----'",
+"output":["ParseError", "ParseError", ["Comment", "--'"]]},
+
+{"description":"<!----,",
+"input":"<!----,",
+"output":["ParseError", "ParseError", ["Comment", "--,"]]},
+
+{"description":"<!-----",
+"input":"<!-----",
+"output":["ParseError", "ParseError", ["Comment", "-"]]},
+
+{"description":"<!----.",
+"input":"<!----.",
+"output":["ParseError", "ParseError", ["Comment", "--."]]},
+
+{"description":"<!----/",
+"input":"<!----/",
+"output":["ParseError", "ParseError", ["Comment", "--/"]]},
+
+{"description":"<!----0",
+"input":"<!----0",
+"output":["ParseError", "ParseError", ["Comment", "--0"]]},
+
+{"description":"<!----1",
+"input":"<!----1",
+"output":["ParseError", "ParseError", ["Comment", "--1"]]},
+
+{"description":"<!----9",
+"input":"<!----9",
+"output":["ParseError", "ParseError", ["Comment", "--9"]]},
+
+{"description":"<!----<",
+"input":"<!----<",
+"output":["ParseError", "ParseError", ["Comment", "--<"]]},
+
+{"description":"<!----=",
+"input":"<!----=",
+"output":["ParseError", "ParseError", ["Comment", "--="]]},
+
+{"description":"<!---->",
+"input":"<!---->",
+"output":[["Comment", ""]]},
+
+{"description":"<!----?",
+"input":"<!----?",
+"output":["ParseError", "ParseError", ["Comment", "--?"]]},
+
+{"description":"<!----@",
+"input":"<!----@",
+"output":["ParseError", "ParseError", ["Comment", "--@"]]},
+
+{"description":"<!----A",
+"input":"<!----A",
+"output":["ParseError", "ParseError", ["Comment", "--A"]]},
+
+{"description":"<!----B",
+"input":"<!----B",
+"output":["ParseError", "ParseError", ["Comment", "--B"]]},
+
+{"description":"<!----Y",
+"input":"<!----Y",
+"output":["ParseError", "ParseError", ["Comment", "--Y"]]},
+
+{"description":"<!----Z",
+"input":"<!----Z",
+"output":["ParseError", "ParseError", ["Comment", "--Z"]]},
+
+{"description":"<!----`",
+"input":"<!----`",
+"output":["ParseError", "ParseError", ["Comment", "--`"]]},
+
+{"description":"<!----a",
+"input":"<!----a",
+"output":["ParseError", "ParseError", ["Comment", "--a"]]},
+
+{"description":"<!----b",
+"input":"<!----b",
+"output":["ParseError", "ParseError", ["Comment", "--b"]]},
+
+{"description":"<!----y",
+"input":"<!----y",
+"output":["ParseError", "ParseError", ["Comment", "--y"]]},
+
+{"description":"<!----z",
+"input":"<!----z",
+"output":["ParseError", "ParseError", ["Comment", "--z"]]},
+
+{"description":"<!----{",
+"input":"<!----{",
+"output":["ParseError", "ParseError", ["Comment", "--{"]]},
+
+{"description":"<!----\\uDBC0\\uDC00",
+"input":"<!----\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["Comment", "--\uDBC0\uDC00"]]},
+
+{"description":"<!---.",
+"input":"<!---.",
+"output":["ParseError", ["Comment", "-."]]},
+
+{"description":"<!---/",
+"input":"<!---/",
+"output":["ParseError", ["Comment", "-/"]]},
+
+{"description":"<!---0",
+"input":"<!---0",
+"output":["ParseError", ["Comment", "-0"]]},
+
+{"description":"<!---1",
+"input":"<!---1",
+"output":["ParseError", ["Comment", "-1"]]},
+
+{"description":"<!---9",
+"input":"<!---9",
+"output":["ParseError", ["Comment", "-9"]]},
+
+{"description":"<!---<",
+"input":"<!---<",
+"output":["ParseError", ["Comment", "-<"]]},
+
+{"description":"<!---=",
+"input":"<!---=",
+"output":["ParseError", ["Comment", "-="]]},
+
+{"description":"<!--->",
+"input":"<!--->",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!---?",
+"input":"<!---?",
+"output":["ParseError", ["Comment", "-?"]]},
+
+{"description":"<!---@",
+"input":"<!---@",
+"output":["ParseError", ["Comment", "-@"]]},
+
+{"description":"<!---A",
+"input":"<!---A",
+"output":["ParseError", ["Comment", "-A"]]},
+
+{"description":"<!---B",
+"input":"<!---B",
+"output":["ParseError", ["Comment", "-B"]]},
+
+{"description":"<!---Y",
+"input":"<!---Y",
+"output":["ParseError", ["Comment", "-Y"]]},
+
+{"description":"<!---Z",
+"input":"<!---Z",
+"output":["ParseError", ["Comment", "-Z"]]},
+
+{"description":"<!---`",
+"input":"<!---`",
+"output":["ParseError", ["Comment", "-`"]]},
+
+{"description":"<!---a",
+"input":"<!---a",
+"output":["ParseError", ["Comment", "-a"]]},
+
+{"description":"<!---b",
+"input":"<!---b",
+"output":["ParseError", ["Comment", "-b"]]},
+
+{"description":"<!---y",
+"input":"<!---y",
+"output":["ParseError", ["Comment", "-y"]]},
+
+{"description":"<!---z",
+"input":"<!---z",
+"output":["ParseError", ["Comment", "-z"]]},
+
+{"description":"<!---{",
+"input":"<!---{",
+"output":["ParseError", ["Comment", "-{"]]},
+
+{"description":"<!---\\uDBC0\\uDC00",
+"input":"<!---\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "-\uDBC0\uDC00"]]},
+
+{"description":"<!--.",
+"input":"<!--.",
+"output":["ParseError", ["Comment", "."]]},
+
+{"description":"<!--/",
+"input":"<!--/",
+"output":["ParseError", ["Comment", "/"]]},
+
+{"description":"<!--0",
+"input":"<!--0",
+"output":["ParseError", ["Comment", "0"]]},
+
+{"description":"<!--1",
+"input":"<!--1",
+"output":["ParseError", ["Comment", "1"]]},
+
+{"description":"<!--9",
+"input":"<!--9",
+"output":["ParseError", ["Comment", "9"]]},
+
+{"description":"<!--<",
+"input":"<!--<",
+"output":["ParseError", ["Comment", "<"]]},
+
+{"description":"<!--=",
+"input":"<!--=",
+"output":["ParseError", ["Comment", "="]]},
+
+{"description":"<!-->",
+"input":"<!-->",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!--?",
+"input":"<!--?",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"<!--@",
+"input":"<!--@",
+"output":["ParseError", ["Comment", "@"]]},
+
+{"description":"<!--A",
+"input":"<!--A",
+"output":["ParseError", ["Comment", "A"]]},
+
+{"description":"<!--B",
+"input":"<!--B",
+"output":["ParseError", ["Comment", "B"]]},
+
+{"description":"<!--Y",
+"input":"<!--Y",
+"output":["ParseError", ["Comment", "Y"]]},
+
+{"description":"<!--Z",
+"input":"<!--Z",
+"output":["ParseError", ["Comment", "Z"]]},
+
+{"description":"<!--`",
+"input":"<!--`",
+"output":["ParseError", ["Comment", "`"]]},
+
+{"description":"<!--a",
+"input":"<!--a",
+"output":["ParseError", ["Comment", "a"]]},
+
+{"description":"<!--b",
+"input":"<!--b",
+"output":["ParseError", ["Comment", "b"]]},
+
+{"description":"<!--y",
+"input":"<!--y",
+"output":["ParseError", ["Comment", "y"]]},
+
+{"description":"<!--z",
+"input":"<!--z",
+"output":["ParseError", ["Comment", "z"]]},
+
+{"description":"<!--{",
+"input":"<!--{",
+"output":["ParseError", ["Comment", "{"]]},
+
+{"description":"<!--\\uDBC0\\uDC00",
+"input":"<!--\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "\uDBC0\uDC00"]]},
+
+{"description":"<!/",
+"input":"<!/",
+"output":["ParseError", ["Comment", "/"]]},
+
+{"description":"<!0",
+"input":"<!0",
+"output":["ParseError", ["Comment", "0"]]},
+
+{"description":"<!1",
+"input":"<!1",
+"output":["ParseError", ["Comment", "1"]]},
+
+{"description":"<!9",
+"input":"<!9",
+"output":["ParseError", ["Comment", "9"]]},
+
+{"description":"<!<",
+"input":"<!<",
+"output":["ParseError", ["Comment", "<"]]},
+
+{"description":"<!=",
+"input":"<!=",
+"output":["ParseError", ["Comment", "="]]},
+
+{"description":"<!>",
+"input":"<!>",
+"output":["ParseError", ["Comment", ""]]},
+
+{"description":"<!?",
+"input":"<!?",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"<!@",
+"input":"<!@",
+"output":["ParseError", ["Comment", "@"]]},
+
+{"description":"<!A",
+"input":"<!A",
+"output":["ParseError", ["Comment", "A"]]},
+
+{"description":"<!B",
+"input":"<!B",
+"output":["ParseError", ["Comment", "B"]]},
+
+{"description":"<!DOCTYPE",
+"input":"<!DOCTYPE",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u0000",
+"input":"<!DOCTYPE\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "\uFFFD", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u0008",
+"input":"<!DOCTYPE\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "\u0008", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u0009",
+"input":"<!DOCTYPE\u0009",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u000A",
+"input":"<!DOCTYPE\u000A",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u000B",
+"input":"<!DOCTYPE\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "\u000B", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u000C",
+"input":"<!DOCTYPE\u000C",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u000D",
+"input":"<!DOCTYPE\u000D",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE\\u001F",
+"input":"<!DOCTYPE\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "\u001F", null, null, false]]},
+
+{"description":"<!DOCTYPE ",
+"input":"<!DOCTYPE ",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u0000",
+"input":"<!DOCTYPE \u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\uFFFD", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u0008",
+"input":"<!DOCTYPE \u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\u0008", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u0009",
+"input":"<!DOCTYPE \u0009",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u000A",
+"input":"<!DOCTYPE \u000A",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u000B",
+"input":"<!DOCTYPE \u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\u000B", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u000C",
+"input":"<!DOCTYPE \u000C",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u000D",
+"input":"<!DOCTYPE \u000D",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE \\u001F",
+"input":"<!DOCTYPE \u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\u001F", null, null, false]]},
+
+{"description":"<!DOCTYPE ",
+"input":"<!DOCTYPE ",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE !",
+"input":"<!DOCTYPE !",
+"output":["ParseError", ["DOCTYPE", "!", null, null, false]]},
+
+{"description":"<!DOCTYPE \"",
+"input":"<!DOCTYPE \"",
+"output":["ParseError", ["DOCTYPE", "\"", null, null, false]]},
+
+{"description":"<!DOCTYPE &",
+"input":"<!DOCTYPE &",
+"output":["ParseError", ["DOCTYPE", "&", null, null, false]]},
+
+{"description":"<!DOCTYPE '",
+"input":"<!DOCTYPE '",
+"output":["ParseError", ["DOCTYPE", "'", null, null, false]]},
+
+{"description":"<!DOCTYPE -",
+"input":"<!DOCTYPE -",
+"output":["ParseError", ["DOCTYPE", "-", null, null, false]]},
+
+{"description":"<!DOCTYPE /",
+"input":"<!DOCTYPE /",
+"output":["ParseError", ["DOCTYPE", "/", null, null, false]]},
+
+{"description":"<!DOCTYPE 0",
+"input":"<!DOCTYPE 0",
+"output":["ParseError", ["DOCTYPE", "0", null, null, false]]},
+
+{"description":"<!DOCTYPE 1",
+"input":"<!DOCTYPE 1",
+"output":["ParseError", ["DOCTYPE", "1", null, null, false]]},
+
+{"description":"<!DOCTYPE 9",
+"input":"<!DOCTYPE 9",
+"output":["ParseError", ["DOCTYPE", "9", null, null, false]]},
+
+{"description":"<!DOCTYPE <",
+"input":"<!DOCTYPE <",
+"output":["ParseError", ["DOCTYPE", "<", null, null, false]]},
+
+{"description":"<!DOCTYPE =",
+"input":"<!DOCTYPE =",
+"output":["ParseError", ["DOCTYPE", "=", null, null, false]]},
+
+{"description":"<!DOCTYPE >",
+"input":"<!DOCTYPE >",
+"output":["ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE ?",
+"input":"<!DOCTYPE ?",
+"output":["ParseError", ["DOCTYPE", "?", null, null, false]]},
+
+{"description":"<!DOCTYPE @",
+"input":"<!DOCTYPE @",
+"output":["ParseError", ["DOCTYPE", "@", null, null, false]]},
+
+{"description":"<!DOCTYPE A",
+"input":"<!DOCTYPE A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE B",
+"input":"<!DOCTYPE B",
+"output":["ParseError", ["DOCTYPE", "b", null, null, false]]},
+
+{"description":"<!DOCTYPE Y",
+"input":"<!DOCTYPE Y",
+"output":["ParseError", ["DOCTYPE", "y", null, null, false]]},
+
+{"description":"<!DOCTYPE Z",
+"input":"<!DOCTYPE Z",
+"output":["ParseError", ["DOCTYPE", "z", null, null, false]]},
+
+{"description":"<!DOCTYPE [",
+"input":"<!DOCTYPE [",
+"output":["ParseError", ["DOCTYPE", "[", null, null, false]]},
+
+{"description":"<!DOCTYPE `",
+"input":"<!DOCTYPE `",
+"output":["ParseError", ["DOCTYPE", "`", null, null, false]]},
+
+{"description":"<!DOCTYPE a",
+"input":"<!DOCTYPE a",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u0000",
+"input":"<!DOCTYPE a\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\uFFFD", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u0008",
+"input":"<!DOCTYPE a\u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\u0008", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u0009",
+"input":"<!DOCTYPE a\u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u000A",
+"input":"<!DOCTYPE a\u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u000B",
+"input":"<!DOCTYPE a\u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\u000B", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u000C",
+"input":"<!DOCTYPE a\u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u000D",
+"input":"<!DOCTYPE a\u000D",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\u001F",
+"input":"<!DOCTYPE a\u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\u001F", null, null, false]]},
+
+{"description":"<!DOCTYPE a ",
+"input":"<!DOCTYPE a ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u0000",
+"input":"<!DOCTYPE a \u0000",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u0008",
+"input":"<!DOCTYPE a \u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u0009",
+"input":"<!DOCTYPE a \u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u000A",
+"input":"<!DOCTYPE a \u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u000B",
+"input":"<!DOCTYPE a \u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u000C",
+"input":"<!DOCTYPE a \u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u000D",
+"input":"<!DOCTYPE a \u000D",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\u001F",
+"input":"<!DOCTYPE a \u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a ",
+"input":"<!DOCTYPE a ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a !",
+"input":"<!DOCTYPE a !",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \"",
+"input":"<!DOCTYPE a \"",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a &",
+"input":"<!DOCTYPE a &",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a '",
+"input":"<!DOCTYPE a '",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a -",
+"input":"<!DOCTYPE a -",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a /",
+"input":"<!DOCTYPE a /",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a 0",
+"input":"<!DOCTYPE a 0",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a 1",
+"input":"<!DOCTYPE a 1",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a 9",
+"input":"<!DOCTYPE a 9",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a <",
+"input":"<!DOCTYPE a <",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a =",
+"input":"<!DOCTYPE a =",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a >",
+"input":"<!DOCTYPE a >",
+"output":[["DOCTYPE", "a", null, null, true]]},
+
+{"description":"<!DOCTYPE a ?",
+"input":"<!DOCTYPE a ?",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a @",
+"input":"<!DOCTYPE a @",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a A",
+"input":"<!DOCTYPE a A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a B",
+"input":"<!DOCTYPE a B",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC",
+"input":"<!DOCTYPE a PUBLIC",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u0000",
+"input":"<!DOCTYPE a PUBLIC\u0000",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u0008",
+"input":"<!DOCTYPE a PUBLIC\u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u0009",
+"input":"<!DOCTYPE a PUBLIC\u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u000A",
+"input":"<!DOCTYPE a PUBLIC\u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u000B",
+"input":"<!DOCTYPE a PUBLIC\u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u000C",
+"input":"<!DOCTYPE a PUBLIC\u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u000D",
+"input":"<!DOCTYPE a PUBLIC\u000D",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\u001F",
+"input":"<!DOCTYPE a PUBLIC\u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC ",
+"input":"<!DOCTYPE a PUBLIC ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC!",
+"input":"<!DOCTYPE a PUBLIC!",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"",
+"input":"<!DOCTYPE a PUBLIC\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u0000",
+"input":"<!DOCTYPE a PUBLIC\"\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uFFFD", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u0009",
+"input":"<!DOCTYPE a PUBLIC\"\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u0009", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u000A",
+"input":"<!DOCTYPE a PUBLIC\"\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u000A", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u000B",
+"input":"<!DOCTYPE a PUBLIC\"\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000B", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\u000C",
+"input":"<!DOCTYPE a PUBLIC\"\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u000C", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\" ",
+"input":"<!DOCTYPE a PUBLIC\" ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", " ", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"!",
+"input":"<!DOCTYPE a PUBLIC\"!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "!", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\"",
+"input":"<!DOCTYPE a PUBLIC\"\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"#",
+"input":"<!DOCTYPE a PUBLIC\"#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "#", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"&",
+"input":"<!DOCTYPE a PUBLIC\"&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "&", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"'",
+"input":"<!DOCTYPE a PUBLIC\"'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "'", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"-",
+"input":"<!DOCTYPE a PUBLIC\"-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "-", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"/",
+"input":"<!DOCTYPE a PUBLIC\"/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "/", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"0",
+"input":"<!DOCTYPE a PUBLIC\"0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "0", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"1",
+"input":"<!DOCTYPE a PUBLIC\"1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "1", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"9",
+"input":"<!DOCTYPE a PUBLIC\"9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "9", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"<",
+"input":"<!DOCTYPE a PUBLIC\"<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "<", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"=",
+"input":"<!DOCTYPE a PUBLIC\"=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "=", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\">",
+"input":"<!DOCTYPE a PUBLIC\">",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"?",
+"input":"<!DOCTYPE a PUBLIC\"?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "?", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"@",
+"input":"<!DOCTYPE a PUBLIC\"@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "@", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"A",
+"input":"<!DOCTYPE a PUBLIC\"A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "A", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"B",
+"input":"<!DOCTYPE a PUBLIC\"B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "B", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"Y",
+"input":"<!DOCTYPE a PUBLIC\"Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "Y", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"Z",
+"input":"<!DOCTYPE a PUBLIC\"Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "Z", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"`",
+"input":"<!DOCTYPE a PUBLIC\"`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "`", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"a",
+"input":"<!DOCTYPE a PUBLIC\"a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "a", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"b",
+"input":"<!DOCTYPE a PUBLIC\"b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "b", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"y",
+"input":"<!DOCTYPE a PUBLIC\"y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "y", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"z",
+"input":"<!DOCTYPE a PUBLIC\"z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "z", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"{",
+"input":"<!DOCTYPE a PUBLIC\"{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "{", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\"\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a PUBLIC\"\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\uDBC0\uDC00", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC#",
+"input":"<!DOCTYPE a PUBLIC#",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC&",
+"input":"<!DOCTYPE a PUBLIC&",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'",
+"input":"<!DOCTYPE a PUBLIC'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u0000",
+"input":"<!DOCTYPE a PUBLIC'\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uFFFD", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u0009",
+"input":"<!DOCTYPE a PUBLIC'\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u0009", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u000A",
+"input":"<!DOCTYPE a PUBLIC'\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u000A", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u000B",
+"input":"<!DOCTYPE a PUBLIC'\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000B", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\u000C",
+"input":"<!DOCTYPE a PUBLIC'\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\u000C", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC' ",
+"input":"<!DOCTYPE a PUBLIC' ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", " ", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'!",
+"input":"<!DOCTYPE a PUBLIC'!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "!", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\"",
+"input":"<!DOCTYPE a PUBLIC'\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\"", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'&",
+"input":"<!DOCTYPE a PUBLIC'&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "&", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''",
+"input":"<!DOCTYPE a PUBLIC''",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u0000",
+"input":"<!DOCTYPE a PUBLIC''\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u0008",
+"input":"<!DOCTYPE a PUBLIC''\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u0009",
+"input":"<!DOCTYPE a PUBLIC''\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u000A",
+"input":"<!DOCTYPE a PUBLIC''\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u000B",
+"input":"<!DOCTYPE a PUBLIC''\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u000C",
+"input":"<!DOCTYPE a PUBLIC''\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u000D",
+"input":"<!DOCTYPE a PUBLIC''\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\u001F",
+"input":"<!DOCTYPE a PUBLIC''\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'' ",
+"input":"<!DOCTYPE a PUBLIC'' ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''!",
+"input":"<!DOCTYPE a PUBLIC''!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\"",
+"input":"<!DOCTYPE a PUBLIC''\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", "", false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''#",
+"input":"<!DOCTYPE a PUBLIC''#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''&",
+"input":"<!DOCTYPE a PUBLIC''&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'''",
+"input":"<!DOCTYPE a PUBLIC'''",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", "", false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''(",
+"input":"<!DOCTYPE a PUBLIC''(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''-",
+"input":"<!DOCTYPE a PUBLIC''-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''/",
+"input":"<!DOCTYPE a PUBLIC''/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''0",
+"input":"<!DOCTYPE a PUBLIC''0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''1",
+"input":"<!DOCTYPE a PUBLIC''1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''9",
+"input":"<!DOCTYPE a PUBLIC''9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''<",
+"input":"<!DOCTYPE a PUBLIC''<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''=",
+"input":"<!DOCTYPE a PUBLIC''=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''>",
+"input":"<!DOCTYPE a PUBLIC''>",
+"output":["ParseError", ["DOCTYPE", "a", "", null, true]]},
+
+{"description":"<!DOCTYPE a PUBLIC''?",
+"input":"<!DOCTYPE a PUBLIC''?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''@",
+"input":"<!DOCTYPE a PUBLIC''@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''A",
+"input":"<!DOCTYPE a PUBLIC''A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''B",
+"input":"<!DOCTYPE a PUBLIC''B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''Y",
+"input":"<!DOCTYPE a PUBLIC''Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''Z",
+"input":"<!DOCTYPE a PUBLIC''Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''`",
+"input":"<!DOCTYPE a PUBLIC''`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''a",
+"input":"<!DOCTYPE a PUBLIC''a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''b",
+"input":"<!DOCTYPE a PUBLIC''b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''y",
+"input":"<!DOCTYPE a PUBLIC''y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''z",
+"input":"<!DOCTYPE a PUBLIC''z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''{",
+"input":"<!DOCTYPE a PUBLIC''{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC''\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a PUBLIC''\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'(",
+"input":"<!DOCTYPE a PUBLIC'(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "(", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'-",
+"input":"<!DOCTYPE a PUBLIC'-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "-", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'/",
+"input":"<!DOCTYPE a PUBLIC'/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "/", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'0",
+"input":"<!DOCTYPE a PUBLIC'0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "0", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'1",
+"input":"<!DOCTYPE a PUBLIC'1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "1", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'9",
+"input":"<!DOCTYPE a PUBLIC'9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "9", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'<",
+"input":"<!DOCTYPE a PUBLIC'<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "<", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'=",
+"input":"<!DOCTYPE a PUBLIC'=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "=", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'>",
+"input":"<!DOCTYPE a PUBLIC'>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'?",
+"input":"<!DOCTYPE a PUBLIC'?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "?", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'@",
+"input":"<!DOCTYPE a PUBLIC'@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "@", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'A",
+"input":"<!DOCTYPE a PUBLIC'A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "A", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'B",
+"input":"<!DOCTYPE a PUBLIC'B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "B", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'Y",
+"input":"<!DOCTYPE a PUBLIC'Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "Y", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'Z",
+"input":"<!DOCTYPE a PUBLIC'Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "Z", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'`",
+"input":"<!DOCTYPE a PUBLIC'`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "`", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'a",
+"input":"<!DOCTYPE a PUBLIC'a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "a", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'b",
+"input":"<!DOCTYPE a PUBLIC'b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "b", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'y",
+"input":"<!DOCTYPE a PUBLIC'y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "y", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'z",
+"input":"<!DOCTYPE a PUBLIC'z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "z", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'{",
+"input":"<!DOCTYPE a PUBLIC'{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "{", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC'\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a PUBLIC'\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "\uDBC0\uDC00", null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC(",
+"input":"<!DOCTYPE a PUBLIC(",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC-",
+"input":"<!DOCTYPE a PUBLIC-",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC/",
+"input":"<!DOCTYPE a PUBLIC/",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC0",
+"input":"<!DOCTYPE a PUBLIC0",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC1",
+"input":"<!DOCTYPE a PUBLIC1",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC9",
+"input":"<!DOCTYPE a PUBLIC9",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC<",
+"input":"<!DOCTYPE a PUBLIC<",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC=",
+"input":"<!DOCTYPE a PUBLIC=",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC>",
+"input":"<!DOCTYPE a PUBLIC>",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC?",
+"input":"<!DOCTYPE a PUBLIC?",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC@",
+"input":"<!DOCTYPE a PUBLIC@",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICA",
+"input":"<!DOCTYPE a PUBLICA",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICB",
+"input":"<!DOCTYPE a PUBLICB",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICY",
+"input":"<!DOCTYPE a PUBLICY",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICZ",
+"input":"<!DOCTYPE a PUBLICZ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC`",
+"input":"<!DOCTYPE a PUBLIC`",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICa",
+"input":"<!DOCTYPE a PUBLICa",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICb",
+"input":"<!DOCTYPE a PUBLICb",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICy",
+"input":"<!DOCTYPE a PUBLICy",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLICz",
+"input":"<!DOCTYPE a PUBLICz",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC{",
+"input":"<!DOCTYPE a PUBLIC{",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a PUBLIC\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a PUBLIC\uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM",
+"input":"<!DOCTYPE a SYSTEM",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u0000",
+"input":"<!DOCTYPE a SYSTEM\u0000",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u0008",
+"input":"<!DOCTYPE a SYSTEM\u0008",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u0009",
+"input":"<!DOCTYPE a SYSTEM\u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u000A",
+"input":"<!DOCTYPE a SYSTEM\u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u000B",
+"input":"<!DOCTYPE a SYSTEM\u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u000C",
+"input":"<!DOCTYPE a SYSTEM\u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u000D",
+"input":"<!DOCTYPE a SYSTEM\u000D",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\u001F",
+"input":"<!DOCTYPE a SYSTEM\u001F",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM ",
+"input":"<!DOCTYPE a SYSTEM ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM!",
+"input":"<!DOCTYPE a SYSTEM!",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"",
+"input":"<!DOCTYPE a SYSTEM\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u0000",
+"input":"<!DOCTYPE a SYSTEM\"\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uFFFD", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u0009",
+"input":"<!DOCTYPE a SYSTEM\"\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u0009", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u000A",
+"input":"<!DOCTYPE a SYSTEM\"\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000A", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u000B",
+"input":"<!DOCTYPE a SYSTEM\"\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000B", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\u000C",
+"input":"<!DOCTYPE a SYSTEM\"\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000C", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\" ",
+"input":"<!DOCTYPE a SYSTEM\" ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, " ", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"!",
+"input":"<!DOCTYPE a SYSTEM\"!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "!", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\"",
+"input":"<!DOCTYPE a SYSTEM\"\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"#",
+"input":"<!DOCTYPE a SYSTEM\"#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "#", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"&",
+"input":"<!DOCTYPE a SYSTEM\"&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "&", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"'",
+"input":"<!DOCTYPE a SYSTEM\"'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "'", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"-",
+"input":"<!DOCTYPE a SYSTEM\"-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "-", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"/",
+"input":"<!DOCTYPE a SYSTEM\"/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "/", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"0",
+"input":"<!DOCTYPE a SYSTEM\"0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "0", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"1",
+"input":"<!DOCTYPE a SYSTEM\"1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "1", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"9",
+"input":"<!DOCTYPE a SYSTEM\"9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "9", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"<",
+"input":"<!DOCTYPE a SYSTEM\"<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "<", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"=",
+"input":"<!DOCTYPE a SYSTEM\"=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "=", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\">",
+"input":"<!DOCTYPE a SYSTEM\">",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"?",
+"input":"<!DOCTYPE a SYSTEM\"?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "?", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"@",
+"input":"<!DOCTYPE a SYSTEM\"@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "@", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"A",
+"input":"<!DOCTYPE a SYSTEM\"A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "A", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"B",
+"input":"<!DOCTYPE a SYSTEM\"B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "B", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"Y",
+"input":"<!DOCTYPE a SYSTEM\"Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "Y", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"Z",
+"input":"<!DOCTYPE a SYSTEM\"Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "Z", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"`",
+"input":"<!DOCTYPE a SYSTEM\"`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "`", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"a",
+"input":"<!DOCTYPE a SYSTEM\"a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "a", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"b",
+"input":"<!DOCTYPE a SYSTEM\"b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "b", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"y",
+"input":"<!DOCTYPE a SYSTEM\"y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "y", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"z",
+"input":"<!DOCTYPE a SYSTEM\"z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "z", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"{",
+"input":"<!DOCTYPE a SYSTEM\"{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "{", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\"\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a SYSTEM\"\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\uDBC0\uDC00", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM#",
+"input":"<!DOCTYPE a SYSTEM#",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM&",
+"input":"<!DOCTYPE a SYSTEM&",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'",
+"input":"<!DOCTYPE a SYSTEM'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u0000",
+"input":"<!DOCTYPE a SYSTEM'\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uFFFD", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u0009",
+"input":"<!DOCTYPE a SYSTEM'\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u0009", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u000A",
+"input":"<!DOCTYPE a SYSTEM'\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000A", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u000B",
+"input":"<!DOCTYPE a SYSTEM'\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000B", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\u000C",
+"input":"<!DOCTYPE a SYSTEM'\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000C", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM' ",
+"input":"<!DOCTYPE a SYSTEM' ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, " ", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'!",
+"input":"<!DOCTYPE a SYSTEM'!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "!", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\"",
+"input":"<!DOCTYPE a SYSTEM'\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\"", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'&",
+"input":"<!DOCTYPE a SYSTEM'&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "&", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''",
+"input":"<!DOCTYPE a SYSTEM''",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u0000",
+"input":"<!DOCTYPE a SYSTEM''\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u0008",
+"input":"<!DOCTYPE a SYSTEM''\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u0009",
+"input":"<!DOCTYPE a SYSTEM''\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u000A",
+"input":"<!DOCTYPE a SYSTEM''\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u000B",
+"input":"<!DOCTYPE a SYSTEM''\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u000C",
+"input":"<!DOCTYPE a SYSTEM''\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u000D",
+"input":"<!DOCTYPE a SYSTEM''\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\u001F",
+"input":"<!DOCTYPE a SYSTEM''\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM'' ",
+"input":"<!DOCTYPE a SYSTEM'' ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM''!",
+"input":"<!DOCTYPE a SYSTEM''!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\"",
+"input":"<!DOCTYPE a SYSTEM''\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''&",
+"input":"<!DOCTYPE a SYSTEM''&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM'''",
+"input":"<!DOCTYPE a SYSTEM'''",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''-",
+"input":"<!DOCTYPE a SYSTEM''-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''/",
+"input":"<!DOCTYPE a SYSTEM''/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''0",
+"input":"<!DOCTYPE a SYSTEM''0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''1",
+"input":"<!DOCTYPE a SYSTEM''1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''9",
+"input":"<!DOCTYPE a SYSTEM''9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''<",
+"input":"<!DOCTYPE a SYSTEM''<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''=",
+"input":"<!DOCTYPE a SYSTEM''=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''>",
+"input":"<!DOCTYPE a SYSTEM''>",
+"output":["ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''?",
+"input":"<!DOCTYPE a SYSTEM''?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''@",
+"input":"<!DOCTYPE a SYSTEM''@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''A",
+"input":"<!DOCTYPE a SYSTEM''A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''B",
+"input":"<!DOCTYPE a SYSTEM''B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''Y",
+"input":"<!DOCTYPE a SYSTEM''Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''Z",
+"input":"<!DOCTYPE a SYSTEM''Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''`",
+"input":"<!DOCTYPE a SYSTEM''`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''a",
+"input":"<!DOCTYPE a SYSTEM''a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''b",
+"input":"<!DOCTYPE a SYSTEM''b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''y",
+"input":"<!DOCTYPE a SYSTEM''y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''z",
+"input":"<!DOCTYPE a SYSTEM''z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''{",
+"input":"<!DOCTYPE a SYSTEM''{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM''\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a SYSTEM''\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPE a SYSTEM'(",
+"input":"<!DOCTYPE a SYSTEM'(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "(", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'-",
+"input":"<!DOCTYPE a SYSTEM'-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "-", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'/",
+"input":"<!DOCTYPE a SYSTEM'/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "/", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'0",
+"input":"<!DOCTYPE a SYSTEM'0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "0", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'1",
+"input":"<!DOCTYPE a SYSTEM'1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "1", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'9",
+"input":"<!DOCTYPE a SYSTEM'9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "9", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'<",
+"input":"<!DOCTYPE a SYSTEM'<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "<", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'=",
+"input":"<!DOCTYPE a SYSTEM'=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "=", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'>",
+"input":"<!DOCTYPE a SYSTEM'>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'?",
+"input":"<!DOCTYPE a SYSTEM'?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "?", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'@",
+"input":"<!DOCTYPE a SYSTEM'@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "@", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'A",
+"input":"<!DOCTYPE a SYSTEM'A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "A", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'B",
+"input":"<!DOCTYPE a SYSTEM'B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "B", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'Y",
+"input":"<!DOCTYPE a SYSTEM'Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "Y", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'Z",
+"input":"<!DOCTYPE a SYSTEM'Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "Z", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'`",
+"input":"<!DOCTYPE a SYSTEM'`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "`", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'a",
+"input":"<!DOCTYPE a SYSTEM'a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "a", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'b",
+"input":"<!DOCTYPE a SYSTEM'b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "b", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'y",
+"input":"<!DOCTYPE a SYSTEM'y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "y", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'z",
+"input":"<!DOCTYPE a SYSTEM'z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "z", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'{",
+"input":"<!DOCTYPE a SYSTEM'{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "{", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM'\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a SYSTEM'\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "\uDBC0\uDC00", false]]},
+
+{"description":"<!DOCTYPE a SYSTEM(",
+"input":"<!DOCTYPE a SYSTEM(",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM-",
+"input":"<!DOCTYPE a SYSTEM-",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM/",
+"input":"<!DOCTYPE a SYSTEM/",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM0",
+"input":"<!DOCTYPE a SYSTEM0",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM1",
+"input":"<!DOCTYPE a SYSTEM1",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM9",
+"input":"<!DOCTYPE a SYSTEM9",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM<",
+"input":"<!DOCTYPE a SYSTEM<",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM=",
+"input":"<!DOCTYPE a SYSTEM=",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM>",
+"input":"<!DOCTYPE a SYSTEM>",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM?",
+"input":"<!DOCTYPE a SYSTEM?",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM@",
+"input":"<!DOCTYPE a SYSTEM@",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMA",
+"input":"<!DOCTYPE a SYSTEMA",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMB",
+"input":"<!DOCTYPE a SYSTEMB",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMY",
+"input":"<!DOCTYPE a SYSTEMY",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMZ",
+"input":"<!DOCTYPE a SYSTEMZ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM`",
+"input":"<!DOCTYPE a SYSTEM`",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMa",
+"input":"<!DOCTYPE a SYSTEMa",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMb",
+"input":"<!DOCTYPE a SYSTEMb",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMy",
+"input":"<!DOCTYPE a SYSTEMy",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEMz",
+"input":"<!DOCTYPE a SYSTEMz",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM{",
+"input":"<!DOCTYPE a SYSTEM{",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a SYSTEM\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a SYSTEM\uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a Y",
+"input":"<!DOCTYPE a Y",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a Z",
+"input":"<!DOCTYPE a Z",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a `",
+"input":"<!DOCTYPE a `",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a",
+"input":"<!DOCTYPE a a",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u0000",
+"input":"<!DOCTYPE a a\u0000",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u0009",
+"input":"<!DOCTYPE a a\u0009",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u000A",
+"input":"<!DOCTYPE a a\u000A",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u000B",
+"input":"<!DOCTYPE a a\u000B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\u000C",
+"input":"<!DOCTYPE a a\u000C",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a ",
+"input":"<!DOCTYPE a a ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a!",
+"input":"<!DOCTYPE a a!",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\"",
+"input":"<!DOCTYPE a a\"",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a&",
+"input":"<!DOCTYPE a a&",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a'",
+"input":"<!DOCTYPE a a'",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a-",
+"input":"<!DOCTYPE a a-",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a/",
+"input":"<!DOCTYPE a a/",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a0",
+"input":"<!DOCTYPE a a0",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a1",
+"input":"<!DOCTYPE a a1",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a9",
+"input":"<!DOCTYPE a a9",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a<",
+"input":"<!DOCTYPE a a<",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a=",
+"input":"<!DOCTYPE a a=",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a>",
+"input":"<!DOCTYPE a a>",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a?",
+"input":"<!DOCTYPE a a?",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a@",
+"input":"<!DOCTYPE a a@",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aA",
+"input":"<!DOCTYPE a aA",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aB",
+"input":"<!DOCTYPE a aB",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aY",
+"input":"<!DOCTYPE a aY",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aZ",
+"input":"<!DOCTYPE a aZ",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a`",
+"input":"<!DOCTYPE a a`",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a aa",
+"input":"<!DOCTYPE a aa",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a ab",
+"input":"<!DOCTYPE a ab",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a ay",
+"input":"<!DOCTYPE a ay",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a az",
+"input":"<!DOCTYPE a az",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a{",
+"input":"<!DOCTYPE a a{",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a a\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a a\uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a b",
+"input":"<!DOCTYPE a b",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a y",
+"input":"<!DOCTYPE a y",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a z",
+"input":"<!DOCTYPE a z",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a {",
+"input":"<!DOCTYPE a {",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a \\uDBC0\\uDC00",
+"input":"<!DOCTYPE a \uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPE a!",
+"input":"<!DOCTYPE a!",
+"output":["ParseError", ["DOCTYPE", "a!", null, null, false]]},
+
+{"description":"<!DOCTYPE a\"",
+"input":"<!DOCTYPE a\"",
+"output":["ParseError", ["DOCTYPE", "a\"", null, null, false]]},
+
+{"description":"<!DOCTYPE a&",
+"input":"<!DOCTYPE a&",
+"output":["ParseError", ["DOCTYPE", "a&", null, null, false]]},
+
+{"description":"<!DOCTYPE a'",
+"input":"<!DOCTYPE a'",
+"output":["ParseError", ["DOCTYPE", "a'", null, null, false]]},
+
+{"description":"<!DOCTYPE a-",
+"input":"<!DOCTYPE a-",
+"output":["ParseError", ["DOCTYPE", "a-", null, null, false]]},
+
+{"description":"<!DOCTYPE a/",
+"input":"<!DOCTYPE a/",
+"output":["ParseError", ["DOCTYPE", "a/", null, null, false]]},
+
+{"description":"<!DOCTYPE a0",
+"input":"<!DOCTYPE a0",
+"output":["ParseError", ["DOCTYPE", "a0", null, null, false]]},
+
+{"description":"<!DOCTYPE a1",
+"input":"<!DOCTYPE a1",
+"output":["ParseError", ["DOCTYPE", "a1", null, null, false]]},
+
+{"description":"<!DOCTYPE a9",
+"input":"<!DOCTYPE a9",
+"output":["ParseError", ["DOCTYPE", "a9", null, null, false]]},
+
+{"description":"<!DOCTYPE a<",
+"input":"<!DOCTYPE a<",
+"output":["ParseError", ["DOCTYPE", "a<", null, null, false]]},
+
+{"description":"<!DOCTYPE a=",
+"input":"<!DOCTYPE a=",
+"output":["ParseError", ["DOCTYPE", "a=", null, null, false]]},
+
+{"description":"<!DOCTYPE a>",
+"input":"<!DOCTYPE a>",
+"output":[["DOCTYPE", "a", null, null, true]]},
+
+{"description":"<!DOCTYPE a?",
+"input":"<!DOCTYPE a?",
+"output":["ParseError", ["DOCTYPE", "a?", null, null, false]]},
+
+{"description":"<!DOCTYPE a@",
+"input":"<!DOCTYPE a@",
+"output":["ParseError", ["DOCTYPE", "a@", null, null, false]]},
+
+{"description":"<!DOCTYPE aA",
+"input":"<!DOCTYPE aA",
+"output":["ParseError", ["DOCTYPE", "aa", null, null, false]]},
+
+{"description":"<!DOCTYPE aB",
+"input":"<!DOCTYPE aB",
+"output":["ParseError", ["DOCTYPE", "ab", null, null, false]]},
+
+{"description":"<!DOCTYPE aY",
+"input":"<!DOCTYPE aY",
+"output":["ParseError", ["DOCTYPE", "ay", null, null, false]]},
+
+{"description":"<!DOCTYPE aZ",
+"input":"<!DOCTYPE aZ",
+"output":["ParseError", ["DOCTYPE", "az", null, null, false]]},
+
+{"description":"<!DOCTYPE a[",
+"input":"<!DOCTYPE a[",
+"output":["ParseError", ["DOCTYPE", "a[", null, null, false]]},
+
+{"description":"<!DOCTYPE a`",
+"input":"<!DOCTYPE a`",
+"output":["ParseError", ["DOCTYPE", "a`", null, null, false]]},
+
+{"description":"<!DOCTYPE aa",
+"input":"<!DOCTYPE aa",
+"output":["ParseError", ["DOCTYPE", "aa", null, null, false]]},
+
+{"description":"<!DOCTYPE ab",
+"input":"<!DOCTYPE ab",
+"output":["ParseError", ["DOCTYPE", "ab", null, null, false]]},
+
+{"description":"<!DOCTYPE ay",
+"input":"<!DOCTYPE ay",
+"output":["ParseError", ["DOCTYPE", "ay", null, null, false]]},
+
+{"description":"<!DOCTYPE az",
+"input":"<!DOCTYPE az",
+"output":["ParseError", ["DOCTYPE", "az", null, null, false]]},
+
+{"description":"<!DOCTYPE a{",
+"input":"<!DOCTYPE a{",
+"output":["ParseError", ["DOCTYPE", "a{", null, null, false]]},
+
+{"description":"<!DOCTYPE a\\uDBC0\\uDC00",
+"input":"<!DOCTYPE a\uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "a\uDBC0\uDC00", null, null, false]]},
+
+{"description":"<!DOCTYPE b",
+"input":"<!DOCTYPE b",
+"output":["ParseError", ["DOCTYPE", "b", null, null, false]]},
+
+{"description":"<!DOCTYPE y",
+"input":"<!DOCTYPE y",
+"output":["ParseError", ["DOCTYPE", "y", null, null, false]]},
+
+{"description":"<!DOCTYPE z",
+"input":"<!DOCTYPE z",
+"output":["ParseError", ["DOCTYPE", "z", null, null, false]]},
+
+{"description":"<!DOCTYPE {",
+"input":"<!DOCTYPE {",
+"output":["ParseError", ["DOCTYPE", "{", null, null, false]]},
+
+{"description":"<!DOCTYPE \\uDBC0\\uDC00",
+"input":"<!DOCTYPE \uDBC0\uDC00",
+"output":["ParseError", ["DOCTYPE", "\uDBC0\uDC00", null, null, false]]},
+
+{"description":"<!DOCTYPE!",
+"input":"<!DOCTYPE!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "!", null, null, false]]},
+
+{"description":"<!DOCTYPE\"",
+"input":"<!DOCTYPE\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\"", null, null, false]]},
+
+{"description":"<!DOCTYPE&",
+"input":"<!DOCTYPE&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "&", null, null, false]]},
+
+{"description":"<!DOCTYPE'",
+"input":"<!DOCTYPE'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "'", null, null, false]]},
+
+{"description":"<!DOCTYPE-",
+"input":"<!DOCTYPE-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "-", null, null, false]]},
+
+{"description":"<!DOCTYPE/",
+"input":"<!DOCTYPE/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "/", null, null, false]]},
+
+{"description":"<!DOCTYPE0",
+"input":"<!DOCTYPE0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "0", null, null, false]]},
+
+{"description":"<!DOCTYPE1",
+"input":"<!DOCTYPE1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "1", null, null, false]]},
+
+{"description":"<!DOCTYPE9",
+"input":"<!DOCTYPE9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "9", null, null, false]]},
+
+{"description":"<!DOCTYPE<",
+"input":"<!DOCTYPE<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "<", null, null, false]]},
+
+{"description":"<!DOCTYPE=",
+"input":"<!DOCTYPE=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "=", null, null, false]]},
+
+{"description":"<!DOCTYPE>",
+"input":"<!DOCTYPE>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "", null, null, false]]},
+
+{"description":"<!DOCTYPE?",
+"input":"<!DOCTYPE?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "?", null, null, false]]},
+
+{"description":"<!DOCTYPE@",
+"input":"<!DOCTYPE@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "@", null, null, false]]},
+
+{"description":"<!DOCTYPEA",
+"input":"<!DOCTYPEA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEB",
+"input":"<!DOCTYPEB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "b", null, null, false]]},
+
+{"description":"<!DOCTYPEY",
+"input":"<!DOCTYPEY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "y", null, null, false]]},
+
+{"description":"<!DOCTYPEZ",
+"input":"<!DOCTYPEZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "z", null, null, false]]},
+
+{"description":"<!DOCTYPE`",
+"input":"<!DOCTYPE`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "`", null, null, false]]},
+
+{"description":"<!DOCTYPEa",
+"input":"<!DOCTYPEa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u0000",
+"input":"<!DOCTYPEa\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a\uFFFD", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u0008",
+"input":"<!DOCTYPEa\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a\u0008", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u0009",
+"input":"<!DOCTYPEa\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u000A",
+"input":"<!DOCTYPEa\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u000B",
+"input":"<!DOCTYPEa\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a\u000B", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u000C",
+"input":"<!DOCTYPEa\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u000D",
+"input":"<!DOCTYPEa\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\u001F",
+"input":"<!DOCTYPEa\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a\u001F", null, null, false]]},
+
+{"description":"<!DOCTYPEa ",
+"input":"<!DOCTYPEa ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u0000",
+"input":"<!DOCTYPEa \u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u0008",
+"input":"<!DOCTYPEa \u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u0009",
+"input":"<!DOCTYPEa \u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u000A",
+"input":"<!DOCTYPEa \u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u000B",
+"input":"<!DOCTYPEa \u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u000C",
+"input":"<!DOCTYPEa \u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u000D",
+"input":"<!DOCTYPEa \u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\u001F",
+"input":"<!DOCTYPEa \u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa ",
+"input":"<!DOCTYPEa ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa !",
+"input":"<!DOCTYPEa !",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \"",
+"input":"<!DOCTYPEa \"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa &",
+"input":"<!DOCTYPEa &",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa '",
+"input":"<!DOCTYPEa '",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa -",
+"input":"<!DOCTYPEa -",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa /",
+"input":"<!DOCTYPEa /",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa 0",
+"input":"<!DOCTYPEa 0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa 1",
+"input":"<!DOCTYPEa 1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa 9",
+"input":"<!DOCTYPEa 9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa <",
+"input":"<!DOCTYPEa <",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa =",
+"input":"<!DOCTYPEa =",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa >",
+"input":"<!DOCTYPEa >",
+"output":["ParseError", ["DOCTYPE", "a", null, null, true]]},
+
+{"description":"<!DOCTYPEa ?",
+"input":"<!DOCTYPEa ?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa @",
+"input":"<!DOCTYPEa @",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa A",
+"input":"<!DOCTYPEa A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa B",
+"input":"<!DOCTYPEa B",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC",
+"input":"<!DOCTYPEa PUBLIC",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u0000",
+"input":"<!DOCTYPEa PUBLIC\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u0008",
+"input":"<!DOCTYPEa PUBLIC\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u0009",
+"input":"<!DOCTYPEa PUBLIC\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u000A",
+"input":"<!DOCTYPEa PUBLIC\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u000B",
+"input":"<!DOCTYPEa PUBLIC\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u000C",
+"input":"<!DOCTYPEa PUBLIC\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u000D",
+"input":"<!DOCTYPEa PUBLIC\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\u001F",
+"input":"<!DOCTYPEa PUBLIC\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC ",
+"input":"<!DOCTYPEa PUBLIC ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC!",
+"input":"<!DOCTYPEa PUBLIC!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"",
+"input":"<!DOCTYPEa PUBLIC\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u0000",
+"input":"<!DOCTYPEa PUBLIC\"\u0000",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uFFFD", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u0009",
+"input":"<!DOCTYPEa PUBLIC\"\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u0009", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u000A",
+"input":"<!DOCTYPEa PUBLIC\"\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000A", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u000B",
+"input":"<!DOCTYPEa PUBLIC\"\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000B", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\u000C",
+"input":"<!DOCTYPEa PUBLIC\"\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000C", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\" ",
+"input":"<!DOCTYPEa PUBLIC\" ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", " ", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"!",
+"input":"<!DOCTYPEa PUBLIC\"!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "!", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\"",
+"input":"<!DOCTYPEa PUBLIC\"\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"#",
+"input":"<!DOCTYPEa PUBLIC\"#",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "#", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"&",
+"input":"<!DOCTYPEa PUBLIC\"&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "&", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"'",
+"input":"<!DOCTYPEa PUBLIC\"'",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "'", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"-",
+"input":"<!DOCTYPEa PUBLIC\"-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "-", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"/",
+"input":"<!DOCTYPEa PUBLIC\"/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "/", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"0",
+"input":"<!DOCTYPEa PUBLIC\"0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "0", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"1",
+"input":"<!DOCTYPEa PUBLIC\"1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "1", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"9",
+"input":"<!DOCTYPEa PUBLIC\"9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "9", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"<",
+"input":"<!DOCTYPEa PUBLIC\"<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "<", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"=",
+"input":"<!DOCTYPEa PUBLIC\"=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "=", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\">",
+"input":"<!DOCTYPEa PUBLIC\">",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"?",
+"input":"<!DOCTYPEa PUBLIC\"?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "?", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"@",
+"input":"<!DOCTYPEa PUBLIC\"@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "@", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"A",
+"input":"<!DOCTYPEa PUBLIC\"A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "A", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"B",
+"input":"<!DOCTYPEa PUBLIC\"B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "B", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"Y",
+"input":"<!DOCTYPEa PUBLIC\"Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "Y", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"Z",
+"input":"<!DOCTYPEa PUBLIC\"Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "Z", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"`",
+"input":"<!DOCTYPEa PUBLIC\"`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "`", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"a",
+"input":"<!DOCTYPEa PUBLIC\"a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "a", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"b",
+"input":"<!DOCTYPEa PUBLIC\"b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "b", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"y",
+"input":"<!DOCTYPEa PUBLIC\"y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "y", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"z",
+"input":"<!DOCTYPEa PUBLIC\"z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "z", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"{",
+"input":"<!DOCTYPEa PUBLIC\"{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "{", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\"\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa PUBLIC\"\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uDBC0\uDC00", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC#",
+"input":"<!DOCTYPEa PUBLIC#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC&",
+"input":"<!DOCTYPEa PUBLIC&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'",
+"input":"<!DOCTYPEa PUBLIC'",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u0000",
+"input":"<!DOCTYPEa PUBLIC'\u0000",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uFFFD", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u0009",
+"input":"<!DOCTYPEa PUBLIC'\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u0009", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u000A",
+"input":"<!DOCTYPEa PUBLIC'\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000A", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u000B",
+"input":"<!DOCTYPEa PUBLIC'\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000B", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\u000C",
+"input":"<!DOCTYPEa PUBLIC'\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\u000C", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC' ",
+"input":"<!DOCTYPEa PUBLIC' ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", " ", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'!",
+"input":"<!DOCTYPEa PUBLIC'!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "!", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\"",
+"input":"<!DOCTYPEa PUBLIC'\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\"", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'&",
+"input":"<!DOCTYPEa PUBLIC'&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "&", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''",
+"input":"<!DOCTYPEa PUBLIC''",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u0000",
+"input":"<!DOCTYPEa PUBLIC''\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u0008",
+"input":"<!DOCTYPEa PUBLIC''\u0008",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u0009",
+"input":"<!DOCTYPEa PUBLIC''\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u000A",
+"input":"<!DOCTYPEa PUBLIC''\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u000B",
+"input":"<!DOCTYPEa PUBLIC''\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u000C",
+"input":"<!DOCTYPEa PUBLIC''\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u000D",
+"input":"<!DOCTYPEa PUBLIC''\u000D",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\u001F",
+"input":"<!DOCTYPEa PUBLIC''\u001F",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'' ",
+"input":"<!DOCTYPEa PUBLIC'' ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''!",
+"input":"<!DOCTYPEa PUBLIC''!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\"",
+"input":"<!DOCTYPEa PUBLIC''\"",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", "", false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''#",
+"input":"<!DOCTYPEa PUBLIC''#",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''&",
+"input":"<!DOCTYPEa PUBLIC''&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'''",
+"input":"<!DOCTYPEa PUBLIC'''",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", "", false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''(",
+"input":"<!DOCTYPEa PUBLIC''(",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''-",
+"input":"<!DOCTYPEa PUBLIC''-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''/",
+"input":"<!DOCTYPEa PUBLIC''/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''0",
+"input":"<!DOCTYPEa PUBLIC''0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''1",
+"input":"<!DOCTYPEa PUBLIC''1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''9",
+"input":"<!DOCTYPEa PUBLIC''9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''<",
+"input":"<!DOCTYPEa PUBLIC''<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''=",
+"input":"<!DOCTYPEa PUBLIC''=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''>",
+"input":"<!DOCTYPEa PUBLIC''>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", "", null, true]]},
+
+{"description":"<!DOCTYPEa PUBLIC''?",
+"input":"<!DOCTYPEa PUBLIC''?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''@",
+"input":"<!DOCTYPEa PUBLIC''@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''A",
+"input":"<!DOCTYPEa PUBLIC''A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''B",
+"input":"<!DOCTYPEa PUBLIC''B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''Y",
+"input":"<!DOCTYPEa PUBLIC''Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''Z",
+"input":"<!DOCTYPEa PUBLIC''Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''`",
+"input":"<!DOCTYPEa PUBLIC''`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''a",
+"input":"<!DOCTYPEa PUBLIC''a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''b",
+"input":"<!DOCTYPEa PUBLIC''b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''y",
+"input":"<!DOCTYPEa PUBLIC''y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''z",
+"input":"<!DOCTYPEa PUBLIC''z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''{",
+"input":"<!DOCTYPEa PUBLIC''{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC''\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa PUBLIC''\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'(",
+"input":"<!DOCTYPEa PUBLIC'(",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "(", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'-",
+"input":"<!DOCTYPEa PUBLIC'-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "-", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'/",
+"input":"<!DOCTYPEa PUBLIC'/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "/", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'0",
+"input":"<!DOCTYPEa PUBLIC'0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "0", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'1",
+"input":"<!DOCTYPEa PUBLIC'1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "1", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'9",
+"input":"<!DOCTYPEa PUBLIC'9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "9", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'<",
+"input":"<!DOCTYPEa PUBLIC'<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "<", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'=",
+"input":"<!DOCTYPEa PUBLIC'=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "=", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'>",
+"input":"<!DOCTYPEa PUBLIC'>",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'?",
+"input":"<!DOCTYPEa PUBLIC'?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "?", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'@",
+"input":"<!DOCTYPEa PUBLIC'@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "@", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'A",
+"input":"<!DOCTYPEa PUBLIC'A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "A", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'B",
+"input":"<!DOCTYPEa PUBLIC'B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "B", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'Y",
+"input":"<!DOCTYPEa PUBLIC'Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "Y", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'Z",
+"input":"<!DOCTYPEa PUBLIC'Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "Z", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'`",
+"input":"<!DOCTYPEa PUBLIC'`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "`", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'a",
+"input":"<!DOCTYPEa PUBLIC'a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "a", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'b",
+"input":"<!DOCTYPEa PUBLIC'b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "b", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'y",
+"input":"<!DOCTYPEa PUBLIC'y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "y", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'z",
+"input":"<!DOCTYPEa PUBLIC'z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "z", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'{",
+"input":"<!DOCTYPEa PUBLIC'{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "{", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC'\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa PUBLIC'\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", "\uDBC0\uDC00", null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC(",
+"input":"<!DOCTYPEa PUBLIC(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC-",
+"input":"<!DOCTYPEa PUBLIC-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC/",
+"input":"<!DOCTYPEa PUBLIC/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC0",
+"input":"<!DOCTYPEa PUBLIC0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC1",
+"input":"<!DOCTYPEa PUBLIC1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC9",
+"input":"<!DOCTYPEa PUBLIC9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC<",
+"input":"<!DOCTYPEa PUBLIC<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC=",
+"input":"<!DOCTYPEa PUBLIC=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC>",
+"input":"<!DOCTYPEa PUBLIC>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC?",
+"input":"<!DOCTYPEa PUBLIC?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC@",
+"input":"<!DOCTYPEa PUBLIC@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICA",
+"input":"<!DOCTYPEa PUBLICA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICB",
+"input":"<!DOCTYPEa PUBLICB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICY",
+"input":"<!DOCTYPEa PUBLICY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICZ",
+"input":"<!DOCTYPEa PUBLICZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC`",
+"input":"<!DOCTYPEa PUBLIC`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICa",
+"input":"<!DOCTYPEa PUBLICa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICb",
+"input":"<!DOCTYPEa PUBLICb",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICy",
+"input":"<!DOCTYPEa PUBLICy",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLICz",
+"input":"<!DOCTYPEa PUBLICz",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC{",
+"input":"<!DOCTYPEa PUBLIC{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa PUBLIC\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa PUBLIC\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM",
+"input":"<!DOCTYPEa SYSTEM",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u0000",
+"input":"<!DOCTYPEa SYSTEM\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u0008",
+"input":"<!DOCTYPEa SYSTEM\u0008",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u0009",
+"input":"<!DOCTYPEa SYSTEM\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u000A",
+"input":"<!DOCTYPEa SYSTEM\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u000B",
+"input":"<!DOCTYPEa SYSTEM\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u000C",
+"input":"<!DOCTYPEa SYSTEM\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u000D",
+"input":"<!DOCTYPEa SYSTEM\u000D",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\u001F",
+"input":"<!DOCTYPEa SYSTEM\u001F",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM ",
+"input":"<!DOCTYPEa SYSTEM ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM!",
+"input":"<!DOCTYPEa SYSTEM!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"",
+"input":"<!DOCTYPEa SYSTEM\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u0000",
+"input":"<!DOCTYPEa SYSTEM\"\u0000",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uFFFD", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u0009",
+"input":"<!DOCTYPEa SYSTEM\"\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u0009", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u000A",
+"input":"<!DOCTYPEa SYSTEM\"\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000A", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u000B",
+"input":"<!DOCTYPEa SYSTEM\"\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000B", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\u000C",
+"input":"<!DOCTYPEa SYSTEM\"\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000C", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\" ",
+"input":"<!DOCTYPEa SYSTEM\" ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, " ", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"!",
+"input":"<!DOCTYPEa SYSTEM\"!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "!", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\"",
+"input":"<!DOCTYPEa SYSTEM\"\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"#",
+"input":"<!DOCTYPEa SYSTEM\"#",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "#", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"&",
+"input":"<!DOCTYPEa SYSTEM\"&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "&", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"'",
+"input":"<!DOCTYPEa SYSTEM\"'",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "'", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"-",
+"input":"<!DOCTYPEa SYSTEM\"-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "-", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"/",
+"input":"<!DOCTYPEa SYSTEM\"/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "/", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"0",
+"input":"<!DOCTYPEa SYSTEM\"0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "0", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"1",
+"input":"<!DOCTYPEa SYSTEM\"1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "1", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"9",
+"input":"<!DOCTYPEa SYSTEM\"9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "9", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"<",
+"input":"<!DOCTYPEa SYSTEM\"<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "<", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"=",
+"input":"<!DOCTYPEa SYSTEM\"=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "=", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\">",
+"input":"<!DOCTYPEa SYSTEM\">",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"?",
+"input":"<!DOCTYPEa SYSTEM\"?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "?", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"@",
+"input":"<!DOCTYPEa SYSTEM\"@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "@", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"A",
+"input":"<!DOCTYPEa SYSTEM\"A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "A", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"B",
+"input":"<!DOCTYPEa SYSTEM\"B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "B", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"Y",
+"input":"<!DOCTYPEa SYSTEM\"Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "Y", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"Z",
+"input":"<!DOCTYPEa SYSTEM\"Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "Z", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"`",
+"input":"<!DOCTYPEa SYSTEM\"`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "`", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"a",
+"input":"<!DOCTYPEa SYSTEM\"a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "a", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"b",
+"input":"<!DOCTYPEa SYSTEM\"b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "b", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"y",
+"input":"<!DOCTYPEa SYSTEM\"y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "y", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"z",
+"input":"<!DOCTYPEa SYSTEM\"z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "z", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"{",
+"input":"<!DOCTYPEa SYSTEM\"{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "{", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\"\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa SYSTEM\"\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uDBC0\uDC00", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM#",
+"input":"<!DOCTYPEa SYSTEM#",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM&",
+"input":"<!DOCTYPEa SYSTEM&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'",
+"input":"<!DOCTYPEa SYSTEM'",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u0000",
+"input":"<!DOCTYPEa SYSTEM'\u0000",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uFFFD", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u0009",
+"input":"<!DOCTYPEa SYSTEM'\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u0009", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u000A",
+"input":"<!DOCTYPEa SYSTEM'\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000A", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u000B",
+"input":"<!DOCTYPEa SYSTEM'\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000B", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\u000C",
+"input":"<!DOCTYPEa SYSTEM'\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\u000C", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM' ",
+"input":"<!DOCTYPEa SYSTEM' ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, " ", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'!",
+"input":"<!DOCTYPEa SYSTEM'!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "!", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\"",
+"input":"<!DOCTYPEa SYSTEM'\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\"", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'&",
+"input":"<!DOCTYPEa SYSTEM'&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "&", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''",
+"input":"<!DOCTYPEa SYSTEM''",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u0000",
+"input":"<!DOCTYPEa SYSTEM''\u0000",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u0008",
+"input":"<!DOCTYPEa SYSTEM''\u0008",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u0009",
+"input":"<!DOCTYPEa SYSTEM''\u0009",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u000A",
+"input":"<!DOCTYPEa SYSTEM''\u000A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u000B",
+"input":"<!DOCTYPEa SYSTEM''\u000B",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u000C",
+"input":"<!DOCTYPEa SYSTEM''\u000C",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u000D",
+"input":"<!DOCTYPEa SYSTEM''\u000D",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\u001F",
+"input":"<!DOCTYPEa SYSTEM''\u001F",
+"output":["ParseError", "ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM'' ",
+"input":"<!DOCTYPEa SYSTEM'' ",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM''!",
+"input":"<!DOCTYPEa SYSTEM''!",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\"",
+"input":"<!DOCTYPEa SYSTEM''\"",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''&",
+"input":"<!DOCTYPEa SYSTEM''&",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM'''",
+"input":"<!DOCTYPEa SYSTEM'''",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''-",
+"input":"<!DOCTYPEa SYSTEM''-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''/",
+"input":"<!DOCTYPEa SYSTEM''/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''0",
+"input":"<!DOCTYPEa SYSTEM''0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''1",
+"input":"<!DOCTYPEa SYSTEM''1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''9",
+"input":"<!DOCTYPEa SYSTEM''9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''<",
+"input":"<!DOCTYPEa SYSTEM''<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''=",
+"input":"<!DOCTYPEa SYSTEM''=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''>",
+"input":"<!DOCTYPEa SYSTEM''>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''?",
+"input":"<!DOCTYPEa SYSTEM''?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''@",
+"input":"<!DOCTYPEa SYSTEM''@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''A",
+"input":"<!DOCTYPEa SYSTEM''A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''B",
+"input":"<!DOCTYPEa SYSTEM''B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''Y",
+"input":"<!DOCTYPEa SYSTEM''Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''Z",
+"input":"<!DOCTYPEa SYSTEM''Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''`",
+"input":"<!DOCTYPEa SYSTEM''`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''a",
+"input":"<!DOCTYPEa SYSTEM''a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''b",
+"input":"<!DOCTYPEa SYSTEM''b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''y",
+"input":"<!DOCTYPEa SYSTEM''y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''z",
+"input":"<!DOCTYPEa SYSTEM''z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''{",
+"input":"<!DOCTYPEa SYSTEM''{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM''\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa SYSTEM''\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", true]]},
+
+{"description":"<!DOCTYPEa SYSTEM'(",
+"input":"<!DOCTYPEa SYSTEM'(",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "(", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'-",
+"input":"<!DOCTYPEa SYSTEM'-",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "-", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'/",
+"input":"<!DOCTYPEa SYSTEM'/",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "/", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'0",
+"input":"<!DOCTYPEa SYSTEM'0",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "0", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'1",
+"input":"<!DOCTYPEa SYSTEM'1",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "1", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'9",
+"input":"<!DOCTYPEa SYSTEM'9",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "9", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'<",
+"input":"<!DOCTYPEa SYSTEM'<",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "<", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'=",
+"input":"<!DOCTYPEa SYSTEM'=",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "=", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'>",
+"input":"<!DOCTYPEa SYSTEM'>",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'?",
+"input":"<!DOCTYPEa SYSTEM'?",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "?", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'@",
+"input":"<!DOCTYPEa SYSTEM'@",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "@", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'A",
+"input":"<!DOCTYPEa SYSTEM'A",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "A", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'B",
+"input":"<!DOCTYPEa SYSTEM'B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "B", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'Y",
+"input":"<!DOCTYPEa SYSTEM'Y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "Y", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'Z",
+"input":"<!DOCTYPEa SYSTEM'Z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "Z", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'`",
+"input":"<!DOCTYPEa SYSTEM'`",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "`", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'a",
+"input":"<!DOCTYPEa SYSTEM'a",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "a", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'b",
+"input":"<!DOCTYPEa SYSTEM'b",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "b", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'y",
+"input":"<!DOCTYPEa SYSTEM'y",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "y", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'z",
+"input":"<!DOCTYPEa SYSTEM'z",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "z", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'{",
+"input":"<!DOCTYPEa SYSTEM'{",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "{", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM'\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa SYSTEM'\uDBC0\uDC00",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, "\uDBC0\uDC00", false]]},
+
+{"description":"<!DOCTYPEa SYSTEM(",
+"input":"<!DOCTYPEa SYSTEM(",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM-",
+"input":"<!DOCTYPEa SYSTEM-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM/",
+"input":"<!DOCTYPEa SYSTEM/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM0",
+"input":"<!DOCTYPEa SYSTEM0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM1",
+"input":"<!DOCTYPEa SYSTEM1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM9",
+"input":"<!DOCTYPEa SYSTEM9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM<",
+"input":"<!DOCTYPEa SYSTEM<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM=",
+"input":"<!DOCTYPEa SYSTEM=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM>",
+"input":"<!DOCTYPEa SYSTEM>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM?",
+"input":"<!DOCTYPEa SYSTEM?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM@",
+"input":"<!DOCTYPEa SYSTEM@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMA",
+"input":"<!DOCTYPEa SYSTEMA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMB",
+"input":"<!DOCTYPEa SYSTEMB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMY",
+"input":"<!DOCTYPEa SYSTEMY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMZ",
+"input":"<!DOCTYPEa SYSTEMZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM`",
+"input":"<!DOCTYPEa SYSTEM`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMa",
+"input":"<!DOCTYPEa SYSTEMa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMb",
+"input":"<!DOCTYPEa SYSTEMb",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMy",
+"input":"<!DOCTYPEa SYSTEMy",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEMz",
+"input":"<!DOCTYPEa SYSTEMz",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM{",
+"input":"<!DOCTYPEa SYSTEM{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa SYSTEM\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa SYSTEM\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa Y",
+"input":"<!DOCTYPEa Y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa Z",
+"input":"<!DOCTYPEa Z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa `",
+"input":"<!DOCTYPEa `",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a",
+"input":"<!DOCTYPEa a",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u0000",
+"input":"<!DOCTYPEa a\u0000",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u0009",
+"input":"<!DOCTYPEa a\u0009",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u000A",
+"input":"<!DOCTYPEa a\u000A",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u000B",
+"input":"<!DOCTYPEa a\u000B",
+"output":["ParseError", "ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\u000C",
+"input":"<!DOCTYPEa a\u000C",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a ",
+"input":"<!DOCTYPEa a ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a!",
+"input":"<!DOCTYPEa a!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\"",
+"input":"<!DOCTYPEa a\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a&",
+"input":"<!DOCTYPEa a&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a'",
+"input":"<!DOCTYPEa a'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a-",
+"input":"<!DOCTYPEa a-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a/",
+"input":"<!DOCTYPEa a/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a0",
+"input":"<!DOCTYPEa a0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a1",
+"input":"<!DOCTYPEa a1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a9",
+"input":"<!DOCTYPEa a9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a<",
+"input":"<!DOCTYPEa a<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a=",
+"input":"<!DOCTYPEa a=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a>",
+"input":"<!DOCTYPEa a>",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a?",
+"input":"<!DOCTYPEa a?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a@",
+"input":"<!DOCTYPEa a@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aA",
+"input":"<!DOCTYPEa aA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aB",
+"input":"<!DOCTYPEa aB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aY",
+"input":"<!DOCTYPEa aY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aZ",
+"input":"<!DOCTYPEa aZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a`",
+"input":"<!DOCTYPEa a`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa aa",
+"input":"<!DOCTYPEa aa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa ab",
+"input":"<!DOCTYPEa ab",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa ay",
+"input":"<!DOCTYPEa ay",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa az",
+"input":"<!DOCTYPEa az",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a{",
+"input":"<!DOCTYPEa a{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa a\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa a\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa b",
+"input":"<!DOCTYPEa b",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa y",
+"input":"<!DOCTYPEa y",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa z",
+"input":"<!DOCTYPEa z",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa {",
+"input":"<!DOCTYPEa {",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa \\uDBC0\\uDC00",
+"input":"<!DOCTYPEa \uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a", null, null, false]]},
+
+{"description":"<!DOCTYPEa!",
+"input":"<!DOCTYPEa!",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a!", null, null, false]]},
+
+{"description":"<!DOCTYPEa\"",
+"input":"<!DOCTYPEa\"",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\"", null, null, false]]},
+
+{"description":"<!DOCTYPEa&",
+"input":"<!DOCTYPEa&",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a&", null, null, false]]},
+
+{"description":"<!DOCTYPEa'",
+"input":"<!DOCTYPEa'",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a'", null, null, false]]},
+
+{"description":"<!DOCTYPEa-",
+"input":"<!DOCTYPEa-",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a-", null, null, false]]},
+
+{"description":"<!DOCTYPEa/",
+"input":"<!DOCTYPEa/",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a/", null, null, false]]},
+
+{"description":"<!DOCTYPEa0",
+"input":"<!DOCTYPEa0",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a0", null, null, false]]},
+
+{"description":"<!DOCTYPEa1",
+"input":"<!DOCTYPEa1",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a1", null, null, false]]},
+
+{"description":"<!DOCTYPEa9",
+"input":"<!DOCTYPEa9",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a9", null, null, false]]},
+
+{"description":"<!DOCTYPEa<",
+"input":"<!DOCTYPEa<",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a<", null, null, false]]},
+
+{"description":"<!DOCTYPEa=",
+"input":"<!DOCTYPEa=",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a=", null, null, false]]},
+
+{"description":"<!DOCTYPEa>",
+"input":"<!DOCTYPEa>",
+"output":["ParseError", ["DOCTYPE", "a", null, null, true]]},
+
+{"description":"<!DOCTYPEa?",
+"input":"<!DOCTYPEa?",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a?", null, null, false]]},
+
+{"description":"<!DOCTYPEa@",
+"input":"<!DOCTYPEa@",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a@", null, null, false]]},
+
+{"description":"<!DOCTYPEaA",
+"input":"<!DOCTYPEaA",
+"output":["ParseError", "ParseError", ["DOCTYPE", "aa", null, null, false]]},
+
+{"description":"<!DOCTYPEaB",
+"input":"<!DOCTYPEaB",
+"output":["ParseError", "ParseError", ["DOCTYPE", "ab", null, null, false]]},
+
+{"description":"<!DOCTYPEaY",
+"input":"<!DOCTYPEaY",
+"output":["ParseError", "ParseError", ["DOCTYPE", "ay", null, null, false]]},
+
+{"description":"<!DOCTYPEaZ",
+"input":"<!DOCTYPEaZ",
+"output":["ParseError", "ParseError", ["DOCTYPE", "az", null, null, false]]},
+
+{"description":"<!DOCTYPEa[",
+"input":"<!DOCTYPEa[",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a[", null, null, false]]},
+
+{"description":"<!DOCTYPEa`",
+"input":"<!DOCTYPEa`",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a`", null, null, false]]},
+
+{"description":"<!DOCTYPEaa",
+"input":"<!DOCTYPEaa",
+"output":["ParseError", "ParseError", ["DOCTYPE", "aa", null, null, false]]},
+
+{"description":"<!DOCTYPEab",
+"input":"<!DOCTYPEab",
+"output":["ParseError", "ParseError", ["DOCTYPE", "ab", null, null, false]]},
+
+{"description":"<!DOCTYPEay",
+"input":"<!DOCTYPEay",
+"output":["ParseError", "ParseError", ["DOCTYPE", "ay", null, null, false]]},
+
+{"description":"<!DOCTYPEaz",
+"input":"<!DOCTYPEaz",
+"output":["ParseError", "ParseError", ["DOCTYPE", "az", null, null, false]]},
+
+{"description":"<!DOCTYPEa{",
+"input":"<!DOCTYPEa{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a{", null, null, false]]},
+
+{"description":"<!DOCTYPEa\\uDBC0\\uDC00",
+"input":"<!DOCTYPEa\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "a\uDBC0\uDC00", null, null, false]]},
+
+{"description":"<!DOCTYPEb",
+"input":"<!DOCTYPEb",
+"output":["ParseError", "ParseError", ["DOCTYPE", "b", null, null, false]]},
+
+{"description":"<!DOCTYPEy",
+"input":"<!DOCTYPEy",
+"output":["ParseError", "ParseError", ["DOCTYPE", "y", null, null, false]]},
+
+{"description":"<!DOCTYPEz",
+"input":"<!DOCTYPEz",
+"output":["ParseError", "ParseError", ["DOCTYPE", "z", null, null, false]]},
+
+{"description":"<!DOCTYPE{",
+"input":"<!DOCTYPE{",
+"output":["ParseError", "ParseError", ["DOCTYPE", "{", null, null, false]]},
+
+{"description":"<!DOCTYPE\\uDBC0\\uDC00",
+"input":"<!DOCTYPE\uDBC0\uDC00",
+"output":["ParseError", "ParseError", ["DOCTYPE", "\uDBC0\uDC00", null, null, false]]},
+
+{"description":"<!Y",
+"input":"<!Y",
+"output":["ParseError", ["Comment", "Y"]]},
+
+{"description":"<!Z",
+"input":"<!Z",
+"output":["ParseError", ["Comment", "Z"]]},
+
+{"description":"<!`",
+"input":"<!`",
+"output":["ParseError", ["Comment", "`"]]},
+
+{"description":"<!a",
+"input":"<!a",
+"output":["ParseError", ["Comment", "a"]]},
+
+{"description":"<!b",
+"input":"<!b",
+"output":["ParseError", ["Comment", "b"]]},
+
+{"description":"<!y",
+"input":"<!y",
+"output":["ParseError", ["Comment", "y"]]},
+
+{"description":"<!z",
+"input":"<!z",
+"output":["ParseError", ["Comment", "z"]]},
+
+{"description":"<!{",
+"input":"<!{",
+"output":["ParseError", ["Comment", "{"]]},
+
+{"description":"<!\\uDBC0\\uDC00",
+"input":"<!\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "\uDBC0\uDC00"]]},
+
+{"description":"<\"",
+"input":"<\"",
+"output":["ParseError", ["Character", "<\""]]},
+
+{"description":"<&",
+"input":"<&",
+"output":["ParseError", ["Character", "<&"]]},
+
+{"description":"<'",
+"input":"<'",
+"output":["ParseError", ["Character", "<'"]]},
+
+{"description":"<-",
+"input":"<-",
+"output":["ParseError", ["Character", "<-"]]},
+
+{"description":"<.",
+"input":"<.",
+"output":["ParseError", ["Character", "<."]]},
+
+{"description":"</",
+"input":"</",
+"output":["ParseError", ["Character", "</"]]},
+
+{"description":"</\\u0000",
+"input":"</\u0000",
+"output":["ParseError", ["Comment", "\uFFFD"]]},
+
+{"description":"</\\u0009",
+"input":"</\u0009",
+"output":["ParseError", ["Comment", "\u0009"]]},
+
+{"description":"</\\u000A",
+"input":"</\u000A",
+"output":["ParseError", ["Comment", "\u000A"]]},
+
+{"description":"</\\u000B",
+"input":"</\u000B",
+"output":["ParseError", "ParseError", ["Comment", "\u000B"]]},
+
+{"description":"</\\u000C",
+"input":"</\u000C",
+"output":["ParseError", ["Comment", "\u000C"]]},
+
+{"description":"</ ",
+"input":"</ ",
+"output":["ParseError", ["Comment", " "]]},
+
+{"description":"</!",
+"input":"</!",
+"output":["ParseError", ["Comment", "!"]]},
+
+{"description":"</\"",
+"input":"</\"",
+"output":["ParseError", ["Comment", "\""]]},
+
+{"description":"</&",
+"input":"</&",
+"output":["ParseError", ["Comment", "&"]]},
+
+{"description":"</'",
+"input":"</'",
+"output":["ParseError", ["Comment", "'"]]},
+
+{"description":"</-",
+"input":"</-",
+"output":["ParseError", ["Comment", "-"]]},
+
+{"description":"<//",
+"input":"<//",
+"output":["ParseError", ["Comment", "/"]]},
+
+{"description":"</0",
+"input":"</0",
+"output":["ParseError", ["Comment", "0"]]},
+
+{"description":"</1",
+"input":"</1",
+"output":["ParseError", ["Comment", "1"]]},
+
+{"description":"</9",
+"input":"</9",
+"output":["ParseError", ["Comment", "9"]]},
+
+{"description":"</<",
+"input":"</<",
+"output":["ParseError", ["Comment", "<"]]},
+
+{"description":"</=",
+"input":"</=",
+"output":["ParseError", ["Comment", "="]]},
+
+{"description":"</>",
+"input":"</>",
+"output":["ParseError"]},
+
+{"description":"</?",
+"input":"</?",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"</@",
+"input":"</@",
+"output":["ParseError", ["Comment", "@"]]},
+
+{"description":"</A>",
+"input":"</A>",
+"output":[["EndTag", "a"]]},
+
+{"description":"</B>",
+"input":"</B>",
+"output":[["EndTag", "b"]]},
+
+{"description":"</Y>",
+"input":"</Y>",
+"output":[["EndTag", "y"]]},
+
+{"description":"</Z>",
+"input":"</Z>",
+"output":[["EndTag", "z"]]},
+
+{"description":"</[",
+"input":"</[",
+"output":["ParseError", ["Comment", "["]]},
+
+{"description":"</`",
+"input":"</`",
+"output":["ParseError", ["Comment", "`"]]},
+
+{"description":"</a>",
+"input":"</a>",
+"output":[["EndTag", "a"]]},
+
+{"description":"</b>",
+"input":"</b>",
+"output":[["EndTag", "b"]]},
+
+{"description":"</y>",
+"input":"</y>",
+"output":[["EndTag", "y"]]},
+
+{"description":"</z>",
+"input":"</z>",
+"output":[["EndTag", "z"]]},
+
+{"description":"</{",
+"input":"</{",
+"output":["ParseError", ["Comment", "{"]]},
+
+{"description":"</\\uDBC0\\uDC00",
+"input":"</\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "\uDBC0\uDC00"]]},
+
+{"description":"<0",
+"input":"<0",
+"output":["ParseError", ["Character", "<0"]]},
+
+{"description":"<1",
+"input":"<1",
+"output":["ParseError", ["Character", "<1"]]},
+
+{"description":"<9",
+"input":"<9",
+"output":["ParseError", ["Character", "<9"]]},
+
+{"description":"<<",
+"input":"<<",
+"output":["ParseError", ["Character", "<"], "ParseError", ["Character", "<"]]},
+
+{"description":"<=",
+"input":"<=",
+"output":["ParseError", ["Character", "<="]]},
+
+{"description":"<>",
+"input":"<>",
+"output":["ParseError", ["Character", "<>"]]},
+
+{"description":"<?",
+"input":"<?",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"<?\\u0000",
+"input":"<?\u0000",
+"output":["ParseError", ["Comment", "?\uFFFD"]]},
+
+{"description":"<?\\u0009",
+"input":"<?\u0009",
+"output":["ParseError", ["Comment", "?\u0009"]]},
+
+{"description":"<?\\u000A",
+"input":"<?\u000A",
+"output":["ParseError", ["Comment", "?\u000A"]]},
+
+{"description":"<?\\u000B",
+"input":"<?\u000B",
+"output":["ParseError", "ParseError", ["Comment", "?\u000B"]]},
+
+{"description":"<?\\u000C",
+"input":"<?\u000C",
+"output":["ParseError", ["Comment", "?\u000C"]]},
+
+{"description":"<? ",
+"input":"<? ",
+"output":["ParseError", ["Comment", "? "]]},
+
+{"description":"<?!",
+"input":"<?!",
+"output":["ParseError", ["Comment", "?!"]]},
+
+{"description":"<?\"",
+"input":"<?\"",
+"output":["ParseError", ["Comment", "?\""]]},
+
+{"description":"<?&",
+"input":"<?&",
+"output":["ParseError", ["Comment", "?&"]]},
+
+{"description":"<?'",
+"input":"<?'",
+"output":["ParseError", ["Comment", "?'"]]},
+
+{"description":"<?-",
+"input":"<?-",
+"output":["ParseError", ["Comment", "?-"]]},
+
+{"description":"<?/",
+"input":"<?/",
+"output":["ParseError", ["Comment", "?/"]]},
+
+{"description":"<?0",
+"input":"<?0",
+"output":["ParseError", ["Comment", "?0"]]},
+
+{"description":"<?1",
+"input":"<?1",
+"output":["ParseError", ["Comment", "?1"]]},
+
+{"description":"<?9",
+"input":"<?9",
+"output":["ParseError", ["Comment", "?9"]]},
+
+{"description":"<?<",
+"input":"<?<",
+"output":["ParseError", ["Comment", "?<"]]},
+
+{"description":"<?=",
+"input":"<?=",
+"output":["ParseError", ["Comment", "?="]]},
+
+{"description":"<?>",
+"input":"<?>",
+"output":["ParseError", ["Comment", "?"]]},
+
+{"description":"<??",
+"input":"<??",
+"output":["ParseError", ["Comment", "??"]]},
+
+{"description":"<?@",
+"input":"<?@",
+"output":["ParseError", ["Comment", "?@"]]},
+
+{"description":"<?A",
+"input":"<?A",
+"output":["ParseError", ["Comment", "?A"]]},
+
+{"description":"<?B",
+"input":"<?B",
+"output":["ParseError", ["Comment", "?B"]]},
+
+{"description":"<?Y",
+"input":"<?Y",
+"output":["ParseError", ["Comment", "?Y"]]},
+
+{"description":"<?Z",
+"input":"<?Z",
+"output":["ParseError", ["Comment", "?Z"]]},
+
+{"description":"<?`",
+"input":"<?`",
+"output":["ParseError", ["Comment", "?`"]]},
+
+{"description":"<?a",
+"input":"<?a",
+"output":["ParseError", ["Comment", "?a"]]},
+
+{"description":"<?b",
+"input":"<?b",
+"output":["ParseError", ["Comment", "?b"]]},
+
+{"description":"<?y",
+"input":"<?y",
+"output":["ParseError", ["Comment", "?y"]]},
+
+{"description":"<?z",
+"input":"<?z",
+"output":["ParseError", ["Comment", "?z"]]},
+
+{"description":"<?{",
+"input":"<?{",
+"output":["ParseError", ["Comment", "?{"]]},
+
+{"description":"<?\\uDBC0\\uDC00",
+"input":"<?\uDBC0\uDC00",
+"output":["ParseError", ["Comment", "?\uDBC0\uDC00"]]},
+
+{"description":"<@",
+"input":"<@",
+"output":["ParseError", ["Character", "<@"]]},
+
+{"description":"<A>",
+"input":"<A>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<B>",
+"input":"<B>",
+"output":[["StartTag", "b", {}]]},
+
+{"description":"<Y>",
+"input":"<Y>",
+"output":[["StartTag", "y", {}]]},
+
+{"description":"<Z>",
+"input":"<Z>",
+"output":[["StartTag", "z", {}]]},
+
+{"description":"<[",
+"input":"<[",
+"output":["ParseError", ["Character", "<["]]},
+
+{"description":"<`",
+"input":"<`",
+"output":["ParseError", ["Character", "<`"]]},
+
+{"description":"<a>",
+"input":"<a>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u0000>",
+"input":"<a\u0000>",
+"output":["ParseError", ["StartTag", "a\uFFFD", {}]]},
+
+{"description":"<a\\u0008>",
+"input":"<a\u0008>",
+"output":["ParseError", ["StartTag", "a\u0008", {}]]},
+
+{"description":"<a\\u0009>",
+"input":"<a\u0009>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u000A>",
+"input":"<a\u000A>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u000B>",
+"input":"<a\u000B>",
+"output":["ParseError", ["StartTag", "a\u000B", {}]]},
+
+{"description":"<a\\u000C>",
+"input":"<a\u000C>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u000D>",
+"input":"<a\u000D>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a\\u001F>",
+"input":"<a\u001F>",
+"output":["ParseError", ["StartTag", "a\u001F", {}]]},
+
+{"description":"<a >",
+"input":"<a >",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u0000>",
+"input":"<a \u0000>",
+"output":["ParseError", ["StartTag", "a", {"\uFFFD":""}]]},
+
+{"description":"<a \\u0008>",
+"input":"<a \u0008>",
+"output":["ParseError", ["StartTag", "a", {"\u0008":""}]]},
+
+{"description":"<a \\u0009>",
+"input":"<a \u0009>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u000A>",
+"input":"<a \u000A>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u000B>",
+"input":"<a \u000B>",
+"output":["ParseError", ["StartTag", "a", {"\u000B":""}]]},
+
+{"description":"<a \\u000C>",
+"input":"<a \u000C>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u000D>",
+"input":"<a \u000D>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a \\u001F>",
+"input":"<a \u001F>",
+"output":["ParseError", ["StartTag", "a", {"\u001F":""}]]},
+
+{"description":"<a >",
+"input":"<a >",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a !>",
+"input":"<a !>",
+"output":[["StartTag", "a", {"!":""}]]},
+
+{"description":"<a \">",
+"input":"<a \">",
+"output":["ParseError", ["StartTag", "a", {"\"":""}]]},
+
+{"description":"<a #>",
+"input":"<a #>",
+"output":[["StartTag", "a", {"#":""}]]},
+
+{"description":"<a &>",
+"input":"<a &>",
+"output":[["StartTag", "a", {"&":""}]]},
+
+{"description":"<a '>",
+"input":"<a '>",
+"output":["ParseError", ["StartTag", "a", {"'":""}]]},
+
+{"description":"<a (>",
+"input":"<a (>",
+"output":[["StartTag", "a", {"(":""}]]},
+
+{"description":"<a ->",
+"input":"<a ->",
+"output":[["StartTag", "a", {"-":""}]]},
+
+{"description":"<a .>",
+"input":"<a .>",
+"output":[["StartTag", "a", {".":""}]]},
+
+{"description":"<a />",
+"input":"<a />",
+"output":[["StartTag", "a", {}, true]]},
+
+{"description":"<a 0>",
+"input":"<a 0>",
+"output":[["StartTag", "a", {"0":""}]]},
+
+{"description":"<a 1>",
+"input":"<a 1>",
+"output":[["StartTag", "a", {"1":""}]]},
+
+{"description":"<a 9>",
+"input":"<a 9>",
+"output":[["StartTag", "a", {"9":""}]]},
+
+{"description":"<a <>",
+"input":"<a <>",
+"output":["ParseError", ["StartTag", "a", {"<":""}]]},
+
+{"description":"<a =>",
+"input":"<a =>",
+"output":["ParseError", ["StartTag", "a", {"=":""}]]},
+
+{"description":"<a >",
+"input":"<a >",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a ?>",
+"input":"<a ?>",
+"output":[["StartTag", "a", {"?":""}]]},
+
+{"description":"<a @>",
+"input":"<a @>",
+"output":[["StartTag", "a", {"@":""}]]},
+
+{"description":"<a A>",
+"input":"<a A>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a B>",
+"input":"<a B>",
+"output":[["StartTag", "a", {"b":""}]]},
+
+{"description":"<a Y>",
+"input":"<a Y>",
+"output":[["StartTag", "a", {"y":""}]]},
+
+{"description":"<a Z>",
+"input":"<a Z>",
+"output":[["StartTag", "a", {"z":""}]]},
+
+{"description":"<a [>",
+"input":"<a [>",
+"output":[["StartTag", "a", {"[":""}]]},
+
+{"description":"<a `>",
+"input":"<a `>",
+"output":[["StartTag", "a", {"`":""}]]},
+
+{"description":"<a a>",
+"input":"<a a>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u0000>",
+"input":"<a a\u0000>",
+"output":["ParseError", ["StartTag", "a", {"a\uFFFD":""}]]},
+
+{"description":"<a a\\u0008>",
+"input":"<a a\u0008>",
+"output":["ParseError", ["StartTag", "a", {"a\u0008":""}]]},
+
+{"description":"<a a\\u0009>",
+"input":"<a a\u0009>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u000A>",
+"input":"<a a\u000A>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u000B>",
+"input":"<a a\u000B>",
+"output":["ParseError", ["StartTag", "a", {"a\u000B":""}]]},
+
+{"description":"<a a\\u000C>",
+"input":"<a a\u000C>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u000D>",
+"input":"<a a\u000D>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a\\u001F>",
+"input":"<a a\u001F>",
+"output":["ParseError", ["StartTag", "a", {"a\u001F":""}]]},
+
+{"description":"<a a >",
+"input":"<a a >",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u0000>",
+"input":"<a a \u0000>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\uFFFD":""}]]},
+
+{"description":"<a a \\u0008>",
+"input":"<a a \u0008>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\u0008":""}]]},
+
+{"description":"<a a \\u0009>",
+"input":"<a a \u0009>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u000A>",
+"input":"<a a \u000A>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u000B>",
+"input":"<a a \u000B>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\u000B":""}]]},
+
+{"description":"<a a \\u000C>",
+"input":"<a a \u000C>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u000D>",
+"input":"<a a \u000D>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a \\u001F>",
+"input":"<a a \u001F>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\u001F":""}]]},
+
+{"description":"<a a >",
+"input":"<a a >",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a !>",
+"input":"<a a !>",
+"output":[["StartTag", "a", {"a":"", "!":""}]]},
+
+{"description":"<a a \">",
+"input":"<a a \">",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\"":""}]]},
+
+{"description":"<a a #>",
+"input":"<a a #>",
+"output":[["StartTag", "a", {"a":"", "#":""}]]},
+
+{"description":"<a a &>",
+"input":"<a a &>",
+"output":[["StartTag", "a", {"a":"", "&":""}]]},
+
+{"description":"<a a '>",
+"input":"<a a '>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "'":""}]]},
+
+{"description":"<a a (>",
+"input":"<a a (>",
+"output":[["StartTag", "a", {"a":"", "(":""}]]},
+
+{"description":"<a a ->",
+"input":"<a a ->",
+"output":[["StartTag", "a", {"a":"", "-":""}]]},
+
+{"description":"<a a .>",
+"input":"<a a .>",
+"output":[["StartTag", "a", {"a":"", ".":""}]]},
+
+{"description":"<a a />",
+"input":"<a a />",
+"output":[["StartTag", "a", {"a":""}, true]]},
+
+{"description":"<a a 0>",
+"input":"<a a 0>",
+"output":[["StartTag", "a", {"a":"", "0":""}]]},
+
+{"description":"<a a 1>",
+"input":"<a a 1>",
+"output":[["StartTag", "a", {"a":"", "1":""}]]},
+
+{"description":"<a a 9>",
+"input":"<a a 9>",
+"output":[["StartTag", "a", {"a":"", "9":""}]]},
+
+{"description":"<a a <>",
+"input":"<a a <>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "<":""}]]},
+
+{"description":"<a a =>",
+"input":"<a a =>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a >",
+"input":"<a a >",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a ?>",
+"input":"<a a ?>",
+"output":[["StartTag", "a", {"a":"", "?":""}]]},
+
+{"description":"<a a @>",
+"input":"<a a @>",
+"output":[["StartTag", "a", {"a":"", "@":""}]]},
+
+{"description":"<a a A>",
+"input":"<a a A>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a B>",
+"input":"<a a B>",
+"output":[["StartTag", "a", {"a":"", "b":""}]]},
+
+{"description":"<a a Y>",
+"input":"<a a Y>",
+"output":[["StartTag", "a", {"a":"", "y":""}]]},
+
+{"description":"<a a Z>",
+"input":"<a a Z>",
+"output":[["StartTag", "a", {"a":"", "z":""}]]},
+
+{"description":"<a a [>",
+"input":"<a a [>",
+"output":[["StartTag", "a", {"a":"", "[":""}]]},
+
+{"description":"<a a `>",
+"input":"<a a `>",
+"output":[["StartTag", "a", {"a":"", "`":""}]]},
+
+{"description":"<a a a>",
+"input":"<a a a>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a b>",
+"input":"<a a b>",
+"output":[["StartTag", "a", {"a":"", "b":""}]]},
+
+{"description":"<a a y>",
+"input":"<a a y>",
+"output":[["StartTag", "a", {"a":"", "y":""}]]},
+
+{"description":"<a a z>",
+"input":"<a a z>",
+"output":[["StartTag", "a", {"a":"", "z":""}]]},
+
+{"description":"<a a {>",
+"input":"<a a {>",
+"output":[["StartTag", "a", {"a":"", "{":""}]]},
+
+{"description":"<a a \\uDBC0\\uDC00>",
+"input":"<a a \uDBC0\uDC00>",
+"output":[["StartTag", "a", {"a":"", "\uDBC0\uDC00":""}]]},
+
+{"description":"<a a!>",
+"input":"<a a!>",
+"output":[["StartTag", "a", {"a!":""}]]},
+
+{"description":"<a a\">",
+"input":"<a a\">",
+"output":["ParseError", ["StartTag", "a", {"a\"":""}]]},
+
+{"description":"<a a#>",
+"input":"<a a#>",
+"output":[["StartTag", "a", {"a#":""}]]},
+
+{"description":"<a a&>",
+"input":"<a a&>",
+"output":[["StartTag", "a", {"a&":""}]]},
+
+{"description":"<a a'>",
+"input":"<a a'>",
+"output":["ParseError", ["StartTag", "a", {"a'":""}]]},
+
+{"description":"<a a(>",
+"input":"<a a(>",
+"output":[["StartTag", "a", {"a(":""}]]},
+
+{"description":"<a a->",
+"input":"<a a->",
+"output":[["StartTag", "a", {"a-":""}]]},
+
+{"description":"<a a.>",
+"input":"<a a.>",
+"output":[["StartTag", "a", {"a.":""}]]},
+
+{"description":"<a a/>",
+"input":"<a a/>",
+"output":[["StartTag", "a", {"a":""}, true]]},
+
+{"description":"<a a0>",
+"input":"<a a0>",
+"output":[["StartTag", "a", {"a0":""}]]},
+
+{"description":"<a a1>",
+"input":"<a a1>",
+"output":[["StartTag", "a", {"a1":""}]]},
+
+{"description":"<a a9>",
+"input":"<a a9>",
+"output":[["StartTag", "a", {"a9":""}]]},
+
+{"description":"<a a<>",
+"input":"<a a<>",
+"output":["ParseError", ["StartTag", "a", {"a<":""}]]},
+
+{"description":"<a a=>",
+"input":"<a a=>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u0000>",
+"input":"<a a=\u0000>",
+"output":["ParseError", ["StartTag", "a", {"a":"\uFFFD"}]]},
+
+{"description":"<a a=\\u0008>",
+"input":"<a a=\u0008>",
+"output":["ParseError", ["StartTag", "a", {"a":"\u0008"}]]},
+
+{"description":"<a a=\\u0009>",
+"input":"<a a=\u0009>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u000A>",
+"input":"<a a=\u000A>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u000B>",
+"input":"<a a=\u000B>",
+"output":["ParseError", ["StartTag", "a", {"a":"\u000B"}]]},
+
+{"description":"<a a=\\u000C>",
+"input":"<a a=\u000C>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u000D>",
+"input":"<a a=\u000D>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\\u001F>",
+"input":"<a a=\u001F>",
+"output":["ParseError", ["StartTag", "a", {"a":"\u001F"}]]},
+
+{"description":"<a a= >",
+"input":"<a a= >",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=!>",
+"input":"<a a=!>",
+"output":[["StartTag", "a", {"a":"!"}]]},
+
+{"description":"<a a=\"\">",
+"input":"<a a=\"\">",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\"\\u0000\">",
+"input":"<a a=\"\u0000\">",
+"output":["ParseError", ["StartTag", "a", {"a":"\uFFFD"}]]},
+
+{"description":"<a a=\"\\u0009\">",
+"input":"<a a=\"\u0009\">",
+"output":[["StartTag", "a", {"a":"\u0009"}]]},
+
+{"description":"<a a=\"\\u000A\">",
+"input":"<a a=\"\u000A\">",
+"output":[["StartTag", "a", {"a":"\u000A"}]]},
+
+{"description":"<a a=\"\\u000B\">",
+"input":"<a a=\"\u000B\">",
+"output":["ParseError", ["StartTag", "a", {"a":"\u000B"}]]},
+
+{"description":"<a a=\"\\u000C\">",
+"input":"<a a=\"\u000C\">",
+"output":[["StartTag", "a", {"a":"\u000C"}]]},
+
+{"description":"<a a=\" \">",
+"input":"<a a=\" \">",
+"output":[["StartTag", "a", {"a":" "}]]},
+
+{"description":"<a a=\"!\">",
+"input":"<a a=\"!\">",
+"output":[["StartTag", "a", {"a":"!"}]]},
+
+{"description":"<a a=\"\">",
+"input":"<a a=\"\">",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=\"#\">",
+"input":"<a a=\"#\">",
+"output":[["StartTag", "a", {"a":"#"}]]},
+
+{"description":"<a a=\"%\">",
+"input":"<a a=\"%\">",
+"output":[["StartTag", "a", {"a":"%"}]]},
+
+{"description":"<a a=\"&\">",
+"input":"<a a=\"&\">",
+"output":[["StartTag", "a", {"a":"&"}]]},
+
+{"description":"<a a=\"'\">",
+"input":"<a a=\"'\">",
+"output":[["StartTag", "a", {"a":"'"}]]},
+
+{"description":"<a a=\"-\">",
+"input":"<a a=\"-\">",
+"output":[["StartTag", "a", {"a":"-"}]]},
+
+{"description":"<a a=\"/\">",
+"input":"<a a=\"/\">",
+"output":[["StartTag", "a", {"a":"/"}]]},
+
+{"description":"<a a=\"0\">",
+"input":"<a a=\"0\">",
+"output":[["StartTag", "a", {"a":"0"}]]},
+
+{"description":"<a a=\"1\">",
+"input":"<a a=\"1\">",
+"output":[["StartTag", "a", {"a":"1"}]]},
+
+{"description":"<a a=\"9\">",
+"input":"<a a=\"9\">",
+"output":[["StartTag", "a", {"a":"9"}]]},
+
+{"description":"<a a=\"<\">",
+"input":"<a a=\"<\">",
+"output":[["StartTag", "a", {"a":"<"}]]},
+
+{"description":"<a a=\"=\">",
+"input":"<a a=\"=\">",
+"output":[["StartTag", "a", {"a":"="}]]},
+
+{"description":"<a a=\">\">",
+"input":"<a a=\">\">",
+"output":[["StartTag", "a", {"a":">"}]]},
+
+{"description":"<a a=\"?\">",
+"input":"<a a=\"?\">",
+"output":[["StartTag", "a", {"a":"?"}]]},
+
+{"description":"<a a=\"@\">",
+"input":"<a a=\"@\">",
+"output":[["StartTag", "a", {"a":"@"}]]},
+
+{"description":"<a a=\"A\">",
+"input":"<a a=\"A\">",
+"output":[["StartTag", "a", {"a":"A"}]]},
+
+{"description":"<a a=\"B\">",
+"input":"<a a=\"B\">",
+"output":[["StartTag", "a", {"a":"B"}]]},
+
+{"description":"<a a=\"Y\">",
+"input":"<a a=\"Y\">",
+"output":[["StartTag", "a", {"a":"Y"}]]},
+
+{"description":"<a a=\"Z\">",
+"input":"<a a=\"Z\">",
+"output":[["StartTag", "a", {"a":"Z"}]]},
+
+{"description":"<a a=\"`\">",
+"input":"<a a=\"`\">",
+"output":[["StartTag", "a", {"a":"`"}]]},
+
+{"description":"<a a=\"a\">",
+"input":"<a a=\"a\">",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=\"b\">",
+"input":"<a a=\"b\">",
+"output":[["StartTag", "a", {"a":"b"}]]},
+
+{"description":"<a a=\"y\">",
+"input":"<a a=\"y\">",
+"output":[["StartTag", "a", {"a":"y"}]]},
+
+{"description":"<a a=\"z\">",
+"input":"<a a=\"z\">",
+"output":[["StartTag", "a", {"a":"z"}]]},
+
+{"description":"<a a=\"{\">",
+"input":"<a a=\"{\">",
+"output":[["StartTag", "a", {"a":"{"}]]},
+
+{"description":"<a a=\"\\uDBC0\\uDC00\">",
+"input":"<a a=\"\uDBC0\uDC00\">",
+"output":[["StartTag", "a", {"a":"\uDBC0\uDC00"}]]},
+
+{"description":"<a a=#>",
+"input":"<a a=#>",
+"output":[["StartTag", "a", {"a":"#"}]]},
+
+{"description":"<a a=%>",
+"input":"<a a=%>",
+"output":[["StartTag", "a", {"a":"%"}]]},
+
+{"description":"<a a=&>",
+"input":"<a a=&>",
+"output":[["StartTag", "a", {"a":"&"}]]},
+
+{"description":"<a a=''>",
+"input":"<a a=''>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a='\\u0000'>",
+"input":"<a a='\u0000'>",
+"output":["ParseError", ["StartTag", "a", {"a":"\uFFFD"}]]},
+
+{"description":"<a a='\\u0009'>",
+"input":"<a a='\u0009'>",
+"output":[["StartTag", "a", {"a":"\u0009"}]]},
+
+{"description":"<a a='\\u000A'>",
+"input":"<a a='\u000A'>",
+"output":[["StartTag", "a", {"a":"\u000A"}]]},
+
+{"description":"<a a='\\u000B'>",
+"input":"<a a='\u000B'>",
+"output":["ParseError", ["StartTag", "a", {"a":"\u000B"}]]},
+
+{"description":"<a a='\\u000C'>",
+"input":"<a a='\u000C'>",
+"output":[["StartTag", "a", {"a":"\u000C"}]]},
+
+{"description":"<a a=' '>",
+"input":"<a a=' '>",
+"output":[["StartTag", "a", {"a":" "}]]},
+
+{"description":"<a a='!'>",
+"input":"<a a='!'>",
+"output":[["StartTag", "a", {"a":"!"}]]},
+
+{"description":"<a a='\"'>",
+"input":"<a a='\"'>",
+"output":[["StartTag", "a", {"a":"\""}]]},
+
+{"description":"<a a='%'>",
+"input":"<a a='%'>",
+"output":[["StartTag", "a", {"a":"%"}]]},
+
+{"description":"<a a='&'>",
+"input":"<a a='&'>",
+"output":[["StartTag", "a", {"a":"&"}]]},
+
+{"description":"<a a=''>",
+"input":"<a a=''>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u0000>",
+"input":"<a a=''\u0000>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\uFFFD":""}]]},
+
+{"description":"<a a=''\\u0008>",
+"input":"<a a=''\u0008>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\u0008":""}]]},
+
+{"description":"<a a=''\\u0009>",
+"input":"<a a=''\u0009>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u000A>",
+"input":"<a a=''\u000A>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u000B>",
+"input":"<a a=''\u000B>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\u000B":""}]]},
+
+{"description":"<a a=''\\u000C>",
+"input":"<a a=''\u000C>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u000D>",
+"input":"<a a=''\u000D>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''\\u001F>",
+"input":"<a a=''\u001F>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\u001F":""}]]},
+
+{"description":"<a a='' >",
+"input":"<a a='' >",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''!>",
+"input":"<a a=''!>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "!":""}]]},
+
+{"description":"<a a=''\">",
+"input":"<a a=''\">",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "\"":""}]]},
+
+{"description":"<a a=''&>",
+"input":"<a a=''&>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "&":""}]]},
+
+{"description":"<a a='''>",
+"input":"<a a='''>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "'":""}]]},
+
+{"description":"<a a=''->",
+"input":"<a a=''->",
+"output":["ParseError", ["StartTag", "a", {"a":"", "-":""}]]},
+
+{"description":"<a a=''.>",
+"input":"<a a=''.>",
+"output":["ParseError", ["StartTag", "a", {"a":"", ".":""}]]},
+
+{"description":"<a a=''/>",
+"input":"<a a=''/>",
+"output":[["StartTag", "a", {"a":""}, true]]},
+
+{"description":"<a a=''0>",
+"input":"<a a=''0>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "0":""}]]},
+
+{"description":"<a a=''1>",
+"input":"<a a=''1>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "1":""}]]},
+
+{"description":"<a a=''9>",
+"input":"<a a=''9>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "9":""}]]},
+
+{"description":"<a a=''<>",
+"input":"<a a=''<>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "<":""}]]},
+
+{"description":"<a a=''=>",
+"input":"<a a=''=>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":"", "=":""}]]},
+
+{"description":"<a a=''>",
+"input":"<a a=''>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''?>",
+"input":"<a a=''?>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "?":""}]]},
+
+{"description":"<a a=''@>",
+"input":"<a a=''@>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "@":""}]]},
+
+{"description":"<a a=''A>",
+"input":"<a a=''A>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''B>",
+"input":"<a a=''B>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "b":""}]]},
+
+{"description":"<a a=''Y>",
+"input":"<a a=''Y>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "y":""}]]},
+
+{"description":"<a a=''Z>",
+"input":"<a a=''Z>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "z":""}]]},
+
+{"description":"<a a=''`>",
+"input":"<a a=''`>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "`":""}]]},
+
+{"description":"<a a=''a>",
+"input":"<a a=''a>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=''b>",
+"input":"<a a=''b>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "b":""}]]},
+
+{"description":"<a a=''y>",
+"input":"<a a=''y>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "y":""}]]},
+
+{"description":"<a a=''z>",
+"input":"<a a=''z>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "z":""}]]},
+
+{"description":"<a a=''{>",
+"input":"<a a=''{>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "{":""}]]},
+
+{"description":"<a a=''\\uDBC0\\uDC00>",
+"input":"<a a=''\uDBC0\uDC00>",
+"output":["ParseError", ["StartTag", "a", {"a":"", "\uDBC0\uDC00":""}]]},
+
+{"description":"<a a='('>",
+"input":"<a a='('>",
+"output":[["StartTag", "a", {"a":"("}]]},
+
+{"description":"<a a='-'>",
+"input":"<a a='-'>",
+"output":[["StartTag", "a", {"a":"-"}]]},
+
+{"description":"<a a='/'>",
+"input":"<a a='/'>",
+"output":[["StartTag", "a", {"a":"/"}]]},
+
+{"description":"<a a='0'>",
+"input":"<a a='0'>",
+"output":[["StartTag", "a", {"a":"0"}]]},
+
+{"description":"<a a='1'>",
+"input":"<a a='1'>",
+"output":[["StartTag", "a", {"a":"1"}]]},
+
+{"description":"<a a='9'>",
+"input":"<a a='9'>",
+"output":[["StartTag", "a", {"a":"9"}]]},
+
+{"description":"<a a='<'>",
+"input":"<a a='<'>",
+"output":[["StartTag", "a", {"a":"<"}]]},
+
+{"description":"<a a='='>",
+"input":"<a a='='>",
+"output":[["StartTag", "a", {"a":"="}]]},
+
+{"description":"<a a='>'>",
+"input":"<a a='>'>",
+"output":[["StartTag", "a", {"a":">"}]]},
+
+{"description":"<a a='?'>",
+"input":"<a a='?'>",
+"output":[["StartTag", "a", {"a":"?"}]]},
+
+{"description":"<a a='@'>",
+"input":"<a a='@'>",
+"output":[["StartTag", "a", {"a":"@"}]]},
+
+{"description":"<a a='A'>",
+"input":"<a a='A'>",
+"output":[["StartTag", "a", {"a":"A"}]]},
+
+{"description":"<a a='B'>",
+"input":"<a a='B'>",
+"output":[["StartTag", "a", {"a":"B"}]]},
+
+{"description":"<a a='Y'>",
+"input":"<a a='Y'>",
+"output":[["StartTag", "a", {"a":"Y"}]]},
+
+{"description":"<a a='Z'>",
+"input":"<a a='Z'>",
+"output":[["StartTag", "a", {"a":"Z"}]]},
+
+{"description":"<a a='`'>",
+"input":"<a a='`'>",
+"output":[["StartTag", "a", {"a":"`"}]]},
+
+{"description":"<a a='a'>",
+"input":"<a a='a'>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a='b'>",
+"input":"<a a='b'>",
+"output":[["StartTag", "a", {"a":"b"}]]},
+
+{"description":"<a a='y'>",
+"input":"<a a='y'>",
+"output":[["StartTag", "a", {"a":"y"}]]},
+
+{"description":"<a a='z'>",
+"input":"<a a='z'>",
+"output":[["StartTag", "a", {"a":"z"}]]},
+
+{"description":"<a a='{'>",
+"input":"<a a='{'>",
+"output":[["StartTag", "a", {"a":"{"}]]},
+
+{"description":"<a a='\\uDBC0\\uDC00'>",
+"input":"<a a='\uDBC0\uDC00'>",
+"output":[["StartTag", "a", {"a":"\uDBC0\uDC00"}]]},
+
+{"description":"<a a=(>",
+"input":"<a a=(>",
+"output":[["StartTag", "a", {"a":"("}]]},
+
+{"description":"<a a=->",
+"input":"<a a=->",
+"output":[["StartTag", "a", {"a":"-"}]]},
+
+{"description":"<a a=/>",
+"input":"<a a=/>",
+"output":[["StartTag", "a", {"a":"/"}]]},
+
+{"description":"<a a=0>",
+"input":"<a a=0>",
+"output":[["StartTag", "a", {"a":"0"}]]},
+
+{"description":"<a a=1>",
+"input":"<a a=1>",
+"output":[["StartTag", "a", {"a":"1"}]]},
+
+{"description":"<a a=9>",
+"input":"<a a=9>",
+"output":[["StartTag", "a", {"a":"9"}]]},
+
+{"description":"<a a=<>",
+"input":"<a a=<>",
+"output":["ParseError", ["StartTag", "a", {"a":"<"}]]},
+
+{"description":"<a a==>",
+"input":"<a a==>",
+"output":["ParseError", ["StartTag", "a", {"a":"="}]]},
+
+{"description":"<a a=>",
+"input":"<a a=>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a=?>",
+"input":"<a a=?>",
+"output":[["StartTag", "a", {"a":"?"}]]},
+
+{"description":"<a a=@>",
+"input":"<a a=@>",
+"output":[["StartTag", "a", {"a":"@"}]]},
+
+{"description":"<a a=A>",
+"input":"<a a=A>",
+"output":[["StartTag", "a", {"a":"A"}]]},
+
+{"description":"<a a=B>",
+"input":"<a a=B>",
+"output":[["StartTag", "a", {"a":"B"}]]},
+
+{"description":"<a a=Y>",
+"input":"<a a=Y>",
+"output":[["StartTag", "a", {"a":"Y"}]]},
+
+{"description":"<a a=Z>",
+"input":"<a a=Z>",
+"output":[["StartTag", "a", {"a":"Z"}]]},
+
+{"description":"<a a=`>",
+"input":"<a a=`>",
+"output":["ParseError", ["StartTag", "a", {"a":"`"}]]},
+
+{"description":"<a a=a>",
+"input":"<a a=a>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u0000>",
+"input":"<a a=a\u0000>",
+"output":["ParseError", ["StartTag", "a", {"a":"a\uFFFD"}]]},
+
+{"description":"<a a=a\\u0008>",
+"input":"<a a=a\u0008>",
+"output":["ParseError", ["StartTag", "a", {"a":"a\u0008"}]]},
+
+{"description":"<a a=a\\u0009>",
+"input":"<a a=a\u0009>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u000A>",
+"input":"<a a=a\u000A>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u000B>",
+"input":"<a a=a\u000B>",
+"output":["ParseError", ["StartTag", "a", {"a":"a\u000B"}]]},
+
+{"description":"<a a=a\\u000C>",
+"input":"<a a=a\u000C>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u000D>",
+"input":"<a a=a\u000D>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a\\u001F>",
+"input":"<a a=a\u001F>",
+"output":["ParseError", ["StartTag", "a", {"a":"a\u001F"}]]},
+
+{"description":"<a a=a >",
+"input":"<a a=a >",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a!>",
+"input":"<a a=a!>",
+"output":[["StartTag", "a", {"a":"a!"}]]},
+
+{"description":"<a a=a\">",
+"input":"<a a=a\">",
+"output":["ParseError", ["StartTag", "a", {"a":"a\""}]]},
+
+{"description":"<a a=a#>",
+"input":"<a a=a#>",
+"output":[["StartTag", "a", {"a":"a#"}]]},
+
+{"description":"<a a=a%>",
+"input":"<a a=a%>",
+"output":[["StartTag", "a", {"a":"a%"}]]},
+
+{"description":"<a a=a&>",
+"input":"<a a=a&>",
+"output":[["StartTag", "a", {"a":"a&"}]]},
+
+{"description":"<a a=a'>",
+"input":"<a a=a'>",
+"output":["ParseError", ["StartTag", "a", {"a":"a'"}]]},
+
+{"description":"<a a=a(>",
+"input":"<a a=a(>",
+"output":[["StartTag", "a", {"a":"a("}]]},
+
+{"description":"<a a=a->",
+"input":"<a a=a->",
+"output":[["StartTag", "a", {"a":"a-"}]]},
+
+{"description":"<a a=a/>",
+"input":"<a a=a/>",
+"output":[["StartTag", "a", {"a":"a/"}]]},
+
+{"description":"<a a=a0>",
+"input":"<a a=a0>",
+"output":[["StartTag", "a", {"a":"a0"}]]},
+
+{"description":"<a a=a1>",
+"input":"<a a=a1>",
+"output":[["StartTag", "a", {"a":"a1"}]]},
+
+{"description":"<a a=a9>",
+"input":"<a a=a9>",
+"output":[["StartTag", "a", {"a":"a9"}]]},
+
+{"description":"<a a=a<>",
+"input":"<a a=a<>",
+"output":["ParseError", ["StartTag", "a", {"a":"a<"}]]},
+
+{"description":"<a a=a=>",
+"input":"<a a=a=>",
+"output":["ParseError", ["StartTag", "a", {"a":"a="}]]},
+
+{"description":"<a a=a>",
+"input":"<a a=a>",
+"output":[["StartTag", "a", {"a":"a"}]]},
+
+{"description":"<a a=a?>",
+"input":"<a a=a?>",
+"output":[["StartTag", "a", {"a":"a?"}]]},
+
+{"description":"<a a=a@>",
+"input":"<a a=a@>",
+"output":[["StartTag", "a", {"a":"a@"}]]},
+
+{"description":"<a a=aA>",
+"input":"<a a=aA>",
+"output":[["StartTag", "a", {"a":"aA"}]]},
+
+{"description":"<a a=aB>",
+"input":"<a a=aB>",
+"output":[["StartTag", "a", {"a":"aB"}]]},
+
+{"description":"<a a=aY>",
+"input":"<a a=aY>",
+"output":[["StartTag", "a", {"a":"aY"}]]},
+
+{"description":"<a a=aZ>",
+"input":"<a a=aZ>",
+"output":[["StartTag", "a", {"a":"aZ"}]]},
+
+{"description":"<a a=a`>",
+"input":"<a a=a`>",
+"output":["ParseError", ["StartTag", "a", {"a":"a`"}]]},
+
+{"description":"<a a=aa>",
+"input":"<a a=aa>",
+"output":[["StartTag", "a", {"a":"aa"}]]},
+
+{"description":"<a a=ab>",
+"input":"<a a=ab>",
+"output":[["StartTag", "a", {"a":"ab"}]]},
+
+{"description":"<a a=ay>",
+"input":"<a a=ay>",
+"output":[["StartTag", "a", {"a":"ay"}]]},
+
+{"description":"<a a=az>",
+"input":"<a a=az>",
+"output":[["StartTag", "a", {"a":"az"}]]},
+
+{"description":"<a a=a{>",
+"input":"<a a=a{>",
+"output":[["StartTag", "a", {"a":"a{"}]]},
+
+{"description":"<a a=a\\uDBC0\\uDC00>",
+"input":"<a a=a\uDBC0\uDC00>",
+"output":[["StartTag", "a", {"a":"a\uDBC0\uDC00"}]]},
+
+{"description":"<a a=b>",
+"input":"<a a=b>",
+"output":[["StartTag", "a", {"a":"b"}]]},
+
+{"description":"<a a=y>",
+"input":"<a a=y>",
+"output":[["StartTag", "a", {"a":"y"}]]},
+
+{"description":"<a a=z>",
+"input":"<a a=z>",
+"output":[["StartTag", "a", {"a":"z"}]]},
+
+{"description":"<a a={>",
+"input":"<a a={>",
+"output":[["StartTag", "a", {"a":"{"}]]},
+
+{"description":"<a a=\\uDBC0\\uDC00>",
+"input":"<a a=\uDBC0\uDC00>",
+"output":[["StartTag", "a", {"a":"\uDBC0\uDC00"}]]},
+
+{"description":"<a a>",
+"input":"<a a>",
+"output":[["StartTag", "a", {"a":""}]]},
+
+{"description":"<a a?>",
+"input":"<a a?>",
+"output":[["StartTag", "a", {"a?":""}]]},
+
+{"description":"<a a@>",
+"input":"<a a@>",
+"output":[["StartTag", "a", {"a@":""}]]},
+
+{"description":"<a aA>",
+"input":"<a aA>",
+"output":[["StartTag", "a", {"aa":""}]]},
+
+{"description":"<a aB>",
+"input":"<a aB>",
+"output":[["StartTag", "a", {"ab":""}]]},
+
+{"description":"<a aY>",
+"input":"<a aY>",
+"output":[["StartTag", "a", {"ay":""}]]},
+
+{"description":"<a aZ>",
+"input":"<a aZ>",
+"output":[["StartTag", "a", {"az":""}]]},
+
+{"description":"<a a[>",
+"input":"<a a[>",
+"output":[["StartTag", "a", {"a[":""}]]},
+
+{"description":"<a a`>",
+"input":"<a a`>",
+"output":[["StartTag", "a", {"a`":""}]]},
+
+{"description":"<a aa>",
+"input":"<a aa>",
+"output":[["StartTag", "a", {"aa":""}]]},
+
+{"description":"<a ab>",
+"input":"<a ab>",
+"output":[["StartTag", "a", {"ab":""}]]},
+
+{"description":"<a ay>",
+"input":"<a ay>",
+"output":[["StartTag", "a", {"ay":""}]]},
+
+{"description":"<a az>",
+"input":"<a az>",
+"output":[["StartTag", "a", {"az":""}]]},
+
+{"description":"<a a{>",
+"input":"<a a{>",
+"output":[["StartTag", "a", {"a{":""}]]},
+
+{"description":"<a a\\uDBC0\\uDC00>",
+"input":"<a a\uDBC0\uDC00>",
+"output":[["StartTag", "a", {"a\uDBC0\uDC00":""}]]},
+
+{"description":"<a b>",
+"input":"<a b>",
+"output":[["StartTag", "a", {"b":""}]]},
+
+{"description":"<a y>",
+"input":"<a y>",
+"output":[["StartTag", "a", {"y":""}]]},
+
+{"description":"<a z>",
+"input":"<a z>",
+"output":[["StartTag", "a", {"z":""}]]},
+
+{"description":"<a {>",
+"input":"<a {>",
+"output":[["StartTag", "a", {"{":""}]]},
+
+{"description":"<a \\uDBC0\\uDC00>",
+"input":"<a \uDBC0\uDC00>",
+"output":[["StartTag", "a", {"\uDBC0\uDC00":""}]]},
+
+{"description":"<a!>",
+"input":"<a!>",
+"output":[["StartTag", "a!", {}]]},
+
+{"description":"<a\">",
+"input":"<a\">",
+"output":[["StartTag", "a\"", {}]]},
+
+{"description":"<a&>",
+"input":"<a&>",
+"output":[["StartTag", "a&", {}]]},
+
+{"description":"<a'>",
+"input":"<a'>",
+"output":[["StartTag", "a'", {}]]},
+
+{"description":"<a->",
+"input":"<a->",
+"output":[["StartTag", "a-", {}]]},
+
+{"description":"<a.>",
+"input":"<a.>",
+"output":[["StartTag", "a.", {}]]},
+
+{"description":"<a/>",
+"input":"<a/>",
+"output":[["StartTag", "a", {}, true]]},
+
+{"description":"<a/\\u0000>",
+"input":"<a/\u0000>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"\uFFFD":""}]]},
+
+{"description":"<a/\\u0009>",
+"input":"<a/\u0009>",
+"output":["ParseError", ["StartTag", "a", {}]]},
+
+{"description":"<a/\\u000A>",
+"input":"<a/\u000A>",
+"output":["ParseError", ["StartTag", "a", {}]]},
+
+{"description":"<a/\\u000B>",
+"input":"<a/\u000B>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"\u000B":""}]]},
+
+{"description":"<a/\\u000C>",
+"input":"<a/\u000C>",
+"output":["ParseError", ["StartTag", "a", {}]]},
+
+{"description":"<a/ >",
+"input":"<a/ >",
+"output":["ParseError", ["StartTag", "a", {}]]},
+
+{"description":"<a/!>",
+"input":"<a/!>",
+"output":["ParseError", ["StartTag", "a", {"!":""}]]},
+
+{"description":"<a/\">",
+"input":"<a/\">",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"\"":""}]]},
+
+{"description":"<a/&>",
+"input":"<a/&>",
+"output":["ParseError", ["StartTag", "a", {"&":""}]]},
+
+{"description":"<a/'>",
+"input":"<a/'>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"'":""}]]},
+
+{"description":"<a/->",
+"input":"<a/->",
+"output":["ParseError", ["StartTag", "a", {"-":""}]]},
+
+{"description":"<a//>",
+"input":"<a//>",
+"output":["ParseError", ["StartTag", "a", {}, true]]},
+
+{"description":"<a/0>",
+"input":"<a/0>",
+"output":["ParseError", ["StartTag", "a", {"0":""}]]},
+
+{"description":"<a/1>",
+"input":"<a/1>",
+"output":["ParseError", ["StartTag", "a", {"1":""}]]},
+
+{"description":"<a/9>",
+"input":"<a/9>",
+"output":["ParseError", ["StartTag", "a", {"9":""}]]},
+
+{"description":"<a/<>",
+"input":"<a/<>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"<":""}]]},
+
+{"description":"<a/=>",
+"input":"<a/=>",
+"output":["ParseError", "ParseError", ["StartTag", "a", {"=":""}]]},
+
+{"description":"<a/>",
+"input":"<a/>",
+"output":[["StartTag", "a", {}, true]]},
+
+{"description":"<a/?>",
+"input":"<a/?>",
+"output":["ParseError", ["StartTag", "a", {"?":""}]]},
+
+{"description":"<a/@>",
+"input":"<a/@>",
+"output":["ParseError", ["StartTag", "a", {"@":""}]]},
+
+{"description":"<a/A>",
+"input":"<a/A>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a/B>",
+"input":"<a/B>",
+"output":["ParseError", ["StartTag", "a", {"b":""}]]},
+
+{"description":"<a/Y>",
+"input":"<a/Y>",
+"output":["ParseError", ["StartTag", "a", {"y":""}]]},
+
+{"description":"<a/Z>",
+"input":"<a/Z>",
+"output":["ParseError", ["StartTag", "a", {"z":""}]]},
+
+{"description":"<a/`>",
+"input":"<a/`>",
+"output":["ParseError", ["StartTag", "a", {"`":""}]]},
+
+{"description":"<a/a>",
+"input":"<a/a>",
+"output":["ParseError", ["StartTag", "a", {"a":""}]]},
+
+{"description":"<a/b>",
+"input":"<a/b>",
+"output":["ParseError", ["StartTag", "a", {"b":""}]]},
+
+{"description":"<a/y>",
+"input":"<a/y>",
+"output":["ParseError", ["StartTag", "a", {"y":""}]]},
+
+{"description":"<a/z>",
+"input":"<a/z>",
+"output":["ParseError", ["StartTag", "a", {"z":""}]]},
+
+{"description":"<a/{>",
+"input":"<a/{>",
+"output":["ParseError", ["StartTag", "a", {"{":""}]]},
+
+{"description":"<a/\\uDBC0\\uDC00>",
+"input":"<a/\uDBC0\uDC00>",
+"output":["ParseError", ["StartTag", "a", {"\uDBC0\uDC00":""}]]},
+
+{"description":"<a0>",
+"input":"<a0>",
+"output":[["StartTag", "a0", {}]]},
+
+{"description":"<a1>",
+"input":"<a1>",
+"output":[["StartTag", "a1", {}]]},
+
+{"description":"<a9>",
+"input":"<a9>",
+"output":[["StartTag", "a9", {}]]},
+
+{"description":"<a<>",
+"input":"<a<>",
+"output":[["StartTag", "a<", {}]]},
+
+{"description":"<a=>",
+"input":"<a=>",
+"output":[["StartTag", "a=", {}]]},
+
+{"description":"<a>",
+"input":"<a>",
+"output":[["StartTag", "a", {}]]},
+
+{"description":"<a?>",
+"input":"<a?>",
+"output":[["StartTag", "a?", {}]]},
+
+{"description":"<a@>",
+"input":"<a@>",
+"output":[["StartTag", "a@", {}]]},
+
+{"description":"<aA>",
+"input":"<aA>",
+"output":[["StartTag", "aa", {}]]},
+
+{"description":"<aB>",
+"input":"<aB>",
+"output":[["StartTag", "ab", {}]]},
+
+{"description":"<aY>",
+"input":"<aY>",
+"output":[["StartTag", "ay", {}]]},
+
+{"description":"<aZ>",
+"input":"<aZ>",
+"output":[["StartTag", "az", {}]]},
+
+{"description":"<a[>",
+"input":"<a[>",
+"output":[["StartTag", "a[", {}]]},
+
+{"description":"<a`>",
+"input":"<a`>",
+"output":[["StartTag", "a`", {}]]},
+
+{"description":"<aa>",
+"input":"<aa>",
+"output":[["StartTag", "aa", {}]]},
+
+{"description":"<ab>",
+"input":"<ab>",
+"output":[["StartTag", "ab", {}]]},
+
+{"description":"<ay>",
+"input":"<ay>",
+"output":[["StartTag", "ay", {}]]},
+
+{"description":"<az>",
+"input":"<az>",
+"output":[["StartTag", "az", {}]]},
+
+{"description":"<a{>",
+"input":"<a{>",
+"output":[["StartTag", "a{", {}]]},
+
+{"description":"<a\\uDBC0\\uDC00>",
+"input":"<a\uDBC0\uDC00>",
+"output":[["StartTag", "a\uDBC0\uDC00", {}]]},
+
+{"description":"<b>",
+"input":"<b>",
+"output":[["StartTag", "b", {}]]},
+
+{"description":"<y>",
+"input":"<y>",
+"output":[["StartTag", "y", {}]]},
+
+{"description":"<z>",
+"input":"<z>",
+"output":[["StartTag", "z", {}]]},
+
+{"description":"<{",
+"input":"<{",
+"output":["ParseError", ["Character", "<{"]]},
+
+{"description":"<\\uDBC0\\uDC00",
+"input":"<\uDBC0\uDC00",
+"output":["ParseError", ["Character", "<\uDBC0\uDC00"]]},
+
+{"description":"=",
+"input":"=",
+"output":[["Character", "="]]},
+
+{"description":">",
+"input":">",
+"output":[["Character", ">"]]},
+
+{"description":"?",
+"input":"?",
+"output":[["Character", "?"]]},
+
+{"description":"@",
+"input":"@",
+"output":[["Character", "@"]]},
+
+{"description":"A",
+"input":"A",
+"output":[["Character", "A"]]},
+
+{"description":"B",
+"input":"B",
+"output":[["Character", "B"]]},
+
+{"description":"Y",
+"input":"Y",
+"output":[["Character", "Y"]]},
+
+{"description":"Z",
+"input":"Z",
+"output":[["Character", "Z"]]},
+
+{"description":"`",
+"input":"`",
+"output":[["Character", "`"]]},
+
+{"description":"a",
+"input":"a",
+"output":[["Character", "a"]]},
+
+{"description":"b",
+"input":"b",
+"output":[["Character", "b"]]},
+
+{"description":"y",
+"input":"y",
+"output":[["Character", "y"]]},
+
+{"description":"z",
+"input":"z",
+"output":[["Character", "z"]]},
+
+{"description":"{",
+"input":"{",
+"output":[["Character", "{"]]},
+
+{"description":"\\uDBC0\\uDC00",
+"input":"\uDBC0\uDC00",
+"output":[["Character", "\uDBC0\uDC00"]]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/test4.test b/pkgs/html/test/data/tokenizer/test4.test
new file mode 100644
index 0000000..c0f3b2b
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/test4.test
@@ -0,0 +1,336 @@
+{"tests": [
+
+{"description":"< in attribute name",
+"input":"<z/0 <>",
+"output":["ParseError", "ParseError", ["StartTag", "z", {"0": "", "<": ""}]]},
+
+{"description":"< in attribute value",
+"input":"<z x=<>",
+"output":["ParseError", ["StartTag", "z", {"x": "<"}]]},
+
+{"description":"= in unquoted attribute value",
+"input":"<z z=z=z>",
+"output":["ParseError", ["StartTag", "z", {"z": "z=z"}]]},
+
+{"description":"= attribute",
+"input":"<z =>",
+"output":["ParseError", ["StartTag", "z", {"=": ""}]]},
+
+{"description":"== attribute",
+"input":"<z ==>",
+"output":["ParseError", "ParseError", ["StartTag", "z", {"=": ""}]]},
+
+{"description":"=== attribute",
+"input":"<z ===>",
+"output":["ParseError", "ParseError", ["StartTag", "z", {"=": "="}]]},
+
+{"description":"==== attribute",
+"input":"<z ====>",
+"output":["ParseError", "ParseError", "ParseError", ["StartTag", "z", {"=": "=="}]]},
+
+{"description":"Allowed \" after ampersand in attribute value",
+"input":"<z z=\"&\">",
+"output":[["StartTag", "z", {"z": "&"}]]},
+
+{"description":"Non-allowed ' after ampersand in attribute value",
+"input":"<z z=\"&'\">",
+"output":["ParseError", ["StartTag", "z", {"z": "&'"}]]},
+
+{"description":"Allowed ' after ampersand in attribute value",
+"input":"<z z='&'>",
+"output":[["StartTag", "z", {"z": "&"}]]},
+
+{"description":"Non-allowed \" after ampersand in attribute value",
+"input":"<z z='&\"'>",
+"output":["ParseError", ["StartTag", "z", {"z": "&\""}]]},
+
+{"description":"Text after bogus character reference",
+"input":"<z z='&xlink_xmlns;'>bar<z>",
+"output":["ParseError",["StartTag","z",{"z":"&xlink_xmlns;"}],["Character","bar"],["StartTag","z",{}]]},
+
+{"description":"Text after hex character reference",
+"input":"<z z='  foo'>bar<z>",
+"output":[["StartTag","z",{"z":" foo"}],["Character","bar"],["StartTag","z",{}]]},
+
+{"description":"Attribute name starting with \"",
+"input":"<foo \"='bar'>",
+"output":["ParseError", ["StartTag", "foo", {"\"": "bar"}]]},
+
+{"description":"Attribute name starting with '",
+"input":"<foo '='bar'>",
+"output":["ParseError", ["StartTag", "foo", {"'": "bar"}]]},
+
+{"description":"Attribute name containing \"",
+"input":"<foo a\"b='bar'>",
+"output":["ParseError", ["StartTag", "foo", {"a\"b": "bar"}]]},
+
+{"description":"Attribute name containing '",
+"input":"<foo a'b='bar'>",
+"output":["ParseError", ["StartTag", "foo", {"a'b": "bar"}]]},
+
+{"description":"Unquoted attribute value containing '",
+"input":"<foo a=b'c>",
+"output":["ParseError", ["StartTag", "foo", {"a": "b'c"}]]},
+
+{"description":"Unquoted attribute value containing \"",
+"input":"<foo a=b\"c>",
+"output":["ParseError", ["StartTag", "foo", {"a": "b\"c"}]]},
+
+{"description":"Double-quoted attribute value not followed by whitespace",
+"input":"<foo a=\"b\"c>",
+"output":["ParseError", ["StartTag", "foo", {"a": "b", "c": ""}]]},
+
+{"description":"Single-quoted attribute value not followed by whitespace",
+"input":"<foo a='b'c>",
+"output":["ParseError", ["StartTag", "foo", {"a": "b", "c": ""}]]},
+
+{"description":"Quoted attribute followed by permitted /",
+"input":"<br a='b'/>",
+"output":[["StartTag","br",{"a":"b"},true]]},
+
+{"description":"Quoted attribute followed by non-permitted /",
+"input":"<bar a='b'/>",
+"output":[["StartTag","bar",{"a":"b"},true]]},
+
+{"description":"CR EOF after doctype name",
+"input":"<!doctype html \r",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"CR EOF in tag name",
+"input":"<z\r",
+"output":["ParseError"]},
+
+{"description":"Slash EOF in tag name",
+"input":"<z/",
+"output":["ParseError"]},
+
+{"description":"Zero hex numeric entity",
+"input":"�",
+"output":["ParseError", "ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Zero decimal numeric entity",
+"input":"�",
+"output":["ParseError", "ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Zero-prefixed hex numeric entity",
+"input":"A",
+"output":[["Character", "A"]]},
+
+{"description":"Zero-prefixed decimal numeric entity",
+"input":"A",
+"output":[["Character", "A"]]},
+
+{"description":"Empty hex numeric entities",
+"input":"&#x &#X ",
+"output":["ParseError", ["Character", "&#x "], "ParseError", ["Character", "&#X "]]},
+
+{"description":"Empty decimal numeric entities",
+"input":"&# &#; ",
+"output":["ParseError", ["Character", "&# "], "ParseError", ["Character", "&#; "]]},
+
+{"description":"Non-BMP numeric entity",
+"input":"𐀀",
+"output":[["Character", "\uD800\uDC00"]]},
+
+{"description":"Maximum non-BMP numeric entity",
+"input":"",
+"output":["ParseError", ["Character", "\uDBFF\uDFFF"]]},
+
+{"description":"Above maximum numeric entity",
+"input":"�",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"32-bit hex numeric entity",
+"input":"�",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"33-bit hex numeric entity",
+"input":"�",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"33-bit decimal numeric entity",
+"input":"�",
+"output":["ParseError", ["Character", "\uFFFD"]]},
+
+{"description":"Surrogate code point edge cases",
+"input":"퟿����",
+"output":[["Character", "\uD7FF"], "ParseError", ["Character", "\uFFFD"], "ParseError", ["Character", "\uFFFD"], "ParseError", ["Character", "\uFFFD"], "ParseError", ["Character", "\uFFFD\uE000"]]},
+
+{"description":"Uppercase start tag name",
+"input":"<X>",
+"output":[["StartTag", "x", {}]]},
+
+{"description":"Uppercase end tag name",
+"input":"</X>",
+"output":[["EndTag", "x"]]},
+
+{"description":"Uppercase attribute name",
+"input":"<x X>",
+"output":[["StartTag", "x", { "x":"" }]]},
+
+{"description":"Tag/attribute name case edge values",
+"input":"<x@AZ[`az{ @AZ[`az{>",
+"output":[["StartTag", "x@az[`az{", { "@az[`az{":"" }]]},
+
+{"description":"Duplicate different-case attributes",
+"input":"<x x=1 x=2 X=3>",
+"output":["ParseError", "ParseError", ["StartTag", "x", { "x":"1" }]]},
+
+{"description":"Uppercase close tag attributes",
+"input":"</x X>",
+"output":["ParseError", ["EndTag", "x"]]},
+
+{"description":"Duplicate close tag attributes",
+"input":"</x x x>",
+"output":["ParseError", "ParseError", ["EndTag", "x"]]},
+
+{"description":"Permitted slash",
+"input":"<br/>",
+"output":[["StartTag","br",{},true]]},
+
+{"description":"Non-permitted slash",
+"input":"<xr/>",
+"output":[["StartTag","xr",{},true]]},
+
+{"description":"Permitted slash but in close tag",
+"input":"</br/>",
+"output":["ParseError", ["EndTag", "br"]]},
+
+{"description":"Doctype public case-sensitivity (1)",
+"input":"<!DoCtYpE HtMl PuBlIc \"AbC\" \"XyZ\">",
+"output":[["DOCTYPE", "html", "AbC", "XyZ", true]]},
+
+{"description":"Doctype public case-sensitivity (2)",
+"input":"<!dOcTyPe hTmL pUbLiC \"aBc\" \"xYz\">",
+"output":[["DOCTYPE", "html", "aBc", "xYz", true]]},
+
+{"description":"Doctype system case-sensitivity (1)",
+"input":"<!DoCtYpE HtMl SyStEm \"XyZ\">",
+"output":[["DOCTYPE", "html", null, "XyZ", true]]},
+
+{"description":"Doctype system case-sensitivity (2)",
+"input":"<!dOcTyPe hTmL sYsTeM \"xYz\">",
+"output":[["DOCTYPE", "html", null, "xYz", true]]},
+
+{"description":"U+0000 in lookahead region after non-matching character",
+"input":"<!doc>\u0000",
+"output":["ParseError", ["Comment", "doc"], "ParseError", ["Character", "\u0000"]],
+"ignoreErrorOrder":true},
+
+{"description":"U+0000 in lookahead region",
+"input":"<!doc\u0000",
+"output":["ParseError", ["Comment", "doc\uFFFD"]],
+"ignoreErrorOrder":true},
+
+{"description":"U+0080 in lookahead region",
+"input":"<!doc\u0080",
+"output":["ParseError", "ParseError", ["Comment", "doc\u0080"]],
+"ignoreErrorOrder":true},
+
+{"description":"U+FDD1 in lookahead region",
+"input":"<!doc\uFDD1",
+"output":["ParseError", "ParseError", ["Comment", "doc\uFDD1"]],
+"ignoreErrorOrder":true},
+
+{"description":"U+1FFFF in lookahead region",
+"input":"<!doc\uD83F\uDFFF",
+"output":["ParseError", "ParseError", ["Comment", "doc\uD83F\uDFFF"]],
+"ignoreErrorOrder":true},
+
+{"description":"CR followed by non-LF",
+"input":"\r?",
+"output":[["Character", "\n?"]]},
+
+{"description":"CR at EOF",
+"input":"\r",
+"output":[["Character", "\n"]]},
+
+{"description":"LF at EOF",
+"input":"\n",
+"output":[["Character", "\n"]]},
+
+{"description":"CR LF",
+"input":"\r\n",
+"output":[["Character", "\n"]]},
+
+{"description":"CR CR",
+"input":"\r\r",
+"output":[["Character", "\n\n"]]},
+
+{"description":"LF LF",
+"input":"\n\n",
+"output":[["Character", "\n\n"]]},
+
+{"description":"LF CR",
+"input":"\n\r",
+"output":[["Character", "\n\n"]]},
+
+{"description":"text CR CR CR text",
+"input":"text\r\r\rtext",
+"output":[["Character", "text\n\n\ntext"]]},
+
+{"description":"Doctype publik",
+"input":"<!DOCTYPE html PUBLIK \"AbC\" \"XyZ\">",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Doctype publi",
+"input":"<!DOCTYPE html PUBLI",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Doctype sistem",
+"input":"<!DOCTYPE html SISTEM \"AbC\">",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Doctype sys",
+"input":"<!DOCTYPE html SYS",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false]]},
+
+{"description":"Doctype html x>text",
+"input":"<!DOCTYPE html x>text",
+"output":["ParseError", ["DOCTYPE", "html", null, null, false], ["Character", "text"]]},
+
+{"description":"Grave accent in unquoted attribute",
+"input":"<a a=aa`>",
+"output":["ParseError", ["StartTag", "a", {"a":"aa`"}]]},
+
+{"description":"EOF in tag name state ",
+"input":"<a",
+"output":["ParseError"]},
+
+{"description":"EOF in tag name state",
+"input":"<a",
+"output":["ParseError"]},
+
+{"description":"EOF in before attribute name state",
+"input":"<a ",
+"output":["ParseError"]},
+
+{"description":"EOF in attribute name state",
+"input":"<a a",
+"output":["ParseError"]},
+
+{"description":"EOF in after attribute name state",
+"input":"<a a ",
+"output":["ParseError"]},
+
+{"description":"EOF in before attribute value state",
+"input":"<a a =",
+"output":["ParseError"]},
+
+{"description":"EOF in attribute value (double quoted) state",
+"input":"<a a =\"a",
+"output":["ParseError"]},
+
+{"description":"EOF in attribute value (single quoted) state",
+"input":"<a a ='a",
+"output":["ParseError"]},
+
+{"description":"EOF in attribute value (unquoted) state",
+"input":"<a a =a",
+"output":["ParseError"]},
+
+{"description":"EOF in after attribute value state",
+"input":"<a a ='a'",
+"output":["ParseError"]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/unicodeChars.test b/pkgs/html/test/data/tokenizer/unicodeChars.test
new file mode 100644
index 0000000..c778668
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/unicodeChars.test
@@ -0,0 +1,1295 @@
+{"tests": [
+
+{"description": "Invalid Unicode character U+0001",
+"input": "\u0001",
+"output": ["ParseError", ["Character", "\u0001"]]},
+
+{"description": "Invalid Unicode character U+0002",
+"input": "\u0002",
+"output": ["ParseError", ["Character", "\u0002"]]},
+
+{"description": "Invalid Unicode character U+0003",
+"input": "\u0003",
+"output": ["ParseError", ["Character", "\u0003"]]},
+
+{"description": "Invalid Unicode character U+0004",
+"input": "\u0004",
+"output": ["ParseError", ["Character", "\u0004"]]},
+
+{"description": "Invalid Unicode character U+0005",
+"input": "\u0005",
+"output": ["ParseError", ["Character", "\u0005"]]},
+
+{"description": "Invalid Unicode character U+0006",
+"input": "\u0006",
+"output": ["ParseError", ["Character", "\u0006"]]},
+
+{"description": "Invalid Unicode character U+0007",
+"input": "\u0007",
+"output": ["ParseError", ["Character", "\u0007"]]},
+
+{"description": "Invalid Unicode character U+0008",
+"input": "\u0008",
+"output": ["ParseError", ["Character", "\u0008"]]},
+
+{"description": "Invalid Unicode character U+000B",
+"input": "\u000B",
+"output": ["ParseError", ["Character", "\u000B"]]},
+
+{"description": "Invalid Unicode character U+000E",
+"input": "\u000E",
+"output": ["ParseError", ["Character", "\u000E"]]},
+
+{"description": "Invalid Unicode character U+000F",
+"input": "\u000F",
+"output": ["ParseError", ["Character", "\u000F"]]},
+
+{"description": "Invalid Unicode character U+0010",
+"input": "\u0010",
+"output": ["ParseError", ["Character", "\u0010"]]},
+
+{"description": "Invalid Unicode character U+0011",
+"input": "\u0011",
+"output": ["ParseError", ["Character", "\u0011"]]},
+
+{"description": "Invalid Unicode character U+0012",
+"input": "\u0012",
+"output": ["ParseError", ["Character", "\u0012"]]},
+
+{"description": "Invalid Unicode character U+0013",
+"input": "\u0013",
+"output": ["ParseError", ["Character", "\u0013"]]},
+
+{"description": "Invalid Unicode character U+0014",
+"input": "\u0014",
+"output": ["ParseError", ["Character", "\u0014"]]},
+
+{"description": "Invalid Unicode character U+0015",
+"input": "\u0015",
+"output": ["ParseError", ["Character", "\u0015"]]},
+
+{"description": "Invalid Unicode character U+0016",
+"input": "\u0016",
+"output": ["ParseError", ["Character", "\u0016"]]},
+
+{"description": "Invalid Unicode character U+0017",
+"input": "\u0017",
+"output": ["ParseError", ["Character", "\u0017"]]},
+
+{"description": "Invalid Unicode character U+0018",
+"input": "\u0018",
+"output": ["ParseError", ["Character", "\u0018"]]},
+
+{"description": "Invalid Unicode character U+0019",
+"input": "\u0019",
+"output": ["ParseError", ["Character", "\u0019"]]},
+
+{"description": "Invalid Unicode character U+001A",
+"input": "\u001A",
+"output": ["ParseError", ["Character", "\u001A"]]},
+
+{"description": "Invalid Unicode character U+001B",
+"input": "\u001B",
+"output": ["ParseError", ["Character", "\u001B"]]},
+
+{"description": "Invalid Unicode character U+001C",
+"input": "\u001C",
+"output": ["ParseError", ["Character", "\u001C"]]},
+
+{"description": "Invalid Unicode character U+001D",
+"input": "\u001D",
+"output": ["ParseError", ["Character", "\u001D"]]},
+
+{"description": "Invalid Unicode character U+001E",
+"input": "\u001E",
+"output": ["ParseError", ["Character", "\u001E"]]},
+
+{"description": "Invalid Unicode character U+001F",
+"input": "\u001F",
+"output": ["ParseError", ["Character", "\u001F"]]},
+
+{"description": "Invalid Unicode character U+007F",
+"input": "\u007F",
+"output": ["ParseError", ["Character", "\u007F"]]},
+
+{"description": "Invalid Unicode character U+FDD0",
+"input": "\uFDD0",
+"output": ["ParseError", ["Character", "\uFDD0"]]},
+
+{"description": "Invalid Unicode character U+FDD1",
+"input": "\uFDD1",
+"output": ["ParseError", ["Character", "\uFDD1"]]},
+
+{"description": "Invalid Unicode character U+FDD2",
+"input": "\uFDD2",
+"output": ["ParseError", ["Character", "\uFDD2"]]},
+
+{"description": "Invalid Unicode character U+FDD3",
+"input": "\uFDD3",
+"output": ["ParseError", ["Character", "\uFDD3"]]},
+
+{"description": "Invalid Unicode character U+FDD4",
+"input": "\uFDD4",
+"output": ["ParseError", ["Character", "\uFDD4"]]},
+
+{"description": "Invalid Unicode character U+FDD5",
+"input": "\uFDD5",
+"output": ["ParseError", ["Character", "\uFDD5"]]},
+
+{"description": "Invalid Unicode character U+FDD6",
+"input": "\uFDD6",
+"output": ["ParseError", ["Character", "\uFDD6"]]},
+
+{"description": "Invalid Unicode character U+FDD7",
+"input": "\uFDD7",
+"output": ["ParseError", ["Character", "\uFDD7"]]},
+
+{"description": "Invalid Unicode character U+FDD8",
+"input": "\uFDD8",
+"output": ["ParseError", ["Character", "\uFDD8"]]},
+
+{"description": "Invalid Unicode character U+FDD9",
+"input": "\uFDD9",
+"output": ["ParseError", ["Character", "\uFDD9"]]},
+
+{"description": "Invalid Unicode character U+FDDA",
+"input": "\uFDDA",
+"output": ["ParseError", ["Character", "\uFDDA"]]},
+
+{"description": "Invalid Unicode character U+FDDB",
+"input": "\uFDDB",
+"output": ["ParseError", ["Character", "\uFDDB"]]},
+
+{"description": "Invalid Unicode character U+FDDC",
+"input": "\uFDDC",
+"output": ["ParseError", ["Character", "\uFDDC"]]},
+
+{"description": "Invalid Unicode character U+FDDD",
+"input": "\uFDDD",
+"output": ["ParseError", ["Character", "\uFDDD"]]},
+
+{"description": "Invalid Unicode character U+FDDE",
+"input": "\uFDDE",
+"output": ["ParseError", ["Character", "\uFDDE"]]},
+
+{"description": "Invalid Unicode character U+FDDF",
+"input": "\uFDDF",
+"output": ["ParseError", ["Character", "\uFDDF"]]},
+
+{"description": "Invalid Unicode character U+FDE0",
+"input": "\uFDE0",
+"output": ["ParseError", ["Character", "\uFDE0"]]},
+
+{"description": "Invalid Unicode character U+FDE1",
+"input": "\uFDE1",
+"output": ["ParseError", ["Character", "\uFDE1"]]},
+
+{"description": "Invalid Unicode character U+FDE2",
+"input": "\uFDE2",
+"output": ["ParseError", ["Character", "\uFDE2"]]},
+
+{"description": "Invalid Unicode character U+FDE3",
+"input": "\uFDE3",
+"output": ["ParseError", ["Character", "\uFDE3"]]},
+
+{"description": "Invalid Unicode character U+FDE4",
+"input": "\uFDE4",
+"output": ["ParseError", ["Character", "\uFDE4"]]},
+
+{"description": "Invalid Unicode character U+FDE5",
+"input": "\uFDE5",
+"output": ["ParseError", ["Character", "\uFDE5"]]},
+
+{"description": "Invalid Unicode character U+FDE6",
+"input": "\uFDE6",
+"output": ["ParseError", ["Character", "\uFDE6"]]},
+
+{"description": "Invalid Unicode character U+FDE7",
+"input": "\uFDE7",
+"output": ["ParseError", ["Character", "\uFDE7"]]},
+
+{"description": "Invalid Unicode character U+FDE8",
+"input": "\uFDE8",
+"output": ["ParseError", ["Character", "\uFDE8"]]},
+
+{"description": "Invalid Unicode character U+FDE9",
+"input": "\uFDE9",
+"output": ["ParseError", ["Character", "\uFDE9"]]},
+
+{"description": "Invalid Unicode character U+FDEA",
+"input": "\uFDEA",
+"output": ["ParseError", ["Character", "\uFDEA"]]},
+
+{"description": "Invalid Unicode character U+FDEB",
+"input": "\uFDEB",
+"output": ["ParseError", ["Character", "\uFDEB"]]},
+
+{"description": "Invalid Unicode character U+FDEC",
+"input": "\uFDEC",
+"output": ["ParseError", ["Character", "\uFDEC"]]},
+
+{"description": "Invalid Unicode character U+FDED",
+"input": "\uFDED",
+"output": ["ParseError", ["Character", "\uFDED"]]},
+
+{"description": "Invalid Unicode character U+FDEE",
+"input": "\uFDEE",
+"output": ["ParseError", ["Character", "\uFDEE"]]},
+
+{"description": "Invalid Unicode character U+FDEF",
+"input": "\uFDEF",
+"output": ["ParseError", ["Character", "\uFDEF"]]},
+
+{"description": "Invalid Unicode character U+FFFE",
+"input": "\uFFFE",
+"output": ["ParseError", ["Character", "\uFFFE"]]},
+
+{"description": "Invalid Unicode character U+FFFF",
+"input": "\uFFFF",
+"output": ["ParseError", ["Character", "\uFFFF"]]},
+
+{"description": "Invalid Unicode character U+1FFFE",
+"input": "\uD83F\uDFFE",
+"output": ["ParseError", ["Character", "\uD83F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+1FFFF",
+"input": "\uD83F\uDFFF",
+"output": ["ParseError", ["Character", "\uD83F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+2FFFE",
+"input": "\uD87F\uDFFE",
+"output": ["ParseError", ["Character", "\uD87F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+2FFFF",
+"input": "\uD87F\uDFFF",
+"output": ["ParseError", ["Character", "\uD87F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+3FFFE",
+"input": "\uD8BF\uDFFE",
+"output": ["ParseError", ["Character", "\uD8BF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+3FFFF",
+"input": "\uD8BF\uDFFF",
+"output": ["ParseError", ["Character", "\uD8BF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+4FFFE",
+"input": "\uD8FF\uDFFE",
+"output": ["ParseError", ["Character", "\uD8FF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+4FFFF",
+"input": "\uD8FF\uDFFF",
+"output": ["ParseError", ["Character", "\uD8FF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+5FFFE",
+"input": "\uD93F\uDFFE",
+"output": ["ParseError", ["Character", "\uD93F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+5FFFF",
+"input": "\uD93F\uDFFF",
+"output": ["ParseError", ["Character", "\uD93F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+6FFFE",
+"input": "\uD97F\uDFFE",
+"output": ["ParseError", ["Character", "\uD97F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+6FFFF",
+"input": "\uD97F\uDFFF",
+"output": ["ParseError", ["Character", "\uD97F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+7FFFE",
+"input": "\uD9BF\uDFFE",
+"output": ["ParseError", ["Character", "\uD9BF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+7FFFF",
+"input": "\uD9BF\uDFFF",
+"output": ["ParseError", ["Character", "\uD9BF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+8FFFE",
+"input": "\uD9FF\uDFFE",
+"output": ["ParseError", ["Character", "\uD9FF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+8FFFF",
+"input": "\uD9FF\uDFFF",
+"output": ["ParseError", ["Character", "\uD9FF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+9FFFE",
+"input": "\uDA3F\uDFFE",
+"output": ["ParseError", ["Character", "\uDA3F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+9FFFF",
+"input": "\uDA3F\uDFFF",
+"output": ["ParseError", ["Character", "\uDA3F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+AFFFE",
+"input": "\uDA7F\uDFFE",
+"output": ["ParseError", ["Character", "\uDA7F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+AFFFF",
+"input": "\uDA7F\uDFFF",
+"output": ["ParseError", ["Character", "\uDA7F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+BFFFE",
+"input": "\uDABF\uDFFE",
+"output": ["ParseError", ["Character", "\uDABF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+BFFFF",
+"input": "\uDABF\uDFFF",
+"output": ["ParseError", ["Character", "\uDABF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+CFFFE",
+"input": "\uDAFF\uDFFE",
+"output": ["ParseError", ["Character", "\uDAFF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+CFFFF",
+"input": "\uDAFF\uDFFF",
+"output": ["ParseError", ["Character", "\uDAFF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+DFFFE",
+"input": "\uDB3F\uDFFE",
+"output": ["ParseError", ["Character", "\uDB3F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+DFFFF",
+"input": "\uDB3F\uDFFF",
+"output": ["ParseError", ["Character", "\uDB3F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+EFFFE",
+"input": "\uDB7F\uDFFE",
+"output": ["ParseError", ["Character", "\uDB7F\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+EFFFF",
+"input": "\uDB7F\uDFFF",
+"output": ["ParseError", ["Character", "\uDB7F\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+FFFFE",
+"input": "\uDBBF\uDFFE",
+"output": ["ParseError", ["Character", "\uDBBF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+FFFFF",
+"input": "\uDBBF\uDFFF",
+"output": ["ParseError", ["Character", "\uDBBF\uDFFF"]]},
+
+{"description": "Invalid Unicode character U+10FFFE",
+"input": "\uDBFF\uDFFE",
+"output": ["ParseError", ["Character", "\uDBFF\uDFFE"]]},
+
+{"description": "Invalid Unicode character U+10FFFF",
+"input": "\uDBFF\uDFFF",
+"output": ["ParseError", ["Character", "\uDBFF\uDFFF"]]},
+
+{"description": "Valid Unicode character U+0009",
+"input": "\u0009",
+"output": [["Character", "\u0009"]]},
+
+{"description": "Valid Unicode character U+000A",
+"input": "\u000A",
+"output": [["Character", "\u000A"]]},
+
+{"description": "Valid Unicode character U+0020",
+"input": "\u0020",
+"output": [["Character", "\u0020"]]},
+
+{"description": "Valid Unicode character U+0021",
+"input": "\u0021",
+"output": [["Character", "\u0021"]]},
+
+{"description": "Valid Unicode character U+0022",
+"input": "\u0022",
+"output": [["Character", "\u0022"]]},
+
+{"description": "Valid Unicode character U+0023",
+"input": "\u0023",
+"output": [["Character", "\u0023"]]},
+
+{"description": "Valid Unicode character U+0024",
+"input": "\u0024",
+"output": [["Character", "\u0024"]]},
+
+{"description": "Valid Unicode character U+0025",
+"input": "\u0025",
+"output": [["Character", "\u0025"]]},
+
+{"description": "Valid Unicode character U+0026",
+"input": "\u0026",
+"output": [["Character", "\u0026"]]},
+
+{"description": "Valid Unicode character U+0027",
+"input": "\u0027",
+"output": [["Character", "\u0027"]]},
+
+{"description": "Valid Unicode character U+0028",
+"input": "\u0028",
+"output": [["Character", "\u0028"]]},
+
+{"description": "Valid Unicode character U+0029",
+"input": "\u0029",
+"output": [["Character", "\u0029"]]},
+
+{"description": "Valid Unicode character U+002A",
+"input": "\u002A",
+"output": [["Character", "\u002A"]]},
+
+{"description": "Valid Unicode character U+002B",
+"input": "\u002B",
+"output": [["Character", "\u002B"]]},
+
+{"description": "Valid Unicode character U+002C",
+"input": "\u002C",
+"output": [["Character", "\u002C"]]},
+
+{"description": "Valid Unicode character U+002D",
+"input": "\u002D",
+"output": [["Character", "\u002D"]]},
+
+{"description": "Valid Unicode character U+002E",
+"input": "\u002E",
+"output": [["Character", "\u002E"]]},
+
+{"description": "Valid Unicode character U+002F",
+"input": "\u002F",
+"output": [["Character", "\u002F"]]},
+
+{"description": "Valid Unicode character U+0030",
+"input": "\u0030",
+"output": [["Character", "\u0030"]]},
+
+{"description": "Valid Unicode character U+0031",
+"input": "\u0031",
+"output": [["Character", "\u0031"]]},
+
+{"description": "Valid Unicode character U+0032",
+"input": "\u0032",
+"output": [["Character", "\u0032"]]},
+
+{"description": "Valid Unicode character U+0033",
+"input": "\u0033",
+"output": [["Character", "\u0033"]]},
+
+{"description": "Valid Unicode character U+0034",
+"input": "\u0034",
+"output": [["Character", "\u0034"]]},
+
+{"description": "Valid Unicode character U+0035",
+"input": "\u0035",
+"output": [["Character", "\u0035"]]},
+
+{"description": "Valid Unicode character U+0036",
+"input": "\u0036",
+"output": [["Character", "\u0036"]]},
+
+{"description": "Valid Unicode character U+0037",
+"input": "\u0037",
+"output": [["Character", "\u0037"]]},
+
+{"description": "Valid Unicode character U+0038",
+"input": "\u0038",
+"output": [["Character", "\u0038"]]},
+
+{"description": "Valid Unicode character U+0039",
+"input": "\u0039",
+"output": [["Character", "\u0039"]]},
+
+{"description": "Valid Unicode character U+003A",
+"input": "\u003A",
+"output": [["Character", "\u003A"]]},
+
+{"description": "Valid Unicode character U+003B",
+"input": "\u003B",
+"output": [["Character", "\u003B"]]},
+
+{"description": "Valid Unicode character U+003D",
+"input": "\u003D",
+"output": [["Character", "\u003D"]]},
+
+{"description": "Valid Unicode character U+003E",
+"input": "\u003E",
+"output": [["Character", "\u003E"]]},
+
+{"description": "Valid Unicode character U+003F",
+"input": "\u003F",
+"output": [["Character", "\u003F"]]},
+
+{"description": "Valid Unicode character U+0040",
+"input": "\u0040",
+"output": [["Character", "\u0040"]]},
+
+{"description": "Valid Unicode character U+0041",
+"input": "\u0041",
+"output": [["Character", "\u0041"]]},
+
+{"description": "Valid Unicode character U+0042",
+"input": "\u0042",
+"output": [["Character", "\u0042"]]},
+
+{"description": "Valid Unicode character U+0043",
+"input": "\u0043",
+"output": [["Character", "\u0043"]]},
+
+{"description": "Valid Unicode character U+0044",
+"input": "\u0044",
+"output": [["Character", "\u0044"]]},
+
+{"description": "Valid Unicode character U+0045",
+"input": "\u0045",
+"output": [["Character", "\u0045"]]},
+
+{"description": "Valid Unicode character U+0046",
+"input": "\u0046",
+"output": [["Character", "\u0046"]]},
+
+{"description": "Valid Unicode character U+0047",
+"input": "\u0047",
+"output": [["Character", "\u0047"]]},
+
+{"description": "Valid Unicode character U+0048",
+"input": "\u0048",
+"output": [["Character", "\u0048"]]},
+
+{"description": "Valid Unicode character U+0049",
+"input": "\u0049",
+"output": [["Character", "\u0049"]]},
+
+{"description": "Valid Unicode character U+004A",
+"input": "\u004A",
+"output": [["Character", "\u004A"]]},
+
+{"description": "Valid Unicode character U+004B",
+"input": "\u004B",
+"output": [["Character", "\u004B"]]},
+
+{"description": "Valid Unicode character U+004C",
+"input": "\u004C",
+"output": [["Character", "\u004C"]]},
+
+{"description": "Valid Unicode character U+004D",
+"input": "\u004D",
+"output": [["Character", "\u004D"]]},
+
+{"description": "Valid Unicode character U+004E",
+"input": "\u004E",
+"output": [["Character", "\u004E"]]},
+
+{"description": "Valid Unicode character U+004F",
+"input": "\u004F",
+"output": [["Character", "\u004F"]]},
+
+{"description": "Valid Unicode character U+0050",
+"input": "\u0050",
+"output": [["Character", "\u0050"]]},
+
+{"description": "Valid Unicode character U+0051",
+"input": "\u0051",
+"output": [["Character", "\u0051"]]},
+
+{"description": "Valid Unicode character U+0052",
+"input": "\u0052",
+"output": [["Character", "\u0052"]]},
+
+{"description": "Valid Unicode character U+0053",
+"input": "\u0053",
+"output": [["Character", "\u0053"]]},
+
+{"description": "Valid Unicode character U+0054",
+"input": "\u0054",
+"output": [["Character", "\u0054"]]},
+
+{"description": "Valid Unicode character U+0055",
+"input": "\u0055",
+"output": [["Character", "\u0055"]]},
+
+{"description": "Valid Unicode character U+0056",
+"input": "\u0056",
+"output": [["Character", "\u0056"]]},
+
+{"description": "Valid Unicode character U+0057",
+"input": "\u0057",
+"output": [["Character", "\u0057"]]},
+
+{"description": "Valid Unicode character U+0058",
+"input": "\u0058",
+"output": [["Character", "\u0058"]]},
+
+{"description": "Valid Unicode character U+0059",
+"input": "\u0059",
+"output": [["Character", "\u0059"]]},
+
+{"description": "Valid Unicode character U+005A",
+"input": "\u005A",
+"output": [["Character", "\u005A"]]},
+
+{"description": "Valid Unicode character U+005B",
+"input": "\u005B",
+"output": [["Character", "\u005B"]]},
+
+{"description": "Valid Unicode character U+005C",
+"input": "\u005C",
+"output": [["Character", "\u005C"]]},
+
+{"description": "Valid Unicode character U+005D",
+"input": "\u005D",
+"output": [["Character", "\u005D"]]},
+
+{"description": "Valid Unicode character U+005E",
+"input": "\u005E",
+"output": [["Character", "\u005E"]]},
+
+{"description": "Valid Unicode character U+005F",
+"input": "\u005F",
+"output": [["Character", "\u005F"]]},
+
+{"description": "Valid Unicode character U+0060",
+"input": "\u0060",
+"output": [["Character", "\u0060"]]},
+
+{"description": "Valid Unicode character U+0061",
+"input": "\u0061",
+"output": [["Character", "\u0061"]]},
+
+{"description": "Valid Unicode character U+0062",
+"input": "\u0062",
+"output": [["Character", "\u0062"]]},
+
+{"description": "Valid Unicode character U+0063",
+"input": "\u0063",
+"output": [["Character", "\u0063"]]},
+
+{"description": "Valid Unicode character U+0064",
+"input": "\u0064",
+"output": [["Character", "\u0064"]]},
+
+{"description": "Valid Unicode character U+0065",
+"input": "\u0065",
+"output": [["Character", "\u0065"]]},
+
+{"description": "Valid Unicode character U+0066",
+"input": "\u0066",
+"output": [["Character", "\u0066"]]},
+
+{"description": "Valid Unicode character U+0067",
+"input": "\u0067",
+"output": [["Character", "\u0067"]]},
+
+{"description": "Valid Unicode character U+0068",
+"input": "\u0068",
+"output": [["Character", "\u0068"]]},
+
+{"description": "Valid Unicode character U+0069",
+"input": "\u0069",
+"output": [["Character", "\u0069"]]},
+
+{"description": "Valid Unicode character U+006A",
+"input": "\u006A",
+"output": [["Character", "\u006A"]]},
+
+{"description": "Valid Unicode character U+006B",
+"input": "\u006B",
+"output": [["Character", "\u006B"]]},
+
+{"description": "Valid Unicode character U+006C",
+"input": "\u006C",
+"output": [["Character", "\u006C"]]},
+
+{"description": "Valid Unicode character U+006D",
+"input": "\u006D",
+"output": [["Character", "\u006D"]]},
+
+{"description": "Valid Unicode character U+006E",
+"input": "\u006E",
+"output": [["Character", "\u006E"]]},
+
+{"description": "Valid Unicode character U+006F",
+"input": "\u006F",
+"output": [["Character", "\u006F"]]},
+
+{"description": "Valid Unicode character U+0070",
+"input": "\u0070",
+"output": [["Character", "\u0070"]]},
+
+{"description": "Valid Unicode character U+0071",
+"input": "\u0071",
+"output": [["Character", "\u0071"]]},
+
+{"description": "Valid Unicode character U+0072",
+"input": "\u0072",
+"output": [["Character", "\u0072"]]},
+
+{"description": "Valid Unicode character U+0073",
+"input": "\u0073",
+"output": [["Character", "\u0073"]]},
+
+{"description": "Valid Unicode character U+0074",
+"input": "\u0074",
+"output": [["Character", "\u0074"]]},
+
+{"description": "Valid Unicode character U+0075",
+"input": "\u0075",
+"output": [["Character", "\u0075"]]},
+
+{"description": "Valid Unicode character U+0076",
+"input": "\u0076",
+"output": [["Character", "\u0076"]]},
+
+{"description": "Valid Unicode character U+0077",
+"input": "\u0077",
+"output": [["Character", "\u0077"]]},
+
+{"description": "Valid Unicode character U+0078",
+"input": "\u0078",
+"output": [["Character", "\u0078"]]},
+
+{"description": "Valid Unicode character U+0079",
+"input": "\u0079",
+"output": [["Character", "\u0079"]]},
+
+{"description": "Valid Unicode character U+007A",
+"input": "\u007A",
+"output": [["Character", "\u007A"]]},
+
+{"description": "Valid Unicode character U+007B",
+"input": "\u007B",
+"output": [["Character", "\u007B"]]},
+
+{"description": "Valid Unicode character U+007C",
+"input": "\u007C",
+"output": [["Character", "\u007C"]]},
+
+{"description": "Valid Unicode character U+007D",
+"input": "\u007D",
+"output": [["Character", "\u007D"]]},
+
+{"description": "Valid Unicode character U+007E",
+"input": "\u007E",
+"output": [["Character", "\u007E"]]},
+
+{"description": "Valid Unicode character U+00A0",
+"input": "\u00A0",
+"output": [["Character", "\u00A0"]]},
+
+{"description": "Valid Unicode character U+00A1",
+"input": "\u00A1",
+"output": [["Character", "\u00A1"]]},
+
+{"description": "Valid Unicode character U+00A2",
+"input": "\u00A2",
+"output": [["Character", "\u00A2"]]},
+
+{"description": "Valid Unicode character U+00A3",
+"input": "\u00A3",
+"output": [["Character", "\u00A3"]]},
+
+{"description": "Valid Unicode character U+00A4",
+"input": "\u00A4",
+"output": [["Character", "\u00A4"]]},
+
+{"description": "Valid Unicode character U+00A5",
+"input": "\u00A5",
+"output": [["Character", "\u00A5"]]},
+
+{"description": "Valid Unicode character U+00A6",
+"input": "\u00A6",
+"output": [["Character", "\u00A6"]]},
+
+{"description": "Valid Unicode character U+00A7",
+"input": "\u00A7",
+"output": [["Character", "\u00A7"]]},
+
+{"description": "Valid Unicode character U+00A8",
+"input": "\u00A8",
+"output": [["Character", "\u00A8"]]},
+
+{"description": "Valid Unicode character U+00A9",
+"input": "\u00A9",
+"output": [["Character", "\u00A9"]]},
+
+{"description": "Valid Unicode character U+00AA",
+"input": "\u00AA",
+"output": [["Character", "\u00AA"]]},
+
+{"description": "Valid Unicode character U+00AB",
+"input": "\u00AB",
+"output": [["Character", "\u00AB"]]},
+
+{"description": "Valid Unicode character U+00AC",
+"input": "\u00AC",
+"output": [["Character", "\u00AC"]]},
+
+{"description": "Valid Unicode character U+00AD",
+"input": "\u00AD",
+"output": [["Character", "\u00AD"]]},
+
+{"description": "Valid Unicode character U+00AE",
+"input": "\u00AE",
+"output": [["Character", "\u00AE"]]},
+
+{"description": "Valid Unicode character U+00AF",
+"input": "\u00AF",
+"output": [["Character", "\u00AF"]]},
+
+{"description": "Valid Unicode character U+00B0",
+"input": "\u00B0",
+"output": [["Character", "\u00B0"]]},
+
+{"description": "Valid Unicode character U+00B1",
+"input": "\u00B1",
+"output": [["Character", "\u00B1"]]},
+
+{"description": "Valid Unicode character U+00B2",
+"input": "\u00B2",
+"output": [["Character", "\u00B2"]]},
+
+{"description": "Valid Unicode character U+00B3",
+"input": "\u00B3",
+"output": [["Character", "\u00B3"]]},
+
+{"description": "Valid Unicode character U+00B4",
+"input": "\u00B4",
+"output": [["Character", "\u00B4"]]},
+
+{"description": "Valid Unicode character U+00B5",
+"input": "\u00B5",
+"output": [["Character", "\u00B5"]]},
+
+{"description": "Valid Unicode character U+00B6",
+"input": "\u00B6",
+"output": [["Character", "\u00B6"]]},
+
+{"description": "Valid Unicode character U+00B7",
+"input": "\u00B7",
+"output": [["Character", "\u00B7"]]},
+
+{"description": "Valid Unicode character U+00B8",
+"input": "\u00B8",
+"output": [["Character", "\u00B8"]]},
+
+{"description": "Valid Unicode character U+00B9",
+"input": "\u00B9",
+"output": [["Character", "\u00B9"]]},
+
+{"description": "Valid Unicode character U+00BA",
+"input": "\u00BA",
+"output": [["Character", "\u00BA"]]},
+
+{"description": "Valid Unicode character U+00BB",
+"input": "\u00BB",
+"output": [["Character", "\u00BB"]]},
+
+{"description": "Valid Unicode character U+00BC",
+"input": "\u00BC",
+"output": [["Character", "\u00BC"]]},
+
+{"description": "Valid Unicode character U+00BD",
+"input": "\u00BD",
+"output": [["Character", "\u00BD"]]},
+
+{"description": "Valid Unicode character U+00BE",
+"input": "\u00BE",
+"output": [["Character", "\u00BE"]]},
+
+{"description": "Valid Unicode character U+00BF",
+"input": "\u00BF",
+"output": [["Character", "\u00BF"]]},
+
+{"description": "Valid Unicode character U+00C0",
+"input": "\u00C0",
+"output": [["Character", "\u00C0"]]},
+
+{"description": "Valid Unicode character U+00C1",
+"input": "\u00C1",
+"output": [["Character", "\u00C1"]]},
+
+{"description": "Valid Unicode character U+00C2",
+"input": "\u00C2",
+"output": [["Character", "\u00C2"]]},
+
+{"description": "Valid Unicode character U+00C3",
+"input": "\u00C3",
+"output": [["Character", "\u00C3"]]},
+
+{"description": "Valid Unicode character U+00C4",
+"input": "\u00C4",
+"output": [["Character", "\u00C4"]]},
+
+{"description": "Valid Unicode character U+00C5",
+"input": "\u00C5",
+"output": [["Character", "\u00C5"]]},
+
+{"description": "Valid Unicode character U+00C6",
+"input": "\u00C6",
+"output": [["Character", "\u00C6"]]},
+
+{"description": "Valid Unicode character U+00C7",
+"input": "\u00C7",
+"output": [["Character", "\u00C7"]]},
+
+{"description": "Valid Unicode character U+00C8",
+"input": "\u00C8",
+"output": [["Character", "\u00C8"]]},
+
+{"description": "Valid Unicode character U+00C9",
+"input": "\u00C9",
+"output": [["Character", "\u00C9"]]},
+
+{"description": "Valid Unicode character U+00CA",
+"input": "\u00CA",
+"output": [["Character", "\u00CA"]]},
+
+{"description": "Valid Unicode character U+00CB",
+"input": "\u00CB",
+"output": [["Character", "\u00CB"]]},
+
+{"description": "Valid Unicode character U+00CC",
+"input": "\u00CC",
+"output": [["Character", "\u00CC"]]},
+
+{"description": "Valid Unicode character U+00CD",
+"input": "\u00CD",
+"output": [["Character", "\u00CD"]]},
+
+{"description": "Valid Unicode character U+00CE",
+"input": "\u00CE",
+"output": [["Character", "\u00CE"]]},
+
+{"description": "Valid Unicode character U+00CF",
+"input": "\u00CF",
+"output": [["Character", "\u00CF"]]},
+
+{"description": "Valid Unicode character U+00D0",
+"input": "\u00D0",
+"output": [["Character", "\u00D0"]]},
+
+{"description": "Valid Unicode character U+00D1",
+"input": "\u00D1",
+"output": [["Character", "\u00D1"]]},
+
+{"description": "Valid Unicode character U+00D2",
+"input": "\u00D2",
+"output": [["Character", "\u00D2"]]},
+
+{"description": "Valid Unicode character U+00D3",
+"input": "\u00D3",
+"output": [["Character", "\u00D3"]]},
+
+{"description": "Valid Unicode character U+00D4",
+"input": "\u00D4",
+"output": [["Character", "\u00D4"]]},
+
+{"description": "Valid Unicode character U+00D5",
+"input": "\u00D5",
+"output": [["Character", "\u00D5"]]},
+
+{"description": "Valid Unicode character U+00D6",
+"input": "\u00D6",
+"output": [["Character", "\u00D6"]]},
+
+{"description": "Valid Unicode character U+00D7",
+"input": "\u00D7",
+"output": [["Character", "\u00D7"]]},
+
+{"description": "Valid Unicode character U+00D8",
+"input": "\u00D8",
+"output": [["Character", "\u00D8"]]},
+
+{"description": "Valid Unicode character U+00D9",
+"input": "\u00D9",
+"output": [["Character", "\u00D9"]]},
+
+{"description": "Valid Unicode character U+00DA",
+"input": "\u00DA",
+"output": [["Character", "\u00DA"]]},
+
+{"description": "Valid Unicode character U+00DB",
+"input": "\u00DB",
+"output": [["Character", "\u00DB"]]},
+
+{"description": "Valid Unicode character U+00DC",
+"input": "\u00DC",
+"output": [["Character", "\u00DC"]]},
+
+{"description": "Valid Unicode character U+00DD",
+"input": "\u00DD",
+"output": [["Character", "\u00DD"]]},
+
+{"description": "Valid Unicode character U+00DE",
+"input": "\u00DE",
+"output": [["Character", "\u00DE"]]},
+
+{"description": "Valid Unicode character U+00DF",
+"input": "\u00DF",
+"output": [["Character", "\u00DF"]]},
+
+{"description": "Valid Unicode character U+00E0",
+"input": "\u00E0",
+"output": [["Character", "\u00E0"]]},
+
+{"description": "Valid Unicode character U+00E1",
+"input": "\u00E1",
+"output": [["Character", "\u00E1"]]},
+
+{"description": "Valid Unicode character U+00E2",
+"input": "\u00E2",
+"output": [["Character", "\u00E2"]]},
+
+{"description": "Valid Unicode character U+00E3",
+"input": "\u00E3",
+"output": [["Character", "\u00E3"]]},
+
+{"description": "Valid Unicode character U+00E4",
+"input": "\u00E4",
+"output": [["Character", "\u00E4"]]},
+
+{"description": "Valid Unicode character U+00E5",
+"input": "\u00E5",
+"output": [["Character", "\u00E5"]]},
+
+{"description": "Valid Unicode character U+00E6",
+"input": "\u00E6",
+"output": [["Character", "\u00E6"]]},
+
+{"description": "Valid Unicode character U+00E7",
+"input": "\u00E7",
+"output": [["Character", "\u00E7"]]},
+
+{"description": "Valid Unicode character U+00E8",
+"input": "\u00E8",
+"output": [["Character", "\u00E8"]]},
+
+{"description": "Valid Unicode character U+00E9",
+"input": "\u00E9",
+"output": [["Character", "\u00E9"]]},
+
+{"description": "Valid Unicode character U+00EA",
+"input": "\u00EA",
+"output": [["Character", "\u00EA"]]},
+
+{"description": "Valid Unicode character U+00EB",
+"input": "\u00EB",
+"output": [["Character", "\u00EB"]]},
+
+{"description": "Valid Unicode character U+00EC",
+"input": "\u00EC",
+"output": [["Character", "\u00EC"]]},
+
+{"description": "Valid Unicode character U+00ED",
+"input": "\u00ED",
+"output": [["Character", "\u00ED"]]},
+
+{"description": "Valid Unicode character U+00EE",
+"input": "\u00EE",
+"output": [["Character", "\u00EE"]]},
+
+{"description": "Valid Unicode character U+00EF",
+"input": "\u00EF",
+"output": [["Character", "\u00EF"]]},
+
+{"description": "Valid Unicode character U+00F0",
+"input": "\u00F0",
+"output": [["Character", "\u00F0"]]},
+
+{"description": "Valid Unicode character U+00F1",
+"input": "\u00F1",
+"output": [["Character", "\u00F1"]]},
+
+{"description": "Valid Unicode character U+00F2",
+"input": "\u00F2",
+"output": [["Character", "\u00F2"]]},
+
+{"description": "Valid Unicode character U+00F3",
+"input": "\u00F3",
+"output": [["Character", "\u00F3"]]},
+
+{"description": "Valid Unicode character U+00F4",
+"input": "\u00F4",
+"output": [["Character", "\u00F4"]]},
+
+{"description": "Valid Unicode character U+00F5",
+"input": "\u00F5",
+"output": [["Character", "\u00F5"]]},
+
+{"description": "Valid Unicode character U+00F6",
+"input": "\u00F6",
+"output": [["Character", "\u00F6"]]},
+
+{"description": "Valid Unicode character U+00F7",
+"input": "\u00F7",
+"output": [["Character", "\u00F7"]]},
+
+{"description": "Valid Unicode character U+00F8",
+"input": "\u00F8",
+"output": [["Character", "\u00F8"]]},
+
+{"description": "Valid Unicode character U+00F9",
+"input": "\u00F9",
+"output": [["Character", "\u00F9"]]},
+
+{"description": "Valid Unicode character U+00FA",
+"input": "\u00FA",
+"output": [["Character", "\u00FA"]]},
+
+{"description": "Valid Unicode character U+00FB",
+"input": "\u00FB",
+"output": [["Character", "\u00FB"]]},
+
+{"description": "Valid Unicode character U+00FC",
+"input": "\u00FC",
+"output": [["Character", "\u00FC"]]},
+
+{"description": "Valid Unicode character U+00FD",
+"input": "\u00FD",
+"output": [["Character", "\u00FD"]]},
+
+{"description": "Valid Unicode character U+00FE",
+"input": "\u00FE",
+"output": [["Character", "\u00FE"]]},
+
+{"description": "Valid Unicode character U+00FF",
+"input": "\u00FF",
+"output": [["Character", "\u00FF"]]},
+
+{"description": "Valid Unicode character U+D7FF",
+"input": "\uD7FF",
+"output": [["Character", "\uD7FF"]]},
+
+{"description": "Valid Unicode character U+E000",
+"input": "\uE000",
+"output": [["Character", "\uE000"]]},
+
+{"description": "Valid Unicode character U+FDCF",
+"input": "\uFDCF",
+"output": [["Character", "\uFDCF"]]},
+
+{"description": "Valid Unicode character U+FDF0",
+"input": "\uFDF0",
+"output": [["Character", "\uFDF0"]]},
+
+{"description": "Valid Unicode character U+FFFD",
+"input": "\uFFFD",
+"output": [["Character", "\uFFFD"]]},
+
+{"description": "Valid Unicode character U+10000",
+"input": "\uD800\uDC00",
+"output": [["Character", "\uD800\uDC00"]]},
+
+{"description": "Valid Unicode character U+1FFFD",
+"input": "\uD83F\uDFFD",
+"output": [["Character", "\uD83F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+20000",
+"input": "\uD840\uDC00",
+"output": [["Character", "\uD840\uDC00"]]},
+
+{"description": "Valid Unicode character U+2FFFD",
+"input": "\uD87F\uDFFD",
+"output": [["Character", "\uD87F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+30000",
+"input": "\uD880\uDC00",
+"output": [["Character", "\uD880\uDC00"]]},
+
+{"description": "Valid Unicode character U+3FFFD",
+"input": "\uD8BF\uDFFD",
+"output": [["Character", "\uD8BF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+40000",
+"input": "\uD8C0\uDC00",
+"output": [["Character", "\uD8C0\uDC00"]]},
+
+{"description": "Valid Unicode character U+4FFFD",
+"input": "\uD8FF\uDFFD",
+"output": [["Character", "\uD8FF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+50000",
+"input": "\uD900\uDC00",
+"output": [["Character", "\uD900\uDC00"]]},
+
+{"description": "Valid Unicode character U+5FFFD",
+"input": "\uD93F\uDFFD",
+"output": [["Character", "\uD93F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+60000",
+"input": "\uD940\uDC00",
+"output": [["Character", "\uD940\uDC00"]]},
+
+{"description": "Valid Unicode character U+6FFFD",
+"input": "\uD97F\uDFFD",
+"output": [["Character", "\uD97F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+70000",
+"input": "\uD980\uDC00",
+"output": [["Character", "\uD980\uDC00"]]},
+
+{"description": "Valid Unicode character U+7FFFD",
+"input": "\uD9BF\uDFFD",
+"output": [["Character", "\uD9BF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+80000",
+"input": "\uD9C0\uDC00",
+"output": [["Character", "\uD9C0\uDC00"]]},
+
+{"description": "Valid Unicode character U+8FFFD",
+"input": "\uD9FF\uDFFD",
+"output": [["Character", "\uD9FF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+90000",
+"input": "\uDA00\uDC00",
+"output": [["Character", "\uDA00\uDC00"]]},
+
+{"description": "Valid Unicode character U+9FFFD",
+"input": "\uDA3F\uDFFD",
+"output": [["Character", "\uDA3F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+A0000",
+"input": "\uDA40\uDC00",
+"output": [["Character", "\uDA40\uDC00"]]},
+
+{"description": "Valid Unicode character U+AFFFD",
+"input": "\uDA7F\uDFFD",
+"output": [["Character", "\uDA7F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+B0000",
+"input": "\uDA80\uDC00",
+"output": [["Character", "\uDA80\uDC00"]]},
+
+{"description": "Valid Unicode character U+BFFFD",
+"input": "\uDABF\uDFFD",
+"output": [["Character", "\uDABF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+C0000",
+"input": "\uDAC0\uDC00",
+"output": [["Character", "\uDAC0\uDC00"]]},
+
+{"description": "Valid Unicode character U+CFFFD",
+"input": "\uDAFF\uDFFD",
+"output": [["Character", "\uDAFF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+D0000",
+"input": "\uDB00\uDC00",
+"output": [["Character", "\uDB00\uDC00"]]},
+
+{"description": "Valid Unicode character U+DFFFD",
+"input": "\uDB3F\uDFFD",
+"output": [["Character", "\uDB3F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+E0000",
+"input": "\uDB40\uDC00",
+"output": [["Character", "\uDB40\uDC00"]]},
+
+{"description": "Valid Unicode character U+EFFFD",
+"input": "\uDB7F\uDFFD",
+"output": [["Character", "\uDB7F\uDFFD"]]},
+
+{"description": "Valid Unicode character U+F0000",
+"input": "\uDB80\uDC00",
+"output": [["Character", "\uDB80\uDC00"]]},
+
+{"description": "Valid Unicode character U+FFFFD",
+"input": "\uDBBF\uDFFD",
+"output": [["Character", "\uDBBF\uDFFD"]]},
+
+{"description": "Valid Unicode character U+100000",
+"input": "\uDBC0\uDC00",
+"output": [["Character", "\uDBC0\uDC00"]]},
+
+{"description": "Valid Unicode character U+10FFFD",
+"input": "\uDBFF\uDFFD",
+"output": [["Character", "\uDBFF\uDFFD"]]}
+
+]}
diff --git a/pkgs/html/test/data/tokenizer/unicodeCharsProblematic.test b/pkgs/html/test/data/tokenizer/unicodeCharsProblematic.test
new file mode 100644
index 0000000..cf2fbe6
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/unicodeCharsProblematic.test
@@ -0,0 +1,27 @@
+{"tests" : [
+{"description": "Invalid Unicode character U+DFFF",
+"doubleEscaped":true,
+"input": "\\uDFFF",
+"output":["ParseError", ["Character", "\\uFFFD"]]},
+
+{"description": "Invalid Unicode character U+D800",
+"doubleEscaped":true,
+"input": "\\uD800",
+"output":["ParseError", ["Character", "\\uFFFD"]]},
+
+{"description": "Invalid Unicode character U+DFFF with valid preceding character",
+"doubleEscaped":true,
+"input": "a\\uDFFF",
+"output":["ParseError", ["Character", "a\\uFFFD"]]},
+
+{"description": "Invalid Unicode character U+D800 with valid following character",
+"doubleEscaped":true,
+"input": "\\uD800a",
+"output":["ParseError", ["Character", "\\uFFFDa"]]},
+
+{"description":"CR followed by U+0000",
+"input":"\r\u0000",
+"output":[["Character", "\n"], "ParseError", ["Character", "\u0000"]],
+"ignoreErrorOrder":true}
+]
+}
\ No newline at end of file
diff --git a/pkgs/html/test/data/tokenizer/unicodeCharsSurrogates.test b/pkgs/html/test/data/tokenizer/unicodeCharsSurrogates.test
new file mode 100644
index 0000000..9b56a98
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/unicodeCharsSurrogates.test
@@ -0,0 +1,24 @@
+{"tests" : [
+{"description": "Unicode surrogate (emoji)",
+"input": "\uD83D\uDC3C",
+"output":[["Character", "\uD83D\uDC3C"]]},
+
+{"description": "Unicode surrogate (emoji) prefixed by characters",
+"input": "before\uD83D\uDC3C",
+"output":[["Character", "before\uD83D\uDC3C"]]},
+
+{"description": "Unicode surrogate (emoji) suffixed by characters",
+"input": "\uD83D\uDC3Cafter",
+"output":[["Character", "\uD83D\uDC3Cafter"]]},
+
+{"description":"Quoted attribute with surrogate unicode content",
+"generateSpans": true,
+"input":"<a href='\uD83D\uDC3C'/>",
+"output":[["StartTag","a",{"href":"\uD83D\uDC3C"},true,0,14]]},
+
+{"description":"Surrogate unicode content followed by attribute",
+"generateSpans": true,
+"input":"\uD83D\uDC3C<a href='b'/>",
+"output":[["Character", "\uD83D\uDC3C", 0, 2],["StartTag","a",{"href":"b"},true,2,15]]}
+]
+}
\ No newline at end of file
diff --git a/pkgs/html/test/data/tokenizer/xmlViolation.test b/pkgs/html/test/data/tokenizer/xmlViolation.test
new file mode 100644
index 0000000..137d964
--- /dev/null
+++ b/pkgs/html/test/data/tokenizer/xmlViolation.test
@@ -0,0 +1,22 @@
+{"xmlViolationTests": [
+
+{"description":"Non-XML character",
+"input":"a\uFFFFb",
+"ignoreErrorOrder":true,
+"output":["ParseError",["Character","a\uFFFDb"]]},
+
+{"description":"Non-XML space",
+"input":"a\u000Cb",
+"ignoreErrorOrder":true,
+"output":[["Character","a b"]]},
+
+{"description":"Double hyphen in comment",
+"input":"<!-- foo -- bar -->",
+"output":["ParseError",["Comment"," foo - - bar "]]},
+
+{"description":"FF between attributes",
+"input":"<a b=''\u000Cc=''>",
+"output":[["StartTag","a",{"b":"","c":""}]]}
+]}
+
+
diff --git a/pkgs/html/test/data/tree-construction/adoption01.dat b/pkgs/html/test/data/tree-construction/adoption01.dat
new file mode 100644
index 0000000..787e1b0
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/adoption01.dat
@@ -0,0 +1,194 @@
+#data
+<a><p></a></p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+
+#data
+<a>1<p>2</a>3</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <p>
+| <a>
+| "2"
+| "3"
+
+#data
+<a>1<button>2</a>3</button>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <button>
+| <a>
+| "2"
+| "3"
+
+#data
+<a>1<b>2</a>3</b>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <b>
+| "2"
+| <b>
+| "3"
+
+#data
+<a>1<div>2<div>3</a>4</div>5</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <div>
+| <a>
+| "2"
+| <div>
+| <a>
+| "3"
+| "4"
+| "5"
+
+#data
+<table><a>1<p>2</a>3</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <p>
+| <a>
+| "2"
+| "3"
+| <table>
+
+#data
+<b><b><a><p></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <b>
+| <a>
+| <p>
+| <a>
+
+#data
+<b><a><b><p></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <a>
+| <b>
+| <b>
+| <p>
+| <a>
+
+#data
+<a><b><b><p></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <b>
+| <b>
+| <p>
+| <a>
+
+#data
+<p>1<s id="A">2<b id="B">3</p>4</s>5</b>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "1"
+| <s>
+| id="A"
+| "2"
+| <b>
+| id="B"
+| "3"
+| <s>
+| id="A"
+| <b>
+| id="B"
+| "4"
+| <b>
+| id="B"
+| "5"
+
+#data
+<table><a>1<td>2</td>3</table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <a>
+| "3"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "2"
+
+#data
+<table>A<td>B</td>C</table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "AC"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "B"
+
+#data
+<a><svg><tr><input></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <svg svg>
+| <svg tr>
+| <svg input>
diff --git a/pkgs/html/test/data/tree-construction/adoption02.dat b/pkgs/html/test/data/tree-construction/adoption02.dat
new file mode 100644
index 0000000..d18151b
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/adoption02.dat
@@ -0,0 +1,31 @@
+#data
+<b>1<i>2<p>3</b>4
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "1"
+| <i>
+| "2"
+| <i>
+| <p>
+| <b>
+| "3"
+| "4"
+
+#data
+<a><div><style></style><address><a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <div>
+| <a>
+| <style>
+| <address>
+| <a>
+| <a>
diff --git a/pkgs/html/test/data/tree-construction/comments01.dat b/pkgs/html/test/data/tree-construction/comments01.dat
new file mode 100644
index 0000000..44f1876
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/comments01.dat
@@ -0,0 +1,135 @@
+#data
+FOO<!-- BAR -->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -->
+| "BAZ"
+
+#data
+FOO<!-- BAR --!>BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- >BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- >BAZ -->
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX --!>BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -- >BAZ -->
+
+#data
+FOO<!---->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+FOO<!--->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+FOO<!-->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+<?xml version="1.0">Hi
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+| <head>
+| <body>
+| "Hi"
+
+#data
+<?xml version="1.0">
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?xml version
+#errors
+#document
+| <!-- ?xml version -->
+| <html>
+| <head>
+| <body>
+
+#data
+FOO<!----->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- - -->
+| "BAZ"
diff --git a/pkgs/html/test/data/tree-construction/doctype01.dat b/pkgs/html/test/data/tree-construction/doctype01.dat
new file mode 100644
index 0000000..ae45732
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/doctype01.dat
@@ -0,0 +1,370 @@
+#data
+<!DOCTYPE html>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!dOctYpE HtMl>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPEhtml>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE>Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE >Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato taco "ddd>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM taco >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM 'taco"'>Hello
+#errors
+#document
+| <!DOCTYPE potato "" "taco"">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "taco">Hello
+#errors
+#document
+| <!DOCTYPE potato "" "taco">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "tai'co">Hello
+#errors
+#document
+| <!DOCTYPE potato "" "tai'co">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEMtaco "ddd">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato grass SYSTEM taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIcgoof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC goof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "go'of">Hello
+#errors
+#document
+| <!DOCTYPE potato "go'of" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go'of'>Hello
+#errors
+#document
+| <!DOCTYPE potato "go" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go:hh of' >Hello
+#errors
+#document
+| <!DOCTYPE potato "go:hh of" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato "W3C-//dfdf" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">Hello
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE ...>Hello
+#errors
+#document
+| <!DOCTYPE ...>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [
+<!-- internal declarations -->
+]>
+#errors
+#document
+| <!DOCTYPE root-element>
+| <html>
+| <head>
+| <body>
+| "]>"
+
+#data
+<!DOCTYPE html PUBLIC
+ "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
+ "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
+#errors
+#document
+| <!DOCTYPE html "" "http://www.w3.org/DTD/HTML4-strict.dtd">
+| <html>
+| <head>
+| <body>
+| <b>
+| "Mine!"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC'-//W3C//DTD HTML 4.01//EN''http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
diff --git a/pkgs/html/test/data/tree-construction/domjs-unsafe.dat b/pkgs/html/test/data/tree-construction/domjs-unsafe.dat
new file mode 100644
index 0000000..905b94e
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/domjs-unsafe.dat
Binary files differ
diff --git a/pkgs/html/test/data/tree-construction/entities01.dat b/pkgs/html/test/data/tree-construction/entities01.dat
new file mode 100644
index 0000000..c8073b7
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/entities01.dat
@@ -0,0 +1,603 @@
+#data
+FOO>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>BAR"
+
+#data
+FOO>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>BAR"
+
+#data
+FOO> BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO> BAR"
+
+#data
+FOO>;;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>;;BAR"
+
+#data
+I'm ¬it; I tell you
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "I'm ¬it; I tell you"
+
+#data
+I'm ∉ I tell you
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "I'm ∉ I tell you"
+
+#data
+FOO& BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO& BAR"
+
+#data
+FOO&<BAR>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&"
+| <bar>
+
+#data
+FOO&&&>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&&&>BAR"
+
+#data
+FOO)BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO)BAR"
+
+#data
+FOOABAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOABAR"
+
+#data
+FOOABAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOABAR"
+
+#data
+FOO&#BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#BAR"
+
+#data
+FOO&#ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#ZOO"
+
+#data
+FOOºR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOºR"
+
+#data
+FOO&#xZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#xZOO"
+
+#data
+FOO&#XZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#XZOO"
+
+#data
+FOO)BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO)BAR"
+
+#data
+FOO䆺R
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO䆺R"
+
+#data
+FOOAZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOAZOO"
+
+#data
+FOO�ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOOxZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOxZOO"
+
+#data
+FOOyZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOyZOO"
+
+#data
+FOO€ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO€ZOO"
+
+#data
+FOOZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO‚ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‚ZOO"
+
+#data
+FOOƒZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOƒZOO"
+
+#data
+FOO„ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO„ZOO"
+
+#data
+FOO…ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO…ZOO"
+
+#data
+FOO†ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO†ZOO"
+
+#data
+FOO‡ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‡ZOO"
+
+#data
+FOOˆZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOˆZOO"
+
+#data
+FOO‰ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‰ZOO"
+
+#data
+FOOŠZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŠZOO"
+
+#data
+FOO‹ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‹ZOO"
+
+#data
+FOOŒZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŒZOO"
+
+#data
+FOOZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOOŽZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŽZOO"
+
+#data
+FOOZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOOZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO‘ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‘ZOO"
+
+#data
+FOO’ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO’ZOO"
+
+#data
+FOO“ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO“ZOO"
+
+#data
+FOO”ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO”ZOO"
+
+#data
+FOO•ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO•ZOO"
+
+#data
+FOO–ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO–ZOO"
+
+#data
+FOO—ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO—ZOO"
+
+#data
+FOO˜ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO˜ZOO"
+
+#data
+FOO™ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO™ZOO"
+
+#data
+FOOšZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOšZOO"
+
+#data
+FOO›ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO›ZOO"
+
+#data
+FOOœZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOœZOO"
+
+#data
+FOOZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOOžZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOžZOO"
+
+#data
+FOOŸZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŸZOO"
+
+#data
+FOO ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO ZOO"
+
+#data
+FOO퟿ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO�ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO�ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO�ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO�ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOOZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOOZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO􈟔ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOOZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO�ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO�ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
diff --git a/pkgs/html/test/data/tree-construction/entities02.dat b/pkgs/html/test/data/tree-construction/entities02.dat
new file mode 100644
index 0000000..e2fb42a
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/entities02.dat
@@ -0,0 +1,249 @@
+#data
+<div bar="ZZ>YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>YY"
+
+#data
+<div bar="ZZ&"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar='ZZ&'></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar=ZZ&></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar="ZZ>=YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>=YY"
+
+#data
+<div bar="ZZ>0YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>0YY"
+
+#data
+<div bar="ZZ>9YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>9YY"
+
+#data
+<div bar="ZZ>aYY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>aYY"
+
+#data
+<div bar="ZZ>ZYY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>ZYY"
+
+#data
+<div bar="ZZ> YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ> YY"
+
+#data
+<div bar="ZZ>"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar='ZZ>'></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar=ZZ>></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar="ZZ£_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&prod_id=23"
+
+#data
+<div bar="ZZ£_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ∏_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ∏_id=23"
+
+#data
+<div bar="ZZ£=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£=23"
+
+#data
+<div bar="ZZ&prod=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&prod=23"
+
+#data
+<div>ZZ£_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£_id=23"
+
+#data
+<div>ZZ&prod_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ&prod_id=23"
+
+#data
+<div>ZZ£_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£_id=23"
+
+#data
+<div>ZZ∏_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ∏_id=23"
+
+#data
+<div>ZZ£=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£=23"
+
+#data
+<div>ZZ&prod=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ&prod=23"
diff --git a/pkgs/html/test/data/tree-construction/html5test-com.dat b/pkgs/html/test/data/tree-construction/html5test-com.dat
new file mode 100644
index 0000000..d7cb71d
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/html5test-com.dat
@@ -0,0 +1,246 @@
+#data
+<div<div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div<div>
+
+#data
+<div foo<bar=''>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo<bar=""
+
+#data
+<div foo=`bar`>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo="`bar`"
+
+#data
+<div \"foo=''>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| \"foo=""
+
+#data
+<a href='\nbar'></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="\nbar"
+
+#data
+<!DOCTYPE html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+⟨⟩
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "⟨⟩"
+
+#data
+'
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "'"
+
+#data
+ⅈ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "ⅈ"
+
+#data
+𝕂
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "𝕂"
+
+#data
+∉
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "∉"
+
+#data
+<?import namespace="foo" implementation="#bar">
+#errors
+#document
+| <!-- ?import namespace="foo" implementation="#bar" -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!--foo--bar-->
+#errors
+#document
+| <!-- foo--bar -->
+| <html>
+| <head>
+| <body>
+
+#data
+<![CDATA[x]]>
+#errors
+#document
+| <!-- [CDATA[x]] -->
+| <html>
+| <head>
+| <body>
+
+#data
+<textarea><!--</textarea>--></textarea>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--"
+| "-->"
+
+#data
+<textarea><!--</textarea>-->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--"
+| "-->"
+
+#data
+<style><!--</style>--></style>
+#errors
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "-->"
+
+#data
+<style><!--</style>-->
+#errors
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "-->"
+
+#data
+<ul><li>A </li> <li>B</li></ul>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| "A "
+| " "
+| <li>
+| "B"
+
+#data
+<table><form><input type=hidden><input></form><div></div></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <input>
+| <div>
+| <table>
+| <form>
+| <input>
+| type="hidden"
+
+#data
+<i>A<b>B<p></i>C</b>D
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <i>
+| "A"
+| <b>
+| "B"
+| <b>
+| <p>
+| <b>
+| <i>
+| "C"
+| "D"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<svg></svg>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<math></math>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
diff --git a/pkgs/html/test/data/tree-construction/inbody01.dat b/pkgs/html/test/data/tree-construction/inbody01.dat
new file mode 100644
index 0000000..3f2bd37
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/inbody01.dat
@@ -0,0 +1,43 @@
+#data
+<button>1</foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| "1"
+
+#data
+<foo>1<p>2</foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| "1"
+| <p>
+| "2"
+
+#data
+<dd>1</foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <dd>
+| "1"
+
+#data
+<foo>1<dd>2</foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| "1"
+| <dd>
+| "2"
diff --git a/pkgs/html/test/data/tree-construction/isindex.dat b/pkgs/html/test/data/tree-construction/isindex.dat
new file mode 100644
index 0000000..88325ff
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/isindex.dat
@@ -0,0 +1,40 @@
+#data
+<isindex>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| <hr>
+
+#data
+<isindex name="A" action="B" prompt="C" foo="D">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| action="B"
+| <hr>
+| <label>
+| "C"
+| <input>
+| foo="D"
+| name="isindex"
+| <hr>
+
+#data
+<form><isindex>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
diff --git a/pkgs/html/test/data/tree-construction/pending-spec-changes-plain-text-unsafe.dat b/pkgs/html/test/data/tree-construction/pending-spec-changes-plain-text-unsafe.dat
new file mode 100644
index 0000000..a5ebb1e
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/pending-spec-changes-plain-text-unsafe.dat
Binary files differ
diff --git a/pkgs/html/test/data/tree-construction/pending-spec-changes.dat b/pkgs/html/test/data/tree-construction/pending-spec-changes.dat
new file mode 100644
index 0000000..5a92084
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/pending-spec-changes.dat
@@ -0,0 +1,52 @@
+#data
+<input type="hidden"><frameset>
+#errors
+21: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+31: “frameset” start tag seen.
+31: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><table><caption><svg>foo</table>bar
+#errors
+47: End tag “table” did not match the name of the current open element (“svg”).
+47: “table” closed but “caption” was still open.
+47: End tag “table” seen, but there were open elements.
+36: Unclosed element “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| "foo"
+| "bar"
+
+#data
+<table><tr><td><svg><desc><td></desc><circle>
+#errors
+7: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+30: A table cell was implicitly closed, but there were open elements.
+26: Unclosed element “desc”.
+20: Unclosed element “svg”.
+37: Stray end tag “desc”.
+45: End of file seen and there were open elements.
+45: Unclosed element “circle”.
+7: Unclosed element “table”.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg desc>
+| <td>
+| <circle>
diff --git a/pkgs/html/test/data/tree-construction/plain-text-unsafe.dat b/pkgs/html/test/data/tree-construction/plain-text-unsafe.dat
new file mode 100644
index 0000000..04cc11f
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/plain-text-unsafe.dat
Binary files differ
diff --git a/pkgs/html/test/data/tree-construction/regression_tests.dat b/pkgs/html/test/data/tree-construction/regression_tests.dat
new file mode 100644
index 0000000..aedb804
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/regression_tests.dat
@@ -0,0 +1,13 @@
+#data
+<button><p></button><button></button>
+#info
+Regression test for https://github.com/dart-lang/html/issues/122
+#errors
+Errors are currently untested: https://github.com/dart-lang/html/issues/127
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| <p>
+| <button>
diff --git a/pkgs/html/test/data/tree-construction/scriptdata01.dat b/pkgs/html/test/data/tree-construction/scriptdata01.dat
new file mode 100644
index 0000000..76b67f4
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/scriptdata01.dat
@@ -0,0 +1,308 @@
+#data
+FOO<script>'Hello'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'Hello'"
+| "BAR"
+
+#data
+FOO<script></script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script >BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script/>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script/ >BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script type="text/plain"></scriptx>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "</scriptx>BAR"
+
+#data
+FOO<script></script foo=">" dd>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script>'<'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<'"
+| "BAR"
+
+#data
+FOO<script>'<!'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!'"
+| "BAR"
+
+#data
+FOO<script>'<!-'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-'"
+| "BAR"
+
+#data
+FOO<script>'<!--'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!--'"
+| "BAR"
+
+#data
+FOO<script>'<!---'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!---'"
+| "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-->'"
+| "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-->'"
+| "BAR"
+
+#data
+FOO<script>'<!-- potato'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- potato'"
+| "BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- <sCrIpt'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt>'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> -'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> --'</script>BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt> -->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- <sCrIpt> -->'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --!>'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> --!>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -- >'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> -- >'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt '</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt '</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt/'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt\'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt\'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR</script>QUX
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt/'</script>BAR"
+| "QUX"
diff --git a/pkgs/html/test/data/tree-construction/scripted/adoption01.dat b/pkgs/html/test/data/tree-construction/scripted/adoption01.dat
new file mode 100644
index 0000000..4e08d0e
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/scripted/adoption01.dat
@@ -0,0 +1,15 @@
+#data
+<p><b id="A"><script>document.getElementById("A").id = "B"</script></p>TEXT</b>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| id="B"
+| <script>
+| "document.getElementById("A").id = "B""
+| <b>
+| id="A"
+| "TEXT"
diff --git a/pkgs/html/test/data/tree-construction/scripted/ark.dat b/pkgs/html/test/data/tree-construction/scripted/ark.dat
new file mode 100644
index 0000000..acbac41
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/scripted/ark.dat
@@ -0,0 +1,26 @@
+#data
+<p><font size=4><font size=4><font size=4><script>document.getElementsByTagName("font")[2].setAttribute("size", "5");</script><font size=4><p>X
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="5"
+| <script>
+| "document.getElementsByTagName("font")[2].setAttribute("size", "5");"
+| <font>
+| size="4"
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| "X"
diff --git a/pkgs/html/test/data/tree-construction/scripted/webkit01.dat b/pkgs/html/test/data/tree-construction/scripted/webkit01.dat
new file mode 100644
index 0000000..ef4a41c
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/scripted/webkit01.dat
@@ -0,0 +1,28 @@
+#data
+1<script>document.write("2")</script>3
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "1"
+| <script>
+| "document.write("2")"
+| "23"
+
+#data
+1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "1"
+| <script>
+| "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")"
+| <script>
+| "document.write('2')"
+| "2"
+| <script>
+| "document.write('3')"
+| "34"
diff --git a/pkgs/html/test/data/tree-construction/tables01.dat b/pkgs/html/test/data/tree-construction/tables01.dat
new file mode 100644
index 0000000..c4b47e4
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tables01.dat
@@ -0,0 +1,212 @@
+#data
+<table><th>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <th>
+
+#data
+<table><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><col foo='bar'>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| foo="bar"
+
+#data
+<table><colgroup></html>foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "foo"
+| <table>
+| <colgroup>
+
+#data
+<table></table><p>foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <p>
+| "foo"
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><select><option>3</select></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "3"
+| <table>
+
+#data
+<table><select><table></table></select></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <table>
+
+#data
+<table><select></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+
+#data
+<table><select><option>A<tr><td>B</td></tr></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "A"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "B"
+
+#data
+<table><td></body></caption></col></colgroup></html>foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "foo"
+
+#data
+<table><td>A</table>B
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+| "B"
+
+#data
+<table><tr><caption>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <caption>
+
+#data
+<table><tr></body></caption></col></colgroup></html></td></th><td>foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "foo"
+
+#data
+<table><td><tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <tr>
+
+#data
+<table><td><button><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <button>
+| <td>
+
+#data
+<table><tr><td><svg><desc><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg desc>
+| <td>
diff --git a/pkgs/html/test/data/tree-construction/tests1.dat b/pkgs/html/test/data/tree-construction/tests1.dat
new file mode 100644
index 0000000..cbf8bdd
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests1.dat
@@ -0,0 +1,1952 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<p>One<p>Two
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "One"
+| <p>
+| "Two"
+
+#data
+Line1<br>Line2<br>Line3<br>Line4
+#errors
+Line: 1 Col: 5 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Line1"
+| <br>
+| "Line2"
+| <br>
+| "Line3"
+| <br>
+| "Line4"
+
+#data
+<html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head><body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head><body></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (body).
+Line: 1 Col: 26 Unexpected end tag (html).
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<head></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</head>
+#errors
+Line: 1 Col: 7 Unexpected end tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</body>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (body) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</html>
+#errors
+Line: 1 Col: 7 Unexpected end tag (html). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<b><table><td></b><i></table>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 30 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+| "X"
+
+#data
+<h1>Hello<h2>World
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Heading cannot be a child of another heading.
+18: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| "Hello"
+| <h2>
+| "World"
+
+#data
+<a><p>X<a>Y</a>Z</p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 10 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+| "X"
+| <a>
+| "Y"
+| "Z"
+
+#data
+<b><button>foo</b>bar
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <button>
+| <b>
+| "foo"
+| "bar"
+
+#data
+<!DOCTYPE html><span><button>foo</span>bar
+#errors
+39: End tag “span” seen but there were unclosed elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <span>
+| <button>
+| "foobar"
+
+#data
+<p><b><div><marquee></p></b></div>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <div>
+| <b>
+| <marquee>
+| <p>
+| "X"
+
+#data
+<script><div></script></div><title><p></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end tag (div). Ignored.
+#document
+| <html>
+| <head>
+| <script>
+| "<div>"
+| <title>
+| "<p>"
+| <body>
+| <p>
+| <p>
+
+#data
+<!--><div>--<!-->
+#errors
+Line: 1 Col: 5 Incorrect comment.
+Line: 1 Col: 10 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Incorrect comment.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <!-- -->
+| <html>
+| <head>
+| <body>
+| <div>
+| "--"
+| <!-- -->
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <hr>
+| <p>
+
+#data
+<select><b><option><select><option></b></select>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 49 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+| "X"
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 63 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 64 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| <table>
+| <a>
+| <a>
+| <b>
+| "X"
+| "C"
+| <a>
+| "Y"
+
+#data
+<a X>0<b>1<a Y>2
+#errors
+Line: 1 Col: 5 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| x=""
+| "0"
+| <b>
+| "1"
+| <b>
+| <a>
+| y=""
+| "2"
+
+#data
+<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X-->
+#errors
+Line: 1 Col: 7 Unexpected '-' after '--' found in comment.
+Line: 1 Col: 14 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected start tag (b) in table context caused voodoo mode.
+Line: 1 Col: 48 Unexpected implied end tag (b) in the table phase.
+Line: 1 Col: 48 Unexpected table cell start tag (th) in the table body phase.
+Line: 1 Col: 63 Got table cell end tag (th) while required end tags are missing.
+Line: 1 Col: 71 Unexpected end of file. Expected table content.
+#document
+| <!-- - -->
+| <html>
+| <head>
+| <body>
+| <font>
+| <div>
+| "helloexcite!"
+| <b>
+| "me!"
+| <table>
+| <tbody>
+| <tr>
+| <th>
+| <i>
+| "please!"
+| <!-- X -->
+
+#data
+<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do-->
+#errors
+Line: 1 Col: 61 Unexpected end tag (li). Missing end tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <li>
+| "hello"
+| <li>
+| "world"
+| <ul>
+| "how"
+| <li>
+| "do"
+| "you"
+| <!-- do -->
+
+#data
+<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E
+#errors
+Line: 1 Col: 54 Unexpected end tag (option) in the select phase. Ignored.
+Line: 1 Col: 55 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+| <option>
+| "B"
+| <optgroup>
+| "C"
+| <select>
+| "DE"
+
+#data
+<
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "<"
+
+#data
+<#
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "<#"
+
+#data
+</
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected end of file.
+Line: 1 Col: 2 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "</"
+
+#data
+</#
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character '#' found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?#
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?# -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!#
+#errors
+Line: 1 Col: 3 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?COMMENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 11 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COMMENT? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!COMMENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 10 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COMMENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+</ COMMENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COMMENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?COM--MENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 13 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COM--MENT? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!COM--MENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COM--MENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+</ COM--MENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 14 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COM--MENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><style> EOF
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| " EOF"
+| <body>
+
+#data
+<!DOCTYPE html><script> <!-- </script> --> </script> EOF
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| " <!-- "
+| " "
+| <body>
+| "--> EOF"
+
+#data
+<b><p></b>TEST
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 10 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <p>
+| <b>
+| "TEST"
+
+#data
+<p id=a><b><p id=b></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (p). Ignored.
+Line: 1 Col: 23 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| id="a"
+| <b>
+| <p>
+| id="b"
+| "TEST"
+
+#data
+<b id=a><p><b id=b></p></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (p). Ignored.
+Line: 1 Col: 27 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 31 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| id="a"
+| <p>
+| <b>
+| id="b"
+| "TEST"
+
+#data
+<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body>
+#errors
+Line: 1 Col: 61 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "U-test"
+| <body>
+| <div>
+| <p>
+| "Test"
+| <u>
+
+#data
+<!DOCTYPE html><font><table></font></table></font>
+#errors
+Line: 1 Col: 35 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 35 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <table>
+
+#data
+<font><p>hello<b>cruel</font>world
+#errors
+Line: 1 Col: 6 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <font>
+| "hello"
+| <b>
+| "cruel"
+| <b>
+| "world"
+
+#data
+<b>Test</i>Test
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 11 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "TestTest"
+
+#data
+<b>A<cite>B<div>C
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| "C"
+
+#data
+<b>A<cite>B<div>C</cite>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end tag (cite). Ignored.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| "CD"
+
+#data
+<b>A<cite>B<div>C</b>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 21 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 22 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| <b>
+| "C"
+| "D"
+
+#data
+
+#errors
+Line: 1 Col: 0 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<DIV>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 5 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<DIV> abc
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 9 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc"
+
+#data
+<DIV> abc <B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+
+#data
+<DIV> abc <B> def
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def"
+
+#data
+<DIV> abc <B> def <I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+
+#data
+<DIV> abc <B> def <I> ghi
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi"
+
+#data
+<DIV> abc <B> def <I> ghi <P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <p>
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <p>
+| " jkl"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <b>
+| " jkl "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <b>
+| " jkl "
+| " mno"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 60 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr "
+| " stu"
+
+#data
+<test attribute---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
+#errors
+Line: 1 Col: 1040 Unexpected start tag (test). Expected DOCTYPE.
+Line: 1 Col: 1040 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <test>
+| attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------=""
+
+#data
+<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 39 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 39 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 39 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 45 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "aba"
+| <a>
+| href="foo"
+| "br"
+| <a>
+| href="foo"
+| "x"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "aoe"
+
+#data
+<a href="blah">aba<table><tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 60 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "abax"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "br"
+| "aoe"
+
+#data
+<table><a href="blah">aba<tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 29 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "aba"
+| <a>
+| href="blah"
+| "x"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "br"
+| <a>
+| href="blah"
+| "aoe"
+
+#data
+<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa
+#errors
+Line: 1 Col: 10 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 45 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="a"
+| "aa"
+| <marquee>
+| "aa"
+| <a>
+| href="b"
+| "bb"
+| "aa"
+
+#data
+<wbr><strike><code></strike><code><strike></code>
+#errors
+Line: 1 Col: 5 Unexpected start tag (wbr). Expected DOCTYPE.
+Line: 1 Col: 28 End tag (strike) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 49 Unexpected end tag (code). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <wbr>
+| <strike>
+| <code>
+| <code>
+| <code>
+| <strike>
+
+#data
+<!DOCTYPE html><spacer>foo
+#errors
+26: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <spacer>
+| "foo"
+
+#data
+<title><meta></title><link><title><meta></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "<meta>"
+| <link>
+| <title>
+| "<meta>"
+| <body>
+
+#data
+<style><!--</style><meta><script>--><link></script>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <meta>
+| <script>
+| "--><link>"
+| <body>
+
+#data
+<head><meta></head><link>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected start tag (link) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <meta>
+| <link>
+| <body>
+
+#data
+<table><tr><tr><td><td><span><th><span>X</table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 33 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 48 Got table cell end tag (th) while required end tags are missing.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <tr>
+| <td>
+| <td>
+| <span>
+| <th>
+| <span>
+| "X"
+
+#data
+<body><body><base><link><meta><title><p></title><body><p></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (body).
+Line: 1 Col: 54 Unexpected start tag (body).
+Line: 1 Col: 64 Unexpected end tag (p). Missing end tag (body).
+#document
+| <html>
+| <head>
+| <body>
+| <base>
+| <link>
+| <meta>
+| <title>
+| "<p>"
+| <p>
+
+#data
+<textarea><p></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<p>"
+
+#data
+<p><image></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (image). Treated as img.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <img>
+
+#data
+<a><table><a></table><p><a><div><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 13 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 13 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 21 Unexpected end tag (table). Expected end tag (a).
+Line: 1 Col: 27 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 27 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 32 Unexpected end tag (p). Ignored.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 35 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <p>
+| <a>
+| <div>
+| <a>
+
+#data
+<head></p><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <meta>
+| <body>
+| <p>
+
+#data
+<head></html><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected start tag (meta).
+#document
+| <html>
+| <head>
+| <body>
+| <meta>
+| <p>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<b><table><td></b><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<h1><h2>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+8: Heading cannot be a child of another heading.
+8: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| <h2>
+
+#data
+<a><p><a></a></p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 9 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 21 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+| <a>
+
+#data
+<b><button></b></button></b>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <button>
+| <b>
+
+#data
+<p><b><div><marquee></p></b></div>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <div>
+| <b>
+| <marquee>
+| <p>
+
+#data
+<script></script></div><title></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (div). Ignored.
+#document
+| <html>
+| <head>
+| <script>
+| <title>
+| <body>
+| <p>
+| <p>
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <hr>
+| <p>
+
+#data
+<select><b><option><select><option></b></select>
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 48 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+
+#data
+<html><head><title></title><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| <body>
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 54 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 54 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| <table>
+| <a>
+| <a>
+
+#data
+<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul>
+#errors
+Line: 1 Col: 4 Unexpected start tag (ul). Expected DOCTYPE.
+Line: 1 Col: 45 Missing end tag (div, li).
+Line: 1 Col: 58 Missing end tag (address, li).
+Line: 1 Col: 69 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| <li>
+| <li>
+| <li>
+| <div>
+| <li>
+| <address>
+| <li>
+| <b>
+| <em>
+| <li>
+
+#data
+<ul><li><ul></li><li>a</li></ul></li></ul>
+#errors
+XXX: fix me
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <ul>
+| <li>
+| "a"
+
+#data
+<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+| <frameset>
+| <frame>
+| <noframes>
+
+#data
+<h1><table><td><h3></table><h3></h1>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+15: “td” start tag in table body.
+27: Unclosed elements.
+31: Heading cannot be a child of another heading.
+36: End tag “h1” seen but there were unclosed elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <h3>
+| <h3>
+
+#data
+<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| <colgroup>
+| <col>
+| <col>
+| <col>
+| <colgroup>
+| <col>
+| <col>
+| <thead>
+| <tr>
+| <td>
+
+#data
+<table><col><tbody><col><tr><col><td><col></table><col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 55 Unexpected start tag col. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <td>
+| <colgroup>
+| <col>
+
+#data
+<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 52 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 80 Unexpected start tag colgroup. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <tbody>
+| <colgroup>
+| <tbody>
+| <tr>
+| <colgroup>
+| <tbody>
+| <tr>
+| <td>
+| <colgroup>
+
+#data
+</strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
+Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
+Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
+Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
+Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
+Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
+Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
+Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
+Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
+Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
+Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
+Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
+Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
+Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
+Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
+Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
+Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
+Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
+Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
+Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
+Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
+Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 140 This element (img) has no end tag.
+Line: 1 Col: 148 Unexpected end tag (title). Ignored.
+Line: 1 Col: 155 Unexpected end tag (span). Ignored.
+Line: 1 Col: 163 Unexpected end tag (style). Ignored.
+Line: 1 Col: 172 Unexpected end tag (script). Ignored.
+Line: 1 Col: 180 Unexpected end tag (table). Ignored.
+Line: 1 Col: 185 Unexpected end tag (th). Ignored.
+Line: 1 Col: 190 Unexpected end tag (td). Ignored.
+Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 203 This element (frame) has no end tag.
+Line: 1 Col: 210 This element (area) has no end tag.
+Line: 1 Col: 217 Unexpected end tag (link). Ignored.
+Line: 1 Col: 225 This element (param) has no end tag.
+Line: 1 Col: 230 This element (hr) has no end tag.
+Line: 1 Col: 238 This element (input) has no end tag.
+Line: 1 Col: 244 Unexpected end tag (col). Ignored.
+Line: 1 Col: 251 Unexpected end tag (base). Ignored.
+Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 269 This element (basefont) has no end tag.
+Line: 1 Col: 279 This element (bgsound) has no end tag.
+Line: 1 Col: 287 This element (embed) has no end tag.
+Line: 1 Col: 296 This element (spacer) has no end tag.
+Line: 1 Col: 300 Unexpected end tag (p). Ignored.
+Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 460 This element (wbr) has no end tag.
+Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 513 Unexpected end tag (html). Ignored.
+Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 520 Unexpected end tag (head). Ignored.
+Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 537 This element (image) has no end tag.
+Line: 1 Col: 547 This element (isindex) has no end tag.
+Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 599 Unexpected end tag (option). Ignored.
+Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+| <p>
+
+#data
+<table><tr></strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode.
+Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode.
+Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode.
+Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode.
+Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode.
+Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (blink). Ignored.
+Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode.
+Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode.
+Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag.
+Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode.
+Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode.
+Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode.
+Line: 1 Col: 99 Unexpected end tag (select). Ignored.
+Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode.
+Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag.
+Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode.
+Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag.
+Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode.
+Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag.
+Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode.
+Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag.
+Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode.
+Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag.
+Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode.
+Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag.
+Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored.
+Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode.
+Line: 1 Col: 141 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode.
+Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode.
+Line: 1 Col: 151 This element (img) has no end tag.
+Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode.
+Line: 1 Col: 159 Unexpected end tag (title). Ignored.
+Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 166 Unexpected end tag (span). Ignored.
+Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode.
+Line: 1 Col: 174 Unexpected end tag (style). Ignored.
+Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode.
+Line: 1 Col: 183 Unexpected end tag (script). Ignored.
+Line: 1 Col: 196 Unexpected end tag (th). Ignored.
+Line: 1 Col: 201 Unexpected end tag (td). Ignored.
+Line: 1 Col: 206 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 214 This element (frame) has no end tag.
+Line: 1 Col: 221 This element (area) has no end tag.
+Line: 1 Col: 228 Unexpected end tag (link). Ignored.
+Line: 1 Col: 236 This element (param) has no end tag.
+Line: 1 Col: 241 This element (hr) has no end tag.
+Line: 1 Col: 249 This element (input) has no end tag.
+Line: 1 Col: 255 Unexpected end tag (col). Ignored.
+Line: 1 Col: 262 Unexpected end tag (base). Ignored.
+Line: 1 Col: 269 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 280 This element (basefont) has no end tag.
+Line: 1 Col: 290 This element (bgsound) has no end tag.
+Line: 1 Col: 298 This element (embed) has no end tag.
+Line: 1 Col: 307 This element (spacer) has no end tag.
+Line: 1 Col: 311 Unexpected end tag (p). Ignored.
+Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 331 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 350 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 366 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 404 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 471 This element (wbr) has no end tag.
+Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 524 Unexpected end tag (html). Ignored.
+Line: 1 Col: 524 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 531 Unexpected end tag (head). Ignored.
+Line: 1 Col: 540 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 548 This element (image) has no end tag.
+Line: 1 Col: 558 This element (isindex) has no end tag.
+Line: 1 Col: 568 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 590 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 610 Unexpected end tag (option). Ignored.
+Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 633 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+| <table>
+| <tbody>
+| <tr>
+| <p>
+
+#data
+<frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
diff --git a/pkgs/html/test/data/tree-construction/tests10.dat b/pkgs/html/test/data/tree-construction/tests10.dat
new file mode 100644
index 0000000..4f8df86
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests10.dat
@@ -0,0 +1,799 @@
+#data
+<!DOCTYPE html><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!DOCTYPE html><svg></svg><![CDATA[a]]>
+#errors
+29: Bogus comment
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <!-- [CDATA[a]] -->
+
+#data
+<!DOCTYPE html><body><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!DOCTYPE html><body><select><svg></svg></select>
+#errors
+35: Stray “svg” start tag.
+42: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!DOCTYPE html><body><select><option><svg></svg></option></select>
+#errors
+43: Stray “svg” start tag.
+50: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!DOCTYPE html><body><table><svg></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+41: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+53: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+58: Stray end tag “g”.
+65: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table>
+#errors
+41: Start tag “svg” seen in “table”.
+53: Stray end tag “g”.
+65: Stray end tag “g”.
+72: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+| <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table>
+#errors
+45: Start tag “svg” seen in “table”.
+57: Stray end tag “g”.
+69: Stray end tag “g”.
+76: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+70: HTML start tag “p” in a foreign namespace context.
+81: “table” closed but “caption” was still open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux
+#errors
+78: “table” closed but “caption” was still open.
+78: Unclosed elements on stack.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+44: Start tag “svg” seen in “table”.
+56: Stray end tag “g”.
+68: Stray end tag “g”.
+71: HTML start tag “p” in a foreign namespace context.
+71: Start tag “p” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+| <table>
+| <colgroup>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+50: Stray “svg” start tag.
+54: Stray “g” start tag.
+62: Stray end tag “g”
+66: Stray “g” start tag.
+74: Stray end tag “g”
+77: Stray “p” start tag.
+88: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| "foobarbaz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+36: Start tag “select” seen in “table”.
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+54: Stray end tag “g”
+58: Stray “g” start tag.
+66: Stray end tag “g”
+69: Stray “p” start tag.
+80: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "foobarbaz"
+| <table>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz
+#errors
+41: Stray “svg” start tag.
+68: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz
+#errors
+34: Stray “svg” start tag.
+61: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><frameset><svg><g></g><g></g><p><span>
+#errors
+31: Stray “svg” start tag.
+35: Stray “g” start tag.
+40: Stray end tag “g”
+44: Stray “g” start tag.
+49: Stray end tag “g”
+52: Stray “p” start tag.
+58: Stray “span” start tag.
+58: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span>
+#errors
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+51: Stray end tag “g”
+55: Stray “g” start tag.
+60: Stray end tag “g”
+63: Stray “p” start tag.
+69: Stray “span” start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| <svg svg>
+| xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+| "bar"
+
+#data
+<svg></path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<div><svg></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| "a"
+
+#data
+<div><svg><path></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| "a"
+
+#data
+<div><svg><path></svg><path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <path>
+
+#data
+<div><svg><path><foreignObject><math></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <math math>
+| "a"
+
+#data
+<div><svg><path><foreignObject><p></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <p>
+| "a"
+
+#data
+<!DOCTYPE html><svg><desc><div><svg><ul>a
+#errors
+40: HTML start tag “ul” in a foreign namespace context.
+41: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg desc>
+| <div>
+| <svg svg>
+| <ul>
+| "a"
+
+#data
+<!DOCTYPE html><svg><desc><svg><ul>a
+#errors
+35: HTML start tag “ul” in a foreign namespace context.
+36: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg desc>
+| <svg svg>
+| <ul>
+| "a"
+
+#data
+<!DOCTYPE html><p><svg><desc><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <svg svg>
+| <svg desc>
+| <p>
+
+#data
+<!DOCTYPE html><p><svg><title><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <svg svg>
+| <svg title>
+| <p>
+
+#data
+<div><svg><path><foreignObject><p></foreignObject><p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <p>
+| <p>
+
+#data
+<math><mi><div><object><div><span></span></div></object></div></mi><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <div>
+| <object>
+| <div>
+| <span>
+| <math mi>
+
+#data
+<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <div>
+| <math mi>
+
+#data
+<svg><script></script><path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg script>
+| <svg path>
+
+#data
+<table><svg></svg><tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<math><mi><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <math mglyph>
+
+#data
+<math><mi><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <math malignmark>
+
+#data
+<math><mo><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mo>
+| <math mglyph>
+
+#data
+<math><mo><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mo>
+| <math malignmark>
+
+#data
+<math><mn><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| <math mglyph>
+
+#data
+<math><mn><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| <math malignmark>
+
+#data
+<math><ms><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math ms>
+| <math mglyph>
+
+#data
+<math><ms><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math ms>
+| <math malignmark>
+
+#data
+<math><mtext><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <math mglyph>
+
+#data
+<math><mtext><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <math malignmark>
+
+#data
+<math><annotation-xml><svg></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><div><math><mi></mi></math><span></span></div></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <math math>
+| <math mi>
+| <span>
+| <svg path>
+| <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><math><mi><svg></svg></mi><mo></mo></math><span></span></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <svg foreignObject>
+| <math math>
+| <math mi>
+| <svg svg>
+| <math mo>
+| <span>
+| <svg path>
+| <math mi>
diff --git a/pkgs/html/test/data/tree-construction/tests11.dat b/pkgs/html/test/data/tree-construction/tests11.dat
new file mode 100644
index 0000000..638cde4
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests11.dat
@@ -0,0 +1,482 @@
+#data
+<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' DIFFUSECONSTANT='' EDGEMODE='' EXTERNALRESOURCESREQUIRED='' FILTERRES='' FILTERUNITS='' GLYPHREF='' GRADIENTTRANSFORM='' GRADIENTUNITS='' KERNELMATRIX='' KERNELUNITLENGTH='' KEYPOINTS='' KEYSPLINES='' KEYTIMES='' LENGTHADJUST='' LIMITINGCONEANGLE='' MARKERHEIGHT='' MARKERUNITS='' MARKERWIDTH='' MASKCONTENTUNITS='' MASKUNITS='' NUMOCTAVES='' PATHLENGTH='' PATTERNCONTENTUNITS='' PATTERNTRANSFORM='' PATTERNUNITS='' POINTSATX='' POINTSATY='' POINTSATZ='' PRESERVEALPHA='' PRESERVEASPECTRATIO='' PRIMITIVEUNITS='' REFX='' REFY='' REPEATCOUNT='' REPEATDUR='' REQUIREDEXTENSIONS='' REQUIREDFEATURES='' SPECULARCONSTANT='' SPECULAREXPONENT='' SPREADMETHOD='' STARTOFFSET='' STDDEVIATION='' STITCHTILES='' SURFACESCALE='' SYSTEMLANGUAGE='' TABLEVALUES='' TARGETX='' TARGETY='' TEXTLENGTH='' VIEWBOX='' VIEWTARGET='' XCHANNELSELECTOR='' YCHANNELSELECTOR='' ZOOMANDPAN=''></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' contentscripttype='' contentstyletype='' diffuseconstant='' edgemode='' externalresourcesrequired='' filterres='' filterunits='' glyphref='' gradienttransform='' gradientunits='' kernelmatrix='' kernelunitlength='' keypoints='' keysplines='' keytimes='' lengthadjust='' limitingconeangle='' markerheight='' markerunits='' markerwidth='' maskcontentunits='' maskunits='' numoctaves='' pathlength='' patterncontentunits='' patterntransform='' patternunits='' pointsatx='' pointsaty='' pointsatz='' preservealpha='' preserveaspectratio='' primitiveunits='' refx='' refy='' repeatcount='' repeatdur='' requiredextensions='' requiredfeatures='' specularconstant='' specularexponent='' spreadmethod='' startoffset='' stddeviation='' stitchtiles='' surfacescale='' systemlanguage='' tablevalues='' targetx='' targety='' textlength='' viewbox='' viewtarget='' xchannelselector='' ychannelselector='' zoomandpan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| attributename=""
+| attributetype=""
+| basefrequency=""
+| baseprofile=""
+| calcmode=""
+| clippathunits=""
+| contentscripttype=""
+| contentstyletype=""
+| diffuseconstant=""
+| edgemode=""
+| externalresourcesrequired=""
+| filterres=""
+| filterunits=""
+| glyphref=""
+| gradienttransform=""
+| gradientunits=""
+| kernelmatrix=""
+| kernelunitlength=""
+| keypoints=""
+| keysplines=""
+| keytimes=""
+| lengthadjust=""
+| limitingconeangle=""
+| markerheight=""
+| markerunits=""
+| markerwidth=""
+| maskcontentunits=""
+| maskunits=""
+| numoctaves=""
+| pathlength=""
+| patterncontentunits=""
+| patterntransform=""
+| patternunits=""
+| pointsatx=""
+| pointsaty=""
+| pointsatz=""
+| preservealpha=""
+| preserveaspectratio=""
+| primitiveunits=""
+| refx=""
+| refy=""
+| repeatcount=""
+| repeatdur=""
+| requiredextensions=""
+| requiredfeatures=""
+| specularconstant=""
+| specularexponent=""
+| spreadmethod=""
+| startoffset=""
+| stddeviation=""
+| stitchtiles=""
+| surfacescale=""
+| systemlanguage=""
+| tablevalues=""
+| targetx=""
+| targety=""
+| textlength=""
+| viewbox=""
+| viewtarget=""
+| xchannelselector=""
+| ychannelselector=""
+| zoomandpan=""
+
+#data
+<!DOCTYPE html><body><svg><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><body><svg><altglyph /><altglyphdef /><altglyphitem /><animatecolor /><animatemotion /><animatetransform /><clippath /><feblend /><fecolormatrix /><fecomponenttransfer /><fecomposite /><feconvolvematrix /><fediffuselighting /><fedisplacementmap /><fedistantlight /><feflood /><fefunca /><fefuncb /><fefuncg /><fefuncr /><fegaussianblur /><feimage /><femerge /><femergenode /><femorphology /><feoffset /><fepointlight /><fespecularlighting /><fespotlight /><fetile /><feturbulence /><foreignobject /><glyphref /><lineargradient /><radialgradient /><textpath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><BODY><SVG><ALTGLYPH /><ALTGLYPHDEF /><ALTGLYPHITEM /><ANIMATECOLOR /><ANIMATEMOTION /><ANIMATETRANSFORM /><CLIPPATH /><FEBLEND /><FECOLORMATRIX /><FECOMPONENTTRANSFER /><FECOMPOSITE /><FECONVOLVEMATRIX /><FEDIFFUSELIGHTING /><FEDISPLACEMENTMAP /><FEDISTANTLIGHT /><FEFLOOD /><FEFUNCA /><FEFUNCB /><FEFUNCG /><FEFUNCR /><FEGAUSSIANBLUR /><FEIMAGE /><FEMERGE /><FEMERGENODE /><FEMORPHOLOGY /><FEOFFSET /><FEPOINTLIGHT /><FESPECULARLIGHTING /><FESPOTLIGHT /><FETILE /><FETURBULENCE /><FOREIGNOBJECT /><GLYPHREF /><LINEARGRADIENT /><RADIALGRADIENT /><TEXTPATH /></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><body><math><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math altglyph>
+| <math altglyphdef>
+| <math altglyphitem>
+| <math animatecolor>
+| <math animatemotion>
+| <math animatetransform>
+| <math clippath>
+| <math feblend>
+| <math fecolormatrix>
+| <math fecomponenttransfer>
+| <math fecomposite>
+| <math feconvolvematrix>
+| <math fediffuselighting>
+| <math fedisplacementmap>
+| <math fedistantlight>
+| <math feflood>
+| <math fefunca>
+| <math fefuncb>
+| <math fefuncg>
+| <math fefuncr>
+| <math fegaussianblur>
+| <math feimage>
+| <math femerge>
+| <math femergenode>
+| <math femorphology>
+| <math feoffset>
+| <math fepointlight>
+| <math fespecularlighting>
+| <math fespotlight>
+| <math fetile>
+| <math feturbulence>
+| <math foreignobject>
+| <math glyphref>
+| <math lineargradient>
+| <math radialgradient>
+| <math textpath>
+
+#data
+<!DOCTYPE html><body><svg><solidColor /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg solidcolor>
diff --git a/pkgs/html/test/data/tree-construction/tests12.dat b/pkgs/html/test/data/tree-construction/tests12.dat
new file mode 100644
index 0000000..63107d2
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests12.dat
@@ -0,0 +1,62 @@
+#data
+<!DOCTYPE html><body><p>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "foo"
+| <math math>
+| <math mtext>
+| <i>
+| "baz"
+| <math annotation-xml>
+| <svg svg>
+| <svg desc>
+| <b>
+| "eggs"
+| <svg g>
+| <svg foreignObject>
+| <p>
+| "spam"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <img>
+| <svg g>
+| "quux"
+| "bar"
+
+#data
+<!DOCTYPE html><body>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "foo"
+| <math math>
+| <math mtext>
+| <i>
+| "baz"
+| <math annotation-xml>
+| <svg svg>
+| <svg desc>
+| <b>
+| "eggs"
+| <svg g>
+| <svg foreignObject>
+| <p>
+| "spam"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <img>
+| <svg g>
+| "quux"
+| "bar"
diff --git a/pkgs/html/test/data/tree-construction/tests14.dat b/pkgs/html/test/data/tree-construction/tests14.dat
new file mode 100644
index 0000000..b8713f8
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests14.dat
@@ -0,0 +1,74 @@
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xyz:abc>
+
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xyz:abc>
+| <span>
+
+#data
+<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+| abc:def="gh"
+| <head>
+| <body>
+| <xyz:abc>
+
+#data
+<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+| xml:lang="bar"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html 123=456>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| 123="456"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html 123=456><html 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| 123="456"
+| 789="012"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html><body 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| 789="012"
diff --git a/pkgs/html/test/data/tree-construction/tests15.dat b/pkgs/html/test/data/tree-construction/tests15.dat
new file mode 100644
index 0000000..6ce1c0d
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests15.dat
@@ -0,0 +1,208 @@
+#data
+<!DOCTYPE html><p><b><i><u></p> <p>X
+#errors
+Line: 1 Col: 31 Unexpected end tag (p). Ignored.
+Line: 1 Col: 36 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <i>
+| <u>
+| <b>
+| <i>
+| <u>
+| " "
+| <p>
+| "X"
+
+#data
+<p><b><i><u></p>
+<p>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag (p). Ignored.
+Line: 2 Col: 4 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <i>
+| <u>
+| <b>
+| <i>
+| <u>
+| "
+"
+| <p>
+| "X"
+
+#data
+<!doctype html></html> <head>
+#errors
+Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " "
+
+#data
+<!doctype html></body><meta>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+
+#data
+<html></html><!-- foo -->
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+| <!-- foo -->
+
+#data
+<!doctype html></body><title>X</title>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+
+#data
+<!doctype html><table> X<meta></table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " X"
+| <meta>
+| <table>
+
+#data
+<!doctype html><table> x</table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x"
+| <table>
+
+#data
+<!doctype html><table> x </table>
+#errors
+Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x "
+| <table>
+
+#data
+<!doctype html><table><tr> x</table>
+#errors
+Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table>X<style> <tr>x </style> </table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <style>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div>
+#errors
+Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <a>
+| "foo"
+| <table>
+| " "
+| <tbody>
+| <tr>
+| <td>
+| "bar"
+| " "
+
+#data
+<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes>
+#errors
+6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Stray start tag “frame”.
+21: Stray end tag “frame”.
+29: Stray end tag “frame”.
+39: “frameset” start tag after “body” already open.
+105: End of file seen inside an [R]CDATA element.
+105: End of file seen and there were open elements.
+XXX: These errors are wrong, please fix me!
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+| <frameset>
+| <frame>
+| <noframes>
+| "</frameset><noframes>"
+
+#data
+<!DOCTYPE html><object></html>
+#errors
+1: Expected closing tag. Unexpected end of file
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <object>
diff --git a/pkgs/html/test/data/tree-construction/tests16.dat b/pkgs/html/test/data/tree-construction/tests16.dat
new file mode 100644
index 0000000..c8ef66f
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests16.dat
@@ -0,0 +1,2299 @@
+#data
+<!doctype html><script>
+#errors
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script>a
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "a"
+| <body>
+
+#data
+<!doctype html><script><
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<"
+| <body>
+
+#data
+<!doctype html><script></
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</"
+| <body>
+
+#data
+<!doctype html><script></S
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</S"
+| <body>
+
+#data
+<!doctype html><script></SC
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SC"
+| <body>
+
+#data
+<!doctype html><script></SCR
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCR"
+| <body>
+
+#data
+<!doctype html><script></SCRI
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRI"
+| <body>
+
+#data
+<!doctype html><script></SCRIP
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRIP"
+| <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRIPT"
+| <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script></s
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</s"
+| <body>
+
+#data
+<!doctype html><script></sc
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</sc"
+| <body>
+
+#data
+<!doctype html><script></scr
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scr"
+| <body>
+
+#data
+<!doctype html><script></scri
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scri"
+| <body>
+
+#data
+<!doctype html><script></scrip
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scrip"
+| <body>
+
+#data
+<!doctype html><script></script
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</script"
+| <body>
+
+#data
+<!doctype html><script></script
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script><!
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!"
+| <body>
+
+#data
+<!doctype html><script><!a
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!a"
+| <body>
+
+#data
+<!doctype html><script><!-
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!-"
+| <body>
+
+#data
+<!doctype html><script><!-a
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!-a"
+| <body>
+
+#data
+<!doctype html><script><!--
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<!doctype html><script><!--a
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--a"
+| <body>
+
+#data
+<!doctype html><script><!--<
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<"
+| <body>
+
+#data
+<!doctype html><script><!--<a
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<a"
+| <body>
+
+#data
+<!doctype html><script><!--</
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--</"
+| <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--</script"
+| <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<!doctype html><script><!--<s
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<s"
+| <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script"
+| <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script "
+| <body>
+
+#data
+<!doctype html><script><!--<script <
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script <"
+| <body>
+
+#data
+<!doctype html><script><!--<script <a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script <a"
+| <body>
+
+#data
+<!doctype html><script><!--<script </
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </"
+| <body>
+
+#data
+<!doctype html><script><!--<script </s
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </s"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+Line: 1 Col: 43 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script"
+| <body>
+
+#data
+<!doctype html><script><!--<script </scripta
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </scripta"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script>
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script>"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script/
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script/"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script <
+#errors
+Line: 1 Col: 45 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script <a
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <a"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </script"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script/
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script -
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -"
+| <body>
+
+#data
+<!doctype html><script><!--<script -a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -a"
+| <body>
+
+#data
+<!doctype html><script><!--<script -<
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -<"
+| <body>
+
+#data
+<!doctype html><script><!--<script --
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --"
+| <body>
+
+#data
+<!doctype html><script><!--<script --a
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --a"
+| <body>
+
+#data
+<!doctype html><script><!--<script --<
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --<"
+| <body>
+
+#data
+<!doctype html><script><!--<script -->
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --><
+#errors
+Line: 1 Col: 39 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --><"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></
+#errors
+Line: 1 Col: 40 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --></"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --></script"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script/
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script><\/script>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script><\/script>-->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt>-->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>--><!--</script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>--><!--"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-- ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>-- >"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- -></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- ->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- - ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- - >"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>->"
+| <body>
+
+#data
+<!doctype html><script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 49 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script>--!></script>X"
+| <body>
+
+#data
+<!doctype html><script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 59 Unexpected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<scr'+'ipt>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 57 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt></script>X"
+| <body>
+
+#data
+<!doctype html><style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 52 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--<style>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><style><!--</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "X"
+
+#data
+<!doctype html><style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <body>
+| "...-->"
+
+#data
+<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+| <body>
+| "X"
+
+#data
+<!doctype html><style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 66 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--...<style><!--...--!>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><style><!--...</style><!-- --><style>@import ...</style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <!-- -->
+| <style>
+| "@import ..."
+| <body>
+
+#data
+<!doctype html><style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 63 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "...<style><!--..."
+| <!-- -->
+| <body>
+
+#data
+<!doctype html><style>...<!--[if IE]><style>...</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "...<!--[if IE]><style>..."
+| <body>
+| "X"
+
+#data
+<!doctype html><title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 52 Unexpected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "<!--<title>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><title></title></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "</title>"
+| <body>
+
+#data
+<!doctype html><title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "foo/title><link></head><body>X"
+| <body>
+
+#data
+<!doctype html><noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noscript).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<!--<noscript>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "X"
+| <noscript>
+| "-->"
+
+#data
+<!doctype html><noscript><iframe></noscript>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<iframe>"
+| <body>
+| "X"
+
+#data
+<!doctype html><noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noframes).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noframes>
+| "<!--<noframes>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><noframes><body><script><!--...</script></body></noframes></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noframes>
+| "<body><script><!--...</script></body>"
+| <body>
+
+#data
+<!doctype html><textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 64 Unexpected end tag (textarea).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--<textarea>"
+| "-->"
+
+#data
+<!doctype html><textarea></textarea></textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "</textarea>"
+
+#data
+<!doctype html><textarea><</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<"
+
+#data
+<!doctype html><textarea>a<b</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "a<b"
+
+#data
+<!doctype html><iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 56 Unexpected end tag (iframe).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "<!--<iframe>"
+| "-->"
+
+#data
+<!doctype html><iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "...<!--X->...<!--/X->..."
+
+#data
+<!doctype html><xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 44 Unexpected end tag (xmp).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xmp>
+| "<!--<xmp>"
+| "-->"
+
+#data
+<!doctype html><noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 60 Unexpected end tag (noembed).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <noembed>
+| "<!--<noembed>"
+| "-->"
+
+#data
+<script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script>a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "a"
+| <body>
+
+#data
+<script><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<"
+| <body>
+
+#data
+<script></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</"
+| <body>
+
+#data
+<script></S
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</S"
+| <body>
+
+#data
+<script></SC
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SC"
+| <body>
+
+#data
+<script></SCR
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCR"
+| <body>
+
+#data
+<script></SCRI
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRI"
+| <body>
+
+#data
+<script></SCRIP
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRIP"
+| <body>
+
+#data
+<script></SCRIPT
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRIPT"
+| <body>
+
+#data
+<script></SCRIPT
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script></s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</s"
+| <body>
+
+#data
+<script></sc
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</sc"
+| <body>
+
+#data
+<script></scr
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scr"
+| <body>
+
+#data
+<script></scri
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scri"
+| <body>
+
+#data
+<script></scrip
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scrip"
+| <body>
+
+#data
+<script></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</script"
+| <body>
+
+#data
+<script></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script><!
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!"
+| <body>
+
+#data
+<script><!a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!a"
+| <body>
+
+#data
+<script><!-
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!-"
+| <body>
+
+#data
+<script><!-a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!-a"
+| <body>
+
+#data
+<script><!--
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<script><!--a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--a"
+| <body>
+
+#data
+<script><!--<
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<"
+| <body>
+
+#data
+<script><!--<a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<a"
+| <body>
+
+#data
+<script><!--</
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--</"
+| <body>
+
+#data
+<script><!--</script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--</script"
+| <body>
+
+#data
+<script><!--</script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<script><!--<s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<s"
+| <body>
+
+#data
+<script><!--<script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script"
+| <body>
+
+#data
+<script><!--<script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script "
+| <body>
+
+#data
+<script><!--<script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script <"
+| <body>
+
+#data
+<script><!--<script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script <a"
+| <body>
+
+#data
+<script><!--<script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </"
+| <body>
+
+#data
+<script><!--<script </s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </s"
+| <body>
+
+#data
+<script><!--<script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script"
+| <body>
+
+#data
+<script><!--<script </scripta
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </scripta"
+| <body>
+
+#data
+<script><!--<script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script>"
+| <body>
+
+#data
+<script><!--<script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script/"
+| <body>
+
+#data
+<script><!--<script </script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <"
+| <body>
+
+#data
+<script><!--<script </script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <a"
+| <body>
+
+#data
+<script><!--<script </script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </"
+| <body>
+
+#data
+<script><!--<script </script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </script"
+| <body>
+
+#data
+<script><!--<script </script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script -
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -"
+| <body>
+
+#data
+<script><!--<script -a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -a"
+| <body>
+
+#data
+<script><!--<script --
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --"
+| <body>
+
+#data
+<script><!--<script --a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --a"
+| <body>
+
+#data
+<script><!--<script -->
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --><"
+| <body>
+
+#data
+<script><!--<script --></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --></"
+| <body>
+
+#data
+<script><!--<script --></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --></script"
+| <body>
+
+#data
+<script><!--<script --></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --></script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script><\/script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script><\/script>-->"
+| <body>
+
+#data
+<script><!--<script></scr'+'ipt>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt>-->"
+| <body>
+
+#data
+<script><!--<script></script><script></script></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>"
+| <body>
+
+#data
+<script><!--<script></script><script></script>--><!--</script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>--><!--"
+| <body>
+
+#data
+<script><!--<script></script><script></script>-- ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>-- >"
+| <body>
+
+#data
+<script><!--<script></script><script></script>- -></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- ->"
+| <body>
+
+#data
+<script><!--<script></script><script></script>- - ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- - >"
+| <body>
+
+#data
+<script><!--<script></script><script></script>-></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>->"
+| <body>
+
+#data
+<script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script>--!></script>X"
+| <body>
+
+#data
+<script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 44 Unexpected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<scr'+'ipt>"
+| <body>
+| "-->"
+
+#data
+<script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 42 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt></script>X"
+| <body>
+
+#data
+<style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--<style>"
+| <body>
+| "-->"
+
+#data
+<style><!--</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "X"
+
+#data
+<style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 36 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <body>
+| "...-->"
+
+#data
+<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+| <body>
+| "X"
+
+#data
+<style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--...<style><!--...--!>"
+| <body>
+| "-->"
+
+#data
+<style><!--...</style><!-- --><style>@import ...</style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <!-- -->
+| <style>
+| "@import ..."
+| <body>
+
+#data
+<style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 48 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "...<style><!--..."
+| <!-- -->
+| <body>
+
+#data
+<style>...<!--[if IE]><style>...</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "...<!--[if IE]><style>..."
+| <body>
+| "X"
+
+#data
+<title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "<!--<title>"
+| <body>
+| "-->"
+
+#data
+<title></title></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "</title>"
+| <body>
+
+#data
+<title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "foo/title><link></head><body>X"
+| <body>
+
+#data
+<noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noscript).
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--<noscript>"
+| <body>
+| "-->"
+
+#data
+<noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "X"
+| <noscript>
+| "-->"
+
+#data
+<noscript><iframe></noscript>X
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<iframe>"
+| <body>
+| "X"
+
+#data
+<noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noframes).
+#document
+| <html>
+| <head>
+| <noframes>
+| "<!--<noframes>"
+| <body>
+| "-->"
+
+#data
+<noframes><body><script><!--...</script></body></noframes></html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noframes>
+| "<body><script><!--...</script></body>"
+| <body>
+
+#data
+<textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (textarea).
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--<textarea>"
+| "-->"
+
+#data
+<textarea></textarea></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "</textarea>"
+
+#data
+<iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+Line: 1 Col: 41 Unexpected end tag (iframe).
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "<!--<iframe>"
+| "-->"
+
+#data
+<iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "...<!--X->...<!--/X->..."
+
+#data
+<xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end tag (xmp).
+#document
+| <html>
+| <head>
+| <body>
+| <xmp>
+| "<!--<xmp>"
+| "-->"
+
+#data
+<noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE.
+Line: 1 Col: 45 Unexpected end tag (noembed).
+#document
+| <html>
+| <head>
+| <body>
+| <noembed>
+| "<!--<noembed>"
+| "-->"
+
+#data
+<!doctype html><table>
+
+#errors
+Line 2 Col 0 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| "
+"
+
+#data
+<!doctype html><table><td><span><font></span><span>
+#errors
+Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase.
+Line 1 Col 45 Unexpected end tag (span).
+Line 1 Col 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <span>
+| <font>
+| <font>
+| <span>
+
+#data
+<!doctype html><form><table></form><form></table></form>
+#errors
+35: Stray end tag “form”.
+41: Start tag “form” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <table>
+| <form>
diff --git a/pkgs/html/test/data/tree-construction/tests17.dat b/pkgs/html/test/data/tree-construction/tests17.dat
new file mode 100644
index 0000000..7b555f8
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests17.dat
@@ -0,0 +1,153 @@
+#data
+<!doctype html><table><tbody><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><tr><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<!doctype html><table><tr><td><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| <td>
+
+#data
+<!doctype html><table><tr><th><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <th>
+| <select>
+| <td>
+
+#data
+<!doctype html><table><caption><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <select>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><select><tr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><th>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><tbody>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><thead>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><tfoot>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><caption>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><table><tr></table>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| "a"
diff --git a/pkgs/html/test/data/tree-construction/tests18.dat b/pkgs/html/test/data/tree-construction/tests18.dat
new file mode 100644
index 0000000..680e1f0
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests18.dat
@@ -0,0 +1,269 @@
+#data
+<!doctype html><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+
+#data
+<!doctype html><table><tbody><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+| <tbody>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><td><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><caption><plaintext></plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><tr><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+| <style>
+| "</script>"
+
+#data
+<!doctype html><table><tr><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+| <script>
+| "</style>"
+
+#data
+<!doctype html><table><caption><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <style>
+| "</script>"
+| "abc"
+
+#data
+<!doctype html><table><td><style></script></style>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <style>
+| "</script>"
+| "abc"
+
+#data
+<!doctype html><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+
+#data
+<!doctype html><table><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+| <table>
+
+#data
+<!doctype html><table><tr><select><script></style></script>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><frameset></frameset><noframes>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+
+#data
+<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+| <!-- abc -->
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+| <!-- abc -->
+
+#data
+<!doctype html><table><tr></tbody><tfoot>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <tfoot>
+
+#data
+<!doctype html><table><td><svg></svg>abc<td>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| "abc"
+| <td>
diff --git a/pkgs/html/test/data/tree-construction/tests19.dat b/pkgs/html/test/data/tree-construction/tests19.dat
new file mode 100644
index 0000000..0d62f5a
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests19.dat
@@ -0,0 +1,1237 @@
+#data
+<!doctype html><math><mn DefinitionUrl="foo">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| definitionURL="foo"
+
+#data
+<!doctype html><html></p><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <!-- foo -->
+| <head>
+| <body>
+
+#data
+<!doctype html><head></head></p><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <!-- foo -->
+| <body>
+
+#data
+<!doctype html><body><p><pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <pre>
+
+#data
+<!doctype html><body><p><listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <listing>
+
+#data
+<!doctype html><p><plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <plaintext>
+
+#data
+<!doctype html><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <h1>
+
+#data
+<!doctype html><form><isindex>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+
+#data
+<!doctype html><isindex action="POST">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| action="POST"
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| <hr>
+
+#data
+<!doctype html><isindex prompt="this is isindex">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "this is isindex"
+| <input>
+| name="isindex"
+| <hr>
+
+#data
+<!doctype html><isindex type="hidden">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| type="hidden"
+| <hr>
+
+#data
+<!doctype html><isindex name="foo">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| <hr>
+
+#data
+<!doctype html><ruby><p><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <p>
+| <rp>
+
+#data
+<!doctype html><ruby><div><span><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <span>
+| <rp>
+
+#data
+<!doctype html><ruby><div><p><rp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <p>
+| <rp>
+
+#data
+<!doctype html><ruby><p><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <p>
+| <rt>
+
+#data
+<!doctype html><ruby><div><span><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <span>
+| <rt>
+
+#data
+<!doctype html><ruby><div><p><rt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <p>
+| <rt>
+
+#data
+<!doctype html><math/><foo>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <foo>
+
+#data
+<!doctype html><svg/><foo>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <foo>
+
+#data
+<!doctype html><div></body><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <!-- foo -->
+
+#data
+<!doctype html><h1><div><h3><span></h1>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <h1>
+| <div>
+| <h3>
+| <span>
+| "foo"
+
+#data
+<!doctype html><p></h3>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "foo"
+
+#data
+<!doctype html><h3><li>abc</h2>foo
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <h3>
+| <li>
+| "abc"
+| "foo"
+
+#data
+<!doctype html><table>abc<!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <!-- foo -->
+
+#data
+<!doctype html><table> <!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <!-- foo -->
+
+#data
+<!doctype html><table> b <!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " b "
+| <table>
+| <!-- foo -->
+
+#data
+<!doctype html><select><option><option>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!doctype html><p><math><mi><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mi>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mo><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mo>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mn><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mn>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><ms><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math ms>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mtext><p><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mtext>
+| <p>
+| <h1>
+
+#data
+<!doctype html><frameset></noframes>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html c=d><body></html><html a=b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <body>
+
+#data
+<!doctype html><html c=d><frameset></frameset></html><html a=b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <!-- foo -->
+
+#data
+<!doctype html><html><frameset></frameset></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!doctype html><html><frameset></frameset></html>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html></p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<html><frameset></frameset></html><!doctype html>
+#errors
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><body><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html><p><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><p>a<frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "a"
+
+#data
+<!doctype html><p> <frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><pre><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+
+#data
+<!doctype html><listing><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <listing>
+
+#data
+<!doctype html><li><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <li>
+
+#data
+<!doctype html><dd><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dd>
+
+#data
+<!doctype html><dt><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dt>
+
+#data
+<!doctype html><button><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <button>
+
+#data
+<!doctype html><applet><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <applet>
+
+#data
+<!doctype html><marquee><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <marquee>
+
+#data
+<!doctype html><object><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <object>
+
+#data
+<!doctype html><table><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+
+#data
+<!doctype html><area><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <area>
+
+#data
+<!doctype html><basefont><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <basefont>
+| <frameset>
+
+#data
+<!doctype html><bgsound><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <bgsound>
+| <frameset>
+
+#data
+<!doctype html><br><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<!doctype html><embed><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <embed>
+
+#data
+<!doctype html><img><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+
+#data
+<!doctype html><input><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+
+#data
+<!doctype html><keygen><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <keygen>
+
+#data
+<!doctype html><wbr><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <wbr>
+
+#data
+<!doctype html><hr><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <hr>
+
+#data
+<!doctype html><textarea></textarea><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+
+#data
+<!doctype html><xmp></xmp><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xmp>
+
+#data
+<!doctype html><iframe></iframe><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+
+#data
+<!doctype html><select></select><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><svg></svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><math></math><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><svg><foreignObject><div> <frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><svg>a</svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "a"
+
+#data
+<!doctype html><svg> </svg><frameset><frame>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<html>aaa<frameset></frameset>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "aaa"
+
+#data
+<html> a <frameset></frameset>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "a "
+
+#data
+<!doctype html><div><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><div><body><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<!doctype html><p><math></p>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| "a"
+
+#data
+<!doctype html><p><math><mn><span></p>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mn>
+| <span>
+| <p>
+| "a"
+
+#data
+<!doctype html><math></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!doctype html><meta charset="ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| charset="ascii"
+| <body>
+
+#data
+<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| content="text/html;charset=ascii"
+| http-equiv="content-type"
+| <body>
+
+#data
+<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -->
+| <meta>
+| charset="utf8"
+| <body>
+
+#data
+<!doctype html><html a=b><head></head><html c=d>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <body>
+
+#data
+<!doctype html><image/>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+
+#data
+<!doctype html>a<i>b<table>c<b>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "a"
+| <i>
+| "bc"
+| <b>
+| "de"
+| "f"
+| <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+| <table>
+
+#data
+<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+
+#data
+<!doctype html><table><i>a<b>b<div>c</i>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <i>
+| "c"
+| <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+| <table>
+
+#data
+<!doctype html><table><i>a<div>b<tr>c<b>d</i>e
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <div>
+| "b"
+| <i>
+| "c"
+| <b>
+| "d"
+| <b>
+| "e"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><td><table><i>a<div>b<b>c</i>d
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+| "a"
+| <div>
+| <i>
+| "b"
+| <b>
+| "c"
+| <b>
+| "d"
+| <table>
+
+#data
+<!doctype html><body><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <bgsound>
+
+#data
+<!doctype html><body><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <basefont>
+
+#data
+<!doctype html><a><b></a><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <basefont>
+
+#data
+<!doctype html><a><b></a><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <bgsound>
+
+#data
+<!doctype html><figcaption><article></figcaption>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <figcaption>
+| <article>
+| "a"
+
+#data
+<!doctype html><summary><article></summary>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <summary>
+| <article>
+| "a"
+
+#data
+<!doctype html><p><a><plaintext>b
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <a>
+| <plaintext>
+| <a>
+| "b"
+
+#data
+<!DOCTYPE html><div>a<a></div>b<p>c</p>d
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| "a"
+| <a>
+| <a>
+| "b"
+| <p>
+| "c"
+| "d"
diff --git a/pkgs/html/test/data/tree-construction/tests2.dat b/pkgs/html/test/data/tree-construction/tests2.dat
new file mode 100644
index 0000000..60d8592
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests2.dat
@@ -0,0 +1,763 @@
+#data
+<!DOCTYPE html>Test
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<textarea>test</div>test
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 24 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "test</div>test"
+
+#data
+<table><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 11 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><td>test</tbody></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "test"
+
+#data
+<frame>test
+#errors
+Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected start tag frame. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| "test"
+
+#data
+<!DOCTYPE html><frameset>test
+#errors
+Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset><!DOCTYPE html>
+#errors
+Line: 1 Col: 40 Unexpected DOCTYPE. Ignored.
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><font><p><b>test</font>
+#errors
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <font>
+| <b>
+| "test"
+
+#data
+<!DOCTYPE html><dt><div><dd>
+#errors
+Line: 1 Col: 28 Missing end tag (div, dt).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dt>
+| <div>
+| <dd>
+
+#data
+<script></x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</x"
+| <body>
+
+#data
+<table><plaintext><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "<td>"
+| <table>
+
+#data
+<plaintext></plaintext>
+#errors
+Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!DOCTYPE html><table><tr>TEST
+#errors
+Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "TEST"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4>
+#errors
+Line: 1 Col: 37 Unexpected start tag (body).
+Line: 1 Col: 53 Unexpected start tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| t1="1"
+| t2="2"
+| t3="3"
+| t4="4"
+
+#data
+</b test
+#errors
+Line: 1 Col: 8 Unexpected end of file in attribute name.
+Line: 1 Col: 8 End tag contains unexpected attributes.
+Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html></b test<b &=&>X
+#errors
+Line: 1 Col: 32 Named entity didn't end with ';'.
+Line: 1 Col: 33 End tag contains unexpected attributes.
+Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+
+#data
+<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 54 Unexpected end of file in the tag name.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| type="text/x-foobar;baz"
+| "X</SCRipt"
+| <body>
+
+#data
+&
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&"
+
+#data
+&#
+#errors
+Line: 1 Col: 1 Numeric entity expected. Got end of file instead.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#"
+
+#data
+&#X
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#X"
+
+#data
+&#x
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#x"
+
+#data
+-
+#errors
+Line: 1 Col: 4 Numeric entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "-"
+
+#data
+&x-test
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&x-test"
+
+#data
+<!doctypehtml><p><li>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <li>
+
+#data
+<!doctypehtml><p><dt>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <dt>
+
+#data
+<!doctypehtml><p><dd>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <dd>
+
+#data
+<!doctypehtml><p><form>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <form>
+
+#data
+<!DOCTYPE html><p></P>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "X"
+
+#data
+&
+#errors
+Line: 1 Col: 4 Named entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&"
+
+#data
+&AMp;
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&AMp;"
+
+#data
+<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY>
+#errors
+Line: 1 Col: 110 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly>
+
+#data
+<!DOCTYPE html>X</body>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "XX"
+
+#data
+<!DOCTYPE html><!-- X
+#errors
+Line: 1 Col: 21 Unexpected end of file in comment.
+#document
+| <!DOCTYPE html>
+| <!-- X -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><table><caption>test TEST</caption><td>test
+#errors
+Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| "test TEST"
+| <tbody>
+| <tr>
+| <td>
+| "test"
+
+#data
+<!DOCTYPE html><select><option><optgroup>
+#errors
+Line: 1 Col: 41 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <optgroup>
+
+#data
+<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
+#errors
+Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 76 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+| <option>
+| <option>
+| <option>
+
+#data
+<!DOCTYPE html><select><optgroup><option><optgroup>
+#errors
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+| <option>
+| <optgroup>
+
+#data
+<!DOCTYPE html><datalist><option>foo</datalist>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <datalist>
+| <option>
+| "foo"
+| "bar"
+
+#data
+<!DOCTYPE html><font><input><input></font>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <input>
+| <input>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX
+#errors
+Line: 1 Col: 29 Unexpected end of file in comment (-)
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<isindex test=x name=x>
+#errors
+Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Enter search keywords: "
+| <input>
+| name="isindex"
+| test="x"
+| <hr>
+
+#data
+test
+test
+#errors
+Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "test
+test"
+
+#data
+<!DOCTYPE html><body><title>test</body></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "test</body>"
+
+#data
+<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style>
+x { content:"</style" } </style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+| <meta>
+| name="z"
+| <link>
+| rel="foo"
+| <style>
+| "
+x { content:"</style" } "
+
+#data
+<!DOCTYPE html><select><optgroup></optgroup></select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+
+#data
+
+
+#errors
+Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html> <html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><script>
+</script> <title>x</title> </head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "
+"
+| " "
+| <title>
+| "x"
+| " "
+| <body>
+
+#data
+<!DOCTYPE html><html><body><html id=x>
+#errors
+Line: 1 Col: 38 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html>X</body><html id="x">
+#errors
+Line: 1 Col: 36 Unexpected start tag token (html) in the after body phase.
+Line: 1 Col: 36 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+| "X"
+
+#data
+<!DOCTYPE html><head><html id=x>
+#errors
+Line: 1 Col: 32 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html>X</html>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "XX"
+
+#data
+<!DOCTYPE html>X</html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X "
+
+#data
+<!DOCTYPE html>X</html><p>X
+#errors
+Line: 1 Col: 26 Unexpected start tag (p).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <p>
+| "X"
+
+#data
+<!DOCTYPE html>X<p/x/y/z>
+#errors
+Line: 1 Col: 19 Expected a > after the /.
+Line: 1 Col: 21 Solidus (/) incorrectly placed in tag.
+Line: 1 Col: 23 Solidus (/) incorrectly placed in tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <p>
+| x=""
+| y=""
+| z=""
+
+#data
+<!DOCTYPE html><!--x--
+#errors
+Line: 1 Col: 22 Unexpected end of file in comment (--).
+#document
+| <!DOCTYPE html>
+| <!-- x -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><table><tr><td></p></table>
+#errors
+Line: 1 Col: 34 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <p>
+
+#data
+<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->-->
+#errors
+Line: 1 Col: 20 Expected space or '>'. Got ''
+Line: 1 Col: 25 Erroneous DOCTYPE.
+Line: 1 Col: 35 Unexpected character in comment found.
+#document
+| <!DOCTYPE <!doctype>
+| <html>
+| <head>
+| <body>
+| ">"
+| <!-- <!--x -->
+| "-->"
+
+#data
+<!doctype html><div><form></form><div></div></div>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <form>
+| <div>
diff --git a/pkgs/html/test/data/tree-construction/tests20.dat b/pkgs/html/test/data/tree-construction/tests20.dat
new file mode 100644
index 0000000..6bd8256
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests20.dat
@@ -0,0 +1,455 @@
+#data
+<!doctype html><p><button><button>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <button>
+
+#data
+<!doctype html><p><button><address>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <address>
+
+#data
+<!doctype html><p><button><blockquote>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <blockquote>
+
+#data
+<!doctype html><p><button><menu>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <menu>
+
+#data
+<!doctype html><p><button><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <p>
+
+#data
+<!doctype html><p><button><ul>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <ul>
+
+#data
+<!doctype html><p><button><h1>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <h1>
+
+#data
+<!doctype html><p><button><h6>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <h6>
+
+#data
+<!doctype html><p><button><listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <listing>
+
+#data
+<!doctype html><p><button><pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <pre>
+
+#data
+<!doctype html><p><button><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <form>
+
+#data
+<!doctype html><p><button><li>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <li>
+
+#data
+<!doctype html><p><button><dd>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <dd>
+
+#data
+<!doctype html><p><button><dt>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <dt>
+
+#data
+<!doctype html><p><button><plaintext>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <plaintext>
+
+#data
+<!doctype html><p><button><table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <table>
+
+#data
+<!doctype html><p><button><hr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <hr>
+
+#data
+<!doctype html><p><button><xmp>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <xmp>
+
+#data
+<!doctype html><p><button></p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <p>
+
+#data
+<!doctype html><address><button></address>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <address>
+| <button>
+| "a"
+
+#data
+<!doctype html><address><button></address>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <address>
+| <button>
+| "a"
+
+#data
+<p><table></p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <p>
+| <table>
+
+#data
+<!doctype html><svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!doctype html><p><figcaption>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <figcaption>
+
+#data
+<!doctype html><p><summary>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <summary>
+
+#data
+<!doctype html><form><table><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <table>
+
+#data
+<!doctype html><table><form><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <form>
+
+#data
+<!doctype html><table><form></table><form>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <form>
+
+#data
+<!doctype html><svg><foreignObject><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg foreignObject>
+| <p>
+
+#data
+<!doctype html><svg><title>abc
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| "abc"
+
+#data
+<option><span><option>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <option>
+| <span>
+| <option>
+
+#data
+<option><option>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <option>
+| <option>
+
+#data
+<math><annotation-xml><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <div>
+
+#data
+<math><annotation-xml encoding="application/svg+xml"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="application/svg+xml"
+| <div>
+
+#data
+<math><annotation-xml encoding="application/xhtml+xml"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="application/xhtml+xml"
+| <div>
+
+#data
+<math><annotation-xml encoding="aPPlication/xhtmL+xMl"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="aPPlication/xhtmL+xMl"
+| <div>
+
+#data
+<math><annotation-xml encoding="text/html"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="text/html"
+| <div>
+
+#data
+<math><annotation-xml encoding="Text/htmL"><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="Text/htmL"
+| <div>
+
+#data
+<math><annotation-xml encoding=" text/html "><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding=" text/html "
+| <div>
diff --git a/pkgs/html/test/data/tree-construction/tests21.dat b/pkgs/html/test/data/tree-construction/tests21.dat
new file mode 100644
index 0000000..1260ec0
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests21.dat
@@ -0,0 +1,221 @@
+#data
+<svg><![CDATA[foo]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<math><![CDATA[foo]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| "foo"
+
+#data
+<div><![CDATA[foo]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<svg><![CDATA[foo
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<svg><![CDATA[
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<svg><![CDATA[]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]] >"
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]] >"
+
+#data
+<svg><![CDATA[]]
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]]"
+
+#data
+<svg><![CDATA[]
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]"
+
+#data
+<svg><![CDATA[]>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]>a"
+
+#data
+<svg><foreignObject><div><![CDATA[foo]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[<svg>]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+
+#data
+<svg><![CDATA[</svg>a]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "</svg>a"
+
+#data
+<svg><![CDATA[<svg>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>a"
+
+#data
+<svg><![CDATA[</svg>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "</svg>a"
+
+#data
+<svg><![CDATA[<svg>]]><path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+| <svg path>
+
+#data
+<svg><![CDATA[<svg>]]></path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+
+#data
+<svg><![CDATA[<svg>]]><!--path-->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+| <!-- path -->
+
+#data
+<svg><![CDATA[<svg>]]>path
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>path"
+
+#data
+<svg><![CDATA[<!--svg-->]]>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<!--svg-->"
diff --git a/pkgs/html/test/data/tree-construction/tests22.dat b/pkgs/html/test/data/tree-construction/tests22.dat
new file mode 100644
index 0000000..aab27b2
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests22.dat
@@ -0,0 +1,157 @@
+#data
+<a><b><big><em><strong><div>X</a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <big>
+| <em>
+| <strong>
+| <big>
+| <em>
+| <strong>
+| <div>
+| <a>
+| "X"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8>A</a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| "A"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9>A</a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| <div>
+| id="9"
+| "A"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9><div id=10>A</a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| <div>
+| id="9"
+| <div>
+| id="10"
+| "A"
+
+#data
+<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST
+#errors
+Line: 1 Col: 6 Unexpected start tag (cite). Expected DOCTYPE.
+Line: 1 Col: 46 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 50 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <cite>
+| <b>
+| <cite>
+| <i>
+| <cite>
+| <i>
+| <cite>
+| <i>
+| <i>
+| <i>
+| <div>
+| <b>
+| "X"
+| "TEST"
diff --git a/pkgs/html/test/data/tree-construction/tests23.dat b/pkgs/html/test/data/tree-construction/tests23.dat
new file mode 100644
index 0000000..34d2a73
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests23.dat
@@ -0,0 +1,155 @@
+#data
+<p><font size=4><font color=red><font size=4><font size=4><font size=4><font size=4><font size=4><font color=red><p>X
+#errors
+3: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+116: Unclosed elements.
+117: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| color="red"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| color="red"
+| <p>
+| <font>
+| color="red"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| color="red"
+| "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size=4><p>X
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size="5"><font size=4><p>X
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="5"
+| <font>
+| size="4"
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="5"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><font size=4 id=a><font size=4 id=b><font size=4><font size=4><p>X
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| id="a"
+| size="4"
+| <font>
+| id="b"
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <p>
+| <font>
+| id="a"
+| size="4"
+| <font>
+| id="b"
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><b id=a><b id=a><b id=a><b><object><b id=a><b id=a>X</object><p>Y
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| <object>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| "X"
+| <p>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| "Y"
diff --git a/pkgs/html/test/data/tree-construction/tests24.dat b/pkgs/html/test/data/tree-construction/tests24.dat
new file mode 100644
index 0000000..f6dc7eb
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests24.dat
@@ -0,0 +1,79 @@
+#data
+<!DOCTYPE html>≂̸
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "≂̸"
+
+#data
+<!DOCTYPE html>≂̸A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "≂̸A"
+
+#data
+<!DOCTYPE html>  
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " "
+
+#data
+<!DOCTYPE html>  A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " A"
+
+#data
+<!DOCTYPE html>⊂⃒
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "⊂⃒"
+
+#data
+<!DOCTYPE html>⊂⃒A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "⊂⃒A"
+
+#data
+<!DOCTYPE html>𝔾
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "𝔾"
+
+#data
+<!DOCTYPE html>𝔾A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "𝔾A"
diff --git a/pkgs/html/test/data/tree-construction/tests25.dat b/pkgs/html/test/data/tree-construction/tests25.dat
new file mode 100644
index 0000000..00de729
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests25.dat
@@ -0,0 +1,219 @@
+#data
+<!DOCTYPE html><body><foo>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <foo>
+| "A"
+
+#data
+<!DOCTYPE html><body><area>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <area>
+| "A"
+
+#data
+<!DOCTYPE html><body><base>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <base>
+| "A"
+
+#data
+<!DOCTYPE html><body><basefont>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <basefont>
+| "A"
+
+#data
+<!DOCTYPE html><body><bgsound>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <bgsound>
+| "A"
+
+#data
+<!DOCTYPE html><body><br>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <br>
+| "A"
+
+#data
+<!DOCTYPE html><body><col>A
+#errors
+26: Stray start tag “col”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+
+#data
+<!DOCTYPE html><body><command>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <command>
+| "A"
+
+#data
+<!DOCTYPE html><body><embed>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <embed>
+| "A"
+
+#data
+<!DOCTYPE html><body><frame>A
+#errors
+26: Stray start tag “frame”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+
+#data
+<!DOCTYPE html><body><hr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <hr>
+| "A"
+
+#data
+<!DOCTYPE html><body><img>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+| "A"
+
+#data
+<!DOCTYPE html><body><input>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| "A"
+
+#data
+<!DOCTYPE html><body><keygen>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <keygen>
+| "A"
+
+#data
+<!DOCTYPE html><body><link>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <link>
+| "A"
+
+#data
+<!DOCTYPE html><body><meta>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+| "A"
+
+#data
+<!DOCTYPE html><body><param>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <param>
+| "A"
+
+#data
+<!DOCTYPE html><body><source>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <source>
+| "A"
+
+#data
+<!DOCTYPE html><body><track>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <track>
+| "A"
+
+#data
+<!DOCTYPE html><body><wbr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <wbr>
+| "A"
diff --git a/pkgs/html/test/data/tree-construction/tests26.dat b/pkgs/html/test/data/tree-construction/tests26.dat
new file mode 100644
index 0000000..fae11ff
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests26.dat
@@ -0,0 +1,313 @@
+#data
+<!DOCTYPE html><body><a href='#1'><nobr>1<nobr></a><br><a href='#2'><nobr>2<nobr></a><br><a href='#3'><nobr>3<nobr></a>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| href="#1"
+| <nobr>
+| "1"
+| <nobr>
+| <nobr>
+| <br>
+| <a>
+| href="#2"
+| <a>
+| href="#2"
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| <br>
+| <a>
+| href="#3"
+| <a>
+| href="#3"
+| <nobr>
+| "3"
+| <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+| <table>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><tr><td><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<div><nobr></b><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <div>
+| <b>
+| <nobr>
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><div><i><nobr>2<nobr></i>3
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <div>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr><ins></b><i><nobr>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <ins>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<ins><nobr></b><i>2
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <ins>
+| <nobr>
+| <nobr>
+| <i>
+| "2"
+
+#data
+<!DOCTYPE html><body><b>1<nobr></b><i><nobr>2</i>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| "1"
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+
+#data
+<p><code x</code></p>
+
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <code>
+| code=""
+| x<=""
+| <code>
+| code=""
+| x<=""
+| "
+"
+
+#data
+<!DOCTYPE html><svg><foreignObject><p><i></p>a
+#errors
+45: End tag “p” seen, but there were open elements.
+41: Unclosed element “i”.
+46: End of file seen and there were open elements.
+35: Unclosed element “foreignObject”.
+20: Unclosed element “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg foreignObject>
+| <p>
+| <i>
+| <i>
+| "a"
+
+#data
+<!DOCTYPE html><table><tr><td><svg><foreignObject><p><i></p>a
+#errors
+56: End tag “p” seen, but there were open elements.
+52: Unclosed element “i”.
+57: End of file seen and there were open elements.
+46: Unclosed element “foreignObject”.
+31: Unclosed element “svg”.
+22: Unclosed element “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg foreignObject>
+| <p>
+| <i>
+| <i>
+| "a"
+
+#data
+<!DOCTYPE html><math><mtext><p><i></p>a
+#errors
+38: End tag “p” seen, but there were open elements.
+34: Unclosed element “i”.
+39: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <p>
+| <i>
+| <i>
+| "a"
+
+#data
+<!DOCTYPE html><table><tr><td><math><mtext><p><i></p>a
+#errors
+53: End tag “p” seen, but there were open elements.
+49: Unclosed element “i”.
+54: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mtext>
+| <p>
+| <i>
+| <i>
+| "a"
+
+#data
+<!DOCTYPE html><body><div><!/div>a
+#errors
+29: Bogus comment.
+34: End of file seen and there were open elements.
+26: Unclosed element “div”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <!-- /div -->
+| "a"
diff --git a/pkgs/html/test/data/tree-construction/tests3.dat b/pkgs/html/test/data/tree-construction/tests3.dat
new file mode 100644
index 0000000..38dc501
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests3.dat
@@ -0,0 +1,305 @@
+#data
+<head></head><style></style>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <style>
+| <body>
+
+#data
+<head></head><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<head></head><!-- --><style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <style>
+| <script>
+| <!-- -->
+| <!-- -->
+| <body>
+
+#data
+<head></head><!-- -->x<style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <!-- -->
+| <body>
+| "x"
+| <style>
+| <!-- -->
+| <script>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "foo
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x</pre><span>
+</span></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x"
+| <span>
+| "
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x
+y</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x
+y"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x<div>
+y</pre></body></html>
+#errors
+Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x"
+| <div>
+| "
+y"
+
+#data
+<!DOCTYPE html><pre>

A</pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "
+A"
+
+#data
+<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| <body>
+
+#data
+<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<textarea>foo<span>bar</span><i>baz
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "foo<span>bar</span><i>baz"
+
+#data
+<title>foo<span>bar</em><i>baz
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "foo<span>bar</em><i>baz"
+| <body>
+
+#data
+<!DOCTYPE html><textarea>
+</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+
+#data
+<!DOCTYPE html><textarea>
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "foo"
+
+#data
+<!DOCTYPE html><textarea>
+
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html>
+#errors
+Line: 1 Col: 60 Missing end tag (div, li).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| <p>
+| <li>
+
+#data
+<!doctype html><nobr><nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <nobr>
+| <nobr>
+| <nobr>
+
+#data
+<!doctype html><nobr><nobr></nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <nobr>
+| <nobr>
+| <nobr>
+
+#data
+<!doctype html><html><body><p><table></table></body></html>
+#errors
+Not known
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <table>
+
+#data
+<p><table></table>
+#errors
+Not known
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <table>
diff --git a/pkgs/html/test/data/tree-construction/tests4.dat b/pkgs/html/test/data/tree-construction/tests4.dat
new file mode 100644
index 0000000..3c50632
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests4.dat
@@ -0,0 +1,59 @@
+#data
+direct div content
+#errors
+#document-fragment
+div
+#document
+| "direct div content"
+
+#data
+direct textarea content
+#errors
+#document-fragment
+textarea
+#document
+| "direct textarea content"
+
+#data
+textarea content with <em>pseudo</em> <foo>markup
+#errors
+#document-fragment
+textarea
+#document
+| "textarea content with <em>pseudo</em> <foo>markup"
+
+#data
+this is CDATA inside a <style> element
+#errors
+#document-fragment
+style
+#document
+| "this is CDATA inside a <style> element"
+
+#data
+</plaintext>
+#errors
+#document-fragment
+plaintext
+#document
+| "</plaintext>"
+
+#data
+setting html's innerHTML
+#errors
+Line: 1 Col: 24 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| "setting html's innerHTML"
+
+#data
+<title>setting head's innerHTML</title>
+#errors
+#document-fragment
+head
+#document
+| <title>
+| "setting head's innerHTML"
diff --git a/pkgs/html/test/data/tree-construction/tests5.dat b/pkgs/html/test/data/tree-construction/tests5.dat
new file mode 100644
index 0000000..d7b5128
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests5.dat
@@ -0,0 +1,191 @@
+#data
+<style> <!-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| " <!-- "
+| <body>
+| "x"
+
+#data
+<style> <!-- </style> --> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<style> <!--> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!--> "
+| <body>
+| "x"
+
+#data
+<style> <!---> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!---> "
+| <body>
+| "x"
+
+#data
+<iframe> <!---> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| " <!---> "
+| "x"
+
+#data
+<iframe> <!--- </iframe>->x</iframe> --> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| " <!--- "
+| "->x --> x"
+
+#data
+<script> <!-- </script> --> </script>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<title> <!-- </title> --> </title>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<textarea> <!--- </textarea>->x</textarea> --> </textarea>x
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| " <!--- "
+| "->x --> x"
+
+#data
+<style> <!</-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!</-- "
+| <body>
+| "x"
+
+#data
+<p><xmp></xmp>
+#errors
+XXX: Unknown
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <xmp>
+
+#data
+<xmp> <!-- > --> </xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <xmp>
+| " <!-- > --> "
+
+#data
+<title>&</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "&"
+| <body>
+
+#data
+<title><!--&--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "<!--&-->"
+| <body>
+
+#data
+<title><!--</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "<!--"
+| <body>
+
+#data
+<noscript><!--</noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "-->"
diff --git a/pkgs/html/test/data/tree-construction/tests6.dat b/pkgs/html/test/data/tree-construction/tests6.dat
new file mode 100644
index 0000000..f28ece4
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests6.dat
@@ -0,0 +1,663 @@
+#data
+<!doctype html></head> <head>
+#errors
+Line: 1 Col: 29 Unexpected start tag head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| " "
+| <body>
+
+#data
+<!doctype html><form><div></form><div>
+#errors
+33: End tag "form" seen but there were unclosed elements.
+38: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <div>
+| <div>
+
+#data
+<!doctype html><title>&</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "&"
+| <body>
+
+#data
+<!doctype html><title><!--&--></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "<!--&-->"
+| <body>
+
+#data
+<!doctype>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 10 Unexpected > character. Expected DOCTYPE name.
+Line: 1 Col: 10 Erroneous DOCTYPE.
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+
+#data
+<!---x
+#errors
+Line: 1 Col: 6 Unexpected end of file in comment.
+Line: 1 Col: 6 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- -x -->
+| <html>
+| <head>
+| <body>
+
+#data
+<body>
+<div>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body).
+Line: 2 Col: 5 Expected closing tag. Unexpected end of file.
+#document-fragment
+div
+#document
+| "
+"
+| <div>
+
+#data
+<frameset></frameset>
+foo
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 3 Unexpected non-space characters in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+<noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+| <noframes>
+
+#data
+<frameset></frameset>
+<div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 5 Unexpected start tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+</html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+</div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 6 Unexpected end tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<form><form>
+#errors
+Line: 1 Col: 6 Unexpected start tag (form). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (form).
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+
+#data
+<button><button>
+#errors
+Line: 1 Col: 8 Unexpected start tag (button). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (button) implies end tag (button).
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| <button>
+
+#data
+<table><tr><td></th>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (th). Ignored.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><caption><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (td). Ignored.
+Line: 1 Col: 20 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><caption><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+</caption><div>
+#errors
+Line: 1 Col: 10 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption><div></caption>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end tag (caption). Missing end tag (div).
+Line: 1 Col: 31 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+<table><caption></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+
+#data
+</table><div>
+#errors
+Line: 1 Col: 8 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 8 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (body). Ignored.
+Line: 1 Col: 29 Unexpected end tag (col). Ignored.
+Line: 1 Col: 40 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 47 Unexpected end tag (html). Ignored.
+Line: 1 Col: 55 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 60 Unexpected end tag (td). Ignored.
+Line: 1 Col: 68 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 73 Unexpected end tag (th). Ignored.
+Line: 1 Col: 81 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 86 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 86 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+
+#data
+<table><caption><div></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 27 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+<table><tr><td></body></caption></col></colgroup></html>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (body). Ignored.
+Line: 1 Col: 32 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 38 Unexpected end tag (col). Ignored.
+Line: 1 Col: 49 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 56 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+</table></tbody></tfoot></thead></tr><div>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 24 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 32 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 37 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document-fragment
+td
+#document
+| <div>
+
+#data
+<table><colgroup>foo
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "foo"
+| <table>
+| <colgroup>
+
+#data
+foo<col>
+#errors
+Line: 1 Col: 3 Unexpected end tag (colgroup). Ignored.
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<table><colgroup></col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 This element (col) has no end tag.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+
+#data
+<frameset><div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</frameset><frame>
+#errors
+Line: 1 Col: 11 Unexpected end tag token (frameset) in the frameset phase (innerHTML).
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+<frameset></div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</body><div>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Ignored.
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document-fragment
+body
+#document
+| <div>
+
+#data
+<table><tr><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+</tr><td>
+#errors
+Line: 1 Col: 5 Unexpected end tag (tr). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</tbody></tfoot></thead><td>
+#errors
+Line: 1 Col: 8 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 24 Unexpected end tag (thead). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<table><tr><div><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected implied end tag (div) in the table row phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<caption><col><colgroup><tbody><tfoot><thead><tr>
+#errors
+Line: 1 Col: 9 Unexpected start tag (caption).
+Line: 1 Col: 14 Unexpected start tag (col).
+Line: 1 Col: 24 Unexpected start tag (colgroup).
+Line: 1 Col: 31 Unexpected start tag (tbody).
+Line: 1 Col: 38 Unexpected start tag (tfoot).
+Line: 1 Col: 45 Unexpected start tag (thead).
+Line: 1 Col: 49 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></thead>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (thead) in the table body phase. Ignored.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></body></caption></col></colgroup></html></td></th></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end tag (body) in the table body phase. Ignored.
+Line: 1 Col: 31 Unexpected end tag (caption) in the table body phase. Ignored.
+Line: 1 Col: 37 Unexpected end tag (col) in the table body phase. Ignored.
+Line: 1 Col: 48 Unexpected end tag (colgroup) in the table body phase. Ignored.
+Line: 1 Col: 55 Unexpected end tag (html) in the table body phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (td) in the table body phase. Ignored.
+Line: 1 Col: 65 Unexpected end tag (th) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end tag (tr) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+<table><tbody></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+<table><table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 14 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <table>
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end tag (body). Ignored.
+Line: 1 Col: 24 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 30 Unexpected end tag (col). Ignored.
+Line: 1 Col: 41 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 48 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 61 Unexpected end tag (td). Ignored.
+Line: 1 Col: 69 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 74 Unexpected end tag (th). Ignored.
+Line: 1 Col: 82 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 87 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 87 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+<body></body></html>
+#errors
+Line: 1 Col: 20 Unexpected html end tag in inner html mode.
+Line: 1 Col: 20 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+
+#data
+<html><frameset></frameset></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html></html>
+#errors
+Line: 1 Col: 50 Erroneous DOCTYPE.
+Line: 1 Col: 63 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "">
+| <html>
+| <head>
+| <body>
+
+#data
+<param><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (param). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<source><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (source). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<track><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (track). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</html><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</body><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+| <head>
+| <frameset>
diff --git a/pkgs/html/test/data/tree-construction/tests7.dat b/pkgs/html/test/data/tree-construction/tests7.dat
new file mode 100644
index 0000000..f5193c6
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests7.dat
@@ -0,0 +1,390 @@
+#data
+<!doctype html><body><title>X</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+
+#data
+<!doctype html><table><title>X</title></table>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) in table context caused voodoo mode.
+Line: 1 Col: 38 Unexpected end tag (title) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+| <table>
+
+#data
+<!doctype html><head></head><title>X</title>
+#errors
+Line: 1 Col: 35 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "X"
+| <body>
+
+#data
+<!doctype html></head><title>X</title>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "X"
+| <body>
+
+#data
+<!doctype html><table><meta></table>
+#errors
+Line: 1 Col: 28 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+| <table>
+
+#data
+<!doctype html><table>X<tr><td><table> <meta></table></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 45 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <meta>
+| <table>
+| " "
+
+#data
+<!doctype html><html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html><table><style> <tr>x </style> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <style>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><table><TBODY><script> <tr>x </script> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <script>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><p><applet><p>X</p></applet>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <applet>
+| <p>
+| "X"
+
+#data
+<!doctype html><listing>
+X</listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <listing>
+| "X"
+
+#data
+<!doctype html><select><input>X
+#errors
+Line: 1 Col: 30 Unexpected input start tag in the select phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <input>
+| "X"
+
+#data
+<!doctype html><select><select>X
+#errors
+Line: 1 Col: 31 Unexpected select start tag in the select phase treated as select end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+
+#data
+<!doctype html><table><input type=hidDEN></table>
+#errors
+Line: 1 Col: 41 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table>X<input type=hidDEN></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table> <input type=hidDEN></table>
+#errors
+Line: 1 Col: 43 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table> <input type='hidDEN'></table>
+#errors
+Line: 1 Col: 45 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table><input type=" hidden"><input type=hidDEN></table>
+#errors
+Line: 1 Col: 44 Unexpected start tag (input) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| type=" hidden"
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table><select>X<tr>
+#errors
+Line: 1 Col: 30 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 35 Unexpected table element start tag (trs) in the select in table phase.
+Line: 1 Col: 35 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><select>X</select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+
+#data
+<!DOCTYPE hTmL><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<body>X</body></body>
+#errors
+Line: 1 Col: 21 Unexpected end tag token (body) in the after body phase.
+Line: 1 Col: 21 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| "X"
+
+#data
+<div><p>a</x> b
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (x). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <p>
+| "a b"
+
+#data
+<table><tr><td><code></code> </table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <code>
+| " "
+
+#data
+<table><b><tr><td>aaa</td></tr>bbb</table>ccc
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <b>
+| "bbb"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "aaa"
+| <b>
+| "ccc"
+
+#data
+A<table><tr> B</tr> B</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| "A B B"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+A<table><tr> B</tr> </em>C</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| "A BC"
+| <table>
+| <tbody>
+| <tr>
+| " "
+
+#data
+<select><keygen>
+#errors
+Not known
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <keygen>
diff --git a/pkgs/html/test/data/tree-construction/tests8.dat b/pkgs/html/test/data/tree-construction/tests8.dat
new file mode 100644
index 0000000..90e6c91
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests8.dat
@@ -0,0 +1,148 @@
+#data
+<div>
+<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 3 Col: 7 Unexpected end tag (span). Ignored.
+Line: 3 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "
+"
+| <div>
+| "
+x"
+
+#data
+<div>x<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 2 Col: 7 Unexpected end tag (span). Ignored.
+Line: 2 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "
+x"
+
+#data
+<div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "xx"
+
+#data
+<div>x<div></div>y</span>z
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "yz"
+
+#data
+<table><div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 18 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 24 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span). Ignored.
+Line: 1 Col: 33 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "xx"
+| <table>
+
+#data
+x<table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 9 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "xx"
+| <table>
+
+#data
+x<table><table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 16 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <table>
+| "x"
+| <table>
+
+#data
+<b>a<div></div><div></b>y
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "a"
+| <div>
+| <div>
+| <b>
+| "y"
+
+#data
+<a><div><p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <div>
+| <a>
+| <p>
+| <a>
diff --git a/pkgs/html/test/data/tree-construction/tests9.dat b/pkgs/html/test/data/tree-construction/tests9.dat
new file mode 100644
index 0000000..554e27a
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests9.dat
@@ -0,0 +1,457 @@
+#data
+<!DOCTYPE html><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!DOCTYPE html><body><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!DOCTYPE html><math><mi>
+#errors
+25: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+
+#data
+<!DOCTYPE html><math><annotation-xml><svg><u>
+#errors
+45: HTML start tag “u” in a foreign namespace context.
+45: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <u>
+
+#data
+<!DOCTYPE html><body><select><math></math></select>
+#errors
+Line: 1 Col: 35 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 42 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!DOCTYPE html><body><select><option><math></math></option></select>
+#errors
+Line: 1 Col: 43 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 50 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!DOCTYPE html><body><table><math></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table>
+#errors
+Line: 1 Col: 41 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 72 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+| <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table>
+#errors
+Line: 1 Col: 45 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 57 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 69 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 76 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 70 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 81 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux
+#errors
+Line: 1 Col: 78 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 78 Unexpected end tag (caption). Missing end tag (math).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 44 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 56 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 68 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 71 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 71 Unexpected start tag (p) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+| <table>
+| <colgroup>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 50 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 62 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 74 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 77 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 88 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| "foobarbaz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 36 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 42 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 80 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "foobarbaz"
+| <table>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 41 Unexpected start tag (math).
+Line: 1 Col: 68 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 34 Unexpected start tag token (math) in the after body phase.
+Line: 1 Col: 61 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 31 Unexpected start tag token (math) in the frameset phase. Ignored.
+Line: 1 Col: 35 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 40 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 44 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 49 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 52 Unexpected start tag token (p) in the frameset phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (span) in the frameset phase. Ignored.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 42 Unexpected start tag (math) in the after frameset phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 51 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 55 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 63 Unexpected start tag (p) in the after frameset phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag (span) in the after frameset phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| <math math>
+| xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+| "bar"
diff --git a/pkgs/html/test/data/tree-construction/tests_innerHTML_1.dat b/pkgs/html/test/data/tree-construction/tests_innerHTML_1.dat
new file mode 100644
index 0000000..6c78661
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tests_innerHTML_1.dat
@@ -0,0 +1,741 @@
+#data
+<body><span>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<body><span>
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| <span>
+
+#data
+<frameset><span>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<frameset><span>
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <frameset>
+
+#data
+<table><tr>
+#errors
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+</table><tr>
+#errors
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+<a>
+#errors
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a>
+#errors
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a><caption>a
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <caption>
+| "a"
+
+#data
+<a><colgroup><col>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <colgroup>
+| <col>
+
+#data
+<a><tbody><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+
+#data
+<a><tfoot><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tfoot>
+| <tr>
+
+#data
+<a><thead><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <thead>
+| <tr>
+
+#data
+<a><tr>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+
+#data
+<a><th>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+| <th>
+
+#data
+<a><td>
+#errors
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table></table><tbody>
+#errors
+#document-fragment
+caption
+#document
+| <table>
+
+#data
+</table><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></table>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+</caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><caption><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><col><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><colgroup><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><html><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tbody><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><td><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tfoot><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><thead><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><th><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tr><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span></table><span>
+#errors
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+</colgroup><col>
+#errors
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<a><col>
+#errors
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<caption><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<a><tr>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<a><td>
+#errors
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<td><table><tbody><a><tr>
+#errors
+#document-fragment
+tbody
+#document
+| <tr>
+| <td>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+</tr><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table><a><tr></tr><tr>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <tr>
+
+#data
+<caption><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<col><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<colgroup><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tbody><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tfoot><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<thead><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tr><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+| <table>
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+| <table>
+| <td>
+
+#data
+<caption><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<th><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tr><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tbody><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</td><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tfoot><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</thead><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</th><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tr><a>
+#errors
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<table><td><td>
+#errors
+#document-fragment
+td
+#document
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <td>
+
+#data
+</select><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<input><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<keygen><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<textarea><option>
+#errors
+#document-fragment
+select
+#document
+| <option>
+
+#data
+</html><!--abc-->
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| <!-- abc -->
+
+#data
+</frameset><frame>
+#errors
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
diff --git a/pkgs/html/test/data/tree-construction/tricky01.dat b/pkgs/html/test/data/tree-construction/tricky01.dat
new file mode 100644
index 0000000..0841992
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/tricky01.dat
@@ -0,0 +1,261 @@
+#data
+<b><p>Bold </b> Not bold</p>
+Also not bold.
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <p>
+| <b>
+| "Bold "
+| " Not bold"
+| "
+Also not bold."
+
+#data
+<html>
+<font color=red><i>Italic and Red<p>Italic and Red </font> Just italic.</p> Italic only.</i> Plain
+<p>I should not be red. <font color=red>Red. <i>Italic and red.</p>
+<p>Italic and red. </i> Red.</font> I should not be red.</p>
+<b>Bold <i>Bold and italic</b> Only Italic </i> Plain
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| color="red"
+| <i>
+| "Italic and Red"
+| <i>
+| <p>
+| <font>
+| color="red"
+| "Italic and Red "
+| " Just italic."
+| " Italic only."
+| " Plain
+"
+| <p>
+| "I should not be red. "
+| <font>
+| color="red"
+| "Red. "
+| <i>
+| "Italic and red."
+| <font>
+| color="red"
+| <i>
+| "
+"
+| <p>
+| <font>
+| color="red"
+| <i>
+| "Italic and red. "
+| " Red."
+| " I should not be red."
+| "
+"
+| <b>
+| "Bold "
+| <i>
+| "Bold and italic"
+| <i>
+| " Only Italic "
+| " Plain"
+
+#data
+<html><body>
+<p><font size="7">First paragraph.</p>
+<p>Second paragraph.</p></font>
+<b><p><i>Bold and Italic</b> Italic</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <p>
+| <font>
+| size="7"
+| "First paragraph."
+| <font>
+| size="7"
+| "
+"
+| <p>
+| "Second paragraph."
+| "
+"
+| <b>
+| <p>
+| <b>
+| <i>
+| "Bold and Italic"
+| <i>
+| " Italic"
+
+#data
+<html>
+<dl>
+<dt><b>Boo
+<dd>Goo?
+</dl>
+</html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <dl>
+| "
+"
+| <dt>
+| <b>
+| "Boo
+"
+| <dd>
+| <b>
+| "Goo?
+"
+| <b>
+| "
+"
+
+#data
+<html><body>
+<label><a><div>Hello<div>World</div></a></label>
+</body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <label>
+| <a>
+| <div>
+| <a>
+| "Hello"
+| <div>
+| "World"
+| "
+"
+
+#data
+<table><center> <font>a</center> <img> <tr><td> </td> </tr> </table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <center>
+| " "
+| <font>
+| "a"
+| <font>
+| <img>
+| " "
+| <table>
+| " "
+| <tbody>
+| <tr>
+| <td>
+| " "
+| " "
+| " "
+
+#data
+<table><tr><p><a><p>You should see this text.
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <a>
+| <p>
+| <a>
+| "You should see this text."
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<TABLE>
+<TR>
+<CENTER><CENTER><TD></TD></TR><TR>
+<FONT>
+<TABLE><tr></tr></TABLE>
+</P>
+<a></font><font></a>
+This page contains an insanely badly-nested tag sequence.
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <center>
+| <center>
+| <font>
+| "
+"
+| <table>
+| "
+"
+| <tbody>
+| <tr>
+| "
+"
+| <td>
+| <tr>
+| "
+"
+| <table>
+| <tbody>
+| <tr>
+| <font>
+| "
+"
+| <p>
+| "
+"
+| <a>
+| <a>
+| <font>
+| <font>
+| "
+This page contains an insanely badly-nested tag sequence."
+
+#data
+<html>
+<body>
+<b><nobr><div>This text is in a div inside a nobr</nobr>More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. </b><pre>A pre tag outside everything else.</pre>
+</body>
+</html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <b>
+| <nobr>
+| <div>
+| <b>
+| <nobr>
+| "This text is in a div inside a nobr"
+| "More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. "
+| <pre>
+| "A pre tag outside everything else."
+| "
+
+"
diff --git a/pkgs/html/test/data/tree-construction/webkit01.dat b/pkgs/html/test/data/tree-construction/webkit01.dat
new file mode 100644
index 0000000..06bc436
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/webkit01.dat
@@ -0,0 +1,594 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<div>Test</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Test"
+
+#data
+<di
+#errors
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<div>Hello</div>
+<script>
+console.log("PASS");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Hello"
+| "
+"
+| <script>
+| "
+console.log("PASS");
+"
+| "
+"
+| <div>
+| "Bye"
+
+#data
+<div foo="bar">Hello</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo="bar"
+| "Hello"
+
+#data
+<div>Hello</div>
+<script>
+console.log("FOO<span>BAR</span>BAZ");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Hello"
+| "
+"
+| <script>
+| "
+console.log("FOO<span>BAR</span>BAZ");
+"
+| "
+"
+| <div>
+| "Bye"
+
+#data
+<foo bar="baz"></foo><potato quack="duck"></potato>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="baz"
+| <potato>
+| quack="duck"
+
+#data
+<foo bar="baz"><potato quack="duck"></potato></foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="baz"
+| <potato>
+| quack="duck"
+
+#data
+<foo></foo bar="baz"><potato></potato quack="duck">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| <potato>
+
+#data
+</ tttt>
+#errors
+#document
+| <!-- tttt -->
+| <html>
+| <head>
+| <body>
+
+#data
+<div FOO ><img><img></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo=""
+| <img>
+| <img>
+
+#data
+<p>Test</p<p>Test2</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "TestTest2"
+
+#data
+<rdar://problem/6869687>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <rdar:>
+| 6869687=""
+| problem=""
+
+#data
+<A>test< /A>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "test< /A>"
+
+#data
+<
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "<"
+
+#data
+<body foo='bar'><body foo='baz' yo='mama'>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| foo="bar"
+| yo="mama"
+
+#data
+<body></br foo="bar"></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<bdy><br foo="bar"></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <bdy>
+| <br>
+| foo="bar"
+
+#data
+<body></body></br foo="bar">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<bdy></body><br foo="bar">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <bdy>
+| <br>
+| foo="bar"
+
+#data
+<html><body></body></html><!-- Hi there -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <!-- Hi there -->
+
+#data
+<html><body></body></html>x<!-- Hi there -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></html><!-- Again -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+| <!-- Again -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></body></html><!-- Again -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+| <!-- Again -->
+
+#data
+<html><body><ruby><div><rp>xx</rp></div></ruby></body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <rp>
+| "xx"
+
+#data
+<html><body><ruby><div><rt>xx</rt></div></ruby></body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <rt>
+| "xx"
+
+#data
+<html><frameset><!--1--><noframes>A</noframes><!--2--></frameset><!--3--><noframes>B</noframes><!--4--></html><!--5--><noframes>C</noframes><!--6-->
+#errors
+#document
+| <html>
+| <head>
+| <frameset>
+| <!-- 1 -->
+| <noframes>
+| "A"
+| <!-- 2 -->
+| <!-- 3 -->
+| <noframes>
+| "B"
+| <!-- 4 -->
+| <noframes>
+| "C"
+| <!-- 5 -->
+| <!-- 6 -->
+
+#data
+<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "A"
+| <option>
+| "B"
+| <select>
+| <option>
+| "C"
+| <option>
+| "D"
+| <select>
+| <option>
+| "E"
+| <option>
+| "F"
+| <select>
+| <option>
+| "G"
+
+#data
+<dd><dd><dt><dt><dd><li><li>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <dd>
+| <dd>
+| <dt>
+| <dt>
+| <dd>
+| <li>
+| <li>
+
+#data
+<div><b></div><div><nobr>a<nobr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <b>
+| <div>
+| <b>
+| <nobr>
+| "a"
+| <nobr>
+
+#data
+<head></head>
+<body></body>
+#errors
+#document
+| <html>
+| <head>
+| "
+"
+| <body>
+
+#data
+<head></head> <style></style>ddd
+#errors
+#document
+| <html>
+| <head>
+| <style>
+| " "
+| <body>
+| "ddd"
+
+#data
+<kbd><table></kbd><col><select><tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <kbd>
+| <select>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+
+#data
+<kbd><table></kbd><col><select><tr></table><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <kbd>
+| <select>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <div>
+
+#data
+<a><li><style></style><title></title></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <li>
+| <a>
+| <style>
+| <title>
+
+#data
+<font></p><p><meta><title></title></font>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <p>
+| <font>
+| <meta>
+| <title>
+
+#data
+<a><center><title></title><a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <center>
+| <a>
+| <title>
+| <a>
+
+#data
+<svg><title><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <div>
+
+#data
+<svg><title><rect><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <rect>
+| <div>
+
+#data
+<svg><title><svg><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <svg svg>
+| <div>
+
+#data
+<img <="" FAIL>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <img>
+| <=""
+| fail=""
+
+#data
+<ul><li><div id='foo'/>A</li><li>B<div>C</div></li></ul>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| id="foo"
+| "A"
+| <li>
+| "B"
+| <div>
+| "C"
+
+#data
+<svg><em><desc></em>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <em>
+| <desc>
+
+#data
+<svg><tfoot></mi><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg tfoot>
+| <svg td>
+
+#data
+<math><mrow><mrow><mn>1</mn></mrow><mi>a</mi></mrow></math>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mrow>
+| <math mrow>
+| <math mn>
+| "1"
+| <math mi>
+| "a"
+
+#data
+<!doctype html><input type="hidden"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><input type="button"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| type="button"
diff --git a/pkgs/html/test/data/tree-construction/webkit02.dat b/pkgs/html/test/data/tree-construction/webkit02.dat
new file mode 100644
index 0000000..468879b
--- /dev/null
+++ b/pkgs/html/test/data/tree-construction/webkit02.dat
@@ -0,0 +1,94 @@
+#data
+<foo bar=qux/>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="qux/"
+
+#data
+<p id="status"><noscript><strong>A</strong></noscript><span>B</span></p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| id="status"
+| <noscript>
+| "<strong>A</strong>"
+| <span>
+| "B"
+
+#data
+<div><sarcasm><div></div></sarcasm></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <sarcasm>
+| <div>
+
+#data
+<html><body><img src="" border="0" alt="><div>A</div></body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<table><td></tbody>A
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "A"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><td></thead>A
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+
+#data
+<table><td></tfoot>A
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+
+#data
+<table><thead><td></tbody>A
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <thead>
+| <tr>
+| <td>
+| "A"
diff --git a/pkgs/html/test/dom_test.dart b/pkgs/html/test/dom_test.dart
new file mode 100644
index 0000000..293443f
--- /dev/null
+++ b/pkgs/html/test/dom_test.dart
@@ -0,0 +1,190 @@
+/// Additional feature tests that aren't based on test data.
+library;
+
+import 'package:html/dom.dart';
+import 'package:html/parser.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('Element', () {
+ test('classes', () {
+ final barBaz = Element.html('<div class=" bar baz"></div>');
+ final quxBaz = Element.html('<div class="qux baz "></div>');
+ expect(barBaz.className, ' bar baz');
+ expect(quxBaz.className, 'qux baz ');
+ expect(barBaz.classes, ['bar', 'baz']);
+ expect(quxBaz.classes, ['qux', 'baz']);
+ });
+ });
+
+ group('Document', () {
+ final doc = parse('<div id=foo>'
+ '<div class=" bar baz"></div>'
+ '<div class="qux baz "></div>'
+ '<div id=Foo>');
+
+ test('getElementById', () {
+ final foo = doc.body!.nodes[0];
+ final fooVar = foo.nodes[2];
+ expect((foo as Element).id, 'foo');
+ expect((fooVar as Element).id, 'Foo');
+ expect(doc.getElementById('foo'), foo);
+ expect(doc.getElementById('Foo'), fooVar);
+ });
+
+ test('getElementsByClassName', () {
+ final foo = doc.body!.nodes[0];
+ final barBaz = foo.nodes[0];
+ final quxBaz = foo.nodes[1];
+ expect((barBaz as Element).className, ' bar baz');
+ expect((quxBaz as Element).className, 'qux baz ');
+ expect(doc.getElementsByClassName('baz'), [barBaz, quxBaz]);
+ expect(doc.getElementsByClassName('bar '), [barBaz]);
+ expect(doc.getElementsByClassName(' qux'), [quxBaz]);
+ expect(doc.getElementsByClassName(' baz qux'), [quxBaz]);
+ });
+
+ test('getElementsByTagName', () {
+ final foo = doc.body!.nodes[0];
+ final barBaz = foo.nodes[0];
+ final quxBaz = foo.nodes[1];
+ final fooVar = foo.nodes[2];
+ expect(doc.getElementsByTagName('div'), [foo, barBaz, quxBaz, fooVar]);
+ });
+ });
+
+ group('fragments are flattened', () {
+ test('add', () {
+ final doc = parse('<body>');
+ doc.body!.nodes.add(parseFragment('<x-foo>'));
+ expect((doc.body!.nodes[0] as Element).localName, 'x-foo');
+ doc.body!.nodes.add(parseFragment('<x-bar>'));
+ expect((doc.body!.nodes[1] as Element).localName, 'x-bar');
+ });
+
+ test('addLast', () {
+ final doc = parse('<body>');
+ doc.body!.nodes.addLast(parseFragment('<x-foo>'));
+ expect((doc.body!.nodes[0] as Element).localName, 'x-foo');
+ doc.body!.nodes.addLast(parseFragment('<x-bar>'));
+ expect((doc.body!.nodes[1] as Element).localName, 'x-bar');
+ });
+
+ test('addAll', () {
+ final doc = parse('<body><x-a></x-a>');
+ doc.body!.nodes.addAll([parseFragment('<x-b></x-b><x-c></x-c>')]);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'x-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'x-c');
+ });
+
+ test('insert', () {
+ var doc = parse('<body><x-a></x-a>');
+ doc.body!.nodes.insert(0, parseFragment('<x-b></x-b><x-c></x-c>'));
+ expect((doc.body!.nodes[0] as Element).localName, 'x-b');
+ expect((doc.body!.nodes[1] as Element).localName, 'x-c');
+ expect((doc.body!.nodes[2] as Element).localName, 'x-a');
+
+ doc = parse('<body><x-a></x-a>');
+ doc.body!.nodes.insert(1, parseFragment('<x-b></x-b><x-c></x-c>'));
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'x-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'x-c');
+
+ doc = parse('<body><x-a></x-a>');
+ doc.body!.nodes.insert(0, parseFragment('<x-b></x-b>'));
+ doc.body!.nodes.insert(1, parseFragment('<x-c></x-c>'));
+ expect((doc.body!.nodes[0] as Element).localName, 'x-b');
+ expect((doc.body!.nodes[1] as Element).localName, 'x-c');
+ expect((doc.body!.nodes[2] as Element).localName, 'x-a');
+ });
+
+ test('insertAll', () {
+ var doc = parse('<body><x-a></x-a>');
+ doc.body!.nodes.insertAll(0, [parseFragment('<x-b></x-b><x-c></x-c>')]);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-b');
+ expect((doc.body!.nodes[1] as Element).localName, 'x-c');
+ expect((doc.body!.nodes[2] as Element).localName, 'x-a');
+ expect(doc.body!.nodes.length, 3);
+
+ doc = parse('<body><x-a></x-a>');
+ doc.body!.nodes.insertAll(1, [parseFragment('<x-b></x-b><x-c></x-c>')]);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'x-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'x-c');
+
+ doc = parse('<body><x-a></x-a>');
+ doc.body!.nodes.insertAll(0, [parseFragment('<x-b></x-b>')]);
+ doc.body!.nodes.insertAll(1, [parseFragment('<x-c></x-c>')]);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-b');
+ expect((doc.body!.nodes[1] as Element).localName, 'x-c');
+ expect((doc.body!.nodes[2] as Element).localName, 'x-a');
+ });
+
+ test('operator []=', () {
+ var doc = parse('<body><x-a></x-a>');
+ doc.body!.nodes[0] = parseFragment('<x-b></x-b><x-c></x-c>');
+ expect((doc.body!.nodes[0] as Element).localName, 'x-b');
+ expect((doc.body!.nodes[1] as Element).localName, 'x-c');
+ expect(doc.body!.nodes.length, 2);
+
+ doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
+ doc.body!.nodes[1] = parseFragment('<y-b></y-b><y-c></y-c>');
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'y-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'y-c');
+ expect((doc.body!.nodes[3] as Element).localName, 'x-c');
+ expect(doc.body!.nodes.length, 4);
+ });
+
+ test('setRange', () {
+ var fragment = parseFragment('<y-b></y-b><y-c></y-c>');
+ var doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
+ doc.body!.nodes.setRange(1, 2, fragment.nodes, 0);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'y-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'y-c');
+ expect(doc.body!.nodes.length, 3);
+
+ fragment = parseFragment('<y-b></y-b><y-c></y-c>');
+ doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
+ doc.body!.nodes.setRange(1, 1, [fragment], 0);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'y-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'y-c');
+ expect((doc.body!.nodes[3] as Element).localName, 'x-c');
+ expect(doc.body!.nodes.length, 4);
+ });
+
+ test('replaceRange', () {
+ var fragment = parseFragment('<y-b></y-b><y-c></y-c>');
+ var doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
+ doc.body!.nodes.replaceRange(1, 2, fragment.nodes);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'y-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'y-c');
+ expect((doc.body!.nodes[3] as Element).localName, 'x-c');
+ expect(doc.body!.nodes.length, 4);
+
+ fragment = parseFragment('<y-b></y-b><y-c></y-c>');
+ doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
+ doc.body!.nodes.replaceRange(1, 2, [fragment]);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'y-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'y-c');
+ expect((doc.body!.nodes[3] as Element).localName, 'x-c');
+ expect(doc.body!.nodes.length, 4);
+ });
+
+ test('replaceWith', () {
+ final fragment = parseFragment('<y-b></y-b><y-c></y-c>');
+ final doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
+ doc.body!.nodes[1].replaceWith(fragment);
+ expect((doc.body!.nodes[0] as Element).localName, 'x-a');
+ expect((doc.body!.nodes[1] as Element).localName, 'y-b');
+ expect((doc.body!.nodes[2] as Element).localName, 'y-c');
+ expect((doc.body!.nodes[3] as Element).localName, 'x-c');
+ expect(doc.body!.nodes.length, 4);
+ });
+ });
+}
diff --git a/pkgs/html/test/parser_feature_test.dart b/pkgs/html/test/parser_feature_test.dart
new file mode 100644
index 0000000..7156146
--- /dev/null
+++ b/pkgs/html/test/parser_feature_test.dart
@@ -0,0 +1,493 @@
+/// Additional feature tests that aren't based on test data.
+library;
+
+import 'package:html/dom.dart';
+import 'package:html/parser.dart';
+import 'package:html/src/constants.dart';
+import 'package:html/src/encoding_parser.dart';
+import 'package:html/src/treebuilder.dart';
+import 'package:source_span/source_span.dart';
+import 'package:test/test.dart';
+
+void main() {
+ _testElementSpans();
+ test('doctype is cloneable', () {
+ final doc = parse('<!doctype HTML>');
+ final doctype = doc.nodes[0] as DocumentType;
+ expect(doctype.clone(false).toString(), '<!DOCTYPE html>');
+ });
+
+ test('line counter', () {
+ // http://groups.google.com/group/html5lib-discuss/browse_frm/thread/f4f00e4a2f26d5c0
+ final doc = parse('<pre>\nx\n>\n</pre>');
+ expect(doc.body!.innerHtml, '<pre>x\n>\n</pre>');
+ });
+
+ test('namespace html elements on', () {
+ final doc = HtmlParser('', tree: TreeBuilder(true)).parse();
+ expect((doc.nodes[0] as Element).namespaceUri, Namespaces.html);
+ });
+
+ test('namespace html elements off', () {
+ final doc = HtmlParser('', tree: TreeBuilder(false)).parse();
+ expect((doc.nodes[0] as Element).namespaceUri, null);
+ });
+
+ test('parse error spans - full', () {
+ final parser = HtmlParser('''
+<!DOCTYPE html>
+<html>
+ <body>
+ <!DOCTYPE html>
+ </body>
+</html>
+''', generateSpans: true, sourceUrl: 'ParseError');
+ final doc = parser.parse();
+ expect(doc.body!.outerHtml, '<body>\n \n \n\n</body>');
+ expect(parser.errors.length, 1);
+ final error = parser.errors[0];
+ expect(error.errorCode, 'unexpected-doctype');
+
+ // Note: these values are 0-based, but the printed format is 1-based.
+ expect(error.span!.start.line, 3);
+ expect(error.span!.end.line, 3);
+ expect(error.span!.start.column, 2);
+ expect(error.span!.end.column, 17);
+ expect(error.span!.text, '<!DOCTYPE html>');
+
+ expect(error.toString(), '''
+On line 4, column 3 of ParseError: Unexpected DOCTYPE. Ignored.
+ ╷
+4 │ <!DOCTYPE html>
+ │ ^^^^^^^^^^^^^^^
+ ╵''');
+ });
+
+ test('parse error spans - minimal', () {
+ final parser = HtmlParser('''
+<!DOCTYPE html>
+<html>
+ <body>
+ <!DOCTYPE html>
+ </body>
+</html>
+''');
+ final doc = parser.parse();
+ expect(doc.body!.outerHtml, '<body>\n \n \n\n</body>');
+ expect(parser.errors.length, 1);
+ final error = parser.errors[0];
+ expect(error.errorCode, 'unexpected-doctype');
+ expect(error.span!.start.line, 3);
+ // Note: error position is at the end, not the beginning
+ expect(error.span!.start.column, 17);
+ });
+
+ test('text spans should have the correct length', () {
+ final textContent = '\n hello {{name}}';
+ final html = '<body><div>$textContent</div>';
+ final doc = parse(html, generateSpans: true);
+ final text = doc.body!.nodes[0].nodes[0] as Text;
+ expect(text, const TypeMatcher<Text>());
+ expect(text.data, textContent);
+ expect(text.sourceSpan!.start.offset, html.indexOf(textContent));
+ expect(text.sourceSpan!.length, textContent.length);
+ });
+
+ test('attribute spans', () {
+ final text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('element')!;
+ expect(elem.sourceSpan!.start.offset, 0);
+ expect(elem.sourceSpan!.end.offset, text.length);
+ expect(elem.sourceSpan!.text, text);
+
+ expect(elem.attributeSpans!['quux'], null);
+
+ final span = elem.attributeSpans!['extends']!;
+ expect(span.start.offset, text.indexOf('extends'));
+ expect(span.text, 'extends="x-bar"');
+ });
+
+ test('attribute value spans', () {
+ final text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('element')!;
+
+ expect(elem.attributeValueSpans!['quux'], null);
+
+ final span = elem.attributeValueSpans!['extends']!;
+ expect(span.start.offset, text.indexOf('x-bar'));
+ expect(span.text, 'x-bar');
+ });
+
+ test('attribute spans if no attributes', () {
+ final text = '<element>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('element')!;
+
+ expect(elem.attributeSpans!['quux'], null);
+ expect(elem.attributeValueSpans!['quux'], null);
+ });
+
+ test('attribute spans if no attribute value', () {
+ final text = '<foo template>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('foo')!;
+
+ expect(elem.attributeSpans!['template']!.start.offset,
+ text.indexOf('template'));
+ expect(elem.attributeValueSpans!.containsKey('template'), false);
+ });
+
+ test('attribute spans null if code parsed without spans', () {
+ final text = '<element name="x-foo" extends="x-bar" constructor="Foo">';
+ final doc = parse(text);
+ final elem = doc.querySelector('element')!;
+ expect(elem.sourceSpan, null);
+ expect(elem.attributeSpans!['quux'], null);
+ expect(elem.attributeSpans!['extends'], null);
+ });
+
+ test('void element innerHTML', () {
+ var doc = parse('<div></div>');
+ expect(doc.body!.innerHtml, '<div></div>');
+ doc = parse('<body><script></script></body>');
+ expect(doc.body!.innerHtml, '<script></script>');
+ doc = parse('<br>');
+ expect(doc.body!.innerHtml, '<br>');
+ doc = parse('<br><foo><bar>');
+ expect(doc.body!.innerHtml, '<br><foo><bar></bar></foo>');
+ });
+
+ test('empty document has html, body, and head', () {
+ final doc = parse('');
+ final html = '<html><head></head><body></body></html>';
+ expect(doc.outerHtml, html);
+ expect(doc.documentElement!.outerHtml, html);
+ expect(doc.head!.outerHtml, '<head></head>');
+ expect(doc.body!.outerHtml, '<body></body>');
+ });
+
+ test('strange table case', () {
+ final doc = parse('<table><tbody><foo>').body!;
+ expect(doc.innerHtml, '<foo></foo><table><tbody></tbody></table>');
+ });
+
+ group('html serialization', () {
+ test('attribute order', () {
+ // Note: the spec only requires a stable order.
+ // However, we preserve the input order via LinkedHashMap
+ final body = parse('<foo d=1 a=2 c=3 b=4>').body!;
+ expect(body.innerHtml, '<foo d="1" a="2" c="3" b="4"></foo>');
+ expect(body.querySelector('foo')!.attributes.remove('a'), '2');
+ expect(body.innerHtml, '<foo d="1" c="3" b="4"></foo>');
+ body.querySelector('foo')!.attributes['a'] = '0';
+ expect(body.innerHtml, '<foo d="1" c="3" b="4" a="0"></foo>');
+ });
+
+ test('escaping Text node in <script>', () {
+ final e = parseFragment('<script>a && b</script>').firstChild as Element;
+ expect(e.outerHtml, '<script>a && b</script>');
+ });
+
+ test('escaping Text node in <span>', () {
+ final e = parseFragment('<span>a && b</span>').firstChild as Element;
+ expect(e.outerHtml, '<span>a && b</span>');
+ });
+
+ test('Escaping attributes', () {
+ var e = parseFragment('<div class="a<b>">').firstChild as Element;
+ expect(e.outerHtml, '<div class="a<b>"></div>');
+ e = parseFragment('<div class=\'a"b\'>').firstChild as Element;
+ expect(e.outerHtml, '<div class="a"b"></div>');
+ });
+
+ test('Escaping non-breaking space', () {
+ final text = '<span>foO\u00A0bar</span>';
+ expect(text.codeUnitAt(text.indexOf('O') + 1), 0xA0);
+ final e = parseFragment(text).firstChild as Element;
+ expect(e.outerHtml, '<span>foO bar</span>');
+ });
+
+ test('Newline after <pre>', () {
+ var e = parseFragment('<pre>\n\nsome text</span>').firstChild as Element;
+ expect((e.firstChild as Text).data, '\nsome text');
+ expect(e.outerHtml, '<pre>\n\nsome text</pre>');
+
+ e = parseFragment('<pre>\nsome text</span>').firstChild as Element;
+ expect((e.firstChild as Text).data, 'some text');
+ expect(e.outerHtml, '<pre>some text</pre>');
+ });
+
+ test('xml namespaces', () {
+ // Note: this is a nonsensical example, but it triggers the behavior
+ // we're looking for with attribute names in foreign content.
+ final doc = parse('''
+ <body>
+ <svg>
+ <desc xlink:type="simple"
+ xlink:href="http://example.com/logo.png"
+ xlink:show="new"></desc>
+ ''');
+ final n = doc.querySelector('desc')!;
+ final keys = n.attributes.keys.toList();
+ expect(
+ keys.first,
+ isA<AttributeName>()
+ .having((n) => n.prefix, 'prefix', 'xlink')
+ .having((n) => n.namespace, 'namespace',
+ 'http://www.w3.org/1999/xlink')
+ .having((n) => n.name, 'name', 'type'));
+
+ expect(
+ n.outerHtml,
+ '<desc xlink:type="simple" '
+ 'xlink:href="http://example.com/logo.png" xlink:show="new"></desc>');
+ });
+ });
+
+ test('error printing without spans', () {
+ final parser = HtmlParser('foo');
+ final doc = parser.parse();
+ expect(doc.body!.innerHtml, 'foo');
+ expect(parser.errors.length, 1);
+ expect(parser.errors[0].errorCode, 'expected-doctype-but-got-chars');
+ expect(parser.errors[0].message,
+ 'Unexpected non-space characters. Expected DOCTYPE.');
+ expect(
+ parser.errors[0].toString(),
+ 'ParserError on line 1, column 4: Unexpected non-space characters. '
+ 'Expected DOCTYPE.\n'
+ ' ╷\n'
+ '1 │ foo\n'
+ ' │ ^\n'
+ ' ╵');
+ });
+
+ test('Element.text', () {
+ final doc = parseFragment('<div>foo<div>bar</div>baz</div>');
+ final e = doc.firstChild!;
+ final text = e.firstChild!;
+ expect((text as Text).data, 'foo');
+ expect(e.text, 'foobarbaz');
+
+ e.text = 'FOO';
+ expect(e.nodes.length, 1);
+ expect(e.firstChild, isNot(text), reason: 'should create a new tree');
+ expect((e.firstChild as Text).data, 'FOO');
+ expect(e.text, 'FOO');
+ });
+
+ test('Text.text', () {
+ final doc = parseFragment('<div>foo<div>bar</div>baz</div>');
+ final e = doc.firstChild!;
+ final text = e.firstChild as Text;
+ expect(text.data, 'foo');
+ expect(text.text, 'foo');
+
+ text.text = 'FOO';
+ expect(text.data, 'FOO');
+ expect(e.text, 'FOObarbaz');
+ expect(text.text, 'FOO');
+ });
+
+ test('Comment.text', () {
+ final doc = parseFragment('<div><!--foo-->bar</div>');
+ final e = doc.firstChild!;
+ final c = e.firstChild!;
+ expect((c as Comment).data, 'foo');
+ expect(c.text, 'foo');
+ expect(e.text, 'bar');
+
+ c.text = 'qux';
+ expect(c.data, 'qux');
+ expect(c.text, 'qux');
+ expect(e.text, 'bar');
+ });
+
+ test('foreignObject end tag', () {
+ final p = HtmlParser('''
+<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"
+ version="1.1">
+ <foreignObject width="320px" height="200px">
+ <x-flow></x-flow>
+ </foreignObject>
+</svg>''');
+ final doc = p.parseFragment();
+ expect(p.errors, isEmpty);
+ final svg = doc.querySelector('svg')!;
+ expect(svg.children[0].children[0].localName, 'x-flow');
+ });
+
+ group('Encoding pre-parser', () {
+ String? getEncoding(String s) => EncodingParser(s.codeUnits).getEncoding();
+
+ test('gets encoding from meta charset', () {
+ expect(getEncoding('<meta charset="utf-16">'), 'utf-16');
+ });
+
+ test('gets encoding from meta in head', () {
+ expect(getEncoding('<head><meta charset="utf-16">'), 'utf-16');
+ });
+
+ test('skips comments', () {
+ expect(getEncoding('<!--comment--><meta charset="utf-16">'), 'utf-16');
+ });
+
+ test('stops if no match', () {
+ // missing closing tag
+ expect(getEncoding('<meta charset="utf-16"'), null);
+ });
+
+ test('ignores whitespace', () {
+ expect(getEncoding(' <meta charset="utf-16">'), 'utf-16');
+ });
+
+ test('parses content attr', () {
+ expect(
+ getEncoding(
+ '<meta http-equiv="content-type" content="text/html; charset=UTF-8">'),
+ null);
+ });
+ });
+}
+
+void _testElementSpans() {
+ void assertSpan(SourceSpan span, int offset, int end, String text) {
+ expect(span, isNotNull);
+ expect(span.start.offset, offset);
+ expect(span.end.offset, end);
+ expect(span.text, text);
+ }
+
+ group('element spans', () {
+ test('html and body', () {
+ final text = '<html><body>123</body></html>';
+ final doc = parse(text, generateSpans: true);
+ {
+ final elem = doc.querySelector('html')!;
+ assertSpan(elem.sourceSpan!, 0, 6, '<html>');
+ assertSpan(elem.endSourceSpan!, 22, 29, '</html>');
+ }
+ {
+ final elem = doc.querySelector('body')!;
+ assertSpan(elem.sourceSpan!, 6, 12, '<body>');
+ assertSpan(elem.endSourceSpan!, 15, 22, '</body>');
+ }
+ });
+
+ test('normal', () {
+ final text = '<div><element><span></span></element></div>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('element')!;
+ assertSpan(elem.sourceSpan!, 5, 14, '<element>');
+ assertSpan(elem.endSourceSpan!, 27, 37, '</element>');
+ });
+
+ test('block', () {
+ final text = '<div>123</div>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('div')!;
+ assertSpan(elem.sourceSpan!, 0, 5, '<div>');
+ assertSpan(elem.endSourceSpan!, 8, 14, '</div>');
+ });
+
+ test('form', () {
+ final text = '<form>123</form>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('form')!;
+ assertSpan(elem.sourceSpan!, 0, 6, '<form>');
+ assertSpan(elem.endSourceSpan!, 9, 16, '</form>');
+ });
+
+ test('p explicit end', () {
+ final text = '<p>123</p>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('p')!;
+ assertSpan(elem.sourceSpan!, 0, 3, '<p>');
+ assertSpan(elem.endSourceSpan!, 6, 10, '</p>');
+ });
+
+ test('p implicit end', () {
+ final text = '<div><p>123<p>456</div>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('p')!;
+ assertSpan(elem.sourceSpan!, 5, 8, '<p>');
+ expect(elem.endSourceSpan, isNull);
+ });
+
+ test('li', () {
+ final text = '<li>123</li>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('li')!;
+ assertSpan(elem.sourceSpan!, 0, 4, '<li>');
+ assertSpan(elem.endSourceSpan!, 7, 12, '</li>');
+ });
+
+ test('heading', () {
+ final text = '<h1>123</h1>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('h1')!;
+ assertSpan(elem.sourceSpan!, 0, 4, '<h1>');
+ assertSpan(elem.endSourceSpan!, 7, 12, '</h1>');
+ });
+
+ test('formatting', () {
+ final text = '<b>123</b>';
+ final doc = parse(text, generateSpans: true);
+ final elem = doc.querySelector('b')!;
+ assertSpan(elem.sourceSpan!, 0, 3, '<b>');
+ assertSpan(elem.endSourceSpan!, 6, 10, '</b>');
+ });
+
+ test('table tbody', () {
+ final text = '<table><tbody> </tbody></table>';
+ final doc = parse(text, generateSpans: true);
+ {
+ final elem = doc.querySelector('tbody')!;
+ assertSpan(elem.sourceSpan!, 7, 14, '<tbody>');
+ assertSpan(elem.endSourceSpan!, 16, 24, '</tbody>');
+ }
+ });
+
+ test('table tr td', () {
+ final text = '<table><tr><td>123</td></tr></table>';
+ final doc = parse(text, generateSpans: true);
+ {
+ final elem = doc.querySelector('table')!;
+ assertSpan(elem.sourceSpan!, 0, 7, '<table>');
+ assertSpan(elem.endSourceSpan!, 28, 36, '</table>');
+ }
+ {
+ final elem = doc.querySelector('tr')!;
+ assertSpan(elem.sourceSpan!, 7, 11, '<tr>');
+ assertSpan(elem.endSourceSpan!, 23, 28, '</tr>');
+ }
+ {
+ final elem = doc.querySelector('td')!;
+ assertSpan(elem.sourceSpan!, 11, 15, '<td>');
+ assertSpan(elem.endSourceSpan!, 18, 23, '</td>');
+ }
+ });
+
+ test('select optgroup option', () {
+ final text = '<select><optgroup><option>123</option></optgroup></select>';
+ final doc = parse(text, generateSpans: true);
+ {
+ final elem = doc.querySelector('select')!;
+ assertSpan(elem.sourceSpan!, 0, 8, '<select>');
+ assertSpan(elem.endSourceSpan!, 49, 58, '</select>');
+ }
+ {
+ final elem = doc.querySelector('optgroup')!;
+ assertSpan(elem.sourceSpan!, 8, 18, '<optgroup>');
+ assertSpan(elem.endSourceSpan!, 38, 49, '</optgroup>');
+ }
+ {
+ final elem = doc.querySelector('option')!;
+ assertSpan(elem.sourceSpan!, 18, 26, '<option>');
+ assertSpan(elem.endSourceSpan!, 29, 38, '</option>');
+ }
+ });
+ });
+}
diff --git a/pkgs/html/test/parser_test.dart b/pkgs/html/test/parser_test.dart
new file mode 100644
index 0000000..952c1b2
--- /dev/null
+++ b/pkgs/html/test/parser_test.dart
@@ -0,0 +1,109 @@
+@TestOn('vm')
+library;
+
+import 'dart:convert';
+
+import 'package:html/dom.dart';
+import 'package:html/parser.dart';
+import 'package:path/path.dart' as pathos;
+import 'package:test/test.dart';
+
+import 'support.dart';
+
+// Run the parse error checks
+// TODO(jmesserly): presumably we want this on by default?
+final checkParseErrors = false;
+
+String namespaceHtml(String expected) {
+ // TODO(jmesserly): this is a workaround for http://dartbug.com/2979
+ // We can't do regex replace directly =\
+ // final namespaceExpected = new RegExp(@"^(\s*)<(\S+)>", multiLine: true);
+ // return expected.replaceAll(namespaceExpected, @"$1<html $2>");
+ final namespaceExpected = RegExp(r'^(\|\s*)<(\S+)>');
+ final lines = expected.split('\n');
+ for (var i = 0; i < lines.length; i++) {
+ final match = namespaceExpected.firstMatch(lines[i]);
+ if (match != null) {
+ lines[i] = '${match[1]}<html ${match[2]}>';
+ }
+ }
+ return lines.join('\n');
+}
+
+void runParserTest(
+ String groupName,
+ String? innerHTML,
+ String? input,
+ String? expected,
+ List<String>? errors,
+ TreeBuilderFactory treeCtor,
+ bool namespaceHTMLElements) {
+ // XXX - move this out into the setup function
+ // concatenate all consecutive character tokens into a single token
+ final builder = treeCtor(namespaceHTMLElements);
+ final parser = HtmlParser(input, tree: builder);
+
+ Node document;
+ if (innerHTML != null) {
+ document = parser.parseFragment(innerHTML);
+ } else {
+ document = parser.parse();
+ }
+
+ final output = testSerializer(document);
+
+ if (namespaceHTMLElements) {
+ expected = namespaceHtml(expected!);
+ }
+
+ expect(output, equals(expected),
+ reason:
+ '\n\nInput:\n$input\n\nExpected:\n$expected\n\nReceived:\n$output');
+
+ if (checkParseErrors) {
+ expect(parser.errors.length, equals(errors!.length),
+ reason: '\n\nInput:\n$input\n\nExpected errors (${errors.length}):\n'
+ "${errors.join('\n')}\n\n"
+ 'Actual errors (${parser.errors.length}):\n'
+ "${parser.errors.map((e) => '$e').join('\n')}");
+ }
+}
+
+void main() async {
+ await for (var path in dataFiles('tree-construction')) {
+ if (!path.endsWith('.dat')) continue;
+
+ final tests = TestData(path, 'data');
+ final testName = pathos.basenameWithoutExtension(path);
+
+ group(testName, () {
+ for (var testData in tests) {
+ final input = testData['data'];
+ final errorString = testData['errors'];
+ final errors = errorString?.split('\n');
+ final innerHTML = testData['document-fragment'];
+ final expected = testData['document'];
+
+ for (var treeCtor in treeTypes!.values) {
+ for (var namespaceHTMLElements in const [false, true]) {
+ test(_nameFor(input!), () {
+ runParserTest(testName, innerHTML, input, expected, errors,
+ treeCtor, namespaceHTMLElements);
+ });
+ }
+ }
+ }
+ });
+ }
+}
+
+/// Extract the name for the test based on the test input data.
+dynamic _nameFor(String input) {
+ // Using jsonDecode to unescape other unicode characters
+ final escapeQuote = input
+ .replaceAll(RegExp('\\\\.'), '_')
+ .replaceAll(RegExp('\u0000'), '_')
+ .replaceAll('"', '\\"')
+ .replaceAll(RegExp('[\n\r\t]'), '_');
+ return jsonDecode('"$escapeQuote"');
+}
diff --git a/pkgs/html/test/query_selector_test.dart b/pkgs/html/test/query_selector_test.dart
new file mode 100644
index 0000000..495b0f1
--- /dev/null
+++ b/pkgs/html/test/query_selector_test.dart
@@ -0,0 +1,24 @@
+import 'package:html/dom.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('querySelector descendant', () {
+ late Element el;
+
+ setUp(() {
+ el = Element.html('<div id="a" class="a"><div id="b"></div></div>');
+ });
+
+ test('descendant of type', () {
+ expect(el.querySelector('div div')?.id, 'b');
+ });
+
+ test('descendant of class', () {
+ expect(el.querySelector('.a div')?.id, 'b');
+ });
+
+ test('descendant of type and class', () {
+ expect(el.querySelector('div.a div')?.id, 'b');
+ });
+ });
+}
diff --git a/pkgs/html/test/selectors/LICENSE b/pkgs/html/test/selectors/LICENSE
new file mode 100644
index 0000000..0dc0193
--- /dev/null
+++ b/pkgs/html/test/selectors/LICENSE
@@ -0,0 +1,9 @@
+Contents of this folder are ported from
+https://github.com/w3c/web-platform-tests/tree/master/selectors-api
+
+It is based on commit 96c61ac7c21f7f37526d1c03c4c6087734524130
+
+The original code is covered by the dual-licensing approach described in:
+
+ http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html
+
\ No newline at end of file
diff --git a/pkgs/html/test/selectors/README b/pkgs/html/test/selectors/README
new file mode 100644
index 0000000..d6e3852
--- /dev/null
+++ b/pkgs/html/test/selectors/README
@@ -0,0 +1,9 @@
+Contents of this folder are ported from
+https://github.com/w3c/web-platform-tests/tree/master/selectors-api
+
+It is based on commit 96c61ac7c21f7f37526d1c03c4c6087734524130
+
+It is used to test the implementation of querySelector/querySelectorAll.
+
+Not all code was ported; as the current implementation doesn't yet support
+all features of those methods.
diff --git a/pkgs/html/test/selectors/level1-content.html b/pkgs/html/test/selectors/level1-content.html
new file mode 100644
index 0000000..b90d918
--- /dev/null
+++ b/pkgs/html/test/selectors/level1-content.html
@@ -0,0 +1,377 @@
+<!DOCTYPE html>
+<html id="html" lang="en">
+<head id="head">
+ <meta id="meta" charset="UTF-8">
+ <title id="title">Selectors-API Test Suite: HTML with Selectors Level 2 using TestHarness: Test Document</title>
+
+ <!-- Links for :link and :visited pseudo-class test -->
+ <link id="pseudo-link-link1" href="">
+ <link id="pseudo-link-link2" href="http://example.org/">
+ <link id="pseudo-link-link3">
+ <style>
+ @namespace ns "http://www.w3.org/1999/xhtml";
+ /* Declare the namespace prefix used in tests. This declaration should not be used by the API. */
+ </style>
+</head>
+<body id="body">
+<div id="root">
+ <div id="target"></div>
+
+ <div id="universal">
+ <p id="universal-p1">Universal selector tests inside element with <code id="universal-code1">id="universal"</code>.</p>
+ <hr id="universal-hr1">
+ <pre id="universal-pre1">Some preformatted text with some <span id="universal-span1">embedded code</span></pre>
+ <p id="universal-p2">This is a normal link: <a id="universal-a1" href="http://www.w3.org/">W3C</a></p>
+ <address id="universal-address1">Some more nested elements <code id="universal-code2"><a href="#" id="universal-a2">code hyperlink</a></code></address>
+ </div>
+
+ <div id="attr-presence">
+ <div class="attr-presence-div1" id="attr-presence-div1" align="center"></div>
+ <div class="attr-presence-div2" id="attr-presence-div2" align=""></div>
+ <div class="attr-presence-div3" id="attr-presence-div3" valign="center"></div>
+ <div class="attr-presence-div4" id="attr-presence-div4" alignv="center"></div>
+ <p id="attr-presence-p1"><a id="attr-presence-a1" tItLe=""></a><span id="attr-presence-span1" TITLE="attr-presence-span1"></span></p>
+ <pre id="attr-presence-pre1" data-attr-presence="pre1"></pre>
+ <blockquote id="attr-presence-blockquote1" data-attr-presence="blockquote1"></blockquote>
+ <ul id="attr-presence-ul1" data-中文=""></ul>
+
+ <select id="attr-presence-select1">
+ <option id="attr-presence-select1-option1">A</option>
+ <option id="attr-presence-select1-option2">B</option>
+ <option id="attr-presence-select1-option3">C</option>
+ <option id="attr-presence-select1-option4">D</option>
+ </select>
+ <select id="attr-presence-select2">
+ <option id="attr-presence-select2-option1">A</option>
+ <option id="attr-presence-select2-option2">B</option>
+ <option id="attr-presence-select2-option3">C</option>
+ <option id="attr-presence-select2-option4" selected="selected">D</option>
+ </select>
+ <select id="attr-presence-select3" multiple="multiple">
+ <option id="attr-presence-select3-option1">A</option>
+ <option id="attr-presence-select3-option2" selected="">B</option>
+ <option id="attr-presence-select3-option3" selected="selected">C</option>
+ <option id="attr-presence-select3-option4">D</option>
+ </select>
+ </div>
+
+ <div id="attr-value">
+ <div id="attr-value-div1" align="center"></div>
+ <div id="attr-value-div2" align=""></div>
+ <div id="attr-value-div3" data-attr-value="é"></div>
+ <div id="attr-value-div4" data-attr-value_foo="é"></div>
+
+ <form id="attr-value-form1">
+ <input id="attr-value-input1" type="text">
+ <input id="attr-value-input2" type="password">
+ <input id="attr-value-input3" type="hidden">
+ <input id="attr-value-input4" type="radio">
+ <input id="attr-value-input5" type="checkbox">
+ <input id="attr-value-input6" type="radio">
+ <input id="attr-value-input7" type="text">
+ <input id="attr-value-input8" type="hidden">
+ <input id="attr-value-input9" type="radio">
+ </form>
+
+ <div id="attr-value-div5" data-attr-value="中文"></div>
+ </div>
+
+ <div id="attr-whitespace">
+ <div id="attr-whitespace-div1" class="foo div1 bar"></div>
+ <div id="attr-whitespace-div2" class=""></div>
+ <div id="attr-whitespace-div3" class="foo div3 bar"></div>
+
+ <div id="attr-whitespace-div4" data-attr-whitespace="foo é bar"></div>
+ <div id="attr-whitespace-div5" data-attr-whitespace_foo="é foo"></div>
+
+ <a id="attr-whitespace-a1" rel="next bookmark"></a>
+ <a id="attr-whitespace-a2" rel="tag nofollow"></a>
+ <a id="attr-whitespace-a3" rel="tag bookmark"></a>
+ <a id="attr-whitespace-a4" rel="book mark"></a> <!-- Intentional space in "book mark" -->
+ <a id="attr-whitespace-a5" rel="nofollow"></a>
+ <a id="attr-whitespace-a6" rev="bookmark nofollow"></a>
+ <a id="attr-whitespace-a7" rel="prev next tag alternate nofollow author help icon noreferrer prefetch search stylesheet tag"></a>
+
+ <p id="attr-whitespace-p1" title="Chinese 中文 characters"></p>
+ </div>
+
+ <div id="attr-hyphen">
+ <div id="attr-hyphen-div1"></div>
+ <div id="attr-hyphen-div2" lang="fr"></div>
+ <div id="attr-hyphen-div3" lang="en-AU"></div>
+ <div id="attr-hyphen-div4" lang="es"></div>
+ </div>
+
+ <div id="attr-begins">
+ <a id="attr-begins-a1" href="http://www.example.org"></a>
+ <a id="attr-begins-a2" href="http://example.org/"></a>
+ <a id="attr-begins-a3" href="http://www.example.com/"></a>
+
+ <div id="attr-begins-div1" lang="fr"></div>
+ <div id="attr-begins-div2" lang="en-AU"></div>
+ <div id="attr-begins-div3" lang="es"></div>
+ <div id="attr-begins-div4" lang="en-US"></div>
+ <div id="attr-begins-div5" lang="en"></div>
+
+ <p id="attr-begins-p1" class=" apple"></p> <!-- Intentional space in class value " apple". -->
+ </div>
+
+ <div id="attr-ends">
+ <a id="attr-ends-a1" href="http://www.example.org"></a>
+ <a id="attr-ends-a2" href="http://example.org/"></a>
+ <a id="attr-ends-a3" href="http://www.example.org"></a>
+
+ <div id="attr-ends-div1" lang="fr"></div>
+ <div id="attr-ends-div2" lang="de-CH"></div>
+ <div id="attr-ends-div3" lang="es"></div>
+ <div id="attr-ends-div4" lang="fr-CH"></div>
+
+ <p id="attr-ends-p1" class="apple "></p> <!-- Intentional space in class value "apple ". -->
+ </div>
+
+ <div id="attr-contains">
+ <a id="attr-contains-a1" href="http://www.example.org"></a>
+ <a id="attr-contains-a2" href="http://example.org/"></a>
+ <a id="attr-contains-a3" href="http://www.example.com/"></a>
+
+ <div id="attr-contains-div1" lang="fr"></div>
+ <div id="attr-contains-div2" lang="en-AU"></div>
+ <div id="attr-contains-div3" lang="de-CH"></div>
+ <div id="attr-contains-div4" lang="es"></div>
+ <div id="attr-contains-div5" lang="fr-CH"></div>
+ <div id="attr-contains-div6" lang="en-US"></div>
+
+ <p id="attr-contains-p1" class=" apple banana orange "></p>
+ </div>
+
+ <div id="pseudo-nth">
+ <table id="pseudo-nth-table1">
+ <tr id="pseudo-nth-tr1"><td id="pseudo-nth-td1"></td><td id="pseudo-nth-td2"></td><td id="pseudo-nth-td3"></td><td id="pseudo-nth-td4"></td><td id="pseudo-nth--td5"></td><td id="pseudo-nth-td6"></td></tr>
+ <tr id="pseudo-nth-tr2"><td id="pseudo-nth-td7"></td><td id="pseudo-nth-td8"></td><td id="pseudo-nth-td9"></td><td id="pseudo-nth-td10"></td><td id="pseudo-nth-td11"></td><td id="pseudo-nth-td12"></td></tr>
+ <tr id="pseudo-nth-tr3"><td id="pseudo-nth-td13"></td><td id="pseudo-nth-td14"></td><td id="pseudo-nth-td15"></td><td id="pseudo-nth-td16"></td><td id="pseudo-nth-td17"></td><td id="pseudo-nth-td18"></td></tr>
+ </table>
+
+ <ol id="pseudo-nth-ol1">
+ <li id="pseudo-nth-li1"></li>
+ <li id="pseudo-nth-li2"></li>
+ <li id="pseudo-nth-li3"></li>
+ <li id="pseudo-nth-li4"></li>
+ <li id="pseudo-nth-li5"></li>
+ <li id="pseudo-nth-li6"></li>
+ <li id="pseudo-nth-li7"></li>
+ <li id="pseudo-nth-li8"></li>
+ <li id="pseudo-nth-li9"></li>
+ <li id="pseudo-nth-li10"></li>
+ <li id="pseudo-nth-li11"></li>
+ <li id="pseudo-nth-li12"></li>
+ </ol>
+
+ <p id="pseudo-nth-p1">
+ <span id="pseudo-nth-span1">span1</span>
+ <em id="pseudo-nth-em1">em1</em>
+ <!-- comment node-->
+ <em id="pseudo-nth-em2">em2</em>
+ <span id="pseudo-nth-span2">span2</span>
+ <strong id="pseudo-nth-strong1">strong1</strong>
+ <em id="pseudo-nth-em3">em3</em>
+ <span id="pseudo-nth-span3">span3</span>
+ <span id="pseudo-nth-span4">span4</span>
+ <strong id="pseudo-nth-strong2">strong2</strong>
+ <em id="pseudo-nth-em4">em4</em>
+ </p>
+ </div>
+
+ <div id="pseudo-first-child">
+ <div id="pseudo-first-child-div1"></div>
+ <div id="pseudo-first-child-div2"></div>
+ <div id="pseudo-first-child-div3"></div>
+
+ <p id="pseudo-first-child-p1"><span id="pseudo-first-child-span1"></span><span id="pseudo-first-child-span2"></span></p>
+ <p id="pseudo-first-child-p2"><span id="pseudo-first-child-span3"></span><span id="pseudo-first-child-span4"></span></p>
+ <p id="pseudo-first-child-p3"><span id="pseudo-first-child-span5"></span><span id="pseudo-first-child-span6"></span></p>
+ </div>
+
+ <div id="pseudo-last-child">
+ <p id="pseudo-last-child-p1"><span id="pseudo-last-child-span1"></span><span id="pseudo-last-child-span2"></span></p>
+ <p id="pseudo-last-child-p2"><span id="pseudo-last-child-span3"></span><span id="pseudo-last-child-span4"></span></p>
+ <p id="pseudo-last-child-p3"><span id="pseudo-last-child-span5"></span><span id="pseudo-last-child-span6"></span></p>
+
+ <div id="pseudo-last-child-div1"></div>
+ <div id="pseudo-last-child-div2"></div>
+ <div id="pseudo-last-child-div3"></div>
+ </div>
+
+ <div id="pseudo-only">
+ <p id="pseudo-only-p1">
+ <span id="pseudo-only-span1"></span>
+ </p>
+ <p id="pseudo-only-p2">
+ <span id="pseudo-only-span2"></span>
+ <span id="pseudo-only-span3"></span>
+ </p>
+ <p id="pseudo-only-p3">
+ <span id="pseudo-only-span4"></span>
+ <em id="pseudo-only-em1"></em>
+ <span id="pseudo-only-span5"></span>
+ </p>
+ </div>>
+
+ <div id="pseudo-empty">
+ <p id="pseudo-empty-p1"></p>
+ <p id="pseudo-empty-p2"><!-- comment node --></p>
+ <p id="pseudo-empty-p3"> </p>
+ <p id="pseudo-empty-p4">Text node</p>
+ <p id="pseudo-empty-p5"><span id="pseudo-empty-span1"></span></p>
+ </div>
+
+ <div id="pseudo-link">
+ <a id="pseudo-link-a1" href="">with href</a>
+ <a id="pseudo-link-a2" href="http://example.org/">with href</a>
+ <a id="pseudo-link-a3">without href</a>
+ <map name="pseudo-link-map1" id="pseudo-link-map1">
+ <area id="pseudo-link-area1" href="">
+ <area id="pseudo-link-area2">
+ </map>
+ </div>
+
+ <div id="pseudo-lang">
+ <div id="pseudo-lang-div1"></div>
+ <div id="pseudo-lang-div2" lang="fr"></div>
+ <div id="pseudo-lang-div3" lang="en-AU"></div>
+ <div id="pseudo-lang-div4" lang="es"></div>
+ </div>
+
+ <div id="pseudo-ui">
+ <input id="pseudo-ui-input1" type="text">
+ <input id="pseudo-ui-input2" type="password">
+ <input id="pseudo-ui-input3" type="radio">
+ <input id="pseudo-ui-input4" type="radio" checked="checked">
+ <input id="pseudo-ui-input5" type="checkbox">
+ <input id="pseudo-ui-input6" type="checkbox" checked="checked">
+ <input id="pseudo-ui-input7" type="submit">
+ <input id="pseudo-ui-input8" type="button">
+ <input id="pseudo-ui-input9" type="hidden">
+ <textarea id="pseudo-ui-textarea1"></textarea>
+ <button id="pseudo-ui-button1">Enabled</button>
+
+ <input id="pseudo-ui-input10" disabled="disabled" type="text">
+ <input id="pseudo-ui-input11" disabled="disabled" type="password">
+ <input id="pseudo-ui-input12" disabled="disabled" type="radio">
+ <input id="pseudo-ui-input13" disabled="disabled" type="radio" checked="checked">
+ <input id="pseudo-ui-input14" disabled="disabled" type="checkbox">
+ <input id="pseudo-ui-input15" disabled="disabled" type="checkbox" checked="checked">
+ <input id="pseudo-ui-input16" disabled="disabled" type="submit">
+ <input id="pseudo-ui-input17" disabled="disabled" type="button">
+ <input id="pseudo-ui-input18" disabled="disabled" type="hidden">
+ <textarea id="pseudo-ui-textarea2" disabled="disabled"></textarea>
+ <button id="pseudo-ui-button2" disabled="disabled">Disabled</button>
+ </div>
+
+ <div id="not">
+ <div id="not-div1"></div>
+ <div id="not-div2"></div>
+ <div id="not-div3"></div>
+
+ <p id="not-p1"><span id="not-span1"></span><em id="not-em1"></em></p>
+ <p id="not-p2"><span id="not-span2"></span><em id="not-em2"></em></p>
+ <p id="not-p3"><span id="not-span3"></span><em id="not-em3"></em></p>
+ </div>
+
+ <div id="pseudo-element">All pseudo-element tests</div>
+
+ <div id="class">
+ <p id="class-p1" class="foo class-p bar"></p>
+ <p id="class-p2" class="class-p foo bar"></p>
+ <p id="class-p3" class="foo bar class-p"></p>
+
+ <!-- All permutations of the classes should match -->
+ <div id="class-div1" class="apple orange banana"></div>
+ <div id="class-div2" class="apple banana orange"></div>
+ <p id="class-p4" class="orange apple banana"></p>
+ <div id="class-div3" class="orange banana apple"></div>
+ <p id="class-p6" class="banana apple orange"></p>
+ <div id="class-div4" class="banana orange apple"></div>
+ <div id="class-div5" class="apple orange"></div>
+ <div id="class-div6" class="apple banana"></div>
+ <div id="class-div7" class="orange banana"></div>
+
+ <span id="class-span1" class="台北Táiběi 台北"></span>
+ <span id="class-span2" class="台北"></span>
+
+ <span id="class-span3" class="foo:bar"></span>
+ <span id="class-span4" class="test.foo[5]bar"></span>
+ </div>
+
+ <div id="id">
+ <div id="id-div1"></div>
+ <div id="id-div2"></div>
+
+ <ul id="id-ul1">
+ <li id="id-li-duplicate"></li>
+ <li id="id-li-duplicate"></li>
+ <li id="id-li-duplicate"></li>
+ <li id="id-li-duplicate"></li>
+ </ul>
+
+ <span id="台北Táiběi"></span>
+ <span id="台北"></span>
+
+ <span id="#foo:bar"></span>
+ <span id="test.foo[5]bar"></span>
+ </div>
+
+ <div id="descendant">
+ <div id="descendant-div1" class="descendant-div1">
+ <div id="descendant-div2" class="descendant-div2">
+ <div id="descendant-div3" class="descendant-div3">
+ </div>
+ </div>
+ </div>
+ <div id="descendant-div4" class="descendant-div4"></div>
+ </div>
+
+ <div id="child">
+ <div id="child-div1" class="child-div1">
+ <div id="child-div2" class="child-div2">
+ <div id="child-div3" class="child-div3">
+ </div>
+ </div>
+ </div>
+ <div id="child-div4" class="child-div4"></div>
+ </div>
+
+ <div id="adjacent">
+ <div id="adjacent-div1" class="adjacent-div1"></div>
+ <div id="adjacent-div2" class="adjacent-div2">
+ <div id="adjacent-div3" class="adjacent-div3"></div>
+ </div>
+ <div id="adjacent-div4" class="adjacent-div4">
+ <p id="adjacent-p1" class="adjacent-p1"></p>
+ <div id="adjacent-div5" class="adjacent-div5"></div>
+ </div>
+ <div id="adjacent-div6" class="adjacent-div6"></div>
+ <p id="adjacent-p2" class="adjacent-p2"></p>
+ <p id="adjacent-p3" class="adjacent-p3"></p>
+ </div>
+
+ <div id="sibling">
+ <div id="sibling-div1" class="sibling-div"></div>
+ <div id="sibling-div2" class="sibling-div">
+ <div id="sibling-div3" class="sibling-div"></div>
+ </div>
+ <div id="sibling-div4" class="sibling-div">
+ <p id="sibling-p1" class="sibling-p"></p>
+ <div id="sibling-div5" class="sibling-div"></div>
+ </div>
+ <div id="sibling-div6" class="sibling-div"></div>
+ <p id="sibling-p2" class="sibling-p"></p>
+ <p id="sibling-p3" class="sibling-p"></p>
+ </div>
+
+ <div id="group">
+ <em id="group-em1"></em>
+ <strong id="group-strong1"></strong>
+ </div>
+</div>
+</body>
+</html>
diff --git a/pkgs/html/test/selectors/level1_baseline_test.dart b/pkgs/html/test/selectors/level1_baseline_test.dart
new file mode 100644
index 0000000..d5614e9
--- /dev/null
+++ b/pkgs/html/test/selectors/level1_baseline_test.dart
@@ -0,0 +1,126 @@
+/// Test for the Selectors API ported from
+/// <https://github.com/w3c/web-platform-tests/tree/master/selectors-api>
+///
+/// Note, unlike the original we don't operate in-browser on a DOM loaded into
+/// an iframe, but instead operate over a parsed DOM.
+
+@TestOn('vm')
+library;
+
+import 'dart:io';
+
+import 'package:html/dom.dart';
+import 'package:html/parser.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+
+import '../support.dart';
+import 'level1_lib.dart';
+import 'selectors.dart';
+
+Future<Document> testContentDocument() async {
+ final testPath =
+ p.join(await testDirectory, 'selectors', 'level1-content.html');
+ return parse(File(testPath).readAsStringSync());
+}
+
+int testType = testQsaBaseline; // Only run baseline tests.
+String docType = 'html'; // Only run tests suitable for HTML
+
+void main() async {
+ /*
+ * This test suite tests Selectors API methods in 4 different contexts:
+ * 1. Document node
+ * 2. In-document Element node
+ * 3. Detached Element node (an element with no parent, not in the document)
+ * 4. Document Fragment node
+ *
+ * For each context, the following tests are run:
+ *
+ * The interface check tests ensure that each type of node exposes the Selectors API methods
+ *
+ * The special selector tests verify the result of passing special values for the selector parameter,
+ * to ensure that the correct WebIDL processing is performed, such as stringification of null and
+ * undefined and missing parameter. The universal selector is also tested here, rather than with the
+ * rest of ordinary selectors for practical reasons.
+ *
+ * The static list verification tests ensure that the node lists returned by the method remain unchanged
+ * due to subsequent document modication, and that a new list is generated each time the method is
+ * invoked based on the current state of the document.
+ *
+ * The invalid selector tests ensure that SyntaxError is thrown for invalid forms of selectors
+ *
+ * The valid selector tests check the result from querying many different types of selectors, with a
+ * list of expected elements. This checks that querySelector() always returns the first result from
+ * querySelectorAll(), and that all matching elements are correctly returned in tree-order. The tests
+ * can be limited by specifying the test types to run, using the testType variable. The constants for this
+ * can be found in selectors.js.
+ *
+ * All the selectors tested for both the valid and invalid selector tests are found in selectors.js.
+ * See comments in that file for documentation of the format used.
+ *
+ * The level1-lib.js file contains all the common test functions for running each of the aforementioned tests
+ */
+
+ // Prepare the nodes for testing
+ //doc = frame.contentDocument; // Document Node tests
+ doc = await testContentDocument();
+
+ final element = doc.getElementById('root')!; // In-document Element Node tests
+
+ //Setup the namespace tests
+ setupSpecialElements(element);
+
+ final outOfScope = element
+ .clone(true); // Append this to the body before running the in-document
+ // Element tests, but after running the Document tests. This
+ // tests that no elements that are not descendants of element
+ // are selected.
+
+ traverse(outOfScope, (elem) {
+ // Annotate each element as being a clone; used for verifying
+ elem.attributes['data-clone'] =
+ ''; // that none of these elements ever match.
+ });
+
+ final detached = element.clone(true); // Detached Element Node tests
+
+ final fragment = doc.createDocumentFragment(); // Fragment Node tests
+ fragment.append(element.clone(true));
+
+ // Setup Tests
+ runSpecialSelectorTests('Document', SelectorAdaptor.document(doc));
+ runSpecialSelectorTests(
+ 'Detached Element', SelectorAdaptor.element(detached));
+ runSpecialSelectorTests('Fragment', SelectorAdaptor.fragment(fragment));
+ runSpecialSelectorTests(
+ 'In-document Element', SelectorAdaptor.element(element));
+
+ verifyStaticList('Document', SelectorAdaptor.document(doc));
+ verifyStaticList('Detached Element', SelectorAdaptor.element(detached));
+ verifyStaticList('Fragment', SelectorAdaptor.fragment(fragment));
+ verifyStaticList('In-document Element', SelectorAdaptor.element(element));
+
+ // TODO(jmesserly): fix negative tests
+ //runInvalidSelectorTest('Document', doc, invalidSelectors);
+ //runInvalidSelectorTest('Detached Element', detached, invalidSelectors);
+ //runInvalidSelectorTest('Fragment', fragment, invalidSelectors);
+ //runInvalidSelectorTest('In-document Element', element, invalidSelectors);
+
+ runValidSelectorTest('Document', SelectorAdaptor.document(doc),
+ validSelectors, testType, docType);
+ runValidSelectorTest('Detached Element', SelectorAdaptor.element(detached),
+ validSelectors, testType, docType);
+ runValidSelectorTest('Fragment', SelectorAdaptor.fragment(fragment),
+ validSelectors, testType, docType);
+
+ group('out of scope', () {
+ setUp(() {
+ doc.body!.append(outOfScope); // Append before in-document Element tests.
+ // None of these elements should match
+ });
+ tearDown(outOfScope.remove);
+ runValidSelectorTest('In-document Element',
+ SelectorAdaptor.element(element), validSelectors, testType, docType);
+ });
+}
diff --git a/pkgs/html/test/selectors/level1_lib.dart b/pkgs/html/test/selectors/level1_lib.dart
new file mode 100644
index 0000000..d77aac7
--- /dev/null
+++ b/pkgs/html/test/selectors/level1_lib.dart
@@ -0,0 +1,347 @@
+/// Test for the Selectors API ported from
+/// <https://github.com/w3c/web-platform-tests/tree/master/selectors-api>
+///
+/// Note: tried to make minimal changes possible here. Hence some oddities such
+/// as [runTest] arguments having a different order, long lines, etc.
+///
+/// As usual with ports: being faithful to the original style is more important
+/// than other style goals, as it reduces friction to integrating changes
+/// from upstream.
+library;
+
+import 'package:html/dom.dart';
+import 'package:test/test.dart' as unittest;
+
+late Document doc;
+
+// Create and append special elements that cannot be created correctly with HTML
+// markup alone.
+void setupSpecialElements(Element parent) {
+ // Setup null and undefined tests
+ parent.append(doc.createElement('null'));
+ parent.append(doc.createElement('undefined'));
+
+ // Setup namespace tests
+ final anyNS = doc.createElement('div');
+ final noNS = doc.createElement('div');
+ anyNS.id = 'any-namespace';
+ noNS.id = 'no-namespace';
+
+ var div = [
+ doc.createElement('div'),
+ doc.createElementNS('http://www.w3.org/1999/xhtml', 'div'),
+ doc.createElementNS('', 'div'),
+ doc.createElementNS('http://www.example.org/ns', 'div')
+ ];
+
+ div[0].id = 'any-namespace-div1';
+ div[1].id = 'any-namespace-div2';
+ div[2].attributes['id'] =
+ 'any-namespace-div3'; // Non-HTML elements can't use .id property
+ div[3].attributes['id'] = 'any-namespace-div4';
+
+ for (var i = 0; i < div.length; i++) {
+ anyNS.append(div[i]);
+ }
+
+ div = [
+ doc.createElement('div'),
+ doc.createElementNS('http://www.w3.org/1999/xhtml', 'div'),
+ doc.createElementNS('', 'div'),
+ doc.createElementNS('http://www.example.org/ns', 'div')
+ ];
+
+ div[0].id = 'no-namespace-div1';
+ div[1].id = 'no-namespace-div2';
+ div[2].attributes['id'] =
+ 'no-namespace-div3'; // Non-HTML elements can't use .id property
+ div[3].attributes['id'] = 'no-namespace-div4';
+
+ for (var i = 0; i < div.length; i++) {
+ noNS.append(div[i]);
+ }
+
+ parent.append(anyNS);
+ parent.append(noNS);
+}
+
+/// Verify that the NodeList returned by querySelectorAll is static and and that
+/// a new list is created after each call. A static list should not be affected
+/// by subsequent changes to the DOM.
+void verifyStaticList(String type, SelectorAdaptor root) {
+ List<Element> pre;
+ List<Element> post;
+ late int preLength;
+
+ runTest(() {
+ pre = root.querySelectorAll('div');
+ preLength = pre.length;
+
+ final div = doc.createElement('div');
+ root.isDocument ? root.body!.append(div) : root.append(div);
+
+ assertEquals(
+ pre.length, preLength, 'The length of the NodeList should not change.');
+ }, '$type: static NodeList');
+
+ runTest(() {
+ post = root.querySelectorAll('div');
+ assertEquals(post.length, preLength + 1,
+ 'The length of the new NodeList should be 1 more than the previous list.');
+ }, '$type: new NodeList');
+}
+
+/// Verify handling of special values for the selector parameter, including
+/// stringification of null and undefined, and the handling of the empty string.
+void runSpecialSelectorTests(String type, SelectorAdaptor root) {
+ // Dart note: changed these tests because we don't have auto conversion to
+ // String like JavaScript does.
+ runTest(() {
+ // 1
+ assertEquals(root.querySelectorAll('null').length, 1,
+ "This should find one element with the tag name 'NULL'.");
+ }, '$type.querySelectorAll null');
+
+ runTest(() {
+ // 2
+ assertEquals(root.querySelectorAll('undefined').length, 1,
+ "This should find one element with the tag name 'UNDEFINED'.");
+ }, '$type.querySelectorAll undefined');
+
+ // runTest(() {
+ // // 3
+ // assertThrows((e) => e is NoSuchMethodError, () {
+ // root.querySelectorAll();
+ // }, 'This should throw a TypeError.');
+ // }, '$type.querySelectorAll no parameter');
+
+ runTest(() {
+ // 4
+ final elm = root.querySelector('null');
+ assertNotEquals(elm, null, 'This should find an element.');
+ // TODO(jmesserly): change "localName" back to "tagName" once implemented.
+ assertEquals(elm!.localName?.toUpperCase(), 'NULL',
+ "The tag name should be 'NULL'.");
+ }, '$type.querySelector null');
+
+ runTest(() {
+ // 5
+ final elm = root.querySelector('undefined');
+ assertNotEquals(elm, 'undefined', 'This should find an element.');
+ // TODO(jmesserly): change "localName" back to "tagName" once implemented.
+ assertEquals(elm!.localName?.toUpperCase(), 'UNDEFINED',
+ "The tag name should be 'UNDEFINED'.");
+ }, '$type.querySelector undefined');
+
+ // runTest(() {
+ // // 6
+ // assertThrows((e) => e is NoSuchMethodError, () {
+ // root.querySelector();
+ // }, 'This should throw a TypeError.');
+ // }, '$type.querySelector no parameter');
+
+ runTest(() {
+ // 7
+ final result = root.querySelectorAll('*');
+ var i = 0;
+ traverse(root.asNode!, (elem) {
+ if (!identical(elem, root.asNode)) {
+ assertEquals(
+ elem, result[i], 'The result in index $i should be in tree order.');
+ i++;
+ }
+ });
+ }, '$type.querySelectorAll tree order');
+}
+
+/// Tests containing this string fail for an unknown reason
+final _failureName = 'matching custom data-* attribute with';
+
+String? _getSkip(String name) {
+ if (name.contains(_failureName)) {
+ return 'Tests related to `$_failureName` fail for an unknown reason.';
+ }
+ return null;
+}
+
+/*
+ * Execute queries with the specified valid selectors for both querySelector() and querySelectorAll()
+ * Only run these tests when results are expected. Don't run for syntax error tests.
+ */
+void runValidSelectorTest(String type, SelectorAdaptor root,
+ List<Map<String, dynamic>> selectors, int testType, String docType) {
+ var nodeType = '';
+ switch (root.nodeType) {
+ case Node.DOCUMENT_NODE:
+ nodeType = 'document';
+ break;
+ case Node.ELEMENT_NODE:
+ nodeType = root.parentNode != null ? 'element' : 'detached';
+ break;
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ nodeType = 'fragment';
+ break;
+ default:
+ throw StateError('Reached unreachable code path.');
+ }
+
+ for (var i = 0; i < selectors.length; i++) {
+ final s = selectors[i];
+ final n = s['name'] as String;
+ final skip = _getSkip(n);
+ final q = s['selector'] as String;
+ final e = s['expect'] as List?;
+
+ final exclude = s['exclude'];
+
+ if ((exclude is! List ||
+ (!exclude.contains(nodeType) && !exclude.contains(docType))) &&
+ ((s['testType'] as int) & testType != 0)) {
+ //console.log("Running tests " + nodeType + ": " + s["testType"] + "&" + testType + "=" + (s["testType"] & testType) + ": " + JSON.stringify(s))
+ late List<Element> foundall;
+ Element? found;
+
+ runTest(() {
+ foundall = root.querySelectorAll(q);
+ assertNotEquals(foundall, null, 'The method should not return null.');
+ assertEquals(foundall.length, e!.length,
+ 'The method should return the expected number of matches.');
+
+ for (var i = 0; i < e.length; i++) {
+ assertNotEquals(
+ foundall[i], null, 'The item in index $i should not be null.');
+ assertEquals(foundall[i].attributes['id'], e[i],
+ 'The item in index $i should have the expected ID.');
+ assertFalse(foundall[i].attributes.containsKey('data-clone'),
+ 'This should not be a cloned element.');
+ }
+ }, '$type.querySelectorAll: $n:$q', skip: skip);
+
+ runTest(() {
+ found = root.querySelector(q);
+
+ if (e!.isNotEmpty) {
+ assertNotEquals(found, null, 'The method should return a match.');
+ assertEquals(found!.attributes['id'], e[0],
+ 'The method should return the first match.');
+ assertEquals(found, foundall[0],
+ 'The result should match the first item from querySelectorAll.');
+ assertFalse(found!.attributes.containsKey('data-clone'),
+ 'This should not be annotated as a cloned element.');
+ } else {
+ assertEquals(found, null, 'The method should not match anything.');
+ }
+ }, '$type.querySelector: $n : $q', skip: skip);
+ } else {
+ //console.log("Excluding for " + nodeType + ": " + s["testType"] + "&" + testType + "=" + (s["testType"] & testType) + ": " + JSON.stringify(s))
+ }
+ }
+}
+
+/*
+ * Execute queries with the specified invalid selectors for both querySelector() and querySelectorAll()
+ * Only run these tests when errors are expected. Don't run for valid selector tests.
+ */
+void runInvalidSelectorTest(
+ String type, SelectorAdaptor root, List<Map<String, dynamic>> selectors) {
+ for (var i = 0; i < selectors.length; i++) {
+ final s = selectors[i];
+ final n = s['name'] as String;
+ final q = s['selector'] as String;
+
+ // Dart note: FormatException seems a reasonable mapping of SyntaxError
+ runTest(() {
+ assertThrows((Object e) => e is FormatException, () {
+ root.querySelector(q);
+ });
+ }, '$type.querySelector: $n:$q');
+
+ runTest(() {
+ assertThrows((Object e) => e is FormatException, () {
+ root.querySelectorAll(q);
+ });
+ }, '$type.querySelectorAll: $n:$q');
+ }
+}
+
+void traverse(Node elem, void Function(Node) fn) {
+ if (elem.nodeType == Node.ELEMENT_NODE) {
+ fn(elem);
+ }
+
+ // Dart note: changed this since our DOM API doesn't support nextNode yet.
+ for (var node in elem.nodes) {
+ traverse(node, fn);
+ }
+}
+
+void runTest(dynamic Function() body, String name, {String? skip}) =>
+ unittest.test(name, body, skip: skip);
+
+void assertTrue(bool value, String reason) =>
+ unittest.expect(value, unittest.isTrue, reason: reason);
+
+void assertFalse(bool value, String reason) =>
+ unittest.expect(value, unittest.isFalse, reason: reason);
+
+void assertEquals(dynamic x, dynamic y, String reason) =>
+ unittest.expect(x, y, reason: reason);
+
+void assertNotEquals(dynamic x, dynamic y, String reason) =>
+ unittest.expect(x, unittest.isNot(y), reason: reason);
+
+void assertThrows(Object exception, void Function() body, [String? reason]) =>
+ unittest.expect(body, unittest.throwsA(exception), reason: reason);
+
+/// Used for testing.
+///
+/// This class delegates to one of three different kinds of objects. They share
+/// methods with similar signatures but do not share a type hierarchy.
+/// Previously these methods were invoked through `dynamic`.
+class SelectorAdaptor {
+ final Document? document;
+ final Element? element;
+ final DocumentFragment? fragment;
+
+ SelectorAdaptor.document(this.document)
+ : element = null,
+ fragment = null;
+
+ SelectorAdaptor.element(this.element)
+ : document = null,
+ fragment = null;
+
+ SelectorAdaptor.fragment(this.fragment)
+ : document = null,
+ element = null;
+
+ bool get isDocument => document != null;
+
+ Element? get body => document?.body;
+
+ Node? get asNode => document ?? element ?? fragment;
+
+ int get nodeType => asNode!.nodeType;
+
+ Node? get parentNode => asNode!.parentNode;
+
+ void append(Node node) {
+ asNode!.append(node);
+ }
+
+ Element? querySelector(String selector) {
+ if (document != null) return document!.querySelector(selector);
+ if (element != null) return element!.querySelector(selector);
+ if (fragment != null) return fragment!.querySelector(selector);
+
+ throw StateError('unsupported');
+ }
+
+ List<Element> querySelectorAll(String selector) {
+ if (document != null) return document!.querySelectorAll(selector);
+ if (element != null) return element!.querySelectorAll(selector);
+ if (fragment != null) return fragment!.querySelectorAll(selector);
+
+ throw StateError('unsupported');
+ }
+}
diff --git a/pkgs/html/test/selectors/selectors.dart b/pkgs/html/test/selectors/selectors.dart
new file mode 100644
index 0000000..81e69c6
--- /dev/null
+++ b/pkgs/html/test/selectors/selectors.dart
@@ -0,0 +1,1875 @@
+/// Test for the Selectors API ported from
+/// <https://github.com/w3c/web-platform-tests/tree/master/selectors-api>
+library;
+
+// Bit-mapped flags to indicate which tests the selector is suitable for
+final int testQsaBaseline =
+ 0x01; // querySelector() and querySelectorAll() baseline tests
+final int testQsaAdditional =
+ 0x02; // querySelector() and querySelectorAll() additional tests
+final int testFindBaseline =
+ 0x04; // find() and findAll() baseline tests, may be unsuitable for querySelector[All]
+final int testFindAdditional =
+ 0x08; // find() and findAll() additional tests, may be unsuitable for querySelector[All]
+final int testMatchBaseline = 0x10; // matches() baseline tests
+int testMatchAdditional = 0x20; // matches() additional tests
+
+/*
+ * All of these invalid selectors should result in a SyntaxError being thrown by the APIs.
+ *
+ * name: A descriptive name of the selector being tested
+ * selector: The selector to test
+ */
+final invalidSelectors = [
+ {'name': 'Empty String', 'selector': ''},
+ {'name': 'Invalid character', 'selector': '['},
+ {'name': 'Invalid character', 'selector': ']'},
+ {'name': 'Invalid character', 'selector': '('},
+ {'name': 'Invalid character', 'selector': ')'},
+ {'name': 'Invalid character', 'selector': '{'},
+ {'name': 'Invalid character', 'selector': '}'},
+ {'name': 'Invalid character', 'selector': '<'},
+ {'name': 'Invalid character', 'selector': '>'},
+ {'name': 'Invalid ID', 'selector': '#'},
+ {'name': 'Invalid group of selectors', 'selector': 'div,'},
+ {'name': 'Invalid class', 'selector': '.'},
+ {'name': 'Invalid class', 'selector': '.5cm'},
+ {'name': 'Invalid class', 'selector': '..test'},
+ {'name': 'Invalid class', 'selector': '.foo..quux'},
+ {'name': 'Invalid class', 'selector': '.bar.'},
+ {'name': 'Invalid combinator', 'selector': 'div & address, p'},
+ {'name': 'Invalid combinator', 'selector': 'div >> address, p'},
+ {'name': 'Invalid combinator', 'selector': 'div ++ address, p'},
+ {'name': 'Invalid combinator', 'selector': 'div ~~ address, p'},
+ {'name': 'Invalid [att=value] selector', 'selector': '[*=test]'},
+ {'name': 'Invalid [att=value] selector', 'selector': '[*|*=test]'},
+ {
+ 'name': 'Invalid [att=value] selector',
+ 'selector': '[class= space unquoted ]'
+ },
+ {'name': 'Unknown pseudo-class', 'selector': 'div:example'},
+ {'name': 'Unknown pseudo-class', 'selector': ':example'},
+ {'name': 'Unknown pseudo-element', 'selector': 'div::example'},
+ {'name': 'Unknown pseudo-element', 'selector': '::example'},
+ {'name': 'Invalid pseudo-element', 'selector': ':::before'},
+ {'name': 'Undeclared namespace', 'selector': 'ns|div'},
+ {'name': 'Undeclared namespace', 'selector': ':not(ns|div)'},
+ {'name': 'Invalid namespace', 'selector': '^|div'},
+ {'name': 'Invalid namespace', 'selector': '\$|div'}
+];
+
+/*
+ * All of these should be valid selectors, expected to match zero or more elements in the document.
+ * None should throw any errors.
+ *
+ * name: A descriptive name of the selector being tested
+ * selector: The selector to test
+ * 'expect': A list of IDs of the elements expected to be matched. List must be given in tree order.
+ * 'exclude': An array of contexts to exclude from testing. The valid values are:
+ * ["document", "element", "fragment", "detached", "html", "xhtml"]
+ * The "html" and "xhtml" values represent the type of document being queried. These are useful
+ * for tests that are affected by differences between HTML and XML, such as case sensitivity.
+ * 'level': An integer indicating the CSS or Selectors level in which the selector being tested was introduced.
+ * 'testType': A bit-mapped flag indicating the type of test.
+ *
+ * Note: Interactive pseudo-classes (:active :hover and :focus) have not been tested in this test suite.
+ */
+final List<Map<String, dynamic>> validSelectors = [
+ // Type Selector
+ {
+ 'name': 'Type selector, matching html element',
+ 'selector': 'html',
+ 'expect': ['html'],
+ 'exclude': ['element', 'fragment', 'detached'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Type selector, matching html element',
+ 'selector': 'html',
+ 'expect': <String>[] /*no matches*/,
+ 'exclude': ['document'],
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'Type selector, matching body element',
+ 'selector': 'body',
+ 'expect': ['body'],
+ 'exclude': ['element', 'fragment', 'detached'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Type selector, matching body element',
+ 'selector': 'body',
+ 'expect': <String>[] /*no matches*/,
+ 'exclude': ['document'],
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+
+ // Universal Selector
+ // Testing "*" for entire an entire context node is handled separately.
+ {
+ 'name':
+ 'Universal selector, matching all children of element with specified ID',
+ 'selector': '#universal>*',
+ 'expect': [
+ 'universal-p1',
+ 'universal-hr1',
+ 'universal-pre1',
+ 'universal-p2',
+ 'universal-address1'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Universal selector, matching all grandchildren of element with specified ID',
+ 'selector': '#universal>*>*',
+ 'expect': [
+ 'universal-code1',
+ 'universal-span1',
+ 'universal-a1',
+ 'universal-code2'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Universal selector, matching all children of empty element with specified ID',
+ 'selector': '#empty>*',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Universal selector, matching all descendants of element with specified ID',
+ 'selector': '#universal *',
+ 'expect': [
+ 'universal-p1',
+ 'universal-code1',
+ 'universal-hr1',
+ 'universal-pre1',
+ 'universal-span1',
+ 'universal-p2',
+ 'universal-a1',
+ 'universal-address1',
+ 'universal-code2',
+ 'universal-a2'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // Attribute Selectors
+ // - presence [att]
+ {
+ 'name': 'Attribute presence selector, matching align attribute with value',
+ 'selector': '.attr-presence-div1[align]',
+ 'expect': ['attr-presence-div1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute presence selector, matching align attribute with empty value',
+ 'selector': '.attr-presence-div2[align]',
+ 'expect': ['attr-presence-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute presence selector, matching title attribute, case insensitivity',
+ 'selector': '#attr-presence [TiTlE]',
+ 'expect': ['attr-presence-a1', 'attr-presence-span1'],
+ 'exclude': ['xhtml'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute presence selector, not matching title attribute, case sensitivity',
+ 'selector': '#attr-presence [TiTlE]',
+ 'expect': <String>[],
+ 'exclude': ['html'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Attribute presence selector, matching custom data-* attribute',
+ 'selector': '[data-attr-presence]',
+ 'expect': ['attr-presence-pre1', 'attr-presence-blockquote1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute presence selector, not matching attribute with similar name',
+ 'selector': '.attr-presence-div3[align], .attr-presence-div4[align]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Attribute presence selector, matching attribute with non-ASCII characters',
+ 'selector': 'ul[data-中文]',
+ 'expect': ['attr-presence-ul1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute presence selector, not matching default option without selected attribute',
+ 'selector': '#attr-presence-select1 option[selected]',
+ 'expect': <String>[] /* no matches */,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Attribute presence selector, matching option with selected attribute',
+ 'selector': '#attr-presence-select2 option[selected]',
+ 'expect': ['attr-presence-select2-option4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute presence selector, matching multiple options with selected attributes',
+ 'selector': '#attr-presence-select3 option[selected]',
+ 'expect': [
+ 'attr-presence-select3-option2',
+ 'attr-presence-select3-option3'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // - value [att=val]
+ {
+ 'name': 'Attribute value selector, matching align attribute with value',
+ 'selector': '#attr-value [align="center"]',
+ 'expect': ['attr-value-div1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector, matching align attribute with empty value',
+ 'selector': '#attr-value [align=""]',
+ 'expect': ['attr-value-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector, not matching align attribute with partial value',
+ 'selector': '#attr-value [align="c"]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector, not matching align attribute with incorrect value',
+ 'selector': '#attr-value [align="centera"]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector, matching custom data-* attribute with unicode escaped value',
+ 'selector': '[data-attr-value="\\e9"]',
+ 'expect': ['attr-value-div3'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector, matching custom data-* attribute with escaped character',
+ 'selector': '[data-attr-value_foo="\\e9"]',
+ 'expect': ['attr-value-div4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector with single-quoted value, matching multiple inputs with type attributes',
+ 'selector':
+ "#attr-value input[type='hidden'],#attr-value input[type='radio']",
+ 'expect': [
+ 'attr-value-input3',
+ 'attr-value-input4',
+ 'attr-value-input6',
+ 'attr-value-input8',
+ 'attr-value-input9'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector with double-quoted value, matching multiple inputs with type attributes',
+ 'selector':
+ "#attr-value input[type=\"hidden\"],#attr-value input[type='radio']",
+ 'expect': [
+ 'attr-value-input3',
+ 'attr-value-input4',
+ 'attr-value-input6',
+ 'attr-value-input8',
+ 'attr-value-input9'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector with unquoted value, matching multiple inputs with type attributes',
+ 'selector': '#attr-value input[type=hidden],#attr-value input[type=radio]',
+ 'expect': [
+ 'attr-value-input3',
+ 'attr-value-input4',
+ 'attr-value-input6',
+ 'attr-value-input8',
+ 'attr-value-input9'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute value selector, matching attribute with value using non-ASCII characters',
+ 'selector': '[data-attr-value=中文]',
+ 'expect': ['attr-value-div5'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // - whitespace-separated list [att~=val]
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector, matching class attribute with value',
+ 'selector': '#attr-whitespace [class~="div1"]',
+ 'expect': ['attr-whitespace-div1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector, not matching class attribute with empty value',
+ 'selector': '#attr-whitespace [class~=""]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector, not matching class attribute with partial value',
+ 'selector': '[data-attr-whitespace~="div"]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value',
+ 'selector': '[data-attr-whitespace~="\\0000e9"]',
+ 'expect': ['attr-whitespace-div4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character',
+ 'selector': '[data-attr-whitespace_foo~="\\e9"]',
+ 'expect': ['attr-whitespace-div5'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes',
+ 'selector':
+ "#attr-whitespace a[rel~='bookmark'], #attr-whitespace a[rel~='nofollow']",
+ 'expect': [
+ 'attr-whitespace-a1',
+ 'attr-whitespace-a2',
+ 'attr-whitespace-a3',
+ 'attr-whitespace-a5',
+ 'attr-whitespace-a7'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes',
+ 'selector':
+ "#attr-whitespace a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']",
+ 'expect': [
+ 'attr-whitespace-a1',
+ 'attr-whitespace-a2',
+ 'attr-whitespace-a3',
+ 'attr-whitespace-a5',
+ 'attr-whitespace-a7'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes',
+ 'selector':
+ '#attr-whitespace a[rel~=bookmark], #attr-whitespace a[rel~=nofollow]',
+ 'expect': [
+ 'attr-whitespace-a1',
+ 'attr-whitespace-a2',
+ 'attr-whitespace-a3',
+ 'attr-whitespace-a5',
+ 'attr-whitespace-a7'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector with double-quoted value, not matching value with space',
+ 'selector': '#attr-whitespace a[rel~="book mark"]',
+ 'expect': <String>[] /* no matches */,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters',
+ 'selector': '#attr-whitespace [title~=中文]',
+ 'expect': ['attr-whitespace-p1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // - hyphen-separated list [att|=val]
+ {
+ 'name':
+ 'Attribute hyphen-separated list selector, not matching unspecified lang attribute',
+ 'selector': '#attr-hyphen-div1[lang|="en"]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Attribute hyphen-separated list selector, matching lang attribute with exact value',
+ 'selector': '#attr-hyphen-div2[lang|="fr"]',
+ 'expect': ['attr-hyphen-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute hyphen-separated list selector, matching lang attribute with partial value',
+ 'selector': '#attr-hyphen-div3[lang|="en"]',
+ 'expect': ['attr-hyphen-div3'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute hyphen-separated list selector, not matching incorrect value',
+ 'selector': '#attr-hyphen-div4[lang|="es-AR"]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+
+ // - substring begins-with [att^=val] (Level 3)
+ {
+ 'name':
+ 'Attribute begins with selector, matching href attributes beginning with specified substring',
+ 'selector': '#attr-begins a[href^="http://www"]',
+ 'expect': ['attr-begins-a1', 'attr-begins-a3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute begins with selector, matching lang attributes beginning with specified substring, ',
+ 'selector': '#attr-begins [lang^="en-"]',
+ 'expect': ['attr-begins-div2', 'attr-begins-div4'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute begins with selector, not matching class attribute not beginning with specified substring',
+ 'selector': '#attr-begins [class^=apple]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+ {
+ 'name':
+ 'Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring',
+ 'selector': "#attr-begins [class^=' apple']",
+ 'expect': ['attr-begins-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring',
+ 'selector': '#attr-begins [class^=" apple"]',
+ 'expect': ['attr-begins-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring',
+ 'selector': '#attr-begins [class^= apple]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // - substring ends-with [att\$=val] (Level 3)
+ {
+ 'name':
+ 'Attribute ends with selector, matching href attributes ending with specified substring',
+ 'selector': '#attr-ends a[href\$=".org"]',
+ 'expect': ['attr-ends-a1', 'attr-ends-a3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute ends with selector, matching lang attributes ending with specified substring, ',
+ 'selector': '#attr-ends [lang\$="-CH"]',
+ 'expect': ['attr-ends-div2', 'attr-ends-div4'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute ends with selector, not matching class attribute not ending with specified substring',
+ 'selector': '#attr-ends [class\$=apple]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+ {
+ 'name':
+ 'Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring',
+ 'selector': "#attr-ends [class\$='apple ']",
+ 'expect': ['attr-ends-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring',
+ 'selector': '#attr-ends [class\$="apple "]',
+ 'expect': ['attr-ends-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring',
+ 'selector': '#attr-ends [class\$=apple ]',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // - substring contains [att*=val] (Level 3)
+ {
+ 'name':
+ 'Attribute contains selector, matching href attributes beginning with specified substring',
+ 'selector': '#attr-contains a[href*="http://www"]',
+ 'expect': ['attr-contains-a1', 'attr-contains-a3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector, matching href attributes ending with specified substring',
+ 'selector': '#attr-contains a[href*=".org"]',
+ 'expect': ['attr-contains-a1', 'attr-contains-a2'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector, matching href attributes containing specified substring',
+ 'selector': '#attr-contains a[href*=".example."]',
+ 'expect': ['attr-contains-a1', 'attr-contains-a3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector, matching lang attributes beginning with specified substring, ',
+ 'selector': '#attr-contains [lang*="en-"]',
+ 'expect': ['attr-contains-div2', 'attr-contains-div6'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector, matching lang attributes ending with specified substring, ',
+ 'selector': '#attr-contains [lang*="-CH"]',
+ 'expect': ['attr-contains-div3', 'attr-contains-div5'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring',
+ 'selector': "#attr-contains [class*=' apple']",
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with single-quoted value, matching class attribute ending with specified substring',
+ 'selector': "#attr-contains [class*='orange ']",
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with single-quoted value, matching class attribute containing specified substring',
+ 'selector': "#attr-contains [class*='ple banana ora']",
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring',
+ 'selector': '#attr-contains [class*=" apple"]',
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with double-quoted value, matching class attribute ending with specified substring',
+ 'selector': '#attr-contains [class*="orange "]',
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with double-quoted value, matching class attribute containing specified substring',
+ 'selector': '#attr-contains [class*="ple banana ora"]',
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with unquoted value, matching class attribute beginning with specified substring',
+ 'selector': '#attr-contains [class*= apple]',
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with unquoted value, matching class attribute ending with specified substring',
+ 'selector': '#attr-contains [class*=orange ]',
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Attribute contains selector with unquoted value, matching class attribute containing specified substring',
+ 'selector': '#attr-contains [class*= banana ]',
+ 'expect': ['attr-contains-p1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // Pseudo-classes
+ // - :root (Level 3)
+ {
+ 'name': ':root pseudo-class selector, matching document root element',
+ 'selector': ':root',
+ 'expect': ['html'],
+ 'exclude': ['element', 'fragment', 'detached'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name': ':root pseudo-class selector, not matching document root element',
+ 'selector': ':root',
+ 'expect': <String>[] /*no matches*/,
+ 'exclude': ['document'],
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // - :nth-child(n) (Level 3)
+ {
+ 'name': ':nth-child selector, matching the third child element',
+ 'selector': '#pseudo-nth-table1 :nth-child(3)',
+ 'expect': [
+ 'pseudo-nth-td3',
+ 'pseudo-nth-td9',
+ 'pseudo-nth-tr3',
+ 'pseudo-nth-td15'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name': ':nth-child selector, matching every third child element',
+ 'selector': '#pseudo-nth li:nth-child(3n)',
+ 'expect': [
+ 'pseudo-nth-li3',
+ 'pseudo-nth-li6',
+ 'pseudo-nth-li9',
+ 'pseudo-nth-li12'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-child selector, matching every second child element, starting from the fourth',
+ 'selector': '#pseudo-nth li:nth-child(2n+4)',
+ 'expect': [
+ 'pseudo-nth-li4',
+ 'pseudo-nth-li6',
+ 'pseudo-nth-li8',
+ 'pseudo-nth-li10',
+ 'pseudo-nth-li12'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-child selector, matching every fourth child element, starting from the third',
+ 'selector': '#pseudo-nth-p1 :nth-child(4n-1)',
+ 'expect': ['pseudo-nth-em2', 'pseudo-nth-span3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :nth-last-child (Level 3)
+ {
+ 'name': ':nth-last-child selector, matching the third last child element',
+ 'selector': '#pseudo-nth-table1 :nth-last-child(3)',
+ 'expect': [
+ 'pseudo-nth-tr1',
+ 'pseudo-nth-td4',
+ 'pseudo-nth-td10',
+ 'pseudo-nth-td16'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-last-child selector, matching every third child element from the end',
+ 'selector': '#pseudo-nth li:nth-last-child(3n)',
+ 'expect': [
+ 'pseudo-nth-li1',
+ 'pseudo-nth-li4',
+ 'pseudo-nth-li7',
+ 'pseudo-nth-li10'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-last-child selector, matching every second child element from the end, starting from the fourth last',
+ 'selector': '#pseudo-nth li:nth-last-child(2n+4)',
+ 'expect': [
+ 'pseudo-nth-li1',
+ 'pseudo-nth-li3',
+ 'pseudo-nth-li5',
+ 'pseudo-nth-li7',
+ 'pseudo-nth-li9'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-last-child selector, matching every fourth element from the end, starting from the third last',
+ 'selector': '#pseudo-nth-p1 :nth-last-child(4n-1)',
+ 'expect': ['pseudo-nth-span2', 'pseudo-nth-span4'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :nth-of-type(n) (Level 3)
+ {
+ 'name': ':nth-of-type selector, matching the third em element',
+ 'selector': '#pseudo-nth-p1 em:nth-of-type(3)',
+ 'expect': ['pseudo-nth-em3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-of-type selector, matching every second element of their type',
+ 'selector': '#pseudo-nth-p1 :nth-of-type(2n)',
+ 'expect': [
+ 'pseudo-nth-em2',
+ 'pseudo-nth-span2',
+ 'pseudo-nth-span4',
+ 'pseudo-nth-strong2',
+ 'pseudo-nth-em4'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-of-type selector, matching every second elemetn of their type, starting from the first',
+ 'selector': '#pseudo-nth-p1 span:nth-of-type(2n-1)',
+ 'expect': ['pseudo-nth-span1', 'pseudo-nth-span3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :nth-last-of-type(n) (Level 3)
+ {
+ 'name': ':nth-last-of-type selector, matching the thrid last em element',
+ 'selector': '#pseudo-nth-p1 em:nth-last-of-type(3)',
+ 'expect': ['pseudo-nth-em2'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-last-of-type selector, matching every second last element of their type',
+ 'selector': '#pseudo-nth-p1 :nth-last-of-type(2n)',
+ 'expect': [
+ 'pseudo-nth-span1',
+ 'pseudo-nth-em1',
+ 'pseudo-nth-strong1',
+ 'pseudo-nth-em3',
+ 'pseudo-nth-span3'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':nth-last-of-type selector, matching every second last element of their type, starting from the last',
+ 'selector': '#pseudo-nth-p1 span:nth-last-of-type(2n-1)',
+ 'expect': ['pseudo-nth-span2', 'pseudo-nth-span4'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :first-of-type (Level 3)
+ {
+ 'name': ':first-of-type selector, matching the first em element',
+ 'selector': '#pseudo-nth-p1 em:first-of-type',
+ 'expect': ['pseudo-nth-em1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':first-of-type selector, matching the first of every type of element',
+ 'selector': '#pseudo-nth-p1 :first-of-type',
+ 'expect': ['pseudo-nth-span1', 'pseudo-nth-em1', 'pseudo-nth-strong1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':first-of-type selector, matching the first td element in each table row',
+ 'selector': '#pseudo-nth-table1 tr :first-of-type',
+ 'expect': ['pseudo-nth-td1', 'pseudo-nth-td7', 'pseudo-nth-td13'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :last-of-type (Level 3)
+ {
+ 'name': ':last-of-type selector, matching the last em elemnet',
+ 'selector': '#pseudo-nth-p1 em:last-of-type',
+ 'expect': ['pseudo-nth-em4'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':last-of-type selector, matching the last of every type of element',
+ 'selector': '#pseudo-nth-p1 :last-of-type',
+ 'expect': ['pseudo-nth-span4', 'pseudo-nth-strong2', 'pseudo-nth-em4'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':last-of-type selector, matching the last td element in each table row',
+ 'selector': '#pseudo-nth-table1 tr :last-of-type',
+ 'expect': ['pseudo-nth-td6', 'pseudo-nth-td12', 'pseudo-nth-td18'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :first-child
+ {
+ 'name':
+ ':first-child pseudo-class selector, matching first child div element',
+ 'selector': '#pseudo-first-child div:first-child',
+ 'expect': ['pseudo-first-child-div1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ ":first-child pseudo-class selector, doesn't match non-first-child elements",
+ 'selector':
+ '.pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ ':first-child pseudo-class selector, matching first-child of multiple elements',
+ 'selector': '#pseudo-first-child span:first-child',
+ 'expect': [
+ 'pseudo-first-child-span1',
+ 'pseudo-first-child-span3',
+ 'pseudo-first-child-span5'
+ ],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // - :last-child (Level 3)
+ {
+ 'name':
+ ':last-child pseudo-class selector, matching last child div element',
+ 'selector': '#pseudo-last-child div:last-child',
+ 'expect': ['pseudo-last-child-div3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ":last-child pseudo-class selector, doesn't match non-last-child elements",
+ 'selector':
+ '.pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+ {
+ 'name':
+ ':last-child pseudo-class selector, matching first-child of multiple elements',
+ 'selector': '#pseudo-last-child span:last-child',
+ 'expect': [
+ 'pseudo-last-child-span2',
+ 'pseudo-last-child-span4',
+ 'pseudo-last-child-span6'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :only-child (Level 3)
+ {
+ 'name':
+ ':pseudo-only-child pseudo-class selector, matching all only-child elements',
+ 'selector': '#pseudo-only :only-child',
+ 'expect': ['pseudo-only-span1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':pseudo-only-child pseudo-class selector, matching only-child em elements',
+ 'selector': '#pseudo-only em:only-child',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // - :only-of-type (Level 3)
+ {
+ 'name':
+ ':pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type',
+ 'selector': '#pseudo-only :only-of-type',
+ 'expect': ['pseudo-only-span1', 'pseudo-only-em1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ ':pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type',
+ 'selector': '#pseudo-only em:only-of-type',
+ 'expect': ['pseudo-only-em1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :empty (Level 3)
+ {
+ 'name': ':empty pseudo-class selector, matching empty p elements',
+ 'selector': '#pseudo-empty p:empty',
+ 'expect': ['pseudo-empty-p1', 'pseudo-empty-p2'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name': ':empty pseudo-class selector, matching all empty elements',
+ 'selector': '#pseudo-empty :empty',
+ 'expect': ['pseudo-empty-p1', 'pseudo-empty-p2', 'pseudo-empty-span1'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :link and :visited
+ // Implementations may treat all visited links as unvisited, so these cannot be tested separately.
+ // The only guarantee is that ":link,:visited" matches the set of all visited and unvisited links and that they are individually mutually exclusive sets.
+ {
+ 'name':
+ ':link and :visited pseudo-class selectors, matching a and area elements with href attributes',
+ 'selector': '#pseudo-link :link, #pseudo-link :visited',
+ 'expect': ['pseudo-link-a1', 'pseudo-link-a2', 'pseudo-link-area1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ ':link and :visited pseudo-class selectors, matching link elements with href attributes',
+ 'selector': '#head :link, #head :visited',
+ 'expect': ['pseudo-link-link1', 'pseudo-link-link2'],
+ 'exclude': ['element', 'fragment', 'detached'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ ':link and :visited pseudo-class selectors, not matching link elements with href attributes',
+ 'selector': '#head :link, #head :visited',
+ 'expect': <String>[] /*no matches*/,
+ 'exclude': ['document'],
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ ':link and :visited pseudo-class selectors, chained, mutually exclusive pseudo-classes match nothing',
+ 'selector': ':link:visited',
+ 'expect': <String>[] /*no matches*/,
+ 'exclude': ['document'],
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+
+ // - :target (Level 3)
+ {
+ 'name':
+ ':target pseudo-class selector, matching the element referenced by the URL fragment identifier',
+ 'selector': ':target',
+ 'expect': <String>[] /*no matches*/,
+ 'exclude': ['document', 'element'],
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+ {
+ 'name':
+ ':target pseudo-class selector, matching the element referenced by the URL fragment identifier',
+ 'selector': ':target',
+ 'expect': ['target'],
+ 'exclude': ['fragment', 'detached'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :lang()
+ {
+ 'name': ':lang pseudo-class selector, matching inherited language',
+ 'selector': '#pseudo-lang-div1:lang(en)',
+ 'expect': ['pseudo-lang-div1'],
+ 'exclude': ['detached', 'fragment'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ ':lang pseudo-class selector, not matching element with no inherited language',
+ 'selector': '#pseudo-lang-div1:lang(en)',
+ 'expect': <String>[] /*no matches*/,
+ 'exclude': ['document', 'element'],
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ ':lang pseudo-class selector, matching specified language with exact value',
+ 'selector': '#pseudo-lang-div2:lang(fr)',
+ 'expect': ['pseudo-lang-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ ':lang pseudo-class selector, matching specified language with partial value',
+ 'selector': '#pseudo-lang-div3:lang(en)',
+ 'expect': ['pseudo-lang-div3'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': ':lang pseudo-class selector, not matching incorrect language',
+ 'selector': '#pseudo-lang-div4:lang(es-AR)',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+
+ // - :enabled (Level 3)
+ {
+ 'name':
+ ':enabled pseudo-class selector, matching all enabled form controls',
+ 'selector': '#pseudo-ui :enabled',
+ 'expect': [
+ 'pseudo-ui-input1',
+ 'pseudo-ui-input2',
+ 'pseudo-ui-input3',
+ 'pseudo-ui-input4',
+ 'pseudo-ui-input5',
+ 'pseudo-ui-input6',
+ 'pseudo-ui-input7',
+ 'pseudo-ui-input8',
+ 'pseudo-ui-input9',
+ 'pseudo-ui-textarea1',
+ 'pseudo-ui-button1'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :disabled (Level 3)
+ {
+ 'name':
+ ':enabled pseudo-class selector, matching all disabled form controls',
+ 'selector': '#pseudo-ui :disabled',
+ 'expect': [
+ 'pseudo-ui-input10',
+ 'pseudo-ui-input11',
+ 'pseudo-ui-input12',
+ 'pseudo-ui-input13',
+ 'pseudo-ui-input14',
+ 'pseudo-ui-input15',
+ 'pseudo-ui-input16',
+ 'pseudo-ui-input17',
+ 'pseudo-ui-input18',
+ 'pseudo-ui-textarea2',
+ 'pseudo-ui-button2'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :checked (Level 3)
+ {
+ 'name':
+ ':checked pseudo-class selector, matching checked radio buttons and checkboxes',
+ 'selector': '#pseudo-ui :checked',
+ 'expect': [
+ 'pseudo-ui-input4',
+ 'pseudo-ui-input6',
+ 'pseudo-ui-input13',
+ 'pseudo-ui-input15'
+ ],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // - :not(s) (Level 3)
+ {
+ 'name': ':not pseudo-class selector, matching ',
+ 'selector': '#not>:not(div)',
+ 'expect': ['not-p1', 'not-p2', 'not-p3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name': ':not pseudo-class selector, matching ',
+ 'selector': '#not * :not(:first-child)',
+ 'expect': ['not-em1', 'not-em2', 'not-em3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name': ':not pseudo-class selector, matching nothing',
+ 'selector': ':not(*)',
+ 'expect': <String>[] /* no matches */,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+ {
+ 'name': ':not pseudo-class selector, matching nothing',
+ 'selector': ':not(*|*)',
+ 'expect': <String>[] /* no matches */,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // Pseudo-elements
+ // - ::first-line
+ {
+ 'name':
+ ':first-line pseudo-element (one-colon syntax) selector, not matching any elements',
+ 'selector': '#pseudo-element:first-line',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ '::first-line pseudo-element (two-colon syntax) selector, not matching any elements',
+ 'selector': '#pseudo-element::first-line',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // - ::first-letter
+ {
+ 'name':
+ ':first-letter pseudo-element (one-colon syntax) selector, not matching any elements',
+ 'selector': '#pseudo-element:first-letter',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ '::first-letter pseudo-element (two-colon syntax) selector, not matching any elements',
+ 'selector': '#pseudo-element::first-letter',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // - ::before
+ {
+ 'name':
+ ':before pseudo-element (one-colon syntax) selector, not matching any elements',
+ 'selector': '#pseudo-element:before',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ '::before pseudo-element (two-colon syntax) selector, not matching any elements',
+ 'selector': '#pseudo-element::before',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // - ::after
+ {
+ 'name':
+ ':after pseudo-element (one-colon syntax) selector, not matching any elements',
+ 'selector': '#pseudo-element:after',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ '::after pseudo-element (two-colon syntax) selector, not matching any elements',
+ 'selector': '#pseudo-element::after',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+
+ // Class Selectors
+ {
+ 'name': 'Class selector, matching element with specified class',
+ 'selector': '.class-p',
+ 'expect': ['class-p1', 'class-p2', 'class-p3'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Class selector, chained, matching only elements with all specified classes',
+ 'selector': '#class .apple.orange.banana',
+ 'expect': [
+ 'class-div1',
+ 'class-div2',
+ 'class-p4',
+ 'class-div3',
+ 'class-p6',
+ 'class-div4'
+ ],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Class Selector, chained, with type selector',
+ 'selector': 'div.apple.banana.orange',
+ 'expect': ['class-div1', 'class-div2', 'class-div3', 'class-div4'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ // Caution: If copying and pasting the folowing non-ASCII classes, ensure unicode normalisation is not performed in the process.
+ {
+ 'name':
+ 'Class selector, matching element with class value using non-ASCII characters',
+ 'selector': '.台北Táiběi',
+ 'expect': ['class-span1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Class selector, matching multiple elements with class value using non-ASCII characters',
+ 'selector': '.台北',
+ 'expect': ['class-span1', 'class-span2'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Class selector, chained, matching element with multiple class values using non-ASCII characters',
+ 'selector': '.台北Táiběi.台北',
+ 'expect': ['class-span1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Class selector, matching element with class with escaped character',
+ 'selector': '.foo\\:bar',
+ 'expect': ['class-span3'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Class selector, matching element with class with escaped character',
+ 'selector': '.test\\.foo\\[5\\]bar',
+ 'expect': ['class-span4'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // ID Selectors
+ {
+ 'name': 'ID selector, matching element with specified id',
+ 'selector': '#id #id-div1',
+ 'expect': ['id-div1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'ID selector, chained, matching element with specified id',
+ 'selector': '#id-div1, #id-div1',
+ 'expect': ['id-div1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'ID selector, chained, matching element with specified id',
+ 'selector': '#id-div1, #id-div2',
+ 'expect': ['id-div1', 'id-div2'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'ID Selector, chained, with type selector',
+ 'selector': 'div#id-div1, div#id-div2',
+ 'expect': ['id-div1', 'id-div2'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'ID selector, not matching non-existent descendant',
+ 'selector': '#id #none',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'ID selector, not matching non-existent ancestor',
+ 'selector': '#none #id-div1',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'ID selector, matching multiple elements with duplicate id',
+ 'selector': '#id-li-duplicate',
+ 'expect': [
+ 'id-li-duplicate',
+ 'id-li-duplicate',
+ 'id-li-duplicate',
+ 'id-li-duplicate'
+ ],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // Caution: If copying and pasting the folowing non-ASCII IDs, ensure unicode normalisation is not performed in the process.
+ {
+ 'name': 'ID selector, matching id value using non-ASCII characters',
+ 'selector': '#台北Táiběi',
+ 'expect': ['台北Táiběi'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'ID selector, matching id value using non-ASCII characters',
+ 'selector': '#台北',
+ 'expect': ['台北'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'ID selector, matching id values using non-ASCII characters',
+ 'selector': '#台北Táiběi, #台北',
+ 'expect': ['台北Táiběi', '台北'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // XXX runMatchesTest() in level2-lib.js can't handle this because obtaining the expected nodes requires escaping characters when generating the selector from 'expect' values
+ {
+ 'name': 'ID selector, matching element with id with escaped character',
+ 'selector': '#\\#foo\\:bar',
+ 'expect': ['#foo:bar'],
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'ID selector, matching element with id with escaped character',
+ 'selector': '#test\\.foo\\[5\\]bar',
+ 'expect': ['test.foo[5]bar'],
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+
+ // Namespaces
+ // XXX runMatchesTest() in level2-lib.js can't handle these because non-HTML elements don't have a recognised id
+ {
+ 'name': 'Namespace selector, matching element with any namespace',
+ 'selector': '#any-namespace *|div',
+ 'expect': [
+ 'any-namespace-div1',
+ 'any-namespace-div2',
+ 'any-namespace-div3',
+ 'any-namespace-div4'
+ ],
+ 'level': 3,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'Namespace selector, matching div elements in no namespace only',
+ 'selector': '#no-namespace |div',
+ 'expect': ['no-namespace-div3'],
+ 'level': 3,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'Namespace selector, matching any elements in no namespace only',
+ 'selector': '#no-namespace |*',
+ 'expect': ['no-namespace-div3'],
+ 'level': 3,
+ 'testType': testQsaBaseline
+ },
+
+ // Combinators
+ // - Descendant combinator ' '
+ {
+ 'name':
+ 'Descendant combinator, matching element that is a descendant of an element with id',
+ 'selector': '#descendant div',
+ 'expect': [
+ 'descendant-div1',
+ 'descendant-div2',
+ 'descendant-div3',
+ 'descendant-div4'
+ ],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Descendant combinator, matching element with id that is a descendant of an element',
+ 'selector': 'body #descendant-div1',
+ 'expect': ['descendant-div1'],
+ 'exclude': ['detached', 'fragment'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Descendant combinator, matching element with id that is a descendant of an element',
+ 'selector': 'div #descendant-div1',
+ 'expect': ['descendant-div1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Descendant combinator, matching element with id that is a descendant of an element with id',
+ 'selector': '#descendant #descendant-div2',
+ 'expect': ['descendant-div2'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Descendant combinator, matching element with class that is a descendant of an element with id',
+ 'selector': '#descendant .descendant-div2',
+ 'expect': ['descendant-div2'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Descendant combinator, matching element with class that is a descendant of an element with class',
+ 'selector': '.descendant-div1 .descendant-div3',
+ 'expect': ['descendant-div3'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Descendant combinator, not matching element with id that is not a descendant of an element with id',
+ 'selector': '#descendant-div1 #descendant-div4',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 1,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'Descendant combinator, whitespace characters',
+ 'selector': '#descendant\t\r\n#descendant-div2',
+ 'expect': ['descendant-div2'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // - Child combinator '>'
+ {
+ 'name':
+ 'Child combinator, matching element that is a child of an element with id',
+ 'selector': '#child>div',
+ 'expect': ['child-div1', 'child-div4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Child combinator, matching element with id that is a child of an element',
+ 'selector': 'div>#child-div1',
+ 'expect': ['child-div1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Child combinator, matching element with id that is a child of an element with id',
+ 'selector': '#child>#child-div1',
+ 'expect': ['child-div1'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Child combinator, matching element with id that is a child of an element with class',
+ 'selector': '#child-div1>.child-div2',
+ 'expect': ['child-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Child combinator, matching element with class that is a child of an element with class',
+ 'selector': '.child-div1>.child-div2',
+ 'expect': ['child-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Child combinator, not matching element with id that is not a child of an element with id',
+ 'selector': '#child>#child-div3',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Child combinator, not matching element with id that is not a child of an element with class',
+ 'selector': '#child-div1>.child-div3',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name':
+ 'Child combinator, not matching element with class that is not a child of an element with class',
+ 'selector': '.child-div1>.child-div3',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'Child combinator, surrounded by whitespace',
+ 'selector': '#child-div1\t\r\n>\t\r\n#child-div2',
+ 'expect': ['child-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Child combinator, whitespace after',
+ 'selector': '#child-div1>\t\r\n#child-div2',
+ 'expect': ['child-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Child combinator, whitespace before',
+ 'selector': '#child-div1\t\r\n>#child-div2',
+ 'expect': ['child-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Child combinator, no whitespace',
+ 'selector': '#child-div1>#child-div2',
+ 'expect': ['child-div2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // - Adjacent sibling combinator '+'
+ {
+ 'name':
+ 'Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id',
+ 'selector': '#adjacent-div2+div',
+ 'expect': ['adjacent-div4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element',
+ 'selector': 'div+#adjacent-div4',
+ 'expect': ['adjacent-div4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id',
+ 'selector': '#adjacent-div2+#adjacent-div4',
+ 'expect': ['adjacent-div4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id',
+ 'selector': '#adjacent-div2+.adjacent-div4',
+ 'expect': ['adjacent-div4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class',
+ 'selector': '.adjacent-div2+.adjacent-div4',
+ 'expect': ['adjacent-div4'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element',
+ 'selector': '#adjacent div+p',
+ 'expect': ['adjacent-p2'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name':
+ 'Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id',
+ 'selector': '#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 2,
+ 'testType': testQsaBaseline
+ },
+ {
+ 'name': 'Adjacent sibling combinator, surrounded by whitespace',
+ 'selector': '#adjacent-p2\t\r\n+\t\r\n#adjacent-p3',
+ 'expect': ['adjacent-p3'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Adjacent sibling combinator, whitespace after',
+ 'selector': '#adjacent-p2+\t\r\n#adjacent-p3',
+ 'expect': ['adjacent-p3'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Adjacent sibling combinator, whitespace before',
+ 'selector': '#adjacent-p2\t\r\n+#adjacent-p3',
+ 'expect': ['adjacent-p3'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Adjacent sibling combinator, no whitespace',
+ 'selector': '#adjacent-p2+#adjacent-p3',
+ 'expect': ['adjacent-p3'],
+ 'level': 2,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+
+ // - General sibling combinator ~ (Level 3)
+ {
+ 'name':
+ 'General sibling combinator, matching element that is a sibling of an element with id',
+ 'selector': '#sibling-div2~div',
+ 'expect': ['sibling-div4', 'sibling-div6'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'General sibling combinator, matching element with id that is a sibling of an element',
+ 'selector': 'div~#sibling-div4',
+ 'expect': ['sibling-div4'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'General sibling combinator, matching element with id that is a sibling of an element with id',
+ 'selector': '#sibling-div2~#sibling-div4',
+ 'expect': ['sibling-div4'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'General sibling combinator, matching element with class that is a sibling of an element with id',
+ 'selector': '#sibling-div2~.sibling-div',
+ 'expect': ['sibling-div4', 'sibling-div6'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'General sibling combinator, matching p element that is a sibling of a div element',
+ 'selector': '#sibling div~p',
+ 'expect': ['sibling-p2', 'sibling-p3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name':
+ 'General sibling combinator, not matching element with id that is not a sibling after a p element',
+ 'selector': '#sibling>p~div',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+ {
+ 'name':
+ 'General sibling combinator, not matching element with id that is not a sibling after an element with id',
+ 'selector': '#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1',
+ 'expect': <String>[] /*no matches*/,
+ 'level': 3,
+ 'testType': testQsaAdditional
+ },
+ {
+ 'name': 'General sibling combinator, surrounded by whitespace',
+ 'selector': '#sibling-p2\t\r\n~\t\r\n#sibling-p3',
+ 'expect': ['sibling-p3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name': 'General sibling combinator, whitespace after',
+ 'selector': '#sibling-p2~\t\r\n#sibling-p3',
+ 'expect': ['sibling-p3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name': 'General sibling combinator, whitespace before',
+ 'selector': '#sibling-p2\t\r\n~#sibling-p3',
+ 'expect': ['sibling-p3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+ {
+ 'name': 'General sibling combinator, no whitespace',
+ 'selector': '#sibling-p2~#sibling-p3',
+ 'expect': ['sibling-p3'],
+ 'level': 3,
+ 'testType': testQsaAdditional | testMatchBaseline
+ },
+
+ // Group of selectors (comma)
+ {
+ 'name': 'Syntax, group of selectors separator, surrounded by whitespace',
+ 'selector': '#group em\t\r \n,\t\r \n#group strong',
+ 'expect': ['group-em1', 'group-strong1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Syntax, group of selectors separator, whitespace after',
+ 'selector': '#group em,\t\r\n#group strong',
+ 'expect': ['group-em1', 'group-strong1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Syntax, group of selectors separator, whitespace before',
+ 'selector': '#group em\t\r\n,#group strong',
+ 'expect': ['group-em1', 'group-strong1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+ {
+ 'name': 'Syntax, group of selectors separator, no whitespace',
+ 'selector': '#group em,#group strong',
+ 'expect': ['group-em1', 'group-strong1'],
+ 'level': 1,
+ 'testType': testQsaBaseline | testMatchBaseline
+ },
+];
diff --git a/pkgs/html/test/support.dart b/pkgs/html/test/support.dart
new file mode 100644
index 0000000..82f8e62
--- /dev/null
+++ b/pkgs/html/test/support.dart
@@ -0,0 +1,186 @@
+/// Support code for the tests in this directory.
+library;
+
+import 'dart:collection';
+import 'dart:io';
+import 'dart:isolate';
+
+import 'package:html/dom.dart';
+import 'package:html/dom_parsing.dart';
+import 'package:html/src/treebuilder.dart';
+import 'package:path/path.dart' as p;
+
+typedef TreeBuilderFactory = TreeBuilder Function(bool namespaceHTMLElements);
+
+Map<String, TreeBuilderFactory>? _treeTypes;
+Map<String, TreeBuilderFactory>? get treeTypes {
+ // TODO(jmesserly): add DOM here once it's implemented
+ _treeTypes ??= {'simpletree': TreeBuilder.new};
+ return _treeTypes;
+}
+
+Future<String> get testDirectory async {
+ final packageUriDir = p.dirname(p.fromUri(await Isolate.resolvePackageUri(
+ Uri(scheme: 'package', path: 'html/html.dart'))));
+ // Assume pub layout - root is parent directory to package URI (`lib/`).
+ final rootPackageDir = p.dirname(packageUriDir);
+ return p.join(rootPackageDir, 'test');
+}
+
+Stream<String> dataFiles(String subdirectory) async* {
+ final dir = Directory(p.join(await testDirectory, 'data', subdirectory));
+ await for (final file in dir.list()) {
+ if (file is! File) continue;
+ yield file.path;
+ }
+}
+
+// TODO(jmesserly): make this class simpler. We could probably split on
+// "\n#" instead of newline and remove a lot of code.
+class TestData extends IterableBase<Map<String?, String>> {
+ final String _text;
+ final String newTestHeading;
+
+ TestData(String filename, [this.newTestHeading = 'data'])
+ // Note: can't use readAsLinesSync here because it splits on \r
+ : _text = File(filename).readAsStringSync();
+
+ // Note: in Python this was a generator, but since we can't do that in Dart,
+ // it's easier to convert it into an upfront computation.
+ @override
+ Iterator<Map<String?, String>> get iterator => _getData().iterator;
+
+ List<Map<String?, String>> _getData() {
+ var data = <String, String>{};
+ String? key;
+ final List<Map<String?, String>> result = <Map<String, String>>[];
+ final lines = _text.split('\n');
+ // Remove trailing newline to match Python
+ if (lines.last == '') {
+ lines.removeLast();
+ }
+ for (var line in lines) {
+ final heading = sectionHeading(line);
+ if (heading != null) {
+ if (data.isNotEmpty && heading == newTestHeading) {
+ // Remove trailing newline
+ data[key!] = data[key]!.substring(0, data[key]!.length - 1);
+ result.add(normaliseOutput(data));
+ data = <String, String>{};
+ }
+ key = heading;
+ data[key] = '';
+ } else if (key != null) {
+ data[key] = '${data[key]}$line\n';
+ }
+ }
+
+ if (data.isNotEmpty) {
+ result.add(normaliseOutput(data));
+ }
+ return result;
+ }
+
+ /// If the current heading is a test section heading return the heading,
+ /// otherwise return null.
+ static String? sectionHeading(String line) {
+ return line.startsWith('#') ? line.substring(1).trim() : null;
+ }
+
+ static Map<String, String> normaliseOutput(Map<String, String> data) {
+ // Remove trailing newlines
+ data.forEach((key, value) {
+ if (value.endsWith('\n')) {
+ data[key] = value.substring(0, value.length - 1);
+ }
+ });
+ return data;
+ }
+}
+
+/// Serialize the [document] into the html5 test data format.
+String testSerializer(Node document) {
+ return (TestSerializer()..visit(document)).toString();
+}
+
+/// Serializes the DOM into test format. See [testSerializer].
+class TestSerializer extends TreeVisitor {
+ final StringBuffer _str;
+ int _indent = 0;
+ String _spaces = '';
+
+ TestSerializer() : _str = StringBuffer();
+
+ @override
+ String toString() => _str.toString();
+
+ int get indent => _indent;
+
+ set indent(int value) {
+ if (_indent == value) return;
+ _spaces = ' ' * value;
+ _indent = value;
+ }
+
+ void _newline() {
+ if (_str.length > 0) _str.write('\n');
+ _str.write('|$_spaces');
+ }
+
+ @override
+ void visitNodeFallback(Node node) {
+ _newline();
+ _str.write(node);
+ visitChildren(node);
+ }
+
+ @override
+ void visitChildren(Node node) {
+ indent += 2;
+ for (var child in node.nodes) {
+ visit(child);
+ }
+ indent -= 2;
+ }
+
+ @override
+ void visitDocument(Document node) => _visitDocumentOrFragment(node);
+
+ void _visitDocumentOrFragment(Node node) {
+ indent += 1;
+ for (var child in node.nodes) {
+ visit(child);
+ }
+ indent -= 1;
+ }
+
+ @override
+ void visitDocumentFragment(DocumentFragment node) =>
+ _visitDocumentOrFragment(node);
+
+ @override
+ void visitElement(Element node) {
+ _newline();
+ _str.write(node);
+ if (node.attributes.isNotEmpty) {
+ indent += 2;
+ final keys = node.attributes.keys.toList();
+ keys.sort((x, y) {
+ if (x is String) return x.compareTo(y as String);
+ if (x is AttributeName) return x.compareTo(y as AttributeName);
+ throw StateError('Cannot sort');
+ });
+ for (var key in keys) {
+ final v = node.attributes[key];
+ if (key is AttributeName) {
+ final attr = key;
+ key = '${attr.prefix} ${attr.name}';
+ }
+ _newline();
+ _str.write('$key="$v"');
+ }
+ indent -= 2;
+ }
+ visitChildren(node);
+ }
+}
diff --git a/pkgs/html/test/tokenizer_test.dart b/pkgs/html/test/tokenizer_test.dart
new file mode 100644
index 0000000..92103ef
--- /dev/null
+++ b/pkgs/html/test/tokenizer_test.dart
@@ -0,0 +1,291 @@
+@TestOn('vm')
+library;
+
+import 'dart:convert';
+import 'dart:io';
+// Note: mirrors used to match the getattr usage in the original test
+import 'dart:mirrors' show reflect;
+
+import 'package:html/src/token.dart';
+import 'package:html/src/tokenizer.dart';
+import 'package:path/path.dart' as pathos;
+import 'package:test/test.dart';
+
+import 'support.dart';
+
+void main() async {
+ await for (var path in dataFiles('tokenizer')) {
+ if (!path.endsWith('.test')) continue;
+
+ final text = File(path).readAsStringSync();
+ final tests = jsonDecode(text) as Map<String, dynamic>;
+ final testName = pathos.basenameWithoutExtension(path);
+ final testList = tests['tests'] as List?;
+ if (testList == null) continue;
+
+ group(testName, () {
+ for (var index = 0; index < testList.length; index++) {
+ final testInfo = testList[index] as Map<String, dynamic>;
+
+ testInfo.putIfAbsent('initialStates', () => ['Data state']);
+ for (var initialState in testInfo['initialStates'] as List) {
+ test(testInfo['description'], () {
+ testInfo['initialState'] = camelCase(initialState as String);
+ runTokenizerTest(testInfo);
+ });
+ }
+ }
+ });
+ }
+}
+
+class TokenizerTestParser {
+ final String? _state;
+ final String? _lastStartTag;
+ final bool _generateSpans;
+ List<List<Object?>>? outputTokens;
+
+ TokenizerTestParser(String? initialState,
+ [String? lastStartTag, bool generateSpans = false])
+ : _state = initialState,
+ _lastStartTag = lastStartTag,
+ _generateSpans = generateSpans;
+
+ List<dynamic>? parse(String str) {
+ // Note: we need to pass bytes to the tokenizer if we want it to handle BOM.
+ final bytes = utf8.encode(str);
+ final tokenizer =
+ HtmlTokenizer(bytes, encoding: 'utf-8', generateSpans: _generateSpans);
+ outputTokens = [];
+
+ // Note: we can't get a closure of the state method. However, we can
+ // create a new closure to invoke it via mirrors.
+ final mtok = reflect(tokenizer);
+ tokenizer.state =
+ () => mtok.invoke(Symbol(_state!), const []).reflectee as bool;
+
+ if (_lastStartTag != null) {
+ tokenizer.currentToken = StartTagToken(_lastStartTag);
+ }
+
+ while (tokenizer.moveNext()) {
+ final token = tokenizer.current;
+ switch (token.kind) {
+ case TokenKind.characters:
+ processCharacters(token as CharactersToken);
+ break;
+ case TokenKind.spaceCharacters:
+ processSpaceCharacters(token as SpaceCharactersToken);
+ break;
+ case TokenKind.startTag:
+ processStartTag(token as StartTagToken);
+ break;
+ case TokenKind.endTag:
+ processEndTag(token as EndTagToken);
+ break;
+ case TokenKind.comment:
+ processComment(token as CommentToken);
+ break;
+ case TokenKind.doctype:
+ processDoctype(token as DoctypeToken);
+ break;
+ case TokenKind.parseError:
+ processParseError(token as ParseErrorToken);
+ break;
+ }
+ }
+
+ return outputTokens;
+ }
+
+ void processDoctype(DoctypeToken token) {
+ addOutputToken(token,
+ ['DOCTYPE', token.name, token.publicId, token.systemId, token.correct]);
+ }
+
+ void processStartTag(StartTagToken token) {
+ addOutputToken(
+ token, ['StartTag', token.name, token.data, token.selfClosing]);
+ }
+
+ void processEndTag(EndTagToken token) {
+ addOutputToken(token, ['EndTag', token.name, token.selfClosing]);
+ }
+
+ void processComment(StringToken token) {
+ addOutputToken(token, ['Comment', token.data]);
+ }
+
+ void processSpaceCharacters(StringToken token) {
+ processCharacters(token);
+ }
+
+ void processCharacters(StringToken token) {
+ addOutputToken(token, ['Character', token.data]);
+ }
+
+ void processParseError(StringToken token) {
+ // TODO(jmesserly): when debugging test failures it can be useful to add
+ // logging here like `print('ParseError $token');`. It would be nice to
+ // use the actual logging library.
+ addOutputToken(token, ['ParseError', token.data]);
+ }
+
+ void addOutputToken(Token token, List<Object?> array) {
+ outputTokens!.add([
+ ...array,
+ if (token.span != null && _generateSpans) token.span!.start.offset,
+ if (token.span != null && _generateSpans) token.span!.end.offset,
+ ]);
+ }
+}
+
+/// [tokens] can contain strings, lists, and maps.
+List<dynamic> concatenateCharacterTokens(List<dynamic> tokens) {
+ final outputTokens = <dynamic>[];
+ for (var token in tokens) {
+ if (token != 'ParseError' && (token as List)[0] == 'Character') {
+ if (outputTokens.isNotEmpty &&
+ outputTokens.last != 'ParseError' &&
+ (outputTokens.last as List)[0] == 'Character') {
+ (outputTokens.last as List)[1] =
+ '${(outputTokens.last as List)[1]}${token[1]}';
+ } else {
+ outputTokens.add(token);
+ }
+ } else {
+ outputTokens.add(token);
+ }
+ }
+ return outputTokens;
+}
+
+List<dynamic> normalizeTokens(List<dynamic> tokens) {
+ // TODO: convert tests to reflect arrays
+ for (var i = 0; i < tokens.length; i++) {
+ final token = tokens[i] as List;
+ if (token[0] == 'ParseError') {
+ tokens[i] = token[0];
+ }
+ }
+ return tokens;
+}
+
+/// Test whether the test has passed or failed
+///
+/// If the ignoreErrorOrder flag is set to true we don't test the relative
+/// positions of parse errors and non parse errors.
+void expectTokensMatch(List<dynamic> expectedTokens,
+ List<dynamic> receivedTokens, bool ignoreErrorOrder,
+ [bool ignoreErrors = false, String? message]) {
+ // If the 'selfClosing' attribute is not included in the expected test tokens,
+ // remove it from the received token.
+ var removeSelfClosing = false;
+ for (var token in expectedTokens.whereType<List<dynamic>>()) {
+ if (token[0] == 'StartTag' && token.length == 3 ||
+ token[0] == 'EndTag' && token.length == 2) {
+ removeSelfClosing = true;
+ break;
+ }
+ }
+
+ if (removeSelfClosing) {
+ for (var token in receivedTokens.whereType<List<dynamic>>()) {
+ if (token[0] == 'StartTag' || token[0] == 'EndTag') {
+ token.removeLast();
+ }
+ }
+ }
+
+ if (!ignoreErrorOrder && !ignoreErrors) {
+ expect(receivedTokens, equals(expectedTokens), reason: message);
+ } else {
+ // Sort the tokens into two groups; non-parse errors and parse errors
+ final expectedNonErrors = expectedTokens.where((t) => t != 'ParseError');
+ final receivedNonErrors = receivedTokens.where((t) => t != 'ParseError');
+
+ expect(receivedNonErrors, equals(expectedNonErrors), reason: message);
+ if (!ignoreErrors) {
+ final expectedParseErrors =
+ expectedTokens.where((t) => t == 'ParseError');
+ final receivedParseErrors =
+ receivedTokens.where((t) => t == 'ParseError');
+ expect(receivedParseErrors, equals(expectedParseErrors), reason: message);
+ }
+ }
+}
+
+void runTokenizerTest(Map<String, dynamic> testInfo) {
+ // XXX - move this out into the setup function
+ // concatenate all consecutive character tokens into a single token
+ if (testInfo.containsKey('doubleEscaped')) {
+ testInfo = unescape(testInfo);
+ }
+
+ final expected = concatenateCharacterTokens(testInfo['output'] as List);
+ if (!testInfo.containsKey('lastStartTag')) {
+ testInfo['lastStartTag'] = null;
+ }
+ final parser = TokenizerTestParser(
+ testInfo['initialState'] as String?,
+ testInfo['lastStartTag'] as String?,
+ testInfo['generateSpans'] as bool? ?? false);
+ var tokens = parser.parse(testInfo['input'] as String)!;
+ tokens = concatenateCharacterTokens(tokens);
+ final received = normalizeTokens(tokens);
+ final errorMsg = [
+ '\n\nInitial state:',
+ testInfo['initialState'],
+ '\nInput:',
+ testInfo['input'],
+ '\nExpected:',
+ expected,
+ '\nreceived:',
+ tokens
+ ].map((s) => '$s').join('\n');
+ final ignoreErrorOrder = testInfo['ignoreErrorOrder'] as bool? ?? false;
+
+ expectTokensMatch(expected, received, ignoreErrorOrder, true, errorMsg);
+}
+
+Map<String, dynamic> unescape(Map<String, dynamic> testInfo) {
+ // TODO(sigmundch,jmesserly): we currently use jsonDecode to unescape the
+ // unicode characters in the string, we should use a decoding that works with
+ // any control characters.
+ dynamic decode(String inp) => inp == '\u0000' ? inp : jsonDecode('"$inp"');
+
+ testInfo['input'] = decode(testInfo['input'] as String);
+
+ for (var token in testInfo['output'] as List) {
+ if (token == 'ParseError') {
+ continue;
+ }
+
+ token as List;
+ token[1] = decode(token[1] as String);
+
+ if (token.length > 2) {
+ for (var pair in token[2] as List) {
+ pair as List;
+ final key = pair[0] as String;
+ final value = pair[1] as String;
+
+ (token[2] as Map).remove(key);
+ (token[2] as Map)[decode(key)] = decode(value);
+ }
+ }
+ }
+
+ return testInfo;
+}
+
+String camelCase(String s) {
+ s = s.toLowerCase();
+ final result = StringBuffer();
+ for (var match in RegExp(r'\W+(\w)(\w+)').allMatches(s)) {
+ if (result.length == 0) result.write(s.substring(0, match.start));
+ result.write(match.group(1)!.toUpperCase());
+ result.write(match.group(2));
+ }
+ return result.toString();
+}
diff --git a/pkgs/io/.gitignore b/pkgs/io/.gitignore
new file mode 100644
index 0000000..01d42c0
--- /dev/null
+++ b/pkgs/io/.gitignore
@@ -0,0 +1,4 @@
+.dart_tool/
+.pub/
+.packages
+pubspec.lock
diff --git a/pkgs/io/AUTHORS b/pkgs/io/AUTHORS
new file mode 100644
index 0000000..ff09364
--- /dev/null
+++ b/pkgs/io/AUTHORS
@@ -0,0 +1,7 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
+
diff --git a/pkgs/io/CHANGELOG.md b/pkgs/io/CHANGELOG.md
new file mode 100644
index 0000000..e0631fa
--- /dev/null
+++ b/pkgs/io/CHANGELOG.md
@@ -0,0 +1,119 @@
+## 1.0.5
+
+* Require Dart 3.4.
+* Move to `dart-lang/tools` monorepo.
+
+## 1.0.4
+
+* Updates to the readme.
+
+## 1.0.3
+
+* Revert `meta` constraint to `^1.3.0`.
+
+## 1.0.2
+
+* Update `meta` constraint to `>=1.3.0 <3.0.0`.
+
+## 1.0.1
+
+* Update code examples to call the unified `dart` developer tool.
+
+## 1.0.0
+
+* Migrate this package to null-safety.
+* Require Dart >=2.12.
+
+## 0.3.5
+
+* Require Dart >=2.1.
+* Remove dependency on `package:charcode`.
+
+## 0.3.4
+
+* Fix a number of issues affecting the package score on `pub.dev`.
+
+## 0.3.3
+
+* Updates for Dart 2 constants. Require at least Dart `2.0.0-dev.54`.
+
+* Fix the type of `StartProcess` typedef to match `Process.start` from
+ `dart:io`.
+
+## 0.3.2+1
+
+* `ansi.dart`
+
+ * The "forScript" code paths now ignore the `ansiOutputEnabled` value. Affects
+ the `escapeForScript` property on `AnsiCode` and the `wrap` and `wrapWith`
+ functions when `forScript` is true.
+
+## 0.3.2
+
+* `ansi.dart`
+
+ * Added `forScript` named argument to top-level `wrapWith` function.
+
+ * `AnsiCode`
+
+ * Added `String get escapeForScript` property.
+
+ * Added `forScript` named argument to `wrap` function.
+
+## 0.3.1
+
+- Added `SharedStdIn.nextLine` (similar to `readLineSync`) and `lines`:
+
+```dart
+main() async {
+ // Prints the first line entered on stdin.
+ print(await sharedStdIn.nextLine());
+
+ // Prints all remaining lines.
+ await for (final line in sharedStdIn.lines) {
+ print(line);
+ }
+}
+```
+
+- Added a `copyPath` and `copyPathSync` function, similar to `cp -R`.
+
+- Added a dependency on `package:path`.
+
+- Added the remaining missing arguments to `ProcessManager.spawnX` which
+ forward to `Process.start`. It is now an interchangeable function for running
+ a process.
+
+## 0.3.0
+
+- **BREAKING CHANGE**: The `arguments` argument to `ProcessManager.spawn` is
+ now positional (not named) and required. This makes it more similar to the
+ built-in `Process.start`, and easier to use as a drop in replacement:
+
+```dart
+main() {
+ processManager.spawn('dart', ['--version']);
+}
+```
+
+- Fixed a bug where processes created from `ProcessManager.spawn` could not
+ have their `stdout`/`stderr` read through their respective getters (a runtime
+ error was always thrown).
+
+- Added `ProcessMangaer#spawnBackground`, which does not forward `stdin`.
+
+- Added `ProcessManager#spawnDetached`, which does not forward any I/O.
+
+- Added the `shellSplit()` function, which parses a list of arguments in the
+ same manner as [the POSIX shell][what_is_posix_shell].
+
+[what_is_posix_shell]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html
+
+## 0.2.0
+
+- Initial commit of...
+ - `FutureOr<bool> String isExecutable(path)`.
+ - `ExitCode`
+ - `ProcessManager` and `Spawn`
+ - `sharedStdIn` and `SharedStdIn`
+ - `ansi.dart` library with support for formatting terminal output
diff --git a/pkgs/io/LICENSE b/pkgs/io/LICENSE
new file mode 100644
index 0000000..03af64a
--- /dev/null
+++ b/pkgs/io/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2017, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/io/README.md b/pkgs/io/README.md
new file mode 100644
index 0000000..adbc941
--- /dev/null
+++ b/pkgs/io/README.md
@@ -0,0 +1,104 @@
+[](https://github.com/dart-lang/tools/actions/workflows/io.yaml)
+[](https://pub.dev/packages/io)
+[](https://pub.dev/packages/io/publisher)
+
+Contains utilities for the Dart VM's `dart:io`.
+
+## Usage - `io.dart`
+
+### Files
+
+#### `isExecutable`
+
+Returns whether a provided file path is considered _executable_ on the host
+operating system.
+
+### Processes
+
+#### `ExitCode`
+
+An `enum`-like class that contains known exit codes.
+
+#### `ProcessManager`
+
+A higher-level service for spawning and communicating with processes.
+
+##### Use `spawn` to create a process with std[in|out|err] forwarded by default
+
+```dart
+Future<void> main() async {
+ final manager = ProcessManager();
+
+ // Print `dart` tool version to stdout.
+ print('** Running `dart --version`');
+ var spawn = await manager.spawn('dart', ['--version']);
+ await spawn.exitCode;
+
+ // Check formatting and print the result to stdout.
+ print('** Running `dart format --output=none .`');
+ spawn = await manager.spawn('dart', ['format', '--output=none', '.']);
+ await spawn.exitCode;
+
+ // Check if a package is ready for publishing.
+ // Upon hitting a blocking stdin state, you may directly
+ // output to the processes's stdin via your own, similar to how a bash or
+ // shell script would spawn a process.
+ print('** Running pub publish');
+ spawn = await manager.spawn('dart', ['pub', 'publish', '--dry-run']);
+ await spawn.exitCode;
+
+ // Closes stdin for the entire program.
+ await sharedStdIn.terminate();
+}
+```
+
+#### `sharedStdIn`
+
+A safer version of the default `stdin` stream from `dart:io` that allows a
+subscriber to cancel their subscription, and then allows a _new_ subscriber to
+start listening. This differs from the default behavior where only a single
+listener is ever allowed in the application lifecycle:
+
+```dart
+test('should allow multiple subscribers', () async {
+ final logs = <String>[];
+ final asUtf8 = sharedStdIn.transform(UTF8.decoder);
+ // Wait for input for the user.
+ logs.add(await asUtf8.first);
+ // Wait for more input for the user.
+ logs.add(await asUtf8.first);
+ expect(logs, ['Hello World', 'Goodbye World']);
+});
+```
+
+For testing, an instance of `SharedStdIn` may be created directly.
+
+## Usage - `ansi.dart`
+
+```dart
+import 'dart:io' as io;
+import 'package:io/ansi.dart';
+
+void main() {
+ // To use one style, call the `wrap` method on one of the provided top-level
+ // values.
+ io.stderr.writeln(red.wrap("Bad error!"));
+
+ // To use multiple styles, call `wrapWith`.
+ print(wrapWith('** Important **', [red, styleBold, styleUnderlined]));
+
+ // The wrap functions will simply return the provided value unchanged if
+ // `ansiOutputEnabled` is false.
+ //
+ // You can override the value `ansiOutputEnabled` by wrapping code in
+ // `overrideAnsiOutput`.
+ overrideAnsiOutput(false, () {
+ assert('Normal text' == green.wrap('Normal text'));
+ });
+}
+```
+
+## Publishing automation
+
+For information about our publishing automation and release process, see
+https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.
diff --git a/pkgs/io/analysis_options.yaml b/pkgs/io/analysis_options.yaml
new file mode 100644
index 0000000..6d74ee9
--- /dev/null
+++ b/pkgs/io/analysis_options.yaml
@@ -0,0 +1,32 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_classes_with_only_static_members
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_returning_this
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - join_return_with_assignment
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - no_runtimeType_toString
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - unnecessary_await_in_return
+ - unnecessary_breaks
+ - use_if_null_to_convert_nulls_to_bools
+ - use_raw_strings
+ - use_string_buffers
diff --git a/pkgs/io/example/example.dart b/pkgs/io/example/example.dart
new file mode 100644
index 0000000..8e358fd
--- /dev/null
+++ b/pkgs/io/example/example.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math';
+
+import 'package:io/ansi.dart';
+
+/// Prints a sample of all of the `AnsiCode` values.
+void main(List<String> args) {
+ final forScript = args.contains('--for-script');
+
+ if (!ansiOutputEnabled) {
+ print('`ansiOutputEnabled` is `false`.');
+ print("Don't expect pretty output.");
+ }
+ _preview('Foreground', foregroundColors, forScript);
+ _preview('Background', backgroundColors, forScript);
+ _preview('Styles', styles, forScript);
+}
+
+void _preview(String name, List<AnsiCode> values, bool forScript) {
+ print('');
+ final longest = values.map((ac) => ac.name.length).reduce(max);
+
+ print(wrapWith('** $name **', [styleBold, styleUnderlined]));
+ for (var code in values) {
+ final header =
+ '${code.name.padRight(longest)} ${code.code.toString().padLeft(3)}';
+
+ print("$header: ${code.wrap('Sample', forScript: forScript)}");
+ }
+}
diff --git a/pkgs/io/example/spawn_process_example.dart b/pkgs/io/example/spawn_process_example.dart
new file mode 100644
index 0000000..b7ba247
--- /dev/null
+++ b/pkgs/io/example/spawn_process_example.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:io/io.dart';
+
+/// Runs a few subcommands in the `dart` command.
+Future<void> main() async {
+ final manager = ProcessManager();
+
+ // Print `dart` tool version to stdout.
+ print('** Running `dart --version`');
+ var spawn = await manager.spawn('dart', ['--version']);
+ await spawn.exitCode;
+
+ // Check formatting and print the result to stdout.
+ print('** Running `dart format --output=none .`');
+ spawn = await manager.spawn('dart', ['format', '--output=none', '.']);
+ await spawn.exitCode;
+
+ // Check if a package is ready for publishing.
+ // Upon hitting a blocking stdin state, you may directly
+ // output to the processes's stdin via your own, similar to how a bash or
+ // shell script would spawn a process.
+ print('** Running pub publish');
+ spawn = await manager.spawn('dart', ['pub', 'publish', '--dry-run']);
+ await spawn.exitCode;
+
+ // Closes stdin for the entire program.
+ await sharedStdIn.terminate();
+}
diff --git a/pkgs/io/lib/ansi.dart b/pkgs/io/lib/ansi.dart
new file mode 100644
index 0000000..a2adbe7
--- /dev/null
+++ b/pkgs/io/lib/ansi.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/ansi_code.dart';
diff --git a/pkgs/io/lib/io.dart b/pkgs/io/lib/io.dart
new file mode 100644
index 0000000..8ee0843
--- /dev/null
+++ b/pkgs/io/lib/io.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/copy_path.dart' show copyPath, copyPathSync;
+export 'src/exit_code.dart' show ExitCode;
+export 'src/permissions.dart' show isExecutable;
+export 'src/process_manager.dart' show ProcessManager, Spawn, StartProcess;
+export 'src/shared_stdin.dart' show SharedStdIn, sharedStdIn;
+export 'src/shell_words.dart' show shellSplit;
diff --git a/pkgs/io/lib/src/ansi_code.dart b/pkgs/io/lib/src/ansi_code.dart
new file mode 100644
index 0000000..c9a22c5
--- /dev/null
+++ b/pkgs/io/lib/src/ansi_code.dart
@@ -0,0 +1,316 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io' as io;
+
+const _ansiEscapeLiteral = '\x1B';
+const _ansiEscapeForScript = r'\033';
+
+/// Whether formatted ANSI output is enabled for [wrapWith] and [AnsiCode.wrap].
+///
+/// By default, returns `true` if both `stdout.supportsAnsiEscapes` and
+/// `stderr.supportsAnsiEscapes` from `dart:io` are `true`.
+///
+/// The default can be overridden by setting the [Zone] variable [AnsiCode] to
+/// either `true` or `false`.
+///
+/// [overrideAnsiOutput] is provided to make this easy.
+bool get ansiOutputEnabled =>
+ Zone.current[AnsiCode] as bool? ??
+ (io.stdout.supportsAnsiEscapes && io.stderr.supportsAnsiEscapes);
+
+/// Returns `true` no formatting is required for [input].
+bool _isNoop(bool skip, String? input, bool? forScript) =>
+ skip ||
+ input == null ||
+ input.isEmpty ||
+ !((forScript ?? false) || ansiOutputEnabled);
+
+/// Allows overriding [ansiOutputEnabled] to [enableAnsiOutput] for the code run
+/// within [body].
+T overrideAnsiOutput<T>(bool enableAnsiOutput, T Function() body) =>
+ runZoned(body, zoneValues: <Object, Object>{AnsiCode: enableAnsiOutput});
+
+/// The type of code represented by [AnsiCode].
+class AnsiCodeType {
+ final String _name;
+
+ /// A foreground color.
+ static const AnsiCodeType foreground = AnsiCodeType._('foreground');
+
+ /// A style.
+ static const AnsiCodeType style = AnsiCodeType._('style');
+
+ /// A background color.
+ static const AnsiCodeType background = AnsiCodeType._('background');
+
+ /// A reset value.
+ static const AnsiCodeType reset = AnsiCodeType._('reset');
+
+ const AnsiCodeType._(this._name);
+
+ @override
+ String toString() => 'AnsiType.$_name';
+}
+
+/// Standard ANSI escape code for customizing terminal text output.
+///
+/// [Source](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
+class AnsiCode {
+ /// The numeric value associated with this code.
+ final int code;
+
+ /// The [AnsiCode] that resets this value, if one exists.
+ ///
+ /// Otherwise, `null`.
+ final AnsiCode? reset;
+
+ /// A description of this code.
+ final String name;
+
+ /// The type of code that is represented.
+ final AnsiCodeType type;
+
+ const AnsiCode._(this.name, this.type, this.code, this.reset);
+
+ /// Represents the value escaped for use in terminal output.
+ String get escape => '$_ansiEscapeLiteral[${code}m';
+
+ /// Represents the value as an unescaped literal suitable for scripts.
+ String get escapeForScript => '$_ansiEscapeForScript[${code}m';
+
+ String _escapeValue({bool forScript = false}) =>
+ forScript ? escapeForScript : escape;
+
+ /// Wraps [value] with the [escape] value for this code, followed by
+ /// [resetAll].
+ ///
+ /// If [forScript] is `true`, the return value is an unescaped literal. The
+ /// value of [ansiOutputEnabled] is also ignored.
+ ///
+ /// Returns `value` unchanged if
+ /// * [value] is `null` or empty
+ /// * both [ansiOutputEnabled] and [forScript] are `false`.
+ /// * [type] is [AnsiCodeType.reset]
+ String? wrap(String? value, {bool forScript = false}) =>
+ _isNoop(type == AnsiCodeType.reset, value, forScript)
+ ? value
+ : '${_escapeValue(forScript: forScript)}$value'
+ '${reset!._escapeValue(forScript: forScript)}';
+
+ @override
+ String toString() => '$name ${type._name} ($code)';
+}
+
+/// Returns a [String] formatted with [codes].
+///
+/// If [forScript] is `true`, the return value is an unescaped literal. The
+/// value of [ansiOutputEnabled] is also ignored.
+///
+/// Returns `value` unchanged if
+/// * [value] is `null` or empty.
+/// * both [ansiOutputEnabled] and [forScript] are `false`.
+/// * [codes] is empty.
+///
+/// Throws an [ArgumentError] if
+/// * [codes] contains more than one value of type [AnsiCodeType.foreground].
+/// * [codes] contains more than one value of type [AnsiCodeType.background].
+/// * [codes] contains any value of type [AnsiCodeType.reset].
+String? wrapWith(String? value, Iterable<AnsiCode> codes,
+ {bool forScript = false}) {
+ // Eliminate duplicates
+ final myCodes = codes.toSet();
+
+ if (_isNoop(myCodes.isEmpty, value, forScript)) {
+ return value;
+ }
+
+ var foreground = 0, background = 0;
+ for (var code in myCodes) {
+ switch (code.type) {
+ case AnsiCodeType.foreground:
+ foreground++;
+ if (foreground > 1) {
+ throw ArgumentError.value(codes, 'codes',
+ 'Cannot contain more than one foreground color code.');
+ }
+ case AnsiCodeType.background:
+ background++;
+ if (background > 1) {
+ throw ArgumentError.value(codes, 'codes',
+ 'Cannot contain more than one foreground color code.');
+ }
+ case AnsiCodeType.reset:
+ throw ArgumentError.value(
+ codes, 'codes', 'Cannot contain reset codes.');
+ case AnsiCodeType.style:
+ // Ignore.
+ break;
+ }
+ }
+
+ final sortedCodes = myCodes.map((ac) => ac.code).toList()..sort();
+ final escapeValue = forScript ? _ansiEscapeForScript : _ansiEscapeLiteral;
+
+ return "$escapeValue[${sortedCodes.join(';')}m$value"
+ '${resetAll._escapeValue(forScript: forScript)}';
+}
+
+//
+// Style values
+//
+
+const styleBold = AnsiCode._('bold', AnsiCodeType.style, 1, resetBold);
+const styleDim = AnsiCode._('dim', AnsiCodeType.style, 2, resetDim);
+const styleItalic = AnsiCode._('italic', AnsiCodeType.style, 3, resetItalic);
+const styleUnderlined =
+ AnsiCode._('underlined', AnsiCodeType.style, 4, resetUnderlined);
+const styleBlink = AnsiCode._('blink', AnsiCodeType.style, 5, resetBlink);
+const styleReverse = AnsiCode._('reverse', AnsiCodeType.style, 7, resetReverse);
+
+/// Not widely supported.
+const styleHidden = AnsiCode._('hidden', AnsiCodeType.style, 8, resetHidden);
+
+/// Not widely supported.
+const styleCrossedOut =
+ AnsiCode._('crossed out', AnsiCodeType.style, 9, resetCrossedOut);
+
+//
+// Reset values
+//
+
+const resetAll = AnsiCode._('all', AnsiCodeType.reset, 0, null);
+
+// NOTE: bold is weird. The reset code seems to be 22 sometimes – not 21
+// See https://gitlab.com/gnachman/iterm2/issues/3208
+const resetBold = AnsiCode._('bold', AnsiCodeType.reset, 22, null);
+const resetDim = AnsiCode._('dim', AnsiCodeType.reset, 22, null);
+const resetItalic = AnsiCode._('italic', AnsiCodeType.reset, 23, null);
+const resetUnderlined = AnsiCode._('underlined', AnsiCodeType.reset, 24, null);
+const resetBlink = AnsiCode._('blink', AnsiCodeType.reset, 25, null);
+const resetReverse = AnsiCode._('reverse', AnsiCodeType.reset, 27, null);
+const resetHidden = AnsiCode._('hidden', AnsiCodeType.reset, 28, null);
+const resetCrossedOut = AnsiCode._('crossed out', AnsiCodeType.reset, 29, null);
+
+//
+// Foreground values
+//
+
+const black = AnsiCode._('black', AnsiCodeType.foreground, 30, resetAll);
+const red = AnsiCode._('red', AnsiCodeType.foreground, 31, resetAll);
+const green = AnsiCode._('green', AnsiCodeType.foreground, 32, resetAll);
+const yellow = AnsiCode._('yellow', AnsiCodeType.foreground, 33, resetAll);
+const blue = AnsiCode._('blue', AnsiCodeType.foreground, 34, resetAll);
+const magenta = AnsiCode._('magenta', AnsiCodeType.foreground, 35, resetAll);
+const cyan = AnsiCode._('cyan', AnsiCodeType.foreground, 36, resetAll);
+const lightGray =
+ AnsiCode._('light gray', AnsiCodeType.foreground, 37, resetAll);
+const defaultForeground =
+ AnsiCode._('default', AnsiCodeType.foreground, 39, resetAll);
+const darkGray = AnsiCode._('dark gray', AnsiCodeType.foreground, 90, resetAll);
+const lightRed = AnsiCode._('light red', AnsiCodeType.foreground, 91, resetAll);
+const lightGreen =
+ AnsiCode._('light green', AnsiCodeType.foreground, 92, resetAll);
+const lightYellow =
+ AnsiCode._('light yellow', AnsiCodeType.foreground, 93, resetAll);
+const lightBlue =
+ AnsiCode._('light blue', AnsiCodeType.foreground, 94, resetAll);
+const lightMagenta =
+ AnsiCode._('light magenta', AnsiCodeType.foreground, 95, resetAll);
+const lightCyan =
+ AnsiCode._('light cyan', AnsiCodeType.foreground, 96, resetAll);
+const white = AnsiCode._('white', AnsiCodeType.foreground, 97, resetAll);
+
+//
+// Background values
+//
+
+const backgroundBlack =
+ AnsiCode._('black', AnsiCodeType.background, 40, resetAll);
+const backgroundRed = AnsiCode._('red', AnsiCodeType.background, 41, resetAll);
+const backgroundGreen =
+ AnsiCode._('green', AnsiCodeType.background, 42, resetAll);
+const backgroundYellow =
+ AnsiCode._('yellow', AnsiCodeType.background, 43, resetAll);
+const backgroundBlue =
+ AnsiCode._('blue', AnsiCodeType.background, 44, resetAll);
+const backgroundMagenta =
+ AnsiCode._('magenta', AnsiCodeType.background, 45, resetAll);
+const backgroundCyan =
+ AnsiCode._('cyan', AnsiCodeType.background, 46, resetAll);
+const backgroundLightGray =
+ AnsiCode._('light gray', AnsiCodeType.background, 47, resetAll);
+const backgroundDefault =
+ AnsiCode._('default', AnsiCodeType.background, 49, resetAll);
+const backgroundDarkGray =
+ AnsiCode._('dark gray', AnsiCodeType.background, 100, resetAll);
+const backgroundLightRed =
+ AnsiCode._('light red', AnsiCodeType.background, 101, resetAll);
+const backgroundLightGreen =
+ AnsiCode._('light green', AnsiCodeType.background, 102, resetAll);
+const backgroundLightYellow =
+ AnsiCode._('light yellow', AnsiCodeType.background, 103, resetAll);
+const backgroundLightBlue =
+ AnsiCode._('light blue', AnsiCodeType.background, 104, resetAll);
+const backgroundLightMagenta =
+ AnsiCode._('light magenta', AnsiCodeType.background, 105, resetAll);
+const backgroundLightCyan =
+ AnsiCode._('light cyan', AnsiCodeType.background, 106, resetAll);
+const backgroundWhite =
+ AnsiCode._('white', AnsiCodeType.background, 107, resetAll);
+
+/// All of the [AnsiCode] values that represent [AnsiCodeType.style].
+const List<AnsiCode> styles = [
+ styleBold,
+ styleDim,
+ styleItalic,
+ styleUnderlined,
+ styleBlink,
+ styleReverse,
+ styleHidden,
+ styleCrossedOut
+];
+
+/// All of the [AnsiCode] values that represent [AnsiCodeType.foreground].
+const List<AnsiCode> foregroundColors = [
+ black,
+ red,
+ green,
+ yellow,
+ blue,
+ magenta,
+ cyan,
+ lightGray,
+ defaultForeground,
+ darkGray,
+ lightRed,
+ lightGreen,
+ lightYellow,
+ lightBlue,
+ lightMagenta,
+ lightCyan,
+ white
+];
+
+/// All of the [AnsiCode] values that represent [AnsiCodeType.background].
+const List<AnsiCode> backgroundColors = [
+ backgroundBlack,
+ backgroundRed,
+ backgroundGreen,
+ backgroundYellow,
+ backgroundBlue,
+ backgroundMagenta,
+ backgroundCyan,
+ backgroundLightGray,
+ backgroundDefault,
+ backgroundDarkGray,
+ backgroundLightRed,
+ backgroundLightGreen,
+ backgroundLightYellow,
+ backgroundLightBlue,
+ backgroundLightMagenta,
+ backgroundLightCyan,
+ backgroundWhite
+];
diff --git a/pkgs/io/lib/src/charcodes.dart b/pkgs/io/lib/src/charcodes.dart
new file mode 100644
index 0000000..4acaf0a
--- /dev/null
+++ b/pkgs/io/lib/src/charcodes.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Generated using:
+// pub global run charcode \$=dollar \'=single_quote \"=double_quote \
+// \' '\\\n"$`# \t'
+
+/// "Horizontal Tab" control character, common name.
+const int $tab = 0x09;
+
+/// "Line feed" control character.
+const int $lf = 0x0a;
+
+/// Space character.
+const int $space = 0x20;
+
+/// Character `"`, short name.
+const int $doubleQuote = 0x22;
+
+/// Character `#`.
+const int $hash = 0x23;
+
+/// Character `$`.
+const int $dollar = 0x24;
+
+/// Character "'".
+const int $singleQuote = 0x27;
+
+/// Character `\`.
+const int $backslash = 0x5c;
+
+/// Character `` ` ``.
+const int $backquote = 0x60;
diff --git a/pkgs/io/lib/src/copy_path.dart b/pkgs/io/lib/src/copy_path.dart
new file mode 100644
index 0000000..3a999b6
--- /dev/null
+++ b/pkgs/io/lib/src/copy_path.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+
+bool _doNothing(String from, String to) {
+ if (p.canonicalize(from) == p.canonicalize(to)) {
+ return true;
+ }
+ if (p.isWithin(from, to)) {
+ throw ArgumentError('Cannot copy from $from to $to');
+ }
+ return false;
+}
+
+/// Copies all of the files in the [from] directory to [to].
+///
+/// This is similar to `cp -R <from> <to>`:
+/// * Symlinks are supported.
+/// * Existing files are over-written, if any.
+/// * If [to] is within [from], throws [ArgumentError] (an infinite operation).
+/// * If [from] and [to] are canonically the same, no operation occurs.
+///
+/// Returns a future that completes when complete.
+Future<void> copyPath(String from, String to) async {
+ if (_doNothing(from, to)) {
+ return;
+ }
+ await Directory(to).create(recursive: true);
+ await for (final file in Directory(from).list(recursive: true)) {
+ final copyTo = p.join(to, p.relative(file.path, from: from));
+ if (file is Directory) {
+ await Directory(copyTo).create(recursive: true);
+ } else if (file is File) {
+ await File(file.path).copy(copyTo);
+ } else if (file is Link) {
+ await Link(copyTo).create(await file.target(), recursive: true);
+ }
+ }
+}
+
+/// Copies all of the files in the [from] directory to [to].
+///
+/// This is similar to `cp -R <from> <to>`:
+/// * Symlinks are supported.
+/// * Existing files are over-written, if any.
+/// * If [to] is within [from], throws [ArgumentError] (an infinite operation).
+/// * If [from] and [to] are canonically the same, no operation occurs.
+///
+/// This action is performed synchronously (blocking I/O).
+void copyPathSync(String from, String to) {
+ if (_doNothing(from, to)) {
+ return;
+ }
+ Directory(to).createSync(recursive: true);
+ for (final file in Directory(from).listSync(recursive: true)) {
+ final copyTo = p.join(to, p.relative(file.path, from: from));
+ if (file is Directory) {
+ Directory(copyTo).createSync(recursive: true);
+ } else if (file is File) {
+ File(file.path).copySync(copyTo);
+ } else if (file is Link) {
+ Link(copyTo).createSync(file.targetSync(), recursive: true);
+ }
+ }
+}
diff --git a/pkgs/io/lib/src/exit_code.dart b/pkgs/io/lib/src/exit_code.dart
new file mode 100644
index 0000000..d405558
--- /dev/null
+++ b/pkgs/io/lib/src/exit_code.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Exit code constants.
+///
+/// [Source](https://www.freebsd.org/cgi/man.cgi?query=sysexits).
+class ExitCode {
+ /// Command completed successfully.
+ static const success = ExitCode._(0, 'success');
+
+ /// Command was used incorrectly.
+ ///
+ /// This may occur if the wrong number of arguments was used, a bad flag, or
+ /// bad syntax in a parameter.
+ static const usage = ExitCode._(64, 'usage');
+
+ /// Input data was used incorrectly.
+ ///
+ /// This should occur only for user data (not system files).
+ static const data = ExitCode._(65, 'data');
+
+ /// An input file (not a system file) did not exist or was not readable.
+ static const noInput = ExitCode._(66, 'noInput');
+
+ /// User specified did not exist.
+ static const noUser = ExitCode._(67, 'noUser');
+
+ /// Host specified did not exist.
+ static const noHost = ExitCode._(68, 'noHost');
+
+ /// A service is unavailable.
+ ///
+ /// This may occur if a support program or file does not exist. This may also
+ /// be used as a catch-all error when something you wanted to do does not
+ /// work, but you do not know why.
+ static const unavailable = ExitCode._(69, 'unavailable');
+
+ /// An internal software error has been detected.
+ ///
+ /// This should be limited to non-operating system related errors as possible.
+ static const software = ExitCode._(70, 'software');
+
+ /// An operating system error has been detected.
+ ///
+ /// This intended to be used for such thing as `cannot fork` or `cannot pipe`.
+ static const osError = ExitCode._(71, 'osError');
+
+ /// Some system file (e.g. `/etc/passwd`) does not exist or could not be read.
+ static const osFile = ExitCode._(72, 'osFile');
+
+ /// A (user specified) output file cannot be created.
+ static const cantCreate = ExitCode._(73, 'cantCreate');
+
+ /// An error occurred doing I/O on some file.
+ static const ioError = ExitCode._(74, 'ioError');
+
+ /// Temporary failure, indicating something is not really an error.
+ ///
+ /// In some cases, this can be re-attempted and will succeed later.
+ static const tempFail = ExitCode._(75, 'tempFail');
+
+ /// You did not have sufficient permissions to perform the operation.
+ ///
+ /// This is not intended for file system problems, which should use [noInput]
+ /// or [cantCreate], but rather for higher-level permissions.
+ static const noPerm = ExitCode._(77, 'noPerm');
+
+ /// Something was found in an unconfigured or misconfigured state.
+ static const config = ExitCode._(78, 'config');
+
+ /// Exit code value.
+ final int code;
+
+ /// Name of the exit code.
+ final String _name;
+
+ const ExitCode._(this.code, this._name);
+
+ @override
+ String toString() => '$_name: $code';
+}
diff --git a/pkgs/io/lib/src/permissions.dart b/pkgs/io/lib/src/permissions.dart
new file mode 100644
index 0000000..c516943
--- /dev/null
+++ b/pkgs/io/lib/src/permissions.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+/// What type of permission is granted to a file based on file permission roles.
+enum _FilePermission {
+ execute,
+ // Although these two values are unused, their positions in the enum are
+ // meaningful.
+ write, // ignore: unused_field
+ read, // ignore: unused_field
+ setGid,
+ setUid,
+ sticky,
+}
+
+/// What type of role is assigned to a file.
+enum _FilePermissionRole {
+ world,
+ group,
+ user,
+}
+
+/// Returns whether file [stat] has [permission] for a [role] type.
+bool _hasPermission(
+ FileStat stat,
+ _FilePermission permission, {
+ _FilePermissionRole role = _FilePermissionRole.world,
+}) {
+ final index = _permissionBitIndex(permission, role);
+ return (stat.mode & (1 << index)) != 0;
+}
+
+int _permissionBitIndex(_FilePermission permission, _FilePermissionRole role) =>
+ switch (permission) {
+ _FilePermission.setUid => 11,
+ _FilePermission.setGid => 10,
+ _FilePermission.sticky => 9,
+ _ => (role.index * 3) + permission.index
+ };
+
+/// Returns whether [path] is considered an executable file on this OS.
+///
+/// May optionally define how to implement [getStat] or whether to execute based
+/// on whether this is the windows platform ([isWindows]) - if not set it is
+/// automatically extracted from `dart:io#Platform`.
+///
+/// **NOTE**: On windows this always returns `true`.
+FutureOr<bool> isExecutable(
+ String path, {
+ bool? isWindows,
+ FutureOr<FileStat> Function(String path) getStat = FileStat.stat,
+}) {
+ // Windows has no concept of executable.
+ if (isWindows ?? Platform.isWindows) return true;
+ final stat = getStat(path);
+ if (stat is FileStat) {
+ return _isExecutable(stat);
+ }
+ return stat.then(_isExecutable);
+}
+
+bool _isExecutable(FileStat stat) =>
+ stat.type == FileSystemEntityType.file &&
+ _FilePermissionRole.values.any(
+ (role) => _hasPermission(stat, _FilePermission.execute, role: role));
diff --git a/pkgs/io/lib/src/process_manager.dart b/pkgs/io/lib/src/process_manager.dart
new file mode 100644
index 0000000..84d22ec
--- /dev/null
+++ b/pkgs/io/lib/src/process_manager.dart
@@ -0,0 +1,255 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: close_sinks,cancel_subscriptions
+
+import 'dart:async';
+import 'dart:io' as io;
+
+import 'package:meta/meta.dart';
+
+import 'shared_stdin.dart';
+
+/// Type definition for both [io.Process.start] and [ProcessManager.spawn].
+///
+/// Useful for taking different implementations of this base functionality.
+typedef StartProcess = Future<io.Process> Function(
+ String executable,
+ List<String> arguments, {
+ String workingDirectory,
+ Map<String, String> environment,
+ bool includeParentEnvironment,
+ bool runInShell,
+ io.ProcessStartMode mode,
+});
+
+/// A high-level abstraction around using and managing processes on the system.
+abstract class ProcessManager {
+ /// Terminates the global `stdin` listener, making future listens impossible.
+ ///
+ /// This method should be invoked only at the _end_ of a program's execution.
+ static Future<void> terminateStdIn() async {
+ await sharedStdIn.terminate();
+ }
+
+ /// Create a new instance of [ProcessManager] for the current platform.
+ ///
+ /// May manually specify whether the current platform [isWindows], otherwise
+ /// this is derived from the Dart runtime (i.e. [io.Platform.isWindows]).
+ factory ProcessManager({
+ Stream<List<int>>? stdin,
+ io.IOSink? stdout,
+ io.IOSink? stderr,
+ bool? isWindows,
+ }) {
+ stdin ??= sharedStdIn;
+ stdout ??= io.stdout;
+ stderr ??= io.stderr;
+ isWindows ??= io.Platform.isWindows;
+ if (isWindows) {
+ return _WindowsProcessManager(stdin, stdout, stderr);
+ }
+ return _UnixProcessManager(stdin, stdout, stderr);
+ }
+
+ final Stream<List<int>> _stdin;
+ final io.IOSink _stdout;
+ final io.IOSink _stderr;
+
+ const ProcessManager._(this._stdin, this._stdout, this._stderr);
+
+ /// Spawns a process by invoking [executable] with [arguments].
+ ///
+ /// This is _similar_ to [io.Process.start], but all standard input and output
+ /// is forwarded/routed between the process and the host, similar to how a
+ /// shell script works.
+ ///
+ /// Returns a future that completes with a handle to the spawned process.
+ Future<io.Process> spawn(
+ String executable,
+ Iterable<String> arguments, {
+ String? workingDirectory,
+ Map<String, String>? environment,
+ bool includeParentEnvironment = true,
+ bool runInShell = false,
+ io.ProcessStartMode mode = io.ProcessStartMode.normal,
+ }) async {
+ final process = io.Process.start(
+ executable,
+ arguments.toList(),
+ workingDirectory: workingDirectory,
+ environment: environment,
+ includeParentEnvironment: includeParentEnvironment,
+ runInShell: runInShell,
+ mode: mode,
+ );
+ return _ForwardingSpawn(await process, _stdin, _stdout, _stderr);
+ }
+
+ /// Spawns a process by invoking [executable] with [arguments].
+ ///
+ /// This is _similar_ to [io.Process.start], but `stdout` and `stderr` is
+ /// forwarded/routed between the process and host, similar to how a shell
+ /// script works.
+ ///
+ /// Returns a future that completes with a handle to the spawned process.
+ Future<io.Process> spawnBackground(
+ String executable,
+ Iterable<String> arguments, {
+ String? workingDirectory,
+ Map<String, String>? environment,
+ bool includeParentEnvironment = true,
+ bool runInShell = false,
+ io.ProcessStartMode mode = io.ProcessStartMode.normal,
+ }) async {
+ final process = io.Process.start(
+ executable,
+ arguments.toList(),
+ workingDirectory: workingDirectory,
+ environment: environment,
+ includeParentEnvironment: includeParentEnvironment,
+ runInShell: runInShell,
+ mode: mode,
+ );
+ return _ForwardingSpawn(
+ await process,
+ const Stream.empty(),
+ _stdout,
+ _stderr,
+ );
+ }
+
+ /// Spawns a process by invoking [executable] with [arguments].
+ ///
+ /// This is _identical to [io.Process.start] (no forwarding of I/O).
+ ///
+ /// Returns a future that completes with a handle to the spawned process.
+ Future<io.Process> spawnDetached(
+ String executable,
+ Iterable<String> arguments, {
+ String? workingDirectory,
+ Map<String, String>? environment,
+ bool includeParentEnvironment = true,
+ bool runInShell = false,
+ io.ProcessStartMode mode = io.ProcessStartMode.normal,
+ }) async =>
+ io.Process.start(
+ executable,
+ arguments.toList(),
+ workingDirectory: workingDirectory,
+ environment: environment,
+ includeParentEnvironment: includeParentEnvironment,
+ runInShell: runInShell,
+ mode: mode,
+ );
+}
+
+/// A process instance created and managed through [ProcessManager].
+///
+/// Unlike one created directly by [io.Process.start] or [io.Process.run], a
+/// spawned process works more like executing a command in a shell script.
+class Spawn implements io.Process {
+ final io.Process _delegate;
+
+ Spawn._(this._delegate) {
+ _delegate.exitCode.then((_) => _onClosed());
+ }
+
+ @mustCallSuper
+ void _onClosed() {}
+
+ @override
+ bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) =>
+ _delegate.kill(signal);
+
+ @override
+ Future<int> get exitCode => _delegate.exitCode;
+
+ @override
+ int get pid => _delegate.pid;
+
+ @override
+ Stream<List<int>> get stderr => _delegate.stderr;
+
+ @override
+ io.IOSink get stdin => _delegate.stdin;
+
+ @override
+ Stream<List<int>> get stdout => _delegate.stdout;
+}
+
+/// Forwards `stdin`/`stdout`/`stderr` to/from the host.
+class _ForwardingSpawn extends Spawn {
+ final StreamSubscription<List<int>> _stdInSub;
+ final StreamSubscription<List<int>> _stdOutSub;
+ final StreamSubscription<List<int>> _stdErrSub;
+ final StreamController<List<int>> _stdOut;
+ final StreamController<List<int>> _stdErr;
+
+ factory _ForwardingSpawn(
+ io.Process delegate,
+ Stream<List<int>> stdin,
+ io.IOSink stdout,
+ io.IOSink stderr,
+ ) {
+ final stdoutSelf = StreamController<List<int>>();
+ final stderrSelf = StreamController<List<int>>();
+ final stdInSub = stdin.listen(delegate.stdin.add);
+ final stdOutSub = delegate.stdout.listen((event) {
+ stdout.add(event);
+ stdoutSelf.add(event);
+ });
+ final stdErrSub = delegate.stderr.listen((event) {
+ stderr.add(event);
+ stderrSelf.add(event);
+ });
+ return _ForwardingSpawn._delegate(
+ delegate,
+ stdInSub,
+ stdOutSub,
+ stdErrSub,
+ stdoutSelf,
+ stderrSelf,
+ );
+ }
+
+ _ForwardingSpawn._delegate(
+ super.delegate,
+ this._stdInSub,
+ this._stdOutSub,
+ this._stdErrSub,
+ this._stdOut,
+ this._stdErr,
+ ) : super._();
+
+ @override
+ void _onClosed() {
+ _stdInSub.cancel();
+ _stdOutSub.cancel();
+ _stdErrSub.cancel();
+ super._onClosed();
+ }
+
+ @override
+ Stream<List<int>> get stdout => _stdOut.stream;
+
+ @override
+ Stream<List<int>> get stderr => _stdErr.stream;
+}
+
+class _UnixProcessManager extends ProcessManager {
+ const _UnixProcessManager(
+ super.stdin,
+ super.stdout,
+ super.stderr,
+ ) : super._();
+}
+
+class _WindowsProcessManager extends ProcessManager {
+ const _WindowsProcessManager(
+ super.stdin,
+ super.stdout,
+ super.stderr,
+ ) : super._();
+}
diff --git a/pkgs/io/lib/src/shared_stdin.dart b/pkgs/io/lib/src/shared_stdin.dart
new file mode 100644
index 0000000..72bb50c
--- /dev/null
+++ b/pkgs/io/lib/src/shared_stdin.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:meta/meta.dart';
+
+/// A shared singleton instance of `dart:io`'s [stdin] stream.
+///
+/// _Unlike_ the normal [stdin] stream, [sharedStdIn] may switch subscribers
+/// as long as the previous subscriber cancels before the new subscriber starts
+/// listening.
+///
+/// [SharedStdIn.terminate] *must* be invoked in order to close the underlying
+/// connection to [stdin], allowing your program to close automatically without
+/// hanging.
+final SharedStdIn sharedStdIn = SharedStdIn(stdin);
+
+/// A singleton wrapper around `stdin` that allows new subscribers.
+///
+/// This class is visible in order to be used as a test harness for mock
+/// implementations of `stdin`. In normal programs, [sharedStdIn] should be
+/// used directly.
+@visibleForTesting
+class SharedStdIn extends Stream<List<int>> {
+ StreamController<List<int>>? _current;
+ StreamSubscription<List<int>>? _sub;
+
+ SharedStdIn([Stream<List<int>>? stream]) {
+ _sub = (stream ??= stdin).listen(_onInput);
+ }
+
+ /// Returns a future that completes with the next line.
+ ///
+ /// This is similar to the standard [Stdin.readLineSync], but asynchronous.
+ Future<String> nextLine({Encoding encoding = systemEncoding}) =>
+ lines(encoding: encoding).first;
+
+ /// Returns the stream transformed as UTF8 strings separated by line breaks.
+ ///
+ /// This is similar to synchronous code using [Stdin.readLineSync]:
+ /// ```dart
+ /// while (true) {
+ /// var line = stdin.readLineSync();
+ /// // ...
+ /// }
+ /// ```
+ ///
+ /// ... but asynchronous.
+ Stream<String> lines({Encoding encoding = systemEncoding}) =>
+ transform(utf8.decoder).transform(const LineSplitter());
+
+ void _onInput(List<int> event) => _getCurrent().add(event);
+
+ StreamController<List<int>> _getCurrent() =>
+ _current ??= StreamController<List<int>>(
+ onCancel: () {
+ _current = null;
+ },
+ sync: true);
+
+ @override
+ StreamSubscription<List<int>> listen(
+ void Function(List<int> event)? onData, {
+ Function? onError,
+ void Function()? onDone,
+ bool? cancelOnError,
+ }) {
+ if (_sub == null) {
+ throw StateError('Stdin has already been terminated.');
+ }
+ // ignore: close_sinks
+ final controller = _getCurrent();
+ if (controller.hasListener) {
+ throw StateError(''
+ 'Subscriber already listening. The existing subscriber must cancel '
+ 'before another may be added.');
+ }
+ return controller.stream.listen(
+ onData,
+ onDone: onDone,
+ onError: onError,
+ cancelOnError: cancelOnError,
+ );
+ }
+
+ /// Terminates the connection to `stdin`, closing all subscription.
+ Future<void> terminate() async {
+ if (_sub == null) {
+ throw StateError('Stdin has already been terminated.');
+ }
+ await _sub?.cancel();
+ await _current?.close();
+ _sub = null;
+ }
+}
diff --git a/pkgs/io/lib/src/shell_words.dart b/pkgs/io/lib/src/shell_words.dart
new file mode 100644
index 0000000..5fca6d9
--- /dev/null
+++ b/pkgs/io/lib/src/shell_words.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: comment_references
+
+import 'package:string_scanner/string_scanner.dart';
+
+import 'charcodes.dart';
+
+/// Splits [command] into tokens according to [the POSIX shell
+/// specification][spec].
+///
+/// [spec]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html
+///
+/// This returns the unquoted values of quoted tokens. For example,
+/// `shellSplit('foo "bar baz"')` returns `["foo", "bar baz"]`. It does not
+/// currently support here-documents. It does *not* treat dynamic features such
+/// as parameter expansion specially. For example, `shellSplit("foo $(bar
+/// baz)")` returns `["foo", "$(bar", "baz)"]`.
+///
+/// This will discard any comments at the end of [command].
+///
+/// Throws a [FormatException] if [command] isn't a valid shell command.
+List<String> shellSplit(String command) {
+ final scanner = StringScanner(command);
+ final results = <String>[];
+ final token = StringBuffer();
+
+ // Whether a token is being parsed, as opposed to a separator character. This
+ // is different than just [token.isEmpty], because empty quoted tokens can
+ // exist.
+ var hasToken = false;
+
+ while (!scanner.isDone) {
+ final next = scanner.readChar();
+ switch (next) {
+ case $backslash:
+ // Section 2.2.1: A <backslash> that is not quoted shall preserve the
+ // literal value of the following character, with the exception of a
+ // <newline>. If a <newline> follows the <backslash>, the shell shall
+ // interpret this as line continuation. The <backslash> and <newline>
+ // shall be removed before splitting the input into tokens. Since the
+ // escaped <newline> is removed entirely from the input and is not
+ // replaced by any white space, it cannot serve as a token separator.
+ if (scanner.scanChar($lf)) break;
+
+ hasToken = true;
+ token.writeCharCode(scanner.readChar());
+
+ case $singleQuote:
+ hasToken = true;
+ // Section 2.2.2: Enclosing characters in single-quotes ( '' ) shall
+ // preserve the literal value of each character within the
+ // single-quotes. A single-quote cannot occur within single-quotes.
+ final firstQuote = scanner.position - 1;
+ while (!scanner.scanChar($singleQuote)) {
+ _checkUnmatchedQuote(scanner, firstQuote);
+ token.writeCharCode(scanner.readChar());
+ }
+
+ case $doubleQuote:
+ hasToken = true;
+ // Section 2.2.3: Enclosing characters in double-quotes ( "" ) shall
+ // preserve the literal value of all characters within the
+ // double-quotes, with the exception of the characters backquote,
+ // <dollar-sign>, and <backslash>.
+ //
+ // (Note that this code doesn't preserve special behavior of backquote
+ // or dollar sign within double quotes, since those are dynamic
+ // features.)
+ final firstQuote = scanner.position - 1;
+ while (!scanner.scanChar($doubleQuote)) {
+ _checkUnmatchedQuote(scanner, firstQuote);
+
+ if (scanner.scanChar($backslash)) {
+ _checkUnmatchedQuote(scanner, firstQuote);
+
+ // The <backslash> shall retain its special meaning as an escape
+ // character (see Escape Character (Backslash)) only when followed
+ // by one of the following characters when considered special:
+ //
+ // $ ` " \ <newline>
+ final next = scanner.readChar();
+ if (next == $lf) continue;
+ if (next == $dollar ||
+ next == $backquote ||
+ next == $doubleQuote ||
+ next == $backslash) {
+ token.writeCharCode(next);
+ } else {
+ token
+ ..writeCharCode($backslash)
+ ..writeCharCode(next);
+ }
+ } else {
+ token.writeCharCode(scanner.readChar());
+ }
+ }
+
+ case $hash:
+ // Section 2.3: If the current character is a '#' [and the previous
+ // characters was not part of a word], it and all subsequent characters
+ // up to, but excluding, the next <newline> shall be discarded as a
+ // comment. The <newline> that ends the line is not considered part of
+ // the comment.
+ if (hasToken) {
+ token.writeCharCode($hash);
+ break;
+ }
+
+ while (!scanner.isDone && scanner.peekChar() != $lf) {
+ scanner.readChar();
+ }
+
+ case $space:
+ case $tab:
+ case $lf:
+ // ignore: invariant_booleans
+ if (hasToken) results.add(token.toString());
+ hasToken = false;
+ token.clear();
+
+ default:
+ hasToken = true;
+ token.writeCharCode(next);
+ }
+ }
+
+ if (hasToken) results.add(token.toString());
+ return results;
+}
+
+/// Throws a [FormatException] if [scanner] is done indicating that a closing
+/// quote matching the one at position [openingQuote] is missing.
+void _checkUnmatchedQuote(StringScanner scanner, int openingQuote) {
+ if (!scanner.isDone) return;
+ final type = scanner.substring(openingQuote, openingQuote + 1) == '"'
+ ? 'double'
+ : 'single';
+ scanner.error('Unmatched $type quote.', position: openingQuote, length: 1);
+}
diff --git a/pkgs/io/pubspec.yaml b/pkgs/io/pubspec.yaml
new file mode 100644
index 0000000..7e00d99
--- /dev/null
+++ b/pkgs/io/pubspec.yaml
@@ -0,0 +1,19 @@
+name: io
+description: >-
+ Utilities for the Dart VM Runtime including support for ANSI colors, file
+ copying, and standard exit code values.
+version: 1.0.5
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/io
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ meta: ^1.3.0
+ path: ^1.8.0
+ string_scanner: ^1.1.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.6
+ test_descriptor: ^2.0.0
diff --git a/pkgs/io/test/_files/is_executable.sh b/pkgs/io/test/_files/is_executable.sh
new file mode 100755
index 0000000..f1f641a
--- /dev/null
+++ b/pkgs/io/test/_files/is_executable.sh
@@ -0,0 +1 @@
+#!/usr/bin/env bash
diff --git a/pkgs/io/test/_files/is_not_executable.sh b/pkgs/io/test/_files/is_not_executable.sh
new file mode 100644
index 0000000..f1f641a
--- /dev/null
+++ b/pkgs/io/test/_files/is_not_executable.sh
@@ -0,0 +1 @@
+#!/usr/bin/env bash
diff --git a/pkgs/io/test/_files/stderr_hello.dart b/pkgs/io/test/_files/stderr_hello.dart
new file mode 100644
index 0000000..ac7a7d3
--- /dev/null
+++ b/pkgs/io/test/_files/stderr_hello.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+void main() => stderr.write('Hello');
diff --git a/pkgs/io/test/_files/stdin_echo.dart b/pkgs/io/test/_files/stdin_echo.dart
new file mode 100644
index 0000000..256e0ee
--- /dev/null
+++ b/pkgs/io/test/_files/stdin_echo.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+void main() => stdout.writeln('You said: ${stdin.readLineSync()}');
diff --git a/pkgs/io/test/_files/stdout_hello.dart b/pkgs/io/test/_files/stdout_hello.dart
new file mode 100644
index 0000000..af3bf51
--- /dev/null
+++ b/pkgs/io/test/_files/stdout_hello.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+void main() => stdout.write('Hello');
diff --git a/pkgs/io/test/ansi_code_test.dart b/pkgs/io/test/ansi_code_test.dart
new file mode 100644
index 0000000..98ae68b
--- /dev/null
+++ b/pkgs/io/test/ansi_code_test.dart
@@ -0,0 +1,187 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'dart:io';
+
+import 'package:io/ansi.dart';
+import 'package:test/test.dart';
+
+const _ansiEscapeLiteral = '\x1B';
+const _ansiEscapeForScript = r'\033';
+const sampleInput = 'sample input';
+
+void main() {
+ group('ansiOutputEnabled', () {
+ test('default value matches dart:io', () {
+ expect(ansiOutputEnabled,
+ stdout.supportsAnsiEscapes && stderr.supportsAnsiEscapes);
+ });
+
+ test('override true', () {
+ overrideAnsiOutput(true, () {
+ expect(ansiOutputEnabled, isTrue);
+ });
+ });
+
+ test('override false', () {
+ overrideAnsiOutput(false, () {
+ expect(ansiOutputEnabled, isFalse);
+ });
+ });
+
+ test('forScript variaents ignore `ansiOutputEnabled`', () {
+ const expected =
+ '$_ansiEscapeForScript[34m$sampleInput$_ansiEscapeForScript[0m';
+
+ for (var override in [true, false]) {
+ overrideAnsiOutput(override, () {
+ expect(blue.escapeForScript, '$_ansiEscapeForScript[34m');
+ expect(blue.wrap(sampleInput, forScript: true), expected);
+ expect(wrapWith(sampleInput, [blue], forScript: true), expected);
+ });
+ }
+ });
+ });
+
+ test('foreground and background colors match', () {
+ expect(foregroundColors, hasLength(backgroundColors.length));
+
+ for (var i = 0; i < foregroundColors.length; i++) {
+ final foreground = foregroundColors[i];
+ expect(foreground.type, AnsiCodeType.foreground);
+ expect(foreground.name.toLowerCase(), foreground.name,
+ reason: 'All names should be lower case');
+ final background = backgroundColors[i];
+ expect(background.type, AnsiCodeType.background);
+ expect(background.name.toLowerCase(), background.name,
+ reason: 'All names should be lower case');
+
+ expect(foreground.name, background.name);
+
+ // The last base-10 digit also matches – good to sanity check
+ expect(foreground.code % 10, background.code % 10);
+ }
+ });
+
+ test('all styles are styles', () {
+ for (var style in styles) {
+ expect(style.type, AnsiCodeType.style);
+ expect(style.name.toLowerCase(), style.name,
+ reason: 'All names should be lower case');
+ if (style == styleBold) {
+ expect(style.reset, resetBold);
+ } else {
+ expect(style.reset!.code, equals(style.code + 20));
+ }
+ expect(style.name, equals(style.reset!.name));
+ }
+ });
+
+ for (var forScript in [true, false]) {
+ group(forScript ? 'forScript' : 'escaped', () {
+ final escapeLiteral =
+ forScript ? _ansiEscapeForScript : _ansiEscapeLiteral;
+
+ group('wrap', () {
+ _test('color', () {
+ final expected = '$escapeLiteral[34m$sampleInput$escapeLiteral[0m';
+
+ expect(blue.wrap(sampleInput, forScript: forScript), expected);
+ });
+
+ _test('style', () {
+ final expected = '$escapeLiteral[1m$sampleInput$escapeLiteral[22m';
+
+ expect(styleBold.wrap(sampleInput, forScript: forScript), expected);
+ });
+
+ _test('style', () {
+ final expected = '$escapeLiteral[34m$sampleInput$escapeLiteral[0m';
+
+ expect(blue.wrap(sampleInput, forScript: forScript), expected);
+ });
+
+ test('empty', () {
+ expect(blue.wrap('', forScript: forScript), '');
+ });
+
+ test(null, () {
+ expect(blue.wrap(null, forScript: forScript), isNull);
+ });
+ });
+
+ group('wrapWith', () {
+ _test('foreground', () {
+ final expected = '$escapeLiteral[34m$sampleInput$escapeLiteral[0m';
+
+ expect(wrapWith(sampleInput, [blue], forScript: forScript), expected);
+ });
+
+ _test('background', () {
+ final expected = '$escapeLiteral[44m$sampleInput$escapeLiteral[0m';
+
+ expect(wrapWith(sampleInput, [backgroundBlue], forScript: forScript),
+ expected);
+ });
+
+ _test('style', () {
+ final expected = '$escapeLiteral[1m$sampleInput$escapeLiteral[0m';
+
+ expect(wrapWith(sampleInput, [styleBold], forScript: forScript),
+ expected);
+ });
+
+ _test('2 styles', () {
+ final expected = '$escapeLiteral[1;3m$sampleInput$escapeLiteral[0m';
+
+ expect(
+ wrapWith(sampleInput, [styleBold, styleItalic],
+ forScript: forScript),
+ expected);
+ });
+
+ _test('2 foregrounds', () {
+ expect(
+ () => wrapWith(sampleInput, [blue, white], forScript: forScript),
+ throwsArgumentError);
+ });
+
+ _test('multi', () {
+ final expected =
+ '$escapeLiteral[1;4;34;107m$sampleInput$escapeLiteral[0m';
+
+ expect(
+ wrapWith(sampleInput,
+ [blue, backgroundWhite, styleBold, styleUnderlined],
+ forScript: forScript),
+ expected);
+ });
+
+ test('no codes', () {
+ expect(wrapWith(sampleInput, []), sampleInput);
+ });
+
+ _test('empty', () {
+ expect(
+ wrapWith('', [blue, backgroundWhite, styleBold],
+ forScript: forScript),
+ '');
+ });
+
+ _test('null', () {
+ expect(
+ wrapWith(null, [blue, backgroundWhite, styleBold],
+ forScript: forScript),
+ isNull);
+ });
+ });
+ });
+ }
+}
+
+void _test<T>(String name, T Function() body) =>
+ test(name, () => overrideAnsiOutput<T>(true, body));
diff --git a/pkgs/io/test/copy_path_test.dart b/pkgs/io/test/copy_path_test.dart
new file mode 100644
index 0000000..fd1e9ce
--- /dev/null
+++ b/pkgs/io/test/copy_path_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'package:io/io.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test_descriptor/test_descriptor.dart' as d;
+
+void main() {
+ test('should copy a directory (async)', () async {
+ await _create();
+ await copyPath(p.join(d.sandbox, 'parent'), p.join(d.sandbox, 'copy'));
+ await _validate();
+ });
+
+ test('should copy a directory (sync)', () async {
+ await _create();
+ copyPathSync(p.join(d.sandbox, 'parent'), p.join(d.sandbox, 'copy'));
+ await _validate();
+ });
+
+ test('should catch an infinite operation', () async {
+ await _create();
+ expect(
+ copyPath(
+ p.join(d.sandbox, 'parent'),
+ p.join(d.sandbox, 'parent', 'child'),
+ ),
+ throwsArgumentError,
+ );
+ });
+}
+
+d.DirectoryDescriptor _struct() => d.dir('parent', [
+ d.dir('child', [
+ d.file('foo.txt'),
+ ]),
+ ]);
+
+Future<void> _create() => _struct().create();
+Future<void> _validate() => _struct().validate();
diff --git a/pkgs/io/test/permissions_test.dart b/pkgs/io/test/permissions_test.dart
new file mode 100644
index 0000000..478e8df
--- /dev/null
+++ b/pkgs/io/test/permissions_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'package:io/io.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('isExecutable', () {
+ const files = 'test/_files';
+ const shellIsExec = '$files/is_executable.sh';
+ const shellNotExec = '$files/is_not_executable.sh';
+
+ group('on shell scripts', () {
+ test('should return true for "is_executable.sh"', () async {
+ expect(await isExecutable(shellIsExec), isTrue);
+ });
+
+ test('should return false for "is_not_executable.sh"', () async {
+ expect(await isExecutable(shellNotExec), isFalse);
+ });
+ }, testOn: '!windows');
+
+ group('on shell scripts [windows]', () {
+ test('should return true for "is_executable.sh"', () async {
+ expect(await isExecutable(shellIsExec, isWindows: true), isTrue);
+ });
+
+ test('should return true for "is_not_executable.sh"', () async {
+ expect(await isExecutable(shellNotExec, isWindows: true), isTrue);
+ });
+ });
+ });
+}
diff --git a/pkgs/io/test/process_manager_test.dart b/pkgs/io/test/process_manager_test.dart
new file mode 100644
index 0000000..9871a77
--- /dev/null
+++ b/pkgs/io/test/process_manager_test.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: close_sinks
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:io/io.dart' hide sharedStdIn;
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+
+void main() {
+ StreamController<String> fakeStdIn;
+ late ProcessManager processManager;
+ SharedStdIn sharedStdIn;
+ late List<String> stdoutLog;
+ late List<String> stderrLog;
+
+ test('spawn functions should match the type definition of Process.start', () {
+ const isStartProcess = TypeMatcher<StartProcess>();
+ expect(Process.start, isStartProcess);
+ final manager = ProcessManager();
+ expect(manager.spawn, isStartProcess);
+ expect(manager.spawnBackground, isStartProcess);
+ expect(manager.spawnDetached, isStartProcess);
+ });
+
+ group('spawn', () {
+ setUp(() async {
+ fakeStdIn = StreamController<String>(sync: true);
+ sharedStdIn = SharedStdIn(fakeStdIn.stream.map((s) => s.codeUnits));
+ stdoutLog = <String>[];
+ stderrLog = <String>[];
+
+ final stdoutController = StreamController<List<int>>(sync: true);
+ stdoutController.stream.map(utf8.decode).listen(stdoutLog.add);
+ final stdout = IOSink(stdoutController);
+ final stderrController = StreamController<List<int>>(sync: true);
+ stderrController.stream.map(utf8.decode).listen(stderrLog.add);
+ final stderr = IOSink(stderrController);
+
+ processManager = ProcessManager(
+ stdin: sharedStdIn,
+ stdout: stdout,
+ stderr: stderr,
+ );
+ });
+
+ final dart = Platform.executable;
+
+ test('should output Hello from another process [via stdout]', () async {
+ final spawn = await processManager.spawn(
+ dart,
+ [p.join('test', '_files', 'stdout_hello.dart')],
+ );
+ await spawn.exitCode;
+ expect(stdoutLog, ['Hello']);
+ });
+
+ test('should output Hello from another process [via stderr]', () async {
+ final spawn = await processManager.spawn(
+ dart,
+ [p.join('test', '_files', 'stderr_hello.dart')],
+ );
+ await spawn.exitCode;
+ expect(stderrLog, ['Hello']);
+ });
+
+ test('should forward stdin to another process', () async {
+ final spawn = await processManager.spawn(
+ dart,
+ [p.join('test', '_files', 'stdin_echo.dart')],
+ );
+ spawn.stdin.writeln('Ping');
+ await spawn.exitCode;
+ expect(stdoutLog.join(), contains('You said: Ping'));
+ });
+
+ group('should return a Process where', () {
+ test('.stdout is readable', () async {
+ final spawn = await processManager.spawn(
+ dart,
+ [p.join('test', '_files', 'stdout_hello.dart')],
+ );
+ expect(await spawn.stdout.transform(utf8.decoder).first, 'Hello');
+ });
+
+ test('.stderr is readable', () async {
+ final spawn = await processManager.spawn(
+ dart,
+ [p.join('test', '_files', 'stderr_hello.dart')],
+ );
+ expect(await spawn.stderr.transform(utf8.decoder).first, 'Hello');
+ });
+ });
+ });
+}
diff --git a/pkgs/io/test/shared_stdin_test.dart b/pkgs/io/test/shared_stdin_test.dart
new file mode 100644
index 0000000..71629ec
--- /dev/null
+++ b/pkgs/io/test/shared_stdin_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:io/io.dart' hide sharedStdIn;
+import 'package:test/test.dart';
+
+void main() {
+ // ignore: close_sinks
+ late StreamController<String> fakeStdIn;
+ late SharedStdIn sharedStdIn;
+
+ setUp(() {
+ fakeStdIn = StreamController<String>(sync: true);
+ sharedStdIn = SharedStdIn(fakeStdIn.stream.map((s) => s.codeUnits));
+ });
+
+ test('should allow a single subscriber', () async {
+ final logs = <String>[];
+ final sub = sharedStdIn.transform(utf8.decoder).listen(logs.add);
+ fakeStdIn.add('Hello World');
+ await sub.cancel();
+ expect(logs, ['Hello World']);
+ });
+
+ test('should allow multiple subscribers', () async {
+ final logs = <String>[];
+ final asUtf8 = sharedStdIn.transform(utf8.decoder);
+ var sub = asUtf8.listen(logs.add);
+ fakeStdIn.add('Hello World');
+ await sub.cancel();
+ sub = asUtf8.listen(logs.add);
+ fakeStdIn.add('Goodbye World');
+ await sub.cancel();
+ expect(logs, ['Hello World', 'Goodbye World']);
+ });
+
+ test('should throw if a subscriber is still active', () async {
+ final active = sharedStdIn.listen((_) {});
+ expect(() => sharedStdIn.listen((_) {}), throwsStateError);
+ await active.cancel();
+ expect(() => sharedStdIn.listen((_) {}), returnsNormally);
+ });
+
+ test('should return a stream of lines', () async {
+ expect(
+ sharedStdIn.lines(),
+ emitsInOrder(<dynamic>[
+ 'I',
+ 'Think',
+ 'Therefore',
+ 'I',
+ 'Am',
+ ]),
+ );
+ [
+ 'I\nThink\n',
+ 'Therefore\n',
+ 'I\n',
+ 'Am\n',
+ ].forEach(fakeStdIn.add);
+ });
+
+ test('should return the next line', () {
+ expect(sharedStdIn.nextLine(), completion('Hello World'));
+ fakeStdIn.add('Hello World\n');
+ });
+
+ test('should allow listening for new lines multiple times', () async {
+ expect(sharedStdIn.nextLine(), completion('Hello World'));
+ fakeStdIn.add('Hello World\n');
+ await Future<void>.value();
+
+ expect(sharedStdIn.nextLine(), completion('Hello World'));
+ fakeStdIn.add('Hello World\n');
+ });
+}
diff --git a/pkgs/io/test/shell_words_test.dart b/pkgs/io/test/shell_words_test.dart
new file mode 100644
index 0000000..dc4441c
--- /dev/null
+++ b/pkgs/io/test/shell_words_test.dart
@@ -0,0 +1,185 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:io/io.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('shellSplit()', () {
+ group('returns an empty list for', () {
+ test('an empty string', () {
+ expect(shellSplit(''), isEmpty);
+ });
+
+ test('spaces', () {
+ expect(shellSplit(' '), isEmpty);
+ });
+
+ test('tabs', () {
+ expect(shellSplit('\t\t\t'), isEmpty);
+ });
+
+ test('newlines', () {
+ expect(shellSplit('\n\n\n'), isEmpty);
+ });
+
+ test('a comment', () {
+ expect(shellSplit('#foo bar baz'), isEmpty);
+ });
+
+ test('a mix', () {
+ expect(shellSplit(' \t\n# foo'), isEmpty);
+ });
+ });
+
+ group('parses unquoted', () {
+ test('a single token', () {
+ expect(shellSplit('foo'), equals(['foo']));
+ });
+
+ test('multiple tokens', () {
+ expect(shellSplit('foo bar baz'), equals(['foo', 'bar', 'baz']));
+ });
+
+ test('tokens separated by tabs', () {
+ expect(shellSplit('foo\tbar\tbaz'), equals(['foo', 'bar', 'baz']));
+ });
+
+ test('tokens separated by newlines', () {
+ expect(shellSplit('foo\nbar\nbaz'), equals(['foo', 'bar', 'baz']));
+ });
+
+ test('a token after whitespace', () {
+ expect(shellSplit(' \t\nfoo'), equals(['foo']));
+ });
+
+ test('a token before whitespace', () {
+ expect(shellSplit('foo \t\n'), equals(['foo']));
+ });
+
+ test('a token with a hash', () {
+ expect(shellSplit('foo#bar'), equals(['foo#bar']));
+ });
+
+ test('a token before a comment', () {
+ expect(shellSplit('foo #bar'), equals(['foo']));
+ });
+
+ test('dynamic shell features', () {
+ expect(
+ shellSplit(r'foo $(bar baz)'), equals(['foo', r'$(bar', 'baz)']));
+ expect(shellSplit('foo `bar baz`'), equals(['foo', '`bar', 'baz`']));
+ expect(shellSplit(r'foo $bar | baz'),
+ equals(['foo', r'$bar', '|', 'baz']));
+ });
+ });
+
+ group('parses a backslash', () {
+ test('before a normal character', () {
+ expect(shellSplit(r'foo\bar'), equals(['foobar']));
+ });
+
+ test('before a dynamic shell feature', () {
+ expect(shellSplit(r'foo\$bar'), equals([r'foo$bar']));
+ });
+
+ test('before a single quote', () {
+ expect(shellSplit(r"foo\'bar"), equals(["foo'bar"]));
+ });
+
+ test('before a double quote', () {
+ expect(shellSplit(r'foo\"bar'), equals(['foo"bar']));
+ });
+
+ test('before a space', () {
+ expect(shellSplit(r'foo\ bar'), equals(['foo bar']));
+ });
+
+ test('at the beginning of a token', () {
+ expect(shellSplit(r'\ foo'), equals([' foo']));
+ });
+
+ test('before whitespace followed by a hash', () {
+ expect(shellSplit(r'\ #foo'), equals([' #foo']));
+ });
+
+ test('before a newline in a token', () {
+ expect(shellSplit('foo\\\nbar'), equals(['foobar']));
+ });
+
+ test('before a newline outside a token', () {
+ expect(shellSplit('foo \\\n bar'), equals(['foo', 'bar']));
+ });
+
+ test('before a backslash', () {
+ expect(shellSplit(r'foo\\bar'), equals([r'foo\bar']));
+ });
+ });
+
+ group('parses single quotes', () {
+ test('that are empty', () {
+ expect(shellSplit("''"), equals(['']));
+ });
+
+ test('that contain normal characters', () {
+ expect(shellSplit("'foo'"), equals(['foo']));
+ });
+
+ test('that contain active characters', () {
+ expect(shellSplit("'\" \\#'"), equals([r'" \#']));
+ });
+
+ test('before a hash', () {
+ expect(shellSplit("''#foo"), equals([r'#foo']));
+ });
+
+ test('inside a token', () {
+ expect(shellSplit("foo'bar baz'qux"), equals([r'foobar bazqux']));
+ });
+
+ test('without a closing quote', () {
+ expect(() => shellSplit("'foo bar"), throwsFormatException);
+ });
+ });
+
+ group('parses double quotes', () {
+ test('that are empty', () {
+ expect(shellSplit('""'), equals(['']));
+ });
+
+ test('that contain normal characters', () {
+ expect(shellSplit('"foo"'), equals(['foo']));
+ });
+
+ test('that contain otherwise-active characters', () {
+ expect(shellSplit('"\' #"'), equals(["' #"]));
+ });
+
+ test('that contain escaped characters', () {
+ expect(shellSplit(r'"\$\`\"\\"'), equals([r'$`"\']));
+ });
+
+ test('that contain an escaped newline', () {
+ expect(shellSplit('"\\\n"'), equals(['']));
+ });
+
+ test("that contain a backslash that's not an escape", () {
+ expect(shellSplit(r'"f\oo"'), equals([r'f\oo']));
+ });
+
+ test('before a hash', () {
+ expect(shellSplit('""#foo'), equals([r'#foo']));
+ });
+
+ test('inside a token', () {
+ expect(shellSplit('foo"bar baz"qux'), equals([r'foobar bazqux']));
+ });
+
+ test('without a closing quote', () {
+ expect(() => shellSplit('"foo bar'), throwsFormatException);
+ expect(() => shellSplit(r'"foo bar\'), throwsFormatException);
+ });
+ });
+ });
+}
diff --git a/pkgs/json_rpc_2/.gitignore b/pkgs/json_rpc_2/.gitignore
new file mode 100644
index 0000000..ab3cb76
--- /dev/null
+++ b/pkgs/json_rpc_2/.gitignore
@@ -0,0 +1,16 @@
+# Don’t commit the following directories created by pub.
+.buildlog
+.dart_tool/
+.pub/
+build/
+packages
+.packages
+
+# Or the files created by dart2js.
+*.dart.js
+*.js_
+*.js.deps
+*.js.map
+
+# Include when developing application packages.
+pubspec.lock
diff --git a/pkgs/json_rpc_2/.test_config b/pkgs/json_rpc_2/.test_config
new file mode 100644
index 0000000..412fc5c
--- /dev/null
+++ b/pkgs/json_rpc_2/.test_config
@@ -0,0 +1,3 @@
+{
+ "test_package": true
+}
\ No newline at end of file
diff --git a/pkgs/json_rpc_2/CHANGELOG.md b/pkgs/json_rpc_2/CHANGELOG.md
new file mode 100644
index 0000000..1f2cf8e
--- /dev/null
+++ b/pkgs/json_rpc_2/CHANGELOG.md
@@ -0,0 +1,151 @@
+## 3.0.3
+
+* Require Dart 3.4
+* Move to `dart-lang/tools` monorepo.
+
+## 3.0.2
+
+* Switch to using `package:lints`.
+* Address a few analysis hint violations.
+* Populate the pubspec `repository` field.
+
+## 3.0.1
+
+* Fix a bug where a `null` result to a request caused an exception.
+
+## 3.0.0
+
+* Migrate to null safety.
+* Accept responses even if the server converts the ID to a String.
+
+## 2.2.2
+
+* Fix `Peer.close()` throwing `Bad state: Future already completed`.
+
+## 2.2.1
+
+* Fix `Peer` requests not terminating when the underlying channel is closed.
+
+## 2.2.0
+
+* Added `strictProtocolChecks` named parameter to `Server` and `Peer`
+ constructors. Setting this parameter to false will result in the server not
+ rejecting requests missing the `jsonrpc` parameter.
+
+## 2.1.1
+
+* Fixed issue where throwing `RpcException.methodNotFound` in an asynchronous
+ fallback handler would not result in the next fallback being executed.
+* Updated minimum SDK to Dart `2.2.0`.
+
+## 2.1.0
+
+* `Server` and related classes can now take an `onUnhandledError` callback to
+ notify callers of unhandled exceptions.
+
+## 2.0.10
+
+* Allow `stream_channel` version 2.x
+
+## 2.0.8
+
+* Updated SDK version to 2.0.0-dev.17.0
+
+## 2.0.7
+
+* When a `Client` is closed before a request completes, the error sent to that
+ request's `Future` now includes the request method to aid in debugging.
+
+## 2.0.6
+
+* Internal changes only.
+
+## 2.0.5
+
+* Internal changes only.
+
+## 2.0.4
+
+* `Client.sendRequest()` now throws a `StateError` if the client is closed while
+ the request is in-flight. This avoids dangling `Future`s that will never be
+ completed.
+
+* Both `Client.sendRequest()` and `Client.sendNotification()` now throw
+ `StateError`s if they're called after the client is closed.
+
+## 2.0.3
+
+* Fix new strong-mode warnings.
+
+## 2.0.2
+
+* Fix all strong-mode warnings.
+
+## 2.0.1
+
+* Fix a race condition in which a `StateError` could be top-leveled if
+ `Peer.close()` was called before the underlying channel closed.
+
+## 2.0.0
+
+* **Breaking change:** all constructors now take a `StreamChannel` rather than a
+ `Stream`/`StreamSink` pair.
+
+* `Client.sendRequest()` and `Client.sendNotification()` no longer throw
+ `StateError`s after the connection has been closed but before `Client.close()`
+ has been called.
+
+* The various `close()` methods may now be called before their corresponding
+ `listen()` methods.
+
+* The various `close()` methods now wait on the result of closing the underlying
+ `StreamSink`. Be aware that [in some circumstances][issue 19095]
+ `StreamController`s' `Sink.close()` futures may never complete.
+
+[issue 19095]: https://github.com/dart-lang/sdk/issues/19095
+
+## 1.2.0
+
+* Add `Client.isClosed` and `Server.isClosed`, which make it possible to
+ synchronously determine whether the connection is open. In particular, this
+ makes it possible to reliably tell whether it's safe to call
+ `Client.sendRequest`.
+
+* Fix a race condition in `Server` where a `StateError` could be thrown if the
+ connection was closed in the middle of handling a request.
+
+* Improve stack traces for error responses.
+
+## 1.1.1
+
+* Update the README to match the current API.
+
+## 1.1.0
+
+* Add a `done` getter to `Client`, `Server`, and `Peer`.
+
+## 1.0.0
+
+* Add a `Client` class for communicating with external JSON-RPC 2.0 servers.
+
+* Add a `Peer` class that's both a `Client` and a `Server`.
+
+## 0.1.0
+
+* Remove `Server.handleRequest()` and `Server.parseRequest()`. Instead, `new
+ Server()` takes a `Stream` and a `StreamSink` and uses those behind-the-scenes
+ for its communication.
+
+* Add `Server.listen()`, which causes the server to begin listening to the
+ underlying request stream.
+
+* Add `Server.close()`, which closes the underlying request stream and response
+ sink.
+
+## 0.0.2+3
+
+* Widen the version constraint for `stack_trace`.
+
+## 0.0.2+2
+
+* Fix error response to include data from `RpcException` when not a map.
diff --git a/pkgs/json_rpc_2/LICENSE b/pkgs/json_rpc_2/LICENSE
new file mode 100644
index 0000000..000cd7b
--- /dev/null
+++ b/pkgs/json_rpc_2/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/json_rpc_2/README.md b/pkgs/json_rpc_2/README.md
new file mode 100644
index 0000000..a7dda4a
--- /dev/null
+++ b/pkgs/json_rpc_2/README.md
@@ -0,0 +1,150 @@
+[](https://github.com/dart-lang/tools/actions/workflows/json_rpc_2.yaml)
+[](https://pub.dev/packages/json_rpc_2)
+[](https://pub.dev/packages/json_rpc_2/publisher)
+
+A library that implements the [JSON-RPC 2.0 spec][spec].
+
+[spec]: https://www.jsonrpc.org/specification
+
+## Server
+
+A JSON-RPC 2.0 server exposes a set of methods that can be called by clients.
+These methods can be registered using `Server.registerMethod`:
+
+```dart
+import 'dart:io';
+
+import 'package:json_rpc_2/json_rpc_2.dart';
+import 'package:web_socket_channel/io.dart';
+import 'package:web_socket_channel/web_socket_channel.dart';
+
+void main() async {
+ var httpServer = await HttpServer.bind(InternetAddress.loopbackIPv4, 4321);
+ var connectedChannels =
+ httpServer.transform(WebSocketTransformer()).map(IOWebSocketChannel.new);
+ connectedChannels.listen(handleClient);
+}
+
+void handleClient(WebSocketChannel socket) {
+ // The socket is a `StreamChannel<dynamic>` because it might emit binary
+ // `List<int>`, but JSON RPC 2 only works with Strings so we assert it only
+ // emits those by casting it.
+ var server = Server(socket.cast<String>());
+
+ // Any string may be used as a method name. JSON-RPC 2.0 methods are
+ // case-sensitive.
+ var i = 0;
+ server.registerMethod('count', () {
+ // Just return the value to be sent as a response to the client. This can
+ // be anything JSON-serializable, or a Future that completes to something
+ // JSON-serializable.
+ return i++;
+ });
+
+ // Methods can take parameters. They're presented as a `Parameters` object
+ // which makes it easy to validate that the expected parameters exist.
+ server.registerMethod('echo', (Parameters params) {
+ // If the request doesn't have a "message" parameter this will
+ // automatically send a response notifying the client that the request
+ // was invalid.
+ return params['message'].value;
+ });
+
+ // `Parameters` has methods for verifying argument types.
+ server.registerMethod('subtract', (Parameters params) {
+ // If "minuend" or "subtrahend" aren't numbers, this will reject the
+ // request.
+ return params['minuend'].asNum - params['subtrahend'].asNum;
+ });
+
+ // [Parameters] also supports optional arguments.
+ server.registerMethod('sort', (Parameters params) {
+ var list = params['list'].asList;
+ list.sort();
+ if (params['descendint'].asBoolOr(false)) {
+ return list.reversed;
+ } else {
+ return list;
+ }
+ });
+
+ // A method can send an error response by throwing a `RpcException`.
+ // Any positive number may be used as an application- defined error code.
+ const dividByZero = 1;
+ server.registerMethod('divide', (Parameters params) {
+ var divisor = params['divisor'].asNum;
+ if (divisor == 0) {
+ throw RpcException(dividByZero, 'Cannot divide by zero.');
+ }
+
+ return params['dividend'].asNum / divisor;
+ });
+
+ // To give you time to register all your methods, the server won't start
+ // listening for requests until you call `listen`. Messages are buffered until
+ // listen is called. The returned Future won't complete until the connection
+ // is closed.
+ server.listen();
+}
+```
+
+## Client
+
+A JSON-RPC 2.0 client calls methods on a server and handles the server's
+responses to those method calls. These methods can be called using
+`Client.sendRequest`:
+
+```dart
+import 'package:json_rpc_2/json_rpc_2.dart';
+import 'package:pedantic/pedantic.dart';
+import 'package:web_socket_channel/web_socket_channel.dart';
+
+void main() async {
+ var socket = WebSocketChannel.connect(Uri.parse('ws://localhost:4321'));
+ var client = Client(socket.cast<String>());
+
+ // The client won't subscribe to the input stream until you call `listen`.
+ // The returned Future won't complete until the connection is closed.
+ unawaited(client.listen());
+
+ // This calls the "count" method on the server. A Future is returned that
+ // will complete to the value contained in the server's response.
+ var count = await client.sendRequest('count');
+ print('Count is $count');
+
+ // Parameters are passed as a simple Map or, for positional parameters, an
+ // Iterable. Make sure they're JSON-serializable!
+ var echo = await client.sendRequest('echo', {'message': 'hello'});
+ print('Echo says "$echo"!');
+
+ // A notification is a way to call a method that tells the server that no
+ // result is expected. Its return type is `void`; even if it causes an
+ // error, you won't hear back.
+ client.sendNotification('count');
+
+ // If the server sends an error response, the returned Future will complete
+ // with an RpcException. You can catch this error and inspect its error
+ // code, message, and any data that the server sent along with it.
+ try {
+ await client.sendRequest('divide', {'dividend': 2, 'divisor': 0});
+ } on RpcException catch (error) {
+ print('RPC error ${error.code}: ${error.message}');
+ }
+
+ await client.close();
+}
+```
+
+## Peer
+
+Although JSON-RPC 2.0 only explicitly describes clients and servers, it also
+mentions that two-way communication can be supported by making each endpoint
+both a client and a server. This package supports this directly using the `Peer`
+class, which implements both `Client` and `Server`. It supports the same methods
+as those classes, and automatically makes sure that every message from the other
+endpoint is routed and handled correctly.
+
+## Publishing automation
+
+For information about our publishing automation and release process, see
+https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.
diff --git a/pkgs/json_rpc_2/analysis_options.yaml b/pkgs/json_rpc_2/analysis_options.yaml
new file mode 100644
index 0000000..295b7cc
--- /dev/null
+++ b/pkgs/json_rpc_2/analysis_options.yaml
@@ -0,0 +1,12 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: false
+ errors:
+ avoid_dynamic_calls: ignore
+
+linter:
+ rules:
+ - avoid_unused_constructor_parameters
+ - cancel_subscriptions
diff --git a/pkgs/json_rpc_2/example/client.dart b/pkgs/json_rpc_2/example/client.dart
new file mode 100644
index 0000000..aa8f7ed
--- /dev/null
+++ b/pkgs/json_rpc_2/example/client.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:json_rpc_2/json_rpc_2.dart';
+import 'package:web_socket_channel/web_socket_channel.dart';
+
+void main() async {
+ var socket = WebSocketChannel.connect(Uri.parse('ws://localhost:4321'));
+ var client = Client(socket.cast<String>());
+
+ // The client won't subscribe to the input stream until you call `listen`.
+ // The returned Future won't complete until the connection is closed.
+ unawaited(client.listen());
+
+ // This calls the "count" method on the server. A Future is returned that
+ // will complete to the value contained in the server's response.
+ var count = await client.sendRequest('count');
+ print('Count is $count');
+
+ // Parameters are passed as a simple Map or, for positional parameters, an
+ // Iterable. Make sure they're JSON-serializable!
+ var echo = await client.sendRequest('echo', {'message': 'hello'});
+ print('Echo says "$echo"!');
+
+ // A notification is a way to call a method that tells the server that no
+ // result is expected. Its return type is `void`; even if it causes an
+ // error, you won't hear back.
+ client.sendNotification('count');
+
+ // If the server sends an error response, the returned Future will complete
+ // with an RpcException. You can catch this error and inspect its error
+ // code, message, and any data that the server sent along with it.
+ try {
+ await client.sendRequest('divide', {'dividend': 2, 'divisor': 0});
+ } on RpcException catch (error) {
+ print('RPC error ${error.code}: ${error.message}');
+ }
+
+ await client.close();
+}
diff --git a/pkgs/json_rpc_2/example/main.dart b/pkgs/json_rpc_2/example/main.dart
new file mode 100644
index 0000000..7d5ab73
--- /dev/null
+++ b/pkgs/json_rpc_2/example/main.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:json_rpc_2/json_rpc_2.dart';
+import 'package:web_socket_channel/io.dart';
+import 'package:web_socket_channel/web_socket_channel.dart';
+
+void main() async {
+ var httpServer = await HttpServer.bind(InternetAddress.loopbackIPv4, 4321);
+ var connectedChannels =
+ httpServer.transform(WebSocketTransformer()).map(IOWebSocketChannel.new);
+ connectedChannels.listen(handleClient);
+}
+
+void handleClient(WebSocketChannel socket) {
+ // The socket is a `StreamChannel<dynamic>` because it might emit binary
+ // `List<int>`, but JSON RPC 2 only works with Strings so we assert it only
+ // emits those by casting it.
+ var server = Server(socket.cast<String>());
+
+ // Any string may be used as a method name. JSON-RPC 2.0 methods are
+ // case-sensitive.
+ var i = 0;
+ server.registerMethod('count', () {
+ // Just return the value to be sent as a response to the client. This can
+ // be anything JSON-serializable, or a Future that completes to something
+ // JSON-serializable.
+ return i++;
+ });
+
+ // Methods can take parameters. They're presented as a `Parameters` object
+ // which makes it easy to validate that the expected parameters exist.
+ server.registerMethod('echo', (Parameters params) {
+ // If the request doesn't have a "message" parameter this will
+ // automatically send a response notifying the client that the request
+ // was invalid.
+ return params['message'].value;
+ });
+
+ // `Parameters` has methods for verifying argument types.
+ server.registerMethod('subtract', (Parameters params) {
+ // If "minuend" or "subtrahend" aren't numbers, this will reject the
+ // request.
+ return params['minuend'].asNum - params['subtrahend'].asNum;
+ });
+
+ // [Parameters] also supports optional arguments.
+ server.registerMethod('sort', (Parameters params) {
+ var list = params['list'].asList;
+ list.sort();
+ if (params['descendint'].asBoolOr(false)) {
+ return list.reversed;
+ } else {
+ return list;
+ }
+ });
+
+ // A method can send an error response by throwing a `RpcException`.
+ // Any positive number may be used as an application- defined error code.
+ const dividByZero = 1;
+ server.registerMethod('divide', (Parameters params) {
+ var divisor = params['divisor'].asNum;
+ if (divisor == 0) {
+ throw RpcException(dividByZero, 'Cannot divide by zero.');
+ }
+
+ return params['dividend'].asNum / divisor;
+ });
+
+ // To give you time to register all your methods, the server won't start
+ // listening for requests until you call `listen`. Messages are buffered until
+ // listen is called. The returned Future won't complete until the connection
+ // is closed.
+ server.listen();
+}
diff --git a/pkgs/json_rpc_2/lib/error_code.dart b/pkgs/json_rpc_2/lib/error_code.dart
new file mode 100644
index 0000000..5f90791
--- /dev/null
+++ b/pkgs/json_rpc_2/lib/error_code.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: constant_identifier_names
+
+import 'src/exception.dart';
+
+/// Error codes defined in the [JSON-RPC 2.0 specification][spec].
+///
+/// These codes are generally used for protocol-level communication. Most of
+/// them shouldn't be used by the application. Those that should have
+/// convenience constructors in [RpcException].
+///
+/// [spec]: http://www.jsonrpc.org/specification#error_object
+/// An error code indicating that invalid JSON was received by the server.
+const PARSE_ERROR = -32700;
+
+/// An error code indicating that the request JSON was invalid according to the
+/// JSON-RPC 2.0 spec.
+const INVALID_REQUEST = -32600;
+
+/// An error code indicating that the requested method does not exist or is
+/// unavailable.
+const METHOD_NOT_FOUND = -32601;
+
+/// An error code indicating that the request parameters are invalid for the
+/// requested method.
+const INVALID_PARAMS = -32602;
+
+/// An internal JSON-RPC error.
+const INTERNAL_ERROR = -32603;
+
+/// An unexpected error occurred on the server.
+///
+/// The spec reserves the range from -32000 to -32099 for implementation-defined
+/// server exceptions, but for now we only use one of those values.
+const SERVER_ERROR = -32000;
+
+/// Returns a human-readable name for [errorCode] if it's one specified by the
+/// JSON-RPC 2.0 spec.
+///
+/// If [errorCode] isn't defined in the JSON-RPC 2.0 spec, returns `null`.
+String? name(int errorCode) => switch (errorCode) {
+ PARSE_ERROR => 'parse error',
+ INVALID_REQUEST => 'invalid request',
+ METHOD_NOT_FOUND => 'method not found',
+ INVALID_PARAMS => 'invalid parameters',
+ INTERNAL_ERROR => 'internal error',
+ _ => null
+ };
diff --git a/pkgs/json_rpc_2/lib/json_rpc_2.dart b/pkgs/json_rpc_2/lib/json_rpc_2.dart
new file mode 100644
index 0000000..33e5f49
--- /dev/null
+++ b/pkgs/json_rpc_2/lib/json_rpc_2.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/client.dart';
+export 'src/exception.dart';
+export 'src/parameters.dart';
+export 'src/peer.dart';
+export 'src/server.dart';
diff --git a/pkgs/json_rpc_2/lib/src/client.dart b/pkgs/json_rpc_2/lib/src/client.dart
new file mode 100644
index 0000000..182f945
--- /dev/null
+++ b/pkgs/json_rpc_2/lib/src/client.dart
@@ -0,0 +1,246 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:stack_trace/stack_trace.dart';
+import 'package:stream_channel/stream_channel.dart';
+
+import 'exception.dart';
+import 'utils.dart';
+
+/// A JSON-RPC 2.0 client.
+///
+/// A client calls methods on a server and handles the server's responses to
+/// those method calls. Methods can be called with [sendRequest], or with
+/// [sendNotification] if no response is expected.
+class Client {
+ final StreamChannel<dynamic> _channel;
+
+ /// The next request id.
+ var _id = 0;
+
+ /// The current batch of requests to be sent together.
+ ///
+ /// Each element is a JSON RPC spec compliant message.
+ List<Map<String, dynamic>>? _batch;
+
+ /// The map of request ids to pending requests.
+ final _pendingRequests = <int, _Request>{};
+
+ final _done = Completer<void>();
+
+ /// Returns a [Future] that completes when the underlying connection is
+ /// closed.
+ ///
+ /// This is the same future that's returned by [listen] and [close]. It may
+ /// complete before [close] is called if the remote endpoint closes the
+ /// connection.
+ Future get done => _done.future;
+
+ /// Whether the underlying connection is closed.
+ ///
+ /// Note that this will be `true` before [close] is called if the remote
+ /// endpoint closes the connection.
+ bool get isClosed => _done.isCompleted;
+
+ /// Creates a [Client] that communicates over [channel].
+ ///
+ /// Note that the client won't begin listening to [channel] until
+ /// [Client.listen] is called.
+ Client(StreamChannel<String> channel)
+ : this.withoutJson(
+ jsonDocument.bind(channel).transformStream(ignoreFormatExceptions));
+
+ /// Creates a [Client] that communicates using decoded messages over
+ /// [_channel].
+ ///
+ /// Unlike [Client.new], this doesn't read or write JSON strings. Instead, it
+ /// reads and writes decoded maps or lists.
+ ///
+ /// Note that the client won't begin listening to [_channel] until
+ /// [Client.listen] is called.
+ Client.withoutJson(this._channel) {
+ done.whenComplete(() {
+ for (var request in _pendingRequests.values) {
+ request.completer.completeError(StateError(
+ 'The client closed with pending request "${request.method}".'));
+ }
+ _pendingRequests.clear();
+ }).catchError((_) {
+ // Avoid an unhandled error.
+ });
+ }
+
+ /// Starts listening to the underlying stream.
+ ///
+ /// Returns a [Future] that will complete when the connection is closed or
+ /// when it has an error. This is the same as [done].
+ ///
+ /// [listen] may only be called once.
+ Future listen() {
+ _channel.stream.listen(_handleResponse,
+ onError: (Object error, StackTrace stackTrace) {
+ _done.completeError(error, stackTrace);
+ _channel.sink.close();
+ }, onDone: () {
+ if (!_done.isCompleted) _done.complete();
+ close();
+ });
+ return done;
+ }
+
+ /// Closes the underlying connection.
+ ///
+ /// Returns a [Future] that completes when all resources have been released.
+ /// This is the same as [done].
+ Future close() {
+ _channel.sink.close();
+ if (!_done.isCompleted) _done.complete();
+ return done;
+ }
+
+ /// Sends a JSON-RPC 2 request to invoke the given [method].
+ ///
+ /// If passed, [parameters] is the parameters for the method. This must be
+ /// either an [Iterable] (to pass parameters by position) or a [Map] with
+ /// [String] keys (to pass parameters by name). Either way, it must be
+ /// JSON-serializable.
+ ///
+ /// If the request succeeds, this returns the response result as a decoded
+ /// JSON-serializable object. If it fails, it throws an [RpcException]
+ /// describing the failure.
+ ///
+ /// Throws a [StateError] if the client is closed while the request is in
+ /// flight, or if the client is closed when this method is called.
+ Future<Object?> sendRequest(String method, [Object? parameters]) {
+ var id = _id++;
+ _send(method, parameters, id);
+
+ var completer = Completer<Object?>.sync();
+ _pendingRequests[id] = _Request(method, completer, Chain.current());
+ return completer.future;
+ }
+
+ /// Sends a JSON-RPC 2 request to invoke the given [method] without expecting
+ /// a response.
+ ///
+ /// If passed, [parameters] is the parameters for the method. This must be
+ /// either an [Iterable] (to pass parameters by position) or a [Map] with
+ /// [String] keys (to pass parameters by name). Either way, it must be
+ /// JSON-serializable.
+ ///
+ /// Since this is just a notification to which the server isn't expected to
+ /// send a response, it has no return value.
+ ///
+ /// Throws a [StateError] if the client is closed when this method is called.
+ void sendNotification(String method, [Object? parameters]) =>
+ _send(method, parameters);
+
+ /// A helper method for [sendRequest] and [sendNotification].
+ ///
+ /// Sends a request to invoke [method] with [parameters]. If [id] is given,
+ /// the request uses that id.
+ void _send(String method, Object? parameters, [int? id]) {
+ if (parameters is Iterable) parameters = parameters.toList();
+ if (parameters is! Map && parameters is! List && parameters != null) {
+ throw ArgumentError('Only maps and lists may be used as JSON-RPC '
+ 'parameters, was "$parameters".');
+ }
+ if (isClosed) throw StateError('The client is closed.');
+
+ var message = <String, dynamic>{'jsonrpc': '2.0', 'method': method};
+ if (id != null) message['id'] = id;
+ if (parameters != null) message['params'] = parameters;
+
+ if (_batch != null) {
+ _batch!.add(message);
+ } else {
+ _channel.sink.add(message);
+ }
+ }
+
+ /// Runs [callback] and batches any requests sent until it returns.
+ ///
+ /// A batch of requests is sent in a single message on the underlying stream,
+ /// and the responses are likewise sent back in a single message.
+ ///
+ /// [callback] may be synchronous or asynchronous. If it returns a [Future],
+ /// requests will be batched until that Future returns; otherwise, requests
+ /// will only be batched while synchronously executing [callback].
+ ///
+ /// If this is called in the context of another [withBatch] call, it just
+ /// invokes [callback] without creating another batch. This means that
+ /// responses are batched until the first batch ends.
+ void withBatch(FutureOr<void> Function() callback) {
+ if (_batch != null) {
+ callback();
+ return;
+ }
+
+ _batch = [];
+ return tryFinally(callback, () {
+ _channel.sink.add(_batch);
+ _batch = null;
+ });
+ }
+
+ /// Handles a decoded response from the server.
+ void _handleResponse(Object? response) {
+ if (response is List) {
+ response.forEach(_handleSingleResponse);
+ } else {
+ _handleSingleResponse(response);
+ }
+ }
+
+ /// Handles a decoded response from the server after batches have been
+ /// resolved.
+ void _handleSingleResponse(Object? response_) {
+ if (!_isResponseValid(response_)) return;
+ final response = response_ as Map;
+ var id = response['id'];
+ id = (id is String) ? int.parse(id) : id;
+ var request = _pendingRequests.remove(id)!;
+ if (response.containsKey('result')) {
+ request.completer.complete(response['result']);
+ } else {
+ request.completer.completeError(
+ RpcException(response['error']['code'], response['error']['message'],
+ data: response['error']['data']),
+ request.chain);
+ }
+ }
+
+ /// Determines whether the server's response is valid per the spec.
+ bool _isResponseValid(Object? response) {
+ if (response is! Map) return false;
+ if (response['jsonrpc'] != '2.0') return false;
+ var id = response['id'];
+ id = (id is String) ? int.parse(id) : id;
+ if (!_pendingRequests.containsKey(id)) return false;
+ if (response.containsKey('result')) return true;
+
+ if (!response.containsKey('error')) return false;
+ var error = response['error'];
+ if (error is! Map) return false;
+ if (error['code'] is! int) return false;
+ if (error['message'] is! String) return false;
+ return true;
+ }
+}
+
+/// A pending request to the server.
+class _Request {
+ /// THe method that was sent.
+ final String method;
+
+ /// The completer to use to complete the response future.
+ final Completer completer;
+
+ /// The stack chain from where the request was made.
+ final Chain chain;
+
+ _Request(this.method, this.completer, this.chain);
+}
diff --git a/pkgs/json_rpc_2/lib/src/exception.dart b/pkgs/json_rpc_2/lib/src/exception.dart
new file mode 100644
index 0000000..906a053
--- /dev/null
+++ b/pkgs/json_rpc_2/lib/src/exception.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../error_code.dart' as error_code;
+
+/// An exception from a JSON-RPC server that can be translated into an error
+/// response.
+class RpcException implements Exception {
+ /// The error code.
+ ///
+ /// All non-negative error codes are available for use by application
+ /// developers.
+ final int code;
+
+ /// The error message.
+ ///
+ /// This should be limited to a concise single sentence. Further information
+ /// should be supplied via [data].
+ final String message;
+
+ /// Extra application-defined information about the error.
+ ///
+ /// This must be a JSON-serializable object. If it's a [Map] without a
+ /// `"request"` key, a copy of the request that caused the error will
+ /// automatically be injected.
+ final Object? data;
+
+ RpcException(this.code, this.message, {this.data});
+
+ /// An exception indicating that the method named [methodName] was not found.
+ ///
+ /// This should usually be used only by fallback handlers.
+ RpcException.methodNotFound(String methodName)
+ : this(error_code.METHOD_NOT_FOUND, 'Unknown method "$methodName".');
+
+ /// An exception indicating that the parameters for the requested method were
+ /// invalid.
+ ///
+ /// Methods can use this to reject requests with invalid parameters.
+ RpcException.invalidParams(String message)
+ : this(error_code.INVALID_PARAMS, message);
+
+ /// Converts this exception into a JSON-serializable object that's a valid
+ /// JSON-RPC 2.0 error response.
+ Map<String, dynamic> serialize(Object? request) {
+ dynamic modifiedData;
+ if (data is Map && !(data as Map).containsKey('request')) {
+ modifiedData = {
+ ...data as Map,
+ 'request': request,
+ };
+ } else if (data == null) {
+ modifiedData = {'request': request};
+ } else {
+ modifiedData = data;
+ }
+
+ var id = request is Map ? request['id'] : null;
+ if (id is! String && id is! num) id = null;
+ return {
+ 'jsonrpc': '2.0',
+ 'error': {'code': code, 'message': message, 'data': modifiedData},
+ 'id': id
+ };
+ }
+
+ @override
+ String toString() {
+ var prefix = 'JSON-RPC error $code';
+ var errorName = error_code.name(code);
+ if (errorName != null) prefix += ' ($errorName)';
+ return '$prefix: $message';
+ }
+}
diff --git a/pkgs/json_rpc_2/lib/src/parameters.dart b/pkgs/json_rpc_2/lib/src/parameters.dart
new file mode 100644
index 0000000..0a18882
--- /dev/null
+++ b/pkgs/json_rpc_2/lib/src/parameters.dart
@@ -0,0 +1,348 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'exception.dart';
+
+/// A wrapper for the parameters to a server method.
+///
+/// JSON-RPC 2.0 allows parameters that are either a list or a map. This class
+/// provides functions that not only assert that the parameters object is the
+/// correct type, but also that the expected arguments exist and are themselves
+/// the correct type.
+///
+/// Example usage:
+///
+/// server.registerMethod("subtract", (params) {
+/// return params["minuend"].asNum - params["subtrahend"].asNum;
+/// });
+class Parameters {
+ /// The name of the method that this request called.
+ final String method;
+
+ /// The underlying value of the parameters object.
+ ///
+ /// If this is accessed for a [Parameter] that was not passed, the request
+ /// will be automatically rejected. To avoid this, use [Parameter.valueOr].
+ final dynamic value;
+
+ Parameters(this.method, this.value);
+
+ /// Returns a single parameter.
+ ///
+ /// If [key] is a [String], the request is expected to provide named
+ /// parameters. If it's an [int], the request is expected to provide
+ /// positional parameters. Requests that don't do so will be rejected
+ /// automatically.
+ ///
+ /// Whether or not the given parameter exists, this returns a [Parameter]
+ /// object. If a parameter's value is accessed through a getter like [value]
+ /// or [Parameter.asNum], the request will be rejected if that parameter
+ /// doesn't exist. On the other hand, if it's accessed through a method with a
+ /// default value like [Parameter.valueOr] or [Parameter.asNumOr], the default
+ /// value will be returned.
+ Parameter operator [](Object? key) {
+ if (key is int) {
+ _assertPositional();
+ if (key < value.length) {
+ return Parameter._(method, value[key], this, key);
+ } else {
+ return _MissingParameter(method, this, key);
+ }
+ } else if (key is String) {
+ _assertNamed();
+ if (value.containsKey(key)) {
+ return Parameter._(method, value[key], this, key);
+ } else {
+ return _MissingParameter(method, this, key);
+ }
+ } else {
+ throw ArgumentError('Parameters[] only takes an int or a string, was '
+ '"$key".');
+ }
+ }
+
+ /// Asserts that [value] exists and is a [List] and returns it.
+ List get asList {
+ _assertPositional();
+ return value;
+ }
+
+ /// Asserts that [value] exists and is a [Map] and returns it.
+ Map get asMap {
+ _assertNamed();
+ return value;
+ }
+
+ /// Asserts that [value] is a positional argument list.
+ void _assertPositional() {
+ if (value is List) return;
+ throw RpcException.invalidParams('Parameters for method "$method" '
+ 'must be passed by position.');
+ }
+
+ /// Asserts that [value] is a named argument map.
+ void _assertNamed() {
+ if (value is Map) return;
+ throw RpcException.invalidParams('Parameters for method "$method" '
+ 'must be passed by name.');
+ }
+}
+
+/// A wrapper for a single parameter to a server method.
+///
+/// This provides numerous functions for asserting the type of the parameter in
+/// question. These functions each have a version that asserts that the
+/// parameter exists (for example, [asNum] and [asString]) and a version that
+/// returns a default value if the parameter doesn't exist (for example,
+/// [asNumOr] and [asStringOr]). If an assertion fails, the request is
+/// automatically rejected.
+///
+/// This extends [Parameters] to make it easy to access nested parameters. For
+/// example:
+///
+/// // "params.value" is "{'scores': {'home': [5, 10, 17]}}"
+/// params['scores']['home'][2].asInt // => 17
+class Parameter extends Parameters {
+ // The parent parameters, used to construct [_path].
+ final Parameters _parent;
+
+ /// The key used to access `this`, used to construct [_path].
+ final Object _key;
+
+ /// A human-readable representation of the path of getters used to get this.
+ ///
+ /// Named parameters are represented as `.name`, whereas positional parameters
+ /// are represented as `[index]`. For example: `"foo[0].bar.baz"`. Named
+ /// parameters that contain characters that are neither alphanumeric,
+ /// underscores, or hyphens will be JSON-encoded. For example: `"foo
+ /// bar"."baz.bang"`. If quotes are used for an individual component, they
+ /// won't be used for the entire string.
+ ///
+ /// An exception is made for single-level parameters. A single-level
+ /// positional parameter is just represented by the index plus one, because
+ /// "parameter 1" is clearer than "parameter [0]". A single-level named
+ /// parameter is represented by that name in quotes.
+ String get _path {
+ if (_parent is! Parameter) {
+ return _key is int ? (_key + 1).toString() : jsonEncode(_key);
+ }
+
+ String quoteKey(String key) {
+ if (key.contains(RegExp(r'[^a-zA-Z0-9_-]'))) return jsonEncode(key);
+ return key;
+ }
+
+ String computePath(Parameter params) {
+ if (params._parent is! Parameter) {
+ return params._key is int
+ ? '[${params._key}]'
+ : quoteKey(params._key as String);
+ }
+
+ var path = computePath(params._parent);
+ return params._key is int
+ ? '$path[${params._key}]'
+ : '$path.${quoteKey(params._key as String)}';
+ }
+
+ return computePath(this);
+ }
+
+ /// Whether this parameter exists.
+ bool get exists => true;
+
+ Parameter._(super.method, super.value, this._parent, this._key);
+
+ /// Returns [value], or [defaultValue] if this parameter wasn't passed.
+ dynamic valueOr(Object? defaultValue) => value;
+
+ /// Asserts that [value] exists and is a number and returns it.
+ ///
+ /// [asNumOr] may be used to provide a default value instead of rejecting the
+ /// request if [value] doesn't exist.
+ num get asNum => _getTyped('a number', (value) => value is num);
+
+ /// Asserts that [value] is a number and returns it.
+ ///
+ /// If [value] doesn't exist, this returns [defaultValue].
+ num asNumOr(num defaultValue) => asNum;
+
+ /// Asserts that [value] exists and is an integer and returns it.
+ ///
+ /// [asIntOr] may be used to provide a default value instead of rejecting the
+ /// request if [value] doesn't exist.
+ ///
+ /// Note that which values count as integers varies between the Dart VM and
+ /// dart2js. The value `1.0` will be considered an integer under dart2js but
+ /// not under the VM.
+ int get asInt => _getTyped('an integer', (value) => value is int);
+
+ /// Asserts that [value] is an integer and returns it.
+ ///
+ /// If [value] doesn't exist, this returns [defaultValue].
+ ///
+ /// Note that which values count as integers varies between the Dart VM and
+ /// dart2js. The value `1.0` will be considered an integer under dart2js but
+ /// not under the VM.
+ int asIntOr(int defaultValue) => asInt;
+
+ /// Asserts that [value] exists and is a boolean and returns it.
+ ///
+ /// [asBoolOr] may be used to provide a default value instead of rejecting the
+ /// request if [value] doesn't exist.
+ bool get asBool => _getTyped('a boolean', (value) => value is bool);
+
+ /// Asserts that [value] is a boolean and returns it.
+ ///
+ /// If [value] doesn't exist, this returns [defaultValue].
+ bool asBoolOr(bool defaultValue) => asBool;
+
+ /// Asserts that [value] exists and is a string and returns it.
+ ///
+ /// [asStringOr] may be used to provide a default value instead of rejecting
+ /// the request if [value] doesn't exist.
+ String get asString => _getTyped('a string', (value) => value is String);
+
+ /// Asserts that [value] is a string and returns it.
+ ///
+ /// If [value] doesn't exist, this returns [defaultValue].
+ String asStringOr(String defaultValue) => asString;
+
+ /// Asserts that [value] exists and is a [List] and returns it.
+ ///
+ /// [asListOr] may be used to provide a default value instead of rejecting the
+ /// request if [value] doesn't exist.
+ @override
+ List get asList => _getTyped('an Array', (value) => value is List);
+
+ /// Asserts that [value] is a [List] and returns it.
+ ///
+ /// If [value] doesn't exist, this returns [defaultValue].
+ List asListOr(List defaultValue) => asList;
+
+ /// Asserts that [value] exists and is a [Map] and returns it.
+ ///
+ /// [asMapOr] may be used to provide a default value instead of rejecting the
+ /// request if [value] doesn't exist.
+ @override
+ Map get asMap => _getTyped('an Object', (value) => value is Map);
+
+ /// Asserts that [value] is a [Map] and returns it.
+ ///
+ /// If [value] doesn't exist, this returns [defaultValue].
+ Map asMapOr(Map defaultValue) => asMap;
+
+ /// Asserts that [value] exists, is a string, and can be parsed as a
+ /// [DateTime] and returns it.
+ ///
+ /// [asDateTimeOr] may be used to provide a default value instead of rejecting
+ /// the request if [value] doesn't exist.
+ DateTime get asDateTime => _getParsed('date/time', DateTime.parse);
+
+ /// Asserts that [value] exists, is a string, and can be parsed as a
+ /// [DateTime] and returns it.
+ ///
+ /// If [value] doesn't exist, this returns [defaultValue].
+ DateTime asDateTimeOr(DateTime defaultValue) => asDateTime;
+
+ /// Asserts that [value] exists, is a string, and can be parsed as a
+ /// [Uri] and returns it.
+ ///
+ /// [asUriOr] may be used to provide a default value instead of rejecting the
+ /// request if [value] doesn't exist.
+ Uri get asUri => _getParsed('URI', Uri.parse);
+
+ /// Asserts that [value] exists, is a string, and can be parsed as a
+ /// [Uri] and returns it.
+ ///
+ /// If [value] doesn't exist, this returns [defaultValue].
+ Uri asUriOr(Uri defaultValue) => asUri;
+
+ /// Get a parameter named [type] that matches [test].
+ ///
+ /// [type] is used for the error message. It should begin with an indefinite
+ /// article.
+ dynamic _getTyped(String type, bool Function(dynamic) test) {
+ if (test(value)) return value;
+ throw RpcException.invalidParams('Parameter $_path for method '
+ '"$method" must be $type, but was ${jsonEncode(value)}.');
+ }
+
+ dynamic _getParsed(String description, void Function(String) parse) {
+ var string = asString;
+ try {
+ return parse(string);
+ } on FormatException catch (error) {
+ // DateTime.parse doesn't actually include any useful information in the
+ // FormatException, just the string that was being parsed. There's no use
+ // in including that in the RPC exception. See issue 17753.
+ var message = error.message;
+ if (message == string) {
+ message = '';
+ } else {
+ message = '\n$message';
+ }
+
+ throw RpcException.invalidParams('Parameter $_path for method '
+ '"$method" must be a valid $description, but was '
+ '${jsonEncode(string)}.$message');
+ }
+ }
+
+ @override
+ void _assertPositional() {
+ // Throw the standard exception for a mis-typed list.
+ asList;
+ }
+
+ @override
+ void _assertNamed() {
+ // Throw the standard exception for a mis-typed map.
+ asMap;
+ }
+}
+
+/// A subclass of [Parameter] representing a missing parameter.
+class _MissingParameter extends Parameter {
+ @override
+ dynamic get value {
+ throw RpcException.invalidParams('Request for method "$method" is '
+ 'missing required parameter $_path.');
+ }
+
+ @override
+ bool get exists => false;
+
+ _MissingParameter(String method, Parameters parent, Object key)
+ : super._(method, null, parent, key);
+
+ @override
+ dynamic valueOr(Object? defaultValue) => defaultValue;
+
+ @override
+ num asNumOr(num defaultValue) => defaultValue;
+
+ @override
+ int asIntOr(int defaultValue) => defaultValue;
+
+ @override
+ bool asBoolOr(bool defaultValue) => defaultValue;
+
+ @override
+ String asStringOr(String defaultValue) => defaultValue;
+
+ @override
+ List asListOr(List defaultValue) => defaultValue;
+
+ @override
+ Map asMapOr(Map defaultValue) => defaultValue;
+
+ @override
+ DateTime asDateTimeOr(DateTime defaultValue) => defaultValue;
+
+ @override
+ Uri asUriOr(Uri defaultValue) => defaultValue;
+}
diff --git a/pkgs/json_rpc_2/lib/src/peer.dart b/pkgs/json_rpc_2/lib/src/peer.dart
new file mode 100644
index 0000000..677b6e1
--- /dev/null
+++ b/pkgs/json_rpc_2/lib/src/peer.dart
@@ -0,0 +1,156 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:stream_channel/stream_channel.dart';
+
+import 'client.dart';
+import 'parameters.dart';
+import 'server.dart';
+import 'utils.dart';
+
+/// A JSON-RPC 2.0 client *and* server.
+///
+/// This supports bidirectional peer-to-peer communication with another JSON-RPC
+/// 2.0 endpoint. It sends both requests and responses across the same
+/// communication channel and expects to connect to a peer that does the same.
+class Peer implements Client, Server {
+ final StreamChannel<dynamic> _channel;
+
+ /// The underlying client that handles request-sending and response-receiving
+ /// logic.
+ late final Client _client;
+
+ /// The underlying server that handles request-receiving and response-sending
+ /// logic.
+ late final Server _server;
+
+ /// A stream controller that forwards incoming messages to [_server] if
+ /// they're requests.
+ final _serverIncomingForwarder = StreamController<Object?>(sync: true);
+
+ /// A stream controller that forwards incoming messages to [_client] if
+ /// they're responses.
+ final _clientIncomingForwarder = StreamController<Object?>(sync: true);
+
+ @override
+ late final Future done = Future.wait([_client.done, _server.done]);
+
+ @override
+ bool get isClosed => _client.isClosed || _server.isClosed;
+
+ @override
+ ErrorCallback? get onUnhandledError => _server.onUnhandledError;
+
+ @override
+ bool get strictProtocolChecks => _server.strictProtocolChecks;
+
+ /// Creates a [Peer] that communicates over [channel].
+ ///
+ /// Note that the peer won't begin listening to [channel] until [Peer.listen]
+ /// is called.
+ ///
+ /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
+ /// If this is not provided, unhandled exceptions will be swallowed.
+ ///
+ /// If [strictProtocolChecks] is false, the underlying [Server] will accept
+ /// some requests which are not conformant with the JSON-RPC 2.0
+ /// specification. In particular, requests missing the `jsonrpc` parameter
+ /// will be accepted.
+ Peer(StreamChannel<String> channel,
+ {ErrorCallback? onUnhandledError, bool strictProtocolChecks = true})
+ : this.withoutJson(
+ jsonDocument.bind(channel).transform(respondToFormatExceptions),
+ onUnhandledError: onUnhandledError,
+ strictProtocolChecks: strictProtocolChecks);
+
+ /// Creates a [Peer] that communicates using decoded messages over [_channel].
+ ///
+ /// Unlike [Peer.new], this doesn't read or write JSON strings. Instead, it
+ /// reads and writes decoded maps or lists.
+ ///
+ /// Note that the peer won't begin listening to [_channel] until
+ /// [Peer.listen] is called.
+ ///
+ /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
+ /// If this is not provided, unhandled exceptions will be swallowed.
+ ///
+ /// If [strictProtocolChecks] is false, the underlying [Server] will accept
+ /// some requests which are not conformant with the JSON-RPC 2.0
+ /// specification. In particular, requests missing the `jsonrpc` parameter
+ /// will be accepted.
+ Peer.withoutJson(this._channel,
+ {ErrorCallback? onUnhandledError, bool strictProtocolChecks = true}) {
+ _server = Server.withoutJson(
+ StreamChannel(_serverIncomingForwarder.stream, _channel.sink),
+ onUnhandledError: onUnhandledError,
+ strictProtocolChecks: strictProtocolChecks);
+ _client = Client.withoutJson(
+ StreamChannel(_clientIncomingForwarder.stream, _channel.sink));
+ }
+
+ // Client methods.
+
+ @override
+ Future sendRequest(String method, [Object? parameters]) =>
+ _client.sendRequest(method, parameters);
+
+ @override
+ void sendNotification(String method, [Object? parameters]) =>
+ _client.sendNotification(method, parameters);
+
+ @override
+ void withBatch(void Function() callback) => _client.withBatch(callback);
+
+ // Server methods.
+
+ @override
+ void registerMethod(String name, Function callback) =>
+ _server.registerMethod(name, callback);
+
+ @override
+ void registerFallback(void Function(Parameters parameters) callback) =>
+ _server.registerFallback(callback);
+
+ // Shared methods.
+
+ @override
+ Future listen() {
+ _client.listen();
+ _server.listen();
+ _channel.stream.listen((message) {
+ if (message is Map) {
+ if (message.containsKey('result') || message.containsKey('error')) {
+ _clientIncomingForwarder.add(message);
+ } else {
+ _serverIncomingForwarder.add(message);
+ }
+ } else if (message is List &&
+ message.isNotEmpty &&
+ message.first is Map) {
+ if (message.first.containsKey('result') ||
+ message.first.containsKey('error')) {
+ _clientIncomingForwarder.add(message);
+ } else {
+ _serverIncomingForwarder.add(message);
+ }
+ } else {
+ // Non-Map and -List messages are ill-formed, so we pass them to the
+ // server since it knows how to send error responses.
+ _serverIncomingForwarder.add(message);
+ }
+ }, onError: (Object error, StackTrace stackTrace) {
+ _serverIncomingForwarder.addError(error, stackTrace);
+ }, onDone: close);
+ return done;
+ }
+
+ @override
+ Future close() {
+ _client.close();
+ _server.close();
+ return done;
+ }
+}
diff --git a/pkgs/json_rpc_2/lib/src/server.dart b/pkgs/json_rpc_2/lib/src/server.dart
new file mode 100644
index 0000000..2c58b79
--- /dev/null
+++ b/pkgs/json_rpc_2/lib/src/server.dart
@@ -0,0 +1,319 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:convert';
+
+import 'package:stack_trace/stack_trace.dart';
+import 'package:stream_channel/stream_channel.dart';
+
+import '../error_code.dart' as error_code;
+import 'exception.dart';
+import 'parameters.dart';
+import 'utils.dart';
+
+/// A callback for unhandled exceptions.
+typedef ErrorCallback = void Function(dynamic error, dynamic stackTrace);
+
+/// A JSON-RPC 2.0 server.
+///
+/// A server exposes methods that are called by requests, to which it provides
+/// responses. Methods can be registered using [registerMethod] and
+/// [registerFallback].
+///
+/// Note that since requests can arrive asynchronously and methods can run
+/// asynchronously, it's possible for multiple methods to be invoked at the same
+/// time, or even for a single method to be invoked multiple times at once.
+class Server {
+ final StreamChannel<dynamic> _channel;
+
+ /// The methods registered for this server.
+ final _methods = <String, Function>{};
+
+ /// The fallback methods for this server.
+ ///
+ /// These are tried in order until one of them doesn't throw a
+ /// [RpcException.methodNotFound] exception.
+ final _fallbacks = Queue<Function>();
+
+ final _done = Completer<void>();
+
+ /// Returns a [Future] that completes when the underlying connection is
+ /// closed.
+ ///
+ /// This is the same future that's returned by [listen] and [close]. It may
+ /// complete before [close] is called if the remote endpoint closes the
+ /// connection.
+ Future get done => _done.future;
+
+ /// Whether the underlying connection is closed.
+ ///
+ /// Note that this will be `true` before [close] is called if the remote
+ /// endpoint closes the connection.
+ bool get isClosed => _done.isCompleted;
+
+ /// A callback that is fired on unhandled exceptions.
+ ///
+ /// In the case where a user provided callback results in an exception that
+ /// cannot be properly routed back to the client, this handler will be
+ /// invoked. If it is not set, the exception will be swallowed.
+ final ErrorCallback? onUnhandledError;
+
+ /// Whether to strictly enforce the JSON-RPC 2.0 specification for received
+ /// messages.
+ ///
+ /// If `false`, this [Server] will accept some requests which are not
+ /// conformant with the JSON-RPC 2.0 specification. In particular, requests
+ /// missing the `jsonrpc` parameter will be accepted.
+ final bool strictProtocolChecks;
+
+ /// Creates a [Server] that communicates over [channel].
+ ///
+ /// Note that the server won't begin listening to [channel] until
+ /// [Server.listen] is called.
+ ///
+ /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
+ /// If this is not provided, unhandled exceptions will be swallowed.
+ ///
+ /// If [strictProtocolChecks] is false, this [Server] will accept some
+ /// requests which are not conformant with the JSON-RPC 2.0 specification. In
+ /// particular, requests missing the `jsonrpc` parameter will be accepted.
+ Server(StreamChannel<String> channel,
+ {ErrorCallback? onUnhandledError, bool strictProtocolChecks = true})
+ : this.withoutJson(
+ jsonDocument.bind(channel).transform(respondToFormatExceptions),
+ onUnhandledError: onUnhandledError,
+ strictProtocolChecks: strictProtocolChecks);
+
+ /// Creates a [Server] that communicates using decoded messages over
+ /// [_channel].
+ ///
+ /// Unlike [Server.new], this doesn't read or write JSON strings. Instead, it
+ /// reads and writes decoded maps or lists.
+ ///
+ /// Note that the server won't begin listening to [_channel] until
+ /// [Server.listen] is called.
+ ///
+ /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
+ /// If this is not provided, unhandled exceptions will be swallowed.
+ ///
+ /// If [strictProtocolChecks] is false, this [Server] will accept some
+ /// requests which are not conformant with the JSON-RPC 2.0 specification. In
+ /// particular, requests missing the `jsonrpc` parameter will be accepted.
+ Server.withoutJson(this._channel,
+ {this.onUnhandledError, this.strictProtocolChecks = true});
+
+ /// Starts listening to the underlying stream.
+ ///
+ /// Returns a [Future] that will complete when the connection is closed or
+ /// when it has an error. This is the same as [done].
+ ///
+ /// [listen] may only be called once.
+ Future listen() {
+ _channel.stream.listen(_handleRequest,
+ onError: (Object error, StackTrace stackTrace) {
+ _done.completeError(error, stackTrace);
+ _channel.sink.close();
+ }, onDone: () {
+ if (!_done.isCompleted) _done.complete();
+ });
+ return done;
+ }
+
+ /// Closes the underlying connection.
+ ///
+ /// Returns a [Future] that completes when all resources have been released.
+ /// This is the same as [done].
+ Future close() {
+ _channel.sink.close();
+ if (!_done.isCompleted) _done.complete();
+ return done;
+ }
+
+ /// Registers a method named [name] on this server.
+ ///
+ /// [callback] can take either zero or one arguments. If it takes zero, any
+ /// requests for that method that include parameters will be rejected. If it
+ /// takes one, it will be passed a [Parameters] object.
+ ///
+ /// [callback] can return either a JSON-serializable object or a Future that
+ /// completes to a JSON-serializable object. Any errors in [callback] will be
+ /// reported to the client as JSON-RPC 2.0 errors.
+ void registerMethod(String name, Function callback) {
+ if (_methods.containsKey(name)) {
+ throw ArgumentError('There\'s already a method named "$name".');
+ }
+
+ _methods[name] = callback;
+ }
+
+ /// Registers a fallback method on this server.
+ ///
+ /// A server may have any number of fallback methods. When a request comes in
+ /// that doesn't match any named methods, each fallback is tried in order. A
+ /// fallback can pass on handling a request by throwing a
+ /// [RpcException.methodNotFound] exception.
+ ///
+ /// [callback] can return either a JSON-serializable object or a Future that
+ /// completes to a JSON-serializable object. Any errors in [callback] will be
+ /// reported to the client as JSON-RPC 2.0 errors. [callback] may send custom
+ /// errors by throwing an [RpcException].
+ void registerFallback(void Function(Parameters parameters) callback) {
+ _fallbacks.add(callback);
+ }
+
+ /// Handle a request.
+ ///
+ /// [request] is expected to be a JSON-serializable object representing a
+ /// request sent by a client. This calls the appropriate method or methods for
+ /// handling that request and returns a JSON-serializable response, or `null`
+ /// if no response should be sent.
+ Future _handleRequest(Object? request) async {
+ dynamic response;
+ if (request is List) {
+ if (request.isEmpty) {
+ response = RpcException(error_code.INVALID_REQUEST,
+ 'A batch must contain at least one request.')
+ .serialize(request);
+ } else {
+ var results = await Future.wait(request.map(_handleSingleRequest));
+ var nonNull = results.where((result) => result != null);
+ if (nonNull.isEmpty) return;
+ response = nonNull.toList();
+ }
+ } else {
+ response = await _handleSingleRequest(request);
+ if (response == null) return;
+ }
+
+ if (!isClosed) _channel.sink.add(response);
+ }
+
+ /// Handles an individual parsed request.
+ Future _handleSingleRequest(Object? request) async {
+ try {
+ _validateRequest(request);
+ request = request as Map;
+
+ var name = request['method'];
+ var method = _methods[name];
+ method ??= _tryFallbacks;
+
+ Object? result;
+ if (method is ZeroArgumentFunction) {
+ if (request.containsKey('params')) {
+ throw RpcException.invalidParams('No parameters are allowed for '
+ 'method "$name".');
+ }
+ result = await method();
+ } else {
+ result = await method(Parameters(name, request['params']));
+ }
+
+ // A request without an id is a notification, which should not be sent a
+ // response, even if one is generated on the server.
+ if (!request.containsKey('id')) return null;
+
+ return {'jsonrpc': '2.0', 'result': result, 'id': request['id']};
+ } catch (error, stackTrace) {
+ if (error is RpcException) {
+ if (error.code == error_code.INVALID_REQUEST ||
+ (request is Map && request.containsKey('id'))) {
+ return error.serialize(request);
+ } else {
+ onUnhandledError?.call(error, stackTrace);
+ return null;
+ }
+ } else if (request is Map && !request.containsKey('id')) {
+ onUnhandledError?.call(error, stackTrace);
+ return null;
+ }
+ final chain = Chain.forTrace(stackTrace);
+ return RpcException(error_code.SERVER_ERROR, getErrorMessage(error),
+ data: {
+ 'full': '$error',
+ 'stack': '$chain',
+ }).serialize(request);
+ }
+ }
+
+ /// Validates that [request] matches the JSON-RPC spec.
+ void _validateRequest(Object? request) {
+ if (request is! Map) {
+ throw RpcException(
+ error_code.INVALID_REQUEST,
+ 'Request must be '
+ 'an Array or an Object.');
+ }
+
+ if (strictProtocolChecks && !request.containsKey('jsonrpc')) {
+ throw RpcException(
+ error_code.INVALID_REQUEST,
+ 'Request must '
+ 'contain a "jsonrpc" key.');
+ }
+
+ if ((strictProtocolChecks || request.containsKey('jsonrpc')) &&
+ request['jsonrpc'] != '2.0') {
+ throw RpcException(
+ error_code.INVALID_REQUEST,
+ 'Invalid JSON-RPC '
+ 'version ${jsonEncode(request['jsonrpc'])}, expected "2.0".');
+ }
+
+ if (!request.containsKey('method')) {
+ throw RpcException(
+ error_code.INVALID_REQUEST,
+ 'Request must '
+ 'contain a "method" key.');
+ }
+
+ var method = request['method'];
+ if (request['method'] is! String) {
+ throw RpcException(
+ error_code.INVALID_REQUEST,
+ 'Request method must '
+ 'be a string, but was ${jsonEncode(method)}.');
+ }
+
+ if (request.containsKey('params')) {
+ var params = request['params'];
+ if (params is! List && params is! Map) {
+ throw RpcException(
+ error_code.INVALID_REQUEST,
+ 'Request params must '
+ 'be an Array or an Object, but was ${jsonEncode(params)}.');
+ }
+ }
+
+ var id = request['id'];
+ if (id != null && id is! String && id is! num) {
+ throw RpcException(
+ error_code.INVALID_REQUEST,
+ 'Request id must be a '
+ 'string, number, or null, but was ${jsonEncode(id)}.');
+ }
+ }
+
+ /// Try all the fallback methods in order.
+ Future _tryFallbacks(Parameters params) {
+ var iterator = _fallbacks.toList().iterator;
+
+ Future tryNext() async {
+ if (!iterator.moveNext()) {
+ throw RpcException.methodNotFound(params.method);
+ }
+
+ try {
+ return await iterator.current(params);
+ } on RpcException catch (error) {
+ if (error.code != error_code.METHOD_NOT_FOUND) rethrow;
+ return tryNext();
+ }
+ }
+
+ return tryNext();
+ }
+}
diff --git a/pkgs/json_rpc_2/lib/src/utils.dart b/pkgs/json_rpc_2/lib/src/utils.dart
new file mode 100644
index 0000000..28bbf21
--- /dev/null
+++ b/pkgs/json_rpc_2/lib/src/utils.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:stream_channel/stream_channel.dart';
+
+import '../error_code.dart' as error_code;
+import 'exception.dart';
+
+typedef ZeroArgumentFunction = FutureOr Function();
+
+/// A regular expression to match the exception prefix that some exceptions'
+/// [Object.toString] values contain.
+final _exceptionPrefix = RegExp(r'^([A-Z][a-zA-Z]*)?(Exception|Error): ');
+
+/// Get a string description of an exception.
+///
+/// Many exceptions include the exception class name at the beginning of their
+/// `toString`, so we remove that if it exists.
+String getErrorMessage(Object error) =>
+ error.toString().replaceFirst(_exceptionPrefix, '');
+
+/// Like `try`/`finally`, run [body] and ensure that [whenComplete] runs
+/// afterwards, regardless of whether [body] succeeded.
+///
+/// This is synchronicity-agnostic relative to [body]. If [body] returns a
+/// [Future], this wil run asynchronously; otherwise it will run synchronously.
+void tryFinally(dynamic Function() body, void Function() whenComplete) {
+ dynamic result;
+ try {
+ result = body();
+ } catch (_) {
+ whenComplete();
+ rethrow;
+ }
+
+ if (result is! Future) {
+ whenComplete();
+ } else {
+ result.whenComplete(whenComplete);
+ }
+}
+
+/// A transformer that silently drops [FormatException]s.
+final ignoreFormatExceptions = StreamTransformer<Object?, Object?>.fromHandlers(
+ handleError: (error, stackTrace, sink) {
+ if (error is FormatException) return;
+ sink.addError(error, stackTrace);
+});
+
+/// A transformer that sends error responses on [FormatException]s.
+final StreamChannelTransformer<Object?, Object?> respondToFormatExceptions =
+ _RespondToFormatExceptionsTransformer();
+
+class _RespondToFormatExceptionsTransformer
+ implements StreamChannelTransformer<Object?, Object?> {
+ @override
+ StreamChannel<Object?> bind(StreamChannel<Object?> channel) {
+ return channel.changeStream((stream) {
+ return stream.handleError((dynamic error) {
+ final formatException = error as FormatException;
+ var exception = RpcException(
+ error_code.PARSE_ERROR, 'Invalid JSON: ${formatException.message}');
+ channel.sink.add(exception.serialize(formatException.source));
+ }, test: (error) => error is FormatException);
+ });
+ }
+}
diff --git a/pkgs/json_rpc_2/pubspec.yaml b/pkgs/json_rpc_2/pubspec.yaml
new file mode 100644
index 0000000..7b42278
--- /dev/null
+++ b/pkgs/json_rpc_2/pubspec.yaml
@@ -0,0 +1,18 @@
+name: json_rpc_2
+version: 3.0.3
+description: >-
+ Utilities to write a client or server using the JSON-RPC 2.0 spec.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/json_rpc_2
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ajson_rpc_2
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ stack_trace: ^1.10.0
+ stream_channel: ^2.1.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.25.5
+ web_socket_channel: ^3.0.0
diff --git a/pkgs/json_rpc_2/test/client/client_test.dart b/pkgs/json_rpc_2/test/client/client_test.dart
new file mode 100644
index 0000000..1a4f65d
--- /dev/null
+++ b/pkgs/json_rpc_2/test/client/client_test.dart
@@ -0,0 +1,218 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:json_rpc_2/error_code.dart' as error_code;
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ late ClientController controller;
+
+ setUp(() => controller = ClientController());
+
+ test('sends a message and returns the response', () {
+ controller.expectRequest((request) {
+ expect(
+ request,
+ allOf([
+ containsPair('jsonrpc', '2.0'),
+ containsPair('method', 'foo'),
+ containsPair('params', {'param': 'value'})
+ ]));
+
+ return {'jsonrpc': '2.0', 'result': 'bar', 'id': request['id']};
+ });
+
+ expect(controller.client.sendRequest('foo', {'param': 'value'}),
+ completion(equals('bar')));
+ });
+
+ test('sends a message and returns the response with String id', () {
+ controller.expectRequest((request) {
+ expect(
+ request,
+ allOf([
+ containsPair('jsonrpc', '2.0'),
+ containsPair('method', 'foo'),
+ containsPair('params', {'param': 'value'})
+ ]));
+
+ return {
+ 'jsonrpc': '2.0',
+ 'result': 'bar',
+ 'id': request['id'].toString()
+ };
+ });
+
+ expect(controller.client.sendRequest('foo', {'param': 'value'}),
+ completion(equals('bar')));
+ });
+
+ test('sends a notification and expects no response', () {
+ controller.expectRequest((request) {
+ expect(
+ request,
+ equals({
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': {'param': 'value'}
+ }));
+ });
+
+ controller.client.sendNotification('foo', {'param': 'value'});
+ });
+
+ test('sends a notification with positional parameters', () {
+ controller.expectRequest((request) {
+ expect(
+ request,
+ equals({
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': ['value1', 'value2']
+ }));
+ });
+
+ controller.client.sendNotification('foo', ['value1', 'value2']);
+ });
+
+ test('sends a notification with no parameters', () {
+ controller.expectRequest((request) {
+ expect(request, equals({'jsonrpc': '2.0', 'method': 'foo'}));
+ });
+
+ controller.client.sendNotification('foo');
+ });
+
+ test('sends a synchronous batch of requests', () {
+ controller.expectRequest((request) {
+ expect(request, isA<List>());
+ expect(request, hasLength(3));
+ expect(request[0], equals({'jsonrpc': '2.0', 'method': 'foo'}));
+ expect(
+ request[1],
+ allOf([
+ containsPair('jsonrpc', '2.0'),
+ containsPair('method', 'bar'),
+ containsPair('params', {'param': 'value'})
+ ]));
+ expect(
+ request[2],
+ allOf(
+ [containsPair('jsonrpc', '2.0'), containsPair('method', 'baz')]));
+
+ return [
+ {'jsonrpc': '2.0', 'result': 'baz response', 'id': request[2]['id']},
+ {'jsonrpc': '2.0', 'result': 'bar response', 'id': request[1]['id']}
+ ];
+ });
+
+ controller.client.withBatch(() {
+ controller.client.sendNotification('foo');
+ expect(controller.client.sendRequest('bar', {'param': 'value'}),
+ completion(equals('bar response')));
+ expect(controller.client.sendRequest('baz'),
+ completion(equals('baz response')));
+ });
+ });
+
+ test('sends an asynchronous batch of requests', () {
+ controller.expectRequest((request) {
+ expect(request, isA<List>());
+ expect(request, hasLength(3));
+ expect(request[0], equals({'jsonrpc': '2.0', 'method': 'foo'}));
+ expect(
+ request[1],
+ allOf([
+ containsPair('jsonrpc', '2.0'),
+ containsPair('method', 'bar'),
+ containsPair('params', {'param': 'value'})
+ ]));
+ expect(
+ request[2],
+ allOf(
+ [containsPair('jsonrpc', '2.0'), containsPair('method', 'baz')]));
+
+ return [
+ {'jsonrpc': '2.0', 'result': 'baz response', 'id': request[2]['id']},
+ {'jsonrpc': '2.0', 'result': 'bar response', 'id': request[1]['id']}
+ ];
+ });
+
+ controller.client.withBatch(() {
+ return Future<void>.value().then<void>((_) {
+ controller.client.sendNotification('foo');
+ }).then<void>((_) {
+ expect(controller.client.sendRequest('bar', {'param': 'value'}),
+ completion(equals('bar response')));
+ }).then<void>((_) {
+ expect(controller.client.sendRequest('baz'),
+ completion(equals('baz response')));
+ });
+ });
+ });
+
+ test('reports an error from the server', () {
+ controller.expectRequest((request) {
+ expect(
+ request,
+ allOf(
+ [containsPair('jsonrpc', '2.0'), containsPair('method', 'foo')]));
+
+ return {
+ 'jsonrpc': '2.0',
+ 'error': {
+ 'code': error_code.SERVER_ERROR,
+ 'message': 'you are bad at requests',
+ 'data': 'some junk'
+ },
+ 'id': request['id']
+ };
+ });
+
+ expect(
+ controller.client.sendRequest('foo', {'param': 'value'}),
+ throwsA(isA<json_rpc.RpcException>()
+ .having((e) => e.code, 'code', error_code.SERVER_ERROR)
+ .having((e) => e.message, 'message', 'you are bad at requests')
+ .having((e) => e.data, 'data', 'some junk')));
+ });
+
+ test('requests throw StateErrors if the client is closed', () {
+ controller.client.close();
+ expect(() => controller.client.sendRequest('foo'), throwsStateError);
+ expect(() => controller.client.sendNotification('foo'), throwsStateError);
+ });
+
+ test('ignores bogus responses', () {
+ // Make a request so we have something to respond to.
+ controller.expectRequest((request) {
+ controller.sendJsonResponse('{invalid');
+ controller.sendResponse('not a map');
+ controller.sendResponse(
+ {'jsonrpc': 'wrong version', 'result': 'wrong', 'id': request['id']});
+ controller.sendResponse({'jsonrpc': '2.0', 'result': 'wrong'});
+ controller.sendResponse({'jsonrpc': '2.0', 'id': request['id']});
+ controller.sendResponse(
+ {'jsonrpc': '2.0', 'error': 'not a map', 'id': request['id']});
+ controller.sendResponse({
+ 'jsonrpc': '2.0',
+ 'error': {'code': 'not an int', 'message': 'dang yo'},
+ 'id': request['id']
+ });
+ controller.sendResponse({
+ 'jsonrpc': '2.0',
+ 'error': {'code': 123, 'message': 0xDEADBEEF},
+ 'id': request['id']
+ });
+
+ return pumpEventQueue().then(
+ (_) => {'jsonrpc': '2.0', 'result': 'right', 'id': request['id']});
+ });
+
+ expect(controller.client.sendRequest('foo'), completion(equals('right')));
+ });
+}
diff --git a/pkgs/json_rpc_2/test/client/stream_test.dart b/pkgs/json_rpc_2/test/client/stream_test.dart
new file mode 100644
index 0000000..b33778e
--- /dev/null
+++ b/pkgs/json_rpc_2/test/client/stream_test.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:stream_channel/stream_channel.dart';
+import 'package:test/test.dart';
+
+void main() {
+ late StreamController responseController;
+ late StreamController requestController;
+ late json_rpc.Client client;
+
+ setUp(() {
+ responseController = StreamController();
+ requestController = StreamController();
+ client = json_rpc.Client.withoutJson(
+ StreamChannel(responseController.stream, requestController.sink));
+ });
+
+ test('.withoutJson supports decoded stream and sink', () {
+ client.listen();
+
+ expect(requestController.stream.first.then((request) {
+ expect(
+ request,
+ allOf(
+ [containsPair('jsonrpc', '2.0'), containsPair('method', 'foo')]));
+
+ responseController
+ .add({'jsonrpc': '2.0', 'result': 'bar', 'id': request['id']});
+ }), completes);
+
+ client.sendRequest('foo');
+ });
+
+ test('.listen returns when the controller is closed', () {
+ var hasListenCompeted = false;
+ expect(client.listen().then((_) => hasListenCompeted = true), completes);
+
+ return pumpEventQueue().then((_) {
+ expect(hasListenCompeted, isFalse);
+
+ // This should cause listen to complete.
+ return responseController.close();
+ });
+ });
+
+ test('.listen returns a stream error', () {
+ expect(client.listen(), throwsA('oh no'));
+ responseController.addError('oh no');
+ });
+
+ test('.listen can\'t be called twice', () {
+ client.listen();
+ expect(() => client.listen(), throwsStateError);
+ });
+
+ test('.close cancels the stream subscription and closes the sink', () {
+ // Work around sdk#19095.
+ requestController.stream.listen(null);
+
+ expect(client.listen(), completes);
+
+ expect(client.isClosed, isFalse);
+ expect(client.close(), completes);
+ expect(client.isClosed, isTrue);
+
+ expect(() => responseController.stream.listen((_) {}), throwsStateError);
+ expect(requestController.isClosed, isTrue);
+ });
+
+ group('a stream error', () {
+ test('is reported through .done', () {
+ expect(client.listen(), throwsA('oh no!'));
+ expect(client.done, throwsA('oh no!'));
+ responseController.addError('oh no!');
+ });
+
+ test('cause a pending request to throw a StateError', () {
+ expect(client.listen(), throwsA('oh no!'));
+ expect(client.sendRequest('foo'), throwsStateError);
+ responseController.addError('oh no!');
+ });
+
+ test('causes future requests to throw StateErrors', () async {
+ expect(client.listen(), throwsA('oh no!'));
+ responseController.addError('oh no!');
+ await pumpEventQueue();
+
+ expect(() => client.sendRequest('foo'), throwsStateError);
+ expect(() => client.sendNotification('foo'), throwsStateError);
+ });
+ });
+}
diff --git a/pkgs/json_rpc_2/test/client/utils.dart b/pkgs/json_rpc_2/test/client/utils.dart
new file mode 100644
index 0000000..38e187f
--- /dev/null
+++ b/pkgs/json_rpc_2/test/client/utils.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:stream_channel/stream_channel.dart';
+import 'package:test/test.dart';
+
+/// A controller used to test a [json_rpc.Client].
+class ClientController {
+ /// The controller for the client's response stream.
+ final _responseController = StreamController<String>();
+
+ /// The controller for the client's request sink.
+ final _requestController = StreamController<String>();
+
+ /// The client.
+ late final json_rpc.Client client;
+
+ ClientController() {
+ client = json_rpc.Client(
+ StreamChannel(_responseController.stream, _requestController.sink));
+ client.listen();
+ }
+
+ /// Expects that the client will send a request.
+ ///
+ /// The request is passed to [callback], which can return a response. If it
+ /// returns a String, that's sent as the response directly. If it returns
+ /// null, no response is sent. Otherwise, the return value is encoded and sent
+ /// as the response.
+ void expectRequest(FutureOr Function(dynamic) callback) {
+ expect(
+ _requestController.stream.first.then((request) {
+ return callback(jsonDecode(request));
+ }).then((response) {
+ if (response == null) return;
+ if (response is! String) response = jsonEncode(response);
+ _responseController.add(response);
+ }),
+ completes);
+ }
+
+ /// Sends [response], a decoded response, to [client].
+ void sendResponse(Object? response) {
+ sendJsonResponse(jsonEncode(response));
+ }
+
+ /// Sends [request], a JSON-encoded response, to [client].
+ void sendJsonResponse(String request) {
+ _responseController.add(request);
+ }
+}
diff --git a/pkgs/json_rpc_2/test/peer_test.dart b/pkgs/json_rpc_2/test/peer_test.dart
new file mode 100644
index 0000000..0df6056
--- /dev/null
+++ b/pkgs/json_rpc_2/test/peer_test.dart
@@ -0,0 +1,251 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: inference_failure_on_instance_creation
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:json_rpc_2/error_code.dart' as error_code;
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:stream_channel/stream_channel.dart';
+import 'package:test/test.dart';
+
+void main() {
+ late StreamSink incoming;
+ late Stream outgoing;
+ late json_rpc.Peer peer;
+
+ setUp(() {
+ var incomingController = StreamController();
+ incoming = incomingController.sink;
+ var outgoingController = StreamController();
+ outgoing = outgoingController.stream;
+ peer = json_rpc.Peer.withoutJson(
+ StreamChannel(incomingController.stream, outgoingController));
+ });
+
+ group('like a client,', () {
+ test('can send a message and receive a response', () {
+ expect(outgoing.first.then((request) {
+ expect(
+ request,
+ equals({
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': {'bar': 'baz'},
+ 'id': 0
+ }));
+ incoming.add({'jsonrpc': '2.0', 'result': 'qux', 'id': 0});
+ }), completes);
+
+ peer.listen();
+ expect(
+ peer.sendRequest('foo', {'bar': 'baz'}), completion(equals('qux')));
+ });
+
+ test('can send a batch of messages and receive a batch of responses', () {
+ expect(outgoing.first.then((request) {
+ expect(
+ request,
+ equals([
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': {'bar': 'baz'},
+ 'id': 0
+ },
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'a',
+ 'params': {'b': 'c'},
+ 'id': 1
+ },
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'w',
+ 'params': {'x': 'y'},
+ 'id': 2
+ }
+ ]));
+
+ incoming.add([
+ {'jsonrpc': '2.0', 'result': 'qux', 'id': 0},
+ {'jsonrpc': '2.0', 'result': 'd', 'id': 1},
+ {'jsonrpc': '2.0', 'result': 'z', 'id': 2}
+ ]);
+ }), completes);
+
+ peer.listen();
+
+ peer.withBatch(() {
+ expect(
+ peer.sendRequest('foo', {'bar': 'baz'}), completion(equals('qux')));
+ expect(peer.sendRequest('a', {'b': 'c'}), completion(equals('d')));
+ expect(peer.sendRequest('w', {'x': 'y'}), completion(equals('z')));
+ });
+ });
+
+ test('requests terminates when the channel is closed', () async {
+ var incomingController = StreamController<void>();
+ var channel = StreamChannel.withGuarantees(
+ incomingController.stream,
+ StreamController<void>(),
+ );
+ var peer = json_rpc.Peer.withoutJson(channel);
+ unawaited(peer.listen());
+
+ var response = peer.sendRequest('foo');
+ await incomingController.close();
+
+ expect(response, throwsStateError);
+ });
+ });
+
+ test('can be closed', () async {
+ var incomingController = StreamController();
+ var channel = StreamChannel.withGuarantees(
+ incomingController.stream,
+ StreamController(),
+ );
+ var peer = json_rpc.Peer.withoutJson(channel);
+ unawaited(peer.listen());
+ await peer.close();
+ });
+
+ test('considered closed with misbehaving StreamChannel', () async {
+ // If a StreamChannel does not enforce the guarantees stated in it's
+ // contract - specifically that "Closing the sink causes the stream to close
+ // before it emits any more events." - The `Peer` should still understand
+ // when it has been closed manually.
+ var channel = StreamChannel(
+ StreamController().stream,
+ StreamController(),
+ );
+ var peer = json_rpc.Peer.withoutJson(channel);
+ unawaited(peer.listen());
+ unawaited(peer.close());
+ expect(peer.isClosed, true);
+ });
+
+ group('like a server,', () {
+ test('can receive a call and return a response', () {
+ expect(outgoing.first,
+ completion(equals({'jsonrpc': '2.0', 'result': 'qux', 'id': 0})));
+
+ peer.registerMethod('foo', (_) => 'qux');
+ peer.listen();
+
+ incoming.add({
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': {'bar': 'baz'},
+ 'id': 0
+ });
+ });
+
+ test('can receive a batch of calls and return a batch of responses', () {
+ expect(
+ outgoing.first,
+ completion(equals([
+ {'jsonrpc': '2.0', 'result': 'qux', 'id': 0},
+ {'jsonrpc': '2.0', 'result': 'd', 'id': 1},
+ {'jsonrpc': '2.0', 'result': 'z', 'id': 2}
+ ])));
+
+ peer.registerMethod('foo', (_) => 'qux');
+ peer.registerMethod('a', (_) => 'd');
+ peer.registerMethod('w', (_) => 'z');
+ peer.listen();
+
+ incoming.add([
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': {'bar': 'baz'},
+ 'id': 0
+ },
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'a',
+ 'params': {'b': 'c'},
+ 'id': 1
+ },
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'w',
+ 'params': {'x': 'y'},
+ 'id': 2
+ }
+ ]);
+ });
+
+ test('returns a response for malformed JSON', () {
+ var incomingController = StreamController<String>();
+ var outgoingController = StreamController<String>();
+ var jsonPeer = json_rpc.Peer(
+ StreamChannel(incomingController.stream, outgoingController));
+
+ expect(
+ outgoingController.stream.first.then(jsonDecode),
+ completion({
+ 'jsonrpc': '2.0',
+ 'error': {
+ 'code': error_code.PARSE_ERROR,
+ 'message': startsWith('Invalid JSON: '),
+ // TODO(nweiz): Always expect the source when sdk#25655 is fixed.
+ 'data': {
+ 'request': anyOf([isNull, '{invalid'])
+ }
+ },
+ 'id': null
+ }));
+
+ jsonPeer.listen();
+
+ incomingController.add('{invalid');
+ });
+
+ test('returns a response for incorrectly-structured JSON', () {
+ expect(
+ outgoing.first,
+ completion({
+ 'jsonrpc': '2.0',
+ 'error': {
+ 'code': error_code.INVALID_REQUEST,
+ 'message': 'Request must contain a "jsonrpc" key.',
+ 'data': {
+ 'request': {'completely': 'wrong'}
+ }
+ },
+ 'id': null
+ }));
+
+ peer.listen();
+
+ incoming.add({'completely': 'wrong'});
+ });
+ });
+
+ test('can notify on unhandled errors for if the method throws', () async {
+ var exception = Exception('test exception');
+ var incomingController = StreamController();
+ var outgoingController = StreamController();
+ final completer = Completer<Exception>();
+ peer = json_rpc.Peer.withoutJson(
+ StreamChannel(incomingController.stream, outgoingController),
+ onUnhandledError: (error, stack) {
+ completer.complete(error);
+ },
+ );
+ peer
+ ..registerMethod('foo', () => throw exception)
+ // ignore: unawaited_futures
+ ..listen();
+
+ incomingController.add({'jsonrpc': '2.0', 'method': 'foo'});
+ var receivedException = await completer.future;
+ expect(receivedException, equals(exception));
+ });
+}
diff --git a/pkgs/json_rpc_2/test/server/batch_test.dart b/pkgs/json_rpc_2/test/server/batch_test.dart
new file mode 100644
index 0000000..af883c4
--- /dev/null
+++ b/pkgs/json_rpc_2/test/server/batch_test.dart
@@ -0,0 +1,147 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:json_rpc_2/error_code.dart' as error_code;
+import 'package:json_rpc_2/src/parameters.dart' show Parameters;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ late ServerController controller;
+
+ setUp(() {
+ controller = ServerController();
+ controller.server
+ ..registerMethod('foo', () => 'foo')
+ ..registerMethod('id', (Parameters params) => params.value)
+ ..registerMethod('arg', (Parameters params) => params['arg'].value);
+ });
+
+ test('handles a batch of requests', () {
+ expect(
+ controller.handleRequest([
+ {'jsonrpc': '2.0', 'method': 'foo', 'id': 1},
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'id',
+ 'params': ['value'],
+ 'id': 2
+ },
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'arg',
+ 'params': {'arg': 'value'},
+ 'id': 3
+ }
+ ]),
+ completion(equals([
+ {'jsonrpc': '2.0', 'result': 'foo', 'id': 1},
+ {
+ 'jsonrpc': '2.0',
+ 'result': ['value'],
+ 'id': 2
+ },
+ {'jsonrpc': '2.0', 'result': 'value', 'id': 3}
+ ])));
+ });
+
+ test('handles errors individually', () {
+ expect(
+ controller.handleRequest([
+ {'jsonrpc': '2.0', 'method': 'foo', 'id': 1},
+ {'jsonrpc': '2.0', 'method': 'zap', 'id': 2},
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'arg',
+ 'params': {'arg': 'value'},
+ 'id': 3
+ }
+ ]),
+ completion(equals([
+ {'jsonrpc': '2.0', 'result': 'foo', 'id': 1},
+ {
+ 'jsonrpc': '2.0',
+ 'id': 2,
+ 'error': {
+ 'code': error_code.METHOD_NOT_FOUND,
+ 'message': 'Unknown method "zap".',
+ 'data': {
+ 'request': {'jsonrpc': '2.0', 'method': 'zap', 'id': 2}
+ },
+ }
+ },
+ {'jsonrpc': '2.0', 'result': 'value', 'id': 3}
+ ])));
+ });
+
+ test('handles notifications individually', () {
+ expect(
+ controller.handleRequest([
+ {'jsonrpc': '2.0', 'method': 'foo', 'id': 1},
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'id',
+ 'params': ['value']
+ },
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'arg',
+ 'params': {'arg': 'value'},
+ 'id': 3
+ }
+ ]),
+ completion(equals([
+ {'jsonrpc': '2.0', 'result': 'foo', 'id': 1},
+ {'jsonrpc': '2.0', 'result': 'value', 'id': 3}
+ ])));
+ });
+
+ test('returns nothing if every request is a notification', () {
+ expect(
+ controller.handleRequest([
+ {'jsonrpc': '2.0', 'method': 'foo'},
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'id',
+ 'params': ['value']
+ },
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'arg',
+ 'params': {'arg': 'value'}
+ }
+ ]),
+ doesNotComplete);
+ });
+
+ test('returns an error if the batch is empty', () {
+ expectErrorResponse(controller, [], error_code.INVALID_REQUEST,
+ 'A batch must contain at least one request.');
+ });
+
+ test('disallows nested batches', () {
+ expect(
+ controller.handleRequest([
+ [
+ {'jsonrpc': '2.0', 'method': 'foo', 'id': 1}
+ ]
+ ]),
+ completion(equals([
+ {
+ 'jsonrpc': '2.0',
+ 'id': null,
+ 'error': {
+ 'code': error_code.INVALID_REQUEST,
+ 'message': 'Request must be an Array or an Object.',
+ 'data': {
+ 'request': [
+ {'jsonrpc': '2.0', 'method': 'foo', 'id': 1}
+ ]
+ }
+ }
+ }
+ ])));
+ });
+}
diff --git a/pkgs/json_rpc_2/test/server/invalid_request_test.dart b/pkgs/json_rpc_2/test/server/invalid_request_test.dart
new file mode 100644
index 0000000..4fa4de1
--- /dev/null
+++ b/pkgs/json_rpc_2/test/server/invalid_request_test.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:json_rpc_2/error_code.dart' as error_code;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ late ServerController controller;
+ setUp(() => controller = ServerController());
+
+ test('a non-Array/Object request is invalid', () {
+ expectErrorResponse(controller, 'foo', error_code.INVALID_REQUEST,
+ 'Request must be an Array or an Object.');
+ });
+
+ test('requests must have a jsonrpc key', () {
+ expectErrorResponse(controller, {'method': 'foo', 'id': 1234},
+ error_code.INVALID_REQUEST, 'Request must contain a "jsonrpc" key.');
+ });
+
+ test('the jsonrpc version must be 2.0', () {
+ expectErrorResponse(
+ controller,
+ {'jsonrpc': '1.0', 'method': 'foo', 'id': 1234},
+ error_code.INVALID_REQUEST,
+ 'Invalid JSON-RPC version "1.0", expected "2.0".');
+ });
+
+ test('requests must have a method key', () {
+ expectErrorResponse(controller, {'jsonrpc': '2.0', 'id': 1234},
+ error_code.INVALID_REQUEST, 'Request must contain a "method" key.');
+ });
+
+ test('request method must be a string', () {
+ expectErrorResponse(
+ controller,
+ {'jsonrpc': '2.0', 'method': 1234, 'id': 1234},
+ error_code.INVALID_REQUEST,
+ 'Request method must be a string, but was 1234.');
+ });
+
+ test('request params must be an Array or Object', () {
+ expectErrorResponse(
+ controller,
+ {'jsonrpc': '2.0', 'method': 'foo', 'params': 1234, 'id': 1234},
+ error_code.INVALID_REQUEST,
+ 'Request params must be an Array or an Object, but was 1234.');
+ });
+
+ test('request id may not be an Array or Object', () {
+ expect(
+ controller.handleRequest({
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'id': {'bad': 'id'}
+ }),
+ completion(equals({
+ 'jsonrpc': '2.0',
+ 'id': null,
+ 'error': {
+ 'code': error_code.INVALID_REQUEST,
+ 'message': 'Request id must be a string, number, or null, but was '
+ '{"bad":"id"}.',
+ 'data': {
+ 'request': {
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'id': {'bad': 'id'}
+ }
+ }
+ }
+ })));
+ });
+
+ group('strict protocol checks disabled', () {
+ setUp(() => controller = ServerController(strictProtocolChecks: false));
+
+ test('and no jsonrpc param', () {
+ expectErrorResponse(controller, {'method': 'foo', 'id': 1234},
+ error_code.METHOD_NOT_FOUND, 'Unknown method "foo".');
+ });
+
+ test('the jsonrpc version must be 2.0', () {
+ expectErrorResponse(
+ controller,
+ {'jsonrpc': '1.0', 'method': 'foo', 'id': 1234},
+ error_code.INVALID_REQUEST,
+ 'Invalid JSON-RPC version "1.0", expected "2.0".');
+ });
+ });
+}
diff --git a/pkgs/json_rpc_2/test/server/parameters_test.dart b/pkgs/json_rpc_2/test/server/parameters_test.dart
new file mode 100644
index 0000000..9ecfb1f
--- /dev/null
+++ b/pkgs/json_rpc_2/test/server/parameters_test.dart
@@ -0,0 +1,403 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ group('with named parameters', () {
+ late json_rpc.Parameters parameters;
+ setUp(() {
+ parameters = json_rpc.Parameters('foo', {
+ 'num': 1.5,
+ 'int': 1,
+ 'bool': true,
+ 'string': 'zap',
+ 'list': [1, 2, 3],
+ 'date-time': '1990-01-01 00:00:00.000',
+ 'uri': 'https://dart.dev',
+ 'invalid-uri': 'http://[::1',
+ 'map': {'num': 4.2, 'bool': false}
+ });
+ });
+
+ test('value returns the wrapped value', () {
+ expect(
+ parameters.value,
+ equals({
+ 'num': 1.5,
+ 'int': 1,
+ 'bool': true,
+ 'string': 'zap',
+ 'list': [1, 2, 3],
+ 'date-time': '1990-01-01 00:00:00.000',
+ 'uri': 'https://dart.dev',
+ 'invalid-uri': 'http://[::1',
+ 'map': {'num': 4.2, 'bool': false}
+ }));
+ });
+
+ test('[int] throws a parameter error', () {
+ expect(
+ () => parameters[0],
+ throwsInvalidParams('Parameters for method "foo" must be passed by '
+ 'position.'));
+ });
+
+ test('[].value returns existing parameters', () {
+ expect(parameters['num'].value, equals(1.5));
+ });
+
+ test('[].valueOr returns existing parameters', () {
+ expect(parameters['num'].valueOr(7), equals(1.5));
+ });
+
+ test('[].value fails for absent parameters', () {
+ expect(
+ () => parameters['fblthp'].value,
+ throwsInvalidParams('Request for method "foo" is missing required '
+ 'parameter "fblthp".'));
+ });
+
+ test('[].valueOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].valueOr(7), equals(7));
+ });
+
+ test('[].exists returns true for existing parameters', () {
+ expect(parameters['num'].exists, isTrue);
+ });
+
+ test('[].exists returns false for missing parameters', () {
+ expect(parameters['fblthp'].exists, isFalse);
+ });
+
+ test('[].asNum returns numeric parameters', () {
+ expect(parameters['num'].asNum, equals(1.5));
+ expect(parameters['int'].asNum, equals(1));
+ });
+
+ test('[].asNumOr returns numeric parameters', () {
+ expect(parameters['num'].asNumOr(7), equals(1.5));
+ });
+
+ test('[].asNum fails for non-numeric parameters', () {
+ expect(
+ () => parameters['bool'].asNum,
+ throwsInvalidParams('Parameter "bool" for method "foo" must be a '
+ 'number, but was true.'));
+ });
+
+ test('[].asNumOr fails for non-numeric parameters', () {
+ expect(
+ () => parameters['bool'].asNumOr(7),
+ throwsInvalidParams('Parameter "bool" for method "foo" must be a '
+ 'number, but was true.'));
+ });
+
+ test('[].asNum fails for absent parameters', () {
+ expect(
+ () => parameters['fblthp'].asNum,
+ throwsInvalidParams('Request for method "foo" is missing required '
+ 'parameter "fblthp".'));
+ });
+
+ test('[].asNumOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].asNumOr(7), equals(7));
+ });
+
+ test('[].asInt returns integer parameters', () {
+ expect(parameters['int'].asInt, equals(1));
+ });
+
+ test('[].asIntOr returns integer parameters', () {
+ expect(parameters['int'].asIntOr(7), equals(1));
+ });
+
+ test('[].asInt fails for non-integer parameters', () {
+ expect(
+ () => parameters['bool'].asInt,
+ throwsInvalidParams('Parameter "bool" for method "foo" must be an '
+ 'integer, but was true.'));
+ });
+
+ test('[].asIntOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].asIntOr(7), equals(7));
+ });
+
+ test('[].asBool returns boolean parameters', () {
+ expect(parameters['bool'].asBool, isTrue);
+ });
+
+ test('[].asBoolOr returns boolean parameters', () {
+ expect(parameters['bool'].asBoolOr(false), isTrue);
+ });
+
+ test('[].asBoolOr fails for non-boolean parameters', () {
+ expect(
+ () => parameters['int'].asBool,
+ throwsInvalidParams('Parameter "int" for method "foo" must be a '
+ 'boolean, but was 1.'));
+ });
+
+ test('[].asBoolOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].asBoolOr(false), isFalse);
+ });
+
+ test('[].asString returns string parameters', () {
+ expect(parameters['string'].asString, equals('zap'));
+ });
+
+ test('[].asStringOr returns string parameters', () {
+ expect(parameters['string'].asStringOr('bap'), equals('zap'));
+ });
+
+ test('[].asString fails for non-string parameters', () {
+ expect(
+ () => parameters['int'].asString,
+ throwsInvalidParams('Parameter "int" for method "foo" must be a '
+ 'string, but was 1.'));
+ });
+
+ test('[].asStringOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].asStringOr('bap'), equals('bap'));
+ });
+
+ test('[].asList returns list parameters', () {
+ expect(parameters['list'].asList, equals([1, 2, 3]));
+ });
+
+ test('[].asListOr returns list parameters', () {
+ expect(parameters['list'].asListOr([5, 6, 7]), equals([1, 2, 3]));
+ });
+
+ test('[].asList fails for non-list parameters', () {
+ expect(
+ () => parameters['int'].asList,
+ throwsInvalidParams('Parameter "int" for method "foo" must be an '
+ 'Array, but was 1.'));
+ });
+
+ test('[].asListOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].asListOr([5, 6, 7]), equals([5, 6, 7]));
+ });
+
+ test('[].asMap returns map parameters', () {
+ expect(parameters['map'].asMap, equals({'num': 4.2, 'bool': false}));
+ });
+
+ test('[].asMapOr returns map parameters', () {
+ expect(
+ parameters['map'].asMapOr({}), equals({'num': 4.2, 'bool': false}));
+ });
+
+ test('[].asMap fails for non-map parameters', () {
+ expect(
+ () => parameters['int'].asMap,
+ throwsInvalidParams('Parameter "int" for method "foo" must be an '
+ 'Object, but was 1.'));
+ });
+
+ test('[].asMapOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].asMapOr({}), equals({}));
+ });
+
+ test('[].asDateTime returns date/time parameters', () {
+ expect(parameters['date-time'].asDateTime, equals(DateTime(1990)));
+ });
+
+ test('[].asDateTimeOr returns date/time parameters', () {
+ expect(parameters['date-time'].asDateTimeOr(DateTime(2014)),
+ equals(DateTime(1990)));
+ });
+
+ test('[].asDateTime fails for non-date/time parameters', () {
+ expect(
+ () => parameters['int'].asDateTime,
+ throwsInvalidParams('Parameter "int" for method "foo" must be a '
+ 'string, but was 1.'));
+ });
+
+ test('[].asDateTimeOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].asDateTimeOr(DateTime(2014)),
+ equals(DateTime(2014)));
+ });
+
+ test('[].asDateTime fails for non-date/time parameters', () {
+ expect(
+ () => parameters['int'].asDateTime,
+ throwsInvalidParams('Parameter "int" for method "foo" must be a '
+ 'string, but was 1.'));
+ });
+
+ test('[].asDateTime fails for invalid date/times', () {
+ expect(
+ () => parameters['string'].asDateTime,
+ throwsInvalidParams('Parameter "string" for method "foo" must be a '
+ 'valid date/time, but was "zap".\n'
+ 'Invalid date format'));
+ });
+
+ test('[].asUri returns URI parameters', () {
+ expect(parameters['uri'].asUri, equals(Uri.parse('https://dart.dev')));
+ });
+
+ test('[].asUriOr returns URI parameters', () {
+ expect(parameters['uri'].asUriOr(Uri.parse('http://google.com')),
+ equals(Uri.parse('https://dart.dev')));
+ });
+
+ test('[].asUri fails for non-URI parameters', () {
+ expect(
+ () => parameters['int'].asUri,
+ throwsInvalidParams('Parameter "int" for method "foo" must be a '
+ 'string, but was 1.'));
+ });
+
+ test('[].asUriOr succeeds for absent parameters', () {
+ expect(parameters['fblthp'].asUriOr(Uri.parse('http://google.com')),
+ equals(Uri.parse('http://google.com')));
+ });
+
+ test('[].asUri fails for non-URI parameters', () {
+ expect(
+ () => parameters['int'].asUri,
+ throwsInvalidParams('Parameter "int" for method "foo" must be a '
+ 'string, but was 1.'));
+ });
+
+ test('[].asUri fails for invalid URIs', () {
+ expect(
+ () => parameters['invalid-uri'].asUri,
+ throwsInvalidParams('Parameter "invalid-uri" for method "foo" must '
+ 'be a valid URI, but was "http://[::1".\n'
+ 'Missing end `]` to match `[` in host'));
+ });
+
+ group('with a nested parameter map', () {
+ late json_rpc.Parameter nested;
+ setUp(() => nested = parameters['map']);
+
+ test('[int] fails with a type error', () {
+ expect(
+ () => nested[0],
+ throwsInvalidParams('Parameter "map" for method "foo" must be an '
+ 'Array, but was {"num":4.2,"bool":false}.'));
+ });
+
+ test('[].value returns existing parameters', () {
+ expect(nested['num'].value, equals(4.2));
+ expect(nested['bool'].value, isFalse);
+ });
+
+ test('[].value fails for absent parameters', () {
+ expect(
+ () => nested['fblthp'].value,
+ throwsInvalidParams('Request for method "foo" is missing required '
+ 'parameter map.fblthp.'));
+ });
+
+ test('typed getters return correctly-typed parameters', () {
+ expect(nested['num'].asNum, equals(4.2));
+ });
+
+ test('typed getters fail for incorrectly-typed parameters', () {
+ expect(
+ () => nested['bool'].asNum,
+ throwsInvalidParams('Parameter map.bool for method "foo" must be '
+ 'a number, but was false.'));
+ });
+ });
+
+ group('with a nested parameter list', () {
+ late json_rpc.Parameter nested;
+
+ setUp(() => nested = parameters['list']);
+
+ test('[string] fails with a type error', () {
+ expect(
+ () => nested['foo'],
+ throwsInvalidParams('Parameter "list" for method "foo" must be an '
+ 'Object, but was [1,2,3].'));
+ });
+
+ test('[].value returns existing parameters', () {
+ expect(nested[0].value, equals(1));
+ expect(nested[1].value, equals(2));
+ });
+
+ test('[].value fails for absent parameters', () {
+ expect(
+ () => nested[5].value,
+ throwsInvalidParams('Request for method "foo" is missing required '
+ 'parameter list[5].'));
+ });
+
+ test('typed getters return correctly-typed parameters', () {
+ expect(nested[0].asInt, equals(1));
+ });
+
+ test('typed getters fail for incorrectly-typed parameters', () {
+ expect(
+ () => nested[0].asBool,
+ throwsInvalidParams('Parameter list[0] for method "foo" must be '
+ 'a boolean, but was 1.'));
+ });
+ });
+ });
+
+ group('with positional parameters', () {
+ late json_rpc.Parameters parameters;
+ setUp(() => parameters = json_rpc.Parameters('foo', [1, 2, 3, 4, 5]));
+
+ test('value returns the wrapped value', () {
+ expect(parameters.value, equals([1, 2, 3, 4, 5]));
+ });
+
+ test('[string] throws a parameter error', () {
+ expect(
+ () => parameters['foo'],
+ throwsInvalidParams('Parameters for method "foo" must be passed by '
+ 'name.'));
+ });
+
+ test('[].value returns existing parameters', () {
+ expect(parameters[2].value, equals(3));
+ });
+
+ test('[].value fails for out-of-range parameters', () {
+ expect(
+ () => parameters[10].value,
+ throwsInvalidParams('Request for method "foo" is missing required '
+ 'parameter 11.'));
+ });
+
+ test('[].exists returns true for existing parameters', () {
+ expect(parameters[0].exists, isTrue);
+ });
+
+ test('[].exists returns false for missing parameters', () {
+ expect(parameters[10].exists, isFalse);
+ });
+ });
+
+ test('with a complex parameter path', () {
+ var parameters = json_rpc.Parameters('foo', {
+ 'bar baz': [
+ 0,
+ 1,
+ 2,
+ {
+ 'bang.zap': {'\n': 'qux'}
+ }
+ ]
+ });
+
+ expect(
+ () => parameters['bar baz'][3]['bang.zap']['\n']['bip'],
+ throwsInvalidParams('Parameter "bar baz"[3]."bang.zap"."\\n" for '
+ 'method "foo" must be an Object, but was "qux".'));
+ });
+}
diff --git a/pkgs/json_rpc_2/test/server/server_test.dart b/pkgs/json_rpc_2/test/server/server_test.dart
new file mode 100644
index 0000000..b3166ce
--- /dev/null
+++ b/pkgs/json_rpc_2/test/server/server_test.dart
@@ -0,0 +1,203 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:json_rpc_2/error_code.dart' as error_code;
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ late ServerController controller;
+
+ setUp(() => controller = ServerController());
+
+ test('calls a registered method with the given name', () {
+ controller.server.registerMethod('foo', (json_rpc.Parameters params) {
+ return {'params': params.value};
+ });
+
+ expect(
+ controller.handleRequest({
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': {'param': 'value'},
+ 'id': 1234
+ }),
+ completion(equals({
+ 'jsonrpc': '2.0',
+ 'result': {
+ 'params': {'param': 'value'}
+ },
+ 'id': 1234
+ })));
+ });
+
+ test('calls a method that takes no parameters', () {
+ controller.server.registerMethod('foo', () => 'foo');
+
+ expect(
+ controller
+ .handleRequest({'jsonrpc': '2.0', 'method': 'foo', 'id': 1234}),
+ completion(equals({'jsonrpc': '2.0', 'result': 'foo', 'id': 1234})));
+ });
+
+ test('Allows a `null` result', () {
+ controller.server.registerMethod('foo', () => null);
+
+ expect(
+ controller
+ .handleRequest({'jsonrpc': '2.0', 'method': 'foo', 'id': 1234}),
+ completion(equals({'jsonrpc': '2.0', 'result': null, 'id': 1234})));
+ });
+
+ test('a method that takes no parameters rejects parameters', () {
+ controller.server.registerMethod('foo', () => 'foo');
+
+ expectErrorResponse(
+ controller,
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': <String, dynamic>{},
+ 'id': 1234
+ },
+ error_code.INVALID_PARAMS,
+ 'No parameters are allowed for method "foo".');
+ });
+
+ test('an unexpected error in a method is captured', () {
+ controller.server
+ .registerMethod('foo', () => throw const FormatException('bad format'));
+
+ expect(
+ controller
+ .handleRequest({'jsonrpc': '2.0', 'method': 'foo', 'id': 1234}),
+ completion({
+ 'jsonrpc': '2.0',
+ 'id': 1234,
+ 'error': {
+ 'code': error_code.SERVER_ERROR,
+ 'message': 'bad format',
+ 'data': {
+ 'request': {'jsonrpc': '2.0', 'method': 'foo', 'id': 1234},
+ 'full': 'FormatException: bad format',
+ 'stack': isA<String>()
+ }
+ }
+ }));
+ });
+
+ test('doesn\'t return a result for a notification', () {
+ controller.server.registerMethod('foo', (args) => 'result');
+
+ expect(
+ controller.handleRequest(
+ {'jsonrpc': '2.0', 'method': 'foo', 'params': <String, dynamic>{}}),
+ doesNotComplete);
+ });
+
+ test('includes the error data in the response', () {
+ controller.server.registerMethod('foo', (params) {
+ throw json_rpc.RpcException(5, 'Error message.', data: 'data value');
+ });
+
+ expectErrorResponse(
+ controller,
+ {
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': <String, dynamic>{},
+ 'id': 1234
+ },
+ 5,
+ 'Error message.',
+ data: 'data value');
+ });
+
+ test('a JSON parse error is rejected', () {
+ return controller.handleJsonRequest('invalid json {').then((result) {
+ expect(jsonDecode(result), {
+ 'jsonrpc': '2.0',
+ 'error': {
+ 'code': error_code.PARSE_ERROR,
+ 'message': startsWith('Invalid JSON: '),
+ // TODO(nweiz): Always expect the source when sdk#25655 is fixed.
+ 'data': {
+ 'request': anyOf([isNull, 'invalid json {'])
+ }
+ },
+ 'id': null
+ });
+ });
+ });
+
+ group('fallbacks', () {
+ test('calls a fallback if no method matches', () {
+ controller.server
+ ..registerMethod('foo', () => 'foo')
+ ..registerMethod('bar', () => 'foo')
+ ..registerFallback((params) => {'fallback': params.value});
+
+ expect(
+ controller.handleRequest({
+ 'jsonrpc': '2.0',
+ 'method': 'baz',
+ 'params': {'param': 'value'},
+ 'id': 1234
+ }),
+ completion(equals({
+ 'jsonrpc': '2.0',
+ 'result': {
+ 'fallback': {'param': 'value'}
+ },
+ 'id': 1234
+ })));
+ });
+
+ test('calls the first matching fallback', () {
+ controller.server
+ ..registerFallback((params) =>
+ throw json_rpc.RpcException.methodNotFound(params.method))
+ ..registerFallback((params) => 'fallback 2')
+ ..registerFallback((params) => 'fallback 3');
+
+ expect(
+ controller.handleRequest(
+ {'jsonrpc': '2.0', 'method': 'fallback 2', 'id': 1234}),
+ completion(
+ equals({'jsonrpc': '2.0', 'result': 'fallback 2', 'id': 1234})));
+ });
+
+ test('an unexpected error in a fallback is captured', () {
+ controller.server
+ .registerFallback((_) => throw const FormatException('bad format'));
+
+ expect(
+ controller
+ .handleRequest({'jsonrpc': '2.0', 'method': 'foo', 'id': 1234}),
+ completion({
+ 'jsonrpc': '2.0',
+ 'id': 1234,
+ 'error': {
+ 'code': error_code.SERVER_ERROR,
+ 'message': 'bad format',
+ 'data': {
+ 'request': {'jsonrpc': '2.0', 'method': 'foo', 'id': 1234},
+ 'full': 'FormatException: bad format',
+ 'stack': isA<String>()
+ }
+ }
+ }));
+ });
+ });
+
+ test('disallows multiple methods with the same name', () {
+ controller.server.registerMethod('foo', () => null);
+ expect(() => controller.server.registerMethod('foo', () => null),
+ throwsArgumentError);
+ });
+}
diff --git a/pkgs/json_rpc_2/test/server/stream_test.dart b/pkgs/json_rpc_2/test/server/stream_test.dart
new file mode 100644
index 0000000..832e13c
--- /dev/null
+++ b/pkgs/json_rpc_2/test/server/stream_test.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:stream_channel/stream_channel.dart';
+import 'package:test/test.dart';
+
+void main() {
+ late StreamController requestController;
+ late StreamController responseController;
+ late json_rpc.Server server;
+
+ setUp(() {
+ requestController = StreamController();
+ responseController = StreamController();
+ server = json_rpc.Server.withoutJson(
+ StreamChannel(requestController.stream, responseController.sink));
+ });
+
+ test('.withoutJson supports decoded stream and sink', () {
+ server.listen();
+
+ server.registerMethod('foo', (json_rpc.Parameters params) {
+ return {'params': params.value};
+ });
+
+ requestController.add({
+ 'jsonrpc': '2.0',
+ 'method': 'foo',
+ 'params': {'param': 'value'},
+ 'id': 1234
+ });
+
+ expect(
+ responseController.stream.first,
+ completion(equals({
+ 'jsonrpc': '2.0',
+ 'result': {
+ 'params': {'param': 'value'}
+ },
+ 'id': 1234
+ })));
+ });
+
+ test('.listen returns when the controller is closed', () {
+ var hasListenCompeted = false;
+ expect(server.listen().then((_) => hasListenCompeted = true), completes);
+
+ return pumpEventQueue().then((_) {
+ expect(hasListenCompeted, isFalse);
+
+ // This should cause listen to complete.
+ return requestController.close();
+ });
+ });
+
+ test('.listen returns a stream error', () {
+ expect(server.listen(), throwsA('oh no'));
+ requestController.addError('oh no');
+ });
+
+ test('.listen can\'t be called twice', () {
+ server.listen();
+
+ expect(() => server.listen(), throwsStateError);
+ });
+
+ test('.close cancels the stream subscription and closes the sink', () {
+ // Work around sdk#19095.
+ responseController.stream.listen(null);
+
+ expect(server.listen(), completes);
+
+ expect(server.isClosed, isFalse);
+ expect(server.close(), completes);
+ expect(server.isClosed, isTrue);
+
+ expect(() => requestController.stream.listen((_) {}), throwsStateError);
+ expect(responseController.isClosed, isTrue);
+ });
+}
diff --git a/pkgs/json_rpc_2/test/server/utils.dart b/pkgs/json_rpc_2/test/server/utils.dart
new file mode 100644
index 0000000..c94628e
--- /dev/null
+++ b/pkgs/json_rpc_2/test/server/utils.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:json_rpc_2/error_code.dart' as error_code;
+import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
+import 'package:stream_channel/stream_channel.dart';
+import 'package:test/test.dart';
+
+/// A controller used to test a [json_rpc.Server].
+class ServerController {
+ /// The controller for the server's request stream.
+ final _requestController = StreamController<String>();
+
+ /// The controller for the server's response sink.
+ final _responseController = StreamController<String>();
+
+ /// The server.
+ late final json_rpc.Server server;
+
+ ServerController(
+ {json_rpc.ErrorCallback? onUnhandledError,
+ bool strictProtocolChecks = true}) {
+ server = json_rpc.Server(
+ StreamChannel(_requestController.stream, _responseController.sink),
+ onUnhandledError: onUnhandledError,
+ strictProtocolChecks: strictProtocolChecks);
+ server.listen();
+ }
+
+ /// Passes [request], a decoded request, to [server] and returns its decoded
+ /// response.
+ Future handleRequest(Object? request) =>
+ handleJsonRequest(jsonEncode(request)).then(jsonDecode);
+
+ /// Passes [request], a JSON-encoded request, to [server] and returns its
+ /// encoded response.
+ Future<String> handleJsonRequest(String request) {
+ _requestController.add(request);
+ return _responseController.stream.first;
+ }
+}
+
+/// Expects that [controller]'s server will return an error response to
+/// [request] with the given [errorCode], [message], and [data].
+void expectErrorResponse(
+ ServerController controller, Object? request, int errorCode, String message,
+ {Object? data}) {
+ dynamic id;
+ if (request is Map) id = request['id'];
+ data ??= {'request': request};
+
+ expect(
+ controller.handleRequest(request),
+ completion(equals({
+ 'jsonrpc': '2.0',
+ 'id': id,
+ 'error': {'code': errorCode, 'message': message, 'data': data}
+ })));
+}
+
+/// Returns a matcher that matches a [json_rpc.RpcException] with an
+/// `invalid_params` error code.
+Matcher throwsInvalidParams(String message) =>
+ throwsA(isA<json_rpc.RpcException>()
+ .having((e) => e.code, 'code', error_code.INVALID_PARAMS)
+ .having((e) => e.message, 'message', message));
diff --git a/pkgs/mime/.gitignore b/pkgs/mime/.gitignore
new file mode 100644
index 0000000..a433102
--- /dev/null
+++ b/pkgs/mime/.gitignore
@@ -0,0 +1,5 @@
+.packages
+.dart_tool/
+.pub/
+packages
+pubspec.lock
diff --git a/pkgs/mime/AUTHORS b/pkgs/mime/AUTHORS
new file mode 100644
index 0000000..e8063a8
--- /dev/null
+++ b/pkgs/mime/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/mime/CHANGELOG.md b/pkgs/mime/CHANGELOG.md
new file mode 100644
index 0000000..fd5a249
--- /dev/null
+++ b/pkgs/mime/CHANGELOG.md
@@ -0,0 +1,110 @@
+## 2.0.0
+
+* **[Breaking]** `extensionFromMime(String mimeType)` returns `null` instead of `mimeType` for an unknown mime type.
+* Update `extensionFromMime` to return a default extension when a MIME type maps to multiple extensions.
+
+## 1.0.6
+
+* Add `topics` section to `pubspec.yaml`.
+* Move to `dart-lang/tools` monorepo.
+
+## 1.0.5
+
+* Update `video/mp4` mimeType lookup by header bytes.
+* Add `image/heic` mimeType lookup by header bytes.
+* Add `image/heif` mimeType lookup by header bytes.
+* Add m4b mimeType lookup by extension.
+* Add `text/markdown` mimeType lookup by extension.
+* Require Dart 3.2.0.
+
+## 1.0.4
+
+* Changed `.js` to `text/javascript` per
+ https://datatracker.ietf.org/doc/html/rfc9239.
+* Added `.mjs` as `text/javascript`.
+* Add `application/dicom` mimeType lookup by extension.
+* Require Dart 2.18.
+
+## 1.0.3
+
+* Add application/manifest+json lookup by extension.
+* Add application/toml mimeType lookup by extension.
+* Add audio/aac mimeType lookup by header bytes.
+* Add audio/mpeg mimeType lookup by header bytes.
+* Add audio/ogg mimeType lookup by header bytes.
+* Add audio/weba mimeType lookup by header bytes.
+* Add font/woff2 lookup by extension and header bytes.
+* Add image/avif mimeType lookup by extension.
+* Add image/heic mimeType lookup by extension.
+* Add image/heif mimeType lookup by extension.
+* Change audio/x-aac to audio/aac when detected by extension.
+
+## 1.0.2
+
+* Add audio/x-aiff mimeType lookup by header bytes.
+* Add audio/x-flac mimeType lookup by header bytes.
+* Add audio/x-wav mimeType lookup by header bytes.
+* Add audio/mp4 mimeType lookup by file path.
+
+## 1.0.1
+
+* Add image/webp mimeType lookup by header bytes.
+
+## 1.0.0
+
+* Stable null safety release.
+
+## 1.0.0-nullsafety.0
+
+* Update to null safety.
+
+## 0.9.7
+
+* Add `extensionFromMime` utility function.
+
+## 0.9.6+3
+
+* Change the mime type for Dart source from `application/dart` to `text/x-dart`.
+* Add example.
+* Fix links and code in README.
+
+## 0.9.6+2
+
+* Set max SDK version to `<3.0.0`, and adjust other dependencies.
+
+## 0.9.6+1
+
+* Stop using deprecated constants from the SDK.
+
+## 0.9.6
+
+* Updates to support Dart 2.0 core library changes (wave
+ 2.2). See [issue 31847][sdk#31847] for details.
+
+ [sdk#31847]: https://github.com/dart-lang/sdk/issues/31847
+
+## 0.9.5
+
+* Add support for the WebAssembly format.
+
+## 0.9.4
+
+* Updated Dart SDK requirement to `>= 1.8.3 <2.0.0`
+
+* Strong-mode clean.
+
+* Added support for glTF text and binary formats.
+
+## 0.9.3
+
+* Fixed erroneous behavior for listening and when pausing/resuming
+ stream of parts.
+
+## 0.9.2
+
+* Fixed erroneous behavior when pausing/canceling stream of parts but already
+ listened to one part.
+
+## 0.9.1
+
+* Handle parsing of MIME multipart content with no parts.
diff --git a/pkgs/mime/CONTRIBUTING.md b/pkgs/mime/CONTRIBUTING.md
new file mode 100644
index 0000000..463063a
--- /dev/null
+++ b/pkgs/mime/CONTRIBUTING.md
@@ -0,0 +1,37 @@
+Want to contribute? Great! First, read this page (including the small print at
+the end).
+
+### Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Code reviews
+All submissions, including submissions by project members, require review.
+
+### File headers
+All files in the project must start with the following header.
+
+ // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+ // for details. All rights reserved. Use of this source code is governed by a
+ // BSD-style license that can be found in the LICENSE file.
+
+### The small print
+Contributions made by corporations are covered by a different agreement than the
+one above, the
+[Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate).
+
+### Adding an extension / MIME type mapping
+If a MIME type ends up with multiple extensions, it is recommended to define a
+preferred extension in `_defaultMimeTypeMap` in [extension.dart](lib/src/extension.dart).
\ No newline at end of file
diff --git a/pkgs/mime/LICENSE b/pkgs/mime/LICENSE
new file mode 100644
index 0000000..dbd2843
--- /dev/null
+++ b/pkgs/mime/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2015, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/mime/README.md b/pkgs/mime/README.md
new file mode 100644
index 0000000..da06de6
--- /dev/null
+++ b/pkgs/mime/README.md
@@ -0,0 +1,70 @@
+[](https://github.com/dart-lang/tools/actions/workflows/mime.yml)
+[](https://pub.dev/packages/mime)
+[](https://pub.dev/packages/mime/publisher)
+
+Package for working with MIME type definitions and for processing
+streams of MIME multipart media types.
+
+## Determining the MIME type for a file
+
+The `MimeTypeResolver` class can be used to determine the MIME type of
+a file. It supports both using the extension of the file name and
+looking at magic bytes from the beginning of the file.
+
+There is a builtin instance of `MimeTypeResolver` accessible through
+the top level function `lookupMimeType`. This builtin instance has
+the most common file name extensions and magic bytes registered.
+
+```dart
+import 'package:mime/mime.dart';
+
+void main() {
+ print(lookupMimeType('test.html'));
+ // text/html
+
+ print(lookupMimeType('test', headerBytes: [0xFF, 0xD8]));
+ // image/jpeg
+
+ print(lookupMimeType('test.html', headerBytes: [0xFF, 0xD8]));
+ // image/jpeg
+}
+```
+
+You can build you own resolver by creating an instance of
+`MimeTypeResolver` and adding file name extensions and magic bytes
+using `addExtension` and `addMagicNumber`.
+
+## Processing MIME multipart media types
+
+The class `MimeMultipartTransformer` is used to process a `Stream` of
+bytes encoded using a MIME multipart media types encoding. The
+transformer provides a new `Stream` of `MimeMultipart` objects each of
+which have the headers and the content of each part. The content of a
+part is provided as a stream of bytes.
+
+Below is an example showing how to process an HTTP request and print
+the length of the content of each part.
+
+```dart
+// HTTP request with content type multipart/form-data.
+HttpRequest request = ...;
+// Determine the boundary form the content type header
+String boundary = request.headers.contentType.parameters['boundary'];
+
+// Process the body just calculating the length of each part.
+request
+ .transform(new MimeMultipartTransformer(boundary))
+ .map((part) => part.fold(0, (p, d) => p + d))
+ .listen((length) => print('Part with length $length'));
+```
+
+## Determining file extension by MIME type
+
+The top level function `extensionFromMime` can be used to determine the
+file extension of a given MIME type.
+
+```dart
+print(extensionFromMime('text/html')); // Prints "html".
+print(extensionFromMime('image/jpeg')); // Prints "jpg".
+print(extensionFromMime('application/pdf')); // Prints "pdf".
+```
diff --git a/pkgs/mime/analysis_options.yaml b/pkgs/mime/analysis_options.yaml
new file mode 100644
index 0000000..dc212e7
--- /dev/null
+++ b/pkgs/mime/analysis_options.yaml
@@ -0,0 +1,33 @@
+# https://dart.dev/tools/analysis#the-analysis-options-file
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_classes_with_only_static_members
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_returning_this
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - join_return_with_assignment
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - no_runtimeType_toString
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - unnecessary_await_in_return
+ - unnecessary_breaks
+ - unnecessary_raw_strings
+ - use_if_null_to_convert_nulls_to_bools
+ - use_raw_strings
+ - use_string_buffers
diff --git a/pkgs/mime/example/example.dart b/pkgs/mime/example/example.dart
new file mode 100644
index 0000000..b54f8e7
--- /dev/null
+++ b/pkgs/mime/example/example.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:mime/mime.dart';
+
+void main() {
+ print(lookupMimeType('test.html'));
+ // text/html
+
+ print(lookupMimeType('test', headerBytes: [0xFF, 0xD8]));
+ // image/jpeg
+
+ print(lookupMimeType('test.html', headerBytes: [0xFF, 0xD8]));
+ // image/jpeg
+}
diff --git a/pkgs/mime/lib/mime.dart b/pkgs/mime/lib/mime.dart
new file mode 100644
index 0000000..cb45098
--- /dev/null
+++ b/pkgs/mime/lib/mime.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Help for working with file format identifiers
+/// such as `text/html` and `image/png`.
+///
+/// More details, including a list of types, are in the Wikipedia article
+/// [Internet media type](http://en.wikipedia.org/wiki/Internet_media_type).
+library;
+
+export 'src/extension.dart';
+export 'src/mime_multipart_transformer.dart';
+export 'src/mime_shared.dart';
+export 'src/mime_type.dart';
diff --git a/pkgs/mime/lib/src/bound_multipart_stream.dart b/pkgs/mime/lib/src/bound_multipart_stream.dart
new file mode 100644
index 0000000..03b213b
--- /dev/null
+++ b/pkgs/mime/lib/src/bound_multipart_stream.dart
@@ -0,0 +1,372 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'char_code.dart' as char_code;
+import 'mime_shared.dart';
+
+/// Bytes for `()<>@,;:\\"/[]?={} \t`.
+const _separators = {
+ 40, 41, 60, 62, 64, 44, 59, 58, 92, 34, 47, 91, 93, 63, 61, 123, 125, 32, 9 //
+};
+
+bool _isTokenChar(int byte) =>
+ byte > 31 && byte < 128 && !_separators.contains(byte);
+
+int _toLowerCase(int byte) {
+ const delta = char_code.lowerA - char_code.upperA;
+ return (char_code.upperA <= byte && byte <= char_code.upperZ)
+ ? byte + delta
+ : byte;
+}
+
+void _expectByteValue(int val1, int val2) {
+ if (val1 != val2) {
+ throw const MimeMultipartException('Failed to parse multipart mime 1');
+ }
+}
+
+void _expectWhitespace(int byte) {
+ if (byte != char_code.sp && byte != char_code.ht) {
+ throw const MimeMultipartException('Failed to parse multipart mime 2');
+ }
+}
+
+class _MimeMultipart extends MimeMultipart {
+ @override
+ final Map<String, String> headers;
+ final Stream<List<int>> _stream;
+
+ _MimeMultipart(this.headers, this._stream);
+
+ @override
+ StreamSubscription<List<int>> listen(
+ void Function(List<int> data)? onData, {
+ void Function()? onDone,
+ Function? onError,
+ bool? cancelOnError,
+ }) =>
+ _stream.listen(
+ onData,
+ onDone: onDone,
+ onError: onError,
+ cancelOnError: cancelOnError,
+ );
+}
+
+class BoundMultipartStream {
+ static const int _startCode = 0;
+ static const int _boundaryEndingCode = 1;
+ static const int _boundaryEndCode = 2;
+ static const int _headerStartCode = 3;
+ static const int _headerFieldCode = 4;
+ static const int _headerValueStartCode = 5;
+ static const int _headerValueCode = 6;
+ static const int _headerValueFoldingOrEndingCode = 7;
+ static const int _headerValueFoldOrEndCode = 8;
+ static const int _headerEndingCode = 9;
+ static const int _contentCode = 10;
+ static const int _lastBoundaryDash2Code = 11;
+ static const int _lastBoundaryEndingCode = 12;
+ static const int _lastBoundaryEndCode = 13;
+ static const int _doneCode = 14;
+ static const int _failCode = 15;
+
+ final List<int> _boundary;
+ final List<int> _headerField = [];
+ final List<int> _headerValue = [];
+
+ // The following states belong to `_controller`, state changes will not be
+ // immediately acted upon but rather only after the current
+ // `_multipartController` is done.
+ static const int _controllerStateIdle = 0;
+ static const int _controllerStateActive = 1;
+ static const int _controllerStatePaused = 2;
+ static const int _controllerStateCanceled = 3;
+
+ int _controllerState = _controllerStateIdle;
+
+ final _controller = StreamController<MimeMultipart>(sync: true);
+
+ Stream<MimeMultipart> get stream => _controller.stream;
+
+ late StreamSubscription<void> _subscription;
+
+ StreamController<List<int>>? _multipartController;
+ Map<String, String>? _headers;
+
+ int _state = _startCode;
+ int _boundaryIndex = 2;
+
+ /// Current index into [_buffer].
+ ///
+ /// If index is negative then it is the index into the artificial prefix of
+ /// the boundary string.
+ int _index = 0;
+ List<int> _buffer = _placeholderBuffer;
+
+ BoundMultipartStream(this._boundary, Stream<List<int>> stream) {
+ _controller
+ ..onPause = _pauseStream
+ ..onResume = _resumeStream
+ ..onCancel = () {
+ _controllerState = _controllerStateCanceled;
+ _tryPropagateControllerState();
+ }
+ ..onListen = () {
+ _controllerState = _controllerStateActive;
+ _subscription = stream.listen((data) {
+ assert(_buffer == _placeholderBuffer);
+ _subscription.pause();
+ _buffer = data;
+ _index = 0;
+ _parse();
+ }, onDone: () {
+ if (_state != _doneCode) {
+ _controller
+ .addError(const MimeMultipartException('Bad multipart ending'));
+ }
+ _controller.close();
+ }, onError: _controller.addError);
+ };
+ }
+
+ void _resumeStream() {
+ assert(_controllerState == _controllerStatePaused);
+ _controllerState = _controllerStateActive;
+ _tryPropagateControllerState();
+ }
+
+ void _pauseStream() {
+ _controllerState = _controllerStatePaused;
+ _tryPropagateControllerState();
+ }
+
+ void _tryPropagateControllerState() {
+ if (_multipartController == null) {
+ switch (_controllerState) {
+ case _controllerStateActive:
+ if (_subscription.isPaused) _subscription.resume();
+ case _controllerStatePaused:
+ if (!_subscription.isPaused) _subscription.pause();
+ case _controllerStateCanceled:
+ _subscription.cancel();
+ default:
+ throw StateError('This code should never be reached.');
+ }
+ }
+ }
+
+ void _parse() {
+ // Number of boundary bytes to artificially place before the supplied data.
+ // The data to parse might be 'artificially' prefixed with a
+ // partial match of the boundary.
+ final boundaryPrefix = _boundaryIndex;
+ // Position where content starts. Will be null if no known content
+ // start exists. Will be negative of the content starts in the
+ // boundary prefix. Will be zero or position if the content starts
+ // in the current buffer.
+ var contentStartIndex =
+ _state == _contentCode && _boundaryIndex == 0 ? 0 : null;
+
+ // Function to report content data for the current part. The data
+ // reported is from the current content start index up til the
+ // current index. As the data can be artificially prefixed with a
+ // prefix of the boundary both the content start index and index
+ // can be negative.
+ void reportData() {
+ if (contentStartIndex! < 0) {
+ final contentLength = boundaryPrefix + _index - _boundaryIndex;
+ if (contentLength <= boundaryPrefix) {
+ _multipartController!.add(_boundary.sublist(0, contentLength));
+ } else {
+ _multipartController!.add(_boundary.sublist(0, boundaryPrefix));
+ _multipartController!
+ .add(_buffer.sublist(0, contentLength - boundaryPrefix));
+ }
+ } else {
+ final contentEndIndex = _index - _boundaryIndex;
+ _multipartController!
+ .add(_buffer.sublist(contentStartIndex, contentEndIndex));
+ }
+ }
+
+ while (
+ _index < _buffer.length && _state != _failCode && _state != _doneCode) {
+ final byte =
+ _index < 0 ? _boundary[boundaryPrefix + _index] : _buffer[_index];
+ switch (_state) {
+ case _startCode:
+ if (byte == _boundary[_boundaryIndex]) {
+ _boundaryIndex++;
+ if (_boundaryIndex == _boundary.length) {
+ _state = _boundaryEndingCode;
+ _boundaryIndex = 0;
+ }
+ } else {
+ // Restart matching of the boundary.
+ _index = _index - _boundaryIndex;
+ _boundaryIndex = 0;
+ }
+
+ case _boundaryEndingCode:
+ if (byte == char_code.cr) {
+ _state = _boundaryEndCode;
+ } else if (byte == char_code.dash) {
+ _state = _lastBoundaryDash2Code;
+ } else {
+ _expectWhitespace(byte);
+ }
+
+ case _boundaryEndCode:
+ _expectByteValue(byte, char_code.lf);
+ _multipartController?.close();
+ if (_multipartController != null) {
+ _multipartController = null;
+ _tryPropagateControllerState();
+ }
+ _state = _headerStartCode;
+
+ case _headerStartCode:
+ _headers = <String, String>{};
+ if (byte == char_code.cr) {
+ _state = _headerEndingCode;
+ } else {
+ // Start of new header field.
+ _headerField.add(_toLowerCase(byte));
+ _state = _headerFieldCode;
+ }
+
+ case _headerFieldCode:
+ if (byte == char_code.colon) {
+ _state = _headerValueStartCode;
+ } else {
+ if (!_isTokenChar(byte)) {
+ throw const MimeMultipartException('Invalid header field name');
+ }
+ _headerField.add(_toLowerCase(byte));
+ }
+
+ case _headerValueStartCode:
+ if (byte == char_code.cr) {
+ _state = _headerValueFoldingOrEndingCode;
+ } else if (byte != char_code.sp && byte != char_code.ht) {
+ // Start of new header value.
+ _headerValue.add(byte);
+ _state = _headerValueCode;
+ }
+
+ case _headerValueCode:
+ if (byte == char_code.cr) {
+ _state = _headerValueFoldingOrEndingCode;
+ } else {
+ _headerValue.add(byte);
+ }
+
+ case _headerValueFoldingOrEndingCode:
+ _expectByteValue(byte, char_code.lf);
+ _state = _headerValueFoldOrEndCode;
+
+ case _headerValueFoldOrEndCode:
+ if (byte == char_code.sp || byte == char_code.ht) {
+ _state = _headerValueStartCode;
+ } else {
+ final headerField = utf8.decode(_headerField);
+ final headerValue = utf8.decode(_headerValue);
+ _headers![headerField.toLowerCase()] = headerValue;
+ _headerField.clear();
+ _headerValue.clear();
+ if (byte == char_code.cr) {
+ _state = _headerEndingCode;
+ } else {
+ // Start of new header field.
+ _headerField.add(_toLowerCase(byte));
+ _state = _headerFieldCode;
+ }
+ }
+
+ case _headerEndingCode:
+ _expectByteValue(byte, char_code.lf);
+ _multipartController = StreamController(
+ sync: true,
+ onListen: () {
+ if (_subscription.isPaused) _subscription.resume();
+ },
+ onPause: _subscription.pause,
+ onResume: _subscription.resume);
+ _controller
+ .add(_MimeMultipart(_headers!, _multipartController!.stream));
+ _headers = null;
+ _state = _contentCode;
+ contentStartIndex = _index + 1;
+
+ case _contentCode:
+ if (byte == _boundary[_boundaryIndex]) {
+ _boundaryIndex++;
+ if (_boundaryIndex == _boundary.length) {
+ if (contentStartIndex != null) {
+ _index++;
+ reportData();
+ _index--;
+ }
+ _multipartController!.close();
+ _multipartController = null;
+ _tryPropagateControllerState();
+ _boundaryIndex = 0;
+ _state = _boundaryEndingCode;
+ }
+ } else {
+ // Restart matching of the boundary.
+ _index = _index - _boundaryIndex;
+ contentStartIndex ??= _index;
+ _boundaryIndex = 0;
+ }
+
+ case _lastBoundaryDash2Code:
+ _expectByteValue(byte, char_code.dash);
+ _state = _lastBoundaryEndingCode;
+
+ case _lastBoundaryEndingCode:
+ if (byte == char_code.cr) {
+ _state = _lastBoundaryEndCode;
+ } else {
+ _expectWhitespace(byte);
+ }
+
+ case _lastBoundaryEndCode:
+ _expectByteValue(byte, char_code.lf);
+ _multipartController?.close();
+ if (_multipartController != null) {
+ _multipartController = null;
+ _tryPropagateControllerState();
+ }
+ _state = _doneCode;
+
+ default:
+ // Should be unreachable.
+ assert(false);
+ }
+
+ // Move to the next byte.
+ _index++;
+ }
+
+ // Report any known content.
+ if (_state == _contentCode && contentStartIndex != null) {
+ reportData();
+ }
+
+ // Resume if at end.
+ if (_index == _buffer.length) {
+ _buffer = _placeholderBuffer;
+ _index = 0;
+ _subscription.resume();
+ }
+ }
+}
+
+// Used as a placeholder instead of having a nullable buffer.
+const _placeholderBuffer = <int>[];
diff --git a/pkgs/mime/lib/src/char_code.dart b/pkgs/mime/lib/src/char_code.dart
new file mode 100644
index 0000000..4cca1b1
--- /dev/null
+++ b/pkgs/mime/lib/src/char_code.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+const int ht = 9;
+const int lf = 10;
+const int cr = 13;
+const int sp = 32;
+const int dash = 45;
+const int colon = 58;
+const int upperA = 65;
+const int upperZ = 90;
+const int lowerA = 97;
diff --git a/pkgs/mime/lib/src/default_extension_map.dart b/pkgs/mime/lib/src/default_extension_map.dart
new file mode 100644
index 0000000..287c957
--- /dev/null
+++ b/pkgs/mime/lib/src/default_extension_map.dart
@@ -0,0 +1,1012 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+const Map<String, String> defaultExtensionMap = <String, String>{
+ '123': 'application/vnd.lotus-1-2-3',
+ '3dml': 'text/vnd.in3d.3dml',
+ '3ds': 'image/x-3ds',
+ '3g2': 'video/3gpp2',
+ '3gp': 'video/3gpp',
+ '7z': 'application/x-7z-compressed',
+ 'aab': 'application/x-authorware-bin',
+ 'aac': 'audio/aac',
+ 'aam': 'application/x-authorware-map',
+ 'aas': 'application/x-authorware-seg',
+ 'abw': 'application/x-abiword',
+ 'ac': 'application/pkix-attr-cert',
+ 'acc': 'application/vnd.americandynamics.acc',
+ 'ace': 'application/x-ace-compressed',
+ 'acu': 'application/vnd.acucobol',
+ 'acutc': 'application/vnd.acucorp',
+ 'adp': 'audio/adpcm',
+ 'aep': 'application/vnd.audiograph',
+ 'afm': 'application/x-font-type1',
+ 'afp': 'application/vnd.ibm.modcap',
+ 'ahead': 'application/vnd.ahead.space',
+ 'ai': 'application/postscript',
+ 'aif': 'audio/x-aiff',
+ 'aifc': 'audio/x-aiff',
+ 'aiff': 'audio/x-aiff',
+ 'air': 'application/vnd.adobe.air-application-installer-package+zip',
+ 'ait': 'application/vnd.dvb.ait',
+ 'ami': 'application/vnd.amiga.ami',
+ 'apk': 'application/vnd.android.package-archive',
+ 'appcache': 'text/cache-manifest',
+ 'application': 'application/x-ms-application',
+ 'apr': 'application/vnd.lotus-approach',
+ 'arc': 'application/x-freearc',
+ 'asc': 'application/pgp-signature',
+ 'asf': 'video/x-ms-asf',
+ 'asm': 'text/x-asm',
+ 'aso': 'application/vnd.accpac.simply.aso',
+ 'asx': 'video/x-ms-asf',
+ 'atc': 'application/vnd.acucorp',
+ 'atom': 'application/atom+xml',
+ 'atomcat': 'application/atomcat+xml',
+ 'atomsvc': 'application/atomsvc+xml',
+ 'atx': 'application/vnd.antix.game-component',
+ 'au': 'audio/basic',
+ 'avi': 'video/x-msvideo',
+ 'avif': 'image/avif',
+ 'aw': 'application/applixware',
+ 'azf': 'application/vnd.airzip.filesecure.azf',
+ 'azs': 'application/vnd.airzip.filesecure.azs',
+ 'azw': 'application/vnd.amazon.ebook',
+ 'bat': 'application/x-msdownload',
+ 'bcpio': 'application/x-bcpio',
+ 'bdf': 'application/x-font-bdf',
+ 'bdm': 'application/vnd.syncml.dm+wbxml',
+ 'bed': 'application/vnd.realvnc.bed',
+ 'bh2': 'application/vnd.fujitsu.oasysprs',
+ 'bin': 'application/octet-stream',
+ 'blb': 'application/x-blorb',
+ 'blorb': 'application/x-blorb',
+ 'bmi': 'application/vnd.bmi',
+ 'bmp': 'image/bmp',
+ 'book': 'application/vnd.framemaker',
+ 'box': 'application/vnd.previewsystems.box',
+ 'boz': 'application/x-bzip2',
+ 'bpk': 'application/octet-stream',
+ 'btif': 'image/prs.btif',
+ 'bz': 'application/x-bzip',
+ 'bz2': 'application/x-bzip2',
+ 'c': 'text/x-c',
+ 'c11amc': 'application/vnd.cluetrust.cartomobile-config',
+ 'c11amz': 'application/vnd.cluetrust.cartomobile-config-pkg',
+ 'c4d': 'application/vnd.clonk.c4group',
+ 'c4f': 'application/vnd.clonk.c4group',
+ 'c4g': 'application/vnd.clonk.c4group',
+ 'c4p': 'application/vnd.clonk.c4group',
+ 'c4u': 'application/vnd.clonk.c4group',
+ 'cab': 'application/vnd.ms-cab-compressed',
+ 'caf': 'audio/x-caf',
+ 'cap': 'application/vnd.tcpdump.pcap',
+ 'car': 'application/vnd.curl.car',
+ 'cat': 'application/vnd.ms-pki.seccat',
+ 'cb7': 'application/x-cbr',
+ 'cba': 'application/x-cbr',
+ 'cbr': 'application/x-cbr',
+ 'cbt': 'application/x-cbr',
+ 'cbz': 'application/x-cbr',
+ 'cc': 'text/x-c',
+ 'cct': 'application/x-director',
+ 'ccxml': 'application/ccxml+xml',
+ 'cdbcmsg': 'application/vnd.contact.cmsg',
+ 'cdf': 'application/x-netcdf',
+ 'cdkey': 'application/vnd.mediastation.cdkey',
+ 'cdmia': 'application/cdmi-capability',
+ 'cdmic': 'application/cdmi-container',
+ 'cdmid': 'application/cdmi-domain',
+ 'cdmio': 'application/cdmi-object',
+ 'cdmiq': 'application/cdmi-queue',
+ 'cdx': 'chemical/x-cdx',
+ 'cdxml': 'application/vnd.chemdraw+xml',
+ 'cdy': 'application/vnd.cinderella',
+ 'cer': 'application/pkix-cert',
+ 'cfs': 'application/x-cfs-compressed',
+ 'cgm': 'image/cgm',
+ 'chat': 'application/x-chat',
+ 'chm': 'application/vnd.ms-htmlhelp',
+ 'chrt': 'application/vnd.kde.kchart',
+ 'cif': 'chemical/x-cif',
+ 'cii': 'application/vnd.anser-web-certificate-issue-initiation',
+ 'cil': 'application/vnd.ms-artgalry',
+ 'cla': 'application/vnd.claymore',
+ 'class': 'application/java-vm',
+ 'clkk': 'application/vnd.crick.clicker.keyboard',
+ 'clkp': 'application/vnd.crick.clicker.palette',
+ 'clkt': 'application/vnd.crick.clicker.template',
+ 'clkw': 'application/vnd.crick.clicker.wordbank',
+ 'clkx': 'application/vnd.crick.clicker',
+ 'clp': 'application/x-msclip',
+ 'cmc': 'application/vnd.cosmocaller',
+ 'cmdf': 'chemical/x-cmdf',
+ 'cml': 'chemical/x-cml',
+ 'cmp': 'application/vnd.yellowriver-custom-menu',
+ 'cmx': 'image/x-cmx',
+ 'cod': 'application/vnd.rim.cod',
+ 'com': 'application/x-msdownload',
+ 'conf': 'text/plain',
+ 'cpio': 'application/x-cpio',
+ 'cpp': 'text/x-c',
+ 'cpt': 'application/mac-compactpro',
+ 'crd': 'application/x-mscardfile',
+ 'crl': 'application/pkix-crl',
+ 'crt': 'application/x-x509-ca-cert',
+ 'cryptonote': 'application/vnd.rig.cryptonote',
+ 'csh': 'application/x-csh',
+ 'csml': 'chemical/x-csml',
+ 'csp': 'application/vnd.commonspace',
+ 'css': 'text/css',
+ 'cst': 'application/x-director',
+ 'csv': 'text/csv',
+ 'cu': 'application/cu-seeme',
+ 'curl': 'text/vnd.curl',
+ 'cww': 'application/prs.cww',
+ 'cxt': 'application/x-director',
+ 'cxx': 'text/x-c',
+ 'dae': 'model/vnd.collada+xml',
+ 'daf': 'application/vnd.mobius.daf',
+ 'dart': 'text/x-dart',
+ 'dataless': 'application/vnd.fdsn.seed',
+ 'davmount': 'application/davmount+xml',
+ 'dbk': 'application/docbook+xml',
+ 'dcm': 'application/dicom',
+ 'dcr': 'application/x-director',
+ 'dcurl': 'text/vnd.curl.dcurl',
+ 'dd2': 'application/vnd.oma.dd2+xml',
+ 'ddd': 'application/vnd.fujixerox.ddd',
+ 'deb': 'application/x-debian-package',
+ 'def': 'text/plain',
+ 'deploy': 'application/octet-stream',
+ 'der': 'application/x-x509-ca-cert',
+ 'dfac': 'application/vnd.dreamfactory',
+ 'dgc': 'application/x-dgc-compressed',
+ 'dic': 'text/x-c',
+ 'dir': 'application/x-director',
+ 'dis': 'application/vnd.mobius.dis',
+ 'dist': 'application/octet-stream',
+ 'distz': 'application/octet-stream',
+ 'djv': 'image/vnd.djvu',
+ 'djvu': 'image/vnd.djvu',
+ 'dll': 'application/x-msdownload',
+ 'dmg': 'application/x-apple-diskimage',
+ 'dmp': 'application/vnd.tcpdump.pcap',
+ 'dms': 'application/octet-stream',
+ 'dna': 'application/vnd.dna',
+ 'doc': 'application/msword',
+ 'docm': 'application/vnd.ms-word.document.macroenabled.12',
+ 'docx':
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dot': 'application/msword',
+ 'dotm': 'application/vnd.ms-word.template.macroenabled.12',
+ 'dotx':
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'dp': 'application/vnd.osgi.dp',
+ 'dpg': 'application/vnd.dpgraph',
+ 'dra': 'audio/vnd.dra',
+ 'dsc': 'text/prs.lines.tag',
+ 'dssc': 'application/dssc+der',
+ 'dtb': 'application/x-dtbook+xml',
+ 'dtd': 'application/xml-dtd',
+ 'dts': 'audio/vnd.dts',
+ 'dtshd': 'audio/vnd.dts.hd',
+ 'dump': 'application/octet-stream',
+ 'dvb': 'video/vnd.dvb.file',
+ 'dvi': 'application/x-dvi',
+ 'dwf': 'model/vnd.dwf',
+ 'dwg': 'image/vnd.dwg',
+ 'dxf': 'image/vnd.dxf',
+ 'dxp': 'application/vnd.spotfire.dxp',
+ 'dxr': 'application/x-director',
+ 'ecelp4800': 'audio/vnd.nuera.ecelp4800',
+ 'ecelp7470': 'audio/vnd.nuera.ecelp7470',
+ 'ecelp9600': 'audio/vnd.nuera.ecelp9600',
+ 'ecma': 'application/ecmascript',
+ 'edm': 'application/vnd.novadigm.edm',
+ 'edx': 'application/vnd.novadigm.edx',
+ 'efif': 'application/vnd.picsel',
+ 'ei6': 'application/vnd.pg.osasli',
+ 'elc': 'application/octet-stream',
+ 'emf': 'application/x-msmetafile',
+ 'eml': 'message/rfc822',
+ 'emma': 'application/emma+xml',
+ 'emz': 'application/x-msmetafile',
+ 'eol': 'audio/vnd.digital-winds',
+ 'eot': 'application/vnd.ms-fontobject',
+ 'eps': 'application/postscript',
+ 'epub': 'application/epub+zip',
+ 'es3': 'application/vnd.eszigno3+xml',
+ 'esa': 'application/vnd.osgi.subsystem',
+ 'esf': 'application/vnd.epson.esf',
+ 'et3': 'application/vnd.eszigno3+xml',
+ 'etx': 'text/x-setext',
+ 'eva': 'application/x-eva',
+ 'evy': 'application/x-envoy',
+ 'exe': 'application/x-msdownload',
+ 'exi': 'application/exi',
+ 'ext': 'application/vnd.novadigm.ext',
+ 'ez': 'application/andrew-inset',
+ 'ez2': 'application/vnd.ezpix-album',
+ 'ez3': 'application/vnd.ezpix-package',
+ 'f': 'text/x-fortran',
+ 'f4v': 'video/x-f4v',
+ 'f77': 'text/x-fortran',
+ 'f90': 'text/x-fortran',
+ 'fbs': 'image/vnd.fastbidsheet',
+ 'fcdt': 'application/vnd.adobe.formscentral.fcdt',
+ 'fcs': 'application/vnd.isac.fcs',
+ 'fdf': 'application/vnd.fdf',
+ 'fe_launch': 'application/vnd.denovo.fcselayout-link',
+ 'fg5': 'application/vnd.fujitsu.oasysgp',
+ 'fgd': 'application/x-director',
+ 'fh': 'image/x-freehand',
+ 'fh4': 'image/x-freehand',
+ 'fh5': 'image/x-freehand',
+ 'fh7': 'image/x-freehand',
+ 'fhc': 'image/x-freehand',
+ 'fig': 'application/x-xfig',
+ 'flac': 'audio/x-flac',
+ 'fli': 'video/x-fli',
+ 'flo': 'application/vnd.micrografx.flo',
+ 'flv': 'video/x-flv',
+ 'flw': 'application/vnd.kde.kivio',
+ 'flx': 'text/vnd.fmi.flexstor',
+ 'fly': 'text/vnd.fly',
+ 'fm': 'application/vnd.framemaker',
+ 'fnc': 'application/vnd.frogans.fnc',
+ 'for': 'text/x-fortran',
+ 'fpx': 'image/vnd.fpx',
+ 'frame': 'application/vnd.framemaker',
+ 'fsc': 'application/vnd.fsc.weblaunch',
+ 'fst': 'image/vnd.fst',
+ 'ftc': 'application/vnd.fluxtime.clip',
+ 'fti': 'application/vnd.anser-web-funds-transfer-initiation',
+ 'fvt': 'video/vnd.fvt',
+ 'fxp': 'application/vnd.adobe.fxp',
+ 'fxpl': 'application/vnd.adobe.fxp',
+ 'fzs': 'application/vnd.fuzzysheet',
+ 'g2w': 'application/vnd.geoplan',
+ 'g3': 'image/g3fax',
+ 'g3w': 'application/vnd.geospace',
+ 'gac': 'application/vnd.groove-account',
+ 'gam': 'application/x-tads',
+ 'gbr': 'application/rpki-ghostbusters',
+ 'gca': 'application/x-gca-compressed',
+ 'gdl': 'model/vnd.gdl',
+ 'geo': 'application/vnd.dynageo',
+ 'gex': 'application/vnd.geometry-explorer',
+ 'ggb': 'application/vnd.geogebra.file',
+ 'ggt': 'application/vnd.geogebra.tool',
+ 'ghf': 'application/vnd.groove-help',
+ 'gif': 'image/gif',
+ 'gim': 'application/vnd.groove-identity-message',
+ 'glb': 'model/gltf-binary',
+ 'gltf': 'model/gltf+json',
+ 'gml': 'application/gml+xml',
+ 'gmx': 'application/vnd.gmx',
+ 'gnumeric': 'application/x-gnumeric',
+ 'gph': 'application/vnd.flographit',
+ 'gpx': 'application/gpx+xml',
+ 'gqf': 'application/vnd.grafeq',
+ 'gqs': 'application/vnd.grafeq',
+ 'gram': 'application/srgs',
+ 'gramps': 'application/x-gramps-xml',
+ 'gre': 'application/vnd.geometry-explorer',
+ 'grv': 'application/vnd.groove-injector',
+ 'grxml': 'application/srgs+xml',
+ 'gsf': 'application/x-font-ghostscript',
+ 'gtar': 'application/x-gtar',
+ 'gtm': 'application/vnd.groove-tool-message',
+ 'gtw': 'model/vnd.gtw',
+ 'gv': 'text/vnd.graphviz',
+ 'gxf': 'application/gxf',
+ 'gxt': 'application/vnd.geonext',
+ 'h': 'text/x-c',
+ 'h261': 'video/h261',
+ 'h263': 'video/h263',
+ 'h264': 'video/h264',
+ 'hal': 'application/vnd.hal+xml',
+ 'hbci': 'application/vnd.hbci',
+ 'hdf': 'application/x-hdf',
+ 'heic': 'image/heic',
+ 'heif': 'image/heif',
+ 'hh': 'text/x-c',
+ 'hlp': 'application/winhlp',
+ 'hpgl': 'application/vnd.hp-hpgl',
+ 'hpid': 'application/vnd.hp-hpid',
+ 'hps': 'application/vnd.hp-hps',
+ 'hqx': 'application/mac-binhex40',
+ 'htke': 'application/vnd.kenameaapp',
+ 'htm': 'text/html',
+ 'html': 'text/html',
+ 'hvd': 'application/vnd.yamaha.hv-dic',
+ 'hvp': 'application/vnd.yamaha.hv-voice',
+ 'hvs': 'application/vnd.yamaha.hv-script',
+ 'i2g': 'application/vnd.intergeo',
+ 'icc': 'application/vnd.iccprofile',
+ 'ice': 'x-conference/x-cooltalk',
+ 'icm': 'application/vnd.iccprofile',
+ 'ico': 'image/x-icon',
+ 'ics': 'text/calendar',
+ 'ief': 'image/ief',
+ 'ifb': 'text/calendar',
+ 'ifm': 'application/vnd.shana.informed.formdata',
+ 'iges': 'model/iges',
+ 'igl': 'application/vnd.igloader',
+ 'igm': 'application/vnd.insors.igm',
+ 'igs': 'model/iges',
+ 'igx': 'application/vnd.micrografx.igx',
+ 'iif': 'application/vnd.shana.informed.interchange',
+ 'imp': 'application/vnd.accpac.simply.imp',
+ 'ims': 'application/vnd.ms-ims',
+ 'in': 'text/plain',
+ 'ink': 'application/inkml+xml',
+ 'inkml': 'application/inkml+xml',
+ 'install': 'application/x-install-instructions',
+ 'iota': 'application/vnd.astraea-software.iota',
+ 'ipfix': 'application/ipfix',
+ 'ipk': 'application/vnd.shana.informed.package',
+ 'irm': 'application/vnd.ibm.rights-management',
+ 'irp': 'application/vnd.irepository.package+xml',
+ 'iso': 'application/x-iso9660-image',
+ 'itp': 'application/vnd.shana.informed.formtemplate',
+ 'ivp': 'application/vnd.immervision-ivp',
+ 'ivu': 'application/vnd.immervision-ivu',
+ 'jad': 'text/vnd.sun.j2me.app-descriptor',
+ 'jam': 'application/vnd.jam',
+ 'jar': 'application/java-archive',
+ 'java': 'text/x-java-source',
+ 'jisp': 'application/vnd.jisp',
+ 'jlt': 'application/vnd.hp-jlyt',
+ 'jnlp': 'application/x-java-jnlp-file',
+ 'joda': 'application/vnd.joost.joda-archive',
+ 'jpe': 'image/jpeg',
+ 'jpeg': 'image/jpeg',
+ 'jpg': 'image/jpeg',
+ 'jpgm': 'video/jpm',
+ 'jpgv': 'video/jpeg',
+ 'jpm': 'video/jpm',
+ 'js': 'text/javascript',
+ 'json': 'application/json',
+ 'jsonml': 'application/jsonml+json',
+ 'kar': 'audio/midi',
+ 'karbon': 'application/vnd.kde.karbon',
+ 'kfo': 'application/vnd.kde.kformula',
+ 'kia': 'application/vnd.kidspiration',
+ 'kml': 'application/vnd.google-earth.kml+xml',
+ 'kmz': 'application/vnd.google-earth.kmz',
+ 'kne': 'application/vnd.kinar',
+ 'knp': 'application/vnd.kinar',
+ 'kon': 'application/vnd.kde.kontour',
+ 'kpr': 'application/vnd.kde.kpresenter',
+ 'kpt': 'application/vnd.kde.kpresenter',
+ 'kpxx': 'application/vnd.ds-keypoint',
+ 'ksp': 'application/vnd.kde.kspread',
+ 'ktr': 'application/vnd.kahootz',
+ 'ktx': 'image/ktx',
+ 'ktz': 'application/vnd.kahootz',
+ 'kwd': 'application/vnd.kde.kword',
+ 'kwt': 'application/vnd.kde.kword',
+ 'lasxml': 'application/vnd.las.las+xml',
+ 'latex': 'application/x-latex',
+ 'lbd': 'application/vnd.llamagraphics.life-balance.desktop',
+ 'lbe': 'application/vnd.llamagraphics.life-balance.exchange+xml',
+ 'les': 'application/vnd.hhe.lesson-player',
+ 'lha': 'application/x-lzh-compressed',
+ 'link66': 'application/vnd.route66.link66+xml',
+ 'list': 'text/plain',
+ 'list3820': 'application/vnd.ibm.modcap',
+ 'listafp': 'application/vnd.ibm.modcap',
+ 'lnk': 'application/x-ms-shortcut',
+ 'log': 'text/plain',
+ 'lostxml': 'application/lost+xml',
+ 'lrf': 'application/octet-stream',
+ 'lrm': 'application/vnd.ms-lrm',
+ 'ltf': 'application/vnd.frogans.ltf',
+ 'lvp': 'audio/vnd.lucent.voice',
+ 'lwp': 'application/vnd.lotus-wordpro',
+ 'lzh': 'application/x-lzh-compressed',
+ 'm13': 'application/x-msmediaview',
+ 'm14': 'application/x-msmediaview',
+ 'm1v': 'video/mpeg',
+ 'm21': 'application/mp21',
+ 'm2a': 'audio/mpeg',
+ 'm2v': 'video/mpeg',
+ 'm3a': 'audio/mpeg',
+ 'm3u': 'audio/x-mpegurl',
+ 'm3u8': 'application/vnd.apple.mpegurl',
+ // Source: https://datatracker.ietf.org/doc/html/rfc4337#section-2
+ 'm4a': 'audio/mp4',
+ 'm4b': 'audio/mp4',
+ 'm4u': 'video/vnd.mpegurl',
+ 'm4v': 'video/x-m4v',
+ 'ma': 'application/mathematica',
+ 'mads': 'application/mads+xml',
+ 'mag': 'application/vnd.ecowin.chart',
+ 'maker': 'application/vnd.framemaker',
+ 'man': 'text/troff',
+ 'mar': 'application/octet-stream',
+ 'mathml': 'application/mathml+xml',
+ 'mb': 'application/mathematica',
+ 'mbk': 'application/vnd.mobius.mbk',
+ 'mbox': 'application/mbox',
+ 'mc1': 'application/vnd.medcalcdata',
+ 'mcd': 'application/vnd.mcd',
+ 'mcurl': 'text/vnd.curl.mcurl',
+ // https://www.rfc-editor.org/rfc/rfc7763
+ 'md': 'text/markdown',
+ 'markdown': 'text/markdown',
+ 'mdb': 'application/x-msaccess',
+ 'mdi': 'image/vnd.ms-modi',
+ 'me': 'text/troff',
+ 'mesh': 'model/mesh',
+ 'meta4': 'application/metalink4+xml',
+ 'metalink': 'application/metalink+xml',
+ 'mets': 'application/mets+xml',
+ 'mfm': 'application/vnd.mfmp',
+ 'mft': 'application/rpki-manifest',
+ 'mgp': 'application/vnd.osgeo.mapguide.package',
+ 'mgz': 'application/vnd.proteus.magazine',
+ 'mid': 'audio/midi',
+ 'midi': 'audio/midi',
+ 'mie': 'application/x-mie',
+ 'mif': 'application/vnd.mif',
+ 'mime': 'message/rfc822',
+ 'mj2': 'video/mj2',
+ 'mjp2': 'video/mj2',
+ 'mjs': 'text/javascript',
+ 'mk3d': 'video/x-matroska',
+ 'mka': 'audio/x-matroska',
+ 'mks': 'video/x-matroska',
+ 'mkv': 'video/x-matroska',
+ 'mlp': 'application/vnd.dolby.mlp',
+ 'mmd': 'application/vnd.chipnuts.karaoke-mmd',
+ 'mmf': 'application/vnd.smaf',
+ 'mmr': 'image/vnd.fujixerox.edmics-mmr',
+ 'mng': 'video/x-mng',
+ 'mny': 'application/x-msmoney',
+ 'mobi': 'application/x-mobipocket-ebook',
+ 'mods': 'application/mods+xml',
+ 'mov': 'video/quicktime',
+ 'movie': 'video/x-sgi-movie',
+ 'mp2': 'audio/mpeg',
+ 'mp21': 'application/mp21',
+ 'mp2a': 'audio/mpeg',
+ 'mp3': 'audio/mpeg',
+ 'mp4': 'video/mp4',
+ 'mp4a': 'audio/mp4',
+ 'mp4s': 'application/mp4',
+ 'mp4v': 'video/mp4',
+ 'mpc': 'application/vnd.mophun.certificate',
+ 'mpe': 'video/mpeg',
+ 'mpeg': 'video/mpeg',
+ 'mpg': 'video/mpeg',
+ 'mpg4': 'video/mp4',
+ 'mpga': 'audio/mpeg',
+ 'mpkg': 'application/vnd.apple.installer+xml',
+ 'mpm': 'application/vnd.blueice.multipass',
+ 'mpn': 'application/vnd.mophun.application',
+ 'mpp': 'application/vnd.ms-project',
+ 'mpt': 'application/vnd.ms-project',
+ 'mpy': 'application/vnd.ibm.minipay',
+ 'mqy': 'application/vnd.mobius.mqy',
+ 'mrc': 'application/marc',
+ 'mrcx': 'application/marcxml+xml',
+ 'ms': 'text/troff',
+ 'mscml': 'application/mediaservercontrol+xml',
+ 'mseed': 'application/vnd.fdsn.mseed',
+ 'mseq': 'application/vnd.mseq',
+ 'msf': 'application/vnd.epson.msf',
+ 'msh': 'model/mesh',
+ 'msi': 'application/x-msdownload',
+ 'msl': 'application/vnd.mobius.msl',
+ 'msty': 'application/vnd.muvee.style',
+ 'mts': 'model/vnd.mts',
+ 'mus': 'application/vnd.musician',
+ 'musicxml': 'application/vnd.recordare.musicxml+xml',
+ 'mvb': 'application/x-msmediaview',
+ 'mwf': 'application/vnd.mfer',
+ 'mxf': 'application/mxf',
+ 'mxl': 'application/vnd.recordare.musicxml',
+ 'mxml': 'application/xv+xml',
+ 'mxs': 'application/vnd.triscape.mxs',
+ 'mxu': 'video/vnd.mpegurl',
+ 'n-gage': 'application/vnd.nokia.n-gage.symbian.install',
+ 'n3': 'text/n3',
+ 'nb': 'application/mathematica',
+ 'nbp': 'application/vnd.wolfram.player',
+ 'nc': 'application/x-netcdf',
+ 'ncx': 'application/x-dtbncx+xml',
+ 'nfo': 'text/x-nfo',
+ 'ngdat': 'application/vnd.nokia.n-gage.data',
+ 'nitf': 'application/vnd.nitf',
+ 'nlu': 'application/vnd.neurolanguage.nlu',
+ 'nml': 'application/vnd.enliven',
+ 'nnd': 'application/vnd.noblenet-directory',
+ 'nns': 'application/vnd.noblenet-sealer',
+ 'nnw': 'application/vnd.noblenet-web',
+ 'npx': 'image/vnd.net-fpx',
+ 'nsc': 'application/x-conference',
+ 'nsf': 'application/vnd.lotus-notes',
+ 'ntf': 'application/vnd.nitf',
+ 'nzb': 'application/x-nzb',
+ 'oa2': 'application/vnd.fujitsu.oasys2',
+ 'oa3': 'application/vnd.fujitsu.oasys3',
+ 'oas': 'application/vnd.fujitsu.oasys',
+ 'obd': 'application/x-msbinder',
+ 'obj': 'application/x-tgif',
+ 'oda': 'application/oda',
+ 'odb': 'application/vnd.oasis.opendocument.database',
+ 'odc': 'application/vnd.oasis.opendocument.chart',
+ 'odf': 'application/vnd.oasis.opendocument.formula',
+ 'odft': 'application/vnd.oasis.opendocument.formula-template',
+ 'odg': 'application/vnd.oasis.opendocument.graphics',
+ 'odi': 'application/vnd.oasis.opendocument.image',
+ 'odm': 'application/vnd.oasis.opendocument.text-master',
+ 'odp': 'application/vnd.oasis.opendocument.presentation',
+ 'ods': 'application/vnd.oasis.opendocument.spreadsheet',
+ 'odt': 'application/vnd.oasis.opendocument.text',
+ 'oga': 'audio/ogg',
+ 'ogg': 'audio/ogg',
+ 'ogv': 'video/ogg',
+ 'ogx': 'application/ogg',
+ 'omdoc': 'application/omdoc+xml',
+ 'onepkg': 'application/onenote',
+ 'onetmp': 'application/onenote',
+ 'onetoc': 'application/onenote',
+ 'onetoc2': 'application/onenote',
+ 'opf': 'application/oebps-package+xml',
+ 'opml': 'text/x-opml',
+ 'oprc': 'application/vnd.palm',
+ 'org': 'application/vnd.lotus-organizer',
+ 'osf': 'application/vnd.yamaha.openscoreformat',
+ 'osfpvg': 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
+ 'otc': 'application/vnd.oasis.opendocument.chart-template',
+ 'otf': 'application/x-font-otf',
+ 'otg': 'application/vnd.oasis.opendocument.graphics-template',
+ 'oth': 'application/vnd.oasis.opendocument.text-web',
+ 'oti': 'application/vnd.oasis.opendocument.image-template',
+ 'otp': 'application/vnd.oasis.opendocument.presentation-template',
+ 'ots': 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'ott': 'application/vnd.oasis.opendocument.text-template',
+ 'oxps': 'application/oxps',
+ 'oxt': 'application/vnd.openofficeorg.extension',
+ 'p': 'text/x-pascal',
+ 'p10': 'application/pkcs10',
+ 'p12': 'application/x-pkcs12',
+ 'p7b': 'application/x-pkcs7-certificates',
+ 'p7c': 'application/pkcs7-mime',
+ 'p7m': 'application/pkcs7-mime',
+ 'p7r': 'application/x-pkcs7-certreqresp',
+ 'p7s': 'application/pkcs7-signature',
+ 'p8': 'application/pkcs8',
+ 'pas': 'text/x-pascal',
+ 'paw': 'application/vnd.pawaafile',
+ 'pbd': 'application/vnd.powerbuilder6',
+ 'pbm': 'image/x-portable-bitmap',
+ 'pcap': 'application/vnd.tcpdump.pcap',
+ 'pcf': 'application/x-font-pcf',
+ 'pcl': 'application/vnd.hp-pcl',
+ 'pclxl': 'application/vnd.hp-pclxl',
+ 'pct': 'image/x-pict',
+ 'pcurl': 'application/vnd.curl.pcurl',
+ 'pcx': 'image/x-pcx',
+ 'pdb': 'application/vnd.palm',
+ 'pdf': 'application/pdf',
+ 'pfa': 'application/x-font-type1',
+ 'pfb': 'application/x-font-type1',
+ 'pfm': 'application/x-font-type1',
+ 'pfr': 'application/font-tdpfr',
+ 'pfx': 'application/x-pkcs12',
+ 'pgm': 'image/x-portable-graymap',
+ 'pgn': 'application/x-chess-pgn',
+ 'pgp': 'application/pgp-encrypted',
+ 'pic': 'image/x-pict',
+ 'pkg': 'application/octet-stream',
+ 'pki': 'application/pkixcmp',
+ 'pkipath': 'application/pkix-pkipath',
+ 'plb': 'application/vnd.3gpp.pic-bw-large',
+ 'plc': 'application/vnd.mobius.plc',
+ 'plf': 'application/vnd.pocketlearn',
+ 'pls': 'application/pls+xml',
+ 'pml': 'application/vnd.ctc-posml',
+ 'png': 'image/png',
+ 'pnm': 'image/x-portable-anymap',
+ 'portpkg': 'application/vnd.macports.portpkg',
+ 'pot': 'application/vnd.ms-powerpoint',
+ 'potm': 'application/vnd.ms-powerpoint.template.macroenabled.12',
+ 'potx':
+ 'application/vnd.openxmlformats-officedocument.presentationml.template',
+ 'ppam': 'application/vnd.ms-powerpoint.addin.macroenabled.12',
+ 'ppd': 'application/vnd.cups-ppd',
+ 'ppm': 'image/x-portable-pixmap',
+ 'pps': 'application/vnd.ms-powerpoint',
+ 'ppsm': 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
+ 'ppsx':
+ 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'ppt': 'application/vnd.ms-powerpoint',
+ 'pptm': 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
+ 'pptx':
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'pqa': 'application/vnd.palm',
+ 'prc': 'application/x-mobipocket-ebook',
+ 'pre': 'application/vnd.lotus-freelance',
+ 'prf': 'application/pics-rules',
+ 'ps': 'application/postscript',
+ 'psb': 'application/vnd.3gpp.pic-bw-small',
+ 'psd': 'image/vnd.adobe.photoshop',
+ 'psf': 'application/x-font-linux-psf',
+ 'pskcxml': 'application/pskc+xml',
+ 'ptid': 'application/vnd.pvi.ptid1',
+ 'pub': 'application/x-mspublisher',
+ 'pvb': 'application/vnd.3gpp.pic-bw-var',
+ 'pwn': 'application/vnd.3m.post-it-notes',
+ 'pya': 'audio/vnd.ms-playready.media.pya',
+ 'pyv': 'video/vnd.ms-playready.media.pyv',
+ 'qam': 'application/vnd.epson.quickanime',
+ 'qbo': 'application/vnd.intu.qbo',
+ 'qfx': 'application/vnd.intu.qfx',
+ 'qps': 'application/vnd.publishare-delta-tree',
+ 'qt': 'video/quicktime',
+ 'qwd': 'application/vnd.quark.quarkxpress',
+ 'qwt': 'application/vnd.quark.quarkxpress',
+ 'qxb': 'application/vnd.quark.quarkxpress',
+ 'qxd': 'application/vnd.quark.quarkxpress',
+ 'qxl': 'application/vnd.quark.quarkxpress',
+ 'qxt': 'application/vnd.quark.quarkxpress',
+ 'ra': 'audio/x-pn-realaudio',
+ 'ram': 'audio/x-pn-realaudio',
+ 'rar': 'application/x-rar-compressed',
+ 'ras': 'image/x-cmu-raster',
+ 'rcprofile': 'application/vnd.ipunplugged.rcprofile',
+ 'rdf': 'application/rdf+xml',
+ 'rdz': 'application/vnd.data-vision.rdz',
+ 'rep': 'application/vnd.businessobjects',
+ 'res': 'application/x-dtbresource+xml',
+ 'rgb': 'image/x-rgb',
+ 'rif': 'application/reginfo+xml',
+ 'rip': 'audio/vnd.rip',
+ 'ris': 'application/x-research-info-systems',
+ 'rl': 'application/resource-lists+xml',
+ 'rlc': 'image/vnd.fujixerox.edmics-rlc',
+ 'rld': 'application/resource-lists-diff+xml',
+ 'rm': 'application/vnd.rn-realmedia',
+ 'rmi': 'audio/midi',
+ 'rmp': 'audio/x-pn-realaudio-plugin',
+ 'rms': 'application/vnd.jcp.javame.midlet-rms',
+ 'rmvb': 'application/vnd.rn-realmedia-vbr',
+ 'rnc': 'application/relax-ng-compact-syntax',
+ 'roa': 'application/rpki-roa',
+ 'roff': 'text/troff',
+ 'rp9': 'application/vnd.cloanto.rp9',
+ 'rpss': 'application/vnd.nokia.radio-presets',
+ 'rpst': 'application/vnd.nokia.radio-preset',
+ 'rq': 'application/sparql-query',
+ 'rs': 'application/rls-services+xml',
+ 'rsd': 'application/rsd+xml',
+ 'rss': 'application/rss+xml',
+ 'rtf': 'application/rtf',
+ 'rtx': 'text/richtext',
+ 's': 'text/x-asm',
+ 's3m': 'audio/s3m',
+ 'saf': 'application/vnd.yamaha.smaf-audio',
+ 'sbml': 'application/sbml+xml',
+ 'sc': 'application/vnd.ibm.secure-container',
+ 'scd': 'application/x-msschedule',
+ 'scm': 'application/vnd.lotus-screencam',
+ 'scq': 'application/scvp-cv-request',
+ 'scs': 'application/scvp-cv-response',
+ 'scurl': 'text/vnd.curl.scurl',
+ 'sda': 'application/vnd.stardivision.draw',
+ 'sdc': 'application/vnd.stardivision.calc',
+ 'sdd': 'application/vnd.stardivision.impress',
+ 'sdkd': 'application/vnd.solent.sdkm+xml',
+ 'sdkm': 'application/vnd.solent.sdkm+xml',
+ 'sdp': 'application/sdp',
+ 'sdw': 'application/vnd.stardivision.writer',
+ 'see': 'application/vnd.seemail',
+ 'seed': 'application/vnd.fdsn.seed',
+ 'sema': 'application/vnd.sema',
+ 'semd': 'application/vnd.semd',
+ 'semf': 'application/vnd.semf',
+ 'ser': 'application/java-serialized-object',
+ 'setpay': 'application/set-payment-initiation',
+ 'setreg': 'application/set-registration-initiation',
+ 'sfd-hdstx': 'application/vnd.hydrostatix.sof-data',
+ 'sfs': 'application/vnd.spotfire.sfs',
+ 'sfv': 'text/x-sfv',
+ 'sgi': 'image/sgi',
+ 'sgl': 'application/vnd.stardivision.writer-global',
+ 'sgm': 'text/sgml',
+ 'sgml': 'text/sgml',
+ 'sh': 'application/x-sh',
+ 'shar': 'application/x-shar',
+ 'shf': 'application/shf+xml',
+ 'sid': 'image/x-mrsid-image',
+ 'sig': 'application/pgp-signature',
+ 'sil': 'audio/silk',
+ 'silo': 'model/mesh',
+ 'sis': 'application/vnd.symbian.install',
+ 'sisx': 'application/vnd.symbian.install',
+ 'sit': 'application/x-stuffit',
+ 'sitx': 'application/x-stuffitx',
+ 'skd': 'application/vnd.koan',
+ 'skm': 'application/vnd.koan',
+ 'skp': 'application/vnd.koan',
+ 'skt': 'application/vnd.koan',
+ 'sldm': 'application/vnd.ms-powerpoint.slide.macroenabled.12',
+ 'sldx': 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+ 'slt': 'application/vnd.epson.salt',
+ 'sm': 'application/vnd.stepmania.stepchart',
+ 'smf': 'application/vnd.stardivision.math',
+ 'smi': 'application/smil+xml',
+ 'smil': 'application/smil+xml',
+ 'smv': 'video/x-smv',
+ 'smzip': 'application/vnd.stepmania.package',
+ 'snd': 'audio/basic',
+ 'snf': 'application/x-font-snf',
+ 'so': 'application/octet-stream',
+ 'spc': 'application/x-pkcs7-certificates',
+ 'spf': 'application/vnd.yamaha.smaf-phrase',
+ 'spl': 'application/x-futuresplash',
+ 'spot': 'text/vnd.in3d.spot',
+ 'spp': 'application/scvp-vp-response',
+ 'spq': 'application/scvp-vp-request',
+ 'spx': 'audio/ogg',
+ 'sql': 'application/x-sql',
+ 'src': 'application/x-wais-source',
+ 'srt': 'application/x-subrip',
+ 'sru': 'application/sru+xml',
+ 'srx': 'application/sparql-results+xml',
+ 'ssdl': 'application/ssdl+xml',
+ 'sse': 'application/vnd.kodak-descriptor',
+ 'ssf': 'application/vnd.epson.ssf',
+ 'ssml': 'application/ssml+xml',
+ 'st': 'application/vnd.sailingtracker.track',
+ 'stc': 'application/vnd.sun.xml.calc.template',
+ 'std': 'application/vnd.sun.xml.draw.template',
+ 'stf': 'application/vnd.wt.stf',
+ 'sti': 'application/vnd.sun.xml.impress.template',
+ 'stk': 'application/hyperstudio',
+ 'stl': 'application/vnd.ms-pki.stl',
+ 'str': 'application/vnd.pg.format',
+ 'stw': 'application/vnd.sun.xml.writer.template',
+ 'sub': 'text/vnd.dvb.subtitle',
+ 'sus': 'application/vnd.sus-calendar',
+ 'susp': 'application/vnd.sus-calendar',
+ 'sv4cpio': 'application/x-sv4cpio',
+ 'sv4crc': 'application/x-sv4crc',
+ 'svc': 'application/vnd.dvb.service',
+ 'svd': 'application/vnd.svd',
+ 'svg': 'image/svg+xml',
+ 'svgz': 'image/svg+xml',
+ 'swa': 'application/x-director',
+ 'swf': 'application/x-shockwave-flash',
+ 'swi': 'application/vnd.aristanetworks.swi',
+ 'sxc': 'application/vnd.sun.xml.calc',
+ 'sxd': 'application/vnd.sun.xml.draw',
+ 'sxg': 'application/vnd.sun.xml.writer.global',
+ 'sxi': 'application/vnd.sun.xml.impress',
+ 'sxm': 'application/vnd.sun.xml.math',
+ 'sxw': 'application/vnd.sun.xml.writer',
+ 't': 'text/troff',
+ 't3': 'application/x-t3vm-image',
+ 'taglet': 'application/vnd.mynfc',
+ 'tao': 'application/vnd.tao.intent-module-archive',
+ 'tar': 'application/x-tar',
+ 'tcap': 'application/vnd.3gpp2.tcap',
+ 'tcl': 'application/x-tcl',
+ 'teacher': 'application/vnd.smart.teacher',
+ 'tei': 'application/tei+xml',
+ 'teicorpus': 'application/tei+xml',
+ 'tex': 'application/x-tex',
+ 'texi': 'application/x-texinfo',
+ 'texinfo': 'application/x-texinfo',
+ 'text': 'text/plain',
+ 'tfi': 'application/thraud+xml',
+ 'tfm': 'application/x-tex-tfm',
+ 'tga': 'image/x-tga',
+ 'thmx': 'application/vnd.ms-officetheme',
+ 'tif': 'image/tiff',
+ 'tiff': 'image/tiff',
+ 'tmo': 'application/vnd.tmobile-livetv',
+ // Source: https://toml.io/en/v1.0.0#mime-type
+ 'toml': 'application/toml',
+ 'torrent': 'application/x-bittorrent',
+ 'tpl': 'application/vnd.groove-tool-template',
+ 'tpt': 'application/vnd.trid.tpt',
+ 'tr': 'text/troff',
+ 'tra': 'application/vnd.trueapp',
+ 'trm': 'application/x-msterminal',
+ 'tsd': 'application/timestamped-data',
+ 'tsv': 'text/tab-separated-values',
+ 'ttc': 'application/x-font-ttf',
+ 'ttf': 'application/x-font-ttf',
+ 'ttl': 'text/turtle',
+ 'twd': 'application/vnd.simtech-mindmapper',
+ 'twds': 'application/vnd.simtech-mindmapper',
+ 'txd': 'application/vnd.genomatix.tuxedo',
+ 'txf': 'application/vnd.mobius.txf',
+ 'txt': 'text/plain',
+ 'u32': 'application/x-authorware-bin',
+ 'udeb': 'application/x-debian-package',
+ 'ufd': 'application/vnd.ufdl',
+ 'ufdl': 'application/vnd.ufdl',
+ 'ulx': 'application/x-glulx',
+ 'umj': 'application/vnd.umajin',
+ 'unityweb': 'application/vnd.unity',
+ 'uoml': 'application/vnd.uoml+xml',
+ 'uri': 'text/uri-list',
+ 'uris': 'text/uri-list',
+ 'urls': 'text/uri-list',
+ 'ustar': 'application/x-ustar',
+ 'utz': 'application/vnd.uiq.theme',
+ 'uu': 'text/x-uuencode',
+ 'uva': 'audio/vnd.dece.audio',
+ 'uvd': 'application/vnd.dece.data',
+ 'uvf': 'application/vnd.dece.data',
+ 'uvg': 'image/vnd.dece.graphic',
+ 'uvh': 'video/vnd.dece.hd',
+ 'uvi': 'image/vnd.dece.graphic',
+ 'uvm': 'video/vnd.dece.mobile',
+ 'uvp': 'video/vnd.dece.pd',
+ 'uvs': 'video/vnd.dece.sd',
+ 'uvt': 'application/vnd.dece.ttml+xml',
+ 'uvu': 'video/vnd.uvvu.mp4',
+ 'uvv': 'video/vnd.dece.video',
+ 'uvva': 'audio/vnd.dece.audio',
+ 'uvvd': 'application/vnd.dece.data',
+ 'uvvf': 'application/vnd.dece.data',
+ 'uvvg': 'image/vnd.dece.graphic',
+ 'uvvh': 'video/vnd.dece.hd',
+ 'uvvi': 'image/vnd.dece.graphic',
+ 'uvvm': 'video/vnd.dece.mobile',
+ 'uvvp': 'video/vnd.dece.pd',
+ 'uvvs': 'video/vnd.dece.sd',
+ 'uvvt': 'application/vnd.dece.ttml+xml',
+ 'uvvu': 'video/vnd.uvvu.mp4',
+ 'uvvv': 'video/vnd.dece.video',
+ 'uvvx': 'application/vnd.dece.unspecified',
+ 'uvvz': 'application/vnd.dece.zip',
+ 'uvx': 'application/vnd.dece.unspecified',
+ 'uvz': 'application/vnd.dece.zip',
+ 'vcard': 'text/vcard',
+ 'vcd': 'application/x-cdlink',
+ 'vcf': 'text/x-vcard',
+ 'vcg': 'application/vnd.groove-vcard',
+ 'vcs': 'text/x-vcalendar',
+ 'vcx': 'application/vnd.vcx',
+ 'vis': 'application/vnd.visionary',
+ 'viv': 'video/vnd.vivo',
+ 'vob': 'video/x-ms-vob',
+ 'vor': 'application/vnd.stardivision.writer',
+ 'vox': 'application/x-authorware-bin',
+ 'vrml': 'model/vrml',
+ 'vsd': 'application/vnd.visio',
+ 'vsf': 'application/vnd.vsf',
+ 'vss': 'application/vnd.visio',
+ 'vst': 'application/vnd.visio',
+ 'vsw': 'application/vnd.visio',
+ 'vtu': 'model/vnd.vtu',
+ 'vxml': 'application/voicexml+xml',
+ 'w3d': 'application/x-director',
+ 'wad': 'application/x-doom',
+ 'wasm': 'application/wasm',
+ 'wav': 'audio/x-wav',
+ 'wax': 'audio/x-ms-wax',
+ 'wbmp': 'image/vnd.wap.wbmp',
+ 'wbs': 'application/vnd.criticaltools.wbs+xml',
+ 'wbxml': 'application/vnd.wap.wbxml',
+ 'wcm': 'application/vnd.ms-works',
+ 'wdb': 'application/vnd.ms-works',
+ 'wdp': 'image/vnd.ms-photo',
+ 'weba': 'audio/webm',
+ 'webm': 'video/webm',
+ // Source: https://w3c.github.io/manifest/#media-type-registration
+ 'webmanifest': 'application/manifest+json',
+ 'webp': 'image/webp',
+ 'wg': 'application/vnd.pmi.widget',
+ 'wgt': 'application/widget',
+ 'wks': 'application/vnd.ms-works',
+ 'wm': 'video/x-ms-wm',
+ 'wma': 'audio/x-ms-wma',
+ 'wmd': 'application/x-ms-wmd',
+ 'wmf': 'application/x-msmetafile',
+ 'wml': 'text/vnd.wap.wml',
+ 'wmlc': 'application/vnd.wap.wmlc',
+ 'wmls': 'text/vnd.wap.wmlscript',
+ 'wmlsc': 'application/vnd.wap.wmlscriptc',
+ 'wmv': 'video/x-ms-wmv',
+ 'wmx': 'video/x-ms-wmx',
+ 'wmz': 'application/x-ms-wmz',
+ 'woff': 'application/x-font-woff',
+ 'woff2': 'font/woff2',
+ 'wpd': 'application/vnd.wordperfect',
+ 'wpl': 'application/vnd.ms-wpl',
+ 'wps': 'application/vnd.ms-works',
+ 'wqd': 'application/vnd.wqd',
+ 'wri': 'application/x-mswrite',
+ 'wrl': 'model/vrml',
+ 'wsdl': 'application/wsdl+xml',
+ 'wspolicy': 'application/wspolicy+xml',
+ 'wtb': 'application/vnd.webturbo',
+ 'wvx': 'video/x-ms-wvx',
+ 'x32': 'application/x-authorware-bin',
+ 'x3d': 'model/x3d+xml',
+ 'x3db': 'model/x3d+binary',
+ 'x3dbz': 'model/x3d+binary',
+ 'x3dv': 'model/x3d+vrml',
+ 'x3dvz': 'model/x3d+vrml',
+ 'x3dz': 'model/x3d+xml',
+ 'xaml': 'application/xaml+xml',
+ 'xap': 'application/x-silverlight-app',
+ 'xar': 'application/vnd.xara',
+ 'xbap': 'application/x-ms-xbap',
+ 'xbd': 'application/vnd.fujixerox.docuworks.binder',
+ 'xbm': 'image/x-xbitmap',
+ 'xdf': 'application/xcap-diff+xml',
+ 'xdm': 'application/vnd.syncml.dm+xml',
+ 'xdp': 'application/vnd.adobe.xdp+xml',
+ 'xdssc': 'application/dssc+xml',
+ 'xdw': 'application/vnd.fujixerox.docuworks',
+ 'xenc': 'application/xenc+xml',
+ 'xer': 'application/patch-ops-error+xml',
+ 'xfdf': 'application/vnd.adobe.xfdf',
+ 'xfdl': 'application/vnd.xfdl',
+ 'xht': 'application/xhtml+xml',
+ 'xhtml': 'application/xhtml+xml',
+ 'xhvml': 'application/xv+xml',
+ 'xif': 'image/vnd.xiff',
+ 'xla': 'application/vnd.ms-excel',
+ 'xlam': 'application/vnd.ms-excel.addin.macroenabled.12',
+ 'xlc': 'application/vnd.ms-excel',
+ 'xlf': 'application/x-xliff+xml',
+ 'xlm': 'application/vnd.ms-excel',
+ 'xls': 'application/vnd.ms-excel',
+ 'xlsb': 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
+ 'xlsm': 'application/vnd.ms-excel.sheet.macroenabled.12',
+ 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xlt': 'application/vnd.ms-excel',
+ 'xltm': 'application/vnd.ms-excel.template.macroenabled.12',
+ 'xltx':
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'xlw': 'application/vnd.ms-excel',
+ 'xm': 'audio/xm',
+ 'xml': 'application/xml',
+ 'xo': 'application/vnd.olpc-sugar',
+ 'xop': 'application/xop+xml',
+ 'xpi': 'application/x-xpinstall',
+ 'xpl': 'application/xproc+xml',
+ 'xpm': 'image/x-xpixmap',
+ 'xpr': 'application/vnd.is-xpr',
+ 'xps': 'application/vnd.ms-xpsdocument',
+ 'xpw': 'application/vnd.intercon.formnet',
+ 'xpx': 'application/vnd.intercon.formnet',
+ 'xsl': 'application/xml',
+ 'xslt': 'application/xslt+xml',
+ 'xsm': 'application/vnd.syncml+xml',
+ 'xspf': 'application/xspf+xml',
+ 'xul': 'application/vnd.mozilla.xul+xml',
+ 'xvm': 'application/xv+xml',
+ 'xvml': 'application/xv+xml',
+ 'xwd': 'image/x-xwindowdump',
+ 'xyz': 'chemical/x-xyz',
+ 'xz': 'application/x-xz',
+ 'yang': 'application/yang',
+ 'yin': 'application/yin+xml',
+ 'z1': 'application/x-zmachine',
+ 'z2': 'application/x-zmachine',
+ 'z3': 'application/x-zmachine',
+ 'z4': 'application/x-zmachine',
+ 'z5': 'application/x-zmachine',
+ 'z6': 'application/x-zmachine',
+ 'z7': 'application/x-zmachine',
+ 'z8': 'application/x-zmachine',
+ 'zaz': 'application/vnd.zzazz.deck+xml',
+ 'zip': 'application/zip',
+ 'zir': 'application/vnd.zul',
+ 'zirz': 'application/vnd.zul',
+ 'zmm': 'application/vnd.handheld-entertainment+xml',
+};
diff --git a/pkgs/mime/lib/src/extension.dart b/pkgs/mime/lib/src/extension.dart
new file mode 100644
index 0000000..293449a
--- /dev/null
+++ b/pkgs/mime/lib/src/extension.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'default_extension_map.dart';
+
+/// Default extension for recognized MIME types.
+///
+/// Is the inverse of [defaultExtensionMap], and where that
+/// map has multiple extensions which map to the same
+/// MIME type, this map maps that MIME type to a *default*
+/// extension.
+///
+/// Used by [extensionFromMime].
+final Map<String, String> _defaultMimeTypeMap = {
+ for (var entry in defaultExtensionMap.entries) entry.value: entry.key,
+ 'application/msword': 'doc',
+ 'application/vnd.ms-excel': 'xls',
+ 'application/vnd.ms-powerpoint': 'ppt',
+ 'application/x-debian-package': 'deb',
+ 'application/xhtml+xml': 'xhtml',
+ 'application/xml': 'xml',
+ 'audio/x-aiff': 'aif',
+ 'audio/midi': 'mid',
+ 'audio/mp4': 'm4a',
+ 'audio/ogg': 'ogg',
+ 'image/jpeg': 'jpg',
+ 'image/tiff': 'tif',
+ 'image/svg+xml': 'svg',
+ 'model/vrml': 'vrml',
+ 'text/calendar': 'ics',
+ 'text/html': 'html',
+ 'text/javascript': 'js',
+ 'text/markdown': 'md',
+ 'text/plain': 'txt',
+ 'text/sgml': 'sgml',
+ 'text/x-asm': 'asm',
+ 'text/x-c': 'c',
+ 'text/x-pascal': 'pas',
+ 'video/mp4': 'mp4',
+ 'video/mpeg': 'mpg',
+ 'video/quicktime': 'mov',
+ 'video/x-matroska': 'mkv',
+};
+
+/// The default file extension for a given MIME type.
+///
+/// If [mimeType] has multiple associated extensions,
+/// the returned string is one of those, chosen as the default
+/// extension for that MIME type.
+///
+/// Returns `null` if [mimeType] is not a recognized and
+/// supported MIME type.
+String? extensionFromMime(String mimeType) =>
+ _defaultMimeTypeMap[mimeType.toLowerCase()];
diff --git a/pkgs/mime/lib/src/magic_number.dart b/pkgs/mime/lib/src/magic_number.dart
new file mode 100644
index 0000000..c8b5c3b
--- /dev/null
+++ b/pkgs/mime/lib/src/magic_number.dart
@@ -0,0 +1,407 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class MagicNumber {
+ final String mimeType;
+ final List<int> numbers;
+ final List<int>? mask;
+
+ const MagicNumber(this.mimeType, this.numbers, {this.mask});
+
+ bool matches(List<int> header) {
+ if (header.length < numbers.length) return false;
+
+ for (var i = 0; i < numbers.length; i++) {
+ if (mask != null) {
+ if ((mask![i] & numbers[i]) != (mask![i] & header[i])) return false;
+ } else {
+ if (numbers[i] != header[i]) return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+const int initialMagicNumbersMaxLength = 12;
+
+const List<MagicNumber> initialMagicNumbers = [
+ MagicNumber('application/pdf', [0x25, 0x50, 0x44, 0x46]),
+ MagicNumber('application/postscript', [0x25, 0x51]),
+
+ /// AIFF is based on the EA IFF 85 Standard for Interchange Format Files.
+ /// -> 4 bytes have the ASCII characters 'F' 'O' 'R' 'M'.
+ /// -> 4 bytes indicating the size of the file
+ /// -> 4 bytes have the ASCII characters 'A' 'I' 'F' 'F'.
+ /// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/Docs/AIFF-1.3.pdf
+ MagicNumber('audio/x-aiff', [
+ 0x46,
+ 0x4F,
+ 0x52,
+ 0x4D,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x41,
+ 0x49,
+ 0x46,
+ 0x46
+ ], mask: [
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+
+ /// -> 4 bytes have the ASCII characters 'f' 'L' 'a' 'C'.
+ /// https://xiph.org/flac/format.html
+ MagicNumber('audio/x-flac', [0x66, 0x4C, 0x61, 0x43]),
+
+ /// The WAVE file format is based on the RIFF document format.
+ /// -> 4 bytes have the ASCII characters 'R' 'I' 'F' 'F'.
+ /// -> 4 bytes indicating the size of the file
+ /// -> 4 bytes have the ASCII characters 'W' 'A' 'V' 'E'.
+ /// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf
+ MagicNumber('audio/x-wav', [
+ 0x52,
+ 0x49,
+ 0x46,
+ 0x46,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x57,
+ 0x41,
+ 0x56,
+ 0x45
+ ], mask: [
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+ MagicNumber('image/gif', [0x47, 0x49, 0x46, 0x38, 0x37, 0x61]),
+ MagicNumber('image/gif', [0x47, 0x49, 0x46, 0x38, 0x39, 0x61]),
+ MagicNumber('image/jpeg', [0xFF, 0xD8]),
+ MagicNumber('image/png', [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]),
+ MagicNumber('image/tiff', [0x49, 0x49, 0x2A, 0x00]),
+ MagicNumber('image/tiff', [0x4D, 0x4D, 0x00, 0x2A]),
+ MagicNumber('audio/aac', [0xFF, 0xF1]),
+ MagicNumber('audio/aac', [0xFF, 0xF9]),
+ MagicNumber('audio/weba', [0x1A, 0x45, 0xDF, 0xA3]),
+ MagicNumber('audio/mpeg', [0x49, 0x44, 0x33]),
+ MagicNumber('audio/mpeg', [0xFF, 0xFB]),
+ MagicNumber('audio/ogg', [0x4F, 0x70, 0x75]),
+ MagicNumber('video/3gpp', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x33,
+ 0x67,
+ 0x70,
+ 0x35
+ ], mask: [
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+ MagicNumber('video/mp4', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x61,
+ 0x76,
+ 0x63,
+ 0x31
+ ], mask: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+ MagicNumber('video/mp4', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x69,
+ 0x73,
+ 0x6F,
+ 0x32
+ ], mask: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+ MagicNumber('video/mp4', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x69,
+ 0x73,
+ 0x6F,
+ 0x6D
+ ], mask: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+ MagicNumber('video/mp4', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x6D,
+ 0x70,
+ 0x34,
+ 0x31
+ ], mask: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+ MagicNumber('video/mp4', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x6D,
+ 0x70,
+ 0x34,
+ 0x32
+ ], mask: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+ MagicNumber('model/gltf-binary', [0x46, 0x54, 0x6C, 0x67]),
+
+ /// The WebP file format is based on the RIFF document format.
+ /// -> 4 bytes have the ASCII characters 'R' 'I' 'F' 'F'.
+ /// -> 4 bytes indicating the size of the file
+ /// -> 4 bytes have the ASCII characters 'W' 'E' 'B' 'P'.
+ /// https://developers.google.com/speed/webp/docs/riff_container
+ MagicNumber('image/webp', [
+ 0x52,
+ 0x49,
+ 0x46,
+ 0x46,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x57,
+ 0x45,
+ 0x42,
+ 0x50
+ ], mask: [
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+
+ MagicNumber('font/woff2', [0x77, 0x4f, 0x46, 0x32]),
+
+ /// High Efficiency Image File Format (ISO/IEC 23008-12).
+ /// -> 4 bytes indicating the ftyp box length.
+ /// -> 4 bytes have the ASCII characters 'f' 't' 'y' 'p'.
+ /// -> 4 bytes have the ASCII characters 'h' 'e' 'i' 'c'.
+ /// https://www.iana.org/assignments/media-types/image/heic
+ MagicNumber('image/heic', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x68,
+ 0x65,
+ 0x69,
+ 0x63
+ ], mask: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+
+ /// -> 4 bytes indicating the ftyp box length.
+ /// -> 4 bytes have the ASCII characters 'f' 't' 'y' 'p'.
+ /// -> 4 bytes have the ASCII characters 'h' 'e' 'i' 'x'.
+ MagicNumber('image/heic', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x68,
+ 0x65,
+ 0x69,
+ 0x78
+ ], mask: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+
+ /// -> 4 bytes indicating the ftyp box length.
+ /// -> 4 bytes have the ASCII characters 'f' 't' 'y' 'p'.
+ /// -> 4 bytes have the ASCII characters 'm' 'i' 'f' '1'.
+ MagicNumber('image/heif', [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x6D,
+ 0x69,
+ 0x66,
+ 0x31
+ ], mask: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]),
+];
diff --git a/pkgs/mime/lib/src/mime_multipart_transformer.dart b/pkgs/mime/lib/src/mime_multipart_transformer.dart
new file mode 100644
index 0000000..2648d7d
--- /dev/null
+++ b/pkgs/mime/lib/src/mime_multipart_transformer.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:typed_data';
+
+import 'bound_multipart_stream.dart';
+import 'char_code.dart' as char_code;
+import 'mime_shared.dart';
+
+Uint8List _getBoundary(String boundary) {
+ final charCodes = boundary.codeUnits;
+
+ final boundaryList = Uint8List(4 + charCodes.length);
+ // Set-up the matching boundary preceding it with CRLF and two
+ // dashes.
+ boundaryList[0] = char_code.cr;
+ boundaryList[1] = char_code.lf;
+ boundaryList[2] = char_code.dash;
+ boundaryList[3] = char_code.dash;
+ boundaryList.setRange(4, 4 + charCodes.length, charCodes);
+ return boundaryList;
+}
+
+/// Parser for MIME multipart types of data as described in RFC 2046
+/// section 5.1.1. The data is transformed into [MimeMultipart] objects, each
+/// of them streaming the multipart data.
+class MimeMultipartTransformer
+ extends StreamTransformerBase<List<int>, MimeMultipart> {
+ final List<int> _boundary;
+
+ /// Construct a new MIME multipart parser with the boundary
+ /// [boundary]. The boundary should be as specified in the content
+ /// type parameter, that is without the -- prefix.
+ MimeMultipartTransformer(String boundary)
+ : _boundary = _getBoundary(boundary);
+
+ @override
+ Stream<MimeMultipart> bind(Stream<List<int>> stream) =>
+ BoundMultipartStream(_boundary, stream).stream;
+}
diff --git a/pkgs/mime/lib/src/mime_shared.dart b/pkgs/mime/lib/src/mime_shared.dart
new file mode 100644
index 0000000..1c98971
--- /dev/null
+++ b/pkgs/mime/lib/src/mime_shared.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'mime_multipart_transformer.dart';
+
+class MimeMultipartException implements Exception {
+ final String message;
+
+ const MimeMultipartException([this.message = '']);
+
+ @override
+ String toString() => 'MimeMultipartException: $message';
+}
+
+/// A Mime Multipart class representing each part parsed by
+/// [MimeMultipartTransformer]. The data is streamed in as it become available.
+abstract class MimeMultipart extends Stream<List<int>> {
+ Map<String, String> get headers;
+}
diff --git a/pkgs/mime/lib/src/mime_type.dart b/pkgs/mime/lib/src/mime_type.dart
new file mode 100644
index 0000000..9cf9194
--- /dev/null
+++ b/pkgs/mime/lib/src/mime_type.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'default_extension_map.dart';
+import 'magic_number.dart';
+
+final MimeTypeResolver _globalResolver = MimeTypeResolver();
+
+/// The maximum number of bytes needed, to match all default magic-numbers.
+int get defaultMagicNumbersMaxLength => _globalResolver.magicNumbersMaxLength;
+
+/// Extract the extension from [path] and use that for MIME-type lookup, using
+/// the default extension map.
+///
+/// If no matching MIME-type was found, `null` is returned.
+///
+/// If [headerBytes] is present, a match for known magic-numbers will be
+/// performed first. This allows the correct mime-type to be found, even though
+/// a file have been saved using the wrong file-name extension. If less than
+/// [defaultMagicNumbersMaxLength] bytes was provided, some magic-numbers won't
+/// be matched against.
+String? lookupMimeType(String path, {List<int>? headerBytes}) =>
+ _globalResolver.lookup(path, headerBytes: headerBytes);
+
+/// MIME-type resolver class, used to customize the lookup of mime-types.
+class MimeTypeResolver {
+ final Map<String, String> _extensionMap = {};
+ final List<MagicNumber> _magicNumbers = [];
+ final bool _useDefault;
+ int _magicNumbersMaxLength;
+
+ /// Create a new empty [MimeTypeResolver].
+ MimeTypeResolver.empty()
+ : _useDefault = false,
+ _magicNumbersMaxLength = 0;
+
+ /// Create a new [MimeTypeResolver] containing the default scope.
+ MimeTypeResolver()
+ : _useDefault = true,
+ _magicNumbersMaxLength = initialMagicNumbersMaxLength;
+
+ /// Get the maximum number of bytes required to match all magic numbers, when
+ /// performing [lookup] with headerBytes present.
+ int get magicNumbersMaxLength => _magicNumbersMaxLength;
+
+ /// Extract the extension from [path] and use that for MIME-type lookup.
+ ///
+ /// If no matching MIME-type was found, `null` is returned.
+ ///
+ /// If [headerBytes] is present, a match for known magic-numbers will be
+ /// performed first. This allows the correct mime-type to be found, even
+ /// though a file have been saved using the wrong file-name extension. If less
+ /// than [magicNumbersMaxLength] bytes was provided, some magic-numbers won't
+ /// be matched against.
+ String? lookup(String path, {List<int>? headerBytes}) {
+ String? result;
+ if (headerBytes != null) {
+ result = _matchMagic(headerBytes, _magicNumbers);
+ if (result != null) return result;
+ if (_useDefault) {
+ result = _matchMagic(headerBytes, initialMagicNumbers);
+ if (result != null) return result;
+ }
+ }
+ final ext = _ext(path);
+ result = _extensionMap[ext];
+ if (result != null) return result;
+ if (_useDefault) {
+ result = defaultExtensionMap[ext];
+ if (result != null) return result;
+ }
+ return null;
+ }
+
+ /// Add a new MIME-type mapping to the [MimeTypeResolver]. If the [extension]
+ /// is already present in the [MimeTypeResolver], it'll be overwritten.
+ void addExtension(String extension, String mimeType) {
+ _extensionMap[extension] = mimeType;
+ }
+
+ /// Add a new magic-number mapping to the [MimeTypeResolver].
+ ///
+ /// If [mask] is present,the [mask] is used to only perform matching on
+ /// selective bits. The [mask] must have the same length as [bytes].
+ void addMagicNumber(List<int> bytes, String mimeType, {List<int>? mask}) {
+ if (mask != null && bytes.length != mask.length) {
+ throw ArgumentError('Bytes and mask are of different lengths');
+ }
+ if (bytes.length > _magicNumbersMaxLength) {
+ _magicNumbersMaxLength = bytes.length;
+ }
+ _magicNumbers.add(MagicNumber(mimeType, bytes, mask: mask));
+ }
+
+ static String? _matchMagic(
+ List<int> headerBytes, List<MagicNumber> magicNumbers) {
+ for (var mn in magicNumbers) {
+ if (mn.matches(headerBytes)) return mn.mimeType;
+ }
+ return null;
+ }
+
+ static String _ext(String path) {
+ final index = path.lastIndexOf('.');
+ if (index < 0 || index + 1 >= path.length) return path;
+ return path.substring(index + 1).toLowerCase();
+ }
+}
diff --git a/pkgs/mime/pubspec.yaml b/pkgs/mime/pubspec.yaml
new file mode 100644
index 0000000..6f1dec7
--- /dev/null
+++ b/pkgs/mime/pubspec.yaml
@@ -0,0 +1,19 @@
+name: mime
+version: 2.0.0
+description: >-
+ Utilities for handling media (MIME) types, including determining a type from
+ a file extension and file contents.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/mime
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Amime
+topics:
+ - magic-numbers
+ - mime
+ - mimetype
+ - multipart-form
+
+environment:
+ sdk: ^3.2.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.0
diff --git a/pkgs/mime/test/default_extension_map_test.dart b/pkgs/mime/test/default_extension_map_test.dart
new file mode 100644
index 0000000..b5539dd
--- /dev/null
+++ b/pkgs/mime/test/default_extension_map_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:mime/src/default_extension_map.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('defaultExtensionMap', () {
+ test('keys are lowercase', () {
+ for (final key in defaultExtensionMap.keys) {
+ expect(key, equals(key.toLowerCase()));
+ }
+ });
+ });
+}
diff --git a/pkgs/mime/test/extension_test.dart b/pkgs/mime/test/extension_test.dart
new file mode 100644
index 0000000..40dae6d
--- /dev/null
+++ b/pkgs/mime/test/extension_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:mime/mime.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('valid-mime-type', () {
+ expect(extensionFromMime('text/x-dart'), equals('dart'));
+ expect(extensionFromMime('text/javascript'), equals('js'));
+ expect(extensionFromMime('application/java-archive'), equals('jar'));
+ expect(extensionFromMime('application/json'), equals('json'));
+ expect(extensionFromMime('application/pdf'), equals('pdf'));
+ expect(extensionFromMime('application/vnd.ms-excel'), equals('xls'));
+ expect(extensionFromMime('application/xhtml+xml'), equals('xhtml'));
+ expect(extensionFromMime('image/jpeg'), equals('jpg'));
+ expect(extensionFromMime('image/png'), equals('png'));
+ expect(extensionFromMime('text/css'), equals('css'));
+ expect(extensionFromMime('text/html'), equals('html'));
+ expect(extensionFromMime('text/plain'), equals('txt'));
+ expect(extensionFromMime('text/x-c'), equals('c'));
+ });
+
+ test('invalid-mime-type', () {
+ expect(extensionFromMime('invalid-mime-type'), isNull);
+ expect(extensionFromMime('invalid/mime/type'), isNull);
+ });
+
+ test('unknown-mime-type', () {
+ expect(extensionFromMime('application/to-be-invented'), isNull);
+ });
+}
diff --git a/pkgs/mime/test/mime_multipart_transformer_test.dart b/pkgs/mime/test/mime_multipart_transformer_test.dart
new file mode 100644
index 0000000..109a9bc
--- /dev/null
+++ b/pkgs/mime/test/mime_multipart_transformer_test.dart
@@ -0,0 +1,469 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:math';
+
+import 'package:mime/mime.dart';
+import 'package:test/test.dart';
+
+void _writeInChunks(
+ List<int> data, int chunkSize, StreamController<List<int>> controller) {
+ if (chunkSize == -1) chunkSize = data.length;
+
+ for (var pos = 0; pos < data.length; pos += chunkSize) {
+ final remaining = data.length - pos;
+ final writeLength = min(chunkSize, remaining);
+ controller.add(data.sublist(pos, pos + writeLength));
+ }
+ controller.close();
+}
+
+enum TestMode { immediateListen, delayListen, pauseResume }
+
+void _runParseTest(
+ String message,
+ String boundary,
+ TestMode mode, [
+ List<Map<String, String>>? expectedHeaders,
+ List<String?>? expectedParts,
+ bool expectError = false,
+]) {
+ Future<void> testWrite(List<int> data, [int chunkSize = -1]) {
+ final controller = StreamController<List<int>>(sync: true);
+
+ final stream =
+ controller.stream.transform(MimeMultipartTransformer(boundary));
+ var i = 0;
+ final completer = Completer<void>();
+ final futures = <Future<void>>[];
+ stream.listen((multipart) {
+ final part = i++;
+ if (expectedHeaders != null) {
+ expect(multipart.headers, equals(expectedHeaders[part]));
+ }
+ switch (mode) {
+ case TestMode.immediateListen:
+ futures.add(multipart.fold<List<int>>(
+ [], (buffer, data) => buffer..addAll(data)).then((data) {
+ if (expectedParts?[part] != null) {
+ expect(data, equals(expectedParts?[part]!.codeUnits));
+ }
+ }));
+
+ case TestMode.delayListen:
+ futures.add(
+ Future(
+ () => multipart.fold<List<int>>(
+ [],
+ (buffer, data) => buffer..addAll(data),
+ ).then(
+ (data) {
+ if (expectedParts?[part] != null) {
+ expect(data, equals(expectedParts?[part]!.codeUnits));
+ }
+ },
+ ),
+ ),
+ );
+
+ case TestMode.pauseResume:
+ final completer = Completer<void>();
+ futures.add(completer.future);
+ final buffer = <int>[];
+ late StreamSubscription<List<int>> subscription;
+ subscription = multipart.listen((data) {
+ buffer.addAll(data);
+ subscription.pause();
+ Future(() => subscription.resume());
+ }, onDone: () {
+ if (expectedParts?[part] != null) {
+ expect(buffer, equals(expectedParts?[part]!.codeUnits));
+ }
+ completer.complete();
+ });
+ addTearDown(subscription.cancel);
+ }
+ }, onError: (Object error) {
+ // ignore: only_throw_errors
+ if (!expectError) throw error;
+ }, onDone: () {
+ if (expectedParts != null) {
+ expect(i, equals(expectedParts.length));
+ }
+ Future.wait(futures).then(completer.complete);
+ });
+
+ _writeInChunks(data, chunkSize, controller);
+
+ return completer.future;
+ }
+
+ Future<void> testFirstPartOnly(List<int> data, [int chunkSize = -1]) {
+ final completer = Completer<void>();
+ final controller = StreamController<List<int>>(sync: true);
+
+ final stream =
+ controller.stream.transform(MimeMultipartTransformer(boundary));
+
+ stream.first.then((multipart) {
+ if (expectedHeaders != null) {
+ expect(multipart.headers, equals(expectedHeaders[0]));
+ }
+ return multipart.fold<List<int>>([], (b, d) => b..addAll(d)).then(
+ (data) {
+ if (expectedParts != null && expectedParts[0] != null) {
+ expect(data, equals(expectedParts[0]!.codeUnits));
+ }
+ },
+ );
+ }).then((_) {
+ completer.complete();
+ });
+
+ _writeInChunks(data, chunkSize, controller);
+
+ return completer.future;
+ }
+
+ Future<void> testCompletePartAfterCancel(List<int> data, int parts,
+ [int chunkSize = -1]) {
+ final completer = Completer<void>();
+ final controller = StreamController<List<int>>(sync: true);
+ final stream =
+ controller.stream.transform(MimeMultipartTransformer(boundary));
+ late StreamSubscription<void> subscription;
+ var i = 0;
+ final futures = <Future<void>>[];
+ subscription = stream.listen((multipart) {
+ final partIndex = i;
+
+ if (partIndex >= parts) {
+ throw StateError('Expected no more parts, but got one.');
+ }
+
+ if (expectedHeaders != null) {
+ expect(multipart.headers, equals(expectedHeaders[partIndex]));
+ }
+ futures.add(
+ multipart.fold<List<int>>([], (b, d) => b..addAll(d)).then((data) {
+ if (expectedParts != null && expectedParts[partIndex] != null) {
+ expect(data, equals(expectedParts[partIndex]!.codeUnits));
+ }
+ }));
+
+ if (partIndex == (parts - 1)) {
+ subscription.cancel();
+ Future.wait(futures).then(completer.complete);
+ }
+ i++;
+ });
+
+ _writeInChunks(data, chunkSize, controller);
+
+ return completer.future;
+ }
+
+ // Test parsing the data three times delivering the data in
+ // different chunks.
+ final data = message.codeUnits;
+ test('test', () {
+ expect(
+ Future.wait([
+ testWrite(data),
+ testWrite(data, 10),
+ testWrite(data, 2),
+ testWrite(data, 1),
+ ]),
+ completes);
+ });
+
+ if (expectedParts!.isNotEmpty) {
+ test('test-first-part-only', () {
+ expect(
+ Future.wait([
+ testFirstPartOnly(data),
+ testFirstPartOnly(data, 10),
+ testFirstPartOnly(data, 2),
+ testFirstPartOnly(data, 1),
+ ]),
+ completes);
+ });
+
+ test('test-n-parts-only', () {
+ var numPartsExpected = expectedParts.length - 1;
+ if (numPartsExpected == 0) numPartsExpected = 1;
+
+ expect(
+ Future.wait([
+ testCompletePartAfterCancel(data, numPartsExpected),
+ testCompletePartAfterCancel(data, numPartsExpected, 10),
+ testCompletePartAfterCancel(data, numPartsExpected, 2),
+ testCompletePartAfterCancel(data, numPartsExpected, 1),
+ ]),
+ completes);
+ });
+ }
+}
+
+void _testParse(String message, String boundary,
+ [List<Map<String, String>>? expectedHeaders,
+ List<String?>? expectedParts,
+ bool expectError = false]) {
+ _runParseTest(message, boundary, TestMode.immediateListen, expectedHeaders,
+ expectedParts, expectError);
+ _runParseTest(message, boundary, TestMode.delayListen, expectedHeaders,
+ expectedParts, expectError);
+ _runParseTest(message, boundary, TestMode.pauseResume, expectedHeaders,
+ expectedParts, expectError);
+}
+
+void _testParseValid() {
+ // Empty message from Chrome form post.
+ var message = '------WebKitFormBoundaryU3FBruSkJKG0Yor1--\r\n';
+ _testParse(message, '----WebKitFormBoundaryU3FBruSkJKG0Yor1', [], []);
+
+ // Sample from Wikipedia.
+ message = '''
+This is a message with multiple parts in MIME format.\r
+--frontier\r
+Content-Type: text/plain\r
+\r
+This is the body of the message.\r
+--frontier\r
+Content-Type: application/octet-stream\r
+Content-Transfer-Encoding: base64\r
+\r
+PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
+Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg=\r
+--frontier--\r\n''';
+ var headers1 = <String, String>{'content-type': 'text/plain'};
+ var headers2 = <String, String>{
+ 'content-type': 'application/octet-stream',
+ 'content-transfer-encoding': 'base64'
+ };
+ var body1 = 'This is the body of the message.';
+ var body2 = '''
+PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
+Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg=''';
+ _testParse(message, 'frontier', [headers1, headers2], [body1, body2]);
+
+ // Sample from HTML 4.01 Specification.
+ message = '''
+\r\n--AaB03x\r
+Content-Disposition: form-data; name="submit-name"\r
+\r
+Larry\r
+--AaB03x\r
+Content-Disposition: form-data; name="files"; filename="file1.txt"\r
+Content-Type: text/plain\r
+\r
+... contents of file1.txt ...\r
+--AaB03x--\r\n''';
+ headers1 = <String, String>{
+ 'content-disposition': 'form-data; name="submit-name"'
+ };
+ headers2 = <String, String>{
+ 'content-type': 'text/plain',
+ 'content-disposition': 'form-data; name="files"; filename="file1.txt"'
+ };
+ body1 = 'Larry';
+ body2 = '... contents of file1.txt ...';
+ _testParse(message, 'AaB03x', [headers1, headers2], [body1, body2]);
+
+ // Longer form from submitting the following from Chrome.
+ //
+ // <html>
+ // <body>
+ // <FORM action="http://127.0.0.1:1234/"
+ // enctype="multipart/form-data"
+ // method='post'>
+ // <P>
+ // Text: <INPUT type='text' name='text_input'>
+ // Password: <INPUT type='password' name='password_input'>
+ // Checkbox: <INPUT type='checkbox' name='checkbox_input'>
+ // Radio: <INPUT type='radio' name='radio_input'>
+ // Send <INPUT type='submit'>
+ // </P>
+ // </FORM>
+ // </body>
+ // </html>
+
+ message = '''
+\r\n------WebKitFormBoundaryQ3cgYAmGRF8yOeYB\r
+Content-Disposition: form-data; name="text_input"\r
+\r
+text\r
+------WebKitFormBoundaryQ3cgYAmGRF8yOeYB\r
+Content-Disposition: form-data; name="password_input"\r
+\r
+password\r
+------WebKitFormBoundaryQ3cgYAmGRF8yOeYB\r
+Content-Disposition: form-data; name="checkbox_input"\r
+\r
+on\r
+------WebKitFormBoundaryQ3cgYAmGRF8yOeYB\r
+Content-Disposition: form-data; name="radio_input"\r
+\r
+on\r
+------WebKitFormBoundaryQ3cgYAmGRF8yOeYB--\r\n''';
+ headers1 = <String, String>{
+ 'content-disposition': 'form-data; name="text_input"'
+ };
+ headers2 = <String, String>{
+ 'content-disposition': 'form-data; name="password_input"'
+ };
+ final headers3 = <String, String>{
+ 'content-disposition': 'form-data; name="checkbox_input"'
+ };
+ final headers4 = <String, String>{
+ 'content-disposition': 'form-data; name="radio_input"'
+ };
+ body1 = 'text';
+ body2 = 'password';
+ const body3 = 'on';
+ const body4 = 'on';
+ _testParse(message, '----WebKitFormBoundaryQ3cgYAmGRF8yOeYB',
+ [headers1, headers2, headers3, headers4], [body1, body2, body3, body4]);
+
+ // Same form from Firefox.
+ message = '''
+\r\n-----------------------------52284550912143824192005403738\r
+Content-Disposition: form-data; name="text_input"\r
+\r
+text\r
+-----------------------------52284550912143824192005403738\r
+Content-Disposition: form-data; name="password_input"\r
+\r
+password\r
+-----------------------------52284550912143824192005403738\r
+Content-Disposition: form-data; name="checkbox_input"\r
+\r
+on\r
+-----------------------------52284550912143824192005403738\r
+Content-Disposition: form-data; name="radio_input"\r
+\r
+on\r
+-----------------------------52284550912143824192005403738--\r\n''';
+ _testParse(
+ message,
+ '---------------------------52284550912143824192005403738',
+ [headers1, headers2, headers3, headers4],
+ [body1, body2, body3, body4]);
+
+ // And Internet Explorer
+ message = '''
+\r\n-----------------------------7dc8f38c60326\r
+Content-Disposition: form-data; name="text_input"\r
+\r
+text\r
+-----------------------------7dc8f38c60326\r
+Content-Disposition: form-data; name="password_input"\r
+\r
+password\r
+-----------------------------7dc8f38c60326\r
+Content-Disposition: form-data; name="checkbox_input"\r
+\r
+on\r
+-----------------------------7dc8f38c60326\r
+Content-Disposition: form-data; name="radio_input"\r
+\r
+on\r
+-----------------------------7dc8f38c60326--\r\n''';
+ _testParse(message, '---------------------------7dc8f38c60326',
+ [headers1, headers2, headers3, headers4], [body1, body2, body3, body4]);
+
+ // Test boundary prefix inside prefix and content.
+ message = '''
+-\r
+--\r
+--b\r
+--bo\r
+--bou\r
+--boun\r
+--bound\r
+--bounda\r
+--boundar\r
+--boundary\r
+Content-Type: text/plain\r
+\r
+-\r
+--\r
+--b\r
+--bo\r
+--bou\r
+--boun\r
+--bound\r\r
+--bounda\r\r\r
+--boundar\r\r\r\r
+--boundary\r
+Content-Type: text/plain\r
+\r
+--boundar\r
+--bounda\r
+--bound\r
+--boun\r
+--bou\r
+--bo\r
+--b\r\r\r\r
+--\r\r\r
+-\r\r
+--boundary--\r\n''';
+ final headers = <String, String>{'content-type': 'text/plain'};
+ body1 = '''
+-\r
+--\r
+--b\r
+--bo\r
+--bou\r
+--boun\r
+--bound\r\r
+--bounda\r\r\r
+--boundar\r\r\r''';
+ body2 = '''
+--boundar\r
+--bounda\r
+--bound\r
+--boun\r
+--bou\r
+--bo\r
+--b\r\r\r\r
+--\r\r\r
+-\r''';
+ _testParse(message, 'boundary', [headers, headers], [body1, body2]);
+
+ // Without initial CRLF.
+ message = '''
+--xxx\r
+\r
+\r
+Body 1\r
+--xxx\r
+\r
+\r
+Body2\r
+--xxx--\r\n''';
+ _testParse(message, 'xxx', null, ['\r\nBody 1', '\r\nBody2']);
+}
+
+void _testParseInvalid() {
+ // Missing end boundary.
+ const message = '''
+\r
+--xxx\r
+\r
+\r
+Body 1\r
+--xxx\r
+\r
+\r
+Body2\r
+--xxx\r\n''';
+ _testParse(message, 'xxx', null, [null, null], true);
+}
+
+void main() {
+ _testParseValid();
+ _testParseInvalid();
+}
diff --git a/pkgs/mime/test/mime_type_test.dart b/pkgs/mime/test/mime_type_test.dart
new file mode 100644
index 0000000..23cb34a
--- /dev/null
+++ b/pkgs/mime/test/mime_type_test.dart
@@ -0,0 +1,320 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' as math;
+
+import 'package:mime/mime.dart';
+import 'package:mime/src/magic_number.dart';
+import 'package:test/test.dart';
+
+void _expectMimeType(String path, String? expectedMimeType,
+ {List<int>? headerBytes, MimeTypeResolver? resolver}) {
+ String? mimeType;
+ if (resolver == null) {
+ mimeType = lookupMimeType(path, headerBytes: headerBytes);
+ } else {
+ mimeType = resolver.lookup(path, headerBytes: headerBytes);
+ }
+
+ expect(mimeType, expectedMimeType);
+}
+
+void main() {
+ group('global-lookup', () {
+ test('by-path', () {
+ _expectMimeType('file.dart', 'text/x-dart');
+ // Test mixed-case
+ _expectMimeType('file.DaRT', 'text/x-dart');
+ _expectMimeType('file.dcm', 'application/dicom');
+ _expectMimeType('file.html', 'text/html');
+ _expectMimeType('file.xhtml', 'application/xhtml+xml');
+ _expectMimeType('file.jpeg', 'image/jpeg');
+ _expectMimeType('file.jpg', 'image/jpeg');
+ _expectMimeType('file.png', 'image/png');
+ _expectMimeType('file.gif', 'image/gif');
+ _expectMimeType('file.cc', 'text/x-c');
+ _expectMimeType('file.c', 'text/x-c');
+ _expectMimeType('file.css', 'text/css');
+ _expectMimeType('file.js', 'text/javascript');
+ _expectMimeType('file.mjs', 'text/javascript');
+ _expectMimeType('file.ps', 'application/postscript');
+ _expectMimeType('file.pdf', 'application/pdf');
+ _expectMimeType('file.tiff', 'image/tiff');
+ _expectMimeType('file.tif', 'image/tiff');
+ _expectMimeType('file.webp', 'image/webp');
+ _expectMimeType('file.mp3', 'audio/mpeg');
+ _expectMimeType('file.aac', 'audio/aac');
+ _expectMimeType('file.ogg', 'audio/ogg');
+ _expectMimeType('file.aiff', 'audio/x-aiff');
+ _expectMimeType('file.m4a', 'audio/mp4');
+ _expectMimeType('file.m4b', 'audio/mp4');
+ _expectMimeType('file.toml', 'application/toml');
+ _expectMimeType('file.md', 'text/markdown');
+ _expectMimeType('file.markdown', 'text/markdown');
+ _expectMimeType('file.heif', 'image/heif');
+ _expectMimeType('file.heic', 'image/heic');
+ });
+
+ test('unknown-mime-type', () {
+ _expectMimeType('file.unsupported-extension', null);
+ });
+
+ test('by-header-bytes', () {
+ _expectMimeType('file.jpg', 'image/png',
+ headerBytes: [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
+ _expectMimeType('file.jpg', 'image/gif', headerBytes: [
+ 0x47,
+ 0x49,
+ 0x46,
+ 0x38,
+ 0x39,
+ 0x61,
+ 0x0D,
+ 0x0A,
+ 0x1A,
+ 0x0A
+ ]);
+ _expectMimeType('file.gif', 'image/jpeg', headerBytes: [
+ 0xFF,
+ 0xD8,
+ 0x46,
+ 0x38,
+ 0x39,
+ 0x61,
+ 0x0D,
+ 0x0A,
+ 0x1A,
+ 0x0A
+ ]);
+ _expectMimeType('file', 'video/3gpp', headerBytes: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x04,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x33,
+ 0x67,
+ 0x70,
+ 0x35
+ ]);
+ _expectMimeType('file.mp4', 'video/mp4', headerBytes: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x04,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+ ]);
+ _expectMimeType('file', 'video/mp4', headerBytes: [
+ 0x00,
+ 0xF0,
+ 0xF0,
+ 0xF0,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x61,
+ 0x76,
+ 0x63,
+ 0x31
+ ]);
+ _expectMimeType('file', 'video/mp4', headerBytes: [
+ 0x00,
+ 0xF0,
+ 0xF0,
+ 0xF0,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x69,
+ 0x73,
+ 0x6F,
+ 0x32
+ ]);
+ _expectMimeType('file', 'video/mp4', headerBytes: [
+ 0x00,
+ 0xF0,
+ 0xF0,
+ 0xF0,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x69,
+ 0x73,
+ 0x6F,
+ 0x6D
+ ]);
+ _expectMimeType('file', 'video/mp4', headerBytes: [
+ 0x00,
+ 0xF0,
+ 0xF0,
+ 0xF0,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x6D,
+ 0x70,
+ 0x34,
+ 0x31
+ ]);
+ _expectMimeType('file', 'video/mp4', headerBytes: [
+ 0x00,
+ 0xF0,
+ 0xF0,
+ 0xF0,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x6D,
+ 0x70,
+ 0x34,
+ 0x32
+ ]);
+ _expectMimeType('file', 'image/webp', headerBytes: [
+ 0x52,
+ 0x49,
+ 0x46,
+ 0x46,
+ 0xE2,
+ 0x4A,
+ 0x01,
+ 0x00,
+ 0x57,
+ 0x45,
+ 0x42,
+ 0x50
+ ]);
+ _expectMimeType('file', 'audio/mpeg',
+ headerBytes: [0x49, 0x44, 0x33, 0x0D, 0x0A, 0x1A, 0x0A]);
+ _expectMimeType('file', 'audio/aac',
+ headerBytes: [0xFF, 0xF1, 0x0D, 0x0A, 0x1A, 0x0A]);
+ _expectMimeType('file', 'audio/ogg',
+ headerBytes: [0x4F, 0x70, 0x75, 0x0D, 0x0A, 0x1A, 0x0A]);
+ _expectMimeType('file', 'audio/x-aiff', headerBytes: [
+ 0x46,
+ 0x4F,
+ 0x52,
+ 0x4D,
+ 0x04,
+ 0x0B,
+ 0xEF,
+ 0xF4,
+ 0x41,
+ 0x49,
+ 0x46,
+ 0x46
+ ]);
+ _expectMimeType('file', 'audio/x-flac',
+ headerBytes: [0x66, 0x4C, 0x61, 0x43]);
+ _expectMimeType('file', 'audio/x-wav', headerBytes: [
+ 0x52,
+ 0x49,
+ 0x46,
+ 0x46,
+ 0xA6,
+ 0x4E,
+ 0x70,
+ 0x03,
+ 0x57,
+ 0x41,
+ 0x56,
+ 0x45
+ ]);
+ _expectMimeType('file', 'image/heic', headerBytes: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x68,
+ 0x65,
+ 0x69,
+ 0x63,
+ 0x00
+ ]);
+ _expectMimeType('file', 'image/heic', headerBytes: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x68,
+ 0x65,
+ 0x69,
+ 0x78,
+ 0x00
+ ]);
+ _expectMimeType('file', 'image/heif', headerBytes: [
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x18,
+ 0x66,
+ 0x74,
+ 0x79,
+ 0x70,
+ 0x6D,
+ 0x69,
+ 0x66,
+ 0x31,
+ 0x00
+ ]);
+ });
+ });
+
+ group('custom-resolver', () {
+ test('override-extension', () {
+ final resolver = MimeTypeResolver();
+ resolver.addExtension('jpg', 'my-mime-type');
+ _expectMimeType('file.jpg', 'my-mime-type', resolver: resolver);
+ });
+
+ test('fallthrough-extension', () {
+ final resolver = MimeTypeResolver();
+ resolver.addExtension('jpg2', 'my-mime-type');
+ _expectMimeType('file.jpg', 'image/jpeg', resolver: resolver);
+ });
+
+ test('with-mask', () {
+ final resolver = MimeTypeResolver.empty();
+ resolver.addMagicNumber([0x01, 0x02, 0x03], 'my-mime-type',
+ mask: [0x01, 0xFF, 0xFE]);
+ _expectMimeType('file', 'my-mime-type',
+ headerBytes: [0x01, 0x02, 0x03], resolver: resolver);
+ _expectMimeType('file', null,
+ headerBytes: [0x01, 0x03, 0x03], resolver: resolver);
+ _expectMimeType('file', 'my-mime-type',
+ headerBytes: [0xFF, 0x02, 0x02], resolver: resolver);
+ });
+ });
+
+ test('default magic number', () {
+ final actualMaxBytes = initialMagicNumbers.fold<int>(
+ 0,
+ (previous, magic) => math.max(previous, magic.numbers.length),
+ );
+
+ expect(initialMagicNumbersMaxLength, actualMaxBytes);
+ });
+}
diff --git a/pkgs/oauth2/.gitignore b/pkgs/oauth2/.gitignore
new file mode 100644
index 0000000..bbe1007
--- /dev/null
+++ b/pkgs/oauth2/.gitignore
@@ -0,0 +1,16 @@
+# Don’t commit the following directories created by pub.
+.buildlog
+.pub/
+.dart_tool/
+build/
+packages
+.packages
+
+# Or the files created by dart2js.
+*.dart.js
+*.js_
+*.js.deps
+*.js.map
+
+# Include when developing application packages.
+pubspec.lock
\ No newline at end of file
diff --git a/pkgs/oauth2/CHANGELOG.md b/pkgs/oauth2/CHANGELOG.md
new file mode 100644
index 0000000..ff39de3
--- /dev/null
+++ b/pkgs/oauth2/CHANGELOG.md
@@ -0,0 +1,135 @@
+## 2.0.4-wip
+
+* Require Dart 3.4
+
+## 2.0.3
+
+* Require `package:http` v1.0.0
+* Move to `dart-lang/tools`.
+
+## 2.0.2
+
+* Require Dart 3.0.
+* Support `package:http` 1.0.0.
+
+## 2.0.1
+
+* Handle `expires_in` when encoded as string.
+* Populate the pubspec `repository` field.
+* Increase the minimum Dart SDK to `2.17.0`.
+
+## 2.0.0
+
+* Migrate to null safety.
+
+## 1.6.3
+
+* Added optional `codeVerifier` parameter to `AuthorizationCodeGrant` constructor.
+
+## 1.6.1
+
+* Added fix to make sure that credentials are only refreshed once when multiple calls are made.
+
+## 1.6.0
+
+* Added PKCE support to `AuthorizationCodeGrant`.
+
+## 1.5.0
+
+* Added support for `clientCredentialsGrant`.
+
+## 1.4.0
+
+* OpenID's id_token treated.
+
+## 1.3.0
+
+* Added `onCredentialsRefreshed` option when creating `Client` objects.
+
+## 1.2.3
+
+* Support the latest `package:http` release.
+
+## 1.2.2
+
+* Allow the stable 2.0 SDK.
+
+## 1.2.1
+
+* Updated SDK version to 2.0.0-dev.17.0
+
+## 1.2.0
+
+* Add a `getParameter()` parameter to `new AuthorizationCodeGrant()`, `new
+ Credentials()`, and `resourceOwnerPasswordGrant()`. This controls how the
+ authorization server's response is parsed for servers that don't provide the
+ standard JSON response.
+
+## 1.1.1
+
+* `resourceOwnerPasswordGrant()` now properly uses its HTTP client for requests
+ made by the OAuth2 client it returns.
+
+## 1.1.0
+
+* Add a `delimiter` parameter to `new AuthorizationCodeGrant()`, `new
+ Credentials()`, and `resourceOwnerPasswordGrant()`. This controls the
+ delimiter between scopes, which some authorization servers require to be
+ different values than the specified `' '`.
+
+## 1.0.2
+
+* Fix all strong-mode warnings.
+* Support `crypto` 1.0.0.
+* Support `http_parser` 3.0.0.
+
+## 1.0.1
+
+* Support `http_parser` 2.0.0.
+
+## 1.0.0
+
+### Breaking changes
+
+* Requests that use client authentication, such as the
+ `AuthorizationCodeGrant`'s access token request and `Credentials`' refresh
+ request, now use HTTP Basic authentication by default. This form of
+ authentication is strongly recommended by the OAuth 2.0 spec. The new
+ `basicAuth` parameter may be set to `false` to force form-based authentication
+ for servers that require it.
+
+* `new AuthorizationCodeGrant()` now takes `secret` as an optional named
+ argument rather than a required argument. This matches the OAuth 2.0 spec,
+ which says that a client secret is only required for confidential clients.
+
+* `new Client()` and `Credentials.refresh()` now take both `identifier` and
+ `secret` as optional named arguments rather than required arguments. This
+ matches the OAuth 2.0 spec, which says that the server may choose not to
+ require client authentication for some flows.
+
+* `new Credentials()` now takes named arguments rather than optional positional
+ arguments.
+
+### Non-breaking changes
+
+* Added a `resourceOwnerPasswordGrant` method.
+
+* The `scopes` argument to `AuthorizationCodeGrant.getAuthorizationUrl()` and
+ `new Credentials()` and the `newScopes` argument to `Credentials.refresh` now
+ take an `Iterable` rather than just a `List`.
+
+* The `scopes` argument to `AuthorizationCodeGrant.getAuthorizationUrl()` now
+ defaults to `null` rather than `const []`.
+
+# 0.9.3
+
+* Update the `http` dependency.
+
+* Since `http` 0.11.0 now works in non-`dart:io` contexts, `oauth2` does as
+ well.
+
+## 0.9.2
+
+* Expand the dependency on the HTTP package to include 0.10.x.
+
+* Add a README file.
diff --git a/pkgs/oauth2/LICENSE b/pkgs/oauth2/LICENSE
new file mode 100644
index 0000000..162572a
--- /dev/null
+++ b/pkgs/oauth2/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/oauth2/README.md b/pkgs/oauth2/README.md
new file mode 100644
index 0000000..07a5976
--- /dev/null
+++ b/pkgs/oauth2/README.md
@@ -0,0 +1,260 @@
+[](https://github.com/dart-lang/tools/actions/workflows/oauth2.yml)
+[](https://pub.dev/packages/oauth2)
+[](https://pub.dev/packages/oauth2/publisher)
+
+A client library for authenticating with a remote service via OAuth2 on behalf
+of a user, and making authorized HTTP requests with the user's OAuth2
+credentials.
+
+## About OAuth2
+
+OAuth2 allows a client (the program using this library) to access and manipulate
+a resource that's owned by a resource owner (the end user) and lives on a remote
+server. The client directs the resource owner to an authorization server
+(usually but not always the same as the server that hosts the resource), where
+the resource owner tells the authorization server to give the client an access
+token. This token serves as proof that the client has permission to access
+resources on behalf of the resource owner.
+
+OAuth2 provides several different methods for the client to obtain
+authorization. At the time of writing, this library only supports the
+[Authorization Code Grant][authorizationCodeGrantSection],
+[Client Credentials Grant][clientCredentialsGrantSection] and
+[Resource Owner Password Grant][resourceOwnerPasswordGrantSection] flows, but
+more may be added in the future.
+
+## Authorization Code Grant
+
+**Resources:** [Class summary][authorizationCodeGrantMethod],
+[OAuth documentation][authorizationCodeGrantDocs]
+
+```dart
+import 'dart:io';
+
+import 'package:oauth2/oauth2.dart' as oauth2;
+
+// These URLs are endpoints that are provided by the authorization
+// server. They're usually included in the server's documentation of its
+// OAuth2 API.
+final authorizationEndpoint =
+ Uri.parse('http://example.com/oauth2/authorization');
+final tokenEndpoint = Uri.parse('http://example.com/oauth2/token');
+
+// The authorization server will issue each client a separate client
+// identifier and secret, which allows the server to tell which client
+// is accessing it. Some servers may also have an anonymous
+// identifier/secret pair that any client may use.
+//
+// Note that clients whose source code or binary executable is readily
+// available may not be able to make sure the client secret is kept a
+// secret. This is fine; OAuth2 servers generally won't rely on knowing
+// with certainty that a client is who it claims to be.
+final identifier = 'my client identifier';
+final secret = 'my client secret';
+
+// This is a URL on your application's server. The authorization server
+// will redirect the resource owner here once they've authorized the
+// client. The redirection will include the authorization code in the
+// query parameters.
+final redirectUrl = Uri.parse('http://my-site.com/oauth2-redirect');
+
+/// A file in which the users credentials are stored persistently. If the server
+/// issues a refresh token allowing the client to refresh outdated credentials,
+/// these may be valid indefinitely, meaning the user never has to
+/// re-authenticate.
+final credentialsFile = File('~/.myapp/credentials.json');
+
+/// Either load an OAuth2 client from saved credentials or authenticate a new
+/// one.
+Future<oauth2.Client> createClient() async {
+ var exists = await credentialsFile.exists();
+
+ // If the OAuth2 credentials have already been saved from a previous run, we
+ // just want to reload them.
+ if (exists) {
+ var credentials =
+ oauth2.Credentials.fromJson(await credentialsFile.readAsString());
+ return oauth2.Client(credentials, identifier: identifier, secret: secret);
+ }
+
+ // If we don't have OAuth2 credentials yet, we need to get the resource owner
+ // to authorize us. We're assuming here that we're a command-line application.
+ var grant = oauth2.AuthorizationCodeGrant(
+ identifier, authorizationEndpoint, tokenEndpoint,
+ secret: secret);
+
+ // A URL on the authorization server (authorizationEndpoint with some additional
+ // query parameters). Scopes and state can optionally be passed into this method.
+ var authorizationUrl = grant.getAuthorizationUrl(redirectUrl);
+
+ // Redirect the resource owner to the authorization URL. Once the resource
+ // owner has authorized, they'll be redirected to `redirectUrl` with an
+ // authorization code. The `redirect` should cause the browser to redirect to
+ // another URL which should also have a listener.
+ //
+ // `redirect` and `listen` are not shown implemented here. See below for the
+ // details.
+ await redirect(authorizationUrl);
+ var responseUrl = await listen(redirectUrl);
+
+ // Once the user is redirected to `redirectUrl`, pass the query parameters to
+ // the AuthorizationCodeGrant. It will validate them and extract the
+ // authorization code to create a new Client.
+ return await grant.handleAuthorizationResponse(responseUrl.queryParameters);
+}
+
+void main() async {
+ var client = await createClient();
+
+ // Once you have a Client, you can use it just like any other HTTP client.
+ print(await client.read('http://example.com/protected-resources.txt'));
+
+ // Once we're done with the client, save the credentials file. This ensures
+ // that if the credentials were automatically refreshed while using the
+ // client, the new credentials are available for the next run of the
+ // program.
+ await credentialsFile.writeAsString(client.credentials.toJson());
+}
+```
+
+<details>
+ <summary>Click here to learn how to implement `redirect` and `listen`.</summary>
+
+--------------------------------------------------------------------------------
+
+There is not a universal example for implementing `redirect` and `listen`,
+because different options exist for each platform.
+
+For Flutter apps, there's two popular approaches:
+
+1. Launch a browser using [url_launcher][] and listen for a redirect using
+ [uni_links][].
+
+ ```dart
+ if (await canLaunch(authorizationUrl.toString())) {
+ await launch(authorizationUrl.toString()); }
+
+ // ------- 8< -------
+
+ final linksStream = getLinksStream().listen((Uri uri) async {
+ if (uri.toString().startsWith(redirectUrl)) {
+ responseUrl = uri;
+ }
+ });
+ ```
+
+1. Launch a WebView inside the app and listen for a redirect using
+ [webview_flutter][].
+
+ ```dart
+ WebView(
+ javascriptMode: JavascriptMode.unrestricted,
+ initialUrl: authorizationUrl.toString(),
+ navigationDelegate: (navReq) {
+ if (navReq.url.startsWith(redirectUrl)) {
+ responseUrl = Uri.parse(navReq.url);
+ return NavigationDecision.prevent;
+ }
+ return NavigationDecision.navigate;
+ },
+ // ------- 8< -------
+ );
+ ```
+
+For Dart apps, the best approach depends on the available options for accessing
+a browser. In general, you'll need to launch the authorization URL through the
+client's browser and listen for the redirect URL.
+</details>
+
+## Client Credentials Grant
+
+**Resources:** [Method summary][clientCredentialsGrantMethod],
+[OAuth documentation][clientCredentialsGrantDocs]
+
+```dart
+// This URL is an endpoint that's provided by the authorization server. It's
+// usually included in the server's documentation of its OAuth2 API.
+final authorizationEndpoint =
+ Uri.parse('http://example.com/oauth2/authorization');
+
+// The OAuth2 specification expects a client's identifier and secret
+// to be sent when using the client credentials grant.
+//
+// Because the client credentials grant is not inherently associated with a user,
+// it is up to the server in question whether the returned token allows limited
+// API access.
+//
+// Either way, you must provide both a client identifier and a client secret:
+final identifier = 'my client identifier';
+final secret = 'my client secret';
+
+// Calling the top-level `clientCredentialsGrant` function will return a
+// [Client] instead.
+var client = await oauth2.clientCredentialsGrant(
+ authorizationEndpoint, identifier, secret);
+
+// With an authenticated client, you can make requests, and the `Bearer` token
+// returned by the server during the client credentials grant will be attached
+// to any request you make.
+var response =
+ await client.read('https://example.com/api/some_resource.json');
+
+// You can save the client's credentials, which consists of an access token, and
+// potentially a refresh token and expiry date, to a file. This way, subsequent runs
+// do not need to reauthenticate, and you can avoid saving the client identifier and
+// secret.
+await credentialsFile.writeAsString(client.credentials.toJson());
+```
+
+## Resource Owner Password Grant
+
+**Resources:** [Method summary][resourceOwnerPasswordGrantMethod],
+[OAuth documentation][resourceOwnerPasswordGrantDocs]
+
+```dart
+// This URL is an endpoint that's provided by the authorization server. It's
+// usually included in the server's documentation of its OAuth2 API.
+final authorizationEndpoint =
+ Uri.parse('http://example.com/oauth2/authorization');
+
+// The user should supply their own username and password.
+final username = 'example user';
+final password = 'example password';
+
+// The authorization server may issue each client a separate client
+// identifier and secret, which allows the server to tell which client
+// is accessing it. Some servers may also have an anonymous
+// identifier/secret pair that any client may use.
+//
+// Some servers don't require the client to authenticate itself, in which case
+// these should be omitted.
+final identifier = 'my client identifier';
+final secret = 'my client secret';
+
+// Make a request to the authorization endpoint that will produce the fully
+// authenticated Client.
+var client = await oauth2.resourceOwnerPasswordGrant(
+ authorizationEndpoint, username, password,
+ identifier: identifier, secret: secret);
+
+// Once you have the client, you can use it just like any other HTTP client.
+var result = await client.read('http://example.com/protected-resources.txt');
+
+// Once we're done with the client, save the credentials file. This will allow
+// us to re-use the credentials and avoid storing the username and password
+// directly.
+File('~/.myapp/credentials.json').writeAsString(client.credentials.toJson());
+```
+
+[authorizationCodeGrantDocs]: https://oauth.net/2/grant-types/authorization-code/
+[authorizationCodeGrantMethod]: https://pub.dev/documentation/oauth2/latest/oauth2/AuthorizationCodeGrant-class.html
+[authorizationCodeGrantSection]: #authorization-code-grant
+[clientCredentialsGrantDocs]: https://oauth.net/2/grant-types/client-credentials/
+[clientCredentialsGrantMethod]: https://pub.dev/documentation/oauth2/latest/oauth2/clientCredentialsGrant.html
+[clientCredentialsGrantSection]: #client-credentials-grant
+[resourceOwnerPasswordGrantDocs]: https://oauth.net/2/grant-types/password/
+[resourceOwnerPasswordGrantMethod]: https://pub.dev/documentation/oauth2/latest/oauth2/resourceOwnerPasswordGrant.html
+[resourceOwnerPasswordGrantSection]: #resource-owner-password-grant
+[uni_links]: https://pub.dev/packages/uni_links
+[url_launcher]: https://pub.dev/packages/url_launcher
+[webview_flutter]: https://pub.dev/packages/webview_flutter
diff --git a/pkgs/oauth2/analysis_options.yaml b/pkgs/oauth2/analysis_options.yaml
new file mode 100644
index 0000000..a5f5ea4
--- /dev/null
+++ b/pkgs/oauth2/analysis_options.yaml
@@ -0,0 +1,22 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ errors:
+ # Too many exceptions
+ comment_references: ignore
+ language:
+ strict-casts: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_private_typedef_functions
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - literal_only_boolean_expressions
+ - no_adjacent_strings_in_list
+ - no_runtimeType_toString
+ - prefer_const_declarations
+ - unnecessary_await_in_return
+ - use_string_buffers
diff --git a/pkgs/oauth2/example/main.dart b/pkgs/oauth2/example/main.dart
new file mode 100644
index 0000000..68e5aa0
--- /dev/null
+++ b/pkgs/oauth2/example/main.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:oauth2/oauth2.dart' as oauth2;
+
+// These URLs are endpoints that are provided by the authorization
+// server. They're usually included in the server's documentation of its
+// OAuth2 API.
+final authorizationEndpoint =
+ Uri.parse('http://example.com/oauth2/authorization');
+final tokenEndpoint = Uri.parse('http://example.com/oauth2/token');
+
+// The authorization server will issue each client a separate client
+// identifier and secret, which allows the server to tell which client
+// is accessing it. Some servers may also have an anonymous
+// identifier/secret pair that any client may use.
+//
+// Note that clients whose source code or binary executable is readily
+// available may not be able to make sure the client secret is kept a
+// secret. This is fine; OAuth2 servers generally won't rely on knowing
+// with certainty that a client is who it claims to be.
+const identifier = 'my client identifier';
+const secret = 'my client secret';
+
+// This is a URL on your application's server. The authorization server
+// will redirect the resource owner here once they've authorized the
+// client. The redirection will include the authorization code in the
+// query parameters.
+final redirectUrl = Uri.parse('http://my-site.com/oauth2-redirect');
+
+/// A file in which the users credentials are stored persistently. If the server
+/// issues a refresh token allowing the client to refresh outdated credentials,
+/// these may be valid indefinitely, meaning the user never has to
+/// re-authenticate.
+final credentialsFile = File('~/.myapp/credentials.json');
+
+/// Either load an OAuth2 client from saved credentials or authenticate a new
+/// one.
+Future<oauth2.Client> createClient() async {
+ var exists = await credentialsFile.exists();
+
+ // If the OAuth2 credentials have already been saved from a previous run, we
+ // just want to reload them.
+ if (exists) {
+ var credentials =
+ oauth2.Credentials.fromJson(await credentialsFile.readAsString());
+ return oauth2.Client(credentials, identifier: identifier, secret: secret);
+ }
+
+ // If we don't have OAuth2 credentials yet, we need to get the resource owner
+ // to authorize us. We're assuming here that we're a command-line application.
+ var grant = oauth2.AuthorizationCodeGrant(
+ identifier, authorizationEndpoint, tokenEndpoint,
+ secret: secret);
+
+ // A URL on the authorization server (authorizationEndpoint with some
+ // additional query parameters). Scopes and state can optionally be passed
+ // into this method.
+ var authorizationUrl = grant.getAuthorizationUrl(redirectUrl);
+
+ // Redirect the resource owner to the authorization URL. Once the resource
+ // owner has authorized, they'll be redirected to `redirectUrl` with an
+ // authorization code. The `redirect` should cause the browser to redirect to
+ // another URL which should also have a listener.
+ //
+ // `redirect` and `listen` are not shown implemented here.
+ await redirect(authorizationUrl);
+ var responseUrl = await listen(redirectUrl);
+
+ // Once the user is redirected to `redirectUrl`, pass the query parameters to
+ // the AuthorizationCodeGrant. It will validate them and extract the
+ // authorization code to create a new Client.
+ return grant.handleAuthorizationResponse(responseUrl.queryParameters);
+}
+
+void main() async {
+ var client = await createClient();
+
+ // Once you have a Client, you can use it just like any other HTTP client.
+ print(await client.read(Uri.http('example.com', 'protected-resources.txt')));
+
+ // Once we're done with the client, save the credentials file. This ensures
+ // that if the credentials were automatically refreshed while using the
+ // client, the new credentials are available for the next run of the
+ // program.
+ await credentialsFile.writeAsString(client.credentials.toJson());
+}
+
+Future<void> redirect(Uri url) async {
+ // Client implementation detail
+}
+
+Future<Uri> listen(Uri url) async {
+ // Client implementation detail
+ return Uri();
+}
diff --git a/pkgs/oauth2/lib/oauth2.dart b/pkgs/oauth2/lib/oauth2.dart
new file mode 100644
index 0000000..45efc5c
--- /dev/null
+++ b/pkgs/oauth2/lib/oauth2.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/authorization_code_grant.dart';
+export 'src/authorization_exception.dart';
+export 'src/client.dart';
+export 'src/client_credentials_grant.dart';
+export 'src/credentials.dart';
+export 'src/expiration_exception.dart';
+export 'src/resource_owner_password_grant.dart';
diff --git a/pkgs/oauth2/lib/src/authorization_code_grant.dart b/pkgs/oauth2/lib/src/authorization_code_grant.dart
new file mode 100644
index 0000000..fac56ba
--- /dev/null
+++ b/pkgs/oauth2/lib/src/authorization_code_grant.dart
@@ -0,0 +1,371 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:math';
+
+import 'package:crypto/crypto.dart';
+import 'package:http/http.dart' as http;
+import 'package:http_parser/http_parser.dart';
+
+import 'authorization_exception.dart';
+import 'client.dart';
+import 'credentials.dart';
+import 'handle_access_token_response.dart';
+import 'parameters.dart';
+import 'utils.dart';
+
+/// A class for obtaining credentials via an [authorization code grant][].
+///
+/// This method of authorization involves sending the resource owner to the
+/// authorization server where they will authorize the client. They're then
+/// redirected back to your server, along with an authorization code. This is
+/// used to obtain [Credentials] and create a fully-authorized [Client].
+///
+/// To use this class, you must first call [getAuthorizationUrl] to get the URL
+/// to which to redirect the resource owner. Then once they've been redirected
+/// back to your application, call [handleAuthorizationResponse] or
+/// [handleAuthorizationCode] to process the authorization server's response and
+/// construct a [Client].
+///
+/// [authorization code grant]: http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.1
+class AuthorizationCodeGrant {
+ /// The function used to parse parameters from a host's response.
+ final GetParameters _getParameters;
+
+ /// The client identifier for this client.
+ ///
+ /// The authorization server will issue each client a separate client
+ /// identifier and secret, which allows the server to tell which client is
+ /// accessing it. Some servers may also have an anonymous identifier/secret
+ /// pair that any client may use.
+ ///
+ /// This is usually global to the program using this library.
+ final String identifier;
+
+ /// The client secret for this client.
+ ///
+ /// The authorization server will issue each client a separate client
+ /// identifier and secret, which allows the server to tell which client is
+ /// accessing it. Some servers may also have an anonymous identifier/secret
+ /// pair that any client may use.
+ ///
+ /// This is usually global to the program using this library.
+ ///
+ /// Note that clients whose source code or binary executable is readily
+ /// available may not be able to make sure the client secret is kept a secret.
+ /// This is fine; OAuth2 servers generally won't rely on knowing with
+ /// certainty that a client is who it claims to be.
+ final String? secret;
+
+ /// A URL provided by the authorization server that serves as the base for the
+ /// URL that the resource owner will be redirected to to authorize this
+ /// client.
+ ///
+ /// This will usually be listed in the authorization server's OAuth2 API
+ /// documentation.
+ final Uri authorizationEndpoint;
+
+ /// A URL provided by the authorization server that this library uses to
+ /// obtain long-lasting credentials.
+ ///
+ /// This will usually be listed in the authorization server's OAuth2 API
+ /// documentation.
+ final Uri tokenEndpoint;
+
+ /// Callback to be invoked whenever the credentials are refreshed.
+ ///
+ /// This will be passed as-is to the constructed [Client].
+ final CredentialsRefreshedCallback? _onCredentialsRefreshed;
+
+ /// Whether to use HTTP Basic authentication for authorizing the client.
+ final bool _basicAuth;
+
+ /// A [String] used to separate scopes; defaults to `" "`.
+ final String _delimiter;
+
+ /// The HTTP client used to make HTTP requests.
+ http.Client? _httpClient;
+
+ /// The URL to which the resource owner will be redirected after they
+ /// authorize this client with the authorization server.
+ Uri? _redirectEndpoint;
+
+ /// The scopes that the client is requesting access to.
+ List<String>? _scopes;
+
+ /// An opaque string that users of this library may specify that will be
+ /// included in the response query parameters.
+ String? _stateString;
+
+ /// The current state of the grant object.
+ _State _state = _State.initial;
+
+ /// Allowed characters for generating the _codeVerifier
+ static const String _charset =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
+
+ /// The PKCE code verifier. Will be generated if one is not provided in the
+ /// constructor.
+ final String _codeVerifier;
+
+ /// Creates a new grant.
+ ///
+ /// If [basicAuth] is `true` (the default), the client credentials are sent to
+ /// the server using using HTTP Basic authentication as defined in [RFC 2617].
+ /// Otherwise, they're included in the request body. Note that the latter form
+ /// is not recommended by the OAuth 2.0 spec, and should only be used if the
+ /// server doesn't support Basic authentication.
+ ///
+ /// [RFC 2617]: https://tools.ietf.org/html/rfc2617
+ ///
+ /// [httpClient] is used for all HTTP requests made by this grant, as well as
+ /// those of the [Client] is constructs.
+ ///
+ /// [onCredentialsRefreshed] will be called by the constructed [Client]
+ /// whenever the credentials are refreshed.
+ ///
+ /// [codeVerifier] String to be used as PKCE code verifier. If none is
+ /// provided a random codeVerifier will be generated.
+ /// The codeVerifier must meet requirements specified in [RFC 7636].
+ ///
+ /// [RFC 7636]: https://tools.ietf.org/html/rfc7636#section-4.1
+ ///
+ /// The scope strings will be separated by the provided [delimiter]. This
+ /// defaults to `" "`, the OAuth2 standard, but some APIs (such as Facebook's)
+ /// use non-standard delimiters.
+ ///
+ /// By default, this follows the OAuth2 spec and requires the server's
+ /// responses to be in JSON format. However, some servers return non-standard
+ /// response formats, which can be parsed using the [getParameters] function.
+ ///
+ /// This function is passed the `Content-Type` header of the response as well
+ /// as its body as a UTF-8-decoded string. It should return a map in the same
+ /// format as the [standard JSON response][].
+ ///
+ /// [standard JSON response]: https://tools.ietf.org/html/rfc6749#section-5.1
+ AuthorizationCodeGrant(
+ this.identifier, this.authorizationEndpoint, this.tokenEndpoint,
+ {this.secret,
+ String? delimiter,
+ bool basicAuth = true,
+ http.Client? httpClient,
+ CredentialsRefreshedCallback? onCredentialsRefreshed,
+ Map<String, dynamic> Function(MediaType? contentType, String body)?
+ getParameters,
+ String? codeVerifier})
+ : _basicAuth = basicAuth,
+ _httpClient = httpClient ?? http.Client(),
+ _delimiter = delimiter ?? ' ',
+ _getParameters = getParameters ?? parseJsonParameters,
+ _onCredentialsRefreshed = onCredentialsRefreshed,
+ _codeVerifier = codeVerifier ?? _createCodeVerifier();
+
+ /// Returns the URL to which the resource owner should be redirected to
+ /// authorize this client.
+ ///
+ /// The resource owner will then be redirected to [redirect], which should
+ /// point to a server controlled by the client. This redirect will have
+ /// additional query parameters that should be passed to
+ /// [handleAuthorizationResponse].
+ ///
+ /// The specific permissions being requested from the authorization server may
+ /// be specified via [scopes]. The scope strings are specific to the
+ /// authorization server and may be found in its documentation. Note that you
+ /// may not be granted access to every scope you request; you may check the
+ /// [Credentials.scopes] field of [Client.credentials] to see which scopes you
+ /// were granted.
+ ///
+ /// An opaque [state] string may also be passed that will be present in the
+ /// query parameters provided to the redirect URL.
+ ///
+ /// It is a [StateError] to call this more than once.
+ Uri getAuthorizationUrl(Uri redirect,
+ {Iterable<String>? scopes, String? state}) {
+ if (_state != _State.initial) {
+ throw StateError('The authorization URL has already been generated.');
+ }
+ _state = _State.awaitingResponse;
+
+ var scopeList = scopes?.toList() ?? <String>[];
+ var codeChallenge = base64Url
+ .encode(sha256.convert(ascii.encode(_codeVerifier)).bytes)
+ .replaceAll('=', '');
+
+ _redirectEndpoint = redirect;
+ _scopes = scopeList;
+ _stateString = state;
+ var parameters = {
+ 'response_type': 'code',
+ 'client_id': identifier,
+ 'redirect_uri': redirect.toString(),
+ 'code_challenge': codeChallenge,
+ 'code_challenge_method': 'S256'
+ };
+
+ if (state != null) parameters['state'] = state;
+ if (scopeList.isNotEmpty) parameters['scope'] = scopeList.join(_delimiter);
+
+ return addQueryParameters(authorizationEndpoint, parameters);
+ }
+
+ /// Processes the query parameters added to a redirect from the authorization
+ /// server.
+ ///
+ /// Note that this "response" is not an HTTP response, but rather the data
+ /// passed to a server controlled by the client as query parameters on the
+ /// redirect URL.
+ ///
+ /// It is a [StateError] to call this more than once, to call it before
+ /// [getAuthorizationUrl] is called, or to call it after
+ /// [handleAuthorizationCode] is called.
+ ///
+ /// Throws [FormatException] if [parameters] is invalid according to the
+ /// OAuth2 spec or if the authorization server otherwise provides invalid
+ /// responses. If `state` was passed to [getAuthorizationUrl], this will throw
+ /// a [FormatException] if the `state` parameter doesn't match the original
+ /// value.
+ ///
+ /// Throws [AuthorizationException] if the authorization fails.
+ Future<Client> handleAuthorizationResponse(
+ Map<String, String> parameters) async {
+ if (_state == _State.initial) {
+ throw StateError('The authorization URL has not yet been generated.');
+ } else if (_state == _State.finished) {
+ throw StateError('The authorization code has already been received.');
+ }
+ _state = _State.finished;
+
+ if (_stateString != null) {
+ if (!parameters.containsKey('state')) {
+ throw FormatException('Invalid OAuth response for '
+ '"$authorizationEndpoint": parameter "state" expected to be '
+ '"$_stateString", was missing.');
+ } else if (parameters['state'] != _stateString) {
+ throw FormatException('Invalid OAuth response for '
+ '"$authorizationEndpoint": parameter "state" expected to be '
+ '"$_stateString", was "${parameters['state']}".');
+ }
+ }
+
+ if (parameters.containsKey('error')) {
+ var description = parameters['error_description'];
+ var uriString = parameters['error_uri'];
+ var uri = uriString == null ? null : Uri.parse(uriString);
+ throw AuthorizationException(parameters['error']!, description, uri);
+ } else if (!parameters.containsKey('code')) {
+ throw FormatException('Invalid OAuth response for '
+ '"$authorizationEndpoint": did not contain required parameter '
+ '"code".');
+ }
+
+ return _handleAuthorizationCode(parameters['code']);
+ }
+
+ /// Processes an authorization code directly.
+ ///
+ /// Usually [handleAuthorizationResponse] is preferable to this method, since
+ /// it validates all of the query parameters. However, some authorization
+ /// servers allow the user to copy and paste an authorization code into a
+ /// command-line application, in which case this method must be used.
+ ///
+ /// It is a [StateError] to call this more than once, to call it before
+ /// [getAuthorizationUrl] is called, or to call it after
+ /// [handleAuthorizationCode] is called.
+ ///
+ /// Throws [FormatException] if the authorization server provides invalid
+ /// responses while retrieving credentials.
+ ///
+ /// Throws [AuthorizationException] if the authorization fails.
+ Future<Client> handleAuthorizationCode(String authorizationCode) async {
+ if (_state == _State.initial) {
+ throw StateError('The authorization URL has not yet been generated.');
+ } else if (_state == _State.finished) {
+ throw StateError('The authorization code has already been received.');
+ }
+ _state = _State.finished;
+
+ return _handleAuthorizationCode(authorizationCode);
+ }
+
+ /// This works just like [handleAuthorizationCode], except it doesn't validate
+ /// the state beforehand.
+ Future<Client> _handleAuthorizationCode(String? authorizationCode) async {
+ var startTime = DateTime.now();
+
+ var headers = <String, String>{};
+
+ var body = {
+ 'grant_type': 'authorization_code',
+ 'code': authorizationCode,
+ 'redirect_uri': _redirectEndpoint.toString(),
+ 'code_verifier': _codeVerifier
+ };
+
+ var secret = this.secret;
+ if (_basicAuth && secret != null) {
+ headers['Authorization'] = basicAuthHeader(identifier, secret);
+ } else {
+ // The ID is required for this request any time basic auth isn't being
+ // used, even if there's no actual client authentication to be done.
+ body['client_id'] = identifier;
+ if (secret != null) body['client_secret'] = secret;
+ }
+
+ var response =
+ await _httpClient!.post(tokenEndpoint, headers: headers, body: body);
+
+ var credentials = handleAccessTokenResponse(
+ response, tokenEndpoint, startTime, _scopes, _delimiter,
+ getParameters: _getParameters);
+ return Client(credentials,
+ identifier: identifier,
+ secret: secret,
+ basicAuth: _basicAuth,
+ httpClient: _httpClient,
+ onCredentialsRefreshed: _onCredentialsRefreshed);
+ }
+
+ // Randomly generate a 128 character string to be used as the PKCE code
+ // verifier.
+ static String _createCodeVerifier() => List.generate(
+ 128,
+ (i) => _charset[Random.secure().nextInt(_charset.length)],
+ ).join();
+
+ /// Closes the grant and frees its resources.
+ ///
+ /// This will close the underlying HTTP client, which is shared by the
+ /// [Client] created by this grant, so it's not safe to close the grant and
+ /// continue using the client.
+ void close() {
+ _httpClient?.close();
+ _httpClient = null;
+ }
+}
+
+/// States that [AuthorizationCodeGrant] can be in.
+class _State {
+ /// [AuthorizationCodeGrant.getAuthorizationUrl] has not yet been called for
+ /// this grant.
+ static const initial = _State('initial');
+
+ // [AuthorizationCodeGrant.getAuthorizationUrl] has been called but neither
+ // [AuthorizationCodeGrant.handleAuthorizationResponse] nor
+ // [AuthorizationCodeGrant.handleAuthorizationCode] has been called.
+ static const awaitingResponse = _State('awaiting response');
+
+ // [AuthorizationCodeGrant.getAuthorizationUrl] and either
+ // [AuthorizationCodeGrant.handleAuthorizationResponse] or
+ // [AuthorizationCodeGrant.handleAuthorizationCode] have been called.
+ static const finished = _State('finished');
+
+ final String _name;
+
+ const _State(this._name);
+
+ @override
+ String toString() => _name;
+}
diff --git a/pkgs/oauth2/lib/src/authorization_exception.dart b/pkgs/oauth2/lib/src/authorization_exception.dart
new file mode 100644
index 0000000..14a5a3c
--- /dev/null
+++ b/pkgs/oauth2/lib/src/authorization_exception.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// An exception raised when OAuth2 authorization fails.
+class AuthorizationException implements Exception {
+ /// The name of the error.
+ ///
+ /// Possible names are enumerated in [the spec][].
+ ///
+ /// [the spec]: http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-5.2
+ final String error;
+
+ /// The description of the error, provided by the server.
+ ///
+ /// May be `null` if the server provided no description.
+ final String? description;
+
+ /// A URL for a page that describes the error in more detail, provided by the
+ /// server.
+ ///
+ /// May be `null` if the server provided no URL.
+ final Uri? uri;
+
+ /// Creates an AuthorizationException.
+ AuthorizationException(this.error, this.description, this.uri);
+
+ /// Provides a string description of the AuthorizationException.
+ @override
+ String toString() {
+ var header = 'OAuth authorization error ($error)';
+ if (description != null) {
+ header = '$header: $description';
+ } else if (uri != null) {
+ header = '$header: $uri';
+ }
+ return '$header.';
+ }
+}
diff --git a/pkgs/oauth2/lib/src/client.dart b/pkgs/oauth2/lib/src/client.dart
new file mode 100644
index 0000000..1dd2282
--- /dev/null
+++ b/pkgs/oauth2/lib/src/client.dart
@@ -0,0 +1,187 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:collection/collection.dart';
+import 'package:http/http.dart' as http;
+import 'package:http_parser/http_parser.dart';
+
+import 'authorization_exception.dart';
+import 'credentials.dart';
+import 'expiration_exception.dart';
+
+/// An OAuth2 client.
+///
+/// This acts as a drop-in replacement for an [http.Client], while sending
+/// OAuth2 authorization credentials along with each request.
+///
+/// The client also automatically refreshes its credentials if possible. When it
+/// makes a request, if its credentials are expired, it will first refresh them.
+/// This means that any request may throw an [AuthorizationException] if the
+/// refresh is not authorized for some reason, a [FormatException] if the
+/// authorization server provides ill-formatted responses, or an
+/// [ExpirationException] if the credentials are expired and can't be refreshed.
+///
+/// The client will also throw an [AuthorizationException] if the resource
+/// server returns a 401 response with a WWW-Authenticate header indicating that
+/// the current credentials are invalid.
+///
+/// If you already have a set of [Credentials], you can construct a [Client]
+/// directly. However, in order to first obtain the credentials, you must
+/// authorize. At the time of writing, the only authorization method this
+/// library supports is [AuthorizationCodeGrant].
+class Client extends http.BaseClient {
+ /// The client identifier for this client.
+ ///
+ /// The authorization server will issue each client a separate client
+ /// identifier and secret, which allows the server to tell which client is
+ /// accessing it. Some servers may also have an anonymous identifier/secret
+ /// pair that any client may use.
+ ///
+ /// This is usually global to the program using this library.
+ final String? identifier;
+
+ /// The client secret for this client.
+ ///
+ /// The authorization server will issue each client a separate client
+ /// identifier and secret, which allows the server to tell which client is
+ /// accessing it. Some servers may also have an anonymous identifier/secret
+ /// pair that any client may use.
+ ///
+ /// This is usually global to the program using this library.
+ ///
+ /// Note that clients whose source code or binary executable is readily
+ /// available may not be able to make sure the client secret is kept a secret.
+ /// This is fine; OAuth2 servers generally won't rely on knowing with
+ /// certainty that a client is who it claims to be.
+ final String? secret;
+
+ /// The credentials this client uses to prove to the resource server that it's
+ /// authorized.
+ ///
+ /// This may change from request to request as the credentials expire and the
+ /// client refreshes them automatically.
+ Credentials get credentials => _credentials;
+ Credentials _credentials;
+
+ /// Callback to be invoked whenever the credentials refreshed.
+ final CredentialsRefreshedCallback? _onCredentialsRefreshed;
+
+ /// Whether to use HTTP Basic authentication for authorizing the client.
+ final bool _basicAuth;
+
+ /// The underlying HTTP client.
+ http.Client? _httpClient;
+
+ /// Creates a new client from a pre-existing set of credentials.
+ ///
+ /// When authorizing a client for the first time, you should use
+ /// [AuthorizationCodeGrant] or [resourceOwnerPasswordGrant] instead of
+ /// constructing a [Client] directly.
+ ///
+ /// [httpClient] is the underlying client that this forwards requests to after
+ /// adding authorization credentials to them.
+ ///
+ /// Throws an [ArgumentError] if [secret] is passed without [identifier].
+ Client(this._credentials,
+ {this.identifier,
+ this.secret,
+ CredentialsRefreshedCallback? onCredentialsRefreshed,
+ bool basicAuth = true,
+ http.Client? httpClient})
+ : _basicAuth = basicAuth,
+ _onCredentialsRefreshed = onCredentialsRefreshed,
+ _httpClient = httpClient ?? http.Client() {
+ if (identifier == null && secret != null) {
+ throw ArgumentError('secret may not be passed without identifier.');
+ }
+ }
+
+ /// Sends an HTTP request with OAuth2 authorization credentials attached.
+ ///
+ /// This will also automatically refresh this client's [Credentials] before
+ /// sending the request if necessary.
+ @override
+ Future<http.StreamedResponse> send(http.BaseRequest request) async {
+ if (credentials.isExpired) {
+ if (!credentials.canRefresh) throw ExpirationException(credentials);
+ await refreshCredentials();
+ }
+
+ request.headers['authorization'] = 'Bearer ${credentials.accessToken}';
+ var response = await _httpClient!.send(request);
+
+ if (response.statusCode != 401) return response;
+ if (!response.headers.containsKey('www-authenticate')) return response;
+
+ List<AuthenticationChallenge> challenges;
+ try {
+ challenges = AuthenticationChallenge.parseHeader(
+ response.headers['www-authenticate']!);
+ } on FormatException {
+ return response;
+ }
+
+ var challenge = challenges
+ .firstWhereOrNull((challenge) => challenge.scheme == 'bearer');
+ if (challenge == null) return response;
+
+ var params = challenge.parameters;
+ if (!params.containsKey('error')) return response;
+
+ throw AuthorizationException(params['error']!, params['error_description'],
+ params['error_uri'] == null ? null : Uri.parse(params['error_uri']!));
+ }
+
+ /// A [Future] used to track whether [refreshCredentials] is running.
+ Future<Credentials>? _refreshingFuture;
+
+ /// Explicitly refreshes this client's credentials. Returns this client.
+ ///
+ /// This will throw a [StateError] if the [Credentials] can't be refreshed, an
+ /// [AuthorizationException] if refreshing the credentials fails, or a
+ /// [FormatException] if the authorization server returns invalid responses.
+ ///
+ /// You may request different scopes than the default by passing in
+ /// [newScopes]. These must be a subset of the scopes in the
+ /// [Credentials.scopes] field of [Client.credentials].
+ Future<Client> refreshCredentials([List<String>? newScopes]) async {
+ if (!credentials.canRefresh) {
+ var prefix = 'OAuth credentials';
+ if (credentials.isExpired) prefix = '$prefix have expired and';
+ throw StateError("$prefix can't be refreshed.");
+ }
+
+ // To make sure that only one refresh happens when credentials are expired
+ // we track it using the [_refreshingFuture]. And also make sure that the
+ // _onCredentialsRefreshed callback is only called once.
+ if (_refreshingFuture == null) {
+ try {
+ _refreshingFuture = credentials.refresh(
+ identifier: identifier,
+ secret: secret,
+ newScopes: newScopes,
+ basicAuth: _basicAuth,
+ httpClient: _httpClient,
+ );
+ _credentials = await _refreshingFuture!;
+ _onCredentialsRefreshed?.call(_credentials);
+ } finally {
+ _refreshingFuture = null;
+ }
+ } else {
+ await _refreshingFuture;
+ }
+
+ return this;
+ }
+
+ /// Closes this client and its underlying HTTP client.
+ @override
+ void close() {
+ _httpClient?.close();
+ _httpClient = null;
+ }
+}
diff --git a/pkgs/oauth2/lib/src/client_credentials_grant.dart b/pkgs/oauth2/lib/src/client_credentials_grant.dart
new file mode 100644
index 0000000..045d1a0
--- /dev/null
+++ b/pkgs/oauth2/lib/src/client_credentials_grant.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:http/http.dart' as http;
+import 'package:http_parser/http_parser.dart';
+
+import 'client.dart';
+import 'handle_access_token_response.dart';
+import 'utils.dart';
+
+/// Obtains credentials using a [client credentials grant](https://tools.ietf.org/html/rfc6749#section-1.3.4).
+///
+/// This mode of authorization uses the client's [identifier] and [secret]
+/// to obtain an authorization token from the authorization server, instead
+/// of sending a user through a dedicated flow.
+///
+/// The client [identifier] and [secret] are required, and are
+/// used to identify and authenticate your specific OAuth2 client. These are
+/// usually global to the program using this library.
+///
+/// The specific permissions being requested from the authorization server may
+/// be specified via [scopes]. The scope strings are specific to the
+/// authorization server and may be found in its documentation. Note that you
+/// may not be granted access to every scope you request; you may check the
+/// [Credentials.scopes] field of [Client.credentials] to see which scopes you
+/// were granted.
+///
+/// The scope strings will be separated by the provided [delimiter]. This
+/// defaults to `" "`, the OAuth2 standard, but some APIs (such as Facebook's)
+/// use non-standard delimiters.
+///
+/// By default, this follows the OAuth2 spec and requires the server's responses
+/// to be in JSON format. However, some servers return non-standard response
+/// formats, which can be parsed using the [getParameters] function.
+///
+/// This function is passed the `Content-Type` header of the response as well as
+/// its body as a UTF-8-decoded string. It should return a map in the same
+/// format as the [standard JSON response](https://tools.ietf.org/html/rfc6749#section-5.1)
+Future<Client> clientCredentialsGrant(
+ Uri authorizationEndpoint, String? identifier, String? secret,
+ {Iterable<String>? scopes,
+ bool basicAuth = true,
+ http.Client? httpClient,
+ String? delimiter,
+ Map<String, dynamic> Function(MediaType? contentType, String body)?
+ getParameters}) async {
+ delimiter ??= ' ';
+ var startTime = DateTime.now();
+
+ var body = {'grant_type': 'client_credentials'};
+
+ var headers = <String, String>{};
+
+ if (identifier != null) {
+ if (basicAuth) {
+ headers['Authorization'] = basicAuthHeader(identifier, secret!);
+ } else {
+ body['client_id'] = identifier;
+ if (secret != null) body['client_secret'] = secret;
+ }
+ }
+
+ if (scopes != null && scopes.isNotEmpty) {
+ body['scope'] = scopes.join(delimiter);
+ }
+
+ httpClient ??= http.Client();
+ var response = await httpClient.post(authorizationEndpoint,
+ headers: headers, body: body);
+
+ var credentials = handleAccessTokenResponse(response, authorizationEndpoint,
+ startTime, scopes?.toList() ?? [], delimiter,
+ getParameters: getParameters);
+ return Client(credentials,
+ identifier: identifier, secret: secret, httpClient: httpClient);
+}
diff --git a/pkgs/oauth2/lib/src/credentials.dart b/pkgs/oauth2/lib/src/credentials.dart
new file mode 100644
index 0000000..088b482
--- /dev/null
+++ b/pkgs/oauth2/lib/src/credentials.dart
@@ -0,0 +1,267 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+import 'package:http_parser/http_parser.dart';
+
+import 'handle_access_token_response.dart';
+import 'parameters.dart';
+import 'utils.dart';
+
+/// Type of the callback when credentials are refreshed.
+typedef CredentialsRefreshedCallback = void Function(Credentials);
+
+/// Credentials that prove that a client is allowed to access a resource on the
+/// resource owner's behalf.
+///
+/// These credentials are long-lasting and can be safely persisted across
+/// multiple runs of the program.
+///
+/// Many authorization servers will attach an expiration date to a set of
+/// credentials, along with a token that can be used to refresh the credentials
+/// once they've expired. The [http.Client] will automatically refresh its
+/// credentials when necessary. It's also possible to explicitly refresh them
+/// via [http.Client.refreshCredentials] or [Credentials.refresh].
+///
+/// Note that a given set of credentials can only be refreshed once, so be sure
+/// to save the refreshed credentials for future use.
+class Credentials {
+ /// A [String] used to separate scopes; defaults to `" "`.
+ String _delimiter;
+
+ /// The token that is sent to the resource server to prove the authorization
+ /// of a client.
+ final String accessToken;
+
+ /// The token that is sent to the authorization server to refresh the
+ /// credentials.
+ ///
+ /// This may be `null`, indicating that the credentials can't be refreshed.
+ final String? refreshToken;
+
+ /// The token that is received from the authorization server to enable
+ /// End-Users to be Authenticated, contains Claims, represented as a
+ /// JSON Web Token (JWT).
+ ///
+ /// This may be `null`, indicating that the 'openid' scope was not
+ /// requested (or not supported).
+ ///
+ /// [spec]: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
+ final String? idToken;
+
+ /// The URL of the authorization server endpoint that's used to refresh the
+ /// credentials.
+ ///
+ /// This may be `null`, indicating that the credentials can't be refreshed.
+ final Uri? tokenEndpoint;
+
+ /// The specific permissions being requested from the authorization server.
+ ///
+ /// The scope strings are specific to the authorization server and may be
+ /// found in its documentation.
+ final List<String>? scopes;
+
+ /// The date at which these credentials will expire.
+ ///
+ /// This is likely to be a few seconds earlier than the server's idea of the
+ /// expiration date.
+ final DateTime? expiration;
+
+ /// The function used to parse parameters from a host's response.
+ final GetParameters _getParameters;
+
+ /// Whether or not these credentials have expired.
+ ///
+ /// Note that it's possible the credentials will expire shortly after this is
+ /// called. However, since the client's expiration date is kept a few seconds
+ /// earlier than the server's, there should be enough leeway to rely on this.
+ bool get isExpired {
+ var expiration = this.expiration;
+ return expiration != null && DateTime.now().isAfter(expiration);
+ }
+
+ /// Whether it's possible to refresh these credentials.
+ bool get canRefresh => refreshToken != null && tokenEndpoint != null;
+
+ /// Creates a new set of credentials.
+ ///
+ /// This class is usually not constructed directly; rather, it's accessed via
+ /// [Client.credentials] after a [Client] is created by
+ /// [AuthorizationCodeGrant]. Alternately, it may be loaded from a serialized
+ /// form via [Credentials.fromJson].
+ ///
+ /// The scope strings will be separated by the provided [delimiter]. This
+ /// defaults to `" "`, the OAuth2 standard, but some APIs (such as Facebook's)
+ /// use non-standard delimiters.
+ ///
+ /// By default, this follows the OAuth2 spec and requires the server's
+ /// responses to be in JSON format. However, some servers return non-standard
+ /// response formats, which can be parsed using the [getParameters] function.
+ ///
+ /// This function is passed the `Content-Type` header of the response as well
+ /// as its body as a UTF-8-decoded string. It should return a map in the same
+ /// format as the [standard JSON response][].
+ ///
+ /// [standard JSON response]: https://tools.ietf.org/html/rfc6749#section-5.1
+ Credentials(this.accessToken,
+ {this.refreshToken,
+ this.idToken,
+ this.tokenEndpoint,
+ Iterable<String>? scopes,
+ this.expiration,
+ String? delimiter,
+ Map<String, dynamic> Function(MediaType? mediaType, String body)?
+ getParameters})
+ : scopes = UnmodifiableListView(
+ // Explicitly type-annotate the list literal to work around
+ // sdk#24202.
+ scopes == null ? <String>[] : scopes.toList()),
+ _delimiter = delimiter ?? ' ',
+ _getParameters = getParameters ?? parseJsonParameters;
+
+ /// Loads a set of credentials from a JSON-serialized form.
+ ///
+ /// Throws a [FormatException] if the JSON is incorrectly formatted.
+ factory Credentials.fromJson(String json) {
+ void validate(bool condition, String message) {
+ if (condition) return;
+ throw FormatException('Failed to load credentials: $message.\n\n$json');
+ }
+
+ dynamic parsed;
+ try {
+ parsed = jsonDecode(json);
+ } on FormatException {
+ validate(false, 'invalid JSON');
+ }
+
+ validate(parsed is Map, 'was not a JSON map');
+
+ parsed = parsed as Map;
+ validate(parsed.containsKey('accessToken'),
+ 'did not contain required field "accessToken"');
+ validate(
+ parsed['accessToken'] is String,
+ 'required field "accessToken" was not a string, was '
+ '${parsed["accessToken"]}',
+ );
+
+ for (var stringField in ['refreshToken', 'idToken', 'tokenEndpoint']) {
+ var value = parsed[stringField];
+ validate(value == null || value is String,
+ 'field "$stringField" was not a string, was "$value"');
+ }
+
+ var scopes = parsed['scopes'];
+ validate(scopes == null || scopes is List,
+ 'field "scopes" was not a list, was "$scopes"');
+
+ var tokenEndpoint = parsed['tokenEndpoint'];
+ Uri? tokenEndpointUri;
+ if (tokenEndpoint != null) {
+ tokenEndpointUri = Uri.parse(tokenEndpoint as String);
+ }
+
+ var expiration = parsed['expiration'];
+ DateTime? expirationDateTime;
+ if (expiration != null) {
+ validate(expiration is int,
+ 'field "expiration" was not an int, was "$expiration"');
+ expiration = expiration as int;
+ expirationDateTime = DateTime.fromMillisecondsSinceEpoch(expiration);
+ }
+
+ return Credentials(
+ parsed['accessToken'] as String,
+ refreshToken: parsed['refreshToken'] as String?,
+ idToken: parsed['idToken'] as String?,
+ tokenEndpoint: tokenEndpointUri,
+ scopes: (scopes as List).map((scope) => scope as String),
+ expiration: expirationDateTime,
+ );
+ }
+
+ /// Serializes a set of credentials to JSON.
+ ///
+ /// Nothing is guaranteed about the output except that it's valid JSON and
+ /// compatible with [Credentials.toJson].
+ String toJson() => jsonEncode({
+ 'accessToken': accessToken,
+ 'refreshToken': refreshToken,
+ 'idToken': idToken,
+ 'tokenEndpoint': tokenEndpoint?.toString(),
+ 'scopes': scopes,
+ 'expiration': expiration?.millisecondsSinceEpoch
+ });
+
+ /// Returns a new set of refreshed credentials.
+ ///
+ /// See [Client.identifier] and [Client.secret] for explanations of those
+ /// parameters.
+ ///
+ /// You may request different scopes than the default by passing in
+ /// [newScopes]. These must be a subset of [scopes].
+ ///
+ /// This throws an [ArgumentError] if [secret] is passed without [identifier],
+ /// a [StateError] if these credentials can't be refreshed, an
+ /// [AuthorizationException] if refreshing the credentials fails, or a
+ /// [FormatException] if the authorization server returns invalid responses.
+ Future<Credentials> refresh(
+ {String? identifier,
+ String? secret,
+ Iterable<String>? newScopes,
+ bool basicAuth = true,
+ http.Client? httpClient}) async {
+ var scopes = this.scopes;
+ if (newScopes != null) scopes = newScopes.toList();
+ scopes ??= [];
+ httpClient ??= http.Client();
+
+ if (identifier == null && secret != null) {
+ throw ArgumentError('secret may not be passed without identifier.');
+ }
+
+ var startTime = DateTime.now();
+ var tokenEndpoint = this.tokenEndpoint;
+ if (refreshToken == null) {
+ throw StateError("Can't refresh credentials without a refresh "
+ 'token.');
+ } else if (tokenEndpoint == null) {
+ throw StateError("Can't refresh credentials without a token "
+ 'endpoint.');
+ }
+
+ var headers = <String, String>{};
+
+ var body = {'grant_type': 'refresh_token', 'refresh_token': refreshToken};
+ if (scopes.isNotEmpty) body['scope'] = scopes.join(_delimiter);
+
+ if (basicAuth && secret != null) {
+ headers['Authorization'] = basicAuthHeader(identifier!, secret);
+ } else {
+ if (identifier != null) body['client_id'] = identifier;
+ if (secret != null) body['client_secret'] = secret;
+ }
+
+ var response =
+ await httpClient.post(tokenEndpoint, headers: headers, body: body);
+ var credentials = handleAccessTokenResponse(
+ response, tokenEndpoint, startTime, scopes, _delimiter,
+ getParameters: _getParameters);
+
+ // The authorization server may issue a new refresh token. If it doesn't,
+ // we should re-use the one we already have.
+ if (credentials.refreshToken != null) return credentials;
+ return Credentials(credentials.accessToken,
+ refreshToken: refreshToken,
+ idToken: credentials.idToken,
+ tokenEndpoint: credentials.tokenEndpoint,
+ scopes: credentials.scopes,
+ expiration: credentials.expiration);
+ }
+}
diff --git a/pkgs/oauth2/lib/src/expiration_exception.dart b/pkgs/oauth2/lib/src/expiration_exception.dart
new file mode 100644
index 0000000..d72fcf6
--- /dev/null
+++ b/pkgs/oauth2/lib/src/expiration_exception.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'credentials.dart';
+
+/// An exception raised when attempting to use expired OAuth2 credentials.
+class ExpirationException implements Exception {
+ /// The expired credentials.
+ final Credentials credentials;
+
+ /// Creates an ExpirationException.
+ ExpirationException(this.credentials);
+
+ /// Provides a string description of the ExpirationException.
+ @override
+ String toString() =>
+ "OAuth2 credentials have expired and can't be refreshed.";
+}
diff --git a/pkgs/oauth2/lib/src/handle_access_token_response.dart b/pkgs/oauth2/lib/src/handle_access_token_response.dart
new file mode 100644
index 0000000..f318e3b
--- /dev/null
+++ b/pkgs/oauth2/lib/src/handle_access_token_response.dart
@@ -0,0 +1,158 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:http/http.dart' as http;
+import 'package:http_parser/http_parser.dart';
+
+import 'authorization_exception.dart';
+import 'credentials.dart';
+import 'parameters.dart';
+
+/// The amount of time to add as a "grace period" for credential expiration.
+///
+/// This allows credential expiration checks to remain valid for a reasonable
+/// amount of time.
+const _expirationGrace = Duration(seconds: 10);
+
+/// Handles a response from the authorization server that contains an access
+/// token.
+///
+/// This response format is common across several different components of the
+/// OAuth2 flow.
+///
+/// By default, this follows the OAuth2 spec and requires the server's responses
+/// to be in JSON format. However, some servers return non-standard response
+/// formats, which can be parsed using the [getParameters] function.
+///
+/// This function is passed the `Content-Type` header of the response as well as
+/// its body as a UTF-8-decoded string. It should return a map in the same
+/// format as the [standard JSON response][].
+///
+/// [standard JSON response]: https://tools.ietf.org/html/rfc6749#section-5.1
+Credentials handleAccessTokenResponse(http.Response response, Uri tokenEndpoint,
+ DateTime startTime, List<String>? scopes, String delimiter,
+ {Map<String, dynamic> Function(MediaType? contentType, String body)?
+ getParameters}) {
+ getParameters ??= parseJsonParameters;
+
+ try {
+ if (response.statusCode != 200) {
+ _handleErrorResponse(response, tokenEndpoint, getParameters);
+ }
+
+ var contentTypeString = response.headers['content-type'];
+ if (contentTypeString == null) {
+ throw const FormatException('Missing Content-Type string.');
+ }
+
+ var parameters =
+ getParameters(MediaType.parse(contentTypeString), response.body);
+
+ for (var requiredParameter in ['access_token', 'token_type']) {
+ if (!parameters.containsKey(requiredParameter)) {
+ throw FormatException(
+ 'did not contain required parameter "$requiredParameter"');
+ } else if (parameters[requiredParameter] is! String) {
+ throw FormatException(
+ 'required parameter "$requiredParameter" was not a string, was '
+ '"${parameters[requiredParameter]}"');
+ }
+ }
+
+ // TODO(nweiz): support the "mac" token type
+ // (http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01)
+ if ((parameters['token_type'] as String).toLowerCase() != 'bearer') {
+ throw FormatException(
+ '"$tokenEndpoint": unknown token type "${parameters['token_type']}"');
+ }
+
+ var expiresIn = parameters['expires_in'];
+ if (expiresIn != null) {
+ if (expiresIn is String) {
+ try {
+ expiresIn = double.parse(expiresIn).toInt();
+ } on FormatException {
+ throw FormatException(
+ 'parameter "expires_in" could not be parsed as in, was: '
+ '"$expiresIn"',
+ );
+ }
+ } else if (expiresIn is! int) {
+ throw FormatException(
+ 'parameter "expires_in" was not an int, was: "$expiresIn"');
+ }
+ }
+
+ for (var name in ['refresh_token', 'id_token', 'scope']) {
+ var value = parameters[name];
+ if (value != null && value is! String) {
+ throw FormatException(
+ 'parameter "$name" was not a string, was "$value"');
+ }
+ }
+
+ var scope = parameters['scope'] as String?;
+ if (scope != null) scopes = scope.split(delimiter);
+
+ var expiration = expiresIn == null
+ ? null
+ : startTime.add(Duration(seconds: expiresIn as int) - _expirationGrace);
+
+ return Credentials(
+ parameters['access_token'] as String,
+ refreshToken: parameters['refresh_token'] as String?,
+ idToken: parameters['id_token'] as String?,
+ tokenEndpoint: tokenEndpoint,
+ scopes: scopes,
+ expiration: expiration,
+ );
+ } on FormatException catch (e) {
+ throw FormatException('Invalid OAuth response for "$tokenEndpoint": '
+ '${e.message}.\n\n${response.body}');
+ }
+}
+
+/// Throws the appropriate exception for an error response from the
+/// authorization server.
+void _handleErrorResponse(
+ http.Response response, Uri tokenEndpoint, GetParameters getParameters) {
+ // OAuth2 mandates a 400 or 401 response code for access token error
+ // responses. If it's not a 400 reponse, the server is either broken or
+ // off-spec.
+ if (response.statusCode != 400 && response.statusCode != 401) {
+ var reason = '';
+ var reasonPhrase = response.reasonPhrase;
+ if (reasonPhrase != null && reasonPhrase.isNotEmpty) {
+ reason = ' $reasonPhrase';
+ }
+ throw FormatException('OAuth request for "$tokenEndpoint" failed '
+ 'with status ${response.statusCode}$reason.\n\n${response.body}');
+ }
+
+ var contentTypeString = response.headers['content-type'];
+ var contentType =
+ contentTypeString == null ? null : MediaType.parse(contentTypeString);
+
+ var parameters = getParameters(contentType, response.body);
+
+ if (!parameters.containsKey('error')) {
+ throw const FormatException('did not contain required parameter "error"');
+ } else if (parameters['error'] is! String) {
+ throw FormatException('required parameter "error" was not a string, was '
+ '"${parameters["error"]}"');
+ }
+
+ for (var name in ['error_description', 'error_uri']) {
+ var value = parameters[name];
+
+ if (value != null && value is! String) {
+ throw FormatException('parameter "$name" was not a string, was "$value"');
+ }
+ }
+
+ var uriString = parameters['error_uri'] as String?;
+ var uri = uriString == null ? null : Uri.parse(uriString);
+ var description = parameters['error_description'] as String?;
+ throw AuthorizationException(parameters['error'] as String, description, uri);
+}
diff --git a/pkgs/oauth2/lib/src/parameters.dart b/pkgs/oauth2/lib/src/parameters.dart
new file mode 100644
index 0000000..ecc6559
--- /dev/null
+++ b/pkgs/oauth2/lib/src/parameters.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:http_parser/http_parser.dart';
+
+/// The type of a callback that parses parameters from an HTTP response.
+typedef GetParameters = Map<String, dynamic> Function(
+ MediaType? contentType, String body);
+
+/// Parses parameters from a response with a JSON body, as per the
+/// [OAuth2 spec][].
+///
+/// [OAuth2 spec]: https://tools.ietf.org/html/rfc6749#section-5.1
+Map<String, dynamic> parseJsonParameters(MediaType? contentType, String body) {
+ // The spec requires a content-type of application/json, but some endpoints
+ // (e.g. Dropbox) serve it as text/javascript instead.
+ if (contentType == null ||
+ (contentType.mimeType != 'application/json' &&
+ contentType.mimeType != 'text/javascript')) {
+ throw FormatException(
+ 'Content-Type was "$contentType", expected "application/json"');
+ }
+
+ var untypedParameters = jsonDecode(body);
+ if (untypedParameters is Map<String, dynamic>) {
+ return untypedParameters;
+ }
+
+ throw FormatException('Parameters must be a map, was "$untypedParameters"');
+}
diff --git a/pkgs/oauth2/lib/src/resource_owner_password_grant.dart b/pkgs/oauth2/lib/src/resource_owner_password_grant.dart
new file mode 100644
index 0000000..96fb503
--- /dev/null
+++ b/pkgs/oauth2/lib/src/resource_owner_password_grant.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:http/http.dart' as http;
+import 'package:http_parser/http_parser.dart';
+
+import 'client.dart';
+import 'credentials.dart';
+import 'handle_access_token_response.dart';
+import 'utils.dart';
+
+/// Obtains credentials using a [resource owner password grant](https://tools.ietf.org/html/rfc6749#section-1.3.3).
+///
+/// This mode of authorization uses the user's username and password to obtain
+/// an authentication token, which can then be stored. This is safer than
+/// storing the username and password directly, but it should be avoided if any
+/// other authorization method is available, since it requires the user to
+/// provide their username and password to a third party (you).
+///
+/// The client [identifier] and [secret] may be issued by the server, and are
+/// used to identify and authenticate your specific OAuth2 client. These are
+/// usually global to the program using this library.
+///
+/// The specific permissions being requested from the authorization server may
+/// be specified via [scopes]. The scope strings are specific to the
+/// authorization server and may be found in its documentation. Note that you
+/// may not be granted access to every scope you request; you may check the
+/// [Credentials.scopes] field of [Client.credentials] to see which scopes you
+/// were granted.
+///
+/// The scope strings will be separated by the provided [delimiter]. This
+/// defaults to `" "`, the OAuth2 standard, but some APIs (such as Facebook's)
+/// use non-standard delimiters.
+///
+/// By default, this follows the OAuth2 spec and requires the server's responses
+/// to be in JSON format. However, some servers return non-standard response
+/// formats, which can be parsed using the [getParameters] function.
+///
+/// This function is passed the `Content-Type` header of the response as well as
+/// its body as a UTF-8-decoded string. It should return a map in the same
+/// format as the [standard JSON response][].
+///
+/// [standard JSON response]: https://tools.ietf.org/html/rfc6749#section-5.1
+Future<Client> resourceOwnerPasswordGrant(
+ Uri authorizationEndpoint, String username, String password,
+ {String? identifier,
+ String? secret,
+ Iterable<String>? scopes,
+ bool basicAuth = true,
+ CredentialsRefreshedCallback? onCredentialsRefreshed,
+ http.Client? httpClient,
+ String? delimiter,
+ Map<String, dynamic> Function(MediaType? contentType, String body)?
+ getParameters}) async {
+ delimiter ??= ' ';
+ var startTime = DateTime.now();
+
+ var body = {
+ 'grant_type': 'password',
+ 'username': username,
+ 'password': password
+ };
+
+ var headers = <String, String>{};
+
+ if (identifier != null) {
+ if (basicAuth) {
+ headers['Authorization'] = basicAuthHeader(identifier, secret!);
+ } else {
+ body['client_id'] = identifier;
+ if (secret != null) body['client_secret'] = secret;
+ }
+ }
+
+ if (scopes != null && scopes.isNotEmpty) {
+ body['scope'] = scopes.join(delimiter);
+ }
+
+ httpClient ??= http.Client();
+ var response = await httpClient.post(authorizationEndpoint,
+ headers: headers, body: body);
+
+ var credentials = handleAccessTokenResponse(
+ response, authorizationEndpoint, startTime, scopes?.toList(), delimiter,
+ getParameters: getParameters);
+ return Client(credentials,
+ identifier: identifier,
+ secret: secret,
+ httpClient: httpClient,
+ onCredentialsRefreshed: onCredentialsRefreshed);
+}
diff --git a/pkgs/oauth2/lib/src/utils.dart b/pkgs/oauth2/lib/src/utils.dart
new file mode 100644
index 0000000..2a22b9f
--- /dev/null
+++ b/pkgs/oauth2/lib/src/utils.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+/// Adds additional query parameters to [url], overwriting the original
+/// parameters if a name conflict occurs.
+Uri addQueryParameters(Uri url, Map<String, String> parameters) => url.replace(
+ queryParameters: Map.from(url.queryParameters)..addAll(parameters));
+
+String basicAuthHeader(String identifier, String secret) {
+ var userPass = '${Uri.encodeFull(identifier)}:${Uri.encodeFull(secret)}';
+ return 'Basic ${base64Encode(ascii.encode(userPass))}';
+}
diff --git a/pkgs/oauth2/pubspec.yaml b/pkgs/oauth2/pubspec.yaml
new file mode 100644
index 0000000..ab705ba
--- /dev/null
+++ b/pkgs/oauth2/pubspec.yaml
@@ -0,0 +1,21 @@
+name: oauth2
+version: 2.0.4-wip
+description: >-
+ A client library for authenticating with a remote service via OAuth2 on
+ behalf of a user, and making authorized HTTP requests with the user's
+ OAuth2 credentials.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/oauth2
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aoauth2
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ collection: ^1.15.0
+ crypto: ^3.0.0
+ http: ^1.0.0
+ http_parser: ^4.0.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.0
diff --git a/pkgs/oauth2/test/authorization_code_grant_test.dart b/pkgs/oauth2/test/authorization_code_grant_test.dart
new file mode 100644
index 0000000..06e88af
--- /dev/null
+++ b/pkgs/oauth2/test/authorization_code_grant_test.dart
@@ -0,0 +1,391 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+import 'package:oauth2/oauth2.dart' as oauth2;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+final redirectUrl = Uri.parse('http://example.com/redirect');
+
+void main() {
+ late ExpectClient client;
+ late oauth2.AuthorizationCodeGrant grant;
+ setUp(() {
+ client = ExpectClient();
+ grant = oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ Uri.parse('https://example.com/authorization'),
+ Uri.parse('https://example.com/token'),
+ secret: 'secret',
+ httpClient: client);
+ });
+
+ group('.getAuthorizationUrl', () {
+ test('builds the correct URL', () {
+ expect(
+ grant.getAuthorizationUrl(redirectUrl).toString(),
+ allOf([
+ startsWith('https://example.com/authorization?response_type=code'),
+ contains('&client_id=identifier'),
+ contains('&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'),
+ matches(r'&code_challenge=[A-Za-z0-9\+\/\-\_]{43}'),
+ contains('&code_challenge_method=S256')
+ ]));
+ });
+
+ test('builds the correct URL with scopes', () {
+ var authorizationUrl = grant
+ .getAuthorizationUrl(redirectUrl, scopes: ['scope', 'other/scope']);
+ expect(
+ authorizationUrl.toString(),
+ allOf([
+ startsWith('https://example.com/authorization?response_type=code'),
+ contains('&client_id=identifier'),
+ contains('&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'),
+ matches(r'&code_challenge=[A-Za-z0-9\+\/\-\_]{43}'),
+ contains('&code_challenge_method=S256'),
+ contains('&scope=scope+other%2Fscope')
+ ]));
+ });
+
+ test('builds the correct URL with passed in code verifier', () {
+ const codeVerifier =
+ 'it1shei7LooGoh3looxaa4sieveijeib2zecauz2oo8aebae5aehee0ahPirewoh'
+ '5Bo6Maexooqui3uL2si6ahweiv7shauc1shahxooveoB3aeyahsaiye0Egh3raix';
+ const expectedCodeChallenge =
+ 'EjfFMv8TFPd3GuNxAn5COhlWBGpfZLimHett7ypJfJ0';
+ var grant = oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ Uri.parse('https://example.com/authorization'),
+ Uri.parse('https://example.com/token'),
+ secret: 'secret',
+ httpClient: client,
+ codeVerifier: codeVerifier);
+ expect(
+ grant.getAuthorizationUrl(redirectUrl).toString(),
+ allOf([
+ startsWith('https://example.com/authorization?response_type=code'),
+ contains('&client_id=identifier'),
+ contains('&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'),
+ contains('&code_challenge=$expectedCodeChallenge'),
+ contains('&code_challenge_method=S256')
+ ]));
+ });
+
+ test('separates scopes with the correct delimiter', () {
+ var grant = oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ Uri.parse('https://example.com/authorization'),
+ Uri.parse('https://example.com/token'),
+ secret: 'secret',
+ httpClient: client,
+ delimiter: '_');
+ var authorizationUrl = grant
+ .getAuthorizationUrl(redirectUrl, scopes: ['scope', 'other/scope']);
+ expect(
+ authorizationUrl.toString(),
+ allOf([
+ startsWith('https://example.com/authorization?response_type=code'),
+ contains('&client_id=identifier'),
+ contains('&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'),
+ matches(r'&code_challenge=[A-Za-z0-9\+\/\-\_]{43}'),
+ contains('&code_challenge_method=S256'),
+ contains('&scope=scope_other%2Fscope')
+ ]));
+ });
+
+ test('builds the correct URL with state', () {
+ var authorizationUrl =
+ grant.getAuthorizationUrl(redirectUrl, state: 'state');
+ expect(
+ authorizationUrl.toString(),
+ allOf([
+ startsWith('https://example.com/authorization?response_type=code'),
+ contains('&client_id=identifier'),
+ contains('&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'),
+ matches(r'&code_challenge=[A-Za-z0-9\+\/\-\_]{43}'),
+ contains('&code_challenge_method=S256'),
+ contains('&state=state')
+ ]));
+ });
+
+ test('merges with existing query parameters', () {
+ grant = oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ Uri.parse('https://example.com/authorization?query=value'),
+ Uri.parse('https://example.com/token'),
+ secret: 'secret',
+ httpClient: client);
+
+ var authorizationUrl = grant.getAuthorizationUrl(redirectUrl);
+ expect(
+ authorizationUrl.toString(),
+ allOf([
+ startsWith('https://example.com/authorization?query=value'),
+ contains('&response_type=code'),
+ contains('&client_id=identifier'),
+ contains('&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'),
+ matches(r'&code_challenge=[A-Za-z0-9\+\/\-\_]{43}'),
+ contains('&code_challenge_method=S256'),
+ ]));
+ });
+
+ test("can't be called twice", () {
+ grant.getAuthorizationUrl(redirectUrl);
+ expect(() => grant.getAuthorizationUrl(redirectUrl), throwsStateError);
+ });
+ });
+
+ group('.handleAuthorizationResponse', () {
+ test("can't be called before .getAuthorizationUrl", () {
+ expect(grant.handleAuthorizationResponse({}), throwsStateError);
+ });
+
+ test("can't be called twice", () {
+ grant.getAuthorizationUrl(redirectUrl);
+ expect(grant.handleAuthorizationResponse({'code': 'auth code'}),
+ throwsFormatException);
+ expect(grant.handleAuthorizationResponse({'code': 'auth code'}),
+ throwsStateError);
+ });
+
+ test('must have a state parameter if the authorization URL did', () {
+ grant.getAuthorizationUrl(redirectUrl, state: 'state');
+ expect(grant.handleAuthorizationResponse({'code': 'auth code'}),
+ throwsFormatException);
+ });
+
+ test('must have the same state parameter the authorization URL did', () {
+ grant.getAuthorizationUrl(redirectUrl, state: 'state');
+ expect(
+ grant.handleAuthorizationResponse(
+ {'code': 'auth code', 'state': 'other state'}),
+ throwsFormatException);
+ });
+
+ test('must have a code parameter', () {
+ grant.getAuthorizationUrl(redirectUrl);
+ expect(grant.handleAuthorizationResponse({}), throwsFormatException);
+ });
+
+ test('with an error parameter throws an AuthorizationException', () {
+ grant.getAuthorizationUrl(redirectUrl);
+ expect(grant.handleAuthorizationResponse({'error': 'invalid_request'}),
+ throwsA(isA<oauth2.AuthorizationException>()));
+ });
+
+ test('sends an authorization code request', () {
+ grant.getAuthorizationUrl(redirectUrl);
+ client.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(grant.tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ allOf([
+ containsPair('grant_type', 'authorization_code'),
+ containsPair('code', 'auth code'),
+ containsPair('redirect_uri', redirectUrl.toString()),
+ containsPair(
+ 'code_verifier', matches(r'[A-Za-z0-9\-\.\_\~]{128}'))
+ ]));
+ expect(request.headers,
+ containsPair('Authorization', 'Basic aWRlbnRpZmllcjpzZWNyZXQ='));
+
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ expect(
+ grant.handleAuthorizationResponse({'code': 'auth code'}).then(
+ (client) => client.credentials.accessToken),
+ completion(equals('access token')));
+ });
+ });
+
+ group('.handleAuthorizationCode', () {
+ test("can't be called before .getAuthorizationUrl", () {
+ expect(grant.handleAuthorizationCode('auth code'), throwsStateError);
+ });
+
+ test("can't be called twice", () {
+ grant.getAuthorizationUrl(redirectUrl);
+ expect(grant.handleAuthorizationCode('auth code'), throwsFormatException);
+ expect(grant.handleAuthorizationCode('auth code'), throwsStateError);
+ });
+
+ test('sends an authorization code request', () async {
+ grant.getAuthorizationUrl(redirectUrl);
+ client.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(grant.tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ allOf([
+ containsPair('grant_type', 'authorization_code'),
+ containsPair('code', 'auth code'),
+ containsPair('redirect_uri', redirectUrl.toString()),
+ containsPair(
+ 'code_verifier', matches(r'[A-Za-z0-9\-\.\_\~]{128}'))
+ ]));
+ expect(request.headers,
+ containsPair('Authorization', 'Basic aWRlbnRpZmllcjpzZWNyZXQ='));
+
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ expect(
+ await grant.handleAuthorizationCode('auth code'),
+ isA<oauth2.Client>().having((c) => c.credentials.accessToken,
+ 'credentials.accessToken', 'access token'));
+ });
+ });
+
+ group('with basicAuth: false', () {
+ setUp(() {
+ client = ExpectClient();
+ grant = oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ Uri.parse('https://example.com/authorization'),
+ Uri.parse('https://example.com/token'),
+ secret: 'secret',
+ basicAuth: false,
+ httpClient: client);
+ });
+
+ test('.handleAuthorizationResponse sends an authorization code request',
+ () {
+ grant.getAuthorizationUrl(redirectUrl);
+ client.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(grant.tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ allOf([
+ containsPair('grant_type', 'authorization_code'),
+ containsPair('code', 'auth code'),
+ containsPair('redirect_uri', redirectUrl.toString()),
+ containsPair(
+ 'code_verifier', matches(r'[A-Za-z0-9\-\.\_\~]{128}')),
+ containsPair('client_id', 'identifier'),
+ containsPair('client_secret', 'secret')
+ ]));
+
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ expect(
+ grant.handleAuthorizationResponse({'code': 'auth code'}).then(
+ (client) => client.credentials.accessToken),
+ completion(equals('access token')));
+ });
+
+ test('.handleAuthorizationCode sends an authorization code request',
+ () async {
+ grant.getAuthorizationUrl(redirectUrl);
+ client.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(grant.tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ allOf([
+ containsPair('grant_type', 'authorization_code'),
+ containsPair('code', 'auth code'),
+ containsPair('redirect_uri', redirectUrl.toString()),
+ containsPair(
+ 'code_verifier', matches(r'[A-Za-z0-9\-\.\_\~]{128}')),
+ containsPair('client_id', 'identifier'),
+ containsPair('client_secret', 'secret')
+ ]));
+
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ expect(
+ await grant.handleAuthorizationCode('auth code'),
+ isA<oauth2.Client>().having((c) => c.credentials.accessToken,
+ 'credentials.accessToken', 'access token'));
+ });
+ });
+
+ group('onCredentialsRefreshed', () {
+ test('is correctly propagated', () async {
+ var isCallbackInvoked = false;
+ var grant = oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ Uri.parse('https://example.com/authorization'),
+ Uri.parse('https://example.com/token'),
+ secret: 'secret',
+ basicAuth: false,
+ httpClient: client, onCredentialsRefreshed: (credentials) {
+ isCallbackInvoked = true;
+ });
+
+ grant.getAuthorizationUrl(redirectUrl);
+ client.expectRequest(
+ (request) => Future.value(
+ http.Response(
+ jsonEncode({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ 'expires_in': -3600,
+ 'refresh_token': 'refresh token',
+ }),
+ 200,
+ headers: {'content-type': 'application/json'},
+ ),
+ ),
+ );
+
+ var oauth2Client = await grant.handleAuthorizationCode('auth code');
+
+ client.expectRequest(
+ (request) => Future.value(
+ http.Response(
+ jsonEncode({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer',
+ }),
+ 200,
+ headers: {'content-type': 'application/json'},
+ ),
+ ),
+ );
+
+ client.expectRequest(
+ (request) => Future.value(http.Response('good job', 200)));
+
+ await oauth2Client.read(Uri.parse('http://example.com/resource'));
+
+ expect(isCallbackInvoked, equals(true));
+ });
+ });
+}
diff --git a/pkgs/oauth2/test/client_credentials_grant_test.dart b/pkgs/oauth2/test/client_credentials_grant_test.dart
new file mode 100644
index 0000000..28de425
--- /dev/null
+++ b/pkgs/oauth2/test/client_credentials_grant_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+import 'package:oauth2/oauth2.dart' as oauth2;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+final success = jsonEncode({
+ 'access_token': '2YotnFZFEjr1zCsicMWpAA',
+ 'token_type': 'bearer',
+ 'expires_in': 3600,
+ 'refresh_token': 'tGzv3JOkF0XG5Qx2TlKWIA',
+});
+
+String auth = 'Basic Y2xpZW50OnNlY3JldA==';
+Uri authEndpoint = Uri.parse('https://example.com');
+
+void main() {
+ late ExpectClient expectClient;
+
+ setUp(() => expectClient = ExpectClient());
+
+ group('basic', () {
+ test('builds correct request with client when using basic auth for client',
+ () async {
+ expectClient.expectRequest((request) async {
+ expect(auth, equals(request.headers['authorization']));
+ expect(request.bodyFields['grant_type'], equals('client_credentials'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var client = await oauth2.clientCredentialsGrant(
+ authEndpoint, 'client', 'secret',
+ httpClient: expectClient);
+
+ expect(client.credentials, isNotNull);
+ expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
+ });
+
+ test('builds correct request when using query parameters for client',
+ () async {
+ expectClient.expectRequest((request) async {
+ expect(request.bodyFields['grant_type'], equals('client_credentials'));
+ expect(request.bodyFields['client_id'], equals('client'));
+ expect(request.bodyFields['client_secret'], equals('secret'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var client = await oauth2.clientCredentialsGrant(
+ authEndpoint, 'client', 'secret',
+ basicAuth: false, httpClient: expectClient);
+ expect(client.credentials, isNotNull);
+ expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
+ });
+
+ test('builds correct request using scope', () async {
+ expectClient.expectRequest((request) async {
+ expect(auth, equals(request.headers['authorization']));
+ expect(request.bodyFields['grant_type'], equals('client_credentials'));
+ expect(request.bodyFields['scope'], equals('one two'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var client = await oauth2.clientCredentialsGrant(
+ authEndpoint, 'client', 'secret',
+ scopes: ['one', 'two'], httpClient: expectClient);
+ expect(client.credentials, isNotNull);
+ expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
+ });
+
+ test('builds correct request using scope with custom delimiter', () async {
+ expectClient.expectRequest((request) async {
+ expect(request.bodyFields['grant_type'], equals('client_credentials'));
+ expect(request.bodyFields['scope'], equals('one,two'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ await oauth2.clientCredentialsGrant(authEndpoint, 'client', 'secret',
+ scopes: ['one', 'two'], httpClient: expectClient, delimiter: ',');
+ });
+
+ test('merges with existing query parameters', () async {
+ var authEndpoint = Uri.parse('https://example.com?query=value');
+
+ expectClient.expectRequest((request) async {
+ expect(request.bodyFields['grant_type'], equals('client_credentials'));
+ expect(request.bodyFields['client_id'], equals('client'));
+ expect(request.bodyFields['client_secret'], equals('secret'));
+ expect(request.url.queryParameters['query'], equals('value'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var client = await oauth2.clientCredentialsGrant(
+ authEndpoint, 'client', 'secret',
+ basicAuth: false, httpClient: expectClient);
+ expect(client.credentials, isNotNull);
+ expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
+ });
+ });
+}
diff --git a/pkgs/oauth2/test/client_test.dart b/pkgs/oauth2/test/client_test.dart
new file mode 100644
index 0000000..3c30d36
--- /dev/null
+++ b/pkgs/oauth2/test/client_test.dart
@@ -0,0 +1,287 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+import 'package:oauth2/oauth2.dart' as oauth2;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+final Uri requestUri = Uri.parse('http://example.com/resource');
+
+final Uri tokenEndpoint = Uri.parse('http://example.com/token');
+
+void main() {
+ late ExpectClient httpClient;
+
+ setUp(() => httpClient = ExpectClient());
+
+ group('with expired credentials', () {
+ test("that can't be refreshed throws an ExpirationException on send", () {
+ var expiration = DateTime.now().subtract(const Duration(hours: 1));
+ var credentials =
+ oauth2.Credentials('access token', expiration: expiration);
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ expect(client.get(requestUri),
+ throwsA(const TypeMatcher<oauth2.ExpirationException>()));
+ });
+
+ test(
+ 'that can be refreshed refreshes the credentials and sends the '
+ 'request', () async {
+ var expiration = DateTime.now().subtract(const Duration(hours: 1));
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ tokenEndpoint: tokenEndpoint,
+ expiration: expiration);
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ return Future.value(http.Response(
+ jsonEncode(
+ {'access_token': 'new access token', 'token_type': 'bearer'}),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'],
+ equals('Bearer new access token'));
+
+ return Future.value(http.Response('good job', 200));
+ });
+
+ await client.read(requestUri);
+ expect(client.credentials.accessToken, equals('new access token'));
+ });
+
+ test(
+ 'that can be refreshed refreshes only once if multiple requests are made',
+ () async {
+ var expiration = DateTime.now().subtract(const Duration(hours: 1));
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ tokenEndpoint: tokenEndpoint,
+ expiration: expiration);
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ return Future.value(http.Response(
+ jsonEncode(
+ {'access_token': 'new access token', 'token_type': 'bearer'}),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ const numCalls = 2;
+
+ for (var i = 0; i < numCalls; i++) {
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'],
+ equals('Bearer new access token'));
+
+ return Future.value(http.Response('good job', 200));
+ });
+ }
+
+ await Future.wait(
+ List<Future<String>>.generate(
+ numCalls, (_) => client.read(requestUri)),
+ );
+
+ expect(client.credentials.accessToken, equals('new access token'));
+ },
+ );
+
+ test('that onCredentialsRefreshed is called', () async {
+ var callbackCalled = false;
+
+ var expiration = DateTime.now().subtract(const Duration(hours: 1));
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ tokenEndpoint: tokenEndpoint,
+ expiration: expiration);
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier',
+ secret: 'secret',
+ httpClient: httpClient, onCredentialsRefreshed: (credentials) {
+ callbackCalled = true;
+ expect(credentials.accessToken, equals('new access token'));
+ });
+
+ httpClient.expectRequest(
+ (request) => Future.value(
+ http.Response(
+ jsonEncode(
+ {'access_token': 'new access token', 'token_type': 'bearer'},
+ ),
+ 200,
+ headers: {'content-type': 'application/json'},
+ ),
+ ),
+ );
+
+ httpClient.expectRequest(
+ (request) => Future.value(http.Response('good job', 200)));
+
+ await client.read(requestUri);
+ expect(callbackCalled, equals(true));
+ });
+ });
+
+ group('with valid credentials', () {
+ test('sends a request with bearer authorization', () {
+ var credentials = oauth2.Credentials('access token');
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'], equals('Bearer access token'));
+
+ return Future.value(http.Response('good job', 200));
+ });
+
+ expect(client.read(requestUri), completion(equals('good job')));
+ });
+
+ test('can manually refresh the credentials', () async {
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token', tokenEndpoint: tokenEndpoint);
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ return Future.value(http.Response(
+ jsonEncode(
+ {'access_token': 'new access token', 'token_type': 'bearer'}),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ await client.refreshCredentials();
+ expect(client.credentials.accessToken, equals('new access token'));
+ });
+
+ test("without a refresh token can't manually refresh the credentials", () {
+ var credentials = oauth2.Credentials('access token');
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ expect(client.refreshCredentials(), throwsA(isStateError));
+ });
+ });
+
+ group('with invalid credentials', () {
+ test('throws an AuthorizationException for a 401 response', () {
+ var credentials = oauth2.Credentials('access token');
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'], equals('Bearer access token'));
+
+ var authenticate = 'Bearer error="invalid_token", error_description='
+ '"Something is terribly wrong."';
+ return Future.value(http.Response('bad job', 401,
+ headers: {'www-authenticate': authenticate}));
+ });
+
+ expect(client.read(requestUri),
+ throwsA(const TypeMatcher<oauth2.AuthorizationException>()));
+ });
+
+ test('passes through a 401 response without www-authenticate', () async {
+ var credentials = oauth2.Credentials('access token');
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'], equals('Bearer access token'));
+
+ return Future.value(http.Response('bad job', 401));
+ });
+
+ expect((await client.get(requestUri)).statusCode, equals(401));
+ });
+
+ test('passes through a 401 response with invalid www-authenticate',
+ () async {
+ var credentials = oauth2.Credentials('access token');
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'], equals('Bearer access token'));
+
+ var authenticate = 'Bearer error="invalid_token" error_description='
+ '"Something is terribly wrong."';
+ return Future.value(http.Response('bad job', 401,
+ headers: {'www-authenticate': authenticate}));
+ });
+
+ expect((await client.get(requestUri)).statusCode, equals(401));
+ });
+
+ test('passes through a 401 response with non-bearer www-authenticate',
+ () async {
+ var credentials = oauth2.Credentials('access token');
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'], equals('Bearer access token'));
+
+ return Future.value(http.Response('bad job', 401,
+ headers: {'www-authenticate': 'Digest'}));
+ });
+
+ expect((await client.get(requestUri)).statusCode, equals(401));
+ });
+
+ test('passes through a 401 response with non-OAuth2 www-authenticate',
+ () async {
+ var credentials = oauth2.Credentials('access token');
+ var client = oauth2.Client(credentials,
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'], equals('Bearer access token'));
+
+ return Future.value(http.Response('bad job', 401,
+ headers: {'www-authenticate': 'Bearer'}));
+ });
+
+ expect((await client.get(requestUri)).statusCode, equals(401));
+ });
+ });
+}
diff --git a/pkgs/oauth2/test/credentials_test.dart b/pkgs/oauth2/test/credentials_test.dart
new file mode 100644
index 0000000..d83bc7e
--- /dev/null
+++ b/pkgs/oauth2/test/credentials_test.dart
@@ -0,0 +1,331 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+import 'package:oauth2/oauth2.dart' as oauth2;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+final Uri tokenEndpoint = Uri.parse('http://example.com/token');
+
+void main() {
+ late ExpectClient httpClient;
+
+ setUp(() => httpClient = ExpectClient());
+
+ test('is not expired if no expiration exists', () {
+ var credentials = oauth2.Credentials('access token');
+ expect(credentials.isExpired, isFalse);
+ });
+
+ test('is not expired if the expiration is in the future', () {
+ var expiration = DateTime.now().add(const Duration(hours: 1));
+ var credentials =
+ oauth2.Credentials('access token', expiration: expiration);
+ expect(credentials.isExpired, isFalse);
+ });
+
+ test('is expired if the expiration is in the past', () {
+ var expiration = DateTime.now().subtract(const Duration(hours: 1));
+ var credentials =
+ oauth2.Credentials('access token', expiration: expiration);
+ expect(credentials.isExpired, isTrue);
+ });
+
+ test("can't refresh without a refresh token", () {
+ var credentials =
+ oauth2.Credentials('access token', tokenEndpoint: tokenEndpoint);
+ expect(credentials.canRefresh, false);
+
+ expect(
+ credentials.refresh(
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient),
+ throwsStateError);
+ });
+
+ test("can't refresh without a token endpoint", () {
+ var credentials =
+ oauth2.Credentials('access token', refreshToken: 'refresh token');
+ expect(credentials.canRefresh, false);
+
+ expect(
+ credentials.refresh(
+ identifier: 'identifier', secret: 'secret', httpClient: httpClient),
+ throwsStateError);
+ });
+
+ test('can refresh with a refresh token and a token endpoint', () async {
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ tokenEndpoint: tokenEndpoint,
+ scopes: ['scope1', 'scope2']);
+ expect(credentials.canRefresh, true);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ equals({
+ 'grant_type': 'refresh_token',
+ 'refresh_token': 'refresh token',
+ 'scope': 'scope1 scope2'
+ }));
+ expect(
+ request.headers,
+ containsPair('Authorization',
+ 'Basic aWQlQzMlQUJudCVDNCVBQmZpZXI6cyVDMyVBQmNyZXQ='));
+
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer',
+ 'refresh_token': 'new refresh token'
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ credentials = await credentials.refresh(
+ identifier: 'idëntīfier', secret: 'sëcret', httpClient: httpClient);
+ expect(credentials.accessToken, equals('new access token'));
+ expect(credentials.refreshToken, equals('new refresh token'));
+ });
+
+ test('sets proper scope string when using custom delimiter', () async {
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ tokenEndpoint: tokenEndpoint,
+ scopes: ['scope1', 'scope2'],
+ delimiter: ',');
+ httpClient.expectRequest((http.Request request) {
+ expect(request.bodyFields['scope'], equals('scope1,scope2'));
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer',
+ 'refresh_token': 'new refresh token'
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+ await credentials.refresh(
+ identifier: 'idëntīfier', secret: 'sëcret', httpClient: httpClient);
+ });
+
+ test('can refresh without a client secret', () async {
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ tokenEndpoint: tokenEndpoint,
+ scopes: ['scope1', 'scope2']);
+ expect(credentials.canRefresh, true);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ equals({
+ 'grant_type': 'refresh_token',
+ 'refresh_token': 'refresh token',
+ 'scope': 'scope1 scope2',
+ 'client_id': 'identifier'
+ }));
+
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer',
+ 'refresh_token': 'new refresh token'
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ credentials = await credentials.refresh(
+ identifier: 'identifier', httpClient: httpClient);
+ expect(credentials.accessToken, equals('new access token'));
+ expect(credentials.refreshToken, equals('new refresh token'));
+ });
+
+ test('can refresh without client authentication', () async {
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ tokenEndpoint: tokenEndpoint,
+ scopes: ['scope1', 'scope2']);
+ expect(credentials.canRefresh, true);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ equals({
+ 'grant_type': 'refresh_token',
+ 'refresh_token': 'refresh token',
+ 'scope': 'scope1 scope2'
+ }));
+
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer',
+ 'refresh_token': 'new refresh token'
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ credentials = await credentials.refresh(httpClient: httpClient);
+ expect(credentials.accessToken, equals('new access token'));
+ expect(credentials.refreshToken, equals('new refresh token'));
+ });
+
+ test("uses the old refresh token if a new one isn't provided", () async {
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token', tokenEndpoint: tokenEndpoint);
+ expect(credentials.canRefresh, true);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ equals({
+ 'grant_type': 'refresh_token',
+ 'refresh_token': 'refresh token'
+ }));
+ expect(
+ request.headers,
+ containsPair('Authorization',
+ 'Basic aWQlQzMlQUJudCVDNCVBQmZpZXI6cyVDMyVBQmNyZXQ='));
+
+ return Future.value(http.Response(
+ jsonEncode(
+ {'access_token': 'new access token', 'token_type': 'bearer'}),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ credentials = await credentials.refresh(
+ identifier: 'idëntīfier', secret: 'sëcret', httpClient: httpClient);
+ expect(credentials.accessToken, equals('new access token'));
+ expect(credentials.refreshToken, equals('refresh token'));
+ });
+
+ test('uses form-field authentication if basicAuth is false', () async {
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ tokenEndpoint: tokenEndpoint,
+ scopes: ['scope1', 'scope2']);
+ expect(credentials.canRefresh, true);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ expect(
+ request.bodyFields,
+ equals({
+ 'grant_type': 'refresh_token',
+ 'refresh_token': 'refresh token',
+ 'scope': 'scope1 scope2',
+ 'client_id': 'idëntīfier',
+ 'client_secret': 'sëcret'
+ }));
+
+ return Future.value(http.Response(
+ jsonEncode({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer',
+ 'refresh_token': 'new refresh token'
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ credentials = await credentials.refresh(
+ identifier: 'idëntīfier',
+ secret: 'sëcret',
+ basicAuth: false,
+ httpClient: httpClient);
+ expect(credentials.accessToken, equals('new access token'));
+ expect(credentials.refreshToken, equals('new refresh token'));
+ });
+
+ group('fromJson', () {
+ oauth2.Credentials fromMap(Map<String, dynamic> map) =>
+ oauth2.Credentials.fromJson(jsonEncode(map));
+
+ test('should load the same credentials from toJson', () {
+ // Round the expiration down to milliseconds since epoch, since that's
+ // what the credentials file stores. Otherwise sub-millisecond time gets
+ // in the way.
+ var expiration = DateTime.now().subtract(const Duration(hours: 1));
+ expiration = DateTime.fromMillisecondsSinceEpoch(
+ expiration.millisecondsSinceEpoch);
+
+ var credentials = oauth2.Credentials('access token',
+ refreshToken: 'refresh token',
+ idToken: 'id token',
+ tokenEndpoint: tokenEndpoint,
+ scopes: ['scope1', 'scope2'],
+ expiration: expiration);
+ var reloaded = oauth2.Credentials.fromJson(credentials.toJson());
+
+ expect(reloaded.accessToken, equals(credentials.accessToken));
+ expect(reloaded.refreshToken, equals(credentials.refreshToken));
+ expect(reloaded.idToken, equals(credentials.idToken));
+ expect(reloaded.tokenEndpoint.toString(),
+ equals(credentials.tokenEndpoint.toString()));
+ expect(reloaded.scopes, equals(credentials.scopes));
+ expect(reloaded.expiration, equals(credentials.expiration));
+ });
+
+ test('should throw a FormatException for invalid JSON', () {
+ expect(
+ () => oauth2.Credentials.fromJson('foo bar'), throwsFormatException);
+ });
+
+ test("should throw a FormatException for JSON that's not a map", () {
+ expect(() => oauth2.Credentials.fromJson('null'), throwsFormatException);
+ });
+
+ test('should throw a FormatException if there is no accessToken', () {
+ expect(() => fromMap({}), throwsFormatException);
+ });
+
+ test('should throw a FormatException if accessToken is not a string', () {
+ expect(() => fromMap({'accessToken': 12}), throwsFormatException);
+ });
+
+ test('should throw a FormatException if refreshToken is not a string', () {
+ expect(() => fromMap({'accessToken': 'foo', 'refreshToken': 12}),
+ throwsFormatException);
+ });
+
+ test('should throw a FormatException if idToken is not a string', () {
+ expect(() => fromMap({'accessToken': 'foo', 'idToken': 12}),
+ throwsFormatException);
+ });
+
+ test('should throw a FormatException if tokenEndpoint is not a string', () {
+ expect(() => fromMap({'accessToken': 'foo', 'tokenEndpoint': 12}),
+ throwsFormatException);
+ });
+
+ test('should throw a FormatException if scopes is not a list', () {
+ expect(() => fromMap({'accessToken': 'foo', 'scopes': 12}),
+ throwsFormatException);
+ });
+
+ test('should throw a FormatException if expiration is not an int', () {
+ expect(() => fromMap({'accessToken': 'foo', 'expiration': '12'}),
+ throwsFormatException);
+ });
+ });
+}
diff --git a/pkgs/oauth2/test/handle_access_token_response_test.dart b/pkgs/oauth2/test/handle_access_token_response_test.dart
new file mode 100644
index 0000000..4d7b519
--- /dev/null
+++ b/pkgs/oauth2/test/handle_access_token_response_test.dart
@@ -0,0 +1,301 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+import 'package:oauth2/oauth2.dart' as oauth2;
+import 'package:oauth2/src/handle_access_token_response.dart';
+import 'package:oauth2/src/parameters.dart';
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+final Uri tokenEndpoint = Uri.parse('https://example.com/token');
+
+final DateTime startTime = DateTime.now();
+
+oauth2.Credentials handle(http.Response response,
+ {GetParameters? getParameters}) =>
+ handleAccessTokenResponse(
+ response, tokenEndpoint, startTime, ['scope'], ' ',
+ getParameters: getParameters);
+
+void main() {
+ group('an error response', () {
+ oauth2.Credentials handleError(
+ {String body = '{"error": "invalid_request"}',
+ int statusCode = 400,
+ Map<String, String> headers = const {
+ 'content-type': 'application/json'
+ }}) =>
+ handle(http.Response(body, statusCode, headers: headers));
+
+ test('causes an AuthorizationException', () {
+ expect(handleError, throwsAuthorizationException);
+ });
+
+ test('with a 401 code causes an AuthorizationException', () {
+ expect(() => handleError(statusCode: 401), throwsAuthorizationException);
+ });
+
+ test('with an unexpected code causes a FormatException', () {
+ expect(() => handleError(statusCode: 500), throwsFormatException);
+ });
+
+ test('with no content-type causes a FormatException', () {
+ expect(() => handleError(headers: {}), throwsFormatException);
+ });
+
+ test('with a non-JSON content-type causes a FormatException', () {
+ expect(() => handleError(headers: {'content-type': 'text/plain'}),
+ throwsFormatException);
+ });
+
+ test('with a non-JSON, non-plain content-type causes a FormatException',
+ () {
+ expect(() => handleError(headers: {'content-type': 'image/png'}),
+ throwsFormatException);
+ });
+
+ test(
+ 'with a JSON content-type and charset causes an '
+ 'AuthorizationException', () {
+ expect(
+ () => handleError(
+ headers: {'content-type': 'application/json; charset=UTF-8'}),
+ throwsAuthorizationException);
+ });
+
+ test('with invalid JSON causes a FormatException', () {
+ expect(() => handleError(body: 'not json'), throwsFormatException);
+ });
+
+ test('with a non-string error causes a FormatException', () {
+ expect(() => handleError(body: '{"error": 12}'), throwsFormatException);
+ });
+
+ test('with a non-string error_description causes a FormatException', () {
+ expect(
+ () => handleError(
+ body: jsonEncode(
+ {'error': 'invalid_request', 'error_description': 12})),
+ throwsFormatException);
+ });
+
+ test('with a non-string error_uri causes a FormatException', () {
+ expect(
+ () => handleError(
+ body: jsonEncode({'error': 'invalid_request', 'error_uri': 12})),
+ throwsFormatException);
+ });
+
+ test('with a string error_description causes a AuthorizationException', () {
+ expect(
+ () => handleError(
+ body: jsonEncode({
+ 'error': 'invalid_request',
+ 'error_description': 'description'
+ })),
+ throwsAuthorizationException);
+ });
+
+ test('with a string error_uri causes a AuthorizationException', () {
+ expect(
+ () => handleError(
+ body: jsonEncode({
+ 'error': 'invalid_request',
+ 'error_uri': 'http://example.com/error'
+ })),
+ throwsAuthorizationException);
+ });
+ });
+
+ group('a success response', () {
+ oauth2.Credentials handleSuccess(
+ {String contentType = 'application/json',
+ Object? accessToken = 'access token',
+ Object? tokenType = 'bearer',
+ Object? expiresIn,
+ Object? refreshToken,
+ Object? scope}) {
+ return handle(http.Response(
+ jsonEncode({
+ 'access_token': accessToken,
+ 'token_type': tokenType,
+ 'expires_in': expiresIn,
+ 'refresh_token': refreshToken,
+ 'scope': scope
+ }),
+ 200,
+ headers: {'content-type': contentType}));
+ }
+
+ test('returns the correct credentials', () {
+ var credentials = handleSuccess();
+ expect(credentials.accessToken, equals('access token'));
+ expect(credentials.tokenEndpoint.toString(),
+ equals(tokenEndpoint.toString()));
+ });
+
+ test('with no content-type causes a FormatException', () {
+ expect(() => handleSuccess(contentType: ''), throwsFormatException);
+ });
+
+ test('with a non-JSON content-type causes a FormatException', () {
+ expect(() => handleSuccess(contentType: 'text/plain'),
+ throwsFormatException);
+ });
+
+ test(
+ 'with a JSON content-type and charset returns the correct '
+ 'credentials', () {
+ var credentials =
+ handleSuccess(contentType: 'application/json; charset=UTF-8');
+ expect(credentials.accessToken, equals('access token'));
+ });
+
+ test('with a JavScript content-type returns the correct credentials', () {
+ var credentials = handleSuccess(contentType: 'text/javascript');
+ expect(credentials.accessToken, equals('access token'));
+ });
+
+ test('with custom getParameters() returns the correct credentials', () {
+ var body = '_${jsonEncode({
+ 'token_type': 'bearer',
+ 'access_token': 'access token'
+ })}';
+ var credentials = handle(
+ http.Response(body, 200, headers: {'content-type': 'text/plain'}),
+ getParameters: (contentType, body) =>
+ jsonDecode(body.substring(1)) as Map<String, dynamic>,
+ );
+ expect(credentials.accessToken, equals('access token'));
+ expect(credentials.tokenEndpoint.toString(),
+ equals(tokenEndpoint.toString()));
+ });
+
+ test('throws a FormatException if custom getParameters rejects response',
+ () {
+ var response = http.Response(
+ jsonEncode({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ 'expires_in': 24,
+ 'refresh_token': 'refresh token',
+ 'scope': 'scope',
+ }),
+ 200,
+ headers: {'content-type': 'foo/bar'});
+
+ expect(
+ () => handle(response,
+ getParameters: (contentType, body) => throw FormatException(
+ 'unsupported content-type: $contentType')),
+ throwsFormatException);
+ });
+
+ test('with a null access token throws a FormatException', () {
+ expect(() => handleSuccess(accessToken: null), throwsFormatException);
+ });
+
+ test('with a non-string access token throws a FormatException', () {
+ expect(() => handleSuccess(accessToken: 12), throwsFormatException);
+ });
+
+ test('with a null token type throws a FormatException', () {
+ expect(() => handleSuccess(tokenType: null), throwsFormatException);
+ });
+
+ test('with a non-string token type throws a FormatException', () {
+ expect(() => handleSuccess(tokenType: 12), throwsFormatException);
+ });
+
+ test('with a non-"bearer" token type throws a FormatException', () {
+ expect(() => handleSuccess(tokenType: 'mac'), throwsFormatException);
+ });
+
+ test('with a non-int expires-in throws a FormatException', () {
+ expect(() => handleSuccess(expiresIn: 'whenever'), throwsFormatException);
+ });
+
+ test(
+ 'with expires-in sets the expiration to ten seconds earlier than the '
+ 'server says', () {
+ var credentials = handleSuccess(expiresIn: 100);
+ expect(credentials.expiration?.millisecondsSinceEpoch,
+ startTime.millisecondsSinceEpoch + 90 * 1000);
+ });
+
+ test('with expires-in encoded as string', () {
+ var credentials = handleSuccess(expiresIn: '110');
+ expect(credentials.expiration?.millisecondsSinceEpoch,
+ startTime.millisecondsSinceEpoch + 100 * 1000);
+ });
+
+ test('with a non-string refresh token throws a FormatException', () {
+ expect(() => handleSuccess(refreshToken: 12), throwsFormatException);
+ });
+
+ test('with a refresh token sets the refresh token', () {
+ var credentials = handleSuccess(refreshToken: 'refresh me');
+ expect(credentials.refreshToken, equals('refresh me'));
+ });
+
+ test('with a non-string scope throws a FormatException', () {
+ expect(() => handleSuccess(scope: 12), throwsFormatException);
+ });
+
+ test('with a scope sets the scopes', () {
+ var credentials = handleSuccess(scope: 'scope1 scope2');
+ expect(credentials.scopes, equals(['scope1', 'scope2']));
+ });
+
+ test('with a custom scope delimiter sets the scopes', () {
+ var response = http.Response(
+ jsonEncode({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ 'expires_in': null,
+ 'refresh_token': null,
+ 'scope': 'scope1,scope2'
+ }),
+ 200,
+ headers: {'content-type': 'application/json'});
+ var credentials = handleAccessTokenResponse(
+ response, tokenEndpoint, startTime, ['scope'], ',');
+ expect(credentials.scopes, equals(['scope1', 'scope2']));
+ });
+ });
+
+ group('a success response with a id_token', () {
+ oauth2.Credentials handleSuccess(
+ {String contentType = 'application/json',
+ Object? accessToken = 'access token',
+ Object? tokenType = 'bearer',
+ Object? expiresIn,
+ Object? idToken = 'decode me',
+ Object? scope}) {
+ return handle(http.Response(
+ jsonEncode({
+ 'access_token': accessToken,
+ 'token_type': tokenType,
+ 'expires_in': expiresIn,
+ 'id_token': idToken,
+ 'scope': scope
+ }),
+ 200,
+ headers: {'content-type': contentType}));
+ }
+
+ test('with a non-string id token throws a FormatException', () {
+ expect(() => handleSuccess(idToken: 12), throwsFormatException);
+ });
+
+ test('with a id token sets the id token', () {
+ var credentials = handleSuccess(idToken: 'decode me');
+ expect(credentials.idToken, equals('decode me'));
+ });
+ });
+}
diff --git a/pkgs/oauth2/test/resource_owner_password_grant_test.dart b/pkgs/oauth2/test/resource_owner_password_grant_test.dart
new file mode 100644
index 0000000..7a5d9b5
--- /dev/null
+++ b/pkgs/oauth2/test/resource_owner_password_grant_test.dart
@@ -0,0 +1,168 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+import 'package:oauth2/oauth2.dart' as oauth2;
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+final success = jsonEncode({
+ 'access_token': '2YotnFZFEjr1zCsicMWpAA',
+ 'token_type': 'bearer',
+ 'expires_in': 3600,
+ 'refresh_token': 'tGzv3JOkF0XG5Qx2TlKWIA',
+});
+
+String auth = 'Basic Y2xpZW50OnNlY3JldA==';
+Uri authEndpoint = Uri.parse('https://example.com');
+
+void main() {
+ late ExpectClient expectClient;
+
+ setUp(() => expectClient = ExpectClient());
+
+ group('basic', () {
+ test('builds correct request with client when using basic auth for client',
+ () async {
+ expectClient.expectRequest((request) async {
+ expect(auth, equals(request.headers['authorization']));
+ expect(request.bodyFields['grant_type'], equals('password'));
+ expect(request.bodyFields['username'], equals('username'));
+ expect(request.bodyFields['password'], equals('userpass'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var client = await oauth2.resourceOwnerPasswordGrant(
+ authEndpoint, 'username', 'userpass',
+ identifier: 'client', secret: 'secret', httpClient: expectClient);
+
+ expect(client.credentials, isNotNull);
+ expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
+ });
+
+ test('passes the onCredentialsRefreshed callback to the client', () async {
+ expectClient.expectRequest((request) async {
+ return http.Response(
+ jsonEncode({
+ 'access_token': '2YotnFZFEjr1zCsicMWpAA',
+ 'token_type': 'bearer',
+ 'expires_in': -3600,
+ 'refresh_token': 'tGzv3JOkF0XG5Qx2TlKWIA',
+ }),
+ 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var isCallbackInvoked = false;
+
+ var client = await oauth2.resourceOwnerPasswordGrant(
+ authEndpoint, 'username', 'userpass',
+ identifier: 'client', secret: 'secret', httpClient: expectClient,
+ onCredentialsRefreshed: (oauth2.Credentials credentials) {
+ isCallbackInvoked = true;
+ });
+
+ expectClient.expectRequest((request) {
+ return Future.value(http.Response(
+ jsonEncode(
+ {'access_token': 'new access token', 'token_type': 'bearer'}),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ expectClient.expectRequest((request) {
+ return Future.value(http.Response('good job', 200));
+ });
+
+ await client.read(Uri.parse('http://example.com/resource'));
+ expect(isCallbackInvoked, equals(true));
+ });
+
+ test('builds correct request when using query parameters for client',
+ () async {
+ expectClient.expectRequest((request) async {
+ expect(request.bodyFields['grant_type'], equals('password'));
+ expect(request.bodyFields['client_id'], equals('client'));
+ expect(request.bodyFields['client_secret'], equals('secret'));
+ expect(request.bodyFields['username'], equals('username'));
+ expect(request.bodyFields['password'], equals('userpass'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var client = await oauth2.resourceOwnerPasswordGrant(
+ authEndpoint, 'username', 'userpass',
+ identifier: 'client',
+ secret: 'secret',
+ basicAuth: false,
+ httpClient: expectClient);
+ expect(client.credentials, isNotNull);
+ expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
+ });
+
+ test('builds correct request using scope', () async {
+ expectClient.expectRequest((request) async {
+ expect(request.bodyFields['grant_type'], equals('password'));
+ expect(request.bodyFields['username'], equals('username'));
+ expect(request.bodyFields['password'], equals('userpass'));
+ expect(request.bodyFields['scope'], equals('one two'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var client = await oauth2.resourceOwnerPasswordGrant(
+ authEndpoint, 'username', 'userpass',
+ scopes: ['one', 'two'], httpClient: expectClient);
+ expect(client.credentials, isNotNull);
+ expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
+ });
+
+ test('builds correct request using scope with custom delimiter', () async {
+ expectClient.expectRequest((request) async {
+ expect(request.bodyFields['grant_type'], equals('password'));
+ expect(request.bodyFields['username'], equals('username'));
+ expect(request.bodyFields['password'], equals('userpass'));
+ expect(request.bodyFields['scope'], equals('one,two'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ await oauth2.resourceOwnerPasswordGrant(
+ authEndpoint, 'username', 'userpass',
+ scopes: ['one', 'two'], httpClient: expectClient, delimiter: ',');
+ });
+
+ test('merges with existing query parameters', () async {
+ var authEndpoint = Uri.parse('https://example.com?query=value');
+
+ expectClient.expectRequest((request) async {
+ expect(request.bodyFields['grant_type'], equals('password'));
+ expect(request.bodyFields['client_id'], equals('client'));
+ expect(request.bodyFields['client_secret'], equals('secret'));
+ expect(request.bodyFields['username'], equals('username'));
+ expect(request.bodyFields['password'], equals('userpass'));
+ expect(request.url.queryParameters['query'], equals('value'));
+ return http.Response(success, 200,
+ headers: {'content-type': 'application/json'});
+ });
+
+ var client = await oauth2.resourceOwnerPasswordGrant(
+ authEndpoint, 'username', 'userpass',
+ identifier: 'client',
+ secret: 'secret',
+ basicAuth: false,
+ httpClient: expectClient);
+ expect(client.credentials, isNotNull);
+ expect(client.credentials.accessToken, equals('2YotnFZFEjr1zCsicMWpAA'));
+ });
+ });
+}
diff --git a/pkgs/oauth2/test/utils.dart b/pkgs/oauth2/test/utils.dart
new file mode 100644
index 0000000..4f3b747
--- /dev/null
+++ b/pkgs/oauth2/test/utils.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection' show Queue;
+
+import 'package:http/http.dart' as http;
+import 'package:http/testing.dart';
+import 'package:oauth2/oauth2.dart' as oauth2;
+import 'package:test/test.dart';
+
+class ExpectClient extends MockClient {
+ final Queue<MockClientHandler> _handlers;
+
+ ExpectClient._(super.fn) : _handlers = Queue<MockClientHandler>();
+
+ factory ExpectClient() {
+ late ExpectClient client;
+ client = ExpectClient._((request) => client._handleRequest(request));
+ return client;
+ }
+
+ void expectRequest(MockClientHandler fn) {
+ var completer = Completer<void>();
+ expect(completer.future, completes);
+
+ _handlers.add((request) {
+ completer.complete(null);
+ return fn(request);
+ });
+ }
+
+ Future<http.Response> _handleRequest(http.Request request) {
+ if (_handlers.isEmpty) {
+ return Future.value(http.Response('not found', 404));
+ } else {
+ return _handlers.removeFirst()(request);
+ }
+ }
+}
+
+/// A matcher for functions that throw AuthorizationException.
+final Matcher throwsAuthorizationException =
+ throwsA(const TypeMatcher<oauth2.AuthorizationException>());
+
+/// A matcher for functions that throw ExpirationException.
+final Matcher throwsExpirationException =
+ throwsA(const TypeMatcher<oauth2.ExpirationException>());
diff --git a/pkgs/package_config/.gitignore b/pkgs/package_config/.gitignore
new file mode 100644
index 0000000..7b888b8
--- /dev/null
+++ b/pkgs/package_config/.gitignore
@@ -0,0 +1,7 @@
+.packages
+.pub
+.dart_tool/
+.vscode/
+packages
+pubspec.lock
+doc/api/
diff --git a/pkgs/package_config/AUTHORS b/pkgs/package_config/AUTHORS
new file mode 100644
index 0000000..e8063a8
--- /dev/null
+++ b/pkgs/package_config/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/package_config/CHANGELOG.md b/pkgs/package_config/CHANGELOG.md
new file mode 100644
index 0000000..101a0fe
--- /dev/null
+++ b/pkgs/package_config/CHANGELOG.md
@@ -0,0 +1,108 @@
+## 2.1.1
+
+- Require Dart 3.4
+- Move to `dart-lang/tools` monorepo.
+
+## 2.1.0
+
+- Adds `minVersion` to `findPackageConfig` and `findPackageConfigVersion`
+ which allows ignoring earlier versions (which currently only means
+ ignoring version 1, aka. `.packages` files.)
+
+- Changes the version number of `SimplePackageConfig.empty` to the
+ current maximum version.
+
+- Improve file read performance; improve lookup performance.
+- Emit an error when a package is inside the package root of another package.
+- Fix a link in the readme.
+
+## 2.0.2
+
+- Update package description and README.
+- Change to package:lints for style checking.
+- Add an example.
+
+## 2.0.1
+
+- Use unique library names to correct docs issue.
+
+## 2.0.0
+
+- Migrate to null safety.
+- Remove legacy APIs.
+- Adds `relativeRoot` property to `Package` which controls whether to
+ make the root URI relative when writing a configuration file.
+
+## 1.9.3
+
+- Fix `Package` constructor not accepting relative `packageUriRoot`.
+
+## 1.9.2
+
+- Updated to support new rules for picking `package_config.json` over
+ a specified `.packages`.
+- Deduce package root from `.packages` derived package configuration,
+ and default all such packages to language version 2.7.
+
+## 1.9.1
+
+- Remove accidental transitive import of `dart:io` from entrypoints that are
+ supposed to be cross-platform compatible.
+
+## 1.9.0
+
+- Based on new JSON file format with more content.
+- This version includes all the new functionality intended for a 2.0.0
+ version, as well as the, now deprecated, version 1 functionality.
+ When we release 2.0.0, the deprecated functionality will be removed.
+
+## 1.1.0
+
+- Allow parsing files with default-package entries and metadata.
+ A default-package entry has an empty key and a valid package name
+ as value.
+ Metadata is attached as fragments to base URIs.
+
+## 1.0.5
+
+- Fix usage of SDK constants.
+
+## 1.0.4
+
+- Set max SDK version to <3.0.0.
+
+## 1.0.3
+
+- Removed unneeded dependency constraint on SDK.
+
+## 1.0.2
+
+- Update SDK constraint to be 2.0.0 dev friendly.
+
+## 1.0.1
+
+- Fix test to not write to sink after it's closed.
+
+## 1.0.0
+
+- Public API marked stable.
+
+## 0.1.5
+
+- `FilePackagesDirectoryPackages.getBase(..)` performance improvements.
+
+## 0.1.4
+
+- Strong mode fixes.
+
+## 0.1.3
+
+- Invalid test cleanup (to keep up with changes in `Uri`).
+
+## 0.1.1
+
+- Syntax updates.
+
+## 0.1.0
+
+- Initial implementation.
diff --git a/pkgs/package_config/LICENSE b/pkgs/package_config/LICENSE
new file mode 100644
index 0000000..7670007
--- /dev/null
+++ b/pkgs/package_config/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2019, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/package_config/README.md b/pkgs/package_config/README.md
new file mode 100644
index 0000000..76fd3cb
--- /dev/null
+++ b/pkgs/package_config/README.md
@@ -0,0 +1,26 @@
+[](https://github.com/dart-lang/tools/actions/workflows/package_config.yaml)
+[](https://pub.dev/packages/package_config)
+[](https://pub.dev/packages/package_config/publisher)
+
+Support for working with **Package Configuration** files as described
+in the Package Configuration v2 [design document](https://github.com/dart-lang/language/blob/master/accepted/2.8/language-versioning/package-config-file-v2.md).
+
+A Dart package configuration file is used to resolve Dart package names (e.g.
+`foobar`) to Dart files containing the source code for that package (e.g.
+`file:///Users/myuser/.pub-cache/hosted/pub.dartlang.org/foobar-1.1.0`). The
+standard package configuration file is `.dart_tool/package_config.json`, and is
+written by the Dart tool when the command `dart pub get` is run.
+
+The primary libraries of this package are
+* `package_config.dart`:
+ Defines the `PackageConfig` class and other types needed to use
+ package configurations, and provides functions to find, read and
+ write package configuration files.
+
+* `package_config_types.dart`:
+ Just the `PackageConfig` class and other types needed to use
+ package configurations. This library does not depend on `dart:io`.
+
+The package includes deprecated backwards compatible functionality to
+work with the `.packages` file. This functionality will not be maintained,
+and will be removed in a future version of this package.
diff --git a/pkgs/package_config/analysis_options.yaml b/pkgs/package_config/analysis_options.yaml
new file mode 100644
index 0000000..c0249e5
--- /dev/null
+++ b/pkgs/package_config/analysis_options.yaml
@@ -0,0 +1,5 @@
+# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+include: package:dart_flutter_team_lints/analysis_options.yaml
diff --git a/pkgs/package_config/example/main.dart b/pkgs/package_config/example/main.dart
new file mode 100644
index 0000000..db137ca
--- /dev/null
+++ b/pkgs/package_config/example/main.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' show Directory;
+
+import 'package:package_config/package_config.dart';
+
+void main() async {
+ var packageConfig = await findPackageConfig(Directory.current);
+ if (packageConfig == null) {
+ print('Failed to locate or read package config.');
+ } else {
+ print('This package depends on ${packageConfig.packages.length} packages:');
+ for (var package in packageConfig.packages) {
+ print('- ${package.name}');
+ }
+ }
+}
diff --git a/pkgs/package_config/lib/package_config.dart b/pkgs/package_config/lib/package_config.dart
new file mode 100644
index 0000000..074c977
--- /dev/null
+++ b/pkgs/package_config/lib/package_config.dart
@@ -0,0 +1,199 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A package configuration is a way to assign file paths to package URIs,
+/// and vice-versa.
+///
+/// This package provides functionality to find, read and write package
+/// configurations in the [specified format](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/package-config-file-v2.md).
+library;
+
+import 'dart:io' show Directory, File;
+import 'dart:typed_data' show Uint8List;
+
+import 'src/discovery.dart' as discover;
+import 'src/errors.dart' show throwError;
+import 'src/package_config.dart';
+import 'src/package_config_io.dart';
+
+export 'package_config_types.dart';
+
+/// Reads a specific package configuration file.
+///
+/// The file must exist and be readable.
+/// It must be either a valid `package_config.json` file
+/// or a valid `.packages` file.
+/// It is considered a `package_config.json` file if its first character
+/// is a `{`.
+///
+/// If the file is a `.packages` file (the file name is `.packages`)
+/// and [preferNewest] is true, the default, also checks if there is
+/// a `.dart_tool/package_config.json` file next
+/// to the original file, and if so, loads that instead.
+/// If [preferNewest] is set to false, a directly specified `.packages` file
+/// is loaded even if there is an available `package_config.json` file.
+/// The caller can determine this from the [PackageConfig.version]
+/// being 1 and look for a `package_config.json` file themselves.
+///
+/// If [onError] is provided, the configuration file parsing will report errors
+/// by calling that function, and then try to recover.
+/// The returned package configuration is a *best effort* attempt to create
+/// a valid configuration from the invalid configuration file.
+/// If no [onError] is provided, errors are thrown immediately.
+Future<PackageConfig> loadPackageConfig(File file,
+ {bool preferNewest = true, void Function(Object error)? onError}) =>
+ readAnyConfigFile(file, preferNewest, onError ?? throwError);
+
+/// Reads a specific package configuration URI.
+///
+/// The file of the URI must exist and be readable.
+/// It must be either a valid `package_config.json` file
+/// or a valid `.packages` file.
+/// It is considered a `package_config.json` file if its first
+/// non-whitespace character is a `{`.
+///
+/// If [preferNewest] is true, the default, and the file is a `.packages` file,
+/// as determined by its file name being `.packages`,
+/// first checks if there is a `.dart_tool/package_config.json` file
+/// next to the original file, and if so, loads that instead.
+/// The [file] *must not* be a `package:` URI.
+/// If [preferNewest] is set to false, a directly specified `.packages` file
+/// is loaded even if there is an available `package_config.json` file.
+/// The caller can determine this from the [PackageConfig.version]
+/// being 1 and look for a `package_config.json` file themselves.
+///
+/// If [loader] is provided, URIs are loaded using that function.
+/// The future returned by the loader must complete with a [Uint8List]
+/// containing the entire file content encoded as UTF-8,
+/// or with `null` if the file does not exist.
+/// The loader may throw at its own discretion, for situations where
+/// it determines that an error might be need user attention,
+/// but it is always allowed to return `null`.
+/// This function makes no attempt to catch such errors.
+/// As such, it may throw any error that [loader] throws.
+///
+/// If no [loader] is supplied, a default loader is used which
+/// only accepts `file:`, `http:` and `https:` URIs,
+/// and which uses the platform file system and HTTP requests to
+/// fetch file content. The default loader never throws because
+/// of an I/O issue, as long as the location URIs are valid.
+/// As such, it does not distinguish between a file not existing,
+/// and it being temporarily locked or unreachable.
+///
+/// If [onError] is provided, the configuration file parsing will report errors
+/// by calling that function, and then try to recover.
+/// The returned package configuration is a *best effort* attempt to create
+/// a valid configuration from the invalid configuration file.
+/// If no [onError] is provided, errors are thrown immediately.
+Future<PackageConfig> loadPackageConfigUri(Uri file,
+ {Future<Uint8List?> Function(Uri uri)? loader,
+ bool preferNewest = true,
+ void Function(Object error)? onError}) =>
+ readAnyConfigFileUri(file, loader, onError ?? throwError, preferNewest);
+
+/// Finds a package configuration relative to [directory].
+///
+/// If [directory] contains a package configuration,
+/// either a `.dart_tool/package_config.json` file or,
+/// if not, a `.packages`, then that file is loaded.
+///
+/// If no file is found in the current directory,
+/// then the parent directories are checked recursively,
+/// all the way to the root directory, to check if those contains
+/// a package configuration.
+/// If [recurse] is set to `false`, this parent directory check is not
+/// performed.
+///
+/// If [onError] is provided, the configuration file parsing will report errors
+/// by calling that function, and then try to recover.
+/// The returned package configuration is a *best effort* attempt to create
+/// a valid configuration from the invalid configuration file.
+/// If no [onError] is provided, errors are thrown immediately.
+///
+/// If [minVersion] is set to something greater than its default,
+/// any lower-version configuration files are ignored in the search.
+///
+/// Returns `null` if no configuration file is found.
+Future<PackageConfig?> findPackageConfig(Directory directory,
+ {bool recurse = true,
+ void Function(Object error)? onError,
+ int minVersion = 1}) {
+ if (minVersion > PackageConfig.maxVersion) {
+ throw ArgumentError.value(minVersion, 'minVersion',
+ 'Maximum known version is ${PackageConfig.maxVersion}');
+ }
+ return discover.findPackageConfig(
+ directory, minVersion, recurse, onError ?? throwError);
+}
+
+/// Finds a package configuration relative to [location].
+///
+/// If [location] contains a package configuration,
+/// either a `.dart_tool/package_config.json` file or,
+/// if not, a `.packages`, then that file is loaded.
+/// The [location] URI *must not* be a `package:` URI.
+/// It should be a hierarchical URI which is supported
+/// by [loader].
+///
+/// If no file is found in the current directory,
+/// then the parent directories are checked recursively,
+/// all the way to the root directory, to check if those contains
+/// a package configuration.
+/// If [recurse] is set to `false`, this parent directory check is not
+/// performed.
+///
+/// If [loader] is provided, URIs are loaded using that function.
+/// The future returned by the loader must complete with a [Uint8List]
+/// containing the entire file content,
+/// or with `null` if the file does not exist.
+/// The loader may throw at its own discretion, for situations where
+/// it determines that an error might be need user attention,
+/// but it is always allowed to return `null`.
+/// This function makes no attempt to catch such errors.
+///
+/// If no [loader] is supplied, a default loader is used which
+/// only accepts `file:`, `http:` and `https:` URIs,
+/// and which uses the platform file system and HTTP requests to
+/// fetch file content. The default loader never throws because
+/// of an I/O issue, as long as the location URIs are valid.
+/// As such, it does not distinguish between a file not existing,
+/// and it being temporarily locked or unreachable.
+///
+/// If [onError] is provided, the configuration file parsing will report errors
+/// by calling that function, and then try to recover.
+/// The returned package configuration is a *best effort* attempt to create
+/// a valid configuration from the invalid configuration file.
+/// If no [onError] is provided, errors are thrown immediately.
+///
+/// If [minVersion] is set to something greater than its default,
+/// any lower-version configuration files are ignored in the search.
+///
+/// Returns `null` if no configuration file is found.
+Future<PackageConfig?> findPackageConfigUri(Uri location,
+ {bool recurse = true,
+ int minVersion = 1,
+ Future<Uint8List?> Function(Uri uri)? loader,
+ void Function(Object error)? onError}) {
+ if (minVersion > PackageConfig.maxVersion) {
+ throw ArgumentError.value(minVersion, 'minVersion',
+ 'Maximum known version is ${PackageConfig.maxVersion}');
+ }
+ return discover.findPackageConfigUri(
+ location, minVersion, loader, onError ?? throwError, recurse);
+}
+
+/// Writes a package configuration to the provided directory.
+///
+/// Writes `.dart_tool/package_config.json` relative to [directory].
+/// If the `.dart_tool/` directory does not exist, it is created.
+/// If it cannot be created, this operation fails.
+///
+/// Also writes a `.packages` file in [directory].
+/// This will stop happening eventually as the `.packages` file becomes
+/// discontinued.
+/// A comment is generated if `[PackageConfig.extraData]` contains a
+/// `"generator"` entry.
+Future<void> savePackageConfig(
+ PackageConfig configuration, Directory directory) =>
+ writePackageConfigJsonFile(configuration, directory);
diff --git a/pkgs/package_config/lib/package_config_types.dart b/pkgs/package_config/lib/package_config_types.dart
new file mode 100644
index 0000000..825f7ac
--- /dev/null
+++ b/pkgs/package_config/lib/package_config_types.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A package configuration is a way to assign file paths to package URIs,
+/// and vice-versa.
+///
+/// {@canonicalFor package_config.InvalidLanguageVersion}
+/// {@canonicalFor package_config.LanguageVersion}
+/// {@canonicalFor package_config.Package}
+/// {@canonicalFor package_config.PackageConfig}
+/// {@canonicalFor errors.PackageConfigError}
+library;
+
+export 'src/errors.dart' show PackageConfigError;
+export 'src/package_config.dart'
+ show InvalidLanguageVersion, LanguageVersion, Package, PackageConfig;
diff --git a/pkgs/package_config/lib/src/discovery.dart b/pkgs/package_config/lib/src/discovery.dart
new file mode 100644
index 0000000..b678410
--- /dev/null
+++ b/pkgs/package_config/lib/src/discovery.dart
@@ -0,0 +1,148 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'errors.dart';
+import 'package_config_impl.dart';
+import 'package_config_io.dart';
+import 'package_config_json.dart';
+import 'packages_file.dart' as packages_file;
+import 'util_io.dart' show defaultLoader, pathJoin;
+
+final Uri packageConfigJsonPath = Uri(path: '.dart_tool/package_config.json');
+final Uri dotPackagesPath = Uri(path: '.packages');
+final Uri currentPath = Uri(path: '.');
+final Uri parentPath = Uri(path: '..');
+
+/// Discover the package configuration for a Dart script.
+///
+/// The [baseDirectory] points to the directory of the Dart script.
+/// A package resolution strategy is found by going through the following steps,
+/// and stopping when something is found.
+///
+/// * Check if a `.dart_tool/package_config.json` file exists in the directory.
+/// * Check if a `.packages` file exists in the directory
+/// (if `minVersion <= 1`).
+/// * Repeat these checks for the parent directories until reaching the
+/// root directory if [recursive] is true.
+///
+/// If any of these tests succeed, a `PackageConfig` class is returned.
+/// Returns `null` if no configuration was found. If a configuration
+/// is needed, then the caller can supply [PackageConfig.empty].
+///
+/// If [minVersion] is greater than 1, `.packages` files are ignored.
+/// If [minVersion] is greater than the version read from the
+/// `package_config.json` file, it too is ignored.
+Future<PackageConfig?> findPackageConfig(Directory baseDirectory,
+ int minVersion, bool recursive, void Function(Object error) onError) async {
+ var directory = baseDirectory;
+ if (!directory.isAbsolute) directory = directory.absolute;
+ if (!await directory.exists()) {
+ return null;
+ }
+ do {
+ // Check for $cwd/.packages
+ var packageConfig =
+ await findPackageConfigInDirectory(directory, minVersion, onError);
+ if (packageConfig != null) return packageConfig;
+ if (!recursive) break;
+ // Check in parent directories.
+ var parentDirectory = directory.parent;
+ if (parentDirectory.path == directory.path) break;
+ directory = parentDirectory;
+ } while (true);
+ return null;
+}
+
+/// Similar to [findPackageConfig] but based on a URI.
+Future<PackageConfig?> findPackageConfigUri(
+ Uri location,
+ int minVersion,
+ Future<Uint8List?> Function(Uri uri)? loader,
+ void Function(Object error) onError,
+ bool recursive) async {
+ if (location.isScheme('package')) {
+ onError(PackageConfigArgumentError(
+ location, 'location', 'Must not be a package: URI'));
+ return null;
+ }
+ if (loader == null) {
+ if (location.isScheme('file')) {
+ return findPackageConfig(
+ Directory.fromUri(location.resolveUri(currentPath)),
+ minVersion,
+ recursive,
+ onError);
+ }
+ loader = defaultLoader;
+ }
+ if (!location.path.endsWith('/')) location = location.resolveUri(currentPath);
+ while (true) {
+ var file = location.resolveUri(packageConfigJsonPath);
+ var bytes = await loader(file);
+ if (bytes != null) {
+ var config = parsePackageConfigBytes(bytes, file, onError);
+ if (config.version >= minVersion) return config;
+ }
+ if (minVersion <= 1) {
+ file = location.resolveUri(dotPackagesPath);
+ bytes = await loader(file);
+ if (bytes != null) {
+ return packages_file.parse(bytes, file, onError);
+ }
+ }
+ if (!recursive) break;
+ var parent = location.resolveUri(parentPath);
+ if (parent == location) break;
+ location = parent;
+ }
+ return null;
+}
+
+/// Finds a `.packages` or `.dart_tool/package_config.json` file in [directory].
+///
+/// Loads the file, if it is there, and returns the resulting [PackageConfig].
+/// Returns `null` if the file isn't there.
+/// Reports a [FormatException] if a file is there but the content is not valid.
+/// If the file exists, but fails to be read, the file system error is reported.
+///
+/// If [onError] is supplied, parsing errors are reported using that, and
+/// a best-effort attempt is made to return a package configuration.
+/// This may be the empty package configuration.
+///
+/// If [minVersion] is greater than 1, `.packages` files are ignored.
+/// If [minVersion] is greater than the version read from the
+/// `package_config.json` file, it too is ignored.
+Future<PackageConfig?> findPackageConfigInDirectory(Directory directory,
+ int minVersion, void Function(Object error) onError) async {
+ var packageConfigFile = await checkForPackageConfigJsonFile(directory);
+ if (packageConfigFile != null) {
+ var config = await readPackageConfigJsonFile(packageConfigFile, onError);
+ if (config.version < minVersion) return null;
+ return config;
+ }
+ if (minVersion <= 1) {
+ packageConfigFile = await checkForDotPackagesFile(directory);
+ if (packageConfigFile != null) {
+ return await readDotPackagesFile(packageConfigFile, onError);
+ }
+ }
+ return null;
+}
+
+Future<File?> checkForPackageConfigJsonFile(Directory directory) async {
+ assert(directory.isAbsolute);
+ var file =
+ File(pathJoin(directory.path, '.dart_tool', 'package_config.json'));
+ if (await file.exists()) return file;
+ return null;
+}
+
+Future<File?> checkForDotPackagesFile(Directory directory) async {
+ var file = File(pathJoin(directory.path, '.packages'));
+ if (await file.exists()) return file;
+ return null;
+}
diff --git a/pkgs/package_config/lib/src/errors.dart b/pkgs/package_config/lib/src/errors.dart
new file mode 100644
index 0000000..a66fef7
--- /dev/null
+++ b/pkgs/package_config/lib/src/errors.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// General superclass of most errors and exceptions thrown by this package.
+///
+/// Only covers errors thrown while parsing package configuration files.
+/// Programming errors and I/O exceptions are not covered.
+abstract class PackageConfigError {
+ PackageConfigError._();
+}
+
+class PackageConfigArgumentError extends ArgumentError
+ implements PackageConfigError {
+ PackageConfigArgumentError(
+ Object? super.value, String super.name, String super.message)
+ : super.value();
+
+ PackageConfigArgumentError.from(ArgumentError error)
+ : super.value(error.invalidValue, error.name, error.message);
+}
+
+class PackageConfigFormatException extends FormatException
+ implements PackageConfigError {
+ PackageConfigFormatException(super.message, Object? super.source,
+ [super.offset]);
+
+ PackageConfigFormatException.from(FormatException exception)
+ : super(exception.message, exception.source, exception.offset);
+}
+
+/// The default `onError` handler.
+// ignore: only_throw_errors
+Never throwError(Object error) => throw error;
diff --git a/pkgs/package_config/lib/src/package_config.dart b/pkgs/package_config/lib/src/package_config.dart
new file mode 100644
index 0000000..155dfc5
--- /dev/null
+++ b/pkgs/package_config/lib/src/package_config.dart
@@ -0,0 +1,402 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+
+import 'errors.dart';
+import 'package_config_impl.dart';
+import 'package_config_json.dart';
+
+/// A package configuration.
+///
+/// Associates configuration data to packages and files in packages.
+///
+/// More members may be added to this class in the future,
+/// so classes outside of this package must not implement [PackageConfig]
+/// or any subclass of it.
+abstract class PackageConfig {
+ /// The largest configuration version currently recognized.
+ static const int maxVersion = 2;
+
+ /// An empty package configuration.
+ ///
+ /// A package configuration with no available packages.
+ /// Is used as a default value where a package configuration
+ /// is expected, but none have been specified or found.
+ static const PackageConfig empty = SimplePackageConfig.empty();
+
+ /// Creates a package configuration with the provided available [packages].
+ ///
+ /// The packages must be valid packages (valid package name, valid
+ /// absolute directory URIs, valid language version, if any),
+ /// and there must not be two packages with the same name.
+ ///
+ /// The package's root ([Package.root]) and package-root
+ /// ([Package.packageUriRoot]) paths must satisfy a number of constraints
+ /// We say that one path (which we know ends with a `/` character)
+ /// is inside another path, if the latter path is a prefix of the former path,
+ /// including the two paths being the same.
+ ///
+ /// * No package's root must be the same as another package's root.
+ /// * The package-root of a package must be inside the package's root.
+ /// * If one package's package-root is inside another package's root,
+ /// then the latter package's package root must not be inside the former
+ /// package's root. (No getting between a package and its package root!)
+ /// This also disallows a package's root being the same as another
+ /// package's package root.
+ ///
+ /// If supplied, the [extraData] will be available as the
+ /// [PackageConfig.extraData] of the created configuration.
+ ///
+ /// The version of the resulting configuration is always [maxVersion].
+ factory PackageConfig(Iterable<Package> packages, {Object? extraData}) =>
+ SimplePackageConfig(maxVersion, packages, extraData);
+
+ /// Parses a package configuration file.
+ ///
+ /// The [bytes] must be an UTF-8 encoded JSON object
+ /// containing a valid package configuration.
+ ///
+ /// The [baseUri] is used as the base for resolving relative
+ /// URI references in the configuration file. If the configuration
+ /// has been read from a file, the [baseUri] can be the URI of that
+ /// file, or of the directory it occurs in.
+ ///
+ /// If [onError] is provided, errors found during parsing or building
+ /// the configuration are reported by calling [onError] instead of
+ /// throwing, and parser makes a *best effort* attempt to continue
+ /// despite the error. The input must still be valid JSON.
+ /// The result may be [PackageConfig.empty] if there is no way to
+ /// extract useful information from the bytes.
+ static PackageConfig parseBytes(Uint8List bytes, Uri baseUri,
+ {void Function(Object error)? onError}) =>
+ parsePackageConfigBytes(bytes, baseUri, onError ?? throwError);
+
+ /// Parses a package configuration file.
+ ///
+ /// The [configuration] must be a JSON object
+ /// containing a valid package configuration.
+ ///
+ /// The [baseUri] is used as the base for resolving relative
+ /// URI references in the configuration file. If the configuration
+ /// has been read from a file, the [baseUri] can be the URI of that
+ /// file, or of the directory it occurs in.
+ ///
+ /// If [onError] is provided, errors found during parsing or building
+ /// the configuration are reported by calling [onError] instead of
+ /// throwing, and parser makes a *best effort* attempt to continue
+ /// despite the error. The input must still be valid JSON.
+ /// The result may be [PackageConfig.empty] if there is no way to
+ /// extract useful information from the bytes.
+ static PackageConfig parseString(String configuration, Uri baseUri,
+ {void Function(Object error)? onError}) =>
+ parsePackageConfigString(configuration, baseUri, onError ?? throwError);
+
+ /// Parses the JSON data of a package configuration file.
+ ///
+ /// The [jsonData] must be a JSON-like Dart data structure,
+ /// like the one provided by parsing JSON text using `dart:convert`,
+ /// containing a valid package configuration.
+ ///
+ /// The [baseUri] is used as the base for resolving relative
+ /// URI references in the configuration file. If the configuration
+ /// has been read from a file, the [baseUri] can be the URI of that
+ /// file, or of the directory it occurs in.
+ ///
+ /// If [onError] is provided, errors found during parsing or building
+ /// the configuration are reported by calling [onError] instead of
+ /// throwing, and parser makes a *best effort* attempt to continue
+ /// despite the error. The input must still be valid JSON.
+ /// The result may be [PackageConfig.empty] if there is no way to
+ /// extract useful information from the bytes.
+ static PackageConfig parseJson(Object? jsonData, Uri baseUri,
+ {void Function(Object error)? onError}) =>
+ parsePackageConfigJson(jsonData, baseUri, onError ?? throwError);
+
+ /// Writes a configuration file for this configuration on [output].
+ ///
+ /// If [baseUri] is provided, URI references in the generated file
+ /// will be made relative to [baseUri] where possible.
+ static void writeBytes(PackageConfig configuration, Sink<Uint8List> output,
+ [Uri? baseUri]) {
+ writePackageConfigJsonUtf8(configuration, baseUri, output);
+ }
+
+ /// Writes a configuration JSON text for this configuration on [output].
+ ///
+ /// If [baseUri] is provided, URI references in the generated file
+ /// will be made relative to [baseUri] where possible.
+ static void writeString(PackageConfig configuration, StringSink output,
+ [Uri? baseUri]) {
+ writePackageConfigJsonString(configuration, baseUri, output);
+ }
+
+ /// Converts a configuration to a JSON-like data structure.
+ ///
+ /// If [baseUri] is provided, URI references in the generated data
+ /// will be made relative to [baseUri] where possible.
+ static Map<String, Object?> toJson(PackageConfig configuration,
+ [Uri? baseUri]) =>
+ packageConfigToJson(configuration, baseUri);
+
+ /// The configuration version number.
+ ///
+ /// Currently this is 1 or 2, where
+ /// * Version one is the `.packages` file format and
+ /// * Version two is the first `package_config.json` format.
+ ///
+ /// Instances of this class supports both, and the version
+ /// is only useful for detecting which kind of file the configuration
+ /// was read from.
+ int get version;
+
+ /// All the available packages of this configuration.
+ ///
+ /// No two of these packages have the same name,
+ /// and no two [Package.root] directories overlap.
+ Iterable<Package> get packages;
+
+ /// Look up a package by name.
+ ///
+ /// Returns the [Package] from [packages] with [packageName] as
+ /// [Package.name]. Returns `null` if the package is not available in the
+ /// current configuration.
+ Package? operator [](String packageName);
+
+ /// Provides the associated package for a specific [file] (or directory).
+ ///
+ /// Returns a [Package] which contains the [file]'s path, if any.
+ /// That is, the [Package.root] directory is a parent directory
+ /// of the [file]'s location.
+ ///
+ /// Returns `null` if the file does not belong to any package.
+ Package? packageOf(Uri file);
+
+ /// Resolves a `package:` URI to a non-package URI
+ ///
+ /// The [packageUri] must be a valid package URI. That means:
+ /// * A URI with `package` as scheme,
+ /// * with no authority part (`package://...`),
+ /// * with a path starting with a valid package name followed by a slash, and
+ /// * with no query or fragment part.
+ ///
+ /// Throws an [ArgumentError] (which also implements [PackageConfigError])
+ /// if the package URI is not valid.
+ ///
+ /// Returns `null` if the package name of [packageUri] is not available
+ /// in this package configuration.
+ /// Returns the remaining path of the package URI resolved relative to the
+ /// [Package.packageUriRoot] of the corresponding package.
+ Uri? resolve(Uri packageUri);
+
+ /// The package URI which resolves to [nonPackageUri].
+ ///
+ /// The [nonPackageUri] must not have any query or fragment part,
+ /// and it must not have `package` as scheme.
+ /// Throws an [ArgumentError] (which also implements [PackageConfigError])
+ /// if the non-package URI is not valid.
+ ///
+ /// Returns a package URI which [resolve] will convert to [nonPackageUri],
+ /// if any such URI exists. Returns `null` if no such package URI exists.
+ Uri? toPackageUri(Uri nonPackageUri);
+
+ /// Extra data associated with the package configuration.
+ ///
+ /// The data may be in any format, depending on who introduced it.
+ /// The standard `package_config.json` file storage will only store
+ /// JSON-like list/map data structures.
+ Object? get extraData;
+}
+
+/// Configuration data for a single package.
+abstract class Package {
+ /// Creates a package with the provided properties.
+ ///
+ /// The [name] must be a valid package name.
+ /// The [root] must be an absolute directory URI, meaning an absolute URI
+ /// with no query or fragment path and a path starting and ending with `/`.
+ /// The [packageUriRoot], if provided, must be either an absolute
+ /// directory URI or a relative URI reference which is then resolved
+ /// relative to [root]. It must then also be a subdirectory of [root],
+ /// or the same directory, and must end with `/`.
+ /// If [languageVersion] is supplied, it must be a valid Dart language
+ /// version, which means two decimal integer literals separated by a `.`,
+ /// where the integer literals have no leading zeros unless they are
+ /// a single zero digit.
+ ///
+ /// The [relativeRoot] controls whether the [root] is written as
+ /// relative to the `package_config.json` file when the package
+ /// configuration is written to a file. It defaults to being relative.
+ ///
+ /// If [extraData] is supplied, it will be available as the
+ /// [Package.extraData] of the created package.
+ factory Package(String name, Uri root,
+ {Uri? packageUriRoot,
+ LanguageVersion? languageVersion,
+ Object? extraData,
+ bool relativeRoot = true}) =>
+ SimplePackage.validate(name, root, packageUriRoot, languageVersion,
+ extraData, relativeRoot, throwError)!;
+
+ /// The package-name of the package.
+ String get name;
+
+ /// The location of the root of the package.
+ ///
+ /// Is always an absolute URI with no query or fragment parts,
+ /// and with a path ending in `/`.
+ ///
+ /// All files in the [root] directory are considered
+ /// part of the package for purposes where that that matters.
+ Uri get root;
+
+ /// The root of the files available through `package:` URIs.
+ ///
+ /// A `package:` URI with [name] as the package name is
+ /// resolved relative to this location.
+ ///
+ /// Is always an absolute URI with no query or fragment part
+ /// with a path ending in `/`,
+ /// and with a location which is a subdirectory
+ /// of the [root], or the same as the [root].
+ Uri get packageUriRoot;
+
+ /// The default language version associated with this package.
+ ///
+ /// Each package may have a default language version associated,
+ /// which is the language version used to parse and compile
+ /// Dart files in the package.
+ /// A package version is defined by two non-negative numbers,
+ /// the *major* and *minor* version numbers.
+ ///
+ /// A package may have no language version associated with it
+ /// in the package configuration, in which case tools should
+ /// use a default behavior for the package.
+ LanguageVersion? get languageVersion;
+
+ /// Extra data associated with the specific package.
+ ///
+ /// The data may be in any format, depending on who introduced it.
+ /// The standard `package_config.json` file storage will only store
+ /// JSON-like list/map data structures.
+ Object? get extraData;
+
+ /// Whether the [root] URI should be written as relative.
+ ///
+ /// When the configuration is written to a `package_config.json`
+ /// file, the [root] URI can be either relative to the file
+ /// location or absolute, controller by this value.
+ bool get relativeRoot;
+}
+
+/// A language version.
+///
+/// A language version is represented by two non-negative integers,
+/// the [major] and [minor] version numbers.
+///
+/// If errors during parsing are handled using an `onError` handler,
+/// then an *invalid* language version may be represented by an
+/// [InvalidLanguageVersion] object.
+abstract class LanguageVersion implements Comparable<LanguageVersion> {
+ /// The maximal value allowed by [major] and [minor] values;
+ static const int maxValue = 0x7FFFFFFF;
+ factory LanguageVersion(int major, int minor) {
+ RangeError.checkValueInInterval(major, 0, maxValue, 'major');
+ RangeError.checkValueInInterval(minor, 0, maxValue, 'major');
+ return SimpleLanguageVersion(major, minor, null);
+ }
+
+ /// Parses a language version string.
+ ///
+ /// A valid language version string has the form
+ ///
+ /// > *decimalNumber* `.` *decimalNumber*
+ ///
+ /// where a *decimalNumber* is a non-empty sequence of decimal digits
+ /// with no unnecessary leading zeros (the decimal number only starts
+ /// with a zero digit if that digit is the entire number).
+ /// No spaces are allowed in the string.
+ ///
+ /// If the [source] is valid then it is parsed into a valid
+ /// [LanguageVersion] object.
+ /// If not, then the [onError] is called with a [FormatException].
+ /// If [onError] is not supplied, it defaults to throwing the exception.
+ /// If the call does not throw, then an [InvalidLanguageVersion] is returned
+ /// containing the original [source].
+ static LanguageVersion parse(String source,
+ {void Function(Object error)? onError}) =>
+ parseLanguageVersion(source, onError ?? throwError);
+
+ /// The major language version.
+ ///
+ /// A non-negative integer less than 2<sup>31</sup>.
+ ///
+ /// The value is negative for objects representing *invalid* language
+ /// versions ([InvalidLanguageVersion]).
+ int get major;
+
+ /// The minor language version.
+ ///
+ /// A non-negative integer less than 2<sup>31</sup>.
+ ///
+ /// The value is negative for objects representing *invalid* language
+ /// versions ([InvalidLanguageVersion]).
+ int get minor;
+
+ /// Compares language versions.
+ ///
+ /// Two language versions are considered equal if they have the
+ /// same major and minor version numbers.
+ ///
+ /// A language version is greater then another if the former's major version
+ /// is greater than the latter's major version, or if they have
+ /// the same major version and the former's minor version is greater than
+ /// the latter's.
+ @override
+ int compareTo(LanguageVersion other);
+
+ /// Valid language versions with the same [major] and [minor] values are
+ /// equal.
+ ///
+ /// Invalid language versions ([InvalidLanguageVersion]) are not equal to
+ /// any other object.
+ @override
+ bool operator ==(Object other);
+
+ @override
+ int get hashCode;
+
+ /// A string representation of the language version.
+ ///
+ /// A valid language version is represented as
+ /// `"${version.major}.${version.minor}"`.
+ @override
+ String toString();
+}
+
+/// An *invalid* language version.
+///
+/// Stored in a [Package] when the original language version string
+/// was invalid and a `onError` handler was passed to the parser
+/// which did not throw on an error.
+abstract class InvalidLanguageVersion implements LanguageVersion {
+ /// The value -1 for an invalid language version.
+ @override
+ int get major;
+
+ /// The value -1 for an invalid language version.
+ @override
+ int get minor;
+
+ /// An invalid language version is only equal to itself.
+ @override
+ bool operator ==(Object other);
+
+ @override
+ int get hashCode;
+
+ /// The original invalid version string.
+ @override
+ String toString();
+}
diff --git a/pkgs/package_config/lib/src/package_config_impl.dart b/pkgs/package_config/lib/src/package_config_impl.dart
new file mode 100644
index 0000000..865e99a
--- /dev/null
+++ b/pkgs/package_config/lib/src/package_config_impl.dart
@@ -0,0 +1,568 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'errors.dart';
+import 'package_config.dart';
+import 'util.dart';
+
+export 'package_config.dart';
+
+const bool _disallowPackagesInsidePackageUriRoot = false;
+
+// Implementations of the main data types exposed by the API of this package.
+
+class SimplePackageConfig implements PackageConfig {
+ @override
+ final int version;
+ final Map<String, Package> _packages;
+ final PackageTree _packageTree;
+ @override
+ final Object? extraData;
+
+ factory SimplePackageConfig(int version, Iterable<Package> packages,
+ [Object? extraData, void Function(Object error)? onError]) {
+ onError ??= throwError;
+ var validVersion = _validateVersion(version, onError);
+ var sortedPackages = [...packages]..sort(_compareRoot);
+ var packageTree = _validatePackages(packages, sortedPackages, onError);
+ return SimplePackageConfig._(validVersion, packageTree,
+ {for (var p in packageTree.allPackages) p.name: p}, extraData);
+ }
+
+ SimplePackageConfig._(
+ this.version, this._packageTree, this._packages, this.extraData);
+
+ /// Creates empty configuration.
+ ///
+ /// The empty configuration can be used in cases where no configuration is
+ /// found, but code expects a non-null configuration.
+ ///
+ /// The version number is [PackageConfig.maxVersion] to avoid
+ /// minimum-version filters discarding the configuration.
+ const SimplePackageConfig.empty()
+ : version = PackageConfig.maxVersion,
+ _packageTree = const EmptyPackageTree(),
+ _packages = const <String, Package>{},
+ extraData = null;
+
+ static int _validateVersion(
+ int version, void Function(Object error) onError) {
+ if (version < 0 || version > PackageConfig.maxVersion) {
+ onError(PackageConfigArgumentError(version, 'version',
+ 'Must be in the range 1 to ${PackageConfig.maxVersion}'));
+ return 2; // The minimal version supporting a SimplePackageConfig.
+ }
+ return version;
+ }
+
+ static PackageTree _validatePackages(Iterable<Package> originalPackages,
+ List<Package> packages, void Function(Object error) onError) {
+ var packageNames = <String>{};
+ var tree = TriePackageTree();
+ for (var originalPackage in packages) {
+ SimplePackage? newPackage;
+ if (originalPackage is! SimplePackage) {
+ // SimplePackage validates these properties.
+ newPackage = SimplePackage.validate(
+ originalPackage.name,
+ originalPackage.root,
+ originalPackage.packageUriRoot,
+ originalPackage.languageVersion,
+ originalPackage.extraData,
+ originalPackage.relativeRoot, (error) {
+ if (error is PackageConfigArgumentError) {
+ onError(PackageConfigArgumentError(packages, 'packages',
+ 'Package ${newPackage!.name}: ${error.message}'));
+ } else {
+ onError(error);
+ }
+ });
+ if (newPackage == null) continue;
+ } else {
+ newPackage = originalPackage;
+ }
+ var name = newPackage.name;
+ if (packageNames.contains(name)) {
+ onError(PackageConfigArgumentError(
+ name, 'packages', "Duplicate package name '$name'"));
+ continue;
+ }
+ packageNames.add(name);
+ tree.add(newPackage, (error) {
+ if (error is ConflictException) {
+ // There is a conflict with an existing package.
+ var existingPackage = error.existingPackage;
+ switch (error.conflictType) {
+ case ConflictType.sameRoots:
+ onError(PackageConfigArgumentError(
+ originalPackages,
+ 'packages',
+ 'Packages ${newPackage!.name} and ${existingPackage.name} '
+ 'have the same root directory: ${newPackage.root}.\n'));
+ break;
+ case ConflictType.interleaving:
+ // The new package is inside the package URI root of the existing
+ // package.
+ onError(PackageConfigArgumentError(
+ originalPackages,
+ 'packages',
+ 'Package ${newPackage!.name} is inside the root of '
+ 'package ${existingPackage.name}, and the package root '
+ 'of ${existingPackage.name} is inside the root of '
+ '${newPackage.name}.\n'
+ '${existingPackage.name} package root: '
+ '${existingPackage.packageUriRoot}\n'
+ '${newPackage.name} root: ${newPackage.root}\n'));
+ break;
+ case ConflictType.insidePackageRoot:
+ onError(PackageConfigArgumentError(
+ originalPackages,
+ 'packages',
+ 'Package ${newPackage!.name} is inside the package root of '
+ 'package ${existingPackage.name}.\n'
+ '${existingPackage.name} package root: '
+ '${existingPackage.packageUriRoot}\n'
+ '${newPackage.name} root: ${newPackage.root}\n'));
+ break;
+ }
+ } else {
+ // Any other error.
+ onError(error);
+ }
+ });
+ }
+ return tree;
+ }
+
+ @override
+ Iterable<Package> get packages => _packages.values;
+
+ @override
+ Package? operator [](String packageName) => _packages[packageName];
+
+ @override
+ Package? packageOf(Uri file) => _packageTree.packageOf(file);
+
+ @override
+ Uri? resolve(Uri packageUri) {
+ var packageName = checkValidPackageUri(packageUri, 'packageUri');
+ return _packages[packageName]?.packageUriRoot.resolveUri(
+ Uri(path: packageUri.path.substring(packageName.length + 1)));
+ }
+
+ @override
+ Uri? toPackageUri(Uri nonPackageUri) {
+ if (nonPackageUri.isScheme('package')) {
+ throw PackageConfigArgumentError(
+ nonPackageUri, 'nonPackageUri', 'Must not be a package URI');
+ }
+ if (nonPackageUri.hasQuery || nonPackageUri.hasFragment) {
+ throw PackageConfigArgumentError(nonPackageUri, 'nonPackageUri',
+ 'Must not have query or fragment part');
+ }
+ // Find package that file belongs to.
+ var package = _packageTree.packageOf(nonPackageUri);
+ if (package == null) return null;
+ // Check if it is inside the package URI root.
+ var path = nonPackageUri.toString();
+ var root = package.packageUriRoot.toString();
+ if (_beginsWith(package.root.toString().length, root, path)) {
+ var rest = path.substring(root.length);
+ return Uri(scheme: 'package', path: '${package.name}/$rest');
+ }
+ return null;
+ }
+}
+
+/// Configuration data for a single package.
+class SimplePackage implements Package {
+ @override
+ final String name;
+ @override
+ final Uri root;
+ @override
+ final Uri packageUriRoot;
+ @override
+ final LanguageVersion? languageVersion;
+ @override
+ final Object? extraData;
+ @override
+ final bool relativeRoot;
+
+ SimplePackage._(this.name, this.root, this.packageUriRoot,
+ this.languageVersion, this.extraData, this.relativeRoot);
+
+ /// Creates a [SimplePackage] with the provided content.
+ ///
+ /// The provided arguments must be valid.
+ ///
+ /// If the arguments are invalid then the error is reported by
+ /// calling [onError], then the erroneous entry is ignored.
+ ///
+ /// If [onError] is provided, the user is expected to be able to handle
+ /// errors themselves. An invalid [languageVersion] string
+ /// will be replaced with the string `"invalid"`. This allows
+ /// users to detect the difference between an absent version and
+ /// an invalid one.
+ ///
+ /// Returns `null` if the input is invalid and an approximately valid package
+ /// cannot be salvaged from the input.
+ static SimplePackage? validate(
+ String name,
+ Uri root,
+ Uri? packageUriRoot,
+ LanguageVersion? languageVersion,
+ Object? extraData,
+ bool relativeRoot,
+ void Function(Object error) onError) {
+ var fatalError = false;
+ var invalidIndex = checkPackageName(name);
+ if (invalidIndex >= 0) {
+ onError(PackageConfigFormatException(
+ 'Not a valid package name', name, invalidIndex));
+ fatalError = true;
+ }
+ if (root.isScheme('package')) {
+ onError(PackageConfigArgumentError(
+ '$root', 'root', 'Must not be a package URI'));
+ fatalError = true;
+ } else if (!isAbsoluteDirectoryUri(root)) {
+ onError(PackageConfigArgumentError(
+ '$root',
+ 'root',
+ 'In package $name: Not an absolute URI with no query or fragment '
+ 'with a path ending in /'));
+ // Try to recover. If the URI has a scheme,
+ // then ensure that the path ends with `/`.
+ if (!root.hasScheme) {
+ fatalError = true;
+ } else if (!root.path.endsWith('/')) {
+ root = root.replace(path: '${root.path}/');
+ }
+ }
+ if (packageUriRoot == null) {
+ packageUriRoot = root;
+ } else if (!fatalError) {
+ packageUriRoot = root.resolveUri(packageUriRoot);
+ if (!isAbsoluteDirectoryUri(packageUriRoot)) {
+ onError(PackageConfigArgumentError(
+ packageUriRoot,
+ 'packageUriRoot',
+ 'In package $name: Not an absolute URI with no query or fragment '
+ 'with a path ending in /'));
+ packageUriRoot = root;
+ } else if (!isUriPrefix(root, packageUriRoot)) {
+ onError(PackageConfigArgumentError(packageUriRoot, 'packageUriRoot',
+ 'The package URI root is not below the package root'));
+ packageUriRoot = root;
+ }
+ }
+ if (fatalError) return null;
+ return SimplePackage._(
+ name, root, packageUriRoot, languageVersion, extraData, relativeRoot);
+ }
+}
+
+/// Checks whether [source] is a valid Dart language version string.
+///
+/// The format is (as RegExp) `^(0|[1-9]\d+)\.(0|[1-9]\d+)$`.
+///
+/// Reports a format exception on [onError] if not, or if the numbers
+/// are too large (at most 32-bit signed integers).
+LanguageVersion parseLanguageVersion(
+ String? source, void Function(Object error) onError) {
+ var index = 0;
+ // Reads a positive decimal numeral. Returns the value of the numeral,
+ // or a negative number in case of an error.
+ // Starts at [index] and increments the index to the position after
+ // the numeral.
+ // It is an error if the numeral value is greater than 0x7FFFFFFFF.
+ // It is a recoverable error if the numeral starts with leading zeros.
+ int readNumeral() {
+ const maxValue = 0x7FFFFFFF;
+ if (index == source!.length) {
+ onError(PackageConfigFormatException('Missing number', source, index));
+ return -1;
+ }
+ var start = index;
+
+ var char = source.codeUnitAt(index);
+ var digit = char ^ 0x30;
+ if (digit > 9) {
+ onError(PackageConfigFormatException('Missing number', source, index));
+ return -1;
+ }
+ var firstDigit = digit;
+ var value = 0;
+ do {
+ value = value * 10 + digit;
+ if (value > maxValue) {
+ onError(
+ PackageConfigFormatException('Number too large', source, start));
+ return -1;
+ }
+ index++;
+ if (index == source.length) break;
+ char = source.codeUnitAt(index);
+ digit = char ^ 0x30;
+ } while (digit <= 9);
+ if (firstDigit == 0 && index > start + 1) {
+ onError(PackageConfigFormatException(
+ 'Leading zero not allowed', source, start));
+ }
+ return value;
+ }
+
+ var major = readNumeral();
+ if (major < 0) {
+ return SimpleInvalidLanguageVersion(source);
+ }
+ if (index == source!.length || source.codeUnitAt(index) != $dot) {
+ onError(PackageConfigFormatException("Missing '.'", source, index));
+ return SimpleInvalidLanguageVersion(source);
+ }
+ index++;
+ var minor = readNumeral();
+ if (minor < 0) {
+ return SimpleInvalidLanguageVersion(source);
+ }
+ if (index != source.length) {
+ onError(PackageConfigFormatException(
+ 'Unexpected trailing character', source, index));
+ return SimpleInvalidLanguageVersion(source);
+ }
+ return SimpleLanguageVersion(major, minor, source);
+}
+
+abstract class _SimpleLanguageVersionBase implements LanguageVersion {
+ @override
+ int compareTo(LanguageVersion other) {
+ var result = major.compareTo(other.major);
+ if (result != 0) return result;
+ return minor.compareTo(other.minor);
+ }
+}
+
+class SimpleLanguageVersion extends _SimpleLanguageVersionBase {
+ @override
+ final int major;
+ @override
+ final int minor;
+ String? _source;
+ SimpleLanguageVersion(this.major, this.minor, this._source);
+
+ @override
+ bool operator ==(Object other) =>
+ other is LanguageVersion && major == other.major && minor == other.minor;
+
+ @override
+ int get hashCode => (major * 17 ^ minor * 37) & 0x3FFFFFFF;
+
+ @override
+ String toString() => _source ??= '$major.$minor';
+}
+
+class SimpleInvalidLanguageVersion extends _SimpleLanguageVersionBase
+ implements InvalidLanguageVersion {
+ final String? _source;
+ SimpleInvalidLanguageVersion(this._source);
+ @override
+ int get major => -1;
+ @override
+ int get minor => -1;
+
+ @override
+ String toString() => _source!;
+}
+
+abstract class PackageTree {
+ Iterable<Package> get allPackages;
+ SimplePackage? packageOf(Uri file);
+}
+
+class _PackageTrieNode {
+ SimplePackage? package;
+
+ /// Indexed by path segment.
+ Map<String, _PackageTrieNode> map = {};
+}
+
+/// Packages of a package configuration ordered by root path.
+///
+/// A package has a root path and a package root path, where the latter
+/// contains the files exposed by `package:` URIs.
+///
+/// A package is said to be inside another package if the root path URI of
+/// the latter is a prefix of the root path URI of the former.
+///
+/// No two packages of a package may have the same root path.
+/// The package root path of a package must not be inside another package's
+/// root path.
+/// Entire other packages are allowed inside a package's root.
+class TriePackageTree implements PackageTree {
+ /// Indexed by URI scheme.
+ final Map<String, _PackageTrieNode> _map = {};
+
+ /// A list of all packages.
+ final List<SimplePackage> _packages = [];
+
+ @override
+ Iterable<Package> get allPackages sync* {
+ for (var package in _packages) {
+ yield package;
+ }
+ }
+
+ bool _checkConflict(_PackageTrieNode node, SimplePackage newPackage,
+ void Function(Object error) onError) {
+ var existingPackage = node.package;
+ if (existingPackage != null) {
+ // Trying to add package that is inside the existing package.
+ // 1) If it's an exact match it's not allowed (i.e. the roots can't be
+ // the same).
+ if (newPackage.root.path.length == existingPackage.root.path.length) {
+ onError(ConflictException(
+ newPackage, existingPackage, ConflictType.sameRoots));
+ return true;
+ }
+ // 2) The existing package has a packageUriRoot thats inside the
+ // root of the new package.
+ if (_beginsWith(0, newPackage.root.toString(),
+ existingPackage.packageUriRoot.toString())) {
+ onError(ConflictException(
+ newPackage, existingPackage, ConflictType.interleaving));
+ return true;
+ }
+
+ // For internal reasons we allow this (for now). One should still never do
+ // it though.
+ // 3) The new package is inside the packageUriRoot of existing package.
+ if (_disallowPackagesInsidePackageUriRoot) {
+ if (_beginsWith(0, existingPackage.packageUriRoot.toString(),
+ newPackage.root.toString())) {
+ onError(ConflictException(
+ newPackage, existingPackage, ConflictType.insidePackageRoot));
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /// Tries to add `newPackage` to the tree.
+ ///
+ /// Reports a [ConflictException] if the added package conflicts with an
+ /// existing package.
+ /// It conflicts if its root or package root is the same as an existing
+ /// package's root or package root, is between the two, or if it's inside the
+ /// package root of an existing package.
+ ///
+ /// If a conflict is detected between [newPackage] and a previous package,
+ /// then [onError] is called with a [ConflictException] object
+ /// and the [newPackage] is not added to the tree.
+ ///
+ /// The packages are added in order of their root path.
+ void add(SimplePackage newPackage, void Function(Object error) onError) {
+ var root = newPackage.root;
+ var node = _map[root.scheme] ??= _PackageTrieNode();
+ if (_checkConflict(node, newPackage, onError)) return;
+ var segments = root.pathSegments;
+ // Notice that we're skipping the last segment as it's always the empty
+ // string because roots are directories.
+ for (var i = 0; i < segments.length - 1; i++) {
+ var path = segments[i];
+ node = node.map[path] ??= _PackageTrieNode();
+ if (_checkConflict(node, newPackage, onError)) return;
+ }
+ node.package = newPackage;
+ _packages.add(newPackage);
+ }
+
+ bool _isMatch(
+ String path, _PackageTrieNode node, List<SimplePackage> potential) {
+ var currentPackage = node.package;
+ if (currentPackage != null) {
+ var currentPackageRootLength = currentPackage.root.toString().length;
+ if (path.length == currentPackageRootLength) return true;
+ var currentPackageUriRoot = currentPackage.packageUriRoot.toString();
+ // Is [file] inside the package root of [currentPackage]?
+ if (currentPackageUriRoot.length == currentPackageRootLength ||
+ _beginsWith(currentPackageRootLength, currentPackageUriRoot, path)) {
+ return true;
+ }
+ potential.add(currentPackage);
+ }
+ return false;
+ }
+
+ @override
+ SimplePackage? packageOf(Uri file) {
+ var currentTrieNode = _map[file.scheme];
+ if (currentTrieNode == null) return null;
+ var path = file.toString();
+ var potential = <SimplePackage>[];
+ if (_isMatch(path, currentTrieNode, potential)) {
+ return currentTrieNode.package;
+ }
+ var segments = file.pathSegments;
+
+ for (var i = 0; i < segments.length - 1; i++) {
+ var segment = segments[i];
+ currentTrieNode = currentTrieNode!.map[segment];
+ if (currentTrieNode == null) break;
+ if (_isMatch(path, currentTrieNode, potential)) {
+ return currentTrieNode.package;
+ }
+ }
+ if (potential.isEmpty) return null;
+ return potential.last;
+ }
+}
+
+class EmptyPackageTree implements PackageTree {
+ const EmptyPackageTree();
+
+ @override
+ Iterable<Package> get allPackages => const Iterable<Package>.empty();
+
+ @override
+ SimplePackage? packageOf(Uri file) => null;
+}
+
+/// Checks whether [longerPath] begins with [parentPath].
+///
+/// Skips checking the [start] first characters which are assumed to
+/// already have been matched.
+bool _beginsWith(int start, String parentPath, String longerPath) {
+ if (longerPath.length < parentPath.length) return false;
+ for (var i = start; i < parentPath.length; i++) {
+ if (longerPath.codeUnitAt(i) != parentPath.codeUnitAt(i)) return false;
+ }
+ return true;
+}
+
+enum ConflictType { sameRoots, interleaving, insidePackageRoot }
+
+/// Conflict between packages added to the same configuration.
+///
+/// The [package] conflicts with [existingPackage] if it has
+/// the same root path or the package URI root path
+/// of [existingPackage] is inside the root path of [package].
+class ConflictException {
+ /// The existing package that [package] conflicts with.
+ final SimplePackage existingPackage;
+
+ /// The package that could not be added without a conflict.
+ final SimplePackage package;
+
+ /// Whether the conflict is with the package URI root of [existingPackage].
+ final ConflictType conflictType;
+
+ /// Creates a root conflict between [package] and [existingPackage].
+ ConflictException(this.package, this.existingPackage, this.conflictType);
+}
+
+/// Used for sorting packages by root path.
+int _compareRoot(Package p1, Package p2) =>
+ p1.root.toString().compareTo(p2.root.toString());
diff --git a/pkgs/package_config/lib/src/package_config_io.dart b/pkgs/package_config/lib/src/package_config_io.dart
new file mode 100644
index 0000000..8c5773b
--- /dev/null
+++ b/pkgs/package_config/lib/src/package_config_io.dart
@@ -0,0 +1,166 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// dart:io dependent functionality for reading and writing configuration files.
+
+import 'dart:convert';
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'errors.dart';
+import 'package_config_impl.dart';
+import 'package_config_json.dart';
+import 'packages_file.dart' as packages_file;
+import 'util.dart';
+import 'util_io.dart';
+
+/// Name of directory where Dart tools store their configuration.
+///
+/// Directory is created in the package root directory.
+const dartToolDirName = '.dart_tool';
+
+/// Name of file containing new package configuration data.
+///
+/// File is stored in the dart tool directory.
+const packageConfigFileName = 'package_config.json';
+
+/// Name of file containing legacy package configuration data.
+///
+/// File is stored in the package root directory.
+const packagesFileName = '.packages';
+
+/// Reads a package configuration file.
+///
+/// Detects whether the [file] is a version one `.packages` file or
+/// a version two `package_config.json` file.
+///
+/// If the [file] is a `.packages` file and [preferNewest] is true,
+/// first checks whether there is an adjacent `.dart_tool/package_config.json`
+/// file, and if so, reads that instead.
+/// If [preferNewest] is false, the specified file is loaded even if it is
+/// a `.packages` file and there is an available `package_config.json` file.
+///
+/// The file must exist and be a normal file.
+Future<PackageConfig> readAnyConfigFile(
+ File file, bool preferNewest, void Function(Object error) onError) async {
+ if (preferNewest && fileName(file.path) == packagesFileName) {
+ var alternateFile = File(
+ pathJoin(dirName(file.path), dartToolDirName, packageConfigFileName));
+ if (alternateFile.existsSync()) {
+ return await readPackageConfigJsonFile(alternateFile, onError);
+ }
+ }
+ Uint8List bytes;
+ try {
+ bytes = await file.readAsBytes();
+ } catch (e) {
+ onError(e);
+ return const SimplePackageConfig.empty();
+ }
+ return parseAnyConfigFile(bytes, file.uri, onError);
+}
+
+/// Like [readAnyConfigFile] but uses a URI and an optional loader.
+Future<PackageConfig> readAnyConfigFileUri(
+ Uri file,
+ Future<Uint8List?> Function(Uri uri)? loader,
+ void Function(Object error) onError,
+ bool preferNewest) async {
+ if (file.isScheme('package')) {
+ throw PackageConfigArgumentError(
+ file, 'file', 'Must not be a package: URI');
+ }
+ if (loader == null) {
+ if (file.isScheme('file')) {
+ return await readAnyConfigFile(File.fromUri(file), preferNewest, onError);
+ }
+ loader = defaultLoader;
+ }
+ if (preferNewest && file.pathSegments.last == packagesFileName) {
+ var alternateFile = file.resolve('$dartToolDirName/$packageConfigFileName');
+ Uint8List? bytes;
+ try {
+ bytes = await loader(alternateFile);
+ } catch (e) {
+ onError(e);
+ return const SimplePackageConfig.empty();
+ }
+ if (bytes != null) {
+ return parsePackageConfigBytes(bytes, alternateFile, onError);
+ }
+ }
+ Uint8List? bytes;
+ try {
+ bytes = await loader(file);
+ } catch (e) {
+ onError(e);
+ return const SimplePackageConfig.empty();
+ }
+ if (bytes == null) {
+ onError(PackageConfigArgumentError(
+ file.toString(), 'file', 'File cannot be read'));
+ return const SimplePackageConfig.empty();
+ }
+ return parseAnyConfigFile(bytes, file, onError);
+}
+
+/// Parses a `.packages` or `package_config.json` file's contents.
+///
+/// Assumes it's a JSON file if the first non-whitespace character
+/// is `{`, otherwise assumes it's a `.packages` file.
+PackageConfig parseAnyConfigFile(
+ Uint8List bytes, Uri file, void Function(Object error) onError) {
+ var firstChar = firstNonWhitespaceChar(bytes);
+ if (firstChar != $lbrace) {
+ // Definitely not a JSON object, probably a .packages.
+ return packages_file.parse(bytes, file, onError);
+ }
+ return parsePackageConfigBytes(bytes, file, onError);
+}
+
+Future<PackageConfig> readPackageConfigJsonFile(
+ File file, void Function(Object error) onError) async {
+ Uint8List bytes;
+ try {
+ bytes = await file.readAsBytes();
+ } catch (error) {
+ onError(error);
+ return const SimplePackageConfig.empty();
+ }
+ return parsePackageConfigBytes(bytes, file.uri, onError);
+}
+
+Future<PackageConfig> readDotPackagesFile(
+ File file, void Function(Object error) onError) async {
+ Uint8List bytes;
+ try {
+ bytes = await file.readAsBytes();
+ } catch (error) {
+ onError(error);
+ return const SimplePackageConfig.empty();
+ }
+ return packages_file.parse(bytes, file.uri, onError);
+}
+
+Future<void> writePackageConfigJsonFile(
+ PackageConfig config, Directory targetDirectory) async {
+ // Write .dart_tool/package_config.json first.
+ var dartToolDir = Directory(pathJoin(targetDirectory.path, dartToolDirName));
+ await dartToolDir.create(recursive: true);
+ var file = File(pathJoin(dartToolDir.path, packageConfigFileName));
+ var baseUri = file.uri;
+
+ var sink = file.openWrite(encoding: utf8);
+ writePackageConfigJsonUtf8(config, baseUri, sink);
+ var doneJson = sink.close();
+
+ // Write .packages too.
+ file = File(pathJoin(targetDirectory.path, packagesFileName));
+ baseUri = file.uri;
+ sink = file.openWrite(encoding: utf8);
+ writeDotPackages(config, baseUri, sink);
+ var donePackages = sink.close();
+
+ await Future.wait([doneJson, donePackages]);
+}
diff --git a/pkgs/package_config/lib/src/package_config_json.dart b/pkgs/package_config/lib/src/package_config_json.dart
new file mode 100644
index 0000000..65560a0
--- /dev/null
+++ b/pkgs/package_config/lib/src/package_config_json.dart
@@ -0,0 +1,321 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Parsing and serialization of package configurations.
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'errors.dart';
+import 'package_config_impl.dart';
+import 'packages_file.dart' as packages_file;
+import 'util.dart';
+
+const String _configVersionKey = 'configVersion';
+const String _packagesKey = 'packages';
+const List<String> _topNames = [_configVersionKey, _packagesKey];
+const String _nameKey = 'name';
+const String _rootUriKey = 'rootUri';
+const String _packageUriKey = 'packageUri';
+const String _languageVersionKey = 'languageVersion';
+const List<String> _packageNames = [
+ _nameKey,
+ _rootUriKey,
+ _packageUriKey,
+ _languageVersionKey
+];
+
+const String _generatedKey = 'generated';
+const String _generatorKey = 'generator';
+const String _generatorVersionKey = 'generatorVersion';
+
+final _jsonUtf8Decoder = json.fuse(utf8).decoder;
+
+PackageConfig parsePackageConfigBytes(
+ Uint8List bytes, Uri file, void Function(Object error) onError) {
+ // TODO(lrn): Make this simpler. Maybe parse directly from bytes.
+ Object? jsonObject;
+ try {
+ jsonObject = _jsonUtf8Decoder.convert(bytes);
+ } on FormatException catch (e) {
+ onError(PackageConfigFormatException.from(e));
+ return const SimplePackageConfig.empty();
+ }
+ return parsePackageConfigJson(jsonObject, file, onError);
+}
+
+PackageConfig parsePackageConfigString(
+ String source, Uri file, void Function(Object error) onError) {
+ Object? jsonObject;
+ try {
+ jsonObject = jsonDecode(source);
+ } on FormatException catch (e) {
+ onError(PackageConfigFormatException.from(e));
+ return const SimplePackageConfig.empty();
+ }
+ return parsePackageConfigJson(jsonObject, file, onError);
+}
+
+/// Creates a [PackageConfig] from a parsed JSON-like object structure.
+///
+/// The [json] argument must be a JSON object (`Map<String, Object?>`)
+/// containing a `"configVersion"` entry with an integer value in the range
+/// 1 to [PackageConfig.maxVersion],
+/// and with a `"packages"` entry which is a JSON array (`List<Object?>`)
+/// containing JSON objects which each has the following properties:
+///
+/// * `"name"`: The package name as a string.
+/// * `"rootUri"`: The root of the package as a URI stored as a string.
+/// * `"packageUri"`: Optionally the root of for `package:` URI resolution
+/// for the package, as a relative URI below the root URI
+/// stored as a string.
+/// * `"languageVersion"`: Optionally a language version string which is a
+/// an integer numeral, a decimal point (`.`) and another integer numeral,
+/// where the integer numeral cannot have a sign, and can only have a
+/// leading zero if the entire numeral is a single zero.
+///
+/// The [baseLocation] is used as base URI to resolve the "rootUri"
+/// URI reference string.
+PackageConfig parsePackageConfigJson(
+ Object? json, Uri baseLocation, void Function(Object error) onError) {
+ if (!baseLocation.hasScheme || baseLocation.isScheme('package')) {
+ throw PackageConfigArgumentError(baseLocation.toString(), 'baseLocation',
+ 'Must be an absolute non-package: URI');
+ }
+
+ if (!baseLocation.path.endsWith('/')) {
+ baseLocation = baseLocation.resolveUri(Uri(path: '.'));
+ }
+
+ String typeName<T>() {
+ if (0 is T) return 'int';
+ if ('' is T) return 'string';
+ if (const <Object?>[] is T) return 'array';
+ return 'object';
+ }
+
+ T? checkType<T>(Object? value, String name, [String? packageName]) {
+ if (value is T) return value;
+ // The only types we are called with are [int], [String], [List<Object?>]
+ // and Map<String, Object?>. Recognize which to give a better error message.
+ var message =
+ "$name${packageName != null ? " of package $packageName" : ""}"
+ ' is not a JSON ${typeName<T>()}';
+ onError(PackageConfigFormatException(message, value));
+ return null;
+ }
+
+ Package? parsePackage(Map<String, Object?> entry) {
+ String? name;
+ String? rootUri;
+ String? packageUri;
+ String? languageVersion;
+ Map<String, Object?>? extraData;
+ var hasName = false;
+ var hasRoot = false;
+ var hasVersion = false;
+ entry.forEach((key, value) {
+ switch (key) {
+ case _nameKey:
+ hasName = true;
+ name = checkType<String>(value, _nameKey);
+ break;
+ case _rootUriKey:
+ hasRoot = true;
+ rootUri = checkType<String>(value, _rootUriKey, name);
+ break;
+ case _packageUriKey:
+ packageUri = checkType<String>(value, _packageUriKey, name);
+ break;
+ case _languageVersionKey:
+ hasVersion = true;
+ languageVersion = checkType<String>(value, _languageVersionKey, name);
+ break;
+ default:
+ (extraData ??= {})[key] = value;
+ break;
+ }
+ });
+ if (!hasName) {
+ onError(PackageConfigFormatException('Missing name entry', entry));
+ }
+ if (!hasRoot) {
+ onError(PackageConfigFormatException('Missing rootUri entry', entry));
+ }
+ if (name == null || rootUri == null) return null;
+ var parsedRootUri = Uri.parse(rootUri!);
+ var relativeRoot = !hasAbsolutePath(parsedRootUri);
+ var root = baseLocation.resolveUri(parsedRootUri);
+ if (!root.path.endsWith('/')) root = root.replace(path: '${root.path}/');
+ var packageRoot = root;
+ if (packageUri != null) packageRoot = root.resolve(packageUri!);
+ if (!packageRoot.path.endsWith('/')) {
+ packageRoot = packageRoot.replace(path: '${packageRoot.path}/');
+ }
+
+ LanguageVersion? version;
+ if (languageVersion != null) {
+ version = parseLanguageVersion(languageVersion, onError);
+ } else if (hasVersion) {
+ version = SimpleInvalidLanguageVersion('invalid');
+ }
+
+ return SimplePackage.validate(
+ name!, root, packageRoot, version, extraData, relativeRoot, (error) {
+ if (error is ArgumentError) {
+ onError(
+ PackageConfigFormatException(
+ error.message.toString(), error.invalidValue),
+ );
+ } else {
+ onError(error);
+ }
+ });
+ }
+
+ var map = checkType<Map<String, Object?>>(json, 'value');
+ if (map == null) return const SimplePackageConfig.empty();
+ Map<String, Object?>? extraData;
+ List<Package>? packageList;
+ int? configVersion;
+ map.forEach((key, value) {
+ switch (key) {
+ case _configVersionKey:
+ configVersion = checkType<int>(value, _configVersionKey) ?? 2;
+ break;
+ case _packagesKey:
+ var packageArray = checkType<List<Object?>>(value, _packagesKey) ?? [];
+ var packages = <Package>[];
+ for (var package in packageArray) {
+ var packageMap =
+ checkType<Map<String, Object?>>(package, 'package entry');
+ if (packageMap != null) {
+ var entry = parsePackage(packageMap);
+ if (entry != null) {
+ packages.add(entry);
+ }
+ }
+ }
+ packageList = packages;
+ break;
+ default:
+ (extraData ??= {})[key] = value;
+ break;
+ }
+ });
+ if (configVersion == null) {
+ onError(PackageConfigFormatException('Missing configVersion entry', json));
+ configVersion = 2;
+ }
+ if (packageList == null) {
+ onError(PackageConfigFormatException('Missing packages list', json));
+ packageList = [];
+ }
+ return SimplePackageConfig(configVersion!, packageList!, extraData, (error) {
+ if (error is ArgumentError) {
+ onError(
+ PackageConfigFormatException(
+ error.message.toString(), error.invalidValue),
+ );
+ } else {
+ onError(error);
+ }
+ });
+}
+
+final _jsonUtf8Encoder = JsonUtf8Encoder(' ');
+
+void writePackageConfigJsonUtf8(
+ PackageConfig config, Uri? baseUri, Sink<List<int>> output) {
+ // Can be optimized.
+ var data = packageConfigToJson(config, baseUri);
+ output.add(_jsonUtf8Encoder.convert(data) as Uint8List);
+}
+
+void writePackageConfigJsonString(
+ PackageConfig config, Uri? baseUri, StringSink output) {
+ // Can be optimized.
+ var data = packageConfigToJson(config, baseUri);
+ output.write(const JsonEncoder.withIndent(' ').convert(data));
+}
+
+Map<String, Object?> packageConfigToJson(PackageConfig config, Uri? baseUri) =>
+ <String, Object?>{
+ ...?_extractExtraData(config.extraData, _topNames),
+ _configVersionKey: PackageConfig.maxVersion,
+ _packagesKey: [
+ for (var package in config.packages)
+ <String, Object?>{
+ _nameKey: package.name,
+ _rootUriKey: trailingSlash((package.relativeRoot
+ ? relativizeUri(package.root, baseUri)
+ : package.root)
+ .toString()),
+ if (package.root != package.packageUriRoot)
+ _packageUriKey: trailingSlash(
+ relativizeUri(package.packageUriRoot, package.root)
+ .toString()),
+ if (package.languageVersion != null &&
+ package.languageVersion is! InvalidLanguageVersion)
+ _languageVersionKey: package.languageVersion.toString(),
+ ...?_extractExtraData(package.extraData, _packageNames),
+ }
+ ],
+ };
+
+void writeDotPackages(PackageConfig config, Uri baseUri, StringSink output) {
+ var extraData = config.extraData;
+ // Write .packages too.
+ String? comment;
+ if (extraData is Map<String, Object?>) {
+ var generator = extraData[_generatorKey];
+ if (generator is String) {
+ var generated = extraData[_generatedKey];
+ var generatorVersion = extraData[_generatorVersionKey];
+ comment = 'Generated by $generator'
+ "${generatorVersion is String ? " $generatorVersion" : ""}"
+ "${generated is String ? " on $generated" : ""}.";
+ }
+ }
+ packages_file.write(output, config, baseUri: baseUri, comment: comment);
+}
+
+/// If "extraData" is a JSON map, then return it, otherwise return null.
+///
+/// If the value contains any of the [reservedNames] for the current context,
+/// entries with that name in the extra data are dropped.
+Map<String, Object?>? _extractExtraData(
+ Object? data, Iterable<String> reservedNames) {
+ if (data is Map<String, Object?>) {
+ if (data.isEmpty) return null;
+ for (var name in reservedNames) {
+ if (data.containsKey(name)) {
+ var filteredData = {
+ for (var key in data.keys)
+ if (!reservedNames.contains(key)) key: data[key]
+ };
+ if (filteredData.isEmpty) return null;
+ for (var value in filteredData.values) {
+ if (!_validateJson(value)) return null;
+ }
+ return filteredData;
+ }
+ }
+ return data;
+ }
+ return null;
+}
+
+/// Checks that the object is a valid JSON-like data structure.
+bool _validateJson(Object? object) {
+ if (object == null || true == object || false == object) return true;
+ if (object is num || object is String) return true;
+ if (object is List<Object?>) {
+ return object.every(_validateJson);
+ }
+ if (object is Map<String, Object?>) {
+ return object.values.every(_validateJson);
+ }
+ return false;
+}
diff --git a/pkgs/package_config/lib/src/packages_file.dart b/pkgs/package_config/lib/src/packages_file.dart
new file mode 100644
index 0000000..bf68f2c
--- /dev/null
+++ b/pkgs/package_config/lib/src/packages_file.dart
@@ -0,0 +1,193 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'errors.dart';
+import 'package_config_impl.dart';
+import 'util.dart';
+
+/// The language version prior to the release of language versioning.
+///
+/// This is the default language version used by all packages from a
+/// `.packages` file.
+final LanguageVersion _languageVersion = LanguageVersion(2, 7);
+
+/// Parses a `.packages` file into a [PackageConfig].
+///
+/// The [source] is the byte content of a `.packages` file, assumed to be
+/// UTF-8 encoded. In practice, all significant parts of the file must be ASCII,
+/// so Latin-1 or Windows-1252 encoding will also work fine.
+///
+/// If the file content is available as a string, its [String.codeUnits] can
+/// be used as the `source` argument of this function.
+///
+/// The [baseLocation] is used as a base URI to resolve all relative
+/// URI references against.
+/// If the content was read from a file, `baseLocation` should be the
+/// location of that file.
+///
+/// Returns a simple package configuration where each package's
+/// [Package.packageUriRoot] is the same as its [Package.root]
+/// and it has no [Package.languageVersion].
+PackageConfig parse(
+ List<int> source, Uri baseLocation, void Function(Object error) onError) {
+ if (baseLocation.isScheme('package')) {
+ onError(PackageConfigArgumentError(
+ baseLocation, 'baseLocation', 'Must not be a package: URI'));
+ return PackageConfig.empty;
+ }
+ var index = 0;
+ var packages = <Package>[];
+ var packageNames = <String>{};
+ while (index < source.length) {
+ var ignoreLine = false;
+ var start = index;
+ var separatorIndex = -1;
+ var end = source.length;
+ var char = source[index++];
+ if (char == $cr || char == $lf) {
+ continue;
+ }
+ if (char == $colon) {
+ onError(PackageConfigFormatException(
+ 'Missing package name', source, index - 1));
+ ignoreLine = true; // Ignore if package name is invalid.
+ } else {
+ ignoreLine = char == $hash; // Ignore if comment.
+ }
+ var queryStart = -1;
+ var fragmentStart = -1;
+ while (index < source.length) {
+ char = source[index++];
+ if (char == $colon && separatorIndex < 0) {
+ separatorIndex = index - 1;
+ } else if (char == $cr || char == $lf) {
+ end = index - 1;
+ break;
+ } else if (char == $question && queryStart < 0 && fragmentStart < 0) {
+ queryStart = index - 1;
+ } else if (char == $hash && fragmentStart < 0) {
+ fragmentStart = index - 1;
+ }
+ }
+ if (ignoreLine) continue;
+ if (separatorIndex < 0) {
+ onError(
+ PackageConfigFormatException("No ':' on line", source, index - 1));
+ continue;
+ }
+ var packageName = String.fromCharCodes(source, start, separatorIndex);
+ var invalidIndex = checkPackageName(packageName);
+ if (invalidIndex >= 0) {
+ onError(PackageConfigFormatException(
+ 'Not a valid package name', source, start + invalidIndex));
+ continue;
+ }
+ if (queryStart >= 0) {
+ onError(PackageConfigFormatException(
+ 'Location URI must not have query', source, queryStart));
+ end = queryStart;
+ } else if (fragmentStart >= 0) {
+ onError(PackageConfigFormatException(
+ 'Location URI must not have fragment', source, fragmentStart));
+ end = fragmentStart;
+ }
+ var packageValue = String.fromCharCodes(source, separatorIndex + 1, end);
+ Uri packageLocation;
+ try {
+ packageLocation = Uri.parse(packageValue);
+ } on FormatException catch (e) {
+ onError(PackageConfigFormatException.from(e));
+ continue;
+ }
+ var relativeRoot = !hasAbsolutePath(packageLocation);
+ packageLocation = baseLocation.resolveUri(packageLocation);
+ if (packageLocation.isScheme('package')) {
+ onError(PackageConfigFormatException(
+ 'Package URI as location for package', source, separatorIndex + 1));
+ continue;
+ }
+ var path = packageLocation.path;
+ if (!path.endsWith('/')) {
+ path += '/';
+ packageLocation = packageLocation.replace(path: path);
+ }
+ if (packageNames.contains(packageName)) {
+ onError(PackageConfigFormatException(
+ 'Same package name occurred more than once', source, start));
+ continue;
+ }
+ var rootUri = packageLocation;
+ if (path.endsWith('/lib/')) {
+ // Assume default Pub package layout. Include package itself in root.
+ rootUri =
+ packageLocation.replace(path: path.substring(0, path.length - 4));
+ }
+ var package = SimplePackage.validate(packageName, rootUri, packageLocation,
+ _languageVersion, null, relativeRoot, (error) {
+ if (error is ArgumentError) {
+ onError(PackageConfigFormatException(error.message.toString(), source));
+ } else {
+ onError(error);
+ }
+ });
+ if (package != null) {
+ packages.add(package);
+ packageNames.add(packageName);
+ }
+ }
+ return SimplePackageConfig(1, packages, null, onError);
+}
+
+/// Writes the configuration to a [StringSink].
+///
+/// If [comment] is provided, the output will contain this comment
+/// with `# ` in front of each line.
+/// Lines are defined as ending in line feed (`'\n'`). If the final
+/// line of the comment doesn't end in a line feed, one will be added.
+///
+/// If [baseUri] is provided, package locations will be made relative
+/// to the base URI, if possible, before writing.
+void write(StringSink output, PackageConfig config,
+ {Uri? baseUri, String? comment}) {
+ if (baseUri != null && !baseUri.isAbsolute) {
+ throw PackageConfigArgumentError(baseUri, 'baseUri', 'Must be absolute');
+ }
+
+ if (comment != null) {
+ var lines = comment.split('\n');
+ if (lines.last.isEmpty) lines.removeLast();
+ for (var commentLine in lines) {
+ output.write('# ');
+ output.writeln(commentLine);
+ }
+ } else {
+ output.write('# generated by package:package_config at ');
+ output.write(DateTime.now());
+ output.writeln();
+ }
+ for (var package in config.packages) {
+ var packageName = package.name;
+ var uri = package.packageUriRoot;
+ // Validate packageName.
+ if (!isValidPackageName(packageName)) {
+ throw PackageConfigArgumentError(
+ config, 'config', '"$packageName" is not a valid package name');
+ }
+ if (uri.scheme == 'package') {
+ throw PackageConfigArgumentError(
+ config, 'config', 'Package location must not be a package URI: $uri');
+ }
+ output.write(packageName);
+ output.write(':');
+ // If baseUri is provided, make the URI relative to baseUri.
+ if (baseUri != null) {
+ uri = relativizeUri(uri, baseUri)!;
+ }
+ if (!uri.path.endsWith('/')) {
+ uri = uri.replace(path: '${uri.path}/');
+ }
+ output.write(uri);
+ output.writeln();
+ }
+}
diff --git a/pkgs/package_config/lib/src/util.dart b/pkgs/package_config/lib/src/util.dart
new file mode 100644
index 0000000..4f0210c
--- /dev/null
+++ b/pkgs/package_config/lib/src/util.dart
@@ -0,0 +1,253 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utility methods used by more than one library in the package.
+library;
+
+import 'errors.dart';
+
+// All ASCII characters that are valid in a package name, with space
+// for all the invalid ones (including space).
+const String _validPackageNameCharacters =
+ r" ! $ &'()*+,-. 0123456789 ; = "
+ r'@ABCDEFGHIJKLMNOPQRSTUVWXYZ _ abcdefghijklmnopqrstuvwxyz ~ ';
+
+/// Tests whether something is a valid Dart package name.
+bool isValidPackageName(String string) {
+ return checkPackageName(string) < 0;
+}
+
+/// Check if a string is a valid package name.
+///
+/// Valid package names contain only characters in [_validPackageNameCharacters]
+/// and must contain at least one non-'.' character.
+///
+/// Returns `-1` if the string is valid.
+/// Otherwise returns the index of the first invalid character,
+/// or `string.length` if the string contains no non-'.' character.
+int checkPackageName(String string) {
+ // Becomes non-zero if any non-'.' character is encountered.
+ var nonDot = 0;
+ for (var i = 0; i < string.length; i++) {
+ var c = string.codeUnitAt(i);
+ if (c > 0x7f || _validPackageNameCharacters.codeUnitAt(c) <= $space) {
+ return i;
+ }
+ nonDot += c ^ $dot;
+ }
+ if (nonDot == 0) return string.length;
+ return -1;
+}
+
+/// Validate that a [Uri] is a valid `package:` URI.
+///
+/// Used to validate user input.
+///
+/// Returns the package name extracted from the package URI,
+/// which is the path segment between `package:` and the first `/`.
+String checkValidPackageUri(Uri packageUri, String name) {
+ if (packageUri.scheme != 'package') {
+ throw PackageConfigArgumentError(packageUri, name, 'Not a package: URI');
+ }
+ if (packageUri.hasAuthority) {
+ throw PackageConfigArgumentError(
+ packageUri, name, 'Package URIs must not have a host part');
+ }
+ if (packageUri.hasQuery) {
+ // A query makes no sense if resolved to a file: URI.
+ throw PackageConfigArgumentError(
+ packageUri, name, 'Package URIs must not have a query part');
+ }
+ if (packageUri.hasFragment) {
+ // We could leave the fragment after the URL when resolving,
+ // but it would be odd if "package:foo/foo.dart#1" and
+ // "package:foo/foo.dart#2" were considered different libraries.
+ // Keep the syntax open in case we ever get multiple libraries in one file.
+ throw PackageConfigArgumentError(
+ packageUri, name, 'Package URIs must not have a fragment part');
+ }
+ if (packageUri.path.startsWith('/')) {
+ throw PackageConfigArgumentError(
+ packageUri, name, "Package URIs must not start with a '/'");
+ }
+ var firstSlash = packageUri.path.indexOf('/');
+ if (firstSlash == -1) {
+ throw PackageConfigArgumentError(packageUri, name,
+ "Package URIs must start with the package name followed by a '/'");
+ }
+ var packageName = packageUri.path.substring(0, firstSlash);
+ var badIndex = checkPackageName(packageName);
+ if (badIndex >= 0) {
+ if (packageName.isEmpty) {
+ throw PackageConfigArgumentError(
+ packageUri, name, 'Package names mus be non-empty');
+ }
+ if (badIndex == packageName.length) {
+ throw PackageConfigArgumentError(packageUri, name,
+ "Package names must contain at least one non-'.' character");
+ }
+ assert(badIndex < packageName.length);
+ var badCharCode = packageName.codeUnitAt(badIndex);
+ var badChar = 'U+${badCharCode.toRadixString(16).padLeft(4, '0')}';
+ if (badCharCode >= 0x20 && badCharCode <= 0x7e) {
+ // Printable character.
+ badChar = "'${packageName[badIndex]}' ($badChar)";
+ }
+ throw PackageConfigArgumentError(
+ packageUri, name, 'Package names must not contain $badChar');
+ }
+ return packageName;
+}
+
+/// Checks whether URI is just an absolute directory.
+///
+/// * It must have a scheme.
+/// * It must not have a query or fragment.
+/// * The path must end with `/`.
+bool isAbsoluteDirectoryUri(Uri uri) {
+ if (uri.hasQuery) return false;
+ if (uri.hasFragment) return false;
+ if (!uri.hasScheme) return false;
+ var path = uri.path;
+ if (!path.endsWith('/')) return false;
+ return true;
+}
+
+/// Whether the former URI is a prefix of the latter.
+bool isUriPrefix(Uri prefix, Uri path) {
+ assert(!prefix.hasFragment);
+ assert(!prefix.hasQuery);
+ assert(!path.hasQuery);
+ assert(!path.hasFragment);
+ assert(prefix.path.endsWith('/'));
+ return path.toString().startsWith(prefix.toString());
+}
+
+/// Finds the first non-JSON-whitespace character in a file.
+///
+/// Used to heuristically detect whether a file is a JSON file or an .ini file.
+int firstNonWhitespaceChar(List<int> bytes) {
+ for (var i = 0; i < bytes.length; i++) {
+ var char = bytes[i];
+ if (char != 0x20 && char != 0x09 && char != 0x0a && char != 0x0d) {
+ return char;
+ }
+ }
+ return -1;
+}
+
+/// Appends a trailing `/` if the path doesn't end with one.
+String trailingSlash(String path) {
+ if (path.isEmpty || path.endsWith('/')) return path;
+ return '$path/';
+}
+
+/// Whether a URI should not be considered relative to the base URI.
+///
+/// Used to determine whether a parsed root URI is relative
+/// to the configuration file or not.
+/// If it is relative, then it's rewritten as relative when
+/// output again later. If not, it's output as absolute.
+bool hasAbsolutePath(Uri uri) =>
+ uri.hasScheme || uri.hasAuthority || uri.hasAbsolutePath;
+
+/// Attempts to return a relative path-only URI for [uri].
+///
+/// First removes any query or fragment part from [uri].
+///
+/// If [uri] is already relative (has no scheme), it's returned as-is.
+/// If that is not desired, the caller can pass `baseUri.resolveUri(uri)`
+/// as the [uri] instead.
+///
+/// If the [uri] has a scheme or authority part which differs from
+/// the [baseUri], or if there is no overlap in the paths of the
+/// two URIs at all, the [uri] is returned as-is.
+///
+/// Otherwise the result is a path-only URI which satisfies
+/// `baseUri.resolveUri(result) == uri`,
+///
+/// The `baseUri` must be absolute.
+Uri? relativizeUri(Uri? uri, Uri? baseUri) {
+ if (baseUri == null) return uri;
+ assert(baseUri.isAbsolute);
+ if (uri!.hasQuery || uri.hasFragment) {
+ uri = Uri(
+ scheme: uri.scheme,
+ userInfo: uri.hasAuthority ? uri.userInfo : null,
+ host: uri.hasAuthority ? uri.host : null,
+ port: uri.hasAuthority ? uri.port : null,
+ path: uri.path);
+ }
+
+ // Already relative. We assume the caller knows what they are doing.
+ if (!uri.isAbsolute) return uri;
+
+ if (baseUri.scheme != uri.scheme) {
+ return uri;
+ }
+
+ // If authority differs, we could remove the scheme, but it's not worth it.
+ if (uri.hasAuthority != baseUri.hasAuthority) return uri;
+ if (uri.hasAuthority) {
+ if (uri.userInfo != baseUri.userInfo ||
+ uri.host.toLowerCase() != baseUri.host.toLowerCase() ||
+ uri.port != baseUri.port) {
+ return uri;
+ }
+ }
+
+ baseUri = baseUri.normalizePath();
+ var base = [...baseUri.pathSegments];
+ if (base.isNotEmpty) base.removeLast();
+ uri = uri.normalizePath();
+ var target = [...uri.pathSegments];
+ if (target.isNotEmpty && target.last.isEmpty) target.removeLast();
+ var index = 0;
+ while (index < base.length && index < target.length) {
+ if (base[index] != target[index]) {
+ break;
+ }
+ index++;
+ }
+ if (index == base.length) {
+ if (index == target.length) {
+ return Uri(path: './');
+ }
+ return Uri(path: target.skip(index).join('/'));
+ } else if (index > 0) {
+ var buffer = StringBuffer();
+ for (var n = base.length - index; n > 0; --n) {
+ buffer.write('../');
+ }
+ buffer.writeAll(target.skip(index), '/');
+ return Uri(path: buffer.toString());
+ } else {
+ return uri;
+ }
+}
+
+// Character constants used by this package.
+/// "Line feed" control character.
+const int $lf = 0x0a;
+
+/// "Carriage return" control character.
+const int $cr = 0x0d;
+
+/// Space character.
+const int $space = 0x20;
+
+/// Character `#`.
+const int $hash = 0x23;
+
+/// Character `.`.
+const int $dot = 0x2e;
+
+/// Character `:`.
+const int $colon = 0x3a;
+
+/// Character `?`.
+const int $question = 0x3f;
+
+/// Character `{`.
+const int $lbrace = 0x7b;
diff --git a/pkgs/package_config/lib/src/util_io.dart b/pkgs/package_config/lib/src/util_io.dart
new file mode 100644
index 0000000..4680eef
--- /dev/null
+++ b/pkgs/package_config/lib/src/util_io.dart
@@ -0,0 +1,108 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utility methods requiring dart:io and used by more than one library in the
+/// package.
+library;
+
+import 'dart:io';
+import 'dart:typed_data';
+
+Future<Uint8List?> defaultLoader(Uri uri) async {
+ if (uri.isScheme('file')) {
+ var file = File.fromUri(uri);
+ try {
+ return await file.readAsBytes();
+ } catch (_) {
+ return null;
+ }
+ }
+ if (uri.isScheme('http') || uri.isScheme('https')) {
+ return _httpGet(uri);
+ }
+ throw UnsupportedError('Default URI unsupported scheme: $uri');
+}
+
+Future<Uint8List?> _httpGet(Uri uri) async {
+ assert(uri.isScheme('http') || uri.isScheme('https'));
+ var client = HttpClient();
+ var request = await client.getUrl(uri);
+ var response = await request.close();
+ if (response.statusCode != HttpStatus.ok) {
+ return null;
+ }
+ var splitContent = await response.toList();
+ var totalLength = 0;
+ if (splitContent.length == 1) {
+ var part = splitContent[0];
+ if (part is Uint8List) {
+ return part;
+ }
+ }
+ for (var list in splitContent) {
+ totalLength += list.length;
+ }
+ var result = Uint8List(totalLength);
+ var offset = 0;
+ for (var contentPart in splitContent as Iterable<Uint8List>) {
+ result.setRange(offset, offset + contentPart.length, contentPart);
+ offset += contentPart.length;
+ }
+ return result;
+}
+
+/// The file name of a path.
+///
+/// The file name is everything after the last occurrence of
+/// [Platform.pathSeparator], or the entire string if no
+/// path separator occurs in the string.
+String fileName(String path) {
+ var separator = Platform.pathSeparator;
+ var lastSeparator = path.lastIndexOf(separator);
+ if (lastSeparator < 0) return path;
+ return path.substring(lastSeparator + separator.length);
+}
+
+/// The directory name of a path.
+///
+/// The directory name is everything before the last occurrence of
+/// [Platform.pathSeparator], or the empty string if no
+/// path separator occurs in the string.
+String dirName(String path) {
+ var separator = Platform.pathSeparator;
+ var lastSeparator = path.lastIndexOf(separator);
+ if (lastSeparator < 0) return '';
+ return path.substring(0, lastSeparator);
+}
+
+/// Join path parts with the [Platform.pathSeparator].
+///
+/// If a part ends with a path separator, then no extra separator is
+/// inserted.
+String pathJoin(String part1, String part2, [String? part3]) {
+ var separator = Platform.pathSeparator;
+ var separator1 = part1.endsWith(separator) ? '' : separator;
+ if (part3 == null) {
+ return '$part1$separator1$part2';
+ }
+ var separator2 = part2.endsWith(separator) ? '' : separator;
+ return '$part1$separator1$part2$separator2$part3';
+}
+
+/// Join an unknown number of path parts with [Platform.pathSeparator].
+///
+/// If a part ends with a path separator, then no extra separator is
+/// inserted.
+String pathJoinAll(Iterable<String> parts) {
+ var buffer = StringBuffer();
+ var separator = '';
+ for (var part in parts) {
+ buffer
+ ..write(separator)
+ ..write(part);
+ separator =
+ part.endsWith(Platform.pathSeparator) ? '' : Platform.pathSeparator;
+ }
+ return buffer.toString();
+}
diff --git a/pkgs/package_config/pubspec.yaml b/pkgs/package_config/pubspec.yaml
new file mode 100644
index 0000000..28f3e13
--- /dev/null
+++ b/pkgs/package_config/pubspec.yaml
@@ -0,0 +1,14 @@
+name: package_config
+version: 2.1.1
+description: Support for reading and writing Dart Package Configuration files.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/package_config
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ path: ^1.8.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.0
diff --git a/pkgs/package_config/test/bench.dart b/pkgs/package_config/test/bench.dart
new file mode 100644
index 0000000..8428481
--- /dev/null
+++ b/pkgs/package_config/test/bench.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:package_config/src/errors.dart';
+import 'package:package_config/src/package_config_json.dart';
+
+void bench(final int size, final bool doPrint) {
+ var sb = StringBuffer();
+ sb.writeln('{');
+ sb.writeln('"configVersion": 2,');
+ sb.writeln('"packages": [');
+ for (var i = 0; i < size; i++) {
+ if (i != 0) {
+ sb.writeln(',');
+ }
+ sb.writeln('{');
+ sb.writeln(' "name": "p_$i",');
+ sb.writeln(' "rootUri": "file:///p_$i/",');
+ sb.writeln(' "packageUri": "lib/",');
+ sb.writeln(' "languageVersion": "2.5",');
+ sb.writeln(' "nonstandard": true');
+ sb.writeln('}');
+ }
+ sb.writeln('],');
+ sb.writeln('"generator": "pub",');
+ sb.writeln('"other": [42]');
+ sb.writeln('}');
+ var stopwatch = Stopwatch()..start();
+ var config = parsePackageConfigBytes(
+ // ignore: unnecessary_cast
+ utf8.encode(sb.toString()) as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'),
+ throwError,
+ );
+ final read = stopwatch.elapsedMilliseconds;
+
+ stopwatch.reset();
+ for (var i = 0; i < size; i++) {
+ if (config.packageOf(Uri.parse('file:///p_$i/lib/src/foo.dart'))!.name !=
+ 'p_$i') {
+ throw StateError('Unexpected result!');
+ }
+ }
+ final lookup = stopwatch.elapsedMilliseconds;
+
+ if (doPrint) {
+ print('Read file with $size packages in $read ms, '
+ 'looked up all packages in $lookup ms');
+ }
+}
+
+void main(List<String> args) {
+ if (args.length != 1 && args.length != 2) {
+ throw ArgumentError('Expects arguments: <size> <warmup iterations>?');
+ }
+ final size = int.parse(args[0]);
+ if (args.length > 1) {
+ final warmups = int.parse(args[1]);
+ print('Performing $warmups warmup iterations.');
+ for (var i = 0; i < warmups; i++) {
+ bench(10, false);
+ }
+ }
+
+ // Benchmark.
+ bench(size, true);
+}
diff --git a/pkgs/package_config/test/discovery_test.dart b/pkgs/package_config/test/discovery_test.dart
new file mode 100644
index 0000000..6d1b655
--- /dev/null
+++ b/pkgs/package_config/test/discovery_test.dart
@@ -0,0 +1,346 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'dart:io';
+
+import 'package:package_config/package_config.dart';
+import 'package:test/test.dart';
+
+import 'src/util.dart';
+import 'src/util_io.dart';
+
+const packagesFile = '''
+# A comment
+foo:file:///dart/packages/foo/
+bar:/dart/packages/bar/
+baz:packages/baz/
+''';
+
+const packageConfigFile = '''
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "foo",
+ "rootUri": "file:///dart/packages/foo/"
+ },
+ {
+ "name": "bar",
+ "rootUri": "/dart/packages/bar/"
+ },
+ {
+ "name": "baz",
+ "rootUri": "../packages/baz/"
+ }
+ ],
+ "extra": [42]
+}
+''';
+
+void validatePackagesFile(PackageConfig resolver, Directory directory) {
+ expect(resolver, isNotNull);
+ expect(resolver.resolve(pkg('foo', 'bar/baz')),
+ equals(Uri.parse('file:///dart/packages/foo/bar/baz')));
+ expect(resolver.resolve(pkg('bar', 'baz/qux')),
+ equals(Uri.parse('file:///dart/packages/bar/baz/qux')));
+ expect(resolver.resolve(pkg('baz', 'qux/foo')),
+ equals(Uri.directory(directory.path).resolve('packages/baz/qux/foo')));
+ expect([for (var p in resolver.packages) p.name],
+ unorderedEquals(['foo', 'bar', 'baz']));
+}
+
+void main() {
+ group('findPackages', () {
+ // Finds package_config.json if there.
+ fileTest('package_config.json', {
+ '.packages': 'invalid .packages file',
+ 'script.dart': 'main(){}',
+ 'packages': {'shouldNotBeFound': <Never, Never>{}},
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ }
+ }, (Directory directory) async {
+ var config = (await findPackageConfig(directory))!;
+ expect(config.version, 2); // Found package_config.json file.
+ validatePackagesFile(config, directory);
+ });
+
+ // Finds .packages if no package_config.json.
+ fileTest('.packages', {
+ '.packages': packagesFile,
+ 'script.dart': 'main(){}',
+ 'packages': {'shouldNotBeFound': <Object, Object>{}}
+ }, (Directory directory) async {
+ var config = (await findPackageConfig(directory))!;
+ expect(config.version, 1); // Found .packages file.
+ validatePackagesFile(config, directory);
+ });
+
+ // Finds package_config.json in super-directory.
+ fileTest('package_config.json recursive', {
+ '.packages': packagesFile,
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ },
+ 'subdir': {
+ 'script.dart': 'main(){}',
+ }
+ }, (Directory directory) async {
+ var config = (await findPackageConfig(subdir(directory, 'subdir/')))!;
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+
+ // Finds .packages in super-directory.
+ fileTest('.packages recursive', {
+ '.packages': packagesFile,
+ 'subdir': {'script.dart': 'main(){}'}
+ }, (Directory directory) async {
+ var config = (await findPackageConfig(subdir(directory, 'subdir/')))!;
+ expect(config.version, 1);
+ validatePackagesFile(config, directory);
+ });
+
+ // Does not find a packages/ directory, and returns null if nothing found.
+ fileTest('package directory packages not supported', {
+ 'packages': {
+ 'foo': <String, dynamic>{},
+ }
+ }, (Directory directory) async {
+ var config = await findPackageConfig(directory);
+ expect(config, null);
+ });
+
+ group('throws', () {
+ fileTest('invalid .packages', {
+ '.packages': 'not a .packages file',
+ }, (Directory directory) {
+ expect(findPackageConfig(directory), throwsA(isA<FormatException>()));
+ });
+
+ fileTest('invalid .packages as JSON', {
+ '.packages': packageConfigFile,
+ }, (Directory directory) {
+ expect(findPackageConfig(directory), throwsA(isA<FormatException>()));
+ });
+
+ fileTest('invalid .packages', {
+ '.dart_tool': {
+ 'package_config.json': 'not a JSON file',
+ }
+ }, (Directory directory) {
+ expect(findPackageConfig(directory), throwsA(isA<FormatException>()));
+ });
+
+ fileTest('invalid .packages as INI', {
+ '.dart_tool': {
+ 'package_config.json': packagesFile,
+ }
+ }, (Directory directory) {
+ expect(findPackageConfig(directory), throwsA(isA<FormatException>()));
+ });
+ });
+
+ group('handles error', () {
+ fileTest('invalid .packages', {
+ '.packages': 'not a .packages file',
+ }, (Directory directory) async {
+ var hadError = false;
+ await findPackageConfig(directory,
+ onError: expectAsync1((error) {
+ hadError = true;
+ expect(error, isA<FormatException>());
+ }, max: -1));
+ expect(hadError, true);
+ });
+
+ fileTest('invalid .packages as JSON', {
+ '.packages': packageConfigFile,
+ }, (Directory directory) async {
+ var hadError = false;
+ await findPackageConfig(directory,
+ onError: expectAsync1((error) {
+ hadError = true;
+ expect(error, isA<FormatException>());
+ }, max: -1));
+ expect(hadError, true);
+ });
+
+ fileTest('invalid package_config not JSON', {
+ '.dart_tool': {
+ 'package_config.json': 'not a JSON file',
+ }
+ }, (Directory directory) async {
+ var hadError = false;
+ await findPackageConfig(directory,
+ onError: expectAsync1((error) {
+ hadError = true;
+ expect(error, isA<FormatException>());
+ }, max: -1));
+ expect(hadError, true);
+ });
+
+ fileTest('invalid package config as INI', {
+ '.dart_tool': {
+ 'package_config.json': packagesFile,
+ }
+ }, (Directory directory) async {
+ var hadError = false;
+ await findPackageConfig(directory,
+ onError: expectAsync1((error) {
+ hadError = true;
+ expect(error, isA<FormatException>());
+ }, max: -1));
+ expect(hadError, true);
+ });
+ });
+
+ // Does not find .packages if no package_config.json and minVersion > 1.
+ fileTest('.packages ignored', {
+ '.packages': packagesFile,
+ 'script.dart': 'main(){}'
+ }, (Directory directory) async {
+ var config = await findPackageConfig(directory, minVersion: 2);
+ expect(config, null);
+ });
+
+ // Finds package_config.json in super-directory, with .packages in
+ // subdir and minVersion > 1.
+ fileTest('package_config.json recursive .packages ignored', {
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ },
+ 'subdir': {
+ '.packages': packagesFile,
+ 'script.dart': 'main(){}',
+ }
+ }, (Directory directory) async {
+ var config = (await findPackageConfig(subdir(directory, 'subdir/'),
+ minVersion: 2))!;
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+ });
+
+ group('loadPackageConfig', () {
+ // Load a specific files
+ group('package_config.json', () {
+ var files = {
+ '.packages': packagesFile,
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ },
+ };
+ fileTest('directly', files, (Directory directory) async {
+ var file =
+ dirFile(subdir(directory, '.dart_tool'), 'package_config.json');
+ var config = await loadPackageConfig(file);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+ fileTest('indirectly through .packages', files,
+ (Directory directory) async {
+ var file = dirFile(directory, '.packages');
+ var config = await loadPackageConfig(file);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+ fileTest('prefer .packages', files, (Directory directory) async {
+ var file = dirFile(directory, '.packages');
+ var config = await loadPackageConfig(file, preferNewest: false);
+ expect(config.version, 1);
+ validatePackagesFile(config, directory);
+ });
+ });
+
+ fileTest('package_config.json non-default name', {
+ '.packages': packagesFile,
+ 'subdir': {
+ 'pheldagriff': packageConfigFile,
+ },
+ }, (Directory directory) async {
+ var file = dirFile(directory, 'subdir/pheldagriff');
+ var config = await loadPackageConfig(file);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+
+ fileTest('package_config.json named .packages', {
+ 'subdir': {
+ '.packages': packageConfigFile,
+ },
+ }, (Directory directory) async {
+ var file = dirFile(directory, 'subdir/.packages');
+ var config = await loadPackageConfig(file);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+
+ fileTest('.packages', {
+ '.packages': packagesFile,
+ }, (Directory directory) async {
+ var file = dirFile(directory, '.packages');
+ var config = await loadPackageConfig(file);
+ expect(config.version, 1);
+ validatePackagesFile(config, directory);
+ });
+
+ fileTest('.packages non-default name', {
+ 'pheldagriff': packagesFile,
+ }, (Directory directory) async {
+ var file = dirFile(directory, 'pheldagriff');
+ var config = await loadPackageConfig(file);
+ expect(config.version, 1);
+ validatePackagesFile(config, directory);
+ });
+
+ fileTest('no config found', {}, (Directory directory) {
+ var file = dirFile(directory, 'anyname');
+ expect(
+ () => loadPackageConfig(file), throwsA(isA<FileSystemException>()));
+ });
+
+ fileTest('no config found, handled', {}, (Directory directory) async {
+ var file = dirFile(directory, 'anyname');
+ var hadError = false;
+ await loadPackageConfig(file,
+ onError: expectAsync1((error) {
+ hadError = true;
+ expect(error, isA<FileSystemException>());
+ }, max: -1));
+ expect(hadError, true);
+ });
+
+ fileTest('specified file syntax error', {
+ 'anyname': 'syntax error',
+ }, (Directory directory) {
+ var file = dirFile(directory, 'anyname');
+ expect(() => loadPackageConfig(file), throwsFormatException);
+ });
+
+ // Find package_config.json in subdir even if initial file syntax error.
+ fileTest('specified file syntax onError', {
+ '.packages': 'syntax error',
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ },
+ }, (Directory directory) async {
+ var file = dirFile(directory, '.packages');
+ var config = await loadPackageConfig(file);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+
+ // A file starting with `{` is a package_config.json file.
+ fileTest('file syntax error with {', {
+ '.packages': '{syntax error',
+ }, (Directory directory) {
+ var file = dirFile(directory, '.packages');
+ expect(() => loadPackageConfig(file), throwsFormatException);
+ });
+ });
+}
diff --git a/pkgs/package_config/test/discovery_uri_test.dart b/pkgs/package_config/test/discovery_uri_test.dart
new file mode 100644
index 0000000..542bf0a
--- /dev/null
+++ b/pkgs/package_config/test/discovery_uri_test.dart
@@ -0,0 +1,310 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'package:package_config/package_config.dart';
+import 'package:test/test.dart';
+
+import 'src/util.dart';
+
+const packagesFile = '''
+# A comment
+foo:file:///dart/packages/foo/
+bar:/dart/packages/bar/
+baz:packages/baz/
+''';
+
+const packageConfigFile = '''
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "foo",
+ "rootUri": "file:///dart/packages/foo/"
+ },
+ {
+ "name": "bar",
+ "rootUri": "/dart/packages/bar/"
+ },
+ {
+ "name": "baz",
+ "rootUri": "../packages/baz/"
+ }
+ ],
+ "extra": [42]
+}
+''';
+
+void validatePackagesFile(PackageConfig resolver, Uri directory) {
+ expect(resolver, isNotNull);
+ expect(resolver.resolve(pkg('foo', 'bar/baz')),
+ equals(Uri.parse('file:///dart/packages/foo/bar/baz')));
+ expect(resolver.resolve(pkg('bar', 'baz/qux')),
+ equals(directory.resolve('/dart/packages/bar/baz/qux')));
+ expect(resolver.resolve(pkg('baz', 'qux/foo')),
+ equals(directory.resolve('packages/baz/qux/foo')));
+ expect([for (var p in resolver.packages) p.name],
+ unorderedEquals(['foo', 'bar', 'baz']));
+}
+
+void main() {
+ group('findPackages', () {
+ // Finds package_config.json if there.
+ loaderTest('package_config.json', {
+ '.packages': 'invalid .packages file',
+ 'script.dart': 'main(){}',
+ 'packages': {'shouldNotBeFound': <String, dynamic>{}},
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ }
+ }, (directory, loader) async {
+ var config = (await findPackageConfigUri(directory, loader: loader))!;
+ expect(config.version, 2); // Found package_config.json file.
+ validatePackagesFile(config, directory);
+ });
+
+ // Finds .packages if no package_config.json.
+ loaderTest('.packages', {
+ '.packages': packagesFile,
+ 'script.dart': 'main(){}',
+ 'packages': {'shouldNotBeFound': <String, dynamic>{}}
+ }, (directory, loader) async {
+ var config = (await findPackageConfigUri(directory, loader: loader))!;
+ expect(config.version, 1); // Found .packages file.
+ validatePackagesFile(config, directory);
+ });
+
+ // Finds package_config.json in super-directory.
+ loaderTest('package_config.json recursive', {
+ '.packages': packagesFile,
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ },
+ 'subdir': {
+ 'script.dart': 'main(){}',
+ }
+ }, (directory, loader) async {
+ var config = (await findPackageConfigUri(directory.resolve('subdir/'),
+ loader: loader))!;
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+
+ // Finds .packages in super-directory.
+ loaderTest('.packages recursive', {
+ '.packages': packagesFile,
+ 'subdir': {'script.dart': 'main(){}'}
+ }, (directory, loader) async {
+ var config = (await findPackageConfigUri(directory.resolve('subdir/'),
+ loader: loader))!;
+ expect(config.version, 1);
+ validatePackagesFile(config, directory);
+ });
+
+ // Does not find a packages/ directory, and returns null if nothing found.
+ loaderTest('package directory packages not supported', {
+ 'packages': {
+ 'foo': <String, dynamic>{},
+ }
+ }, (Uri directory, loader) async {
+ var config = await findPackageConfigUri(directory, loader: loader);
+ expect(config, null);
+ });
+
+ loaderTest('invalid .packages', {
+ '.packages': 'not a .packages file',
+ }, (Uri directory, loader) {
+ expect(() => findPackageConfigUri(directory, loader: loader),
+ throwsA(isA<FormatException>()));
+ });
+
+ loaderTest('invalid .packages as JSON', {
+ '.packages': packageConfigFile,
+ }, (Uri directory, loader) {
+ expect(() => findPackageConfigUri(directory, loader: loader),
+ throwsA(isA<FormatException>()));
+ });
+
+ loaderTest('invalid .packages', {
+ '.dart_tool': {
+ 'package_config.json': 'not a JSON file',
+ }
+ }, (Uri directory, loader) {
+ expect(() => findPackageConfigUri(directory, loader: loader),
+ throwsA(isA<FormatException>()));
+ });
+
+ loaderTest('invalid .packages as INI', {
+ '.dart_tool': {
+ 'package_config.json': packagesFile,
+ }
+ }, (Uri directory, loader) {
+ expect(() => findPackageConfigUri(directory, loader: loader),
+ throwsA(isA<FormatException>()));
+ });
+
+ // Does not find .packages if no package_config.json and minVersion > 1.
+ loaderTest('.packages ignored', {
+ '.packages': packagesFile,
+ 'script.dart': 'main(){}'
+ }, (directory, loader) async {
+ var config =
+ await findPackageConfigUri(directory, minVersion: 2, loader: loader);
+ expect(config, null);
+ });
+
+ // Finds package_config.json in super-directory, with .packages in
+ // subdir and minVersion > 1.
+ loaderTest('package_config.json recursive ignores .packages', {
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ },
+ 'subdir': {
+ '.packages': packagesFile,
+ 'script.dart': 'main(){}',
+ }
+ }, (directory, loader) async {
+ var config = (await findPackageConfigUri(directory.resolve('subdir/'),
+ minVersion: 2, loader: loader))!;
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+ });
+
+ group('loadPackageConfig', () {
+ // Load a specific files
+ group('package_config.json', () {
+ var files = {
+ '.packages': packagesFile,
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ },
+ };
+ loaderTest('directly', files, (Uri directory, loader) async {
+ var file = directory.resolve('.dart_tool/package_config.json');
+ var config = await loadPackageConfigUri(file, loader: loader);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+ loaderTest('indirectly through .packages', files,
+ (Uri directory, loader) async {
+ var file = directory.resolve('.packages');
+ var config = await loadPackageConfigUri(file, loader: loader);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+ });
+
+ loaderTest('package_config.json non-default name', {
+ '.packages': packagesFile,
+ 'subdir': {
+ 'pheldagriff': packageConfigFile,
+ },
+ }, (Uri directory, loader) async {
+ var file = directory.resolve('subdir/pheldagriff');
+ var config = await loadPackageConfigUri(file, loader: loader);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+
+ loaderTest('package_config.json named .packages', {
+ 'subdir': {
+ '.packages': packageConfigFile,
+ },
+ }, (Uri directory, loader) async {
+ var file = directory.resolve('subdir/.packages');
+ var config = await loadPackageConfigUri(file, loader: loader);
+ expect(config.version, 2);
+ validatePackagesFile(config, directory);
+ });
+
+ loaderTest('.packages', {
+ '.packages': packagesFile,
+ }, (Uri directory, loader) async {
+ var file = directory.resolve('.packages');
+ var config = await loadPackageConfigUri(file, loader: loader);
+ expect(config.version, 1);
+ validatePackagesFile(config, directory);
+ });
+
+ loaderTest('.packages non-default name', {
+ 'pheldagriff': packagesFile,
+ }, (Uri directory, loader) async {
+ var file = directory.resolve('pheldagriff');
+ var config = await loadPackageConfigUri(file, loader: loader);
+ expect(config.version, 1);
+ validatePackagesFile(config, directory);
+ });
+
+ loaderTest('no config found', {}, (Uri directory, loader) {
+ var file = directory.resolve('anyname');
+ expect(() => loadPackageConfigUri(file, loader: loader),
+ throwsA(isA<ArgumentError>()));
+ });
+
+ loaderTest('no config found, handle error', {},
+ (Uri directory, loader) async {
+ var file = directory.resolve('anyname');
+ var hadError = false;
+ await loadPackageConfigUri(file,
+ loader: loader,
+ onError: expectAsync1((error) {
+ hadError = true;
+ expect(error, isA<ArgumentError>());
+ }, max: -1));
+ expect(hadError, true);
+ });
+
+ loaderTest('specified file syntax error', {
+ 'anyname': 'syntax error',
+ }, (Uri directory, loader) {
+ var file = directory.resolve('anyname');
+ expect(() => loadPackageConfigUri(file, loader: loader),
+ throwsFormatException);
+ });
+
+ loaderTest('specified file syntax onError', {
+ 'anyname': 'syntax error',
+ }, (directory, loader) async {
+ var file = directory.resolve('anyname');
+ var hadError = false;
+ await loadPackageConfigUri(file,
+ loader: loader,
+ onError: expectAsync1((error) {
+ hadError = true;
+ expect(error, isA<FormatException>());
+ }, max: -1));
+ expect(hadError, true);
+ });
+
+ // Don't look for package_config.json if original file not named .packages.
+ loaderTest('specified file syntax error with alternative', {
+ 'anyname': 'syntax error',
+ '.dart_tool': {
+ 'package_config.json': packageConfigFile,
+ },
+ }, (directory, loader) async {
+ var file = directory.resolve('anyname');
+ expect(() => loadPackageConfigUri(file, loader: loader),
+ throwsFormatException);
+ });
+
+ // A file starting with `{` is a package_config.json file.
+ loaderTest('file syntax error with {', {
+ '.packages': '{syntax error',
+ }, (directory, loader) async {
+ var file = directory.resolve('.packages');
+ var hadError = false;
+ await loadPackageConfigUri(file,
+ loader: loader,
+ onError: expectAsync1((error) {
+ hadError = true;
+ expect(error, isA<FormatException>());
+ }, max: -1));
+ expect(hadError, true);
+ });
+ });
+}
diff --git a/pkgs/package_config/test/package_config_impl_test.dart b/pkgs/package_config/test/package_config_impl_test.dart
new file mode 100644
index 0000000..0f39963
--- /dev/null
+++ b/pkgs/package_config/test/package_config_impl_test.dart
@@ -0,0 +1,188 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show jsonDecode;
+
+import 'package:package_config/package_config_types.dart';
+import 'package:test/test.dart';
+import 'src/util.dart';
+
+void main() {
+ var unique = Object();
+ var root = Uri.file('/tmp/root/');
+
+ group('LanguageVersion', () {
+ test('minimal', () {
+ var version = LanguageVersion(3, 5);
+ expect(version.major, 3);
+ expect(version.minor, 5);
+ });
+
+ test('negative major', () {
+ expect(() => LanguageVersion(-1, 1), throwsArgumentError);
+ });
+
+ test('negative minor', () {
+ expect(() => LanguageVersion(1, -1), throwsArgumentError);
+ });
+
+ test('minimal parse', () {
+ var version = LanguageVersion.parse('3.5');
+ expect(version.major, 3);
+ expect(version.minor, 5);
+ });
+
+ void failParse(String name, String input) {
+ test('$name - error', () {
+ expect(() => LanguageVersion.parse(input),
+ throwsA(isA<PackageConfigError>()));
+ expect(() => LanguageVersion.parse(input), throwsFormatException);
+ var failed = false;
+ var actual = LanguageVersion.parse(input, onError: (_) {
+ failed = true;
+ });
+ expect(failed, true);
+ expect(actual, isA<LanguageVersion>());
+ });
+ }
+
+ failParse('Leading zero major', '01.1');
+ failParse('Leading zero minor', '1.01');
+ failParse('Sign+ major', '+1.1');
+ failParse('Sign- major', '-1.1');
+ failParse('Sign+ minor', '1.+1');
+ failParse('Sign- minor', '1.-1');
+ failParse('WhiteSpace 1', ' 1.1');
+ failParse('WhiteSpace 2', '1 .1');
+ failParse('WhiteSpace 3', '1. 1');
+ failParse('WhiteSpace 4', '1.1 ');
+ });
+
+ group('Package', () {
+ test('minimal', () {
+ var package = Package('name', root, extraData: unique);
+ expect(package.name, 'name');
+ expect(package.root, root);
+ expect(package.packageUriRoot, root);
+ expect(package.languageVersion, null);
+ expect(package.extraData, same(unique));
+ });
+
+ test('absolute package root', () {
+ var version = LanguageVersion(1, 1);
+ var absolute = root.resolve('foo/bar/');
+ var package = Package('name', root,
+ packageUriRoot: absolute,
+ relativeRoot: false,
+ languageVersion: version,
+ extraData: unique);
+ expect(package.name, 'name');
+ expect(package.root, root);
+ expect(package.packageUriRoot, absolute);
+ expect(package.languageVersion, version);
+ expect(package.extraData, same(unique));
+ expect(package.relativeRoot, false);
+ });
+
+ test('relative package root', () {
+ var relative = Uri.parse('foo/bar/');
+ var absolute = root.resolveUri(relative);
+ var package = Package('name', root,
+ packageUriRoot: relative, relativeRoot: true, extraData: unique);
+ expect(package.name, 'name');
+ expect(package.root, root);
+ expect(package.packageUriRoot, absolute);
+ expect(package.relativeRoot, true);
+ expect(package.languageVersion, null);
+ expect(package.extraData, same(unique));
+ });
+
+ for (var badName in ['a/z', 'a:z', '', '...']) {
+ test("Invalid name '$badName'", () {
+ expect(() => Package(badName, root), throwsPackageConfigError);
+ });
+ }
+
+ test('Invalid root, not absolute', () {
+ expect(
+ () => Package('name', Uri.parse('/foo/')), throwsPackageConfigError);
+ });
+
+ test('Invalid root, not ending in slash', () {
+ expect(() => Package('name', Uri.parse('file:///foo')),
+ throwsPackageConfigError);
+ });
+
+ test('invalid package root, not ending in slash', () {
+ expect(() => Package('name', root, packageUriRoot: Uri.parse('foo')),
+ throwsPackageConfigError);
+ });
+
+ test('invalid package root, not inside root', () {
+ expect(() => Package('name', root, packageUriRoot: Uri.parse('../baz/')),
+ throwsPackageConfigError);
+ });
+ });
+
+ group('package config', () {
+ test('empty', () {
+ var empty = PackageConfig([], extraData: unique);
+ expect(empty.version, 2);
+ expect(empty.packages, isEmpty);
+ expect(empty.extraData, same(unique));
+ expect(empty.resolve(pkg('a', 'b')), isNull);
+ });
+
+ test('single', () {
+ var package = Package('name', root);
+ var single = PackageConfig([package], extraData: unique);
+ expect(single.version, 2);
+ expect(single.packages, hasLength(1));
+ expect(single.extraData, same(unique));
+ expect(single.resolve(pkg('a', 'b')), isNull);
+ var resolved = single.resolve(pkg('name', 'a/b'));
+ expect(resolved, root.resolve('a/b'));
+ });
+ });
+ test('writeString', () {
+ var config = PackageConfig([
+ Package('foo', Uri.parse('file:///pkg/foo/'),
+ packageUriRoot: Uri.parse('file:///pkg/foo/lib/'),
+ relativeRoot: false,
+ languageVersion: LanguageVersion(2, 4),
+ extraData: {'foo': 'foo!'}),
+ Package('bar', Uri.parse('file:///pkg/bar/'),
+ packageUriRoot: Uri.parse('file:///pkg/bar/lib/'),
+ relativeRoot: true,
+ extraData: {'bar': 'bar!'}),
+ ], extraData: {
+ 'extra': 'data'
+ });
+ var buffer = StringBuffer();
+ PackageConfig.writeString(config, buffer, Uri.parse('file:///pkg/'));
+ var text = buffer.toString();
+ var json = jsonDecode(text); // Is valid JSON.
+ expect(json, {
+ 'configVersion': 2,
+ 'packages': unorderedEquals([
+ {
+ 'name': 'foo',
+ 'rootUri': 'file:///pkg/foo/',
+ 'packageUri': 'lib/',
+ 'languageVersion': '2.4',
+ 'foo': 'foo!',
+ },
+ {
+ 'name': 'bar',
+ 'rootUri': 'bar/',
+ 'packageUri': 'lib/',
+ 'bar': 'bar!',
+ },
+ ]),
+ 'extra': 'data',
+ });
+ });
+}
+
+final Matcher throwsPackageConfigError = throwsA(isA<PackageConfigError>());
diff --git a/pkgs/package_config/test/parse_test.dart b/pkgs/package_config/test/parse_test.dart
new file mode 100644
index 0000000..a92b9bf
--- /dev/null
+++ b/pkgs/package_config/test/parse_test.dart
@@ -0,0 +1,552 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:package_config/package_config_types.dart';
+import 'package:package_config/src/errors.dart';
+import 'package:package_config/src/package_config_json.dart';
+import 'package:package_config/src/packages_file.dart' as packages;
+import 'package:test/test.dart';
+
+import 'src/util.dart';
+
+void main() {
+ group('.packages', () {
+ test('valid', () {
+ var packagesFile = '# Generated by pub yadda yadda\n'
+ 'foo:file:///foo/lib/\n'
+ 'bar:/bar/lib/\n'
+ 'baz:lib/\n';
+ var result = packages.parse(utf8.encode(packagesFile),
+ Uri.parse('file:///tmp/file.dart'), throwError);
+ expect(result.version, 1);
+ expect({for (var p in result.packages) p.name}, {'foo', 'bar', 'baz'});
+ expect(result.resolve(pkg('foo', 'foo.dart')),
+ Uri.parse('file:///foo/lib/foo.dart'));
+ expect(result.resolve(pkg('bar', 'bar.dart')),
+ Uri.parse('file:///bar/lib/bar.dart'));
+ expect(result.resolve(pkg('baz', 'baz.dart')),
+ Uri.parse('file:///tmp/lib/baz.dart'));
+
+ var foo = result['foo']!;
+ expect(foo, isNotNull);
+ expect(foo.root, Uri.parse('file:///foo/'));
+ expect(foo.packageUriRoot, Uri.parse('file:///foo/lib/'));
+ expect(foo.languageVersion, LanguageVersion(2, 7));
+ expect(foo.relativeRoot, false);
+ });
+
+ test('valid empty', () {
+ var packagesFile = '# Generated by pub yadda yadda\n';
+ var result = packages.parse(
+ utf8.encode(packagesFile), Uri.file('/tmp/file.dart'), throwError);
+ expect(result.version, 1);
+ expect({for (var p in result.packages) p.name}, <String>{});
+ });
+
+ group('invalid', () {
+ var baseFile = Uri.file('/tmp/file.dart');
+ void testThrows(String name, String content) {
+ test(name, () {
+ expect(
+ () => packages.parse(utf8.encode(content), baseFile, throwError),
+ throwsA(isA<FormatException>()));
+ });
+ test('$name, handle error', () {
+ var hadError = false;
+ packages.parse(utf8.encode(content), baseFile, (error) {
+ hadError = true;
+ expect(error, isA<FormatException>());
+ });
+ expect(hadError, true);
+ });
+ }
+
+ testThrows('repeated package name', 'foo:lib/\nfoo:lib\n');
+ testThrows('no colon', 'foo\n');
+ testThrows('empty package name', ':lib/\n');
+ testThrows('dot only package name', '.:lib/\n');
+ testThrows('dot only package name', '..:lib/\n');
+ testThrows('invalid package name character', 'f\\o:lib/\n');
+ testThrows('package URI', 'foo:package:bar/lib/');
+ testThrows('location with query', 'f\\o:lib/?\n');
+ testThrows('location with fragment', 'f\\o:lib/#\n');
+ });
+ });
+
+ group('package_config.json', () {
+ test('valid', () {
+ var packageConfigFile = '''
+ {
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "foo",
+ "rootUri": "file:///foo/",
+ "packageUri": "lib/",
+ "languageVersion": "2.5",
+ "nonstandard": true
+ },
+ {
+ "name": "bar",
+ "rootUri": "/bar/",
+ "packageUri": "lib/",
+ "languageVersion": "9999.9999"
+ },
+ {
+ "name": "baz",
+ "rootUri": "../",
+ "packageUri": "lib/"
+ },
+ {
+ "name": "noslash",
+ "rootUri": "../noslash",
+ "packageUri": "lib"
+ }
+ ],
+ "generator": "pub",
+ "other": [42]
+ }
+ ''';
+ var config = parsePackageConfigBytes(
+ // ignore: unnecessary_cast
+ utf8.encode(packageConfigFile) as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'),
+ throwError);
+ expect(config.version, 2);
+ expect({for (var p in config.packages) p.name},
+ {'foo', 'bar', 'baz', 'noslash'});
+
+ expect(config.resolve(pkg('foo', 'foo.dart')),
+ Uri.parse('file:///foo/lib/foo.dart'));
+ expect(config.resolve(pkg('bar', 'bar.dart')),
+ Uri.parse('file:///bar/lib/bar.dart'));
+ expect(config.resolve(pkg('baz', 'baz.dart')),
+ Uri.parse('file:///tmp/lib/baz.dart'));
+
+ var foo = config['foo']!;
+ expect(foo, isNotNull);
+ expect(foo.root, Uri.parse('file:///foo/'));
+ expect(foo.packageUriRoot, Uri.parse('file:///foo/lib/'));
+ expect(foo.languageVersion, LanguageVersion(2, 5));
+ expect(foo.extraData, {'nonstandard': true});
+ expect(foo.relativeRoot, false);
+
+ var bar = config['bar']!;
+ expect(bar, isNotNull);
+ expect(bar.root, Uri.parse('file:///bar/'));
+ expect(bar.packageUriRoot, Uri.parse('file:///bar/lib/'));
+ expect(bar.languageVersion, LanguageVersion(9999, 9999));
+ expect(bar.extraData, null);
+ expect(bar.relativeRoot, false);
+
+ var baz = config['baz']!;
+ expect(baz, isNotNull);
+ expect(baz.root, Uri.parse('file:///tmp/'));
+ expect(baz.packageUriRoot, Uri.parse('file:///tmp/lib/'));
+ expect(baz.languageVersion, null);
+ expect(baz.relativeRoot, true);
+
+ // No slash after root or package root. One is inserted.
+ var noslash = config['noslash']!;
+ expect(noslash, isNotNull);
+ expect(noslash.root, Uri.parse('file:///tmp/noslash/'));
+ expect(noslash.packageUriRoot, Uri.parse('file:///tmp/noslash/lib/'));
+ expect(noslash.languageVersion, null);
+ expect(noslash.relativeRoot, true);
+
+ expect(config.extraData, {
+ 'generator': 'pub',
+ 'other': [42]
+ });
+ });
+
+ test('valid other order', () {
+ // The ordering in the file is not important.
+ var packageConfigFile = '''
+ {
+ "generator": "pub",
+ "other": [42],
+ "packages": [
+ {
+ "languageVersion": "2.5",
+ "packageUri": "lib/",
+ "rootUri": "file:///foo/",
+ "name": "foo"
+ },
+ {
+ "packageUri": "lib/",
+ "languageVersion": "9999.9999",
+ "rootUri": "/bar/",
+ "name": "bar"
+ },
+ {
+ "packageUri": "lib/",
+ "name": "baz",
+ "rootUri": "../"
+ }
+ ],
+ "configVersion": 2
+ }
+ ''';
+ var config = parsePackageConfigBytes(
+ // ignore: unnecessary_cast
+ utf8.encode(packageConfigFile) as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'),
+ throwError);
+ expect(config.version, 2);
+ expect({for (var p in config.packages) p.name}, {'foo', 'bar', 'baz'});
+
+ expect(config.resolve(pkg('foo', 'foo.dart')),
+ Uri.parse('file:///foo/lib/foo.dart'));
+ expect(config.resolve(pkg('bar', 'bar.dart')),
+ Uri.parse('file:///bar/lib/bar.dart'));
+ expect(config.resolve(pkg('baz', 'baz.dart')),
+ Uri.parse('file:///tmp/lib/baz.dart'));
+ expect(config.extraData, {
+ 'generator': 'pub',
+ 'other': [42]
+ });
+ });
+
+ // Check that a few minimal configurations are valid.
+ // These form the basis of invalid tests below.
+ var cfg = '"configVersion":2';
+ var pkgs = '"packages":[]';
+ var name = '"name":"foo"';
+ var root = '"rootUri":"/foo/"';
+ test('minimal', () {
+ var config = parsePackageConfigBytes(
+ // ignore: unnecessary_cast
+ utf8.encode('{$cfg,$pkgs}') as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'),
+ throwError);
+ expect(config.version, 2);
+ expect(config.packages, isEmpty);
+ });
+ test('minimal package', () {
+ // A package must have a name and a rootUri, the remaining properties
+ // are optional.
+ var config = parsePackageConfigBytes(
+ // ignore: unnecessary_cast
+ utf8.encode('{$cfg,"packages":[{$name,$root}]}') as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'),
+ throwError);
+ expect(config.version, 2);
+ expect(config.packages.first.name, 'foo');
+ });
+
+ test('nested packages', () {
+ var configBytes = utf8.encode(json.encode({
+ 'configVersion': 2,
+ 'packages': [
+ {'name': 'foo', 'rootUri': '/foo/', 'packageUri': 'lib/'},
+ {'name': 'bar', 'rootUri': '/foo/bar/', 'packageUri': 'lib/'},
+ {'name': 'baz', 'rootUri': '/foo/bar/baz/', 'packageUri': 'lib/'},
+ {'name': 'qux', 'rootUri': '/foo/qux/', 'packageUri': 'lib/'},
+ ]
+ }));
+ // ignore: unnecessary_cast
+ var config = parsePackageConfigBytes(configBytes as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError);
+ expect(config.version, 2);
+ expect(config.packageOf(Uri.parse('file:///foo/lala/lala.dart'))!.name,
+ 'foo');
+ expect(config.packageOf(Uri.parse('file:///foo/bar/lala.dart'))!.name,
+ 'bar');
+ expect(config.packageOf(Uri.parse('file:///foo/bar/baz/lala.dart'))!.name,
+ 'baz');
+ expect(config.packageOf(Uri.parse('file:///foo/qux/lala.dart'))!.name,
+ 'qux');
+ expect(config.toPackageUri(Uri.parse('file:///foo/lib/diz')),
+ Uri.parse('package:foo/diz'));
+ expect(config.toPackageUri(Uri.parse('file:///foo/bar/lib/diz')),
+ Uri.parse('package:bar/diz'));
+ expect(config.toPackageUri(Uri.parse('file:///foo/bar/baz/lib/diz')),
+ Uri.parse('package:baz/diz'));
+ expect(config.toPackageUri(Uri.parse('file:///foo/qux/lib/diz')),
+ Uri.parse('package:qux/diz'));
+ });
+
+ test('nested packages 2', () {
+ var configBytes = utf8.encode(json.encode({
+ 'configVersion': 2,
+ 'packages': [
+ {'name': 'foo', 'rootUri': '/', 'packageUri': 'lib/'},
+ {'name': 'bar', 'rootUri': '/bar/', 'packageUri': 'lib/'},
+ {'name': 'baz', 'rootUri': '/bar/baz/', 'packageUri': 'lib/'},
+ {'name': 'qux', 'rootUri': '/qux/', 'packageUri': 'lib/'},
+ ]
+ }));
+ // ignore: unnecessary_cast
+ var config = parsePackageConfigBytes(configBytes as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError);
+ expect(config.version, 2);
+ expect(
+ config.packageOf(Uri.parse('file:///lala/lala.dart'))!.name, 'foo');
+ expect(config.packageOf(Uri.parse('file:///bar/lala.dart'))!.name, 'bar');
+ expect(config.packageOf(Uri.parse('file:///bar/baz/lala.dart'))!.name,
+ 'baz');
+ expect(config.packageOf(Uri.parse('file:///qux/lala.dart'))!.name, 'qux');
+ expect(config.toPackageUri(Uri.parse('file:///lib/diz')),
+ Uri.parse('package:foo/diz'));
+ expect(config.toPackageUri(Uri.parse('file:///bar/lib/diz')),
+ Uri.parse('package:bar/diz'));
+ expect(config.toPackageUri(Uri.parse('file:///bar/baz/lib/diz')),
+ Uri.parse('package:baz/diz'));
+ expect(config.toPackageUri(Uri.parse('file:///qux/lib/diz')),
+ Uri.parse('package:qux/diz'));
+ });
+
+ test('packageOf is case sensitive on windows', () {
+ var configBytes = utf8.encode(json.encode({
+ 'configVersion': 2,
+ 'packages': [
+ {'name': 'foo', 'rootUri': 'file:///C:/Foo/', 'packageUri': 'lib/'},
+ ]
+ }));
+ var config = parsePackageConfigBytes(
+ // ignore: unnecessary_cast
+ configBytes as Uint8List,
+ Uri.parse('file:///C:/tmp/.dart_tool/file.dart'),
+ throwError);
+ expect(config.version, 2);
+ expect(
+ config.packageOf(Uri.parse('file:///C:/foo/lala/lala.dart')), null);
+ expect(config.packageOf(Uri.parse('file:///C:/Foo/lala/lala.dart'))!.name,
+ 'foo');
+ });
+
+ group('invalid', () {
+ void testThrows(String name, String source) {
+ test(name, () {
+ expect(
+ // ignore: unnecessary_cast
+ () => parsePackageConfigBytes(utf8.encode(source) as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'), throwError),
+ throwsA(isA<FormatException>()));
+ });
+ }
+
+ void testThrowsContains(
+ String name, String source, String containsString) {
+ test(name, () {
+ dynamic exception;
+ try {
+ parsePackageConfigBytes(
+ // ignore: unnecessary_cast
+ utf8.encode(source) as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'),
+ throwError,
+ );
+ } catch (e) {
+ exception = e;
+ }
+ if (exception == null) fail("Didn't get exception");
+ expect('$exception', contains(containsString));
+ });
+ }
+
+ testThrows('comment', '# comment\n {$cfg,$pkgs}');
+ testThrows('.packages file', 'foo:/foo\n');
+ testThrows('no configVersion', '{$pkgs}');
+ testThrows('no packages', '{$cfg}');
+ group('config version:', () {
+ testThrows('null', '{"configVersion":null,$pkgs}');
+ testThrows('string', '{"configVersion":"2",$pkgs}');
+ testThrows('array', '{"configVersion":[2],$pkgs}');
+ });
+ group('packages:', () {
+ testThrows('null', '{$cfg,"packages":null}');
+ testThrows('string', '{$cfg,"packages":"foo"}');
+ testThrows('object', '{$cfg,"packages":{}}');
+ });
+ group('packages entry:', () {
+ testThrows('null', '{$cfg,"packages":[null]}');
+ testThrows('string', '{$cfg,"packages":["foo"]}');
+ testThrows('array', '{$cfg,"packages":[[]]}');
+ });
+ group('package', () {
+ testThrows('no name', '{$cfg,"packages":[{$root}]}');
+ group('name:', () {
+ testThrows('null', '{$cfg,"packages":[{"name":null,$root}]}');
+ testThrows('num', '{$cfg,"packages":[{"name":1,$root}]}');
+ testThrows('object', '{$cfg,"packages":[{"name":{},$root}]}');
+ testThrows('empty', '{$cfg,"packages":[{"name":"",$root}]}');
+ testThrows('one-dot', '{$cfg,"packages":[{"name":".",$root}]}');
+ testThrows('two-dot', '{$cfg,"packages":[{"name":"..",$root}]}');
+ testThrows(
+ "invalid char '\\'", '{$cfg,"packages":[{"name":"\\",$root}]}');
+ testThrows(
+ "invalid char ':'", '{$cfg,"packages":[{"name":":",$root}]}');
+ testThrows(
+ "invalid char ' '", '{$cfg,"packages":[{"name":" ",$root}]}');
+ });
+
+ testThrows('no root', '{$cfg,"packages":[{$name}]}');
+ group('root:', () {
+ testThrows('null', '{$cfg,"packages":[{$name,"rootUri":null}]}');
+ testThrows('num', '{$cfg,"packages":[{$name,"rootUri":1}]}');
+ testThrows('object', '{$cfg,"packages":[{$name,"rootUri":{}}]}');
+ testThrows('fragment', '{$cfg,"packages":[{$name,"rootUri":"x/#"}]}');
+ testThrows('query', '{$cfg,"packages":[{$name,"rootUri":"x/?"}]}');
+ testThrows('package-URI',
+ '{$cfg,"packages":[{$name,"rootUri":"package:x/x/"}]}');
+ });
+ group('package-URI root:', () {
+ testThrows(
+ 'null', '{$cfg,"packages":[{$name,$root,"packageUri":null}]}');
+ testThrows('num', '{$cfg,"packages":[{$name,$root,"packageUri":1}]}');
+ testThrows(
+ 'object', '{$cfg,"packages":[{$name,$root,"packageUri":{}}]}');
+ testThrows('fragment',
+ '{$cfg,"packages":[{$name,$root,"packageUri":"x/#"}]}');
+ testThrows(
+ 'query', '{$cfg,"packages":[{$name,$root,"packageUri":"x/?"}]}');
+ testThrows('package: URI',
+ '{$cfg,"packages":[{$name,$root,"packageUri":"package:x/x/"}]}');
+ testThrows('not inside root',
+ '{$cfg,"packages":[{$name,$root,"packageUri":"../other/"}]}');
+ });
+ group('language version', () {
+ testThrows('null',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":null}]}');
+ testThrows(
+ 'num', '{$cfg,"packages":[{$name,$root,"languageVersion":1}]}');
+ testThrows('object',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":{}}]}');
+ testThrows('empty',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":""}]}');
+ testThrows('non number.number',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"x.1"}]}');
+ testThrows('number.non number',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"1.x"}]}');
+ testThrows('non number',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"x"}]}');
+ testThrows('one number',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"1"}]}');
+ testThrows('three numbers',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"1.2.3"}]}');
+ testThrows('leading zero first',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"01.1"}]}');
+ testThrows('leading zero second',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"1.01"}]}');
+ testThrows('trailing-',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"1.1-1"}]}');
+ testThrows('trailing+',
+ '{$cfg,"packages":[{$name,$root,"languageVersion":"1.1+1"}]}');
+ });
+ });
+ testThrows('duplicate package name',
+ '{$cfg,"packages":[{$name,$root},{$name,"rootUri":"/other/"}]}');
+ testThrowsContains(
+ // The roots of foo and bar are the same.
+ 'same roots',
+ '{$cfg,"packages":[{$name,$root},{"name":"bar",$root}]}',
+ 'the same root directory');
+ testThrowsContains(
+ // The roots of foo and bar are the same.
+ 'same roots 2',
+ '{$cfg,"packages":[{$name,"rootUri":"/"},{"name":"bar","rootUri":"/"}]}',
+ 'the same root directory');
+ testThrowsContains(
+ // The root of bar is inside the root of foo,
+ // but the package root of foo is inside the root of bar.
+ 'between root and lib',
+ '{$cfg,"packages":['
+ '{"name":"foo","rootUri":"/foo/","packageUri":"bar/lib/"},'
+ '{"name":"bar","rootUri":"/foo/bar/","packageUri":"baz/lib"}]}',
+ 'package root of foo is inside the root of bar');
+
+ // This shouldn't be allowed, but for internal reasons it is.
+ test('package inside package root', () {
+ var config = parsePackageConfigBytes(
+ // ignore: unnecessary_cast
+ utf8.encode(
+ '{$cfg,"packages":['
+ '{"name":"foo","rootUri":"/foo/","packageUri":"lib/"},'
+ '{"name":"bar","rootUri":"/foo/lib/bar/","packageUri":"lib"}]}',
+ ) as Uint8List,
+ Uri.parse('file:///tmp/.dart_tool/file.dart'),
+ throwError);
+ expect(
+ config
+ .packageOf(Uri.parse('file:///foo/lib/bar/lib/lala.dart'))!
+ .name,
+ 'foo'); // why not bar?
+ expect(config.toPackageUri(Uri.parse('file:///foo/lib/bar/lib/diz')),
+ Uri.parse('package:foo/bar/lib/diz')); // why not package:bar/diz?
+ });
+ });
+ });
+
+ group('factories', () {
+ void testConfig(String name, PackageConfig config, PackageConfig expected) {
+ group(name, () {
+ test('structure', () {
+ expect(config.version, expected.version);
+ var expectedPackages = {for (var p in expected.packages) p.name};
+ var actualPackages = {for (var p in config.packages) p.name};
+ expect(actualPackages, expectedPackages);
+ });
+ for (var package in config.packages) {
+ var name = package.name;
+ test('package $name', () {
+ var expectedPackage = expected[name]!;
+ expect(expectedPackage, isNotNull);
+ expect(package.root, expectedPackage.root, reason: 'root');
+ expect(package.packageUriRoot, expectedPackage.packageUriRoot,
+ reason: 'package root');
+ expect(package.languageVersion, expectedPackage.languageVersion,
+ reason: 'languageVersion');
+ });
+ }
+ });
+ }
+
+ var configText = '''
+ {"configVersion": 2, "packages": [
+ {
+ "name": "foo",
+ "rootUri": "foo/",
+ "packageUri": "bar/",
+ "languageVersion": "1.2"
+ }
+ ]}
+ ''';
+ var baseUri = Uri.parse('file:///start/');
+ var config = PackageConfig([
+ Package('foo', Uri.parse('file:///start/foo/'),
+ packageUriRoot: Uri.parse('file:///start/foo/bar/'),
+ languageVersion: LanguageVersion(1, 2))
+ ]);
+ testConfig(
+ 'string', PackageConfig.parseString(configText, baseUri), config);
+ testConfig(
+ 'bytes',
+ PackageConfig.parseBytes(
+ Uint8List.fromList(configText.codeUnits), baseUri),
+ config);
+ testConfig('json', PackageConfig.parseJson(jsonDecode(configText), baseUri),
+ config);
+
+ baseUri = Uri.parse('file:///start2/');
+ config = PackageConfig([
+ Package('foo', Uri.parse('file:///start2/foo/'),
+ packageUriRoot: Uri.parse('file:///start2/foo/bar/'),
+ languageVersion: LanguageVersion(1, 2))
+ ]);
+ testConfig(
+ 'string2', PackageConfig.parseString(configText, baseUri), config);
+ testConfig(
+ 'bytes2',
+ PackageConfig.parseBytes(
+ Uint8List.fromList(configText.codeUnits), baseUri),
+ config);
+ testConfig('json2',
+ PackageConfig.parseJson(jsonDecode(configText), baseUri), config);
+ });
+}
diff --git a/pkgs/package_config/test/src/util.dart b/pkgs/package_config/test/src/util.dart
new file mode 100644
index 0000000..780ee80
--- /dev/null
+++ b/pkgs/package_config/test/src/util.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:test/test.dart';
+
+/// Creates a package: URI.
+Uri pkg(String packageName, String packagePath) {
+ var path =
+ "$packageName${packagePath.startsWith('/') ? "" : "/"}$packagePath";
+ return Uri(scheme: 'package', path: path);
+}
+
+// Remove if not used.
+String configFromPackages(List<List<String>> packages) => """
+{
+ "configVersion": 2,
+ "packages": [
+${packages.map((nu) => """
+ {
+ "name": "${nu[0]}",
+ "rootUri": "${nu[1]}"
+ }""").join(",\n")}
+ ]
+}
+""";
+
+/// Mimics a directory structure of [description] and runs [loaderTest].
+///
+/// Description is a map, each key is a file entry. If the value is a map,
+/// it's a subdirectory, otherwise it's a file and the value is the content
+/// as a string.
+void loaderTest(
+ String name,
+ Map<String, Object> description,
+ void Function(Uri root, Future<Uint8List?> Function(Uri) loader) loaderTest,
+) {
+ var root = Uri(scheme: 'test', path: '/');
+ Future<Uint8List?> loader(Uri uri) async {
+ var path = uri.path;
+ if (!uri.isScheme('test') || !path.startsWith('/')) return null;
+ var parts = path.split('/');
+ Object? value = description;
+ for (var i = 1; i < parts.length; i++) {
+ if (value is! Map<String, Object?>) return null;
+ value = value[parts[i]];
+ }
+ // ignore: unnecessary_cast
+ if (value is String) return utf8.encode(value) as Uint8List;
+ return null;
+ }
+
+ test(name, () => loaderTest(root, loader));
+}
diff --git a/pkgs/package_config/test/src/util_io.dart b/pkgs/package_config/test/src/util_io.dart
new file mode 100644
index 0000000..e032556
--- /dev/null
+++ b/pkgs/package_config/test/src/util_io.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:package_config/src/util_io.dart';
+import 'package:test/test.dart';
+
+/// Creates a directory structure from [description] and runs [fileTest].
+///
+/// Description is a map, each key is a file entry. If the value is a map,
+/// it's a subdirectory, otherwise it's a file and the value is the content
+/// as a string.
+/// Introduces a group to hold the [setUp]/[tearDown] logic.
+void fileTest(String name, Map<String, Object> description,
+ void Function(Directory directory) fileTest) {
+ group('file-test', () {
+ var tempDir = Directory.systemTemp.createTempSync('pkgcfgtest');
+ setUp(() {
+ _createFiles(tempDir, description);
+ });
+ tearDown(() {
+ tempDir.deleteSync(recursive: true);
+ });
+ test(name, () => fileTest(tempDir));
+ });
+}
+
+/// Creates a set of files under a new temporary directory.
+/// Returns the temporary directory.
+///
+/// The [description] is a map from file names to content.
+/// If the content is again a map, it represents a subdirectory
+/// with the content as description.
+/// Otherwise the content should be a string,
+/// which is written to the file as UTF-8.
+// Directory createTestFiles(Map<String, Object> description) {
+// var target = Directory.systemTemp.createTempSync("pkgcfgtest");
+// _createFiles(target, description);
+// return target;
+// }
+
+// Creates temporary files in the target directory.
+void _createFiles(Directory target, Map<Object?, Object?> description) {
+ description.forEach((name, content) {
+ var entryName = pathJoin(target.path, '$name');
+ if (content is Map<Object?, Object?>) {
+ _createFiles(Directory(entryName)..createSync(), content);
+ } else {
+ File(entryName).writeAsStringSync(content as String, flush: true);
+ }
+ });
+}
+
+/// Creates a [Directory] for a subdirectory of [parent].
+Directory subdir(Directory parent, String dirName) =>
+ Directory(pathJoinAll([parent.path, ...dirName.split('/')]));
+
+/// Creates a [File] for an entry in the [directory] directory.
+File dirFile(Directory directory, String fileName) =>
+ File(pathJoin(directory.path, fileName));
diff --git a/pkgs/pool/.gitignore b/pkgs/pool/.gitignore
new file mode 100644
index 0000000..e450c83
--- /dev/null
+++ b/pkgs/pool/.gitignore
@@ -0,0 +1,5 @@
+# Don’t commit the following directories created by pub.
+.dart_tool/
+.packages
+.pub/
+pubspec.lock
diff --git a/pkgs/pool/CHANGELOG.md b/pkgs/pool/CHANGELOG.md
new file mode 100644
index 0000000..56424fc
--- /dev/null
+++ b/pkgs/pool/CHANGELOG.md
@@ -0,0 +1,105 @@
+## 1.5.2-wip
+
+* Require Dart 3.4.
+* Move to `dart-lang/tools` monorepo.
+
+## 1.5.1
+
+* Populate the pubspec `repository` field.
+
+## 1.5.0
+
+* Stable release for null safety.
+
+## 1.5.0-nullsafety.3
+
+* Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release
+ guidelines.
+
+## 1.5.0-nullsafety.2
+
+* Allow prerelease versions of the 2.12 sdk.
+
+## 1.5.0-nullsafety.1
+
+* Allow 2.10 stable and 2.11.0 dev SDK versions.
+
+## 1.5.0-nullsafety
+
+* Migrate to null safety.
+* `forEach`: Avoid `await null` if the `Stream` is not paused.
+ Improves trivial benchmark by 40%.
+
+## 1.4.0
+
+* Add `forEach` to `Pool` to support efficient async processing of an
+ `Iterable`.
+
+* Throw ArgumentError if poolSize <= 0
+
+## 1.3.6
+
+* Set max SDK version to `<3.0.0`, and adjust other dependencies.
+
+## 1.3.5
+
+- Updated SDK version to 2.0.0-dev.17.0
+
+## 1.3.4
+
+* Modify code to eliminate Future flattening.
+
+## 1.3.3
+
+* Declare support for `async` 2.0.0.
+
+## 1.3.2
+
+* Update to make the code work with strong-mode clean Zone API.
+
+* Required minimum SDK of 1.23.0.
+
+## 1.3.1
+
+* Fix the type annotation of `Pool.withResource()` to indicate that it takes
+ `() -> FutureOr<T>`.
+
+## 1.3.0
+
+* Add a `Pool.done` getter that returns the same future returned by
+ `Pool.close()`.
+
+## 1.2.4
+
+* Fix a strong-mode error.
+
+## 1.2.3
+
+* Fix a bug in which `Pool.withResource()` could throw a `StateError` when
+ called immediately before closing the pool.
+
+## 1.2.2
+
+* Fix strong mode warnings and add generic method annotations.
+
+## 1.2.1
+
+* Internal changes only.
+
+## 1.2.0
+
+* Add `Pool.close()`, which forbids new resource requests and releases all
+ releasable resources.
+
+## 1.1.0
+
+* Add `PoolResource.allowRelease()`, which allows a resource to indicate that it
+ can be released without forcing it to deallocate immediately.
+
+## 1.0.2
+
+* Fixed the homepage.
+
+## 1.0.1
+
+* A `TimeoutException` is now correctly thrown if the pool detects a deadlock.
diff --git a/pkgs/pool/LICENSE b/pkgs/pool/LICENSE
new file mode 100644
index 0000000..000cd7b
--- /dev/null
+++ b/pkgs/pool/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/pool/README.md b/pkgs/pool/README.md
new file mode 100644
index 0000000..461e872
--- /dev/null
+++ b/pkgs/pool/README.md
@@ -0,0 +1,57 @@
+[](https://github.com/dart-lang/tools/actions/workflows/pool.yaml)
+[](https://pub.dev/packages/pool)
+[](https://pub.dev/packages/pool/publisher)
+
+The pool package exposes a `Pool` class which makes it easy to manage a limited
+pool of resources.
+
+The easiest way to use a pool is by calling `withResource`. This runs a callback
+and returns its result, but only once there aren't too many other callbacks
+currently running.
+
+```dart
+// Create a Pool that will only allocate 10 resources at once. After 30 seconds
+// of inactivity with all resources checked out, the pool will throw an error.
+final pool = new Pool(10, timeout: new Duration(seconds: 30));
+
+Future<String> readFile(String path) {
+ // Since the call to [File.readAsString] is within [withResource], no more
+ // than ten files will be open at once.
+ return pool.withResource(() => new File(path).readAsString());
+}
+```
+
+For more fine-grained control, the user can also explicitly request generic
+`PoolResource` objects that can later be released back into the pool. This is
+what `withResource` does under the covers: requests a resource, then releases it
+once the callback completes.
+
+`Pool` ensures that only a limited number of resources are allocated at once.
+It's the caller's responsibility to ensure that the corresponding physical
+resource is only consumed when a `PoolResource` is allocated.
+
+```dart
+class PooledFile implements RandomAccessFile {
+ final RandomAccessFile _file;
+ final PoolResource _resource;
+
+ static Future<PooledFile> open(String path) {
+ return pool.request().then((resource) {
+ return new File(path).open().then((file) {
+ return new PooledFile._(file, resource);
+ });
+ });
+ }
+
+ PooledFile(this._file, this._resource);
+
+ // ...
+
+ Future<RandomAccessFile> close() {
+ return _file.close.then((_) {
+ _resource.release();
+ return this;
+ });
+ }
+}
+```
diff --git a/pkgs/pool/analysis_options.yaml b/pkgs/pool/analysis_options.yaml
new file mode 100644
index 0000000..44cda4d
--- /dev/null
+++ b/pkgs/pool/analysis_options.yaml
@@ -0,0 +1,5 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
diff --git a/pkgs/pool/benchmark/for_each_benchmark.dart b/pkgs/pool/benchmark/for_each_benchmark.dart
new file mode 100644
index 0000000..0cd2543
--- /dev/null
+++ b/pkgs/pool/benchmark/for_each_benchmark.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:pool/pool.dart';
+
+void main(List<String> args) async {
+ var poolSize = args.isEmpty ? 5 : int.parse(args.first);
+ print('Pool size: $poolSize');
+
+ final pool = Pool(poolSize);
+ final watch = Stopwatch()..start();
+ final start = DateTime.now();
+
+ DateTime? lastLog;
+ Duration? fastest;
+ late int fastestIteration;
+ var i = 1;
+
+ void log(bool force) {
+ var now = DateTime.now();
+ if (force ||
+ lastLog == null ||
+ now.difference(lastLog!) > const Duration(seconds: 1)) {
+ lastLog = now;
+ print([
+ now.difference(start),
+ i.toString().padLeft(10),
+ fastestIteration.toString().padLeft(7),
+ fastest!.inMicroseconds.toString().padLeft(9)
+ ].join(' '));
+ }
+ }
+
+ print(['Elapsed ', 'Iterations', 'Fastest', 'Time (us)'].join(' '));
+
+ for (;; i++) {
+ watch.reset();
+
+ var sum = await pool
+ .forEach<int, int>(Iterable<int>.generate(100000), (i) => i)
+ .reduce((a, b) => a + b);
+
+ assert(sum == 4999950000, 'was $sum');
+
+ var elapsed = watch.elapsed;
+ if (fastest == null || fastest > elapsed) {
+ fastest = elapsed;
+ fastestIteration = i;
+ log(true);
+ } else {
+ log(false);
+ }
+ }
+}
diff --git a/pkgs/pool/lib/pool.dart b/pkgs/pool/lib/pool.dart
new file mode 100644
index 0000000..70e9df1
--- /dev/null
+++ b/pkgs/pool/lib/pool.dart
@@ -0,0 +1,380 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'package:async/async.dart';
+import 'package:stack_trace/stack_trace.dart';
+
+/// Manages an abstract pool of resources with a limit on how many may be in use
+/// at once.
+///
+/// When a resource is needed, the user should call [request]. When the returned
+/// future completes with a [PoolResource], the resource may be allocated. Once
+/// the resource has been released, the user should call [PoolResource.release].
+/// The pool will ensure that only a certain number of [PoolResource]s may be
+/// allocated at once.
+class Pool {
+ /// Completers for requests beyond the first [_maxAllocatedResources].
+ ///
+ /// When an item is released, the next element of [_requestedResources] will
+ /// be completed.
+ final _requestedResources = Queue<Completer<PoolResource>>();
+
+ /// Callbacks that must be called before additional resources can be
+ /// allocated.
+ ///
+ /// See [PoolResource.allowRelease].
+ final _onReleaseCallbacks = Queue<void Function()>();
+
+ /// Completers that will be completed once `onRelease` callbacks are done
+ /// running.
+ ///
+ /// These are kept in a queue to ensure that the earliest request completes
+ /// first regardless of what order the `onRelease` callbacks complete in.
+ final _onReleaseCompleters = Queue<Completer<PoolResource>>();
+
+ /// The maximum number of resources that may be allocated at once.
+ final int _maxAllocatedResources;
+
+ /// The number of resources that are currently allocated.
+ int _allocatedResources = 0;
+
+ /// The timeout timer.
+ ///
+ /// This timer is canceled as long as the pool is below the resource limit.
+ /// It's reset once the resource limit is reached and again every time an
+ /// resource is released or a new resource is requested. If it fires, that
+ /// indicates that the caller became deadlocked, likely due to files waiting
+ /// for additional files to be read before they could be closed.
+ ///
+ /// This is `null` if this pool shouldn't time out.
+ RestartableTimer? _timer;
+
+ /// The amount of time to wait before timing out the pending resources.
+ final Duration? _timeout;
+
+ /// A [FutureGroup] that tracks all the `onRelease` callbacks for resources
+ /// that have been marked releasable.
+ ///
+ /// This is `null` until [close] is called.
+ FutureGroup? _closeGroup;
+
+ /// Whether [close] has been called.
+ bool get isClosed => _closeMemo.hasRun;
+
+ /// A future that completes once the pool is closed and all its outstanding
+ /// resources have been released.
+ ///
+ /// If any [PoolResource.allowRelease] callback throws an exception after the
+ /// pool is closed, this completes with that exception.
+ Future get done => _closeMemo.future;
+
+ /// Creates a new pool with the given limit on how many resources may be
+ /// allocated at once.
+ ///
+ /// If [timeout] is passed, then if that much time passes without any activity
+ /// all pending [request] futures will throw a [TimeoutException]. This is
+ /// intended to avoid deadlocks.
+ Pool(this._maxAllocatedResources, {Duration? timeout}) : _timeout = timeout {
+ if (_maxAllocatedResources <= 0) {
+ throw ArgumentError.value(_maxAllocatedResources, 'maxAllocatedResources',
+ 'Must be greater than zero.');
+ }
+
+ if (timeout != null) {
+ // Start the timer canceled since we only want to start counting down once
+ // we've run out of available resources.
+ _timer = RestartableTimer(timeout, _onTimeout)..cancel();
+ }
+ }
+
+ /// Request a [PoolResource].
+ ///
+ /// If the maximum number of resources is already allocated, this will delay
+ /// until one of them is released.
+ Future<PoolResource> request() {
+ if (isClosed) {
+ throw StateError('request() may not be called on a closed Pool.');
+ }
+
+ if (_allocatedResources < _maxAllocatedResources) {
+ _allocatedResources++;
+ return Future.value(PoolResource._(this));
+ } else if (_onReleaseCallbacks.isNotEmpty) {
+ return _runOnRelease(_onReleaseCallbacks.removeFirst());
+ } else {
+ var completer = Completer<PoolResource>();
+ _requestedResources.add(completer);
+ _resetTimer();
+ return completer.future;
+ }
+ }
+
+ /// Requests a resource for the duration of [callback], which may return a
+ /// Future.
+ ///
+ /// The return value of [callback] is piped to the returned Future.
+ Future<T> withResource<T>(FutureOr<T> Function() callback) async {
+ if (isClosed) {
+ throw StateError('withResource() may not be called on a closed Pool.');
+ }
+
+ var resource = await request();
+ try {
+ return await callback();
+ } finally {
+ resource.release();
+ }
+ }
+
+ /// Returns a [Stream] containing the result of [action] applied to each
+ /// element of [elements].
+ ///
+ /// While [action] is invoked on each element of [elements] in order,
+ /// it's possible the return [Stream] may have items out-of-order – especially
+ /// if the completion time of [action] varies.
+ ///
+ /// If [action] throws an error the source item along with the error object
+ /// and [StackTrace] are passed to [onError], if it is provided. If [onError]
+ /// returns `true`, the error is added to the returned [Stream], otherwise
+ /// it is ignored.
+ ///
+ /// Errors thrown from iterating [elements] will not be passed to
+ /// [onError]. They will always be added to the returned stream as an error.
+ ///
+ /// Note: all of the resources of the this [Pool] will be used when the
+ /// returned [Stream] is listened to until it is completed or canceled.
+ ///
+ /// Note: if this [Pool] is closed before the returned [Stream] is listened
+ /// to, a [StateError] is thrown.
+ Stream<T> forEach<S, T>(
+ Iterable<S> elements, FutureOr<T> Function(S source) action,
+ {bool Function(S item, Object error, StackTrace stack)? onError}) {
+ onError ??= (item, e, s) => true;
+
+ var cancelPending = false;
+
+ Completer? resumeCompleter;
+ late StreamController<T> controller;
+
+ late Iterator<S> iterator;
+
+ Future<void> run(int _) async {
+ while (iterator.moveNext()) {
+ // caching `current` is necessary because there are async breaks
+ // in this code and `iterator` is shared across many workers
+ final current = iterator.current;
+
+ _resetTimer();
+
+ if (resumeCompleter != null) {
+ await resumeCompleter!.future;
+ }
+
+ if (cancelPending) {
+ break;
+ }
+
+ T value;
+ try {
+ value = await action(current);
+ } catch (e, stack) {
+ if (onError!(current, e, stack)) {
+ controller.addError(e, stack);
+ }
+ continue;
+ }
+ controller.add(value);
+ }
+ }
+
+ Future<void>? doneFuture;
+
+ void onListen() {
+ iterator = elements.iterator;
+
+ assert(doneFuture == null);
+ var futures = Iterable<Future<void>>.generate(
+ _maxAllocatedResources, (i) => withResource(() => run(i)));
+ doneFuture = Future.wait(futures, eagerError: true)
+ .then<void>((_) {})
+ .catchError(controller.addError);
+
+ doneFuture!.whenComplete(controller.close);
+ }
+
+ controller = StreamController<T>(
+ sync: true,
+ onListen: onListen,
+ onCancel: () async {
+ assert(!cancelPending);
+ cancelPending = true;
+ await doneFuture;
+ },
+ onPause: () {
+ assert(resumeCompleter == null);
+ resumeCompleter = Completer<void>();
+ },
+ onResume: () {
+ assert(resumeCompleter != null);
+ resumeCompleter!.complete();
+ resumeCompleter = null;
+ },
+ );
+
+ return controller.stream;
+ }
+
+ /// Closes the pool so that no more resources are requested.
+ ///
+ /// Existing resource requests remain unchanged.
+ ///
+ /// Any resources that are marked as releasable using
+ /// [PoolResource.allowRelease] are released immediately. Once all resources
+ /// have been released and any `onRelease` callbacks have completed, the
+ /// returned future completes successfully. If any `onRelease` callback throws
+ /// an error, the returned future completes with that error.
+ ///
+ /// This may be called more than once; it returns the same [Future] each time.
+ Future close() => _closeMemo.runOnce(_close);
+
+ Future<void> _close() {
+ if (_closeGroup != null) return _closeGroup!.future;
+
+ _resetTimer();
+
+ _closeGroup = FutureGroup();
+ for (var callback in _onReleaseCallbacks) {
+ _closeGroup!.add(Future.sync(callback));
+ }
+
+ _allocatedResources -= _onReleaseCallbacks.length;
+ _onReleaseCallbacks.clear();
+
+ if (_allocatedResources == 0) _closeGroup!.close();
+ return _closeGroup!.future;
+ }
+
+ final _closeMemo = AsyncMemoizer<void>();
+
+ /// If there are any pending requests, this will fire the oldest one.
+ void _onResourceReleased() {
+ _resetTimer();
+
+ if (_requestedResources.isNotEmpty) {
+ var pending = _requestedResources.removeFirst();
+ pending.complete(PoolResource._(this));
+ } else {
+ _allocatedResources--;
+ if (isClosed && _allocatedResources == 0) _closeGroup!.close();
+ }
+ }
+
+ /// If there are any pending requests, this will fire the oldest one after
+ /// running [onRelease].
+ void _onResourceReleaseAllowed(void Function() onRelease) {
+ _resetTimer();
+
+ if (_requestedResources.isNotEmpty) {
+ var pending = _requestedResources.removeFirst();
+ pending.complete(_runOnRelease(onRelease));
+ } else if (isClosed) {
+ _closeGroup!.add(Future.sync(onRelease));
+ _allocatedResources--;
+ if (_allocatedResources == 0) _closeGroup!.close();
+ } else {
+ var zone = Zone.current;
+ var registered = zone.registerCallback(onRelease);
+ _onReleaseCallbacks.add(() => zone.run(registered));
+ }
+ }
+
+ /// Runs [onRelease] and returns a Future that completes to a resource once an
+ /// [onRelease] callback completes.
+ ///
+ /// Futures returned by [_runOnRelease] always complete in the order they were
+ /// created, even if earlier [onRelease] callbacks take longer to run.
+ Future<PoolResource> _runOnRelease(void Function() onRelease) {
+ Future.sync(onRelease).then((value) {
+ _onReleaseCompleters.removeFirst().complete(PoolResource._(this));
+ }).catchError((Object error, StackTrace stackTrace) {
+ _onReleaseCompleters.removeFirst().completeError(error, stackTrace);
+ });
+
+ var completer = Completer<PoolResource>.sync();
+ _onReleaseCompleters.add(completer);
+ return completer.future;
+ }
+
+ /// A resource has been requested, allocated, or released.
+ void _resetTimer() {
+ if (_timer == null) return;
+
+ if (_requestedResources.isEmpty) {
+ _timer!.cancel();
+ } else {
+ _timer!.reset();
+ }
+ }
+
+ /// Handles [_timer] timing out by causing all pending resource completers to
+ /// emit exceptions.
+ void _onTimeout() {
+ for (var completer in _requestedResources) {
+ completer.completeError(
+ TimeoutException(
+ 'Pool deadlock: all resources have been '
+ 'allocated for too long.',
+ _timeout),
+ Chain.current());
+ }
+ _requestedResources.clear();
+ _timer = null;
+ }
+}
+
+/// A member of a [Pool].
+///
+/// A [PoolResource] is a token that indicates that a resource is allocated.
+/// When the associated resource is released, the user should call [release].
+class PoolResource {
+ final Pool _pool;
+
+ /// Whether `this` has been released yet.
+ bool _released = false;
+
+ PoolResource._(this._pool);
+
+ /// Tells the parent [Pool] that the resource associated with this resource is
+ /// no longer allocated, and that a new [PoolResource] may be allocated.
+ void release() {
+ if (_released) {
+ throw StateError('A PoolResource may only be released once.');
+ }
+ _released = true;
+ _pool._onResourceReleased();
+ }
+
+ /// Tells the parent [Pool] that the resource associated with this resource is
+ /// no longer necessary, but should remain allocated until more resources are
+ /// needed.
+ ///
+ /// When [Pool.request] is called and there are no remaining available
+ /// resources, the [onRelease] callback is called. It should free the
+ /// resource, and it may return a Future or `null`. Once that completes, the
+ /// [Pool.request] call will complete to a new [PoolResource].
+ ///
+ /// This is useful when a resource's main function is complete, but it may
+ /// produce additional information later on. For example, an isolate's task
+ /// may be complete, but it could still emit asynchronous errors.
+ void allowRelease(FutureOr<void> Function() onRelease) {
+ if (_released) {
+ throw StateError('A PoolResource may only be released once.');
+ }
+ _released = true;
+ _pool._onResourceReleaseAllowed(onRelease);
+ }
+}
diff --git a/pkgs/pool/pubspec.yaml b/pkgs/pool/pubspec.yaml
new file mode 100644
index 0000000..a205b74
--- /dev/null
+++ b/pkgs/pool/pubspec.yaml
@@ -0,0 +1,18 @@
+name: pool
+version: 1.5.2-wip
+description: >-
+ Manage a finite pool of resources.
+ Useful for controlling concurrent file system or network requests.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/pool
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ async: ^2.5.0
+ stack_trace: ^1.10.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ fake_async: ^1.2.0
+ test: ^1.16.6
diff --git a/pkgs/pool/test/pool_test.dart b/pkgs/pool/test/pool_test.dart
new file mode 100644
index 0000000..6334a8a
--- /dev/null
+++ b/pkgs/pool/test/pool_test.dart
@@ -0,0 +1,745 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:fake_async/fake_async.dart';
+import 'package:pool/pool.dart';
+import 'package:stack_trace/stack_trace.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('request()', () {
+ test('resources can be requested freely up to the limit', () {
+ var pool = Pool(50);
+ for (var i = 0; i < 50; i++) {
+ expect(pool.request(), completes);
+ }
+ });
+
+ test('resources block past the limit', () {
+ FakeAsync().run((async) {
+ var pool = Pool(50);
+ for (var i = 0; i < 50; i++) {
+ expect(pool.request(), completes);
+ }
+ expect(pool.request(), doesNotComplete);
+
+ async.elapse(const Duration(seconds: 1));
+ });
+ });
+
+ test('a blocked resource is allocated when another is released', () {
+ FakeAsync().run((async) {
+ var pool = Pool(50);
+ for (var i = 0; i < 49; i++) {
+ expect(pool.request(), completes);
+ }
+
+ pool.request().then((lastAllocatedResource) {
+ // This will only complete once [lastAllocatedResource] is released.
+ expect(pool.request(), completes);
+
+ Future<void>.delayed(const Duration(microseconds: 1)).then((_) {
+ lastAllocatedResource.release();
+ });
+ });
+
+ async.elapse(const Duration(seconds: 1));
+ });
+ });
+ });
+
+ group('withResource()', () {
+ test('can be called freely up to the limit', () {
+ var pool = Pool(50);
+ for (var i = 0; i < 50; i++) {
+ pool.withResource(expectAsync0(() => Completer<void>().future));
+ }
+ });
+
+ test('blocks the callback past the limit', () {
+ FakeAsync().run((async) {
+ var pool = Pool(50);
+ for (var i = 0; i < 50; i++) {
+ pool.withResource(expectAsync0(() => Completer<void>().future));
+ }
+ pool.withResource(expectNoAsync());
+
+ async.elapse(const Duration(seconds: 1));
+ });
+ });
+
+ test('a blocked resource is allocated when another is released', () {
+ FakeAsync().run((async) {
+ var pool = Pool(50);
+ for (var i = 0; i < 49; i++) {
+ pool.withResource(expectAsync0(() => Completer<void>().future));
+ }
+
+ var completer = Completer<void>();
+ pool.withResource(() => completer.future);
+ var blockedResourceAllocated = false;
+ pool.withResource(() {
+ blockedResourceAllocated = true;
+ });
+
+ Future<void>.delayed(const Duration(microseconds: 1)).then((_) {
+ expect(blockedResourceAllocated, isFalse);
+ completer.complete();
+ return Future<void>.delayed(const Duration(microseconds: 1));
+ }).then((_) {
+ expect(blockedResourceAllocated, isTrue);
+ });
+
+ async.elapse(const Duration(seconds: 1));
+ });
+ });
+
+ // Regression test for #3.
+ test('can be called immediately before close()', () async {
+ var pool = Pool(1);
+ unawaited(pool.withResource(expectAsync0(() {})));
+ await pool.close();
+ });
+ });
+
+ group('with a timeout', () {
+ test("doesn't time out if there are no pending requests", () {
+ FakeAsync().run((async) {
+ var pool = Pool(50, timeout: const Duration(seconds: 5));
+ for (var i = 0; i < 50; i++) {
+ expect(pool.request(), completes);
+ }
+
+ async.elapse(const Duration(seconds: 6));
+ });
+ });
+
+ test('resets the timer if a resource is returned', () {
+ FakeAsync().run((async) {
+ var pool = Pool(50, timeout: const Duration(seconds: 5));
+ for (var i = 0; i < 49; i++) {
+ expect(pool.request(), completes);
+ }
+
+ pool.request().then((lastAllocatedResource) {
+ // This will only complete once [lastAllocatedResource] is released.
+ expect(pool.request(), completes);
+
+ Future<void>.delayed(const Duration(seconds: 3)).then((_) {
+ lastAllocatedResource.release();
+ expect(pool.request(), doesNotComplete);
+ });
+ });
+
+ async.elapse(const Duration(seconds: 6));
+ });
+ });
+
+ test('resets the timer if a resource is requested', () {
+ FakeAsync().run((async) {
+ var pool = Pool(50, timeout: const Duration(seconds: 5));
+ for (var i = 0; i < 50; i++) {
+ expect(pool.request(), completes);
+ }
+ expect(pool.request(), doesNotComplete);
+
+ Future<void>.delayed(const Duration(seconds: 3)).then((_) {
+ expect(pool.request(), doesNotComplete);
+ });
+
+ async.elapse(const Duration(seconds: 6));
+ });
+ });
+
+ test('times out if nothing happens', () {
+ FakeAsync().run((async) {
+ var pool = Pool(50, timeout: const Duration(seconds: 5));
+ for (var i = 0; i < 50; i++) {
+ expect(pool.request(), completes);
+ }
+ expect(pool.request(), throwsA(const TypeMatcher<TimeoutException>()));
+
+ async.elapse(const Duration(seconds: 6));
+ });
+ });
+ });
+
+ group('allowRelease()', () {
+ test('runs the callback once the resource limit is exceeded', () async {
+ var pool = Pool(50);
+ for (var i = 0; i < 49; i++) {
+ expect(pool.request(), completes);
+ }
+
+ var resource = await pool.request();
+ var onReleaseCalled = false;
+ resource.allowRelease(() => onReleaseCalled = true);
+ await Future<void>.delayed(Duration.zero);
+ expect(onReleaseCalled, isFalse);
+
+ expect(pool.request(), completes);
+ await Future<void>.delayed(Duration.zero);
+ expect(onReleaseCalled, isTrue);
+ });
+
+ test('runs the callback immediately if there are blocked requests',
+ () async {
+ var pool = Pool(1);
+ var resource = await pool.request();
+
+ // This will be blocked until [resource.allowRelease] is called.
+ expect(pool.request(), completes);
+
+ var onReleaseCalled = false;
+ resource.allowRelease(() => onReleaseCalled = true);
+ await Future<void>.delayed(Duration.zero);
+ expect(onReleaseCalled, isTrue);
+ });
+
+ test('blocks the request until the callback completes', () async {
+ var pool = Pool(1);
+ var resource = await pool.request();
+
+ var requestComplete = false;
+ unawaited(pool.request().then((_) => requestComplete = true));
+
+ var completer = Completer<void>();
+ resource.allowRelease(() => completer.future);
+ await Future<void>.delayed(Duration.zero);
+ expect(requestComplete, isFalse);
+
+ completer.complete();
+ await Future<void>.delayed(Duration.zero);
+ expect(requestComplete, isTrue);
+ });
+
+ test('completes requests in request order regardless of callback order',
+ () async {
+ var pool = Pool(2);
+ var resource1 = await pool.request();
+ var resource2 = await pool.request();
+
+ var request1Complete = false;
+ unawaited(pool.request().then((_) => request1Complete = true));
+ var request2Complete = false;
+ unawaited(pool.request().then((_) => request2Complete = true));
+
+ var onRelease1Called = false;
+ var completer1 = Completer<void>();
+ resource1.allowRelease(() {
+ onRelease1Called = true;
+ return completer1.future;
+ });
+ await Future<void>.delayed(Duration.zero);
+ expect(onRelease1Called, isTrue);
+
+ var onRelease2Called = false;
+ var completer2 = Completer<void>();
+ resource2.allowRelease(() {
+ onRelease2Called = true;
+ return completer2.future;
+ });
+ await Future<void>.delayed(Duration.zero);
+ expect(onRelease2Called, isTrue);
+ expect(request1Complete, isFalse);
+ expect(request2Complete, isFalse);
+
+ // Complete the second resource's onRelease callback first. Even though it
+ // was triggered by the second blocking request, it should complete the
+ // first one to preserve ordering.
+ completer2.complete();
+ await Future<void>.delayed(Duration.zero);
+ expect(request1Complete, isTrue);
+ expect(request2Complete, isFalse);
+
+ completer1.complete();
+ await Future<void>.delayed(Duration.zero);
+ expect(request1Complete, isTrue);
+ expect(request2Complete, isTrue);
+ });
+
+ test('runs onRequest in the zone it was created', () async {
+ var pool = Pool(1);
+ var resource = await pool.request();
+
+ var outerZone = Zone.current;
+ runZoned(() {
+ var innerZone = Zone.current;
+ expect(innerZone, isNot(equals(outerZone)));
+
+ resource.allowRelease(expectAsync0(() {
+ expect(Zone.current, equals(innerZone));
+ }));
+ });
+
+ await pool.request();
+ });
+ });
+
+ test("done doesn't complete without close", () async {
+ var pool = Pool(1);
+ unawaited(pool.done.then(expectAsync1((_) {}, count: 0)));
+
+ var resource = await pool.request();
+ resource.release();
+
+ await Future<void>.delayed(Duration.zero);
+ });
+
+ group('close()', () {
+ test('disallows request() and withResource()', () {
+ var pool = Pool(1)..close();
+ expect(pool.request, throwsStateError);
+ expect(() => pool.withResource(() {}), throwsStateError);
+ });
+
+ test('pending requests are fulfilled', () async {
+ var pool = Pool(1);
+ var resource1 = await pool.request();
+ expect(
+ pool.request().then((resource2) {
+ resource2.release();
+ }),
+ completes);
+ expect(pool.done, completes);
+ expect(pool.close(), completes);
+ resource1.release();
+ });
+
+ test('pending requests are fulfilled with allowRelease', () async {
+ var pool = Pool(1);
+ var resource1 = await pool.request();
+
+ var completer = Completer<void>();
+ expect(
+ pool.request().then((resource2) {
+ expect(completer.isCompleted, isTrue);
+ resource2.release();
+ }),
+ completes);
+ expect(pool.close(), completes);
+
+ resource1.allowRelease(() => completer.future);
+ await Future<void>.delayed(Duration.zero);
+
+ completer.complete();
+ });
+
+ test("doesn't complete until all resources are released", () async {
+ var pool = Pool(2);
+ var resource1 = await pool.request();
+ var resource2 = await pool.request();
+ var resource3Future = pool.request();
+
+ var resource1Released = false;
+ var resource2Released = false;
+ var resource3Released = false;
+ expect(
+ pool.close().then((_) {
+ expect(resource1Released, isTrue);
+ expect(resource2Released, isTrue);
+ expect(resource3Released, isTrue);
+ }),
+ completes);
+
+ resource1Released = true;
+ resource1.release();
+ await Future<void>.delayed(Duration.zero);
+
+ resource2Released = true;
+ resource2.release();
+ await Future<void>.delayed(Duration.zero);
+
+ var resource3 = await resource3Future;
+ resource3Released = true;
+ resource3.release();
+ });
+
+ test('active onReleases complete as usual', () async {
+ var pool = Pool(1);
+ var resource = await pool.request();
+
+ // Set up an onRelease callback whose completion is controlled by
+ // [completer].
+ var completer = Completer<void>();
+ resource.allowRelease(() => completer.future);
+ expect(
+ pool.request().then((_) {
+ expect(completer.isCompleted, isTrue);
+ }),
+ completes);
+
+ await Future<void>.delayed(Duration.zero);
+ unawaited(pool.close());
+
+ await Future<void>.delayed(Duration.zero);
+ completer.complete();
+ });
+
+ test('inactive onReleases fire', () async {
+ var pool = Pool(2);
+ var resource1 = await pool.request();
+ var resource2 = await pool.request();
+
+ var completer1 = Completer<void>();
+ resource1.allowRelease(() => completer1.future);
+ var completer2 = Completer<void>();
+ resource2.allowRelease(() => completer2.future);
+
+ expect(
+ pool.close().then((_) {
+ expect(completer1.isCompleted, isTrue);
+ expect(completer2.isCompleted, isTrue);
+ }),
+ completes);
+
+ await Future<void>.delayed(Duration.zero);
+ completer1.complete();
+
+ await Future<void>.delayed(Duration.zero);
+ completer2.complete();
+ });
+
+ test('new allowReleases fire immediately', () async {
+ var pool = Pool(1);
+ var resource = await pool.request();
+
+ var completer = Completer<void>();
+ expect(
+ pool.close().then((_) {
+ expect(completer.isCompleted, isTrue);
+ }),
+ completes);
+
+ await Future<void>.delayed(Duration.zero);
+ resource.allowRelease(() => completer.future);
+
+ await Future<void>.delayed(Duration.zero);
+ completer.complete();
+ });
+
+ test('an onRelease error is piped to the return value', () async {
+ var pool = Pool(1);
+ var resource = await pool.request();
+
+ var completer = Completer<void>();
+ resource.allowRelease(() => completer.future);
+
+ expect(pool.done, throwsA('oh no!'));
+ expect(pool.close(), throwsA('oh no!'));
+
+ await Future<void>.delayed(Duration.zero);
+ completer.completeError('oh no!');
+ });
+ });
+
+ group('forEach', () {
+ late Pool pool;
+
+ tearDown(() async {
+ await pool.close();
+ });
+
+ const delayedToStringDuration = Duration(milliseconds: 10);
+
+ Future<String> delayedToString(int i) =>
+ Future<String>.delayed(delayedToStringDuration, () => i.toString());
+
+ for (var itemCount in [0, 5]) {
+ for (var poolSize in [1, 5, 6]) {
+ test('poolSize: $poolSize, itemCount: $itemCount', () async {
+ pool = Pool(poolSize);
+
+ var finishedItems = 0;
+
+ await for (var item in pool.forEach(
+ Iterable.generate(itemCount, (i) {
+ expect(i, lessThanOrEqualTo(finishedItems + poolSize),
+ reason: 'the iterator should be called lazily');
+ return i;
+ }),
+ delayedToString)) {
+ expect(int.parse(item), lessThan(itemCount));
+ finishedItems++;
+ }
+
+ expect(finishedItems, itemCount);
+ });
+ }
+ }
+
+ test('pool closed before listen', () async {
+ pool = Pool(2);
+
+ var stream = pool.forEach(Iterable<int>.generate(5), delayedToString);
+
+ await pool.close();
+
+ expect(stream.toList(), throwsStateError);
+ });
+
+ test('completes even if the pool is partially used', () async {
+ pool = Pool(2);
+
+ var resource = await pool.request();
+
+ var stream = pool.forEach(<int>[], delayedToString);
+
+ expect(await stream.length, 0);
+
+ resource.release();
+ });
+
+ test('stream paused longer than timeout', () async {
+ pool = Pool(2, timeout: delayedToStringDuration);
+
+ var resource = await pool.request();
+
+ var stream = pool.forEach<int, int>(
+ Iterable.generate(100, (i) {
+ expect(i, lessThan(20),
+ reason: 'The timeout should happen '
+ 'before the entire iterable is iterated.');
+ return i;
+ }), (i) async {
+ await Future<void>.delayed(Duration(milliseconds: i));
+ return i;
+ });
+
+ await expectLater(
+ stream.toList,
+ throwsA(const TypeMatcher<TimeoutException>().having(
+ (te) => te.message,
+ 'message',
+ contains('Pool deadlock: '
+ 'all resources have been allocated for too long.'))));
+
+ resource.release();
+ });
+
+ group('timing and timeout', () {
+ for (var poolSize in [2, 8, 64]) {
+ for (var otherTaskCount
+ in [0, 1, 7, 63].where((otc) => otc < poolSize)) {
+ test('poolSize: $poolSize, otherTaskCount: $otherTaskCount',
+ () async {
+ final itemCount = 128;
+ pool = Pool(poolSize, timeout: const Duration(milliseconds: 20));
+
+ var otherTasks = await Future.wait(
+ Iterable<int>.generate(otherTaskCount)
+ .map((i) => pool.request()));
+
+ try {
+ var finishedItems = 0;
+
+ var watch = Stopwatch()..start();
+
+ await for (var item in pool.forEach(
+ Iterable.generate(itemCount, (i) {
+ expect(i, lessThanOrEqualTo(finishedItems + poolSize),
+ reason: 'the iterator should be called lazily');
+ return i;
+ }),
+ delayedToString)) {
+ expect(int.parse(item), lessThan(itemCount));
+ finishedItems++;
+ }
+
+ expect(finishedItems, itemCount);
+
+ final expectedElapsed =
+ delayedToStringDuration.inMicroseconds * 4;
+
+ expect((watch.elapsed ~/ itemCount).inMicroseconds,
+ lessThan(expectedElapsed / (poolSize - otherTaskCount)),
+ reason: 'Average time per task should be '
+ 'proportionate to the available pool resources.');
+ } finally {
+ for (var task in otherTasks) {
+ task.release();
+ }
+ }
+ });
+ }
+ }
+ }, testOn: 'vm');
+
+ test('partial iteration', () async {
+ pool = Pool(5);
+ var stream = pool.forEach(Iterable<int>.generate(100), delayedToString);
+ expect(await stream.take(10).toList(), hasLength(10));
+ });
+
+ test('pool close during data with waiting to be done', () async {
+ pool = Pool(5);
+
+ var stream = pool.forEach(Iterable<int>.generate(100), delayedToString);
+
+ var dataCount = 0;
+ var subscription = stream.listen((data) {
+ dataCount++;
+ pool.close();
+ });
+
+ await subscription.asFuture<void>();
+ expect(dataCount, 100);
+ await subscription.cancel();
+ });
+
+ test('pause and resume ', () async {
+ var generatedCount = 0;
+ var dataCount = 0;
+ final poolSize = 5;
+
+ pool = Pool(poolSize);
+
+ var stream = pool.forEach(
+ Iterable<int>.generate(40, (i) {
+ expect(generatedCount, lessThanOrEqualTo(dataCount + 2 * poolSize),
+ reason: 'The iterator should not be called '
+ 'much faster than the data is consumed.');
+ generatedCount++;
+ return i;
+ }),
+ delayedToString);
+
+ // ignore: cancel_subscriptions
+ late StreamSubscription subscription;
+
+ subscription = stream.listen(
+ (data) {
+ dataCount++;
+
+ if (int.parse(data) % 3 == 1) {
+ subscription.pause(Future(() async {
+ await Future<void>.delayed(const Duration(milliseconds: 100));
+ }));
+ }
+ },
+ onError: registerException,
+ onDone: expectAsync0(() {
+ expect(dataCount, 40);
+ }),
+ );
+ });
+
+ group('cancel', () {
+ final dataSize = 32;
+ for (var i = 1; i < 5; i++) {
+ test('with pool size $i', () async {
+ pool = Pool(i);
+
+ var stream =
+ pool.forEach(Iterable<int>.generate(dataSize), delayedToString);
+
+ var cancelCompleter = Completer<void>();
+
+ StreamSubscription subscription;
+
+ var eventCount = 0;
+ subscription = stream.listen((data) {
+ eventCount++;
+ if (int.parse(data) == dataSize ~/ 2) {
+ cancelCompleter.complete();
+ }
+ }, onError: registerException);
+
+ await cancelCompleter.future;
+
+ await subscription.cancel();
+
+ expect(eventCount, 1 + dataSize ~/ 2);
+ });
+ }
+ });
+
+ group('errors', () {
+ Future<void> errorInIterator({
+ bool Function(int item, Object error, StackTrace stack)? onError,
+ }) async {
+ pool = Pool(20);
+
+ var listFuture = pool
+ .forEach(
+ Iterable.generate(100, (i) {
+ if (i == 50) {
+ throw StateError('error while generating item in iterator');
+ }
+
+ return i;
+ }),
+ delayedToString,
+ onError: onError)
+ .toList();
+
+ await expectLater(() async => listFuture, throwsStateError);
+ }
+
+ test('iteration, no onError', () async {
+ await errorInIterator();
+ });
+ test('iteration, with onError', () async {
+ await errorInIterator(onError: (i, e, s) => false);
+ });
+
+ test('error in action, no onError', () async {
+ pool = Pool(20);
+
+ var listFuture = pool.forEach(Iterable<int>.generate(100), (i) async {
+ await Future<void>.delayed(const Duration(milliseconds: 10));
+ if (i == 10) {
+ throw UnsupportedError('10 is not supported');
+ }
+ return i.toString();
+ }).toList();
+
+ await expectLater(() async => listFuture, throwsUnsupportedError);
+ });
+
+ test('error in action, no onError', () async {
+ pool = Pool(20);
+
+ var list = await pool.forEach(Iterable<int>.generate(100),
+ (int i) async {
+ await Future<void>.delayed(const Duration(milliseconds: 10));
+ if (i % 10 == 0) {
+ throw UnsupportedError('Multiples of 10 not supported');
+ }
+ return i.toString();
+ },
+ onError: (item, error, stack) =>
+ error is! UnsupportedError).toList();
+
+ expect(list, hasLength(90));
+ });
+ });
+ });
+
+ test('throw error when pool limit <= 0', () {
+ expect(() => Pool(-1), throwsArgumentError);
+ expect(() => Pool(0), throwsArgumentError);
+ });
+}
+
+/// Returns a function that will cause the test to fail if it's called.
+///
+/// This should only be called within a [FakeAsync.run] zone.
+void Function() expectNoAsync() {
+ var stack = Trace.current(1);
+ return () => registerException(
+ TestFailure('Expected function not to be called.'), stack);
+}
+
+/// A matcher for Futures that asserts that they don't complete.
+///
+/// This should only be called within a [FakeAsync.run] zone.
+Matcher get doesNotComplete => predicate((Future future) {
+ var stack = Trace.current(1);
+ future.then((_) => registerException(
+ TestFailure('Expected future not to complete.'), stack));
+ return true;
+ });
diff --git a/pkgs/pub_semver/.gitignore b/pkgs/pub_semver/.gitignore
new file mode 100644
index 0000000..49ce72d
--- /dev/null
+++ b/pkgs/pub_semver/.gitignore
@@ -0,0 +1,3 @@
+.dart_tool/
+.packages
+pubspec.lock
diff --git a/pkgs/pub_semver/CHANGELOG.md b/pkgs/pub_semver/CHANGELOG.md
new file mode 100644
index 0000000..a31fbb2
--- /dev/null
+++ b/pkgs/pub_semver/CHANGELOG.md
@@ -0,0 +1,177 @@
+## 2.1.5
+
+- Require Dart `3.4.0`.
+- Move to `dart-lang/tools` monorepo.
+
+## 2.1.4
+
+- Added topics to `pubspec.yaml`.
+
+## 2.1.3
+
+- Add type parameters to the signatures of the `Version.preRelease` and
+ `Version.build` fields (`List` ==> `List<Object>`).
+ [#74](https://github.com/dart-lang/pub_semver/pull/74).
+- Require Dart 2.17.
+
+## 2.1.2
+
+- Add markdown badges to the readme.
+
+## 2.1.1
+
+- Fixed the version parsing pattern to only accept dots between version
+ components.
+
+## 2.1.0
+
+- Added `Version.canonicalizedVersion` to help scrub leading zeros and highlight
+ that `Version.toString()` preserves leading zeros.
+- Annotated `Version` with `@sealed` to discourage users from implementing the
+ interface.
+
+## 2.0.0
+
+- Stable null safety release.
+- `Version.primary` now throws `StateError` if the `versions` argument is empty.
+
+## 1.4.4
+
+- Fix a bug of `VersionRange.union` where ranges bounded at infinity would get
+ combined wrongly.
+
+# 1.4.3
+
+- Update Dart SDK constraint to `>=2.0.0 <3.0.0`.
+- Update `package:collection` constraint to `^1.0.0`.
+
+## 1.4.2
+
+* Set max SDK version to `<3.0.0`.
+
+## 1.4.1
+
+* Fix a bug where there upper bound of a version range with a build identifier
+ could accidentally be rewritten.
+
+## 1.4.0
+
+* Add a `Version.firstPreRelease` getter that returns the first possible
+ pre-release of a version.
+
+* Add a `Version.isFirstPreRelease` getter that returns whether a version is the
+ first possible pre-release.
+
+* `new VersionRange()` with an exclusive maximum now replaces the maximum with
+ its first pre-release version. This matches the existing semantics, where an
+ exclusive maximum would exclude pre-release versions of that maximum.
+
+ Explicitly representing this by changing the maximum version ensures that all
+ operations behave correctly with respect to the special pre-release semantics.
+ In particular, it fixes bugs where, for example,
+ `(>=1.0.0 <2.0.0-dev).union(>=2.0.0-dev <2.0.0)` and
+ `(>=1.0.0 <3.0.0).difference(^1.0.0)` wouldn't include `2.0.0-dev`.
+
+* Add an `alwaysIncludeMaxPreRelease` parameter to `new VersionRange()`, which
+ disables the replacement described above and allows users to create ranges
+ that do include the pre-release versions of an exclusive max version.
+
+## 1.3.7
+
+* Fix more bugs with `VersionRange.intersect()`, `VersionRange.difference()`,
+ and `VersionRange.union()` involving version ranges with pre-release maximums.
+
+## 1.3.6
+
+* Fix a bug where constraints that only allowed pre-release versions would be
+ parsed as empty constraints.
+
+## 1.3.5
+
+* Fix a bug where `VersionRange.intersect()` would return incorrect results for
+ pre-release versions with the same base version number as release versions.
+
+## 1.3.4
+
+* Fix a bug where `VersionRange.allowsAll()`, `VersionRange.allowsAny()`, and
+ `VersionRange.difference()` would return incorrect results for pre-release
+ versions with the same base version number as release versions.
+
+## 1.3.3
+
+* Fix a bug where `VersionRange.difference()` with a union constraint that
+ covered the entire range would crash.
+
+## 1.3.2
+
+* Fix a checked-mode error in `VersionRange.difference()`.
+
+## 1.3.1
+
+* Fix a new strong mode error.
+
+## 1.3.0
+
+* Make the `VersionUnion` class public. This was previously used internally to
+ implement `new VersionConstraint.unionOf()` and `VersionConstraint.union()`.
+ Now it's public so you can use it too.
+
+* Added `VersionConstraint.difference()`. This returns a constraint matching all
+ versions matched by one constraint but not another.
+
+* Make `VersionRange` implement `Comparable<VersionRange>`. Ranges are ordered
+ first by lower bound, then by upper bound.
+
+## 1.2.4
+
+* Fix all remaining strong mode warnings.
+
+## 1.2.3
+
+* Addressed three strong mode warnings.
+
+## 1.2.2
+
+* Make the package analyze under strong mode and compile with the DDC (Dart Dev
+ Compiler). Fix two issues with a private subclass of `VersionConstraint`
+ having different types for overridden methods.
+
+## 1.2.1
+
+* Allow version ranges like `>=1.2.3-dev.1 <1.2.3` to match pre-release versions
+ of `1.2.3`. Previously, these didn't match, since the pre-release versions had
+ the same major, minor, and patch numbers as the max; now an exception has been
+ added if they also have the same major, minor, and patch numbers as the min
+ *and* the min is also a pre-release version.
+
+## 1.2.0
+
+* Add a `VersionConstraint.union()` method and a `new
+ VersionConstraint.unionOf()` constructor. These each return a constraint that
+ matches multiple existing constraints.
+
+* Add a `VersionConstraint.allowsAll()` method, which returns whether one
+ constraint is a superset of another.
+
+* Add a `VersionConstraint.allowsAny()` method, which returns whether one
+ constraint overlaps another.
+
+* `Version` now implements `VersionRange`.
+
+## 1.1.0
+
+* Add support for the `^` operator for compatible versions according to pub's
+ notion of compatibility. `^1.2.3` is equivalent to `>=1.2.3 <2.0.0`; `^0.1.2`
+ is equivalent to `>=0.1.2 <0.2.0`.
+
+* Add `Version.nextBreaking`, which returns the next version that introduces
+ breaking changes after a given version.
+
+* Add `new VersionConstraint.compatibleWith()`, which returns a range covering
+ all versions compatible with a given version.
+
+* Add a custom `VersionRange.hashCode` to make it properly hashable.
+
+## 1.0.0
+
+* Initial release.
diff --git a/pkgs/pub_semver/LICENSE b/pkgs/pub_semver/LICENSE
new file mode 100644
index 0000000..000cd7b
--- /dev/null
+++ b/pkgs/pub_semver/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/pub_semver/README.md b/pkgs/pub_semver/README.md
new file mode 100644
index 0000000..03c92a3
--- /dev/null
+++ b/pkgs/pub_semver/README.md
@@ -0,0 +1,107 @@
+[](https://github.com/dart-lang/tools/actions/workflows/pub_semver.yaml)
+[](https://pub.dev/packages/pub_semver)
+[](https://pub.dev/packages/pub_semver/publisher)
+
+Handles version numbers and version constraints in the same way that [pub][]
+does.
+
+## Semantics
+
+The semantics here very closely follow the
+[Semantic Versioning spec version 2.0.0-rc.1][semver]. It differs from semver
+in a few corner cases:
+
+ * **Version ordering does take build suffixes into account.** This is unlike
+ semver 2.0.0 but like earlier versions of semver. Version `1.2.3+1` is
+ considered a lower number than `1.2.3+2`.
+
+ Since a package may have published multiple versions that differ only by
+ build suffix, pub still has to pick one of them *somehow*. Semver leaves
+ that issue unresolved, so we just say that build numbers are sorted like
+ pre-release suffixes.
+
+ * **Pre-release versions are excluded from most max ranges.** Let's say a
+ user is depending on "foo" with constraint `>=1.0.0 <2.0.0` and that "foo"
+ has published these versions:
+
+ * `1.0.0`
+ * `1.1.0`
+ * `1.2.0`
+ * `2.0.0-alpha`
+ * `2.0.0-beta`
+ * `2.0.0`
+ * `2.1.0`
+
+ Versions `2.0.0` and `2.1.0` are excluded by the constraint since neither
+ matches `<2.0.0`. However, since semver specifies that pre-release versions
+ are lower than the non-prerelease version (i.e. `2.0.0-beta < 2.0.0`, then
+ the `<2.0.0` constraint does technically allow those.
+
+ But that's almost never what the user wants. If their package doesn't work
+ with foo `2.0.0`, it's certainly not likely to work with experimental,
+ unstable versions of `2.0.0`'s API, which is what pre-release versions
+ represent.
+
+ To handle that, `<` version ranges don't allow pre-release versions of the
+ maximum unless the max is itself a pre-release, or the min is a pre-release
+ of the same version. In other words, a `<2.0.0` constraint will prohibit not
+ just `2.0.0` but any pre-release of `2.0.0`. However, `<2.0.0-beta` will
+ exclude `2.0.0-beta` but allow `2.0.0-alpha`. Likewise, `>2.0.0-alpha
+ <2.0.0` will exclude `2.0.0-alpha` but allow `2.0.0-beta`.
+
+ * **Pre-release versions are avoided when possible.** The above case
+ handles pre-release versions at the top of the range, but what about in
+ the middle? What if "foo" has these versions:
+
+ * `1.0.0`
+ * `1.2.0-alpha`
+ * `1.2.0`
+ * `1.3.0-experimental`
+
+ When a number of versions are valid, pub chooses the best one where "best"
+ usually means "highest numbered". That follows the user's intuition that,
+ all else being equal, they want the latest and greatest. Here, that would
+ mean `1.3.0-experimental`. However, most users don't want to use unstable
+ versions of their dependencies.
+
+ We want pre-releases to be explicitly opt-in so that package consumers
+ don't get unpleasant surprises and so that package maintainers are free to
+ put out pre-releases and get feedback without dragging all of their users
+ onto the bleeding edge.
+
+ To accommodate that, when pub is choosing a version, it uses *priority*
+ order which is different from strict comparison ordering. Any stable
+ version is considered higher priority than any unstable version. The above
+ versions, in priority order, are:
+
+ * `1.2.0-alpha`
+ * `1.3.0-experimental`
+ * `1.0.0`
+ * `1.2.0`
+
+ This ensures that users only end up with an unstable version when there are
+ no alternatives. Usually this means they've picked a constraint that
+ specifically selects that unstable version -- they've deliberately opted
+ into it.
+
+ * **There is a notion of compatibility between pre-1.0.0 versions.** Semver
+ deems all pre-1.0.0 versions to be incompatible. This means that the only
+ way to ensure compatibility when depending on a pre-1.0.0 package is to
+ pin the dependency to an exact version. Pinned version constraints prevent
+ automatic patch and pre-release updates. To avoid this situation, pub
+ defines the "next breaking" version as the version which increments the
+ major version if it's greater than zero, and the minor version otherwise,
+ resets subsequent digits to zero, and strips any pre-release or build
+ suffix. For example, here are some versions along with their next breaking
+ ones:
+
+ `0.0.3` -> `0.1.0`
+ `0.7.2-alpha` -> `0.8.0`
+ `1.2.3` -> `2.0.0`
+
+ To make use of this, pub defines a "^" operator which yields a version
+ constraint greater than or equal to a given version, but less than its next
+ breaking one.
+
+[pub]: https://pub.dev
+[semver]: https://semver.org/spec/v2.0.0-rc.1.html
diff --git a/pkgs/pub_semver/analysis_options.yaml b/pkgs/pub_semver/analysis_options.yaml
new file mode 100644
index 0000000..76380a0
--- /dev/null
+++ b/pkgs/pub_semver/analysis_options.yaml
@@ -0,0 +1,31 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_classes_with_only_static_members
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_returning_this
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - cascade_invocations
+ - join_return_with_assignment
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - no_runtimeType_toString
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - unnecessary_await_in_return
+ - use_if_null_to_convert_nulls_to_bools
+ - use_raw_strings
+ - use_string_buffers
diff --git a/pkgs/pub_semver/example/example.dart b/pkgs/pub_semver/example/example.dart
new file mode 100644
index 0000000..890343c
--- /dev/null
+++ b/pkgs/pub_semver/example/example.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:pub_semver/pub_semver.dart';
+
+void main() {
+ final range = VersionConstraint.parse('^2.0.0');
+
+ for (var version in [
+ Version.parse('1.2.3-pre'),
+ Version.parse('2.0.0+123'),
+ Version.parse('3.0.0-dev'),
+ ]) {
+ print('$version ${version.isPreRelease} ${range.allows(version)}');
+ }
+}
diff --git a/pkgs/pub_semver/lib/pub_semver.dart b/pkgs/pub_semver/lib/pub_semver.dart
new file mode 100644
index 0000000..4b6487c
--- /dev/null
+++ b/pkgs/pub_semver/lib/pub_semver.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/version.dart';
+export 'src/version_constraint.dart';
+export 'src/version_range.dart' hide CompatibleWithVersionRange;
+export 'src/version_union.dart';
diff --git a/pkgs/pub_semver/lib/src/patterns.dart b/pkgs/pub_semver/lib/src/patterns.dart
new file mode 100644
index 0000000..03119ac
--- /dev/null
+++ b/pkgs/pub_semver/lib/src/patterns.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Regex that matches a version number at the beginning of a string.
+final startVersion = RegExp(r'^' // Start at beginning.
+ r'(\d+)\.(\d+)\.(\d+)' // Version number.
+ r'(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?' // Pre-release.
+ r'(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?'); // Build.
+
+/// Like [startVersion] but matches the entire string.
+final completeVersion = RegExp('${startVersion.pattern}\$');
+
+/// Parses a comparison operator ("<", ">", "<=", or ">=") at the beginning of
+/// a string.
+final startComparison = RegExp(r'^[<>]=?');
+
+/// The "compatible with" operator.
+const compatibleWithChar = '^';
diff --git a/pkgs/pub_semver/lib/src/utils.dart b/pkgs/pub_semver/lib/src/utils.dart
new file mode 100644
index 0000000..a9f714f
--- /dev/null
+++ b/pkgs/pub_semver/lib/src/utils.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'version.dart';
+import 'version_range.dart';
+
+/// Returns whether [range1] is immediately next to, but not overlapping,
+/// [range2].
+bool areAdjacent(VersionRange range1, VersionRange range2) {
+ if (range1.max != range2.min) return false;
+
+ return (range1.includeMax && !range2.includeMin) ||
+ (!range1.includeMax && range2.includeMin);
+}
+
+/// Returns whether [range1] allows lower versions than [range2].
+bool allowsLower(VersionRange range1, VersionRange range2) {
+ if (range1.min == null) return range2.min != null;
+ if (range2.min == null) return false;
+
+ var comparison = range1.min!.compareTo(range2.min!);
+ if (comparison == -1) return true;
+ if (comparison == 1) return false;
+ return range1.includeMin && !range2.includeMin;
+}
+
+/// Returns whether [range1] allows higher versions than [range2].
+bool allowsHigher(VersionRange range1, VersionRange range2) {
+ if (range1.max == null) return range2.max != null;
+ if (range2.max == null) return false;
+
+ var comparison = range1.max!.compareTo(range2.max!);
+ if (comparison == 1) return true;
+ if (comparison == -1) return false;
+ return range1.includeMax && !range2.includeMax;
+}
+
+/// Returns whether [range1] allows only versions lower than those allowed by
+/// [range2].
+bool strictlyLower(VersionRange range1, VersionRange range2) {
+ if (range1.max == null || range2.min == null) return false;
+
+ var comparison = range1.max!.compareTo(range2.min!);
+ if (comparison == -1) return true;
+ if (comparison == 1) return false;
+ return !range1.includeMax || !range2.includeMin;
+}
+
+/// Returns whether [range1] allows only versions higher than those allowed by
+/// [range2].
+bool strictlyHigher(VersionRange range1, VersionRange range2) =>
+ strictlyLower(range2, range1);
+
+bool equalsWithoutPreRelease(Version version1, Version version2) =>
+ version1.major == version2.major &&
+ version1.minor == version2.minor &&
+ version1.patch == version2.patch;
diff --git a/pkgs/pub_semver/lib/src/version.dart b/pkgs/pub_semver/lib/src/version.dart
new file mode 100644
index 0000000..90f3d53
--- /dev/null
+++ b/pkgs/pub_semver/lib/src/version.dart
@@ -0,0 +1,391 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' as math;
+
+import 'package:collection/collection.dart';
+import 'package:meta/meta.dart' show sealed;
+
+import 'patterns.dart';
+import 'version_constraint.dart';
+import 'version_range.dart';
+
+/// The equality operator to use for comparing version components.
+const _equality = IterableEquality<Object>();
+
+/// A parsed semantic version number.
+@sealed
+class Version implements VersionConstraint, VersionRange {
+ /// No released version: i.e. "0.0.0".
+ static Version get none => Version(0, 0, 0);
+
+ /// Compares [a] and [b] to see which takes priority over the other.
+ ///
+ /// Returns `1` if [a] takes priority over [b] and `-1` if vice versa. If
+ /// [a] and [b] are equivalent, returns `0`.
+ ///
+ /// Unlike [compareTo], which *orders* versions, this determines which
+ /// version a user is likely to prefer. In particular, it prioritizes
+ /// pre-release versions lower than stable versions, regardless of their
+ /// version numbers. Pub uses this when determining which version to prefer
+ /// when a number of versions are allowed. In that case, it will always
+ /// choose a stable version when possible.
+ ///
+ /// When used to sort a list, orders in ascending priority so that the
+ /// highest priority version is *last* in the result.
+ static int prioritize(Version a, Version b) {
+ // Sort all prerelease versions after all normal versions. This way
+ // the solver will prefer stable packages over unstable ones.
+ if (a.isPreRelease && !b.isPreRelease) return -1;
+ if (!a.isPreRelease && b.isPreRelease) return 1;
+
+ return a.compareTo(b);
+ }
+
+ /// Like [prioritize], but lower version numbers are considered greater than
+ /// higher version numbers.
+ ///
+ /// This still considers prerelease versions to be lower than non-prerelease
+ /// versions. Pub uses this when downgrading -- it chooses the lowest version
+ /// but still excludes pre-release versions when possible.
+ static int antiprioritize(Version a, Version b) {
+ if (a.isPreRelease && !b.isPreRelease) return -1;
+ if (!a.isPreRelease && b.isPreRelease) return 1;
+
+ return b.compareTo(a);
+ }
+
+ /// The major version number: "1" in "1.2.3".
+ final int major;
+
+ /// The minor version number: "2" in "1.2.3".
+ final int minor;
+
+ /// The patch version number: "3" in "1.2.3".
+ final int patch;
+
+ /// The pre-release identifier: "foo" in "1.2.3-foo".
+ ///
+ /// This is split into a list of components, each of which may be either a
+ /// string or a non-negative integer. It may also be empty, indicating that
+ /// this version has no pre-release identifier.
+ final List<Object> preRelease;
+
+ /// The build identifier: "foo" in "1.2.3+foo".
+ ///
+ /// This is split into a list of components, each of which may be either a
+ /// string or a non-negative integer. It may also be empty, indicating that
+ /// this version has no build identifier.
+ final List<Object> build;
+
+ /// The original string representation of the version number.
+ ///
+ /// This preserves textual artifacts like leading zeros that may be left out
+ /// of the parsed version.
+ final String _text;
+
+ @override
+ Version get min => this;
+ @override
+ Version get max => this;
+ @override
+ bool get includeMin => true;
+ @override
+ bool get includeMax => true;
+
+ Version._(this.major, this.minor, this.patch, String? preRelease,
+ String? build, this._text)
+ : preRelease = preRelease == null ? <Object>[] : _splitParts(preRelease),
+ build = build == null ? [] : _splitParts(build) {
+ if (major < 0) throw ArgumentError('Major version must be non-negative.');
+ if (minor < 0) throw ArgumentError('Minor version must be non-negative.');
+ if (patch < 0) throw ArgumentError('Patch version must be non-negative.');
+ }
+
+ /// Creates a new [Version] object.
+ factory Version(int major, int minor, int patch,
+ {String? pre, String? build}) {
+ var text = '$major.$minor.$patch';
+ if (pre != null) text += '-$pre';
+ if (build != null) text += '+$build';
+
+ return Version._(major, minor, patch, pre, build, text);
+ }
+
+ /// Creates a new [Version] by parsing [text].
+ factory Version.parse(String text) {
+ final match = completeVersion.firstMatch(text);
+ if (match == null) {
+ throw FormatException('Could not parse "$text".');
+ }
+
+ try {
+ var major = int.parse(match[1]!);
+ var minor = int.parse(match[2]!);
+ var patch = int.parse(match[3]!);
+
+ var preRelease = match[5];
+ var build = match[8];
+
+ return Version._(major, minor, patch, preRelease, build, text);
+ } on FormatException {
+ throw FormatException('Could not parse "$text".');
+ }
+ }
+
+ /// Returns the primary version out of [versions].
+ ///
+ /// This is the highest-numbered stable (non-prerelease) version. If there
+ /// are no stable versions, it's just the highest-numbered version.
+ ///
+ /// If [versions] is empty, throws a [StateError].
+ static Version primary(List<Version> versions) {
+ var primary = versions.first;
+ for (var version in versions.skip(1)) {
+ if ((!version.isPreRelease && primary.isPreRelease) ||
+ (version.isPreRelease == primary.isPreRelease && version > primary)) {
+ primary = version;
+ }
+ }
+ return primary;
+ }
+
+ /// Splits a string of dot-delimited identifiers into their component parts.
+ ///
+ /// Identifiers that are numeric are converted to numbers.
+ static List<Object> _splitParts(String text) => text
+ .split('.')
+ .map((part) =>
+ // Return an integer part if possible, otherwise return the string
+ // as-is
+ int.tryParse(part) ?? part)
+ .toList();
+
+ @override
+ bool operator ==(Object other) =>
+ other is Version &&
+ major == other.major &&
+ minor == other.minor &&
+ patch == other.patch &&
+ _equality.equals(preRelease, other.preRelease) &&
+ _equality.equals(build, other.build);
+
+ @override
+ int get hashCode =>
+ major ^
+ minor ^
+ patch ^
+ _equality.hash(preRelease) ^
+ _equality.hash(build);
+
+ bool operator <(Version other) => compareTo(other) < 0;
+ bool operator >(Version other) => compareTo(other) > 0;
+ bool operator <=(Version other) => compareTo(other) <= 0;
+ bool operator >=(Version other) => compareTo(other) >= 0;
+
+ @override
+ bool get isAny => false;
+ @override
+ bool get isEmpty => false;
+
+ /// Whether or not this is a pre-release version.
+ bool get isPreRelease => preRelease.isNotEmpty;
+
+ /// Gets the next major version number that follows this one.
+ ///
+ /// If this version is a pre-release of a major version release (i.e. the
+ /// minor and patch versions are zero), then it just strips the pre-release
+ /// suffix. Otherwise, it increments the major version and resets the minor
+ /// and patch.
+ Version get nextMajor {
+ if (isPreRelease && minor == 0 && patch == 0) {
+ return Version(major, minor, patch);
+ }
+
+ return _incrementMajor();
+ }
+
+ /// Gets the next minor version number that follows this one.
+ ///
+ /// If this version is a pre-release of a minor version release (i.e. the
+ /// patch version is zero), then it just strips the pre-release suffix.
+ /// Otherwise, it increments the minor version and resets the patch.
+ Version get nextMinor {
+ if (isPreRelease && patch == 0) {
+ return Version(major, minor, patch);
+ }
+
+ return _incrementMinor();
+ }
+
+ /// Gets the next patch version number that follows this one.
+ ///
+ /// If this version is a pre-release, then it just strips the pre-release
+ /// suffix. Otherwise, it increments the patch version.
+ Version get nextPatch {
+ if (isPreRelease) {
+ return Version(major, minor, patch);
+ }
+
+ return _incrementPatch();
+ }
+
+ /// Gets the next breaking version number that follows this one.
+ ///
+ /// Increments [major] if it's greater than zero, otherwise [minor], resets
+ /// subsequent digits to zero, and strips any [preRelease] or [build]
+ /// suffix.
+ Version get nextBreaking {
+ if (major == 0) {
+ return _incrementMinor();
+ }
+
+ return _incrementMajor();
+ }
+
+ /// Returns the first possible pre-release of this version.
+ Version get firstPreRelease => Version(major, minor, patch, pre: '0');
+
+ /// Returns whether this is the first possible pre-release of its version.
+ bool get isFirstPreRelease => preRelease.length == 1 && preRelease.first == 0;
+
+ Version _incrementMajor() => Version(major + 1, 0, 0);
+ Version _incrementMinor() => Version(major, minor + 1, 0);
+ Version _incrementPatch() => Version(major, minor, patch + 1);
+
+ /// Tests if [other] matches this version exactly.
+ @override
+ bool allows(Version other) => this == other;
+
+ @override
+ bool allowsAll(VersionConstraint other) => other.isEmpty || other == this;
+
+ @override
+ bool allowsAny(VersionConstraint other) => other.allows(this);
+
+ @override
+ VersionConstraint intersect(VersionConstraint other) =>
+ other.allows(this) ? this : VersionConstraint.empty;
+
+ @override
+ VersionConstraint union(VersionConstraint other) {
+ if (other.allows(this)) return other;
+
+ if (other is VersionRange) {
+ if (other.min == this) {
+ return VersionRange(
+ min: other.min,
+ max: other.max,
+ includeMin: true,
+ includeMax: other.includeMax,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ if (other.max == this) {
+ return VersionRange(
+ min: other.min,
+ max: other.max,
+ includeMin: other.includeMin,
+ includeMax: true,
+ alwaysIncludeMaxPreRelease: true);
+ }
+ }
+
+ return VersionConstraint.unionOf([this, other]);
+ }
+
+ @override
+ VersionConstraint difference(VersionConstraint other) =>
+ other.allows(this) ? VersionConstraint.empty : this;
+
+ @override
+ int compareTo(VersionRange other) {
+ if (other is Version) {
+ if (major != other.major) return major.compareTo(other.major);
+ if (minor != other.minor) return minor.compareTo(other.minor);
+ if (patch != other.patch) return patch.compareTo(other.patch);
+
+ // Pre-releases always come before no pre-release string.
+ if (!isPreRelease && other.isPreRelease) return 1;
+ if (!other.isPreRelease && isPreRelease) return -1;
+
+ var comparison = _compareLists(preRelease, other.preRelease);
+ if (comparison != 0) return comparison;
+
+ // Builds always come after no build string.
+ if (build.isEmpty && other.build.isNotEmpty) return -1;
+ if (other.build.isEmpty && build.isNotEmpty) return 1;
+ return _compareLists(build, other.build);
+ } else {
+ return -other.compareTo(this);
+ }
+ }
+
+ /// Get non-canonical string representation of this [Version].
+ ///
+ /// If created with [Version.parse], the string from which the version was
+ /// parsed is returned. Unlike the [canonicalizedVersion] this preserves
+ /// artifacts such as leading zeros.
+ @override
+ String toString() => _text;
+
+ /// Get a canonicalized string representation of this [Version].
+ ///
+ /// Unlike [Version.toString()] this always returns a canonical string
+ /// representation of this [Version].
+ ///
+ /// **Example**
+ /// ```dart
+ /// final v = Version.parse('01.02.03-01.dev+pre.02');
+ ///
+ /// assert(v.toString() == '01.02.03-01.dev+pre.02');
+ /// assert(v.canonicalizedVersion == '1.2.3-1.dev+pre.2');
+ /// assert(Version.parse(v.canonicalizedVersion) == v);
+ /// ```
+ String get canonicalizedVersion => Version(
+ major,
+ minor,
+ patch,
+ pre: preRelease.isNotEmpty ? preRelease.join('.') : null,
+ build: build.isNotEmpty ? build.join('.') : null,
+ ).toString();
+
+ /// Compares a dot-separated component of two versions.
+ ///
+ /// This is used for the pre-release and build version parts. This follows
+ /// Rule 12 of the Semantic Versioning spec (v2.0.0-rc.1).
+ int _compareLists(List<Object> a, List<Object> b) {
+ for (var i = 0; i < math.max(a.length, b.length); i++) {
+ var aPart = (i < a.length) ? a[i] : null;
+ var bPart = (i < b.length) ? b[i] : null;
+
+ if (aPart == bPart) continue;
+
+ // Missing parts come before present ones.
+ if (aPart == null) return -1;
+ if (bPart == null) return 1;
+
+ if (aPart is num) {
+ if (bPart is num) {
+ // Compare two numbers.
+ return aPart.compareTo(bPart);
+ } else {
+ // Numbers come before strings.
+ return -1;
+ }
+ } else {
+ if (bPart is num) {
+ // Strings come after numbers.
+ return 1;
+ } else {
+ // Compare two strings.
+ return (aPart as String).compareTo(bPart as String);
+ }
+ }
+ }
+
+ // The lists are entirely equal.
+ return 0;
+ }
+}
diff --git a/pkgs/pub_semver/lib/src/version_constraint.dart b/pkgs/pub_semver/lib/src/version_constraint.dart
new file mode 100644
index 0000000..948118e
--- /dev/null
+++ b/pkgs/pub_semver/lib/src/version_constraint.dart
@@ -0,0 +1,287 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'patterns.dart';
+import 'utils.dart';
+import 'version.dart';
+import 'version_range.dart';
+import 'version_union.dart';
+
+/// A [VersionConstraint] is a predicate that can determine whether a given
+/// version is valid or not.
+///
+/// For example, a ">= 2.0.0" constraint allows any version that is "2.0.0" or
+/// greater. Version objects themselves implement this to match a specific
+/// version.
+abstract class VersionConstraint {
+ /// A [VersionConstraint] that allows all versions.
+ static VersionConstraint any = VersionRange();
+
+ /// A [VersionConstraint] that allows no versions -- the empty set.
+ static VersionConstraint empty = const _EmptyVersion();
+
+ /// Parses a version constraint.
+ ///
+ /// This string is one of:
+ ///
+ /// * "any". [any] version.
+ /// * "^" followed by a version string. Versions compatible with
+ /// ([VersionConstraint.compatibleWith]) the version.
+ /// * a series of version parts. Each part can be one of:
+ /// * A version string like `1.2.3`. In other words, anything that can be
+ /// parsed by [Version.parse()].
+ /// * A comparison operator (`<`, `>`, `<=`, or `>=`) followed by a
+ /// version string.
+ ///
+ /// Whitespace is ignored.
+ ///
+ /// Examples:
+ ///
+ /// any
+ /// ^0.7.2
+ /// ^1.0.0-alpha
+ /// 1.2.3-alpha
+ /// <=5.1.4
+ /// >2.0.4 <= 2.4.6
+ factory VersionConstraint.parse(String text) {
+ var originalText = text;
+
+ void skipWhitespace() {
+ text = text.trim();
+ }
+
+ skipWhitespace();
+
+ // Handle the "any" constraint.
+ if (text == 'any') return any;
+
+ // Try to parse and consume a version number.
+ Version? matchVersion() {
+ var version = startVersion.firstMatch(text);
+ if (version == null) return null;
+
+ text = text.substring(version.end);
+ return Version.parse(version[0]!);
+ }
+
+ // Try to parse and consume a comparison operator followed by a version.
+ VersionRange? matchComparison() {
+ var comparison = startComparison.firstMatch(text);
+ if (comparison == null) return null;
+
+ var op = comparison[0]!;
+ text = text.substring(comparison.end);
+ skipWhitespace();
+
+ var version = matchVersion();
+ if (version == null) {
+ throw FormatException('Expected version number after "$op" in '
+ '"$originalText", got "$text".');
+ }
+
+ return switch (op) {
+ '<=' => VersionRange(max: version, includeMax: true),
+ '<' => VersionRange(max: version, alwaysIncludeMaxPreRelease: true),
+ '>=' => VersionRange(min: version, includeMin: true),
+ '>' => VersionRange(min: version),
+ _ => throw UnsupportedError(op),
+ };
+ }
+
+ // Try to parse the "^" operator followed by a version.
+ VersionConstraint? matchCompatibleWith() {
+ if (!text.startsWith(compatibleWithChar)) return null;
+
+ text = text.substring(compatibleWithChar.length);
+ skipWhitespace();
+
+ var version = matchVersion();
+ if (version == null) {
+ throw FormatException('Expected version number after '
+ '"$compatibleWithChar" in "$originalText", got "$text".');
+ }
+
+ if (text.isNotEmpty) {
+ throw FormatException('Cannot include other constraints with '
+ '"$compatibleWithChar" constraint in "$originalText".');
+ }
+
+ return VersionConstraint.compatibleWith(version);
+ }
+
+ var compatibleWith = matchCompatibleWith();
+ if (compatibleWith != null) return compatibleWith;
+
+ Version? min;
+ var includeMin = false;
+ Version? max;
+ var includeMax = false;
+
+ for (;;) {
+ skipWhitespace();
+
+ if (text.isEmpty) break;
+
+ var newRange = matchVersion() ?? matchComparison();
+ if (newRange == null) {
+ throw FormatException('Could not parse version "$originalText". '
+ 'Unknown text at "$text".');
+ }
+
+ if (newRange.min != null) {
+ if (min == null || newRange.min! > min) {
+ min = newRange.min;
+ includeMin = newRange.includeMin;
+ } else if (newRange.min == min && !newRange.includeMin) {
+ includeMin = false;
+ }
+ }
+
+ if (newRange.max != null) {
+ if (max == null || newRange.max! < max) {
+ max = newRange.max;
+ includeMax = newRange.includeMax;
+ } else if (newRange.max == max && !newRange.includeMax) {
+ includeMax = false;
+ }
+ }
+ }
+
+ if (min == null && max == null) {
+ throw const FormatException('Cannot parse an empty string.');
+ }
+
+ if (min != null && max != null) {
+ if (min > max) return VersionConstraint.empty;
+ if (min == max) {
+ if (includeMin && includeMax) return min;
+ return VersionConstraint.empty;
+ }
+ }
+
+ return VersionRange(
+ min: min, includeMin: includeMin, max: max, includeMax: includeMax);
+ }
+
+ /// Creates a version constraint which allows all versions that are
+ /// backward compatible with [version].
+ ///
+ /// Versions are considered backward compatible with [version] if they
+ /// are greater than or equal to [version], but less than the next breaking
+ /// version ([Version.nextBreaking]) of [version].
+ factory VersionConstraint.compatibleWith(Version version) =>
+ CompatibleWithVersionRange(version);
+
+ /// Creates a new version constraint that is the intersection of
+ /// [constraints].
+ ///
+ /// It only allows versions that all of those constraints allow. If
+ /// constraints is empty, then it returns a VersionConstraint that allows
+ /// all versions.
+ factory VersionConstraint.intersection(
+ Iterable<VersionConstraint> constraints) {
+ var constraint = VersionRange();
+ for (var other in constraints) {
+ constraint = constraint.intersect(other) as VersionRange;
+ }
+ return constraint;
+ }
+
+ /// Creates a new version constraint that is the union of [constraints].
+ ///
+ /// It allows any versions that any of those constraints allows. If
+ /// [constraints] is empty, this returns a constraint that allows no versions.
+ factory VersionConstraint.unionOf(Iterable<VersionConstraint> constraints) {
+ var flattened = constraints.expand((constraint) {
+ if (constraint.isEmpty) return <VersionRange>[];
+ if (constraint is VersionUnion) return constraint.ranges;
+ if (constraint is VersionRange) return [constraint];
+ throw ArgumentError('Unknown VersionConstraint type $constraint.');
+ }).toList();
+
+ if (flattened.isEmpty) return VersionConstraint.empty;
+
+ if (flattened.any((constraint) => constraint.isAny)) {
+ return VersionConstraint.any;
+ }
+
+ flattened.sort();
+
+ var merged = <VersionRange>[];
+ for (var constraint in flattened) {
+ // Merge this constraint with the previous one, but only if they touch.
+ if (merged.isEmpty ||
+ (!merged.last.allowsAny(constraint) &&
+ !areAdjacent(merged.last, constraint))) {
+ merged.add(constraint);
+ } else {
+ merged[merged.length - 1] =
+ merged.last.union(constraint) as VersionRange;
+ }
+ }
+
+ if (merged.length == 1) return merged.single;
+ return VersionUnion.fromRanges(merged);
+ }
+
+ /// Returns `true` if this constraint allows no versions.
+ bool get isEmpty;
+
+ /// Returns `true` if this constraint allows all versions.
+ bool get isAny;
+
+ /// Returns `true` if this constraint allows [version].
+ bool allows(Version version);
+
+ /// Returns `true` if this constraint allows all the versions that [other]
+ /// allows.
+ bool allowsAll(VersionConstraint other);
+
+ /// Returns `true` if this constraint allows any of the versions that [other]
+ /// allows.
+ bool allowsAny(VersionConstraint other);
+
+ /// Returns a [VersionConstraint] that only allows [Version]s allowed by both
+ /// this and [other].
+ VersionConstraint intersect(VersionConstraint other);
+
+ /// Returns a [VersionConstraint] that allows [Version]s allowed by either
+ /// this or [other].
+ VersionConstraint union(VersionConstraint other);
+
+ /// Returns a [VersionConstraint] that allows [Version]s allowed by this but
+ /// not [other].
+ VersionConstraint difference(VersionConstraint other);
+}
+
+class _EmptyVersion implements VersionConstraint {
+ const _EmptyVersion();
+
+ @override
+ bool get isEmpty => true;
+
+ @override
+ bool get isAny => false;
+
+ @override
+ bool allows(Version other) => false;
+
+ @override
+ bool allowsAll(VersionConstraint other) => other.isEmpty;
+
+ @override
+ bool allowsAny(VersionConstraint other) => false;
+
+ @override
+ VersionConstraint intersect(VersionConstraint other) => this;
+
+ @override
+ VersionConstraint union(VersionConstraint other) => other;
+
+ @override
+ VersionConstraint difference(VersionConstraint other) => this;
+
+ @override
+ String toString() => '<empty>';
+}
diff --git a/pkgs/pub_semver/lib/src/version_range.dart b/pkgs/pub_semver/lib/src/version_range.dart
new file mode 100644
index 0000000..6f2ed54
--- /dev/null
+++ b/pkgs/pub_semver/lib/src/version_range.dart
@@ -0,0 +1,476 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'utils.dart';
+import 'version.dart';
+import 'version_constraint.dart';
+import 'version_union.dart';
+
+/// Constrains versions to a fall within a given range.
+///
+/// If there is a minimum, then this only allows versions that are at that
+/// minimum or greater. If there is a maximum, then only versions less than
+/// that are allowed. In other words, this allows `>= min, < max`.
+///
+/// Version ranges are ordered first by their lower bounds, then by their upper
+/// bounds. For example, `>=1.0.0 <2.0.0` is before `>=1.5.0 <2.0.0` is before
+/// `>=1.5.0 <3.0.0`.
+class VersionRange implements Comparable<VersionRange>, VersionConstraint {
+ /// The minimum end of the range.
+ ///
+ /// If [includeMin] is `true`, this will be the minimum allowed version.
+ /// Otherwise, it will be the highest version below the range that is not
+ /// allowed.
+ ///
+ /// This may be `null` in which case the range has no minimum end and allows
+ /// any version less than the maximum.
+ final Version? min;
+
+ /// The maximum end of the range.
+ ///
+ /// If [includeMax] is `true`, this will be the maximum allowed version.
+ /// Otherwise, it will be the lowest version above the range that is not
+ /// allowed.
+ ///
+ /// This may be `null` in which case the range has no maximum end and allows
+ /// any version greater than the minimum.
+ final Version? max;
+
+ /// If `true` then [min] is allowed by the range.
+ final bool includeMin;
+
+ /// If `true`, then [max] is allowed by the range.
+ final bool includeMax;
+
+ /// Creates a new version range from [min] to [max], either inclusive or
+ /// exclusive.
+ ///
+ /// If it is an error if [min] is greater than [max].
+ ///
+ /// Either [max] or [min] may be omitted to not clamp the range at that end.
+ /// If both are omitted, the range allows all versions.
+ ///
+ /// If [includeMin] is `true`, then the minimum end of the range is inclusive.
+ /// Likewise, passing [includeMax] as `true` makes the upper end inclusive.
+ ///
+ /// If [alwaysIncludeMaxPreRelease] is `true`, this will always include
+ /// pre-release versions of an exclusive [max]. Otherwise, it will use the
+ /// default behavior for pre-release versions of [max].
+ factory VersionRange(
+ {Version? min,
+ Version? max,
+ bool includeMin = false,
+ bool includeMax = false,
+ bool alwaysIncludeMaxPreRelease = false}) {
+ if (min != null && max != null && min > max) {
+ throw ArgumentError(
+ 'Minimum version ("$min") must be less than maximum ("$max").');
+ }
+
+ if (!alwaysIncludeMaxPreRelease &&
+ !includeMax &&
+ max != null &&
+ !max.isPreRelease &&
+ max.build.isEmpty &&
+ (min == null ||
+ !min.isPreRelease ||
+ !equalsWithoutPreRelease(min, max))) {
+ max = max.firstPreRelease;
+ }
+
+ return VersionRange._(min, max, includeMin, includeMax);
+ }
+
+ VersionRange._(this.min, this.max, this.includeMin, this.includeMax);
+
+ @override
+ bool operator ==(Object other) {
+ if (other is! VersionRange) return false;
+
+ return min == other.min &&
+ max == other.max &&
+ includeMin == other.includeMin &&
+ includeMax == other.includeMax;
+ }
+
+ @override
+ int get hashCode =>
+ min.hashCode ^
+ (max.hashCode * 3) ^
+ (includeMin.hashCode * 5) ^
+ (includeMax.hashCode * 7);
+
+ @override
+ bool get isEmpty => false;
+
+ @override
+ bool get isAny => min == null && max == null;
+
+ /// Tests if [other] falls within this version range.
+ @override
+ bool allows(Version other) {
+ if (min != null) {
+ if (other < min!) return false;
+ if (!includeMin && other == min) return false;
+ }
+
+ if (max != null) {
+ if (other > max!) return false;
+ if (!includeMax && other == max) return false;
+ }
+
+ return true;
+ }
+
+ @override
+ bool allowsAll(VersionConstraint other) {
+ if (other.isEmpty) return true;
+ if (other is Version) return allows(other);
+
+ if (other is VersionUnion) {
+ return other.ranges.every(allowsAll);
+ }
+
+ if (other is VersionRange) {
+ return !allowsLower(other, this) && !allowsHigher(other, this);
+ }
+
+ throw ArgumentError('Unknown VersionConstraint type $other.');
+ }
+
+ @override
+ bool allowsAny(VersionConstraint other) {
+ if (other.isEmpty) return false;
+ if (other is Version) return allows(other);
+
+ if (other is VersionUnion) {
+ return other.ranges.any(allowsAny);
+ }
+
+ if (other is VersionRange) {
+ return !strictlyLower(other, this) && !strictlyHigher(other, this);
+ }
+
+ throw ArgumentError('Unknown VersionConstraint type $other.');
+ }
+
+ @override
+ VersionConstraint intersect(VersionConstraint other) {
+ if (other.isEmpty) return other;
+ if (other is VersionUnion) return other.intersect(this);
+
+ // A range and a Version just yields the version if it's in the range.
+ if (other is Version) {
+ return allows(other) ? other : VersionConstraint.empty;
+ }
+
+ if (other is VersionRange) {
+ // Intersect the two ranges.
+ Version? intersectMin;
+ bool intersectIncludeMin;
+ if (allowsLower(this, other)) {
+ if (strictlyLower(this, other)) return VersionConstraint.empty;
+ intersectMin = other.min;
+ intersectIncludeMin = other.includeMin;
+ } else {
+ if (strictlyLower(other, this)) return VersionConstraint.empty;
+ intersectMin = min;
+ intersectIncludeMin = includeMin;
+ }
+
+ Version? intersectMax;
+ bool intersectIncludeMax;
+ if (allowsHigher(this, other)) {
+ intersectMax = other.max;
+ intersectIncludeMax = other.includeMax;
+ } else {
+ intersectMax = max;
+ intersectIncludeMax = includeMax;
+ }
+
+ if (intersectMin == null && intersectMax == null) {
+ // Open range.
+ return VersionRange();
+ }
+
+ // If the range is just a single version.
+ if (intersectMin == intersectMax) {
+ // Because we already verified that the lower range isn't strictly
+ // lower, there must be some overlap.
+ assert(intersectIncludeMin && intersectIncludeMax);
+ return intersectMin!;
+ }
+
+ // If we got here, there is an actual range.
+ return VersionRange(
+ min: intersectMin,
+ max: intersectMax,
+ includeMin: intersectIncludeMin,
+ includeMax: intersectIncludeMax,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ throw ArgumentError('Unknown VersionConstraint type $other.');
+ }
+
+ @override
+ VersionConstraint union(VersionConstraint other) {
+ if (other is Version) {
+ if (allows(other)) return this;
+
+ if (other == min) {
+ return VersionRange(
+ min: min,
+ max: max,
+ includeMin: true,
+ includeMax: includeMax,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ if (other == max) {
+ return VersionRange(
+ min: min,
+ max: max,
+ includeMin: includeMin,
+ includeMax: true,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ return VersionConstraint.unionOf([this, other]);
+ }
+
+ if (other is VersionRange) {
+ // If the two ranges don't overlap, we won't be able to create a single
+ // VersionRange for both of them.
+ var edgesTouch = (max != null &&
+ max == other.min &&
+ (includeMax || other.includeMin)) ||
+ (min != null && min == other.max && (includeMin || other.includeMax));
+ if (!edgesTouch && !allowsAny(other)) {
+ return VersionConstraint.unionOf([this, other]);
+ }
+
+ Version? unionMin;
+ bool unionIncludeMin;
+ if (allowsLower(this, other)) {
+ unionMin = min;
+ unionIncludeMin = includeMin;
+ } else {
+ unionMin = other.min;
+ unionIncludeMin = other.includeMin;
+ }
+
+ Version? unionMax;
+ bool unionIncludeMax;
+ if (allowsHigher(this, other)) {
+ unionMax = max;
+ unionIncludeMax = includeMax;
+ } else {
+ unionMax = other.max;
+ unionIncludeMax = other.includeMax;
+ }
+
+ return VersionRange(
+ min: unionMin,
+ max: unionMax,
+ includeMin: unionIncludeMin,
+ includeMax: unionIncludeMax,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ return VersionConstraint.unionOf([this, other]);
+ }
+
+ @override
+ VersionConstraint difference(VersionConstraint other) {
+ if (other.isEmpty) return this;
+
+ if (other is Version) {
+ if (!allows(other)) return this;
+
+ if (other == min) {
+ if (!includeMin) return this;
+ return VersionRange(
+ min: min,
+ max: max,
+ includeMax: includeMax,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ if (other == max) {
+ if (!includeMax) return this;
+ return VersionRange(
+ min: min,
+ max: max,
+ includeMin: includeMin,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ return VersionUnion.fromRanges([
+ VersionRange(
+ min: min,
+ max: other,
+ includeMin: includeMin,
+ alwaysIncludeMaxPreRelease: true),
+ VersionRange(
+ min: other,
+ max: max,
+ includeMax: includeMax,
+ alwaysIncludeMaxPreRelease: true)
+ ]);
+ } else if (other is VersionRange) {
+ if (!allowsAny(other)) return this;
+
+ VersionRange? before;
+ if (!allowsLower(this, other)) {
+ before = null;
+ } else if (min == other.min) {
+ assert(includeMin && !other.includeMin);
+ assert(min != null);
+ before = min;
+ } else {
+ before = VersionRange(
+ min: min,
+ max: other.min,
+ includeMin: includeMin,
+ includeMax: !other.includeMin,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ VersionRange? after;
+ if (!allowsHigher(this, other)) {
+ after = null;
+ } else if (max == other.max) {
+ assert(includeMax && !other.includeMax);
+ assert(max != null);
+ after = max;
+ } else {
+ after = VersionRange(
+ min: other.max,
+ max: max,
+ includeMin: !other.includeMax,
+ includeMax: includeMax,
+ alwaysIncludeMaxPreRelease: true);
+ }
+
+ if (before == null && after == null) return VersionConstraint.empty;
+ if (before == null) return after!;
+ if (after == null) return before;
+ return VersionUnion.fromRanges([before, after]);
+ } else if (other is VersionUnion) {
+ var ranges = <VersionRange>[];
+ var current = this;
+
+ for (var range in other.ranges) {
+ // Skip any ranges that are strictly lower than [current].
+ if (strictlyLower(range, current)) continue;
+
+ // If we reach a range strictly higher than [current], no more ranges
+ // will be relevant so we can bail early.
+ if (strictlyHigher(range, current)) break;
+
+ var difference = current.difference(range);
+ if (difference.isEmpty) {
+ return VersionConstraint.empty;
+ } else if (difference is VersionUnion) {
+ // If [range] split [current] in half, we only need to continue
+ // checking future ranges against the latter half.
+ assert(difference.ranges.length == 2);
+ ranges.add(difference.ranges.first);
+ current = difference.ranges.last;
+ } else {
+ current = difference as VersionRange;
+ }
+ }
+
+ if (ranges.isEmpty) return current;
+ return VersionUnion.fromRanges(ranges..add(current));
+ }
+
+ throw ArgumentError('Unknown VersionConstraint type $other.');
+ }
+
+ @override
+ int compareTo(VersionRange other) {
+ if (min == null) {
+ if (other.min == null) return _compareMax(other);
+ return -1;
+ } else if (other.min == null) {
+ return 1;
+ }
+
+ var result = min!.compareTo(other.min!);
+ if (result != 0) return result;
+ if (includeMin != other.includeMin) return includeMin ? -1 : 1;
+
+ return _compareMax(other);
+ }
+
+ /// Compares the maximum values of `this` and [other].
+ int _compareMax(VersionRange other) {
+ if (max == null) {
+ if (other.max == null) return 0;
+ return 1;
+ } else if (other.max == null) {
+ return -1;
+ }
+
+ var result = max!.compareTo(other.max!);
+ if (result != 0) return result;
+ if (includeMax != other.includeMax) return includeMax ? 1 : -1;
+ return 0;
+ }
+
+ @override
+ String toString() {
+ var buffer = StringBuffer();
+
+ final min = this.min;
+ if (min != null) {
+ buffer
+ ..write(includeMin ? '>=' : '>')
+ ..write(min);
+ }
+
+ final max = this.max;
+
+ if (max != null) {
+ if (min != null) buffer.write(' ');
+ if (includeMax) {
+ buffer
+ ..write('<=')
+ ..write(max);
+ } else {
+ buffer.write('<');
+ if (max.isFirstPreRelease) {
+ // Since `"<$max"` would parse the same as `"<$max-0"`, we just emit
+ // `<$max` to avoid confusing "-0" suffixes.
+ buffer.write('${max.major}.${max.minor}.${max.patch}');
+ } else {
+ buffer.write(max);
+
+ // If `">=$min <$max"` would parse as `">=$min <$max-0"`, add `-*` to
+ // indicate that actually does allow pre-release versions.
+ var minIsPreReleaseOfMax = min != null &&
+ min.isPreRelease &&
+ equalsWithoutPreRelease(min, max);
+ if (!max.isPreRelease && max.build.isEmpty && !minIsPreReleaseOfMax) {
+ buffer.write('-∞');
+ }
+ }
+ }
+ }
+
+ if (min == null && max == null) buffer.write('any');
+ return buffer.toString();
+ }
+}
+
+class CompatibleWithVersionRange extends VersionRange {
+ CompatibleWithVersionRange(Version version)
+ : super._(version, version.nextBreaking.firstPreRelease, true, false);
+
+ @override
+ String toString() => '^$min';
+}
diff --git a/pkgs/pub_semver/lib/src/version_union.dart b/pkgs/pub_semver/lib/src/version_union.dart
new file mode 100644
index 0000000..844d3b8
--- /dev/null
+++ b/pkgs/pub_semver/lib/src/version_union.dart
@@ -0,0 +1,224 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:collection/collection.dart';
+
+import 'utils.dart';
+import 'version.dart';
+import 'version_constraint.dart';
+import 'version_range.dart';
+
+/// A version constraint representing a union of multiple disjoint version
+/// ranges.
+///
+/// An instance of this will only be created if the version can't be represented
+/// as a non-compound value.
+class VersionUnion implements VersionConstraint {
+ /// The constraints that compose this union.
+ ///
+ /// This list has two invariants:
+ ///
+ /// * Its contents are sorted using the standard ordering of [VersionRange]s.
+ /// * Its contents are disjoint and non-adjacent. In other words, for any two
+ /// constraints next to each other in the list, there's some version between
+ /// those constraints that they don't match.
+ final List<VersionRange> ranges;
+
+ @override
+ bool get isEmpty => false;
+
+ @override
+ bool get isAny => false;
+
+ /// Creates a union from a list of ranges with no pre-processing.
+ ///
+ /// It's up to the caller to ensure that the invariants described in [ranges]
+ /// are maintained. They are not verified by this constructor. To
+ /// automatically ensure that they're maintained, use
+ /// [VersionConstraint.unionOf] instead.
+ VersionUnion.fromRanges(this.ranges);
+
+ @override
+ bool allows(Version version) =>
+ ranges.any((constraint) => constraint.allows(version));
+
+ @override
+ bool allowsAll(VersionConstraint other) {
+ var ourRanges = ranges.iterator;
+ var theirRanges = _rangesFor(other).iterator;
+
+ // Because both lists of ranges are ordered by minimum version, we can
+ // safely move through them linearly here.
+ var ourRangesMoved = ourRanges.moveNext();
+ var theirRangesMoved = theirRanges.moveNext();
+ while (ourRangesMoved && theirRangesMoved) {
+ if (ourRanges.current.allowsAll(theirRanges.current)) {
+ theirRangesMoved = theirRanges.moveNext();
+ } else {
+ ourRangesMoved = ourRanges.moveNext();
+ }
+ }
+
+ // If our ranges have allowed all of their ranges, we'll have consumed all
+ // of them.
+ return !theirRangesMoved;
+ }
+
+ @override
+ bool allowsAny(VersionConstraint other) {
+ var ourRanges = ranges.iterator;
+ var theirRanges = _rangesFor(other).iterator;
+
+ // Because both lists of ranges are ordered by minimum version, we can
+ // safely move through them linearly here.
+ var ourRangesMoved = ourRanges.moveNext();
+ var theirRangesMoved = theirRanges.moveNext();
+ while (ourRangesMoved && theirRangesMoved) {
+ if (ourRanges.current.allowsAny(theirRanges.current)) {
+ return true;
+ }
+
+ // Move the constraint with the lower max value forward. This ensures that
+ // we keep both lists in sync as much as possible.
+ if (allowsHigher(theirRanges.current, ourRanges.current)) {
+ ourRangesMoved = ourRanges.moveNext();
+ } else {
+ theirRangesMoved = theirRanges.moveNext();
+ }
+ }
+
+ return false;
+ }
+
+ @override
+ VersionConstraint intersect(VersionConstraint other) {
+ var ourRanges = ranges.iterator;
+ var theirRanges = _rangesFor(other).iterator;
+
+ // Because both lists of ranges are ordered by minimum version, we can
+ // safely move through them linearly here.
+ var newRanges = <VersionRange>[];
+ var ourRangesMoved = ourRanges.moveNext();
+ var theirRangesMoved = theirRanges.moveNext();
+ while (ourRangesMoved && theirRangesMoved) {
+ var intersection = ourRanges.current.intersect(theirRanges.current);
+
+ if (!intersection.isEmpty) newRanges.add(intersection as VersionRange);
+
+ // Move the constraint with the lower max value forward. This ensures that
+ // we keep both lists in sync as much as possible, and that large ranges
+ // have a chance to match multiple small ranges that they contain.
+ if (allowsHigher(theirRanges.current, ourRanges.current)) {
+ ourRangesMoved = ourRanges.moveNext();
+ } else {
+ theirRangesMoved = theirRanges.moveNext();
+ }
+ }
+
+ if (newRanges.isEmpty) return VersionConstraint.empty;
+ if (newRanges.length == 1) return newRanges.single;
+
+ return VersionUnion.fromRanges(newRanges);
+ }
+
+ @override
+ VersionConstraint difference(VersionConstraint other) {
+ var ourRanges = ranges.iterator;
+ var theirRanges = _rangesFor(other).iterator;
+
+ var newRanges = <VersionRange>[];
+ ourRanges.moveNext();
+ theirRanges.moveNext();
+ var current = ourRanges.current;
+
+ bool theirNextRange() {
+ if (theirRanges.moveNext()) return true;
+
+ // If there are no more of their ranges, none of the rest of our ranges
+ // need to be subtracted so we can add them as-is.
+ newRanges.add(current);
+ while (ourRanges.moveNext()) {
+ newRanges.add(ourRanges.current);
+ }
+ return false;
+ }
+
+ bool ourNextRange({bool includeCurrent = true}) {
+ if (includeCurrent) newRanges.add(current);
+ if (!ourRanges.moveNext()) return false;
+ current = ourRanges.current;
+ return true;
+ }
+
+ for (;;) {
+ // If the current ranges are disjoint, move the lowest one forward.
+ if (strictlyLower(theirRanges.current, current)) {
+ if (!theirNextRange()) break;
+ continue;
+ }
+
+ if (strictlyHigher(theirRanges.current, current)) {
+ if (!ourNextRange()) break;
+ continue;
+ }
+
+ // If we're here, we know [theirRanges.current] overlaps [current].
+ var difference = current.difference(theirRanges.current);
+ if (difference is VersionUnion) {
+ // If their range split [current] in half, we only need to continue
+ // checking future ranges against the latter half.
+ assert(difference.ranges.length == 2);
+ newRanges.add(difference.ranges.first);
+ current = difference.ranges.last;
+
+ // Since their range split [current], it definitely doesn't allow higher
+ // versions, so we should move their ranges forward.
+ if (!theirNextRange()) break;
+ } else if (difference.isEmpty) {
+ if (!ourNextRange(includeCurrent: false)) break;
+ } else {
+ current = difference as VersionRange;
+
+ // Move the constraint with the lower max value forward. This ensures
+ // that we keep both lists in sync as much as possible, and that large
+ // ranges have a chance to subtract or be subtracted by multiple small
+ // ranges that they contain.
+ if (allowsHigher(current, theirRanges.current)) {
+ if (!theirNextRange()) break;
+ } else {
+ if (!ourNextRange()) break;
+ }
+ }
+ }
+
+ if (newRanges.isEmpty) return VersionConstraint.empty;
+ if (newRanges.length == 1) return newRanges.single;
+ return VersionUnion.fromRanges(newRanges);
+ }
+
+ /// Returns [constraint] as a list of ranges.
+ ///
+ /// This is used to normalize ranges of various types.
+ List<VersionRange> _rangesFor(VersionConstraint constraint) {
+ if (constraint.isEmpty) return [];
+ if (constraint is VersionUnion) return constraint.ranges;
+ if (constraint is VersionRange) return [constraint];
+ throw ArgumentError('Unknown VersionConstraint type $constraint.');
+ }
+
+ @override
+ VersionConstraint union(VersionConstraint other) =>
+ VersionConstraint.unionOf([this, other]);
+
+ @override
+ bool operator ==(Object other) =>
+ other is VersionUnion &&
+ const ListEquality<VersionRange>().equals(ranges, other.ranges);
+
+ @override
+ int get hashCode => const ListEquality<VersionRange>().hash(ranges);
+
+ @override
+ String toString() => ranges.join(' or ');
+}
diff --git a/pkgs/pub_semver/pubspec.yaml b/pkgs/pub_semver/pubspec.yaml
new file mode 100644
index 0000000..290fb92
--- /dev/null
+++ b/pkgs/pub_semver/pubspec.yaml
@@ -0,0 +1,20 @@
+name: pub_semver
+version: 2.1.5
+description: >-
+ Versions and version constraints implementing pub's versioning policy. This
+ is very similar to vanilla semver, with a few corner cases.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/pub_semver
+topics:
+ - dart-pub
+ - semver
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ collection: ^1.15.0
+ meta: ^1.3.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.0
diff --git a/pkgs/pub_semver/test/utils.dart b/pkgs/pub_semver/test/utils.dart
new file mode 100644
index 0000000..bd7aa8f
--- /dev/null
+++ b/pkgs/pub_semver/test/utils.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:pub_semver/pub_semver.dart';
+import 'package:test/test.dart';
+
+/// Some stock example versions to use in tests.
+final v003 = Version.parse('0.0.3');
+final v010 = Version.parse('0.1.0');
+final v072 = Version.parse('0.7.2');
+final v080 = Version.parse('0.8.0');
+final v114 = Version.parse('1.1.4');
+final v123 = Version.parse('1.2.3');
+final v124 = Version.parse('1.2.4');
+final v130 = Version.parse('1.3.0');
+final v140 = Version.parse('1.4.0');
+final v200 = Version.parse('2.0.0');
+final v201 = Version.parse('2.0.1');
+final v234 = Version.parse('2.3.4');
+final v250 = Version.parse('2.5.0');
+final v300 = Version.parse('3.0.0');
+
+/// A range that allows pre-release versions of its max version.
+final includeMaxPreReleaseRange =
+ VersionRange(max: v200, alwaysIncludeMaxPreRelease: true);
+
+/// A [Matcher] that tests if a [VersionConstraint] allows or does not allow a
+/// given list of [Version]s.
+class _VersionConstraintMatcher implements Matcher {
+ final List<Version> _expected;
+ final bool _allow;
+
+ _VersionConstraintMatcher(this._expected, this._allow);
+
+ @override
+ bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
+ (item is VersionConstraint) &&
+ _expected.every((version) => item.allows(version) == _allow);
+
+ @override
+ Description describe(Description description) {
+ description.addAll(' ${_allow ? "allows" : "does not allow"} versions ',
+ ', ', '', _expected);
+ return description;
+ }
+
+ @override
+ Description describeMismatch(dynamic item, Description mismatchDescription,
+ Map<dynamic, dynamic> matchState, bool verbose) {
+ if (item is! VersionConstraint) {
+ mismatchDescription.add('was not a VersionConstraint');
+ return mismatchDescription;
+ }
+
+ var first = true;
+ for (var version in _expected) {
+ if (item.allows(version) != _allow) {
+ if (first) {
+ if (_allow) {
+ mismatchDescription.addDescriptionOf(item).add(' did not allow ');
+ } else {
+ mismatchDescription.addDescriptionOf(item).add(' allowed ');
+ }
+ } else {
+ mismatchDescription.add(' and ');
+ }
+ first = false;
+
+ mismatchDescription.add(version.toString());
+ }
+ }
+
+ return mismatchDescription;
+ }
+}
+
+/// Gets a [Matcher] that validates that a [VersionConstraint] allows all
+/// given versions.
+Matcher allows(Version v1,
+ [Version? v2,
+ Version? v3,
+ Version? v4,
+ Version? v5,
+ Version? v6,
+ Version? v7,
+ Version? v8]) {
+ var versions = _makeVersionList(v1, v2, v3, v4, v5, v6, v7, v8);
+ return _VersionConstraintMatcher(versions, true);
+}
+
+/// Gets a [Matcher] that validates that a [VersionConstraint] allows none of
+/// the given versions.
+Matcher doesNotAllow(Version v1,
+ [Version? v2,
+ Version? v3,
+ Version? v4,
+ Version? v5,
+ Version? v6,
+ Version? v7,
+ Version? v8]) {
+ var versions = _makeVersionList(v1, v2, v3, v4, v5, v6, v7, v8);
+ return _VersionConstraintMatcher(versions, false);
+}
+
+List<Version> _makeVersionList(Version v1,
+ [Version? v2,
+ Version? v3,
+ Version? v4,
+ Version? v5,
+ Version? v6,
+ Version? v7,
+ Version? v8]) {
+ var versions = [v1];
+ if (v2 != null) versions.add(v2);
+ if (v3 != null) versions.add(v3);
+ if (v4 != null) versions.add(v4);
+ if (v5 != null) versions.add(v5);
+ if (v6 != null) versions.add(v6);
+ if (v7 != null) versions.add(v7);
+ if (v8 != null) versions.add(v8);
+ return versions;
+}
diff --git a/pkgs/pub_semver/test/version_constraint_test.dart b/pkgs/pub_semver/test/version_constraint_test.dart
new file mode 100644
index 0000000..4fbcbe0
--- /dev/null
+++ b/pkgs/pub_semver/test/version_constraint_test.dart
@@ -0,0 +1,185 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:pub_semver/pub_semver.dart';
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ test('any', () {
+ expect(VersionConstraint.any.isAny, isTrue);
+ expect(
+ VersionConstraint.any,
+ allows(Version.parse('0.0.0-blah'), Version.parse('1.2.3'),
+ Version.parse('12345.678.90')));
+ });
+
+ test('empty', () {
+ expect(VersionConstraint.empty.isEmpty, isTrue);
+ expect(VersionConstraint.empty.isAny, isFalse);
+ expect(
+ VersionConstraint.empty,
+ doesNotAllow(Version.parse('0.0.0-blah'), Version.parse('1.2.3'),
+ Version.parse('12345.678.90')));
+ });
+
+ group('parse()', () {
+ test('parses an exact version', () {
+ var constraint = VersionConstraint.parse('1.2.3-alpha');
+
+ expect(constraint is Version, isTrue);
+ expect(constraint, equals(Version(1, 2, 3, pre: 'alpha')));
+ });
+
+ test('parses "any"', () {
+ var constraint = VersionConstraint.parse('any');
+
+ expect(
+ constraint,
+ allows(Version.parse('0.0.0'), Version.parse('1.2.3'),
+ Version.parse('12345.678.90')));
+ });
+
+ test('parses a ">" minimum version', () {
+ var constraint = VersionConstraint.parse('>1.2.3');
+
+ expect(constraint,
+ allows(Version.parse('1.2.3+foo'), Version.parse('1.2.4')));
+ expect(
+ constraint,
+ doesNotAllow(Version.parse('1.2.1'), Version.parse('1.2.3-build'),
+ Version.parse('1.2.3')));
+ });
+
+ test('parses a ">=" minimum version', () {
+ var constraint = VersionConstraint.parse('>=1.2.3');
+
+ expect(
+ constraint,
+ allows(Version.parse('1.2.3'), Version.parse('1.2.3+foo'),
+ Version.parse('1.2.4')));
+ expect(constraint,
+ doesNotAllow(Version.parse('1.2.1'), Version.parse('1.2.3-build')));
+ });
+
+ test('parses a "<" maximum version', () {
+ var constraint = VersionConstraint.parse('<1.2.3');
+
+ expect(constraint,
+ allows(Version.parse('1.2.1'), Version.parse('1.2.2+foo')));
+ expect(
+ constraint,
+ doesNotAllow(Version.parse('1.2.3'), Version.parse('1.2.3+foo'),
+ Version.parse('1.2.4')));
+ });
+
+ test('parses a "<=" maximum version', () {
+ var constraint = VersionConstraint.parse('<=1.2.3');
+
+ expect(
+ constraint,
+ allows(Version.parse('1.2.1'), Version.parse('1.2.3-build'),
+ Version.parse('1.2.3')));
+ expect(constraint,
+ doesNotAllow(Version.parse('1.2.3+foo'), Version.parse('1.2.4')));
+ });
+
+ test('parses a series of space-separated constraints', () {
+ var constraint = VersionConstraint.parse('>1.0.0 >=1.2.3 <1.3.0');
+
+ expect(
+ constraint, allows(Version.parse('1.2.3'), Version.parse('1.2.5')));
+ expect(
+ constraint,
+ doesNotAllow(Version.parse('1.2.3-pre'), Version.parse('1.3.0'),
+ Version.parse('3.4.5')));
+ });
+
+ test('parses a pre-release-only constraint', () {
+ var constraint = VersionConstraint.parse('>=1.0.0-dev.2 <1.0.0');
+ expect(constraint,
+ allows(Version.parse('1.0.0-dev.2'), Version.parse('1.0.0-dev.3')));
+ expect(constraint,
+ doesNotAllow(Version.parse('1.0.0-dev.1'), Version.parse('1.0.0')));
+ });
+
+ test('ignores whitespace around comparison operators', () {
+ var constraint = VersionConstraint.parse(' >1.0.0>=1.2.3 < 1.3.0');
+
+ expect(
+ constraint, allows(Version.parse('1.2.3'), Version.parse('1.2.5')));
+ expect(
+ constraint,
+ doesNotAllow(Version.parse('1.2.3-pre'), Version.parse('1.3.0'),
+ Version.parse('3.4.5')));
+ });
+
+ test('does not allow "any" to be mixed with other constraints', () {
+ expect(() => VersionConstraint.parse('any 1.0.0'), throwsFormatException);
+ });
+
+ test('parses a "^" version', () {
+ expect(VersionConstraint.parse('^0.0.3'),
+ equals(VersionConstraint.compatibleWith(v003)));
+
+ expect(VersionConstraint.parse('^0.7.2'),
+ equals(VersionConstraint.compatibleWith(v072)));
+
+ expect(VersionConstraint.parse('^1.2.3'),
+ equals(VersionConstraint.compatibleWith(v123)));
+
+ var min = Version.parse('0.7.2-pre+1');
+ expect(VersionConstraint.parse('^0.7.2-pre+1'),
+ equals(VersionConstraint.compatibleWith(min)));
+ });
+
+ test('does not allow "^" to be mixed with other constraints', () {
+ expect(() => VersionConstraint.parse('>=1.2.3 ^1.0.0'),
+ throwsFormatException);
+ expect(() => VersionConstraint.parse('^1.0.0 <1.2.3'),
+ throwsFormatException);
+ });
+
+ test('ignores whitespace around "^"', () {
+ var constraint = VersionConstraint.parse(' ^ 1.2.3 ');
+
+ expect(constraint, equals(VersionConstraint.compatibleWith(v123)));
+ });
+
+ test('throws FormatException on a bad string', () {
+ var bad = [
+ '', ' ', // Empty string.
+ 'foo', // Bad text.
+ '>foo', // Bad text after operator.
+ '^foo', // Bad text after "^".
+ '1.0.0 foo', '1.0.0foo', // Bad text after version.
+ 'anything', // Bad text after "any".
+ '<>1.0.0', // Multiple operators.
+ '1.0.0<' // Trailing operator.
+ ];
+
+ for (var text in bad) {
+ expect(() => VersionConstraint.parse(text), throwsFormatException);
+ }
+ });
+ });
+
+ group('compatibleWith()', () {
+ test('returns the range of compatible versions', () {
+ var constraint = VersionConstraint.compatibleWith(v072);
+
+ expect(
+ constraint,
+ equals(VersionRange(
+ min: v072, includeMin: true, max: v072.nextBreaking)));
+ });
+
+ test('toString() uses "^"', () {
+ var constraint = VersionConstraint.compatibleWith(v072);
+
+ expect(constraint.toString(), equals('^0.7.2'));
+ });
+ });
+}
diff --git a/pkgs/pub_semver/test/version_range_test.dart b/pkgs/pub_semver/test/version_range_test.dart
new file mode 100644
index 0000000..5978df0
--- /dev/null
+++ b/pkgs/pub_semver/test/version_range_test.dart
@@ -0,0 +1,998 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:pub_semver/pub_semver.dart';
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ group('constructor', () {
+ test('takes a min and max', () {
+ var range = VersionRange(min: v123, max: v124);
+ expect(range.isAny, isFalse);
+ expect(range.min, equals(v123));
+ expect(range.max, equals(v124.firstPreRelease));
+ });
+
+ group("doesn't make the max a pre-release if", () {
+ test("it's already a pre-release", () {
+ expect(VersionRange(max: Version.parse('1.2.4-pre')).max,
+ equals(Version.parse('1.2.4-pre')));
+ });
+
+ test('includeMax is true', () {
+ expect(VersionRange(max: v124, includeMax: true).max, equals(v124));
+ });
+
+ test('min is a prerelease of max', () {
+ expect(VersionRange(min: Version.parse('1.2.4-pre'), max: v124).max,
+ equals(v124));
+ });
+
+ test('max has a build identifier', () {
+ expect(VersionRange(max: Version.parse('1.2.4+1')).max,
+ equals(Version.parse('1.2.4+1')));
+ });
+ });
+
+ test('allows omitting max', () {
+ var range = VersionRange(min: v123);
+ expect(range.isAny, isFalse);
+ expect(range.min, equals(v123));
+ expect(range.max, isNull);
+ });
+
+ test('allows omitting min and max', () {
+ var range = VersionRange();
+ expect(range.isAny, isTrue);
+ expect(range.min, isNull);
+ expect(range.max, isNull);
+ });
+
+ test('takes includeMin', () {
+ var range = VersionRange(min: v123, includeMin: true);
+ expect(range.includeMin, isTrue);
+ });
+
+ test('includeMin defaults to false if omitted', () {
+ var range = VersionRange(min: v123);
+ expect(range.includeMin, isFalse);
+ });
+
+ test('takes includeMax', () {
+ var range = VersionRange(max: v123, includeMax: true);
+ expect(range.includeMax, isTrue);
+ });
+
+ test('includeMax defaults to false if omitted', () {
+ var range = VersionRange(max: v123);
+ expect(range.includeMax, isFalse);
+ });
+
+ test('throws if min > max', () {
+ expect(() => VersionRange(min: v124, max: v123), throwsArgumentError);
+ });
+ });
+
+ group('allows()', () {
+ test('version must be greater than min', () {
+ var range = VersionRange(min: v123);
+
+ expect(range, allows(Version.parse('1.3.3'), Version.parse('2.3.3')));
+ expect(
+ range, doesNotAllow(Version.parse('1.2.2'), Version.parse('1.2.3')));
+ });
+
+ test('version must be min or greater if includeMin', () {
+ var range = VersionRange(min: v123, includeMin: true);
+
+ expect(
+ range,
+ allows(Version.parse('1.2.3'), Version.parse('1.3.3'),
+ Version.parse('2.3.3')));
+ expect(range, doesNotAllow(Version.parse('1.2.2')));
+ });
+
+ test('pre-release versions of inclusive min are excluded', () {
+ var range = VersionRange(min: v123, includeMin: true);
+
+ expect(range, allows(Version.parse('1.2.4-dev')));
+ expect(range, doesNotAllow(Version.parse('1.2.3-dev')));
+ });
+
+ test('version must be less than max', () {
+ var range = VersionRange(max: v234);
+
+ expect(range, allows(Version.parse('2.3.3')));
+ expect(
+ range, doesNotAllow(Version.parse('2.3.4'), Version.parse('2.4.3')));
+ });
+
+ test('pre-release versions of non-pre-release max are excluded', () {
+ var range = VersionRange(max: v234);
+
+ expect(range, allows(Version.parse('2.3.3')));
+ expect(range,
+ doesNotAllow(Version.parse('2.3.4-dev'), Version.parse('2.3.4')));
+ });
+
+ test(
+ 'pre-release versions of non-pre-release max are included if min is a '
+ 'pre-release of the same version', () {
+ var range = VersionRange(min: Version.parse('2.3.4-dev.0'), max: v234);
+
+ expect(range, allows(Version.parse('2.3.4-dev.1')));
+ expect(
+ range,
+ doesNotAllow(Version.parse('2.3.3'), Version.parse('2.3.4-dev'),
+ Version.parse('2.3.4')));
+ });
+
+ test('pre-release versions of pre-release max are included', () {
+ var range = VersionRange(max: Version.parse('2.3.4-dev.2'));
+
+ expect(range, allows(Version.parse('2.3.4-dev.1')));
+ expect(
+ range,
+ doesNotAllow(
+ Version.parse('2.3.4-dev.2'), Version.parse('2.3.4-dev.3')));
+ });
+
+ test('version must be max or less if includeMax', () {
+ var range = VersionRange(min: v123, max: v234, includeMax: true);
+
+ expect(
+ range,
+ allows(
+ Version.parse('2.3.3'),
+ Version.parse('2.3.4'),
+ // Pre-releases of the max are allowed.
+ Version.parse('2.3.4-dev')));
+ expect(range, doesNotAllow(Version.parse('2.4.3')));
+ });
+
+ test('has no min if one was not set', () {
+ var range = VersionRange(max: v123);
+
+ expect(range, allows(Version.parse('0.0.0')));
+ expect(range, doesNotAllow(Version.parse('1.2.3')));
+ });
+
+ test('has no max if one was not set', () {
+ var range = VersionRange(min: v123);
+
+ expect(range, allows(Version.parse('1.3.3'), Version.parse('999.3.3')));
+ expect(range, doesNotAllow(Version.parse('1.2.3')));
+ });
+
+ test('allows any version if there is no min or max', () {
+ var range = VersionRange();
+
+ expect(range, allows(Version.parse('0.0.0'), Version.parse('999.99.9')));
+ });
+
+ test('allows pre-releases of the max with includeMaxPreRelease', () {
+ expect(includeMaxPreReleaseRange, allows(Version.parse('2.0.0-dev')));
+ });
+ });
+
+ group('allowsAll()', () {
+ test('allows an empty constraint', () {
+ expect(
+ VersionRange(min: v123, max: v250).allowsAll(VersionConstraint.empty),
+ isTrue);
+ });
+
+ test('allows allowed versions', () {
+ var range = VersionRange(min: v123, max: v250, includeMax: true);
+ expect(range.allowsAll(v123), isFalse);
+ expect(range.allowsAll(v124), isTrue);
+ expect(range.allowsAll(v250), isTrue);
+ expect(range.allowsAll(v300), isFalse);
+ });
+
+ test('with no min', () {
+ var range = VersionRange(max: v250);
+ expect(range.allowsAll(VersionRange(min: v080, max: v140)), isTrue);
+ expect(range.allowsAll(VersionRange(min: v080, max: v300)), isFalse);
+ expect(range.allowsAll(VersionRange(max: v140)), isTrue);
+ expect(range.allowsAll(VersionRange(max: v300)), isFalse);
+ expect(range.allowsAll(range), isTrue);
+ expect(range.allowsAll(VersionConstraint.any), isFalse);
+ });
+
+ test('with no max', () {
+ var range = VersionRange(min: v010);
+ expect(range.allowsAll(VersionRange(min: v080, max: v140)), isTrue);
+ expect(range.allowsAll(VersionRange(min: v003, max: v140)), isFalse);
+ expect(range.allowsAll(VersionRange(min: v080)), isTrue);
+ expect(range.allowsAll(VersionRange(min: v003)), isFalse);
+ expect(range.allowsAll(range), isTrue);
+ expect(range.allowsAll(VersionConstraint.any), isFalse);
+ });
+
+ test('with a min and max', () {
+ var range = VersionRange(min: v010, max: v250);
+ expect(range.allowsAll(VersionRange(min: v080, max: v140)), isTrue);
+ expect(range.allowsAll(VersionRange(min: v080, max: v300)), isFalse);
+ expect(range.allowsAll(VersionRange(min: v003, max: v140)), isFalse);
+ expect(range.allowsAll(VersionRange(min: v080)), isFalse);
+ expect(range.allowsAll(VersionRange(max: v140)), isFalse);
+ expect(range.allowsAll(range), isTrue);
+ });
+
+ test("allows a bordering range that's not more inclusive", () {
+ var exclusive = VersionRange(min: v010, max: v250);
+ var inclusive = VersionRange(
+ min: v010, includeMin: true, max: v250, includeMax: true);
+ expect(inclusive.allowsAll(exclusive), isTrue);
+ expect(inclusive.allowsAll(inclusive), isTrue);
+ expect(exclusive.allowsAll(inclusive), isFalse);
+ expect(exclusive.allowsAll(exclusive), isTrue);
+ });
+
+ test('allows unions that are completely contained', () {
+ var range = VersionRange(min: v114, max: v200);
+ expect(range.allowsAll(VersionRange(min: v123, max: v124).union(v140)),
+ isTrue);
+ expect(range.allowsAll(VersionRange(min: v010, max: v124).union(v140)),
+ isFalse);
+ expect(range.allowsAll(VersionRange(min: v123, max: v234).union(v140)),
+ isFalse);
+ });
+
+ group('pre-release versions', () {
+ test('of inclusive min are excluded', () {
+ var range = VersionRange(min: v123, includeMin: true);
+
+ expect(range.allowsAll(VersionConstraint.parse('>1.2.4-dev')), isTrue);
+ expect(range.allowsAll(VersionConstraint.parse('>1.2.3-dev')), isFalse);
+ });
+
+ test('of non-pre-release max are excluded', () {
+ var range = VersionRange(max: v234);
+
+ expect(range.allowsAll(VersionConstraint.parse('<2.3.3')), isTrue);
+ expect(range.allowsAll(VersionConstraint.parse('<2.3.4-dev')), isFalse);
+ });
+
+ test('of non-pre-release max are included with includeMaxPreRelease', () {
+ expect(
+ includeMaxPreReleaseRange
+ .allowsAll(VersionConstraint.parse('<2.0.0-dev')),
+ isTrue);
+ });
+
+ test(
+ 'of non-pre-release max are included if min is a pre-release of the '
+ 'same version', () {
+ var range = VersionRange(min: Version.parse('2.3.4-dev.0'), max: v234);
+
+ expect(
+ range.allowsAll(
+ VersionConstraint.parse('>2.3.4-dev.0 <2.3.4-dev.1')),
+ isTrue);
+ });
+
+ test('of pre-release max are included', () {
+ var range = VersionRange(max: Version.parse('2.3.4-dev.2'));
+
+ expect(
+ range.allowsAll(VersionConstraint.parse('<2.3.4-dev.1')), isTrue);
+ expect(
+ range.allowsAll(VersionConstraint.parse('<2.3.4-dev.2')), isTrue);
+ expect(
+ range.allowsAll(VersionConstraint.parse('<=2.3.4-dev.2')), isFalse);
+ expect(
+ range.allowsAll(VersionConstraint.parse('<2.3.4-dev.3')), isFalse);
+ });
+ });
+ });
+
+ group('allowsAny()', () {
+ test('disallows an empty constraint', () {
+ expect(
+ VersionRange(min: v123, max: v250).allowsAny(VersionConstraint.empty),
+ isFalse);
+ });
+
+ test('allows allowed versions', () {
+ var range = VersionRange(min: v123, max: v250, includeMax: true);
+ expect(range.allowsAny(v123), isFalse);
+ expect(range.allowsAny(v124), isTrue);
+ expect(range.allowsAny(v250), isTrue);
+ expect(range.allowsAny(v300), isFalse);
+ });
+
+ test('with no min', () {
+ var range = VersionRange(max: v200);
+ expect(range.allowsAny(VersionRange(min: v140, max: v300)), isTrue);
+ expect(range.allowsAny(VersionRange(min: v234, max: v300)), isFalse);
+ expect(range.allowsAny(VersionRange(min: v140)), isTrue);
+ expect(range.allowsAny(VersionRange(min: v234)), isFalse);
+ expect(range.allowsAny(range), isTrue);
+ });
+
+ test('with no max', () {
+ var range = VersionRange(min: v072);
+ expect(range.allowsAny(VersionRange(min: v003, max: v140)), isTrue);
+ expect(range.allowsAny(VersionRange(min: v003, max: v010)), isFalse);
+ expect(range.allowsAny(VersionRange(max: v080)), isTrue);
+ expect(range.allowsAny(VersionRange(max: v003)), isFalse);
+ expect(range.allowsAny(range), isTrue);
+ });
+
+ test('with a min and max', () {
+ var range = VersionRange(min: v072, max: v200);
+ expect(range.allowsAny(VersionRange(min: v003, max: v140)), isTrue);
+ expect(range.allowsAny(VersionRange(min: v140, max: v300)), isTrue);
+ expect(range.allowsAny(VersionRange(min: v003, max: v010)), isFalse);
+ expect(range.allowsAny(VersionRange(min: v234, max: v300)), isFalse);
+ expect(range.allowsAny(VersionRange(max: v010)), isFalse);
+ expect(range.allowsAny(VersionRange(min: v234)), isFalse);
+ expect(range.allowsAny(range), isTrue);
+ });
+
+ test('allows a bordering range when both are inclusive', () {
+ expect(
+ VersionRange(max: v250).allowsAny(VersionRange(min: v250)), isFalse);
+
+ expect(
+ VersionRange(max: v250, includeMax: true)
+ .allowsAny(VersionRange(min: v250)),
+ isFalse);
+
+ expect(
+ VersionRange(max: v250)
+ .allowsAny(VersionRange(min: v250, includeMin: true)),
+ isFalse);
+
+ expect(
+ VersionRange(max: v250, includeMax: true)
+ .allowsAny(VersionRange(min: v250, includeMin: true)),
+ isTrue);
+
+ expect(
+ VersionRange(min: v250).allowsAny(VersionRange(max: v250)), isFalse);
+
+ expect(
+ VersionRange(min: v250, includeMin: true)
+ .allowsAny(VersionRange(max: v250)),
+ isFalse);
+
+ expect(
+ VersionRange(min: v250)
+ .allowsAny(VersionRange(max: v250, includeMax: true)),
+ isFalse);
+
+ expect(
+ VersionRange(min: v250, includeMin: true)
+ .allowsAny(VersionRange(max: v250, includeMax: true)),
+ isTrue);
+ });
+
+ test('allows unions that are partially contained', () {
+ var range = VersionRange(min: v114, max: v200);
+ expect(range.allowsAny(VersionRange(min: v010, max: v080).union(v140)),
+ isTrue);
+ expect(range.allowsAny(VersionRange(min: v123, max: v234).union(v300)),
+ isTrue);
+ expect(range.allowsAny(VersionRange(min: v234, max: v300).union(v010)),
+ isFalse);
+ });
+
+ group('pre-release versions', () {
+ test('of inclusive min are excluded', () {
+ var range = VersionRange(min: v123, includeMin: true);
+
+ expect(range.allowsAny(VersionConstraint.parse('<1.2.4-dev')), isTrue);
+ expect(range.allowsAny(VersionConstraint.parse('<1.2.3-dev')), isFalse);
+ });
+
+ test('of non-pre-release max are excluded', () {
+ var range = VersionRange(max: v234);
+
+ expect(range.allowsAny(VersionConstraint.parse('>2.3.3')), isTrue);
+ expect(range.allowsAny(VersionConstraint.parse('>2.3.4-dev')), isFalse);
+ });
+
+ test('of non-pre-release max are included with includeMaxPreRelease', () {
+ expect(
+ includeMaxPreReleaseRange
+ .allowsAny(VersionConstraint.parse('>2.0.0-dev')),
+ isTrue);
+ });
+
+ test(
+ 'of non-pre-release max are included if min is a pre-release of the '
+ 'same version', () {
+ var range = VersionRange(min: Version.parse('2.3.4-dev.0'), max: v234);
+
+ expect(
+ range.allowsAny(VersionConstraint.parse('>2.3.4-dev.1')), isTrue);
+ expect(range.allowsAny(VersionConstraint.parse('>2.3.4')), isFalse);
+
+ expect(
+ range.allowsAny(VersionConstraint.parse('<2.3.4-dev.1')), isTrue);
+ expect(range.allowsAny(VersionConstraint.parse('<2.3.4-dev')), isFalse);
+ });
+
+ test('of pre-release max are included', () {
+ var range = VersionConstraint.parse('<2.3.4-dev.2');
+
+ expect(
+ range.allowsAny(VersionConstraint.parse('>2.3.4-dev.1')), isTrue);
+ expect(
+ range.allowsAny(VersionConstraint.parse('>2.3.4-dev.2')), isFalse);
+ expect(
+ range.allowsAny(VersionConstraint.parse('>2.3.4-dev.3')), isFalse);
+ });
+ });
+ });
+
+ group('intersect()', () {
+ test('two overlapping ranges', () {
+ expect(
+ VersionRange(min: v123, max: v250)
+ .intersect(VersionRange(min: v200, max: v300)),
+ equals(VersionRange(min: v200, max: v250)));
+ });
+
+ test('a non-overlapping range allows no versions', () {
+ var a = VersionRange(min: v114, max: v124);
+ var b = VersionRange(min: v200, max: v250);
+ expect(a.intersect(b).isEmpty, isTrue);
+ });
+
+ test('adjacent ranges allow no versions if exclusive', () {
+ var a = VersionRange(min: v114, max: v124);
+ var b = VersionRange(min: v124, max: v200);
+ expect(a.intersect(b).isEmpty, isTrue);
+ });
+
+ test('adjacent ranges allow version if inclusive', () {
+ var a = VersionRange(min: v114, max: v124, includeMax: true);
+ var b = VersionRange(min: v124, max: v200, includeMin: true);
+ expect(a.intersect(b), equals(v124));
+ });
+
+ test('with an open range', () {
+ var open = VersionRange();
+ var a = VersionRange(min: v114, max: v124);
+ expect(open.intersect(open), equals(open));
+ expect(a.intersect(open), equals(a));
+ });
+
+ test('returns the version if the range allows it', () {
+ expect(VersionRange(min: v114, max: v124).intersect(v123), equals(v123));
+ expect(
+ VersionRange(min: v123, max: v124).intersect(v114).isEmpty, isTrue);
+ });
+
+ test('with a range with a pre-release min, returns an empty constraint',
+ () {
+ expect(
+ VersionRange(max: v200)
+ .intersect(VersionConstraint.parse('>=2.0.0-dev')),
+ equals(VersionConstraint.empty));
+ });
+
+ test('with a range with a pre-release max, returns the original', () {
+ expect(
+ VersionRange(max: v200)
+ .intersect(VersionConstraint.parse('<2.0.0-dev')),
+ equals(VersionRange(max: v200)));
+ });
+
+ group('with includeMaxPreRelease', () {
+ test('preserves includeMaxPreRelease if the max version is included', () {
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(VersionConstraint.parse('<1.0.0')),
+ equals(VersionConstraint.parse('<1.0.0')));
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(VersionConstraint.parse('<2.0.0')),
+ equals(VersionConstraint.parse('<2.0.0')));
+ expect(includeMaxPreReleaseRange.intersect(includeMaxPreReleaseRange),
+ equals(includeMaxPreReleaseRange));
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(VersionConstraint.parse('<3.0.0')),
+ equals(includeMaxPreReleaseRange));
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(VersionConstraint.parse('>1.1.4')),
+ equals(VersionRange(
+ min: v114, max: v200, alwaysIncludeMaxPreRelease: true)));
+ });
+
+ test(
+ 'and a range with a pre-release min, returns '
+ 'an intersection', () {
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(VersionConstraint.parse('>=2.0.0-dev')),
+ equals(VersionConstraint.parse('>=2.0.0-dev <2.0.0')));
+ });
+
+ test(
+ 'and a range with a pre-release max, returns '
+ 'the narrower constraint', () {
+ expect(
+ includeMaxPreReleaseRange
+ .intersect(VersionConstraint.parse('<2.0.0-dev')),
+ equals(VersionConstraint.parse('<2.0.0-dev')));
+ });
+ });
+ });
+
+ group('union()', () {
+ test('with a version returns the range if it contains the version', () {
+ var range = VersionRange(min: v114, max: v124);
+ expect(range.union(v123), equals(range));
+ });
+
+ test('with a version on the edge of the range, expands the range', () {
+ expect(
+ VersionRange(min: v114, max: v124, alwaysIncludeMaxPreRelease: true)
+ .union(v124),
+ equals(VersionRange(min: v114, max: v124, includeMax: true)));
+ expect(VersionRange(min: v114, max: v124).union(v114),
+ equals(VersionRange(min: v114, max: v124, includeMin: true)));
+ });
+
+ test(
+ 'with a version allows both the range and the version if the range '
+ "doesn't contain the version", () {
+ var result = VersionRange(min: v003, max: v114).union(v124);
+ expect(result, allows(v010));
+ expect(result, doesNotAllow(v123));
+ expect(result, allows(v124));
+ });
+
+ test('returns a VersionUnion for a disjoint range', () {
+ var result = VersionRange(min: v003, max: v114)
+ .union(VersionRange(min: v130, max: v200));
+ expect(result, allows(v080));
+ expect(result, doesNotAllow(v123));
+ expect(result, allows(v140));
+ });
+
+ test('returns a VersionUnion for a disjoint range with infinite end', () {
+ void isVersionUnion(VersionConstraint constraint) {
+ expect(constraint, allows(v080));
+ expect(constraint, doesNotAllow(v123));
+ expect(constraint, allows(v140));
+ }
+
+ for (final includeAMin in [true, false]) {
+ for (final includeAMax in [true, false]) {
+ for (final includeBMin in [true, false]) {
+ for (final includeBMax in [true, false]) {
+ final a = VersionRange(
+ min: v130, includeMin: includeAMin, includeMax: includeAMax);
+ final b = VersionRange(
+ max: v114, includeMin: includeBMin, includeMax: includeBMax);
+ isVersionUnion(a.union(b));
+ isVersionUnion(b.union(a));
+ }
+ }
+ }
+ }
+ });
+
+ test('considers open ranges disjoint', () {
+ var result = VersionRange(min: v003, max: v114)
+ .union(VersionRange(min: v114, max: v200));
+ expect(result, allows(v080));
+ expect(result, doesNotAllow(v114));
+ expect(result, allows(v140));
+
+ result = VersionRange(min: v114, max: v200)
+ .union(VersionRange(min: v003, max: v114));
+ expect(result, allows(v080));
+ expect(result, doesNotAllow(v114));
+ expect(result, allows(v140));
+ });
+
+ test('returns a merged range for an overlapping range', () {
+ var result = VersionRange(min: v003, max: v114)
+ .union(VersionRange(min: v080, max: v200));
+ expect(result, equals(VersionRange(min: v003, max: v200)));
+ });
+
+ test('considers closed ranges overlapping', () {
+ var result = VersionRange(min: v003, max: v114, includeMax: true)
+ .union(VersionRange(min: v114, max: v200));
+ expect(result, equals(VersionRange(min: v003, max: v200)));
+
+ result =
+ VersionRange(min: v003, max: v114, alwaysIncludeMaxPreRelease: true)
+ .union(VersionRange(min: v114, max: v200, includeMin: true));
+ expect(result, equals(VersionRange(min: v003, max: v200)));
+
+ result = VersionRange(min: v114, max: v200)
+ .union(VersionRange(min: v003, max: v114, includeMax: true));
+ expect(result, equals(VersionRange(min: v003, max: v200)));
+
+ result = VersionRange(min: v114, max: v200, includeMin: true).union(
+ VersionRange(min: v003, max: v114, alwaysIncludeMaxPreRelease: true));
+ expect(result, equals(VersionRange(min: v003, max: v200)));
+ });
+
+ test('includes edges if either range does', () {
+ var result = VersionRange(min: v003, max: v114, includeMin: true)
+ .union(VersionRange(min: v003, max: v114, includeMax: true));
+ expect(
+ result,
+ equals(VersionRange(
+ min: v003, max: v114, includeMin: true, includeMax: true)));
+ });
+
+ test('with a range with a pre-release min, returns a constraint with a gap',
+ () {
+ var result =
+ VersionRange(max: v200).union(VersionConstraint.parse('>=2.0.0-dev'));
+ expect(result, allows(v140));
+ expect(result, doesNotAllow(Version.parse('2.0.0-alpha')));
+ expect(result, allows(Version.parse('2.0.0-dev')));
+ expect(result, allows(Version.parse('2.0.0-dev.1')));
+ expect(result, allows(Version.parse('2.0.0')));
+ });
+
+ test('with a range with a pre-release max, returns the larger constraint',
+ () {
+ expect(
+ VersionRange(max: v200).union(VersionConstraint.parse('<2.0.0-dev')),
+ equals(VersionConstraint.parse('<2.0.0-dev')));
+ });
+
+ group('with includeMaxPreRelease', () {
+ test('adds includeMaxPreRelease if the max version is included', () {
+ expect(
+ includeMaxPreReleaseRange.union(VersionConstraint.parse('<1.0.0')),
+ equals(includeMaxPreReleaseRange));
+ expect(includeMaxPreReleaseRange.union(includeMaxPreReleaseRange),
+ equals(includeMaxPreReleaseRange));
+ expect(
+ includeMaxPreReleaseRange.union(VersionConstraint.parse('<2.0.0')),
+ equals(includeMaxPreReleaseRange));
+ expect(
+ includeMaxPreReleaseRange.union(VersionConstraint.parse('<3.0.0')),
+ equals(VersionConstraint.parse('<3.0.0')));
+ });
+
+ test('and a range with a pre-release min, returns any', () {
+ expect(
+ includeMaxPreReleaseRange
+ .union(VersionConstraint.parse('>=2.0.0-dev')),
+ equals(VersionConstraint.any));
+ });
+
+ test('and a range with a pre-release max, returns the original', () {
+ expect(
+ includeMaxPreReleaseRange
+ .union(VersionConstraint.parse('<2.0.0-dev')),
+ equals(includeMaxPreReleaseRange));
+ });
+ });
+ });
+
+ group('difference()', () {
+ test('with an empty range returns the original range', () {
+ expect(
+ VersionRange(min: v003, max: v114)
+ .difference(VersionConstraint.empty),
+ equals(VersionRange(min: v003, max: v114)));
+ });
+
+ test('with a version outside the range returns the original range', () {
+ expect(VersionRange(min: v003, max: v114).difference(v200),
+ equals(VersionRange(min: v003, max: v114)));
+ });
+
+ test('with a version in the range splits the range', () {
+ expect(
+ VersionRange(min: v003, max: v114).difference(v072),
+ equals(VersionConstraint.unionOf([
+ VersionRange(
+ min: v003, max: v072, alwaysIncludeMaxPreRelease: true),
+ VersionRange(min: v072, max: v114)
+ ])));
+ });
+
+ test('with the max version makes the max exclusive', () {
+ expect(
+ VersionRange(min: v003, max: v114, includeMax: true).difference(v114),
+ equals(VersionRange(
+ min: v003, max: v114, alwaysIncludeMaxPreRelease: true)));
+ });
+
+ test('with the min version makes the min exclusive', () {
+ expect(
+ VersionRange(min: v003, max: v114, includeMin: true).difference(v003),
+ equals(VersionRange(min: v003, max: v114)));
+ });
+
+ test('with a disjoint range returns the original', () {
+ expect(
+ VersionRange(min: v003, max: v114)
+ .difference(VersionRange(min: v123, max: v140)),
+ equals(VersionRange(min: v003, max: v114)));
+ });
+
+ test('with an adjacent range returns the original', () {
+ expect(
+ VersionRange(min: v003, max: v114, includeMax: true)
+ .difference(VersionRange(min: v114, max: v140)),
+ equals(VersionRange(min: v003, max: v114, includeMax: true)));
+ });
+
+ test('with a range at the beginning cuts off the beginning of the range',
+ () {
+ expect(
+ VersionRange(min: v080, max: v130)
+ .difference(VersionRange(min: v010, max: v114)),
+ equals(VersionConstraint.parse('>=1.1.4-0 <1.3.0')));
+ expect(
+ VersionRange(min: v080, max: v130)
+ .difference(VersionRange(max: v114)),
+ equals(VersionConstraint.parse('>=1.1.4-0 <1.3.0')));
+ expect(
+ VersionRange(min: v080, max: v130)
+ .difference(VersionRange(min: v010, max: v114, includeMax: true)),
+ equals(VersionRange(min: v114, max: v130)));
+ expect(
+ VersionRange(min: v080, max: v130, includeMin: true)
+ .difference(VersionRange(min: v010, max: v080, includeMax: true)),
+ equals(VersionRange(min: v080, max: v130)));
+ expect(
+ VersionRange(min: v080, max: v130, includeMax: true)
+ .difference(VersionRange(min: v080, max: v130)),
+ equals(VersionConstraint.parse('>=1.3.0-0 <=1.3.0')));
+ });
+
+ test('with a range at the end cuts off the end of the range', () {
+ expect(
+ VersionRange(min: v080, max: v130)
+ .difference(VersionRange(min: v114, max: v140)),
+ equals(VersionRange(min: v080, max: v114, includeMax: true)));
+ expect(
+ VersionRange(min: v080, max: v130)
+ .difference(VersionRange(min: v114)),
+ equals(VersionRange(min: v080, max: v114, includeMax: true)));
+ expect(
+ VersionRange(min: v080, max: v130)
+ .difference(VersionRange(min: v114, max: v140, includeMin: true)),
+ equals(VersionRange(
+ min: v080, max: v114, alwaysIncludeMaxPreRelease: true)));
+ expect(
+ VersionRange(min: v080, max: v130, includeMax: true)
+ .difference(VersionRange(min: v130, max: v140, includeMin: true)),
+ equals(VersionRange(
+ min: v080, max: v130, alwaysIncludeMaxPreRelease: true)));
+ expect(
+ VersionRange(min: v080, max: v130, includeMin: true)
+ .difference(VersionRange(min: v080, max: v130)),
+ equals(v080));
+ });
+
+ test('with a range in the middle cuts the range in half', () {
+ expect(
+ VersionRange(min: v003, max: v130)
+ .difference(VersionRange(min: v072, max: v114)),
+ equals(VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v072, includeMax: true),
+ VersionConstraint.parse('>=1.1.4-0 <1.3.0')
+ ])));
+ });
+
+ test('with a totally covering range returns empty', () {
+ expect(
+ VersionRange(min: v114, max: v200)
+ .difference(VersionRange(min: v072, max: v300)),
+ isEmpty);
+ expect(
+ VersionRange(min: v003, max: v114)
+ .difference(VersionRange(min: v003, max: v114)),
+ isEmpty);
+ expect(
+ VersionRange(min: v003, max: v114, includeMin: true, includeMax: true)
+ .difference(VersionRange(
+ min: v003, max: v114, includeMin: true, includeMax: true)),
+ isEmpty);
+ });
+
+ test(
+ "with a version union that doesn't cover the range, returns the "
+ 'original', () {
+ expect(
+ VersionRange(min: v114, max: v140)
+ .difference(VersionConstraint.unionOf([v010, v200])),
+ equals(VersionRange(min: v114, max: v140)));
+ });
+
+ test('with a version union that intersects the ends, chops them off', () {
+ expect(
+ VersionRange(min: v114, max: v140).difference(
+ VersionConstraint.unionOf([
+ VersionRange(min: v080, max: v123),
+ VersionRange(min: v130, max: v200)
+ ])),
+ equals(VersionConstraint.parse('>=1.2.3-0 <=1.3.0')));
+ });
+
+ test('with a version union that intersects the middle, chops it up', () {
+ expect(
+ VersionRange(min: v114, max: v140)
+ .difference(VersionConstraint.unionOf([v123, v124, v130])),
+ equals(VersionConstraint.unionOf([
+ VersionRange(
+ min: v114, max: v123, alwaysIncludeMaxPreRelease: true),
+ VersionRange(
+ min: v123, max: v124, alwaysIncludeMaxPreRelease: true),
+ VersionRange(
+ min: v124, max: v130, alwaysIncludeMaxPreRelease: true),
+ VersionRange(min: v130, max: v140)
+ ])));
+ });
+
+ test('with a version union that covers the whole range, returns empty', () {
+ expect(
+ VersionRange(min: v114, max: v140).difference(
+ VersionConstraint.unionOf([v003, VersionRange(min: v010)])),
+ equals(VersionConstraint.empty));
+ });
+
+ test('with a range with a pre-release min, returns the original', () {
+ expect(
+ VersionRange(max: v200)
+ .difference(VersionConstraint.parse('>=2.0.0-dev')),
+ equals(VersionRange(max: v200)));
+ });
+
+ test('with a range with a pre-release max, returns null', () {
+ expect(
+ VersionRange(max: v200)
+ .difference(VersionConstraint.parse('<2.0.0-dev')),
+ equals(VersionConstraint.empty));
+ });
+
+ group('with includeMaxPreRelease', () {
+ group('for the minuend', () {
+ test('preserves includeMaxPreRelease if the max version is included',
+ () {
+ expect(
+ includeMaxPreReleaseRange
+ .difference(VersionConstraint.parse('<1.0.0')),
+ equals(VersionRange(
+ min: Version.parse('1.0.0-0'),
+ max: v200,
+ includeMin: true,
+ alwaysIncludeMaxPreRelease: true)));
+ expect(
+ includeMaxPreReleaseRange
+ .difference(VersionConstraint.parse('<2.0.0')),
+ equals(VersionRange(
+ min: v200.firstPreRelease,
+ max: v200,
+ includeMin: true,
+ alwaysIncludeMaxPreRelease: true)));
+ expect(
+ includeMaxPreReleaseRange.difference(includeMaxPreReleaseRange),
+ equals(VersionConstraint.empty));
+ expect(
+ includeMaxPreReleaseRange
+ .difference(VersionConstraint.parse('<3.0.0')),
+ equals(VersionConstraint.empty));
+ });
+
+ test('with a range with a pre-release min, adjusts the max', () {
+ expect(
+ includeMaxPreReleaseRange
+ .difference(VersionConstraint.parse('>=2.0.0-dev')),
+ equals(VersionConstraint.parse('<2.0.0-dev')));
+ });
+
+ test('with a range with a pre-release max, adjusts the min', () {
+ expect(
+ includeMaxPreReleaseRange
+ .difference(VersionConstraint.parse('<2.0.0-dev')),
+ equals(VersionConstraint.parse('>=2.0.0-dev <2.0.0')));
+ });
+ });
+
+ group('for the subtrahend', () {
+ group("doesn't create a pre-release minimum", () {
+ test('when cutting off the bottom', () {
+ expect(
+ VersionConstraint.parse('<3.0.0')
+ .difference(includeMaxPreReleaseRange),
+ equals(VersionRange(min: v200, max: v300, includeMin: true)));
+ });
+
+ test('with splitting down the middle', () {
+ expect(
+ VersionConstraint.parse('<4.0.0').difference(VersionRange(
+ min: v200,
+ max: v300,
+ includeMin: true,
+ alwaysIncludeMaxPreRelease: true)),
+ equals(VersionConstraint.unionOf([
+ VersionRange(max: v200, alwaysIncludeMaxPreRelease: true),
+ VersionConstraint.parse('>=3.0.0 <4.0.0')
+ ])));
+ });
+
+ test('can leave a single version', () {
+ expect(
+ VersionConstraint.parse('<=2.0.0')
+ .difference(includeMaxPreReleaseRange),
+ equals(v200));
+ });
+ });
+ });
+ });
+ });
+
+ test('isEmpty', () {
+ expect(VersionRange().isEmpty, isFalse);
+ expect(VersionRange(min: v123, max: v124).isEmpty, isFalse);
+ });
+
+ group('compareTo()', () {
+ test('orders by minimum first', () {
+ _expectComparesSmaller(VersionRange(min: v003, max: v080),
+ VersionRange(min: v010, max: v072));
+ _expectComparesSmaller(VersionRange(min: v003, max: v080),
+ VersionRange(min: v010, max: v080));
+ _expectComparesSmaller(VersionRange(min: v003, max: v080),
+ VersionRange(min: v010, max: v114));
+ });
+
+ test('orders by maximum second', () {
+ _expectComparesSmaller(VersionRange(min: v003, max: v010),
+ VersionRange(min: v003, max: v072));
+ });
+
+ test('includeMin comes before !includeMin', () {
+ _expectComparesSmaller(
+ VersionRange(min: v003, max: v080, includeMin: true),
+ VersionRange(min: v003, max: v080));
+ });
+
+ test('includeMax comes after !includeMax', () {
+ _expectComparesSmaller(VersionRange(min: v003, max: v080),
+ VersionRange(min: v003, max: v080, includeMax: true));
+ });
+
+ test('includeMaxPreRelease comes after !includeMaxPreRelease', () {
+ _expectComparesSmaller(
+ VersionRange(max: v200), includeMaxPreReleaseRange);
+ });
+
+ test('no minimum comes before small minimum', () {
+ _expectComparesSmaller(
+ VersionRange(max: v010), VersionRange(min: v003, max: v010));
+ _expectComparesSmaller(VersionRange(max: v010, includeMin: true),
+ VersionRange(min: v003, max: v010));
+ });
+
+ test('no maximium comes after large maximum', () {
+ _expectComparesSmaller(
+ VersionRange(min: v003, max: v300), VersionRange(min: v003));
+ _expectComparesSmaller(VersionRange(min: v003, max: v300),
+ VersionRange(min: v003, includeMax: true));
+ });
+ });
+}
+
+void _expectComparesSmaller(VersionRange smaller, VersionRange larger) {
+ expect(smaller.compareTo(larger), lessThan(0),
+ reason: 'expected $smaller to sort below $larger');
+ expect(larger.compareTo(smaller), greaterThan(0),
+ reason: 'expected $larger to sort above $smaller');
+}
diff --git a/pkgs/pub_semver/test/version_test.dart b/pkgs/pub_semver/test/version_test.dart
new file mode 100644
index 0000000..d7f1197
--- /dev/null
+++ b/pkgs/pub_semver/test/version_test.dart
@@ -0,0 +1,411 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:pub_semver/pub_semver.dart';
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ test('none', () {
+ expect(Version.none.toString(), equals('0.0.0'));
+ });
+
+ test('prioritize()', () {
+ // A correctly sorted list of versions in order of increasing priority.
+ var versions = [
+ '1.0.0-alpha',
+ '2.0.0-alpha',
+ '1.0.0',
+ '1.0.0+build',
+ '1.0.1',
+ '1.1.0',
+ '2.0.0'
+ ];
+
+ // Ensure that every pair of versions is prioritized in the order that it
+ // appears in the list.
+ for (var i = 0; i < versions.length; i++) {
+ for (var j = 0; j < versions.length; j++) {
+ var a = Version.parse(versions[i]);
+ var b = Version.parse(versions[j]);
+ expect(Version.prioritize(a, b), equals(i.compareTo(j)));
+ }
+ }
+ });
+
+ test('antiprioritize()', () {
+ // A correctly sorted list of versions in order of increasing antipriority.
+ var versions = [
+ '2.0.0-alpha',
+ '1.0.0-alpha',
+ '2.0.0',
+ '1.1.0',
+ '1.0.1',
+ '1.0.0+build',
+ '1.0.0'
+ ];
+
+ // Ensure that every pair of versions is prioritized in the order that it
+ // appears in the list.
+ for (var i = 0; i < versions.length; i++) {
+ for (var j = 0; j < versions.length; j++) {
+ var a = Version.parse(versions[i]);
+ var b = Version.parse(versions[j]);
+ expect(Version.antiprioritize(a, b), equals(i.compareTo(j)));
+ }
+ }
+ });
+
+ group('constructor', () {
+ test('throws on negative numbers', () {
+ expect(() => Version(-1, 1, 1), throwsArgumentError);
+ expect(() => Version(1, -1, 1), throwsArgumentError);
+ expect(() => Version(1, 1, -1), throwsArgumentError);
+ });
+ });
+
+ group('comparison', () {
+ // A correctly sorted list of versions.
+ var versions = [
+ '1.0.0-alpha',
+ '1.0.0-alpha.1',
+ '1.0.0-beta.2',
+ '1.0.0-beta.11',
+ '1.0.0-rc.1',
+ '1.0.0-rc.1+build.1',
+ '1.0.0',
+ '1.0.0+0.3.7',
+ '1.3.7+build',
+ '1.3.7+build.2.b8f12d7',
+ '1.3.7+build.11.e0f985a',
+ '2.0.0',
+ '2.1.0',
+ '2.2.0',
+ '2.11.0',
+ '2.11.1'
+ ];
+
+ test('compareTo()', () {
+ // Ensure that every pair of versions compares in the order that it
+ // appears in the list.
+ for (var i = 0; i < versions.length; i++) {
+ for (var j = 0; j < versions.length; j++) {
+ var a = Version.parse(versions[i]);
+ var b = Version.parse(versions[j]);
+ expect(a.compareTo(b), equals(i.compareTo(j)));
+ }
+ }
+ });
+
+ test('operators', () {
+ for (var i = 0; i < versions.length; i++) {
+ for (var j = 0; j < versions.length; j++) {
+ var a = Version.parse(versions[i]);
+ var b = Version.parse(versions[j]);
+ expect(a < b, equals(i < j));
+ expect(a > b, equals(i > j));
+ expect(a <= b, equals(i <= j));
+ expect(a >= b, equals(i >= j));
+ expect(a == b, equals(i == j));
+ expect(a != b, equals(i != j));
+ }
+ }
+ });
+
+ test('equality', () {
+ expect(Version.parse('01.2.3'), equals(Version.parse('1.2.3')));
+ expect(Version.parse('1.02.3'), equals(Version.parse('1.2.3')));
+ expect(Version.parse('1.2.03'), equals(Version.parse('1.2.3')));
+ expect(Version.parse('1.2.3-01'), equals(Version.parse('1.2.3-1')));
+ expect(Version.parse('1.2.3+01'), equals(Version.parse('1.2.3+1')));
+ });
+ });
+
+ test('allows()', () {
+ expect(v123, allows(v123));
+ expect(
+ v123,
+ doesNotAllow(
+ Version.parse('2.2.3'),
+ Version.parse('1.3.3'),
+ Version.parse('1.2.4'),
+ Version.parse('1.2.3-dev'),
+ Version.parse('1.2.3+build')));
+ });
+
+ test('allowsAll()', () {
+ expect(v123.allowsAll(v123), isTrue);
+ expect(v123.allowsAll(v003), isFalse);
+ expect(v123.allowsAll(VersionRange(min: v114, max: v124)), isFalse);
+ expect(v123.allowsAll(VersionConstraint.any), isFalse);
+ expect(v123.allowsAll(VersionConstraint.empty), isTrue);
+ });
+
+ test('allowsAny()', () {
+ expect(v123.allowsAny(v123), isTrue);
+ expect(v123.allowsAny(v003), isFalse);
+ expect(v123.allowsAny(VersionRange(min: v114, max: v124)), isTrue);
+ expect(v123.allowsAny(VersionConstraint.any), isTrue);
+ expect(v123.allowsAny(VersionConstraint.empty), isFalse);
+ });
+
+ test('intersect()', () {
+ // Intersecting the same version returns the version.
+ expect(v123.intersect(v123), equals(v123));
+
+ // Intersecting a different version allows no versions.
+ expect(v123.intersect(v114).isEmpty, isTrue);
+
+ // Intersecting a range returns the version if the range allows it.
+ expect(v123.intersect(VersionRange(min: v114, max: v124)), equals(v123));
+
+ // Intersecting a range allows no versions if the range doesn't allow it.
+ expect(v114.intersect(VersionRange(min: v123, max: v124)).isEmpty, isTrue);
+ });
+
+ group('union()', () {
+ test('with the same version returns the version', () {
+ expect(v123.union(v123), equals(v123));
+ });
+
+ test('with a different version returns a version that matches both', () {
+ var result = v123.union(v080);
+ expect(result, allows(v123));
+ expect(result, allows(v080));
+
+ // Nothing in between should match.
+ expect(result, doesNotAllow(v114));
+ });
+
+ test('with a range returns the range if it contains the version', () {
+ var range = VersionRange(min: v114, max: v124);
+ expect(v123.union(range), equals(range));
+ });
+
+ test('with a range with the version on the edge, expands the range', () {
+ expect(
+ v124.union(VersionRange(
+ min: v114, max: v124, alwaysIncludeMaxPreRelease: true)),
+ equals(VersionRange(min: v114, max: v124, includeMax: true)));
+ expect(
+ v124.firstPreRelease.union(VersionRange(min: v114, max: v124)),
+ equals(VersionRange(
+ min: v114, max: v124.firstPreRelease, includeMax: true)));
+ expect(v114.union(VersionRange(min: v114, max: v124)),
+ equals(VersionRange(min: v114, max: v124, includeMin: true)));
+ });
+
+ test(
+ 'with a range allows both the range and the version if the range '
+ "doesn't contain the version", () {
+ var result = v123.union(VersionRange(min: v003, max: v114));
+ expect(result, allows(v123));
+ expect(result, allows(v010));
+ });
+ });
+
+ group('difference()', () {
+ test('with the same version returns an empty constraint', () {
+ expect(v123.difference(v123), isEmpty);
+ });
+
+ test('with a different version returns the original version', () {
+ expect(v123.difference(v080), equals(v123));
+ });
+
+ test('returns an empty constraint with a range that contains the version',
+ () {
+ expect(v123.difference(VersionRange(min: v114, max: v124)), isEmpty);
+ });
+
+ test("returns the version constraint with a range that doesn't contain it",
+ () {
+ expect(v123.difference(VersionRange(min: v140, max: v300)), equals(v123));
+ });
+ });
+
+ test('isEmpty', () {
+ expect(v123.isEmpty, isFalse);
+ });
+
+ test('nextMajor', () {
+ expect(v123.nextMajor, equals(v200));
+ expect(v114.nextMajor, equals(v200));
+ expect(v200.nextMajor, equals(v300));
+
+ // Ignores pre-release if not on a major version.
+ expect(Version.parse('1.2.3-dev').nextMajor, equals(v200));
+
+ // Just removes it if on a major version.
+ expect(Version.parse('2.0.0-dev').nextMajor, equals(v200));
+
+ // Strips build suffix.
+ expect(Version.parse('1.2.3+patch').nextMajor, equals(v200));
+ });
+
+ test('nextMinor', () {
+ expect(v123.nextMinor, equals(v130));
+ expect(v130.nextMinor, equals(v140));
+
+ // Ignores pre-release if not on a minor version.
+ expect(Version.parse('1.2.3-dev').nextMinor, equals(v130));
+
+ // Just removes it if on a minor version.
+ expect(Version.parse('1.3.0-dev').nextMinor, equals(v130));
+
+ // Strips build suffix.
+ expect(Version.parse('1.2.3+patch').nextMinor, equals(v130));
+ });
+
+ test('nextPatch', () {
+ expect(v123.nextPatch, equals(v124));
+ expect(v200.nextPatch, equals(v201));
+
+ // Just removes pre-release version if present.
+ expect(Version.parse('1.2.4-dev').nextPatch, equals(v124));
+
+ // Strips build suffix.
+ expect(Version.parse('1.2.3+patch').nextPatch, equals(v124));
+ });
+
+ test('nextBreaking', () {
+ expect(v123.nextBreaking, equals(v200));
+ expect(v072.nextBreaking, equals(v080));
+ expect(v003.nextBreaking, equals(v010));
+
+ // Removes pre-release version if present.
+ expect(Version.parse('1.2.3-dev').nextBreaking, equals(v200));
+
+ // Strips build suffix.
+ expect(Version.parse('1.2.3+patch').nextBreaking, equals(v200));
+ });
+
+ test('parse()', () {
+ expect(Version.parse('0.0.0'), equals(Version(0, 0, 0)));
+ expect(Version.parse('12.34.56'), equals(Version(12, 34, 56)));
+
+ expect(Version.parse('1.2.3-alpha.1'),
+ equals(Version(1, 2, 3, pre: 'alpha.1')));
+ expect(Version.parse('1.2.3-x.7.z-92'),
+ equals(Version(1, 2, 3, pre: 'x.7.z-92')));
+
+ expect(Version.parse('1.2.3+build.1'),
+ equals(Version(1, 2, 3, build: 'build.1')));
+ expect(Version.parse('1.2.3+x.7.z-92'),
+ equals(Version(1, 2, 3, build: 'x.7.z-92')));
+
+ expect(Version.parse('1.0.0-rc-1+build-1'),
+ equals(Version(1, 0, 0, pre: 'rc-1', build: 'build-1')));
+
+ expect(() => Version.parse('1.0'), throwsFormatException);
+ expect(() => Version.parse('1a2b3'), throwsFormatException);
+ expect(() => Version.parse('1.2.3.4'), throwsFormatException);
+ expect(() => Version.parse('1234'), throwsFormatException);
+ expect(() => Version.parse('-2.3.4'), throwsFormatException);
+ expect(() => Version.parse('1.3-pre'), throwsFormatException);
+ expect(() => Version.parse('1.3+build'), throwsFormatException);
+ expect(() => Version.parse('1.3+bu?!3ild'), throwsFormatException);
+ });
+
+ group('toString()', () {
+ test('returns the version string', () {
+ expect(Version(0, 0, 0).toString(), equals('0.0.0'));
+ expect(Version(12, 34, 56).toString(), equals('12.34.56'));
+
+ expect(
+ Version(1, 2, 3, pre: 'alpha.1').toString(), equals('1.2.3-alpha.1'));
+ expect(Version(1, 2, 3, pre: 'x.7.z-92').toString(),
+ equals('1.2.3-x.7.z-92'));
+
+ expect(Version(1, 2, 3, build: 'build.1').toString(),
+ equals('1.2.3+build.1'));
+ expect(Version(1, 2, 3, pre: 'pre', build: 'bui').toString(),
+ equals('1.2.3-pre+bui'));
+ });
+
+ test('preserves leading zeroes', () {
+ expect(Version.parse('001.02.0003-01.dev+pre.002').toString(),
+ equals('001.02.0003-01.dev+pre.002'));
+ });
+ });
+
+ group('canonicalizedVersion', () {
+ test('returns version string', () {
+ expect(Version(0, 0, 0).canonicalizedVersion, equals('0.0.0'));
+ expect(Version(12, 34, 56).canonicalizedVersion, equals('12.34.56'));
+
+ expect(Version(1, 2, 3, pre: 'alpha.1').canonicalizedVersion,
+ equals('1.2.3-alpha.1'));
+ expect(Version(1, 2, 3, pre: 'x.7.z-92').canonicalizedVersion,
+ equals('1.2.3-x.7.z-92'));
+
+ expect(Version(1, 2, 3, build: 'build.1').canonicalizedVersion,
+ equals('1.2.3+build.1'));
+ expect(Version(1, 2, 3, pre: 'pre', build: 'bui').canonicalizedVersion,
+ equals('1.2.3-pre+bui'));
+ });
+
+ test('discards leading zeroes', () {
+ expect(Version.parse('001.02.0003-01.dev+pre.002').canonicalizedVersion,
+ equals('1.2.3-1.dev+pre.2'));
+ });
+
+ test('example from documentation', () {
+ final v = Version.parse('01.02.03-01.dev+pre.02');
+
+ assert(v.toString() == '01.02.03-01.dev+pre.02');
+ assert(v.canonicalizedVersion == '1.2.3-1.dev+pre.2');
+ assert(Version.parse(v.canonicalizedVersion) == v);
+ });
+ });
+
+ group('primary', () {
+ test('single', () {
+ expect(
+ _primary([
+ '1.2.3',
+ ]).toString(),
+ '1.2.3',
+ );
+ });
+
+ test('normal', () {
+ expect(
+ _primary([
+ '1.2.3',
+ '1.2.2',
+ ]).toString(),
+ '1.2.3',
+ );
+ });
+
+ test('all prerelease', () {
+ expect(
+ _primary([
+ '1.2.2-dev.1',
+ '1.2.2-dev.2',
+ ]).toString(),
+ '1.2.2-dev.2',
+ );
+ });
+
+ test('later prerelease', () {
+ expect(
+ _primary([
+ '1.2.3',
+ '1.2.3-dev',
+ ]).toString(),
+ '1.2.3',
+ );
+ });
+
+ test('empty', () {
+ expect(() => Version.primary([]), throwsStateError);
+ });
+ });
+}
+
+Version _primary(List<String> input) =>
+ Version.primary(input.map(Version.parse).toList());
diff --git a/pkgs/pub_semver/test/version_union_test.dart b/pkgs/pub_semver/test/version_union_test.dart
new file mode 100644
index 0000000..857f10e
--- /dev/null
+++ b/pkgs/pub_semver/test/version_union_test.dart
@@ -0,0 +1,482 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:pub_semver/pub_semver.dart';
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ group('factory', () {
+ test('ignores empty constraints', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionConstraint.empty,
+ VersionConstraint.empty,
+ v123,
+ VersionConstraint.empty
+ ]),
+ equals(v123));
+
+ expect(
+ VersionConstraint.unionOf(
+ [VersionConstraint.empty, VersionConstraint.empty]),
+ isEmpty);
+ });
+
+ test('returns an empty constraint for an empty list', () {
+ expect(VersionConstraint.unionOf([]), isEmpty);
+ });
+
+ test('any constraints override everything', () {
+ expect(
+ VersionConstraint.unionOf([
+ v123,
+ VersionConstraint.any,
+ v200,
+ VersionRange(min: v234, max: v250)
+ ]),
+ equals(VersionConstraint.any));
+ });
+
+ test('flattens other unions', () {
+ expect(
+ VersionConstraint.unionOf([
+ v072,
+ VersionConstraint.unionOf([v123, v124]),
+ v250
+ ]),
+ equals(VersionConstraint.unionOf([v072, v123, v124, v250])));
+ });
+
+ test('returns a single merged range as-is', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v080, max: v140),
+ VersionRange(min: v123, max: v200)
+ ]),
+ equals(VersionRange(min: v080, max: v200)));
+ });
+ });
+
+ group('equality', () {
+ test("doesn't depend on original order", () {
+ expect(
+ VersionConstraint.unionOf([
+ v250,
+ VersionRange(min: v201, max: v234),
+ v124,
+ v072,
+ VersionRange(min: v080, max: v114),
+ v123
+ ]),
+ equals(VersionConstraint.unionOf([
+ v072,
+ VersionRange(min: v080, max: v114),
+ v123,
+ v124,
+ VersionRange(min: v201, max: v234),
+ v250
+ ])));
+ });
+
+ test('merges overlapping ranges', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v072),
+ VersionRange(min: v010, max: v080),
+ VersionRange(min: v114, max: v124),
+ VersionRange(min: v123, max: v130)
+ ]),
+ equals(VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v114, max: v130)
+ ])));
+ });
+
+ test('merges adjacent ranges', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v072, includeMax: true),
+ VersionRange(min: v072, max: v080),
+ VersionRange(
+ min: v114, max: v124, alwaysIncludeMaxPreRelease: true),
+ VersionRange(min: v124, max: v130, includeMin: true),
+ VersionRange(min: v130.firstPreRelease, max: v200, includeMin: true)
+ ]),
+ equals(VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v114, max: v200)
+ ])));
+ });
+
+ test("doesn't merge not-quite-adjacent ranges", () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v114, max: v124),
+ VersionRange(min: v124, max: v130, includeMin: true)
+ ]),
+ isNot(equals(VersionRange(min: v114, max: v130))));
+
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v072),
+ VersionRange(min: v072, max: v080)
+ ]),
+ isNot(equals(VersionRange(min: v003, max: v080))));
+ });
+
+ test('merges version numbers into ranges', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v072),
+ v010,
+ VersionRange(min: v114, max: v124),
+ v123
+ ]),
+ equals(VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v072),
+ VersionRange(min: v114, max: v124)
+ ])));
+ });
+
+ test('merges adjacent version numbers into ranges', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(
+ min: v003, max: v072, alwaysIncludeMaxPreRelease: true),
+ v072,
+ v114,
+ VersionRange(min: v114, max: v124),
+ v124.firstPreRelease
+ ]),
+ equals(VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v072, includeMax: true),
+ VersionRange(
+ min: v114,
+ max: v124.firstPreRelease,
+ includeMin: true,
+ includeMax: true)
+ ])));
+ });
+
+ test("doesn't merge not-quite-adjacent version numbers into ranges", () {
+ expect(
+ VersionConstraint.unionOf([VersionRange(min: v003, max: v072), v072]),
+ isNot(equals(VersionRange(min: v003, max: v072, includeMax: true))));
+ });
+ });
+
+ test('isEmpty returns false', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v123, max: v130),
+ ]),
+ isNot(isEmpty));
+ });
+
+ test('isAny returns false', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v123, max: v130),
+ ]).isAny,
+ isFalse);
+ });
+
+ test('allows() allows anything the components allow', () {
+ var union = VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v123, max: v130),
+ v200
+ ]);
+
+ expect(union, allows(v010));
+ expect(union, doesNotAllow(v080));
+ expect(union, allows(v124));
+ expect(union, doesNotAllow(v140));
+ expect(union, allows(v200));
+ });
+
+ group('allowsAll()', () {
+ test('for a version, returns true if any component allows the version', () {
+ var union = VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v123, max: v130),
+ v200
+ ]);
+
+ expect(union.allowsAll(v010), isTrue);
+ expect(union.allowsAll(v080), isFalse);
+ expect(union.allowsAll(v124), isTrue);
+ expect(union.allowsAll(v140), isFalse);
+ expect(union.allowsAll(v200), isTrue);
+ });
+
+ test(
+ 'for a version range, returns true if any component allows the whole '
+ 'range', () {
+ var union = VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v123, max: v130)
+ ]);
+
+ expect(union.allowsAll(VersionRange(min: v003, max: v080)), isTrue);
+ expect(union.allowsAll(VersionRange(min: v010, max: v072)), isTrue);
+ expect(union.allowsAll(VersionRange(min: v010, max: v124)), isFalse);
+ });
+
+ group('for a union,', () {
+ var union = VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v123, max: v130)
+ ]);
+
+ test('returns true if every constraint matches a different constraint',
+ () {
+ expect(
+ union.allowsAll(VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v072),
+ VersionRange(min: v124, max: v130)
+ ])),
+ isTrue);
+ });
+
+ test('returns true if every constraint matches the same constraint', () {
+ expect(
+ union.allowsAll(VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v010),
+ VersionRange(min: v072, max: v080)
+ ])),
+ isTrue);
+ });
+
+ test("returns false if there's an unmatched constraint", () {
+ expect(
+ union.allowsAll(VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v072),
+ VersionRange(min: v124, max: v130),
+ VersionRange(min: v140, max: v200)
+ ])),
+ isFalse);
+ });
+
+ test("returns false if a constraint isn't fully matched", () {
+ expect(
+ union.allowsAll(VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v114),
+ VersionRange(min: v124, max: v130)
+ ])),
+ isFalse);
+ });
+ });
+ });
+
+ group('allowsAny()', () {
+ test('for a version, returns true if any component allows the version', () {
+ var union = VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v123, max: v130),
+ v200
+ ]);
+
+ expect(union.allowsAny(v010), isTrue);
+ expect(union.allowsAny(v080), isFalse);
+ expect(union.allowsAny(v124), isTrue);
+ expect(union.allowsAny(v140), isFalse);
+ expect(union.allowsAny(v200), isTrue);
+ });
+
+ test(
+ 'for a version range, returns true if any component allows part of '
+ 'the range', () {
+ var union =
+ VersionConstraint.unionOf([VersionRange(min: v003, max: v080), v123]);
+
+ expect(union.allowsAny(VersionRange(min: v010, max: v114)), isTrue);
+ expect(union.allowsAny(VersionRange(min: v114, max: v124)), isTrue);
+ expect(union.allowsAny(VersionRange(min: v124, max: v130)), isFalse);
+ });
+
+ group('for a union,', () {
+ var union = VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v080),
+ VersionRange(min: v123, max: v130)
+ ]);
+
+ test('returns true if any constraint matches', () {
+ expect(
+ union.allowsAny(VersionConstraint.unionOf(
+ [v072, VersionRange(min: v200, max: v300)])),
+ isTrue);
+
+ expect(
+ union.allowsAny(VersionConstraint.unionOf(
+ [v003, VersionRange(min: v124, max: v300)])),
+ isTrue);
+ });
+
+ test('returns false if no constraint matches', () {
+ expect(
+ union.allowsAny(VersionConstraint.unionOf([
+ v003,
+ VersionRange(min: v130, max: v140),
+ VersionRange(min: v140, max: v200)
+ ])),
+ isFalse);
+ });
+ });
+ });
+
+ group('intersect()', () {
+ test('with an overlapping version, returns that version', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v080),
+ VersionRange(min: v123, max: v140)
+ ]).intersect(v072),
+ equals(v072));
+ });
+
+ test('with a non-overlapping version, returns an empty constraint', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v080),
+ VersionRange(min: v123, max: v140)
+ ]).intersect(v300),
+ isEmpty);
+ });
+
+ test('with an overlapping range, returns that range', () {
+ var range = VersionRange(min: v072, max: v080);
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v080),
+ VersionRange(min: v123, max: v140)
+ ]).intersect(range),
+ equals(range));
+ });
+
+ test('with a non-overlapping range, returns an empty constraint', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v080),
+ VersionRange(min: v123, max: v140)
+ ]).intersect(VersionRange(min: v080, max: v123)),
+ isEmpty);
+ });
+
+ test('with a parially-overlapping range, returns the overlapping parts',
+ () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v080),
+ VersionRange(min: v123, max: v140)
+ ]).intersect(VersionRange(min: v072, max: v130)),
+ equals(VersionConstraint.unionOf([
+ VersionRange(min: v072, max: v080),
+ VersionRange(min: v123, max: v130)
+ ])));
+ });
+
+ group('for a union,', () {
+ var union = VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v080),
+ VersionRange(min: v123, max: v130)
+ ]);
+
+ test('returns the overlapping parts', () {
+ expect(
+ union.intersect(VersionConstraint.unionOf([
+ v010,
+ VersionRange(min: v072, max: v124),
+ VersionRange(min: v124, max: v130)
+ ])),
+ equals(VersionConstraint.unionOf([
+ v010,
+ VersionRange(min: v072, max: v080),
+ VersionRange(min: v123, max: v124),
+ VersionRange(min: v124, max: v130)
+ ])));
+ });
+
+ test("drops parts that don't match", () {
+ expect(
+ union.intersect(VersionConstraint.unionOf([
+ v003,
+ VersionRange(min: v072, max: v080),
+ VersionRange(min: v080, max: v123)
+ ])),
+ equals(VersionRange(min: v072, max: v080)));
+ });
+ });
+ });
+
+ group('difference()', () {
+ test("ignores ranges that don't intersect", () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v072, max: v080),
+ VersionRange(min: v123, max: v130)
+ ]).difference(VersionConstraint.unionOf([
+ VersionRange(min: v003, max: v010),
+ VersionRange(min: v080, max: v123),
+ VersionRange(min: v140)
+ ])),
+ equals(VersionConstraint.unionOf([
+ VersionRange(min: v072, max: v080),
+ VersionRange(min: v123, max: v130)
+ ])));
+ });
+
+ test('removes overlapping portions', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v080),
+ VersionRange(min: v123, max: v130)
+ ]).difference(VersionConstraint.unionOf(
+ [VersionRange(min: v003, max: v072), VersionRange(min: v124)])),
+ equals(VersionConstraint.unionOf([
+ VersionRange(
+ min: v072.firstPreRelease, max: v080, includeMin: true),
+ VersionRange(min: v123, max: v124, includeMax: true)
+ ])));
+ });
+
+ test('removes multiple portions from the same range', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v114),
+ VersionRange(min: v130, max: v200)
+ ]).difference(VersionConstraint.unionOf([v072, v080])),
+ equals(VersionConstraint.unionOf([
+ VersionRange(
+ min: v010, max: v072, alwaysIncludeMaxPreRelease: true),
+ VersionRange(
+ min: v072, max: v080, alwaysIncludeMaxPreRelease: true),
+ VersionRange(min: v080, max: v114),
+ VersionRange(min: v130, max: v200)
+ ])));
+ });
+
+ test('removes the same range from multiple ranges', () {
+ expect(
+ VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v072),
+ VersionRange(min: v080, max: v123),
+ VersionRange(min: v124, max: v130),
+ VersionRange(min: v200, max: v234),
+ VersionRange(min: v250, max: v300)
+ ]).difference(VersionRange(min: v114, max: v201)),
+ equals(VersionConstraint.unionOf([
+ VersionRange(min: v010, max: v072),
+ VersionRange(min: v080, max: v114, includeMax: true),
+ VersionRange(
+ min: v201.firstPreRelease, max: v234, includeMin: true),
+ VersionRange(min: v250, max: v300)
+ ])));
+ });
+ });
+}
diff --git a/pkgs/source_map_stack_trace/.gitignore b/pkgs/source_map_stack_trace/.gitignore
new file mode 100644
index 0000000..f73b2f9
--- /dev/null
+++ b/pkgs/source_map_stack_trace/.gitignore
@@ -0,0 +1,4 @@
+.dart_tool/
+.packages
+.pub/
+pubspec.lock
diff --git a/pkgs/source_map_stack_trace/.test_config b/pkgs/source_map_stack_trace/.test_config
new file mode 100644
index 0000000..531426a
--- /dev/null
+++ b/pkgs/source_map_stack_trace/.test_config
@@ -0,0 +1,5 @@
+{
+ "test_package": {
+ "platforms": ["vm"]
+ }
+}
\ No newline at end of file
diff --git a/pkgs/source_map_stack_trace/AUTHORS b/pkgs/source_map_stack_trace/AUTHORS
new file mode 100644
index 0000000..e8063a8
--- /dev/null
+++ b/pkgs/source_map_stack_trace/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/source_map_stack_trace/CHANGELOG.md b/pkgs/source_map_stack_trace/CHANGELOG.md
new file mode 100644
index 0000000..00c66d9
--- /dev/null
+++ b/pkgs/source_map_stack_trace/CHANGELOG.md
@@ -0,0 +1,82 @@
+## 2.1.3-wip
+
+## 2.1.2
+
+* Require Dart 3.3.0
+* Move to `dart-lang/tools` monorepo.
+
+## 2.1.1
+
+* Populate the pubspec `repository` field.
+
+## 2.1.0
+
+* Stable release for null safety.
+* Require Dart 2.12
+
+## 2.0.0
+
+### Breaking Changes
+
+* Removed dependency on `package_resolver` and changed the apis to accept a
+ `Map<String, Uri>` which maps package names to the base uri to resolve the
+ `package:` uris for those packages.
+* The `sdkRoot` argument must be an `Uri`. Use `Uri.parse` for use
+ cases previously passing a `String`.
+* The deprecated `packageRoot` argument has been removed.
+
+## 1.1.5
+
+* Set max SDK version to `<3.0.0`.
+
+## 1.1.4
+
+* Support source maps that depend on the uri of the location to resolve spans
+ correctly.
+
+## 1.1.3
+
+* Add a missing dependency on `path`.
+
+## 1.1.2
+
+* Fix a typo in the previous fix.
+
+## 1.1.1
+
+* Don't crash if the `SyncPackageResolver` has no package information at all.
+
+## 1.1.0
+
+* `mapStackTrace()` now uses a `SyncPackageResolver` object from the
+ [`package_resolver` package][package_resolver] to recreate `package:` URIs.
+
+* **Deprecation**: the `packageRoot` parameter to `mapStackTrace` is deprecated
+ in favor of the `packageInfo` parameter described above. It will be removed in
+ a future release.
+
+[package_resolver]: https://pub.dartlang.org/packages/package_resolver
+
+## 1.0.5
+
+* Add compatibility for member names that include named arguments.
+
+## 1.0.4
+
+* Add compatibility for Dart 1.10-style name munging.
+
+## 1.0.3
+
+* Prefer "dart:" URLs to "package:" URLs.
+
+## 1.0.2
+
+* Fix an off-by-one bug that was causing line numbers to be slightly off.
+
+## 1.0.1
+
+* Don't crash when mapping stack chains.
+
+## 1.0.0
+
+* Initial release.
diff --git a/pkgs/source_map_stack_trace/LICENSE b/pkgs/source_map_stack_trace/LICENSE
new file mode 100644
index 0000000..633672a
--- /dev/null
+++ b/pkgs/source_map_stack_trace/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2015, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/source_map_stack_trace/README.md b/pkgs/source_map_stack_trace/README.md
new file mode 100644
index 0000000..9b11612
--- /dev/null
+++ b/pkgs/source_map_stack_trace/README.md
@@ -0,0 +1,50 @@
+[](https://github.com/dart-lang/tools/actions/workflows/source_map_stack_trace.yml)
+[](https://pub.dev/packages/source_map_stack_trace)
+[](https://pub.dev/packages/source_map_stack_trace/publisher)
+
+`source_map_stack_trace` is a package for converting stack traces generated by
+dart2js-compiled JavaScript code into readable native Dart stack traces using
+source maps. For example:
+
+```dart
+import 'package:source_map_stack_trace/source_map_stack_trace.dart';
+
+void main() {
+ var jsTrace = // Get a StackTrace generated by dart2js.
+ var mapping = // Get a source map mapping the JS to the Dart source.
+
+ // Convert jsTrace to refer to the Dart source instead.
+ var dartTrace = mapStackTrace(jsTrace, sourceMap);
+ print(dartTrace);
+}
+```
+
+This can convert the following JavaScript trace:
+
+```
+expect_async_test.dart.browser_test.dart.js 2636:15 dart.wrapException
+expect_async_test.dart.browser_test.dart.js 14661:15 main__closure16.call$0
+expect_async_test.dart.browser_test.dart.js 18237:26 Declarer_test__closure.call$1
+expect_async_test.dart.browser_test.dart.js 17905:23 StackZoneSpecification_registerUnaryCallback__closure.call$0
+expect_async_test.dart.browser_test.dart.js 17876:16 StackZoneSpecification._stack_zone_specification$_run$2
+expect_async_test.dart.browser_test.dart.js 17899:26 StackZoneSpecification_registerUnaryCallback_closure.call$1
+expect_async_test.dart.browser_test.dart.js 6115:16 _rootRunUnary
+expect_async_test.dart.browser_test.dart.js 8576:39 _CustomZone.runUnary$2
+expect_async_test.dart.browser_test.dart.js 7135:57 _Future__propagateToListeners_handleValueCallback.call$0
+expect_async_test.dart.browser_test.dart.js 7031:147 dart._Future.static._Future__propagateToListeners
+```
+
+to:
+
+```
+dart:_internal/compiler/js_lib/js_helper.dart 1210:1 wrapException
+test/frontend/expect_async_test.dart 24:5 main.<fn>.<fn>
+package:test/src/backend/declarer.dart 45:48 Declarer.test.<fn>.<fn>
+package:stack_trace/src/stack_zone_specification.dart 134:30 StackZoneSpecification.registerUnaryCallback.<fn>.<fn>
+package:stack_trace/src/stack_zone_specification.dart 210:7 StackZoneSpecification._run
+package:stack_trace/src/stack_zone_specification.dart 135:5 StackZoneSpecification.registerUnaryCallback.<fn>
+dart:async/zone.dart 904:14 _rootRunUnary
+dart:async/zone.dart 806:3 _CustomZone.runUnary
+dart:async/future_impl.dart 486:13 _Future._propagateToListeners.handleValueCallback
+dart:async/future_impl.dart 567:32 _Future._propagateToListeners
+```
diff --git a/pkgs/source_map_stack_trace/analysis_options.yaml b/pkgs/source_map_stack_trace/analysis_options.yaml
new file mode 100644
index 0000000..5ee158a
--- /dev/null
+++ b/pkgs/source_map_stack_trace/analysis_options.yaml
@@ -0,0 +1,7 @@
+# https://dart.dev/tools/analysis#the-analysis-options-file
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-raw-types: true
diff --git a/pkgs/source_map_stack_trace/lib/source_map_stack_trace.dart b/pkgs/source_map_stack_trace/lib/source_map_stack_trace.dart
new file mode 100644
index 0000000..a3925cd
--- /dev/null
+++ b/pkgs/source_map_stack_trace/lib/source_map_stack_trace.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:path/path.dart' as p;
+import 'package:source_maps/source_maps.dart';
+import 'package:stack_trace/stack_trace.dart';
+
+/// Convert [stackTrace], a stack trace generated by dart2js-compiled
+/// JavaScript, to a native-looking stack trace using [sourceMap].
+///
+/// [minified] indicates whether or not the dart2js code was minified. If it
+/// hasn't, this tries to clean up the stack frame member names.
+///
+/// The [packageMap] maps package names to the base uri used to resolve the
+/// `package:` uris for those packages. It is used to it's used to reconstruct
+/// `package:` URIs for stack frames that come from packages.
+///
+/// [sdkRoot] is the URI surfaced in the stack traces for SDK libraries.
+/// If it's passed, stack frames from the SDK will have `dart:` URLs.
+StackTrace mapStackTrace(Mapping sourceMap, StackTrace stackTrace,
+ {bool minified = false, Map<String, Uri>? packageMap, Uri? sdkRoot}) {
+ if (stackTrace is Chain) {
+ return Chain(stackTrace.traces.map((trace) {
+ return Trace.from(mapStackTrace(sourceMap, trace,
+ minified: minified, packageMap: packageMap, sdkRoot: sdkRoot));
+ }));
+ }
+
+ var sdkLib = sdkRoot == null ? null : '$sdkRoot/lib';
+
+ var trace = Trace.from(stackTrace);
+ return Trace(trace.frames.map((frame) {
+ var line = frame.line;
+ // If there's no line information, there's no way to translate this frame.
+ // We could return it as-is, but these lines are usually not useful anyways.
+ if (line == null) return null;
+
+ // If there's no column, try using the first column of the line.
+ var column = frame.column ?? 0;
+
+ // Subtract 1 because stack traces use 1-indexed lines and columns and
+ // source maps uses 0-indexed.
+ var span =
+ sourceMap.spanFor(line - 1, column - 1, uri: frame.uri.toString());
+
+ // If we can't find a source span, ignore the frame. It's probably something
+ // internal that the user doesn't care about.
+ if (span == null) return null;
+
+ var sourceUrl = span.sourceUrl.toString();
+ if (sdkLib != null && p.url.isWithin(sdkLib, sourceUrl)) {
+ sourceUrl = 'dart:${p.url.relative(sourceUrl, from: sdkLib)}';
+ } else if (packageMap != null) {
+ for (var package in packageMap.keys) {
+ var packageUrl = packageMap[package].toString();
+ if (!p.url.isWithin(packageUrl, sourceUrl)) continue;
+
+ sourceUrl =
+ 'package:$package/${p.url.relative(sourceUrl, from: packageUrl)}';
+ break;
+ }
+ }
+
+ return Frame(
+ Uri.parse(sourceUrl),
+ span.start.line + 1,
+ span.start.column + 1,
+ // If the dart2js output is minified, there's no use trying to prettify
+ // its member names. Use the span's identifier if available, otherwise
+ // use the minified member name.
+ minified
+ ? (span.isIdentifier ? span.text : frame.member)
+ : _prettifyMember(frame.member!));
+ }).whereType<Frame>());
+}
+
+/// Reformats a JS member name to make it look more Dart-like.
+String _prettifyMember(String member) {
+ return member
+ // Get rid of the noise that Firefox sometimes adds.
+ .replaceAll(RegExp(r'/?<$'), '')
+ // Get rid of arity indicators and named arguments.
+ .replaceAll(RegExp(r'\$\d+(\$[a-zA-Z_0-9]+)*$'), '')
+ // Convert closures to <fn>.
+ .replaceAllMapped(
+ RegExp(r'(_+)closure\d*\.call$'),
+ // The number of underscores before "closure" indicates how nested it
+ // is.
+ (match) => '.<fn>' * match[1]!.length)
+ // Get rid of explicitly-generated calls.
+ .replaceAll(RegExp(r'\.call$'), '')
+ // Get rid of the top-level method prefix.
+ .replaceAll(RegExp(r'^dart\.'), '')
+ // Get rid of library namespaces.
+ .replaceAll(RegExp(r'[a-zA-Z_0-9]+\$'), '')
+ // Get rid of the static method prefix. The class name also exists in the
+ // invocation, so we're not getting rid of any information.
+ .replaceAll(RegExp(r'^[a-zA-Z_0-9]+.(static|dart).'), '')
+ // Convert underscores after identifiers to dots. This runs the risk of
+ // incorrectly converting members that contain underscores, but those are
+ // contrary to the style guide anyway.
+ .replaceAllMapped(RegExp(r'([a-zA-Z0-9]+)_'), (match) => '${match[1]!}.');
+}
diff --git a/pkgs/source_map_stack_trace/pubspec.yaml b/pkgs/source_map_stack_trace/pubspec.yaml
new file mode 100644
index 0000000..4e67109
--- /dev/null
+++ b/pkgs/source_map_stack_trace/pubspec.yaml
@@ -0,0 +1,18 @@
+name: source_map_stack_trace
+version: 2.1.3-wip
+description: A package for applying source maps to stack traces.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/source_map_stack_trace
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_map_stack_trace
+
+environment:
+ sdk: ^3.3.0
+
+dependencies:
+ path: ^1.8.0
+ source_maps: ^0.10.10
+ stack_trace: ^1.10.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ source_span: ^1.8.0
+ test: ^1.16.0
diff --git a/pkgs/source_map_stack_trace/test/source_map_stack_trace_test.dart b/pkgs/source_map_stack_trace/test/source_map_stack_trace_test.dart
new file mode 100644
index 0000000..dd4d710
--- /dev/null
+++ b/pkgs/source_map_stack_trace/test/source_map_stack_trace_test.dart
@@ -0,0 +1,264 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:path/path.dart' as p;
+import 'package:source_map_stack_trace/source_map_stack_trace.dart';
+import 'package:source_maps/source_maps.dart';
+import 'package:source_span/source_span.dart';
+import 'package:stack_trace/stack_trace.dart';
+import 'package:test/test.dart';
+
+/// A simple [Mapping] for tests that don't need anything special.
+final _simpleMapping = parseJson((SourceMapBuilder()
+ ..addSpan(
+ SourceMapSpan.identifier(
+ SourceLocation(1, line: 1, column: 3, sourceUrl: 'foo.dart'),
+ 'qux'),
+ SourceSpan(SourceLocation(8, line: 5, column: 0),
+ SourceLocation(18, line: 15, column: 0), '\n' * 10)))
+ .build('foo.dart.js.map'));
+
+final _packageMap = {
+ 'bar': Uri.parse('packages/bar'),
+ 'foo': Uri.parse('packages/foo'),
+};
+
+void main() {
+ test('maps a JS line and column to a Dart line and span', () {
+ var trace = Trace.parse('foo.dart.js 10:11 foo');
+ var frame = _mapTrace(_simpleMapping, trace).frames.first;
+ expect(frame.uri, equals(Uri.parse('foo.dart')));
+
+ // These are +1 because stack_trace is 1-based whereas source_span is
+ // 0-basd.
+ expect(frame.line, equals(2));
+ expect(frame.column, equals(4));
+ });
+
+ test('ignores JS frames without line info', () {
+ var trace = Trace.parse('''
+foo.dart.js 10:11 foo
+foo.dart.js bar
+foo.dart.js 10:11 baz
+''');
+ var frames = _mapTrace(_simpleMapping, trace).frames;
+
+ expect(frames.length, equals(2));
+ expect(frames.first.member, equals('foo'));
+ expect(frames.last.member, equals('baz'));
+ });
+
+ test('ignores JS frames without corresponding spans', () {
+ var trace = Trace.parse('''
+foo.dart.js 10:11 foo
+foo.dart.js 1:1 bar
+foo.dart.js 10:11 baz
+''');
+
+ var frames = _mapTrace(_simpleMapping, trace).frames;
+
+ expect(frames.length, equals(2));
+ expect(frames.first.member, equals('foo'));
+ expect(frames.last.member, equals('baz'));
+ });
+
+ test('include frames from JS files not covered by the source map bundle', () {
+ var trace = Trace.parse('''
+foo.dart.js 10:11 foo
+jquery.js 10:1 foo
+bar.dart.js 10:11 foo
+''');
+ var builder = SourceMapBuilder()
+ ..addSpan(
+ SourceMapSpan.identifier(
+ SourceLocation(1,
+ line: 1, column: 3, sourceUrl: 'packages/foo/foo.dart'),
+ 'qux'),
+ SourceSpan(SourceLocation(8, line: 5, column: 0),
+ SourceLocation(12, line: 9, column: 1), '\n' * 4));
+ var sourceMapJson1 = builder.build('foo.dart.js.map');
+ sourceMapJson1['file'] = 'foo.dart.js';
+
+ builder = SourceMapBuilder()
+ ..addSpan(
+ SourceMapSpan.identifier(
+ SourceLocation(1,
+ line: 1, column: 3, sourceUrl: 'packages/bar/bar.dart'),
+ 'qux'),
+ SourceSpan(SourceLocation(8, line: 5, column: 0),
+ SourceLocation(12, line: 9, column: 1), '\n' * 4));
+ var sourceMapJson2 = builder.build('bar.dart.js.map');
+ sourceMapJson2['file'] = 'bar.dart.js';
+
+ var bundle = [sourceMapJson1, sourceMapJson2];
+ var mapping = parseJsonExtended(bundle);
+ var frames = _mapTrace(mapping, trace, packageMap: _packageMap).frames;
+
+ expect(frames.length, equals(3));
+
+ var frame = frames[0];
+ expect(frame.uri, equals(Uri.parse('package:foo/foo.dart')));
+ expect(frame.line, equals(2));
+ expect(frame.column, equals(4));
+
+ frame = frames[1];
+ expect(p.basename(frame.uri.toString()), equals('jquery.js'));
+ expect(frame.line, equals(10));
+
+ frame = frames[2];
+ expect(frame.uri, equals(Uri.parse('package:bar/bar.dart')));
+ expect(frame.line, equals(2));
+ expect(frame.column, equals(4));
+ });
+
+ test('falls back to column 0 for unlisted column', () {
+ var trace = Trace.parse('foo.dart.js 10 foo');
+ var builder = SourceMapBuilder()
+ ..addSpan(
+ SourceMapSpan.identifier(
+ SourceLocation(1, line: 1, column: 3, sourceUrl: 'foo.dart'),
+ 'qux'),
+ SourceSpan(SourceLocation(8, line: 5, column: 0),
+ SourceLocation(12, line: 9, column: 1), '\n' * 4));
+
+ var mapping = parseJson(builder.build('foo.dart.js.map'));
+ var frame = _mapTrace(mapping, trace).frames.first;
+ expect(frame.uri, equals(Uri.parse('foo.dart')));
+ expect(frame.line, equals(2));
+ expect(frame.column, equals(4));
+ });
+
+ test('uses package: URIs for frames within a packageResolver.packageMap URL',
+ () {
+ var trace = Trace.parse('foo.dart.js 10 foo');
+ var builder = SourceMapBuilder()
+ ..addSpan(
+ SourceMapSpan.identifier(
+ SourceLocation(1,
+ line: 1, column: 3, sourceUrl: 'packages/foo/foo.dart'),
+ 'qux'),
+ SourceSpan(SourceLocation(8, line: 5, column: 0),
+ SourceLocation(12, line: 9, column: 1), '\n' * 4));
+
+ var mapping = parseJson(builder.build('foo.dart.js.map'));
+ var mappedTrace = _mapTrace(mapping, trace, packageMap: _packageMap);
+ var frame = mappedTrace.frames.first;
+ expect(frame.uri, equals(Uri.parse('package:foo/foo.dart')));
+ expect(frame.line, equals(2));
+ expect(frame.column, equals(4));
+ });
+
+ test('uses dart: URIs for frames within sdkRoot', () {
+ var trace = Trace.parse('foo.dart.js 10 foo');
+ var builder = SourceMapBuilder()
+ ..addSpan(
+ SourceMapSpan.identifier(
+ SourceLocation(1,
+ line: 1, column: 3, sourceUrl: 'sdk/lib/async/foo.dart'),
+ 'qux'),
+ SourceSpan(SourceLocation(8, line: 5, column: 0),
+ SourceLocation(12, line: 9, column: 1), '\n' * 4));
+
+ var mapping = parseJson(builder.build('foo.dart.js.map'));
+ var frame =
+ _mapTrace(mapping, trace, sdkRoot: Uri.parse('sdk/')).frames.first;
+ expect(frame.uri, equals(Uri.parse('dart:async/foo.dart')));
+ expect(frame.line, equals(2));
+ expect(frame.column, equals(4));
+ });
+
+ test('converts a stack chain', () {
+ var trace = Chain([
+ Trace.parse('foo.dart.js 10:11 foo'),
+ Trace.parse('foo.dart.js 10:11 bar')
+ ]);
+ var traces = _mapChain(_simpleMapping, trace).traces;
+
+ var frame = traces.first.frames.single;
+ expect(frame.uri, equals(Uri.parse('foo.dart')));
+ expect(frame.member, equals('foo'));
+ expect(frame.line, equals(2));
+ expect(frame.column, equals(4));
+
+ frame = traces.last.frames.single;
+ expect(frame.uri, equals(Uri.parse('foo.dart')));
+ expect(frame.member, equals('bar'));
+ expect(frame.line, equals(2));
+ expect(frame.column, equals(4));
+ });
+
+ group('cleans up', () {
+ test('Firefox junk', () {
+ expect(_prettify('foo/<'), equals('foo'));
+ expect(_prettify('foo<'), equals('foo'));
+ });
+
+ test('arity indicators', () {
+ expect(_prettify(r'foo$1'), equals('foo'));
+ expect(_prettify(r'foo$1234'), equals('foo'));
+ });
+
+ test('named arguments', () {
+ expect(_prettify(r'foo$1$bar'), equals('foo'));
+ expect(_prettify(r'foo$123$bar$bang$qux'), equals('foo'));
+ });
+
+ test('closures', () {
+ expect(_prettify('foo_closure.call'), equals('foo.<fn>'));
+ });
+
+ test('nested closures', () {
+ expect(_prettify('foo__closure.call'), equals('foo.<fn>.<fn>'));
+ expect(
+ _prettify('foo____closure.call'), equals('foo.<fn>.<fn>.<fn>.<fn>'));
+ });
+
+ test('.call', () {
+ expect(_prettify('foo.call'), equals('foo'));
+ });
+
+ test('top-level functions', () {
+ expect(_prettify('dart.foo'), equals('foo'));
+ });
+
+ test('library namespaces', () {
+ expect(_prettify(r'my_library$foo'), equals('foo'));
+ });
+
+ test('static methods', () {
+ expect(_prettify(r'Foo.static.foo'), equals('foo'));
+ });
+
+ test('instance methods', () {
+ expect(_prettify(r'Foo_bar__baz'), equals('Foo.bar._baz'));
+ });
+
+ test('lots of stuff', () {
+ expect(_prettify(r'lib$Foo.static.lib$Foo_closure.call$0/<'),
+ equals('Foo.<fn>'));
+ });
+ });
+}
+
+/// Like [mapStackTrace], but is guaranteed to return a [Trace] so it can be
+/// inspected.
+Trace _mapTrace(Mapping sourceMap, StackTrace stackTrace,
+ {bool minified = false, Map<String, Uri>? packageMap, Uri? sdkRoot}) {
+ return Trace.from(mapStackTrace(sourceMap, stackTrace,
+ minified: minified, packageMap: packageMap, sdkRoot: sdkRoot));
+}
+
+/// Like [mapStackTrace], but is guaranteed to return a [Chain] so it can be
+/// inspected.
+Chain _mapChain(Mapping sourceMap, StackTrace stackTrace,
+ {bool minified = false, Map<String, Uri>? packageMap, Uri? sdkRoot}) {
+ return Chain.forTrace(mapStackTrace(sourceMap, stackTrace,
+ minified: minified, packageMap: packageMap, sdkRoot: sdkRoot));
+}
+
+/// Runs the mapper's prettification logic on [member] and returns the result.
+String? _prettify(String member) {
+ var trace = Trace([Frame(Uri.parse('foo.dart.js'), 10, 11, member)]);
+ return _mapTrace(_simpleMapping, trace).frames.first.member;
+}
diff --git a/pkgs/source_maps/.gitignore b/pkgs/source_maps/.gitignore
new file mode 100644
index 0000000..f73b2f9
--- /dev/null
+++ b/pkgs/source_maps/.gitignore
@@ -0,0 +1,4 @@
+.dart_tool/
+.packages
+.pub/
+pubspec.lock
diff --git a/pkgs/source_maps/CHANGELOG.md b/pkgs/source_maps/CHANGELOG.md
new file mode 100644
index 0000000..ae7711e
--- /dev/null
+++ b/pkgs/source_maps/CHANGELOG.md
@@ -0,0 +1,131 @@
+## 0.10.13
+
+* Require Dart 3.3
+* Move to `dart-lang/tools` monorepo.
+
+## 0.10.12
+
+* Add additional types at API boundaries.
+
+## 0.10.11
+
+* Populate the pubspec `repository` field.
+* Update the source map documentation link in the readme.
+
+## 0.10.10
+
+* Stable release for null safety.
+
+## 0.10.9
+
+* Fix a number of document comment issues.
+* Allow parsing source map files with a missing `names` field.
+
+## 0.10.8
+
+* Preserve source-map extensions in `SingleMapping`. Extensions are keys in the
+ json map that start with `"x_"`.
+
+## 0.10.7
+
+* Set max SDK version to `<3.0.0`, and adjust other dependencies.
+
+## 0.10.6
+
+* Require version 2.0.0 of the Dart SDK.
+
+## 0.10.5
+
+* Add a `SingleMapping.files` field which provides access to `SourceFile`s
+ representing the `"sourcesContent"` fields in the source map.
+
+* Add an `includeSourceContents` flag to `SingleMapping.toJson()` which
+ indicates whether to include source file contents in the source map.
+
+## 0.10.4
+* Implement `highlight` in `SourceMapFileSpan`.
+* Require version `^1.3.0` of `source_span`.
+
+## 0.10.3
+ * Add `addMapping` and `containsMapping` members to `MappingBundle`.
+
+## 0.10.2
+ * Support for extended source map format.
+ * Polish `MappingBundle.spanFor` handling of URIs that have a suffix that
+ exactly match a source map in the MappingBundle.
+
+## 0.10.1+5
+ * Fix strong mode warning in test.
+
+## 0.10.1+4
+
+* Extend `MappingBundle.spanFor` to accept requests for output files that
+ don't have source maps.
+
+## 0.10.1+3
+
+* Add `MappingBundle` class that handles extended source map format that
+ supports source maps for multiple output files in a single mapper.
+ Extend `Mapping.spanFor` API to accept a uri parameter that is optional
+ for normal source maps but required for MappingBundle source maps.
+
+## 0.10.1+2
+
+* Fix more strong mode warnings.
+
+## 0.10.1+1
+
+* Fix all strong mode warnings.
+
+## 0.10.1
+
+* Add a `mapUrl` named argument to `parse` and `parseJson`. This argument is
+ used to resolve source URLs for source spans.
+
+## 0.10.0+2
+
+* Fix analyzer error (FileSpan has a new field since `source_span` 1.1.1)
+
+## 0.10.0+1
+
+* Remove an unnecessary warning printed when the "file" field is missing from a
+ Json formatted source map. This field is optional and its absence is not
+ unusual.
+
+## 0.10.0
+
+* Remove the `Span`, `Location` and `SourceFile` classes. Use the
+ corresponding `source_span` classes instead.
+
+## 0.9.4
+
+* Update `SpanFormatException` with `source` and `offset`.
+
+* All methods that take `Span`s, `Location`s, and `SourceFile`s as inputs now
+ also accept the corresponding `source_span` classes as well. Using the old
+ classes is now deprecated and will be unsupported in version 0.10.0.
+
+## 0.9.3
+
+* Support writing SingleMapping objects to source map version 3 format.
+* Support the `sourceRoot` field in the SingleMapping class.
+* Support updating the `targetUrl` field in the SingleMapping class.
+
+## 0.9.2+2
+
+* Fix a bug in `FixedSpan.getLocationMessage`.
+
+## 0.9.2+1
+
+* Minor readability improvements to `FixedSpan.getLocationMessage` and
+ `SpanException.toString`.
+
+## 0.9.2
+
+* Add `SpanException` and `SpanFormatException` classes.
+
+## 0.9.1
+
+* Support unmapped areas in source maps.
+
+* Increase the readability of location messages.
diff --git a/pkgs/source_maps/LICENSE b/pkgs/source_maps/LICENSE
new file mode 100644
index 0000000..162572a
--- /dev/null
+++ b/pkgs/source_maps/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/source_maps/README.md b/pkgs/source_maps/README.md
new file mode 100644
index 0000000..cf80291
--- /dev/null
+++ b/pkgs/source_maps/README.md
@@ -0,0 +1,25 @@
+[](https://github.com/dart-lang/tools/actions/workflows/source_maps.yaml)
+[](https://pub.dev/packages/source_maps)
+[](https://pub.dev/packages/source_maps/publisher)
+
+This project implements a Dart pub package to work with source maps.
+
+## Docs and usage
+
+The implementation is based on the [source map version 3 spec][spec] which was
+originated from the [Closure Compiler][closure] and has been implemented in
+Chrome and Firefox.
+
+In this package we provide:
+
+ * Data types defining file locations and spans: these are not part of the
+ original source map specification. These data types are great for tracking
+ source locations on source maps, but they can also be used by tools to
+ reporting useful error messages that include on source locations.
+ * A builder that creates a source map programmatically and produces the encoded
+ source map format.
+ * A parser that reads the source map format and provides APIs to read the
+ mapping information.
+
+[closure]: https://github.com/google/closure-compiler/wiki/Source-Maps
+[spec]: https://docs.google.com/a/google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
diff --git a/pkgs/source_maps/analysis_options.yaml b/pkgs/source_maps/analysis_options.yaml
new file mode 100644
index 0000000..d978f81
--- /dev/null
+++ b/pkgs/source_maps/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:dart_flutter_team_lints/analysis_options.yaml
diff --git a/pkgs/source_maps/lib/builder.dart b/pkgs/source_maps/lib/builder.dart
new file mode 100644
index 0000000..54ba743
--- /dev/null
+++ b/pkgs/source_maps/lib/builder.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Contains a builder object useful for creating source maps programatically.
+library source_maps.builder;
+
+// TODO(sigmund): add a builder for multi-section mappings.
+
+import 'dart:convert';
+
+import 'package:source_span/source_span.dart';
+
+import 'parser.dart';
+import 'src/source_map_span.dart';
+
+/// Builds a source map given a set of mappings.
+class SourceMapBuilder {
+ final List<Entry> _entries = <Entry>[];
+
+ /// Adds an entry mapping the [targetOffset] to [source].
+ void addFromOffset(SourceLocation source, SourceFile targetFile,
+ int targetOffset, String identifier) {
+ ArgumentError.checkNotNull(targetFile, 'targetFile');
+ _entries.add(Entry(source, targetFile.location(targetOffset), identifier));
+ }
+
+ /// Adds an entry mapping [target] to [source].
+ ///
+ /// If [isIdentifier] is true or if [target] is a [SourceMapSpan] with
+ /// `isIdentifier` set to true, this entry is considered to represent an
+ /// identifier whose value will be stored in the source map. [isIdentifier]
+ /// takes precedence over [target]'s `isIdentifier` value.
+ void addSpan(SourceSpan source, SourceSpan target, {bool? isIdentifier}) {
+ isIdentifier ??= source is SourceMapSpan ? source.isIdentifier : false;
+
+ var name = isIdentifier ? source.text : null;
+ _entries.add(Entry(source.start, target.start, name));
+ }
+
+ /// Adds an entry mapping [target] to [source].
+ void addLocation(
+ SourceLocation source, SourceLocation target, String? identifier) {
+ _entries.add(Entry(source, target, identifier));
+ }
+
+ /// Encodes all mappings added to this builder as a json map.
+ Map<String, dynamic> build(String fileUrl) {
+ return SingleMapping.fromEntries(_entries, fileUrl).toJson();
+ }
+
+ /// Encodes all mappings added to this builder as a json string.
+ String toJson(String fileUrl) => jsonEncode(build(fileUrl));
+}
+
+/// An entry in the source map builder.
+class Entry implements Comparable<Entry> {
+ /// Span denoting the original location in the input source file
+ final SourceLocation source;
+
+ /// Span indicating the corresponding location in the target file.
+ final SourceLocation target;
+
+ /// An identifier name, when this location is the start of an identifier.
+ final String? identifierName;
+
+ /// Creates a new [Entry] mapping [target] to [source].
+ Entry(this.source, this.target, this.identifierName);
+
+ /// Implements [Comparable] to ensure that entries are ordered by their
+ /// location in the target file. We sort primarily by the target offset
+ /// because source map files are encoded by printing each mapping in order as
+ /// they appear in the target file.
+ @override
+ int compareTo(Entry other) {
+ var res = target.compareTo(other.target);
+ if (res != 0) return res;
+ res = source.sourceUrl
+ .toString()
+ .compareTo(other.source.sourceUrl.toString());
+ if (res != 0) return res;
+ return source.compareTo(other.source);
+ }
+}
diff --git a/pkgs/source_maps/lib/parser.dart b/pkgs/source_maps/lib/parser.dart
new file mode 100644
index 0000000..b699ac7
--- /dev/null
+++ b/pkgs/source_maps/lib/parser.dart
@@ -0,0 +1,718 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Contains the top-level function to parse source maps version 3.
+library source_maps.parser;
+
+import 'dart:convert';
+
+import 'package:source_span/source_span.dart';
+
+import 'builder.dart' as builder;
+import 'src/source_map_span.dart';
+import 'src/utils.dart';
+import 'src/vlq.dart';
+
+/// Parses a source map directly from a json string.
+///
+/// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of
+/// the source map file itself. If it's passed, any URLs in the source
+/// map will be interpreted as relative to this URL when generating spans.
+// TODO(sigmund): evaluate whether other maps should have the json parsed, or
+// the string represenation.
+// TODO(tjblasi): Ignore the first line of [jsonMap] if the JSON safety string
+// `)]}'` begins the string representation of the map.
+Mapping parse(String jsonMap,
+ {Map<String, Map>? otherMaps, /*String|Uri*/ Object? mapUrl}) =>
+ parseJson(jsonDecode(jsonMap) as Map, otherMaps: otherMaps, mapUrl: mapUrl);
+
+/// Parses a source map or source map bundle directly from a json string.
+///
+/// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of
+/// the source map file itself. If it's passed, any URLs in the source
+/// map will be interpreted as relative to this URL when generating spans.
+Mapping parseExtended(String jsonMap,
+ {Map<String, Map>? otherMaps, /*String|Uri*/ Object? mapUrl}) =>
+ parseJsonExtended(jsonDecode(jsonMap),
+ otherMaps: otherMaps, mapUrl: mapUrl);
+
+/// Parses a source map or source map bundle.
+///
+/// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of
+/// the source map file itself. If it's passed, any URLs in the source
+/// map will be interpreted as relative to this URL when generating spans.
+Mapping parseJsonExtended(/*List|Map*/ Object? json,
+ {Map<String, Map>? otherMaps, /*String|Uri*/ Object? mapUrl}) {
+ if (json is List) {
+ return MappingBundle.fromJson(json, mapUrl: mapUrl);
+ }
+ return parseJson(json as Map);
+}
+
+/// Parses a source map.
+///
+/// [mapUrl], which may be either a [String] or a [Uri], indicates the URL of
+/// the source map file itself. If it's passed, any URLs in the source
+/// map will be interpreted as relative to this URL when generating spans.
+Mapping parseJson(Map map,
+ {Map<String, Map>? otherMaps, /*String|Uri*/ Object? mapUrl}) {
+ if (map['version'] != 3) {
+ throw ArgumentError('unexpected source map version: ${map["version"]}. '
+ 'Only version 3 is supported.');
+ }
+
+ if (map.containsKey('sections')) {
+ if (map.containsKey('mappings') ||
+ map.containsKey('sources') ||
+ map.containsKey('names')) {
+ throw const FormatException('map containing "sections" '
+ 'cannot contain "mappings", "sources", or "names".');
+ }
+ return MultiSectionMapping.fromJson(map['sections'] as List, otherMaps,
+ mapUrl: mapUrl);
+ }
+ return SingleMapping.fromJson(map.cast<String, dynamic>(), mapUrl: mapUrl);
+}
+
+/// A mapping parsed out of a source map.
+abstract class Mapping {
+ /// Returns the span associated with [line] and [column].
+ ///
+ /// [uri] is the optional location of the output file to find the span for
+ /// to disambiguate cases where a mapping may have different mappings for
+ /// different output files.
+ SourceMapSpan? spanFor(int line, int column,
+ {Map<String, SourceFile>? files, String? uri});
+
+ /// Returns the span associated with [location].
+ SourceMapSpan? spanForLocation(SourceLocation location,
+ {Map<String, SourceFile>? files}) {
+ return spanFor(location.line, location.column,
+ uri: location.sourceUrl?.toString(), files: files);
+ }
+}
+
+/// A meta-level map containing sections.
+class MultiSectionMapping extends Mapping {
+ /// For each section, the start line offset.
+ final List<int> _lineStart = <int>[];
+
+ /// For each section, the start column offset.
+ final List<int> _columnStart = <int>[];
+
+ /// For each section, the actual source map information, which is not adjusted
+ /// for offsets.
+ final List<Mapping> _maps = <Mapping>[];
+
+ /// Creates a section mapping from json.
+ MultiSectionMapping.fromJson(List sections, Map<String, Map>? otherMaps,
+ {/*String|Uri*/ Object? mapUrl}) {
+ for (var section in sections.cast<Map>()) {
+ var offset = section['offset'] as Map?;
+ if (offset == null) throw const FormatException('section missing offset');
+
+ var line = offset['line'] as int?;
+ if (line == null) throw const FormatException('offset missing line');
+
+ var column = offset['column'] as int?;
+ if (column == null) throw const FormatException('offset missing column');
+
+ _lineStart.add(line);
+ _columnStart.add(column);
+
+ var url = section['url'] as String?;
+ var map = section['map'] as Map?;
+
+ if (url != null && map != null) {
+ throw const FormatException(
+ "section can't use both url and map entries");
+ } else if (url != null) {
+ var other = otherMaps?[url];
+ if (otherMaps == null || other == null) {
+ throw FormatException(
+ 'section contains refers to $url, but no map was '
+ 'given for it. Make sure a map is passed in "otherMaps"');
+ }
+ _maps.add(parseJson(other, otherMaps: otherMaps, mapUrl: url));
+ } else if (map != null) {
+ _maps.add(parseJson(map, otherMaps: otherMaps, mapUrl: mapUrl));
+ } else {
+ throw const FormatException('section missing url or map');
+ }
+ }
+ if (_lineStart.isEmpty) {
+ throw const FormatException('expected at least one section');
+ }
+ }
+
+ int _indexFor(int line, int column) {
+ for (var i = 0; i < _lineStart.length; i++) {
+ if (line < _lineStart[i]) return i - 1;
+ if (line == _lineStart[i] && column < _columnStart[i]) return i - 1;
+ }
+ return _lineStart.length - 1;
+ }
+
+ @override
+ SourceMapSpan? spanFor(int line, int column,
+ {Map<String, SourceFile>? files, String? uri}) {
+ // TODO(jacobr): perhaps verify that targetUrl matches the actual uri
+ // or at least ends in the same file name.
+ var index = _indexFor(line, column);
+ return _maps[index].spanFor(
+ line - _lineStart[index], column - _columnStart[index],
+ files: files);
+ }
+
+ @override
+ String toString() {
+ var buff = StringBuffer('$runtimeType : [');
+ for (var i = 0; i < _lineStart.length; i++) {
+ buff
+ ..write('(')
+ ..write(_lineStart[i])
+ ..write(',')
+ ..write(_columnStart[i])
+ ..write(':')
+ ..write(_maps[i])
+ ..write(')');
+ }
+ buff.write(']');
+ return buff.toString();
+ }
+}
+
+class MappingBundle extends Mapping {
+ final Map<String, SingleMapping> _mappings = {};
+
+ MappingBundle();
+
+ MappingBundle.fromJson(List json, {/*String|Uri*/ Object? mapUrl}) {
+ for (var map in json) {
+ addMapping(parseJson(map as Map, mapUrl: mapUrl) as SingleMapping);
+ }
+ }
+
+ void addMapping(SingleMapping mapping) {
+ // TODO(jacobr): verify that targetUrl is valid uri instead of a windows
+ // path.
+ // TODO: Remove type arg https://github.com/dart-lang/sdk/issues/42227
+ var targetUrl = ArgumentError.checkNotNull<String>(
+ mapping.targetUrl, 'mapping.targetUrl');
+ _mappings[targetUrl] = mapping;
+ }
+
+ /// Encodes the Mapping mappings as a json map.
+ List toJson() => _mappings.values.map((v) => v.toJson()).toList();
+
+ @override
+ String toString() {
+ var buff = StringBuffer();
+ for (var map in _mappings.values) {
+ buff.write(map.toString());
+ }
+ return buff.toString();
+ }
+
+ bool containsMapping(String url) => _mappings.containsKey(url);
+
+ @override
+ SourceMapSpan? spanFor(int line, int column,
+ {Map<String, SourceFile>? files, String? uri}) {
+ // TODO: Remove type arg https://github.com/dart-lang/sdk/issues/42227
+ uri = ArgumentError.checkNotNull<String>(uri, 'uri');
+
+ // Find the longest suffix of the uri that matches the sourcemap
+ // where the suffix starts after a path segment boundary.
+ // We consider ":" and "/" as path segment boundaries so that
+ // "package:" uris can be handled with minimal special casing. Having a
+ // few false positive path segment boundaries is not a significant issue
+ // as we prefer the longest matching prefix.
+ // Using package:path `path.split` to find path segment boundaries would
+ // not generate all of the path segment boundaries we want for "package:"
+ // urls as "package:package_name" would be one path segment when we want
+ // "package" and "package_name" to be sepearate path segments.
+
+ var onBoundary = true;
+ var separatorCodeUnits = ['/'.codeUnitAt(0), ':'.codeUnitAt(0)];
+ for (var i = 0; i < uri.length; ++i) {
+ if (onBoundary) {
+ var candidate = uri.substring(i);
+ var candidateMapping = _mappings[candidate];
+ if (candidateMapping != null) {
+ return candidateMapping.spanFor(line, column,
+ files: files, uri: candidate);
+ }
+ }
+ onBoundary = separatorCodeUnits.contains(uri.codeUnitAt(i));
+ }
+
+ // Note: when there is no source map for an uri, this behaves like an
+ // identity function, returning the requested location as the result.
+
+ // Create a mock offset for the output location. We compute it in terms
+ // of the input line and column to minimize the chances that two different
+ // line and column locations are mapped to the same offset.
+ var offset = line * 1000000 + column;
+ var location = SourceLocation(offset,
+ line: line, column: column, sourceUrl: Uri.parse(uri));
+ return SourceMapSpan(location, location, '');
+ }
+}
+
+/// A map containing direct source mappings.
+class SingleMapping extends Mapping {
+ /// Source urls used in the mapping, indexed by id.
+ final List<String> urls;
+
+ /// Source names used in the mapping, indexed by id.
+ final List<String> names;
+
+ /// The [SourceFile]s to which the entries in [lines] refer.
+ ///
+ /// This is in the same order as [urls]. If this was constructed using
+ /// [SingleMapping.fromEntries], this contains files from any [FileLocation]s
+ /// used to build the mapping. If it was parsed from JSON, it contains files
+ /// for any sources whose contents were provided via the `"sourcesContent"`
+ /// field.
+ ///
+ /// Files whose contents aren't available are `null`.
+ final List<SourceFile?> files;
+
+ /// Entries indicating the beginning of each span.
+ final List<TargetLineEntry> lines;
+
+ /// Url of the target file.
+ String? targetUrl;
+
+ /// Source root prepended to all entries in [urls].
+ String? sourceRoot;
+
+ final Uri? _mapUrl;
+
+ final Map<String, dynamic> extensions;
+
+ SingleMapping._(this.targetUrl, this.files, this.urls, this.names, this.lines)
+ : _mapUrl = null,
+ extensions = {};
+
+ factory SingleMapping.fromEntries(Iterable<builder.Entry> entries,
+ [String? fileUrl]) {
+ // The entries needs to be sorted by the target offsets.
+ var sourceEntries = entries.toList()..sort();
+ var lines = <TargetLineEntry>[];
+
+ // Indices associated with file urls that will be part of the source map. We
+ // rely on map order so that `urls.keys[urls[u]] == u`
+ var urls = <String, int>{};
+
+ // Indices associated with identifiers that will be part of the source map.
+ // We rely on map order so that `names.keys[names[n]] == n`
+ var names = <String, int>{};
+
+ /// The file for each URL, indexed by [urls]' values.
+ var files = <int, SourceFile>{};
+
+ int? lineNum;
+ late List<TargetEntry> targetEntries;
+ for (var sourceEntry in sourceEntries) {
+ if (lineNum == null || sourceEntry.target.line > lineNum) {
+ lineNum = sourceEntry.target.line;
+ targetEntries = <TargetEntry>[];
+ lines.add(TargetLineEntry(lineNum, targetEntries));
+ }
+
+ var sourceUrl = sourceEntry.source.sourceUrl;
+ var urlId = urls.putIfAbsent(
+ sourceUrl == null ? '' : sourceUrl.toString(), () => urls.length);
+
+ if (sourceEntry.source is FileLocation) {
+ files.putIfAbsent(
+ urlId, () => (sourceEntry.source as FileLocation).file);
+ }
+
+ var sourceEntryIdentifierName = sourceEntry.identifierName;
+ var srcNameId = sourceEntryIdentifierName == null
+ ? null
+ : names.putIfAbsent(sourceEntryIdentifierName, () => names.length);
+ targetEntries.add(TargetEntry(sourceEntry.target.column, urlId,
+ sourceEntry.source.line, sourceEntry.source.column, srcNameId));
+ }
+ return SingleMapping._(fileUrl, urls.values.map((i) => files[i]).toList(),
+ urls.keys.toList(), names.keys.toList(), lines);
+ }
+
+ SingleMapping.fromJson(Map<String, dynamic> map, {Object? mapUrl})
+ : targetUrl = map['file'] as String?,
+ urls = List<String>.from(map['sources'] as List),
+ names = List<String>.from((map['names'] as List?) ?? []),
+ files = List.filled((map['sources'] as List).length, null),
+ sourceRoot = map['sourceRoot'] as String?,
+ lines = <TargetLineEntry>[],
+ _mapUrl = mapUrl is String ? Uri.parse(mapUrl) : (mapUrl as Uri?),
+ extensions = {} {
+ var sourcesContent = map['sourcesContent'] == null
+ ? const <String?>[]
+ : List<String?>.from(map['sourcesContent'] as List);
+ for (var i = 0; i < urls.length && i < sourcesContent.length; i++) {
+ var source = sourcesContent[i];
+ if (source == null) continue;
+ files[i] = SourceFile.fromString(source, url: urls[i]);
+ }
+
+ var line = 0;
+ var column = 0;
+ var srcUrlId = 0;
+ var srcLine = 0;
+ var srcColumn = 0;
+ var srcNameId = 0;
+ var tokenizer = _MappingTokenizer(map['mappings'] as String);
+ var entries = <TargetEntry>[];
+
+ while (tokenizer.hasTokens) {
+ if (tokenizer.nextKind.isNewLine) {
+ if (entries.isNotEmpty) {
+ lines.add(TargetLineEntry(line, entries));
+ entries = <TargetEntry>[];
+ }
+ line++;
+ column = 0;
+ tokenizer._consumeNewLine();
+ continue;
+ }
+
+ // Decode the next entry, using the previous encountered values to
+ // decode the relative values.
+ //
+ // We expect 1, 4, or 5 values. If present, values are expected in the
+ // following order:
+ // 0: the starting column in the current line of the generated file
+ // 1: the id of the original source file
+ // 2: the starting line in the original source
+ // 3: the starting column in the original source
+ // 4: the id of the original symbol name
+ // The values are relative to the previous encountered values.
+ if (tokenizer.nextKind.isNewSegment) throw _segmentError(0, line);
+ column += tokenizer._consumeValue();
+ if (!tokenizer.nextKind.isValue) {
+ entries.add(TargetEntry(column));
+ } else {
+ srcUrlId += tokenizer._consumeValue();
+ if (srcUrlId >= urls.length) {
+ throw StateError(
+ 'Invalid source url id. $targetUrl, $line, $srcUrlId');
+ }
+ if (!tokenizer.nextKind.isValue) throw _segmentError(2, line);
+ srcLine += tokenizer._consumeValue();
+ if (!tokenizer.nextKind.isValue) throw _segmentError(3, line);
+ srcColumn += tokenizer._consumeValue();
+ if (!tokenizer.nextKind.isValue) {
+ entries.add(TargetEntry(column, srcUrlId, srcLine, srcColumn));
+ } else {
+ srcNameId += tokenizer._consumeValue();
+ if (srcNameId >= names.length) {
+ throw StateError('Invalid name id: $targetUrl, $line, $srcNameId');
+ }
+ entries.add(
+ TargetEntry(column, srcUrlId, srcLine, srcColumn, srcNameId));
+ }
+ }
+ if (tokenizer.nextKind.isNewSegment) tokenizer._consumeNewSegment();
+ }
+ if (entries.isNotEmpty) {
+ lines.add(TargetLineEntry(line, entries));
+ }
+
+ map.forEach((name, value) {
+ if (name.startsWith('x_')) extensions[name] = value;
+ });
+ }
+
+ /// Encodes the Mapping mappings as a json map.
+ ///
+ /// If [includeSourceContents] is `true`, this includes the source file
+ /// contents from [files] in the map if possible.
+ Map<String, dynamic> toJson({bool includeSourceContents = false}) {
+ var buff = StringBuffer();
+ var line = 0;
+ var column = 0;
+ var srcLine = 0;
+ var srcColumn = 0;
+ var srcUrlId = 0;
+ var srcNameId = 0;
+ var first = true;
+
+ for (var entry in lines) {
+ var nextLine = entry.line;
+ if (nextLine > line) {
+ for (var i = line; i < nextLine; ++i) {
+ buff.write(';');
+ }
+ line = nextLine;
+ column = 0;
+ first = true;
+ }
+
+ for (var segment in entry.entries) {
+ if (!first) buff.write(',');
+ first = false;
+ column = _append(buff, column, segment.column);
+
+ // Encoding can be just the column offset if there is no source
+ // information.
+ var newUrlId = segment.sourceUrlId;
+ if (newUrlId == null) continue;
+ srcUrlId = _append(buff, srcUrlId, newUrlId);
+ srcLine = _append(buff, srcLine, segment.sourceLine!);
+ srcColumn = _append(buff, srcColumn, segment.sourceColumn!);
+
+ if (segment.sourceNameId == null) continue;
+ srcNameId = _append(buff, srcNameId, segment.sourceNameId!);
+ }
+ }
+
+ var result = <String, dynamic>{
+ 'version': 3,
+ 'sourceRoot': sourceRoot ?? '',
+ 'sources': urls,
+ 'names': names,
+ 'mappings': buff.toString(),
+ };
+ if (targetUrl != null) result['file'] = targetUrl!;
+
+ if (includeSourceContents) {
+ result['sourcesContent'] = files.map((file) => file?.getText(0)).toList();
+ }
+ extensions.forEach((name, value) => result[name] = value);
+
+ return result;
+ }
+
+ /// Appends to [buff] a VLQ encoding of [newValue] using the difference
+ /// between [oldValue] and [newValue]
+ static int _append(StringBuffer buff, int oldValue, int newValue) {
+ buff.writeAll(encodeVlq(newValue - oldValue));
+ return newValue;
+ }
+
+ StateError _segmentError(int seen, int line) =>
+ StateError('Invalid entry in sourcemap, expected 1, 4, or 5'
+ ' values, but got $seen.\ntargeturl: $targetUrl, line: $line');
+
+ /// Returns [TargetLineEntry] which includes the location in the target [line]
+ /// number. In particular, the resulting entry is the last entry whose line
+ /// number is lower or equal to [line].
+ TargetLineEntry? _findLine(int line) {
+ var index = binarySearch(lines, (e) => e.line > line);
+ return (index <= 0) ? null : lines[index - 1];
+ }
+
+ /// Returns [TargetEntry] which includes the location denoted by
+ /// [line], [column]. If [lineEntry] corresponds to [line], then this will be
+ /// the last entry whose column is lower or equal than [column]. If
+ /// [lineEntry] corresponds to a line prior to [line], then the result will be
+ /// the very last entry on that line.
+ TargetEntry? _findColumn(int line, int column, TargetLineEntry? lineEntry) {
+ if (lineEntry == null || lineEntry.entries.isEmpty) return null;
+ if (lineEntry.line != line) return lineEntry.entries.last;
+ var entries = lineEntry.entries;
+ var index = binarySearch(entries, (e) => e.column > column);
+ return (index <= 0) ? null : entries[index - 1];
+ }
+
+ @override
+ SourceMapSpan? spanFor(int line, int column,
+ {Map<String, SourceFile>? files, String? uri}) {
+ var entry = _findColumn(line, column, _findLine(line));
+ if (entry == null) return null;
+
+ var sourceUrlId = entry.sourceUrlId;
+ if (sourceUrlId == null) return null;
+
+ var url = urls[sourceUrlId];
+ if (sourceRoot != null) {
+ url = '$sourceRoot$url';
+ }
+
+ var sourceNameId = entry.sourceNameId;
+ var file = files?[url];
+ if (file != null) {
+ var start = file.getOffset(entry.sourceLine!, entry.sourceColumn);
+ if (sourceNameId != null) {
+ var text = names[sourceNameId];
+ return SourceMapFileSpan(file.span(start, start + text.length),
+ isIdentifier: true);
+ } else {
+ return SourceMapFileSpan(file.location(start).pointSpan());
+ }
+ } else {
+ var start = SourceLocation(0,
+ sourceUrl: _mapUrl?.resolve(url) ?? url,
+ line: entry.sourceLine,
+ column: entry.sourceColumn);
+
+ // Offset and other context is not available.
+ if (sourceNameId != null) {
+ return SourceMapSpan.identifier(start, names[sourceNameId]);
+ } else {
+ return SourceMapSpan(start, start, '');
+ }
+ }
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('$runtimeType : [')
+ ..write('targetUrl: ')
+ ..write(targetUrl)
+ ..write(', sourceRoot: ')
+ ..write(sourceRoot)
+ ..write(', urls: ')
+ ..write(urls)
+ ..write(', names: ')
+ ..write(names)
+ ..write(', lines: ')
+ ..write(lines)
+ ..write(']'))
+ .toString();
+ }
+
+ String get debugString {
+ var buff = StringBuffer();
+ for (var lineEntry in lines) {
+ var line = lineEntry.line;
+ for (var entry in lineEntry.entries) {
+ buff
+ ..write(targetUrl)
+ ..write(': ')
+ ..write(line)
+ ..write(':')
+ ..write(entry.column);
+ var sourceUrlId = entry.sourceUrlId;
+ if (sourceUrlId != null) {
+ buff
+ ..write(' --> ')
+ ..write(sourceRoot)
+ ..write(urls[sourceUrlId])
+ ..write(': ')
+ ..write(entry.sourceLine)
+ ..write(':')
+ ..write(entry.sourceColumn);
+ }
+ var sourceNameId = entry.sourceNameId;
+ if (sourceNameId != null) {
+ buff
+ ..write(' (')
+ ..write(names[sourceNameId])
+ ..write(')');
+ }
+ buff.write('\n');
+ }
+ }
+ return buff.toString();
+ }
+}
+
+/// A line entry read from a source map.
+class TargetLineEntry {
+ final int line;
+ List<TargetEntry> entries;
+ TargetLineEntry(this.line, this.entries);
+
+ @override
+ String toString() => '$runtimeType: $line $entries';
+}
+
+/// A target segment entry read from a source map
+class TargetEntry {
+ final int column;
+ final int? sourceUrlId;
+ final int? sourceLine;
+ final int? sourceColumn;
+ final int? sourceNameId;
+
+ TargetEntry(this.column,
+ [this.sourceUrlId,
+ this.sourceLine,
+ this.sourceColumn,
+ this.sourceNameId]);
+
+ @override
+ String toString() => '$runtimeType: '
+ '($column, $sourceUrlId, $sourceLine, $sourceColumn, $sourceNameId)';
+}
+
+/// A character iterator over a string that can peek one character ahead.
+class _MappingTokenizer implements Iterator<String> {
+ final String _internal;
+ final int _length;
+ int index = -1;
+ _MappingTokenizer(String internal)
+ : _internal = internal,
+ _length = internal.length;
+
+ // Iterator API is used by decodeVlq to consume VLQ entries.
+ @override
+ bool moveNext() => ++index < _length;
+
+ @override
+ String get current => (index >= 0 && index < _length)
+ ? _internal[index]
+ : throw RangeError.index(index, _internal);
+
+ bool get hasTokens => index < _length - 1 && _length > 0;
+
+ _TokenKind get nextKind {
+ if (!hasTokens) return _TokenKind.eof;
+ var next = _internal[index + 1];
+ if (next == ';') return _TokenKind.line;
+ if (next == ',') return _TokenKind.segment;
+ return _TokenKind.value;
+ }
+
+ int _consumeValue() => decodeVlq(this);
+ void _consumeNewLine() {
+ ++index;
+ }
+
+ void _consumeNewSegment() {
+ ++index;
+ }
+
+ // Print the state of the iterator, with colors indicating the current
+ // position.
+ @override
+ String toString() {
+ var buff = StringBuffer();
+ for (var i = 0; i < index; i++) {
+ buff.write(_internal[i]);
+ }
+ buff.write('[31m');
+ try {
+ buff.write(current);
+ // TODO: Determine whether this try / catch can be removed.
+ // ignore: avoid_catching_errors
+ } on RangeError catch (_) {}
+ buff.write('[0m');
+ for (var i = index + 1; i < _internal.length; i++) {
+ buff.write(_internal[i]);
+ }
+ buff.write(' ($index)');
+ return buff.toString();
+ }
+}
+
+class _TokenKind {
+ static const _TokenKind line = _TokenKind(isNewLine: true);
+ static const _TokenKind segment = _TokenKind(isNewSegment: true);
+ static const _TokenKind eof = _TokenKind(isEof: true);
+ static const _TokenKind value = _TokenKind();
+ final bool isNewLine;
+ final bool isNewSegment;
+ final bool isEof;
+ bool get isValue => !isNewLine && !isNewSegment && !isEof;
+
+ const _TokenKind(
+ {this.isNewLine = false, this.isNewSegment = false, this.isEof = false});
+}
diff --git a/pkgs/source_maps/lib/printer.dart b/pkgs/source_maps/lib/printer.dart
new file mode 100644
index 0000000..17733cd
--- /dev/null
+++ b/pkgs/source_maps/lib/printer.dart
@@ -0,0 +1,262 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Contains a code printer that generates code by recording the source maps.
+library source_maps.printer;
+
+import 'package:source_span/source_span.dart';
+
+import 'builder.dart';
+import 'src/source_map_span.dart';
+import 'src/utils.dart';
+
+/// A simple printer that keeps track of offset locations and records source
+/// maps locations.
+class Printer {
+ final String filename;
+ final StringBuffer _buff = StringBuffer();
+ final SourceMapBuilder _maps = SourceMapBuilder();
+ String get text => _buff.toString();
+ String get map => _maps.toJson(filename);
+
+ /// Current source location mapping.
+ SourceLocation? _loc;
+
+ /// Current line in the buffer;
+ int _line = 0;
+
+ /// Current column in the buffer.
+ int _column = 0;
+
+ Printer(this.filename);
+
+ /// Add [str] contents to the output, tracking new lines to track correct
+ /// positions for span locations. When [projectMarks] is true, this method
+ /// adds a source map location on each new line, projecting that every new
+ /// line in the target file (printed here) corresponds to a new line in the
+ /// source file.
+ void add(String str, {bool projectMarks = false}) {
+ var chars = str.runes.toList();
+ var length = chars.length;
+ for (var i = 0; i < length; i++) {
+ var c = chars[i];
+ if (c == lineFeed ||
+ (c == carriageReturn &&
+ (i + 1 == length || chars[i + 1] != lineFeed))) {
+ // Return not followed by line-feed is treated as a new line.
+ _line++;
+ _column = 0;
+ {
+ // **Warning**: Any calls to `mark` will change the value of `_loc`,
+ // so this local variable is no longer up to date after that point.
+ //
+ // This is why it has been put inside its own block to limit the
+ // scope in which it is available.
+ var loc = _loc;
+ if (projectMarks && loc != null) {
+ if (loc is FileLocation) {
+ var file = loc.file;
+ mark(file.location(file.getOffset(loc.line + 1)));
+ } else {
+ mark(SourceLocation(0,
+ sourceUrl: loc.sourceUrl, line: loc.line + 1, column: 0));
+ }
+ }
+ }
+ } else {
+ _column++;
+ }
+ }
+ _buff.write(str);
+ }
+
+ /// Append a [total] number of spaces in the target file. Typically used for
+ /// formatting indentation.
+ void addSpaces(int total) {
+ for (var i = 0; i < total; i++) {
+ _buff.write(' ');
+ }
+ _column += total;
+ }
+
+ /// Marks that the current point in the target file corresponds to the [mark]
+ /// in the source file, which can be either a [SourceLocation] or a
+ /// [SourceSpan]. When the mark is a [SourceMapSpan] with `isIdentifier` set,
+ /// this also records the name of the identifier in the source map
+ /// information.
+ void mark(Object mark) {
+ late final SourceLocation loc;
+ String? identifier;
+ if (mark is SourceLocation) {
+ loc = mark;
+ } else if (mark is SourceSpan) {
+ loc = mark.start;
+ if (mark is SourceMapSpan && mark.isIdentifier) identifier = mark.text;
+ }
+ _maps.addLocation(loc,
+ SourceLocation(_buff.length, line: _line, column: _column), identifier);
+ _loc = loc;
+ }
+}
+
+/// A more advanced printer that keeps track of offset locations to record
+/// source maps, but additionally allows nesting of different kind of items,
+/// including [NestedPrinter]s, and it let's you automatically indent text.
+///
+/// This class is especially useful when doing code generation, where different
+/// pieces of the code are generated independently on separate printers, and are
+/// finally put together in the end.
+class NestedPrinter implements NestedItem {
+ /// Items recoded by this printer, which can be [String] literals,
+ /// [NestedItem]s, and source map information like [SourceLocation] and
+ /// [SourceSpan].
+ final List<Object> _items = [];
+
+ /// Internal buffer to merge consecutive strings added to this printer.
+ StringBuffer? _buff;
+
+ /// Current indentation, which can be updated from outside this class.
+ int indent;
+
+ /// [Printer] used during the last call to [build], if any.
+ Printer? printer;
+
+ /// Returns the text produced after calling [build].
+ String? get text => printer?.text;
+
+ /// Returns the source-map information produced after calling [build].
+ String? get map => printer?.map;
+
+ /// Item used to indicate that the following item is copied from the original
+ /// source code, and hence we should preserve source-maps on every new line.
+ static final _original = Object();
+
+ NestedPrinter([this.indent = 0]);
+
+ /// Adds [object] to this printer. [object] can be a [String],
+ /// [NestedPrinter], or anything implementing [NestedItem]. If [object] is a
+ /// [String], the value is appended directly, without doing any formatting
+ /// changes. If you wish to add a line of code with automatic indentation, use
+ /// [addLine] instead. [NestedPrinter]s and [NestedItem]s are not processed
+ /// until [build] gets called later on. We ensure that [build] emits every
+ /// object in the order that they were added to this printer.
+ ///
+ /// The [location] and [span] parameters indicate the corresponding source map
+ /// location of [object] in the original input. Only one, [location] or
+ /// [span], should be provided at a time.
+ ///
+ /// Indicate [isOriginal] when [object] is copied directly from the user code.
+ /// Setting [isOriginal] will make this printer propagate source map locations
+ /// on every line-break.
+ void add(Object object,
+ {SourceLocation? location, SourceSpan? span, bool isOriginal = false}) {
+ if (object is! String || location != null || span != null || isOriginal) {
+ _flush();
+ assert(location == null || span == null);
+ if (location != null) _items.add(location);
+ if (span != null) _items.add(span);
+ if (isOriginal) _items.add(_original);
+ }
+
+ if (object is String) {
+ _appendString(object);
+ } else {
+ _items.add(object);
+ }
+ }
+
+ /// Append `2 * indent` spaces to this printer.
+ void insertIndent() => _indent(indent);
+
+ /// Add a [line], autoindenting to the current value of [indent]. Note,
+ /// indentation is not inferred from the contents added to this printer. If a
+ /// line starts or ends an indentation block, you need to also update [indent]
+ /// accordingly. Also, indentation is not adapted for nested printers. If
+ /// you add a [NestedPrinter] to this printer, its indentation is set
+ /// separately and will not include any the indentation set here.
+ ///
+ /// The [location] and [span] parameters indicate the corresponding source map
+ /// location of [line] in the original input. Only one, [location] or
+ /// [span], should be provided at a time.
+ void addLine(String? line, {SourceLocation? location, SourceSpan? span}) {
+ if (location != null || span != null) {
+ _flush();
+ assert(location == null || span == null);
+ if (location != null) _items.add(location);
+ if (span != null) _items.add(span);
+ }
+ if (line == null) return;
+ if (line != '') {
+ // We don't indent empty lines.
+ _indent(indent);
+ _appendString(line);
+ }
+ _appendString('\n');
+ }
+
+ /// Appends a string merging it with any previous strings, if possible.
+ void _appendString(String s) {
+ var buf = _buff ??= StringBuffer();
+ buf.write(s);
+ }
+
+ /// Adds all of the current [_buff] contents as a string item.
+ void _flush() {
+ if (_buff != null) {
+ _items.add(_buff.toString());
+ _buff = null;
+ }
+ }
+
+ void _indent(int indent) {
+ for (var i = 0; i < indent; i++) {
+ _appendString(' ');
+ }
+ }
+
+ /// Returns a string representation of all the contents appended to this
+ /// printer, including source map location tokens.
+ @override
+ String toString() {
+ _flush();
+ return (StringBuffer()..writeAll(_items)).toString();
+ }
+
+ /// Builds the output of this printer and source map information. After
+ /// calling this function, you can use [text] and [map] to retrieve the
+ /// geenrated code and source map information, respectively.
+ void build(String filename) {
+ writeTo(printer = Printer(filename));
+ }
+
+ /// Implements the [NestedItem] interface.
+ @override
+ void writeTo(Printer printer) {
+ _flush();
+ var propagate = false;
+ for (var item in _items) {
+ if (item is NestedItem) {
+ item.writeTo(printer);
+ } else if (item is String) {
+ printer.add(item, projectMarks: propagate);
+ propagate = false;
+ } else if (item is SourceLocation || item is SourceSpan) {
+ printer.mark(item);
+ } else if (item == _original) {
+ // we insert booleans when we are about to quote text that was copied
+ // from the original source. In such case, we will propagate marks on
+ // every new-line.
+ propagate = true;
+ } else {
+ throw UnsupportedError('Unknown item type: $item');
+ }
+ }
+ }
+}
+
+/// An item added to a [NestedPrinter].
+abstract class NestedItem {
+ /// Write the contents of this item into [printer].
+ void writeTo(Printer printer);
+}
diff --git a/pkgs/source_maps/lib/refactor.dart b/pkgs/source_maps/lib/refactor.dart
new file mode 100644
index 0000000..98e0c93
--- /dev/null
+++ b/pkgs/source_maps/lib/refactor.dart
@@ -0,0 +1,140 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Tools to help implement refactoring like transformations to Dart code.
+///
+/// [TextEditTransaction] supports making a series of changes to a text buffer.
+/// [guessIndent] helps to guess the appropriate indentiation for the new code.
+library source_maps.refactor;
+
+import 'package:source_span/source_span.dart';
+
+import 'printer.dart';
+import 'src/utils.dart';
+
+/// Editable text transaction.
+///
+/// Applies a series of edits using original location
+/// information, and composes them into the edited string.
+class TextEditTransaction {
+ final SourceFile? file;
+ final String original;
+ final _edits = <_TextEdit>[];
+
+ /// Creates a new transaction.
+ TextEditTransaction(this.original, this.file);
+
+ bool get hasEdits => _edits.isNotEmpty;
+
+ /// Edit the original text, replacing text on the range [begin] and [end]
+ /// with the [replacement]. [replacement] can be either a string or a
+ /// [NestedPrinter].
+ void edit(int begin, int end, Object replacement) {
+ _edits.add(_TextEdit(begin, end, replacement));
+ }
+
+ /// Create a source map [SourceLocation] for [offset], if [file] is not
+ /// `null`.
+ SourceLocation? _loc(int offset) => file?.location(offset);
+
+ /// Applies all pending [edit]s and returns a [NestedPrinter] containing the
+ /// rewritten string and source map information. [file]`.location` is given to
+ /// the underlying printer to indicate the name of the generated file that
+ /// will contains the source map information.
+ ///
+ /// Throws [UnsupportedError] if the edits were overlapping. If no edits were
+ /// made, the printer simply contains the original string.
+ NestedPrinter commit() {
+ var printer = NestedPrinter();
+ if (_edits.isEmpty) {
+ return printer..add(original, location: _loc(0), isOriginal: true);
+ }
+
+ // Sort edits by start location.
+ _edits.sort();
+
+ var consumed = 0;
+ for (var edit in _edits) {
+ if (consumed > edit.begin) {
+ var sb = StringBuffer();
+ sb
+ ..write(file?.location(edit.begin).toolString)
+ ..write(': overlapping edits. Insert at offset ')
+ ..write(edit.begin)
+ ..write(' but have consumed ')
+ ..write(consumed)
+ ..write(' input characters. List of edits:');
+ for (var e in _edits) {
+ sb
+ ..write('\n ')
+ ..write(e);
+ }
+ throw UnsupportedError(sb.toString());
+ }
+
+ // Add characters from the original string between this edit and the last
+ // one, if any.
+ var betweenEdits = original.substring(consumed, edit.begin);
+ printer
+ ..add(betweenEdits, location: _loc(consumed), isOriginal: true)
+ ..add(edit.replace, location: _loc(edit.begin));
+ consumed = edit.end;
+ }
+
+ // Add any text from the end of the original string that was not replaced.
+ printer.add(original.substring(consumed),
+ location: _loc(consumed), isOriginal: true);
+ return printer;
+ }
+}
+
+class _TextEdit implements Comparable<_TextEdit> {
+ final int begin;
+ final int end;
+
+ /// The replacement used by the edit, can be a string or a [NestedPrinter].
+ final Object replace;
+
+ _TextEdit(this.begin, this.end, this.replace);
+
+ int get length => end - begin;
+
+ @override
+ String toString() => '(Edit @ $begin,$end: "$replace")';
+
+ @override
+ int compareTo(_TextEdit other) {
+ var diff = begin - other.begin;
+ if (diff != 0) return diff;
+ return end - other.end;
+ }
+}
+
+/// Returns all whitespace characters at the start of [charOffset]'s line.
+String guessIndent(String code, int charOffset) {
+ // Find the beginning of the line
+ var lineStart = 0;
+ for (var i = charOffset - 1; i >= 0; i--) {
+ var c = code.codeUnitAt(i);
+ if (c == lineFeed || c == carriageReturn) {
+ lineStart = i + 1;
+ break;
+ }
+ }
+
+ // Grab all the whitespace
+ var whitespaceEnd = code.length;
+ for (var i = lineStart; i < code.length; i++) {
+ var c = code.codeUnitAt(i);
+ if (c != _space && c != _tab) {
+ whitespaceEnd = i;
+ break;
+ }
+ }
+
+ return code.substring(lineStart, whitespaceEnd);
+}
+
+const int _tab = 9;
+const int _space = 32;
diff --git a/pkgs/source_maps/lib/source_maps.dart b/pkgs/source_maps/lib/source_maps.dart
new file mode 100644
index 0000000..58f805a
--- /dev/null
+++ b/pkgs/source_maps/lib/source_maps.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Library to create and parse source maps.
+///
+/// Create a source map using [SourceMapBuilder]. For example:
+///
+/// ```dart
+/// var json = (new SourceMapBuilder()
+/// ..add(inputSpan1, outputSpan1)
+/// ..add(inputSpan2, outputSpan2)
+/// ..add(inputSpan3, outputSpan3)
+/// .toJson(outputFile);
+/// ```
+///
+/// Use the source_span package's [SourceSpan] and [SourceFile] classes to
+/// specify span locations.
+///
+/// Parse a source map using [parse], and call `spanFor` on the returned mapping
+/// object. For example:
+///
+/// ```dart
+/// var mapping = parse(json);
+/// mapping.spanFor(outputSpan1.line, outputSpan1.column)
+/// ```
+library source_maps;
+
+import 'package:source_span/source_span.dart';
+
+import 'builder.dart';
+import 'parser.dart';
+
+export 'builder.dart';
+export 'parser.dart';
+export 'printer.dart';
+export 'refactor.dart';
+export 'src/source_map_span.dart';
diff --git a/pkgs/source_maps/lib/src/source_map_span.dart b/pkgs/source_maps/lib/src/source_map_span.dart
new file mode 100644
index 0000000..aad8a32
--- /dev/null
+++ b/pkgs/source_maps/lib/src/source_map_span.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+
+/// A [SourceSpan] for spans coming from or being written to source maps.
+///
+/// These spans have an extra piece of metadata: whether or not they represent
+/// an identifier (see [isIdentifier]).
+class SourceMapSpan extends SourceSpanBase {
+ /// Whether this span represents an identifier.
+ ///
+ /// If this is `true`, [text] is the value of the identifier.
+ final bool isIdentifier;
+
+ SourceMapSpan(super.start, super.end, super.text,
+ {this.isIdentifier = false});
+
+ /// Creates a [SourceMapSpan] for an identifier with value [text] starting at
+ /// [start].
+ ///
+ /// The [end] location is determined by adding [text] to [start].
+ SourceMapSpan.identifier(SourceLocation start, String text)
+ : this(
+ start,
+ SourceLocation(start.offset + text.length,
+ sourceUrl: start.sourceUrl,
+ line: start.line,
+ column: start.column + text.length),
+ text,
+ isIdentifier: true);
+}
+
+/// A wrapper aruond a [FileSpan] that implements [SourceMapSpan].
+class SourceMapFileSpan implements SourceMapSpan, FileSpan {
+ final FileSpan _inner;
+ @override
+ final bool isIdentifier;
+
+ @override
+ SourceFile get file => _inner.file;
+ @override
+ FileLocation get start => _inner.start;
+ @override
+ FileLocation get end => _inner.end;
+ @override
+ String get text => _inner.text;
+ @override
+ String get context => _inner.context;
+ @override
+ Uri? get sourceUrl => _inner.sourceUrl;
+ @override
+ int get length => _inner.length;
+
+ SourceMapFileSpan(this._inner, {this.isIdentifier = false});
+
+ @override
+ int compareTo(SourceSpan other) => _inner.compareTo(other);
+ @override
+ String highlight({Object? color}) => _inner.highlight(color: color);
+ @override
+ SourceSpan union(SourceSpan other) => _inner.union(other);
+ @override
+ FileSpan expand(FileSpan other) => _inner.expand(other);
+ @override
+ String message(String message, {Object? color}) =>
+ _inner.message(message, color: color);
+ @override
+ String toString() =>
+ _inner.toString().replaceAll('FileSpan', 'SourceMapFileSpan');
+}
diff --git a/pkgs/source_maps/lib/src/utils.dart b/pkgs/source_maps/lib/src/utils.dart
new file mode 100644
index 0000000..f70531e
--- /dev/null
+++ b/pkgs/source_maps/lib/src/utils.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utilities that shouldn't be in this package.
+library source_maps.utils;
+
+/// Find the first entry in a sorted [list] that matches a monotonic predicate.
+/// Given a result `n`, that all items before `n` will not match, `n` matches,
+/// and all items after `n` match too. The result is -1 when there are no
+/// items, 0 when all items match, and list.length when none does.
+// TODO(sigmund): remove this function after dartbug.com/5624 is fixed.
+int binarySearch<T>(List<T> list, bool Function(T) matches) {
+ if (list.isEmpty) return -1;
+ if (matches(list.first)) return 0;
+ if (!matches(list.last)) return list.length;
+
+ var min = 0;
+ var max = list.length - 1;
+ while (min < max) {
+ var half = min + ((max - min) ~/ 2);
+ if (matches(list[half])) {
+ max = half;
+ } else {
+ min = half + 1;
+ }
+ }
+ return max;
+}
+
+const int lineFeed = 10;
+const int carriageReturn = 13;
diff --git a/pkgs/source_maps/lib/src/vlq.dart b/pkgs/source_maps/lib/src/vlq.dart
new file mode 100644
index 0000000..61b4768
--- /dev/null
+++ b/pkgs/source_maps/lib/src/vlq.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utilities to encode and decode VLQ values used in source maps.
+///
+/// Sourcemaps are encoded with variable length numbers as base64 encoded
+/// strings with the least significant digit coming first. Each base64 digit
+/// encodes a 5-bit value (0-31) and a continuation bit. Signed values can be
+/// represented by using the least significant bit of the value as the sign bit.
+///
+/// For more details see the source map [version 3 documentation](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?usp=sharing).
+library source_maps.src.vlq;
+
+import 'dart:math';
+
+const int vlqBaseShift = 5;
+
+const int vlqBaseMask = (1 << 5) - 1;
+
+const int vlqContinuationBit = 1 << 5;
+
+const int vlqContinuationMask = 1 << 5;
+
+const String base64Digits =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+final Map<String, int> _digits = () {
+ var map = <String, int>{};
+ for (var i = 0; i < 64; i++) {
+ map[base64Digits[i]] = i;
+ }
+ return map;
+}();
+
+final int maxInt32 = (pow(2, 31) as int) - 1;
+final int minInt32 = -(pow(2, 31) as int);
+
+/// Creates the VLQ encoding of [value] as a sequence of characters
+Iterable<String> encodeVlq(int value) {
+ if (value < minInt32 || value > maxInt32) {
+ throw ArgumentError('expected 32 bit int, got: $value');
+ }
+ var res = <String>[];
+ var signBit = 0;
+ if (value < 0) {
+ signBit = 1;
+ value = -value;
+ }
+ value = (value << 1) | signBit;
+ do {
+ var digit = value & vlqBaseMask;
+ value >>= vlqBaseShift;
+ if (value > 0) {
+ digit |= vlqContinuationBit;
+ }
+ res.add(base64Digits[digit]);
+ } while (value > 0);
+ return res;
+}
+
+/// Decodes a value written as a sequence of VLQ characters. The first input
+/// character will be `chars.current` after calling `chars.moveNext` once. The
+/// iterator is advanced until a stop character is found (a character without
+/// the [vlqContinuationBit]).
+int decodeVlq(Iterator<String> chars) {
+ var result = 0;
+ var stop = false;
+ var shift = 0;
+ while (!stop) {
+ if (!chars.moveNext()) throw StateError('incomplete VLQ value');
+ var char = chars.current;
+ var digit = _digits[char];
+ if (digit == null) {
+ throw FormatException('invalid character in VLQ encoding: $char');
+ }
+ stop = (digit & vlqContinuationBit) == 0;
+ digit &= vlqBaseMask;
+ result += digit << shift;
+ shift += vlqBaseShift;
+ }
+
+ // Result uses the least significant bit as a sign bit. We convert it into a
+ // two-complement value. For example,
+ // 2 (10 binary) becomes 1
+ // 3 (11 binary) becomes -1
+ // 4 (100 binary) becomes 2
+ // 5 (101 binary) becomes -2
+ // 6 (110 binary) becomes 3
+ // 7 (111 binary) becomes -3
+ var negate = (result & 1) == 1;
+ result = result >> 1;
+ result = negate ? -result : result;
+
+ // TODO(sigmund): can we detect this earlier?
+ if (result < minInt32 || result > maxInt32) {
+ throw FormatException(
+ 'expected an encoded 32 bit int, but we got: $result');
+ }
+ return result;
+}
diff --git a/pkgs/source_maps/pubspec.yaml b/pkgs/source_maps/pubspec.yaml
new file mode 100644
index 0000000..8518fa7
--- /dev/null
+++ b/pkgs/source_maps/pubspec.yaml
@@ -0,0 +1,15 @@
+name: source_maps
+version: 0.10.13
+description: A library to programmatically manipulate source map files.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/source_maps
+
+environment:
+ sdk: ^3.3.0
+
+dependencies:
+ source_span: ^1.8.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^2.0.0
+ term_glyph: ^1.2.0
+ test: ^1.16.0
diff --git a/pkgs/source_maps/test/builder_test.dart b/pkgs/source_maps/test/builder_test.dart
new file mode 100644
index 0000000..4f773e7
--- /dev/null
+++ b/pkgs/source_maps/test/builder_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:source_maps/source_maps.dart';
+import 'package:test/test.dart';
+
+import 'common.dart';
+
+void main() {
+ test('builder - with span', () {
+ var map = (SourceMapBuilder()
+ ..addSpan(inputVar1, outputVar1)
+ ..addSpan(inputFunction, outputFunction)
+ ..addSpan(inputVar2, outputVar2)
+ ..addSpan(inputExpr, outputExpr))
+ .build(output.url.toString());
+ expect(map, equals(expectedMap));
+ });
+
+ test('builder - with location', () {
+ var str = (SourceMapBuilder()
+ ..addLocation(inputVar1.start, outputVar1.start, 'longVar1')
+ ..addLocation(inputFunction.start, outputFunction.start, 'longName')
+ ..addLocation(inputVar2.start, outputVar2.start, 'longVar2')
+ ..addLocation(inputExpr.start, outputExpr.start, null))
+ .toJson(output.url.toString());
+ expect(str, jsonEncode(expectedMap));
+ });
+}
diff --git a/pkgs/source_maps/test/common.dart b/pkgs/source_maps/test/common.dart
new file mode 100644
index 0000000..f6139de
--- /dev/null
+++ b/pkgs/source_maps/test/common.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Common input/output used by builder, parser and end2end tests
+library test.common;
+
+import 'package:source_maps/source_maps.dart';
+import 'package:source_span/source_span.dart';
+import 'package:test/test.dart';
+
+/// Content of the source file
+const String inputContent = '''
+/** this is a comment. */
+int longVar1 = 3;
+
+// this is a comment too
+int longName(int longVar2) {
+ return longVar1 + longVar2;
+}
+''';
+final input = SourceFile.fromString(inputContent, url: 'input.dart');
+
+/// A span in the input file
+SourceMapSpan ispan(int start, int end, [bool isIdentifier = false]) =>
+ SourceMapFileSpan(input.span(start, end), isIdentifier: isIdentifier);
+
+SourceMapSpan inputVar1 = ispan(30, 38, true);
+SourceMapSpan inputFunction = ispan(74, 82, true);
+SourceMapSpan inputVar2 = ispan(87, 95, true);
+
+SourceMapSpan inputVar1NoSymbol = ispan(30, 38);
+SourceMapSpan inputFunctionNoSymbol = ispan(74, 82);
+SourceMapSpan inputVar2NoSymbol = ispan(87, 95);
+
+SourceMapSpan inputExpr = ispan(108, 127);
+
+/// Content of the target file
+const String outputContent = '''
+var x = 3;
+f(y) => x + y;
+''';
+final output = SourceFile.fromString(outputContent, url: 'output.dart');
+
+/// A span in the output file
+SourceMapSpan ospan(int start, int end, [bool isIdentifier = false]) =>
+ SourceMapFileSpan(output.span(start, end), isIdentifier: isIdentifier);
+
+SourceMapSpan outputVar1 = ospan(4, 5, true);
+SourceMapSpan outputFunction = ospan(11, 12, true);
+SourceMapSpan outputVar2 = ospan(13, 14, true);
+SourceMapSpan outputVar1NoSymbol = ospan(4, 5);
+SourceMapSpan outputFunctionNoSymbol = ospan(11, 12);
+SourceMapSpan outputVar2NoSymbol = ospan(13, 14);
+SourceMapSpan outputExpr = ospan(19, 24);
+
+/// Expected output mapping when recording the following four mappings:
+/// inputVar1 <= outputVar1
+/// inputFunction <= outputFunction
+/// inputVar2 <= outputVar2
+/// inputExpr <= outputExpr
+///
+/// This mapping is stored in the tests so we can independently test the builder
+/// and parser algorithms without relying entirely on end2end tests.
+const Map<String, dynamic> expectedMap = {
+ 'version': 3,
+ 'sourceRoot': '',
+ 'sources': ['input.dart'],
+ 'names': ['longVar1', 'longName', 'longVar2'],
+ 'mappings': 'IACIA;AAGAC,EAAaC,MACR',
+ 'file': 'output.dart'
+};
+
+void check(SourceSpan outputSpan, Mapping mapping, SourceMapSpan inputSpan,
+ bool realOffsets) {
+ var line = outputSpan.start.line;
+ var column = outputSpan.start.column;
+ var files = realOffsets ? {'input.dart': input} : null;
+ var span = mapping.spanFor(line, column, files: files)!;
+ var span2 = mapping.spanForLocation(outputSpan.start, files: files)!;
+
+ // Both mapping APIs are equivalent.
+ expect(span.start.offset, span2.start.offset);
+ expect(span.start.line, span2.start.line);
+ expect(span.start.column, span2.start.column);
+ expect(span.end.offset, span2.end.offset);
+ expect(span.end.line, span2.end.line);
+ expect(span.end.column, span2.end.column);
+
+ // Mapping matches our input location (modulo using real offsets)
+ expect(span.start.line, inputSpan.start.line);
+ expect(span.start.column, inputSpan.start.column);
+ expect(span.sourceUrl, inputSpan.sourceUrl);
+ expect(span.start.offset, realOffsets ? inputSpan.start.offset : 0);
+
+ // Mapping includes the identifier, if any
+ if (inputSpan.isIdentifier) {
+ expect(span.end.line, inputSpan.end.line);
+ expect(span.end.column, inputSpan.end.column);
+ expect(span.end.offset, span.start.offset + inputSpan.text.length);
+ if (realOffsets) expect(span.end.offset, inputSpan.end.offset);
+ } else {
+ expect(span.end.offset, span.start.offset);
+ expect(span.end.line, span.start.line);
+ expect(span.end.column, span.start.column);
+ }
+}
diff --git a/pkgs/source_maps/test/end2end_test.dart b/pkgs/source_maps/test/end2end_test.dart
new file mode 100644
index 0000000..84dd5ba
--- /dev/null
+++ b/pkgs/source_maps/test/end2end_test.dart
@@ -0,0 +1,160 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_maps/source_maps.dart';
+import 'package:source_span/source_span.dart';
+import 'package:test/test.dart';
+
+import 'common.dart';
+
+void main() {
+ test('end-to-end setup', () {
+ expect(inputVar1.text, 'longVar1');
+ expect(inputFunction.text, 'longName');
+ expect(inputVar2.text, 'longVar2');
+ expect(inputVar1NoSymbol.text, 'longVar1');
+ expect(inputFunctionNoSymbol.text, 'longName');
+ expect(inputVar2NoSymbol.text, 'longVar2');
+ expect(inputExpr.text, 'longVar1 + longVar2');
+
+ expect(outputVar1.text, 'x');
+ expect(outputFunction.text, 'f');
+ expect(outputVar2.text, 'y');
+ expect(outputVar1NoSymbol.text, 'x');
+ expect(outputFunctionNoSymbol.text, 'f');
+ expect(outputVar2NoSymbol.text, 'y');
+ expect(outputExpr.text, 'x + y');
+ });
+
+ test('build + parse', () {
+ var map = (SourceMapBuilder()
+ ..addSpan(inputVar1, outputVar1)
+ ..addSpan(inputFunction, outputFunction)
+ ..addSpan(inputVar2, outputVar2)
+ ..addSpan(inputExpr, outputExpr))
+ .build(output.url.toString());
+ var mapping = parseJson(map);
+ check(outputVar1, mapping, inputVar1, false);
+ check(outputVar2, mapping, inputVar2, false);
+ check(outputFunction, mapping, inputFunction, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('build + parse - no symbols', () {
+ var map = (SourceMapBuilder()
+ ..addSpan(inputVar1NoSymbol, outputVar1NoSymbol)
+ ..addSpan(inputFunctionNoSymbol, outputFunctionNoSymbol)
+ ..addSpan(inputVar2NoSymbol, outputVar2NoSymbol)
+ ..addSpan(inputExpr, outputExpr))
+ .build(output.url.toString());
+ var mapping = parseJson(map);
+ check(outputVar1NoSymbol, mapping, inputVar1NoSymbol, false);
+ check(outputVar2NoSymbol, mapping, inputVar2NoSymbol, false);
+ check(outputFunctionNoSymbol, mapping, inputFunctionNoSymbol, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('build + parse, repeated entries', () {
+ var map = (SourceMapBuilder()
+ ..addSpan(inputVar1, outputVar1)
+ ..addSpan(inputVar1, outputVar1)
+ ..addSpan(inputFunction, outputFunction)
+ ..addSpan(inputFunction, outputFunction)
+ ..addSpan(inputVar2, outputVar2)
+ ..addSpan(inputVar2, outputVar2)
+ ..addSpan(inputExpr, outputExpr)
+ ..addSpan(inputExpr, outputExpr))
+ .build(output.url.toString());
+ var mapping = parseJson(map);
+ check(outputVar1, mapping, inputVar1, false);
+ check(outputVar2, mapping, inputVar2, false);
+ check(outputFunction, mapping, inputFunction, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('build + parse - no symbols, repeated entries', () {
+ var map = (SourceMapBuilder()
+ ..addSpan(inputVar1NoSymbol, outputVar1NoSymbol)
+ ..addSpan(inputVar1NoSymbol, outputVar1NoSymbol)
+ ..addSpan(inputFunctionNoSymbol, outputFunctionNoSymbol)
+ ..addSpan(inputFunctionNoSymbol, outputFunctionNoSymbol)
+ ..addSpan(inputVar2NoSymbol, outputVar2NoSymbol)
+ ..addSpan(inputVar2NoSymbol, outputVar2NoSymbol)
+ ..addSpan(inputExpr, outputExpr))
+ .build(output.url.toString());
+ var mapping = parseJson(map);
+ check(outputVar1NoSymbol, mapping, inputVar1NoSymbol, false);
+ check(outputVar2NoSymbol, mapping, inputVar2NoSymbol, false);
+ check(outputFunctionNoSymbol, mapping, inputFunctionNoSymbol, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('build + parse with file', () {
+ var json = (SourceMapBuilder()
+ ..addSpan(inputVar1, outputVar1)
+ ..addSpan(inputFunction, outputFunction)
+ ..addSpan(inputVar2, outputVar2)
+ ..addSpan(inputExpr, outputExpr))
+ .toJson(output.url.toString());
+ var mapping = parse(json);
+ check(outputVar1, mapping, inputVar1, true);
+ check(outputVar2, mapping, inputVar2, true);
+ check(outputFunction, mapping, inputFunction, true);
+ check(outputExpr, mapping, inputExpr, true);
+ });
+
+ test('printer projecting marks + parse', () {
+ var out = inputContent.replaceAll('long', '_s');
+ var file = SourceFile.fromString(out, url: 'output2.dart');
+ var printer = Printer('output2.dart');
+ printer.mark(ispan(0, 0));
+
+ var segments = inputContent.split('long');
+ expect(segments.length, 6);
+ printer.add(segments[0], projectMarks: true);
+ printer.mark(inputVar1);
+ printer.add('_s');
+ printer.add(segments[1], projectMarks: true);
+ printer.mark(inputFunction);
+ printer.add('_s');
+ printer.add(segments[2], projectMarks: true);
+ printer.mark(inputVar2);
+ printer.add('_s');
+ printer.add(segments[3], projectMarks: true);
+ printer.mark(inputExpr);
+ printer.add('_s');
+ printer.add(segments[4], projectMarks: true);
+ printer.add('_s');
+ printer.add(segments[5], projectMarks: true);
+
+ expect(printer.text, out);
+
+ var mapping = parse(printer.map);
+ void checkHelper(SourceMapSpan inputSpan, int adjustment) {
+ var start = inputSpan.start.offset - adjustment;
+ var end = (inputSpan.end.offset - adjustment) - 2;
+ var span = SourceMapFileSpan(file.span(start, end),
+ isIdentifier: inputSpan.isIdentifier);
+ check(span, mapping, inputSpan, true);
+ }
+
+ checkHelper(inputVar1, 0);
+ checkHelper(inputFunction, 2);
+ checkHelper(inputVar2, 4);
+ checkHelper(inputExpr, 6);
+
+ // We projected correctly lines that have no mappings
+ check(file.span(66, 66), mapping, ispan(45, 45), true);
+ check(file.span(63, 64), mapping, ispan(45, 45), true);
+ check(file.span(68, 68), mapping, ispan(70, 70), true);
+ check(file.span(71, 71), mapping, ispan(70, 70), true);
+
+ // Start of the last line
+ var oOffset = out.length - 2;
+ var iOffset = inputContent.length - 2;
+ check(file.span(oOffset, oOffset), mapping, ispan(iOffset, iOffset), true);
+ check(file.span(oOffset + 1, oOffset + 1), mapping, ispan(iOffset, iOffset),
+ true);
+ });
+}
diff --git a/pkgs/source_maps/test/parser_test.dart b/pkgs/source_maps/test/parser_test.dart
new file mode 100644
index 0000000..6cfe928
--- /dev/null
+++ b/pkgs/source_maps/test/parser_test.dart
@@ -0,0 +1,431 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: inference_failure_on_collection_literal
+// ignore_for_file: inference_failure_on_instance_creation
+
+import 'dart:convert';
+
+import 'package:source_maps/source_maps.dart';
+import 'package:source_span/source_span.dart';
+import 'package:test/test.dart';
+
+import 'common.dart';
+
+const Map<String, dynamic> _mapWithNoSourceLocation = {
+ 'version': 3,
+ 'sourceRoot': '',
+ 'sources': ['input.dart'],
+ 'names': [],
+ 'mappings': 'A',
+ 'file': 'output.dart'
+};
+
+const Map<String, dynamic> _mapWithSourceLocation = {
+ 'version': 3,
+ 'sourceRoot': '',
+ 'sources': ['input.dart'],
+ 'names': [],
+ 'mappings': 'AAAA',
+ 'file': 'output.dart'
+};
+
+const Map<String, dynamic> _mapWithSourceLocationAndMissingNames = {
+ 'version': 3,
+ 'sourceRoot': '',
+ 'sources': ['input.dart'],
+ 'mappings': 'AAAA',
+ 'file': 'output.dart'
+};
+
+const Map<String, dynamic> _mapWithSourceLocationAndName = {
+ 'version': 3,
+ 'sourceRoot': '',
+ 'sources': ['input.dart'],
+ 'names': ['var'],
+ 'mappings': 'AAAAA',
+ 'file': 'output.dart'
+};
+
+const Map<String, dynamic> _mapWithSourceLocationAndName1 = {
+ 'version': 3,
+ 'sourceRoot': 'pkg/',
+ 'sources': ['input1.dart'],
+ 'names': ['var1'],
+ 'mappings': 'AAAAA',
+ 'file': 'output.dart'
+};
+
+const Map<String, dynamic> _mapWithSourceLocationAndName2 = {
+ 'version': 3,
+ 'sourceRoot': 'pkg/',
+ 'sources': ['input2.dart'],
+ 'names': ['var2'],
+ 'mappings': 'AAAAA',
+ 'file': 'output2.dart'
+};
+
+const Map<String, dynamic> _mapWithSourceLocationAndName3 = {
+ 'version': 3,
+ 'sourceRoot': 'pkg/',
+ 'sources': ['input3.dart'],
+ 'names': ['var3'],
+ 'mappings': 'AAAAA',
+ 'file': '3/output.dart'
+};
+
+const _sourceMapBundle = [
+ _mapWithSourceLocationAndName1,
+ _mapWithSourceLocationAndName2,
+ _mapWithSourceLocationAndName3,
+];
+
+void main() {
+ test('parse', () {
+ var mapping = parseJson(expectedMap);
+ check(outputVar1, mapping, inputVar1, false);
+ check(outputVar2, mapping, inputVar2, false);
+ check(outputFunction, mapping, inputFunction, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('parse + json', () {
+ var mapping = parse(jsonEncode(expectedMap));
+ check(outputVar1, mapping, inputVar1, false);
+ check(outputVar2, mapping, inputVar2, false);
+ check(outputFunction, mapping, inputFunction, false);
+ check(outputExpr, mapping, inputExpr, false);
+ });
+
+ test('parse with file', () {
+ var mapping = parseJson(expectedMap);
+ check(outputVar1, mapping, inputVar1, true);
+ check(outputVar2, mapping, inputVar2, true);
+ check(outputFunction, mapping, inputFunction, true);
+ check(outputExpr, mapping, inputExpr, true);
+ });
+
+ test('parse with no source location', () {
+ var map = parse(jsonEncode(_mapWithNoSourceLocation)) as SingleMapping;
+ expect(map.lines.length, 1);
+ expect(map.lines.first.entries.length, 1);
+ var entry = map.lines.first.entries.first;
+
+ expect(entry.column, 0);
+ expect(entry.sourceUrlId, null);
+ expect(entry.sourceColumn, null);
+ expect(entry.sourceLine, null);
+ expect(entry.sourceNameId, null);
+ });
+
+ test('parse with source location and no name', () {
+ var map = parse(jsonEncode(_mapWithSourceLocation)) as SingleMapping;
+ expect(map.lines.length, 1);
+ expect(map.lines.first.entries.length, 1);
+ var entry = map.lines.first.entries.first;
+
+ expect(entry.column, 0);
+ expect(entry.sourceUrlId, 0);
+ expect(entry.sourceColumn, 0);
+ expect(entry.sourceLine, 0);
+ expect(entry.sourceNameId, null);
+ });
+
+ test('parse with source location and missing names entry', () {
+ var map = parse(jsonEncode(_mapWithSourceLocationAndMissingNames))
+ as SingleMapping;
+ expect(map.lines.length, 1);
+ expect(map.lines.first.entries.length, 1);
+ var entry = map.lines.first.entries.first;
+
+ expect(entry.column, 0);
+ expect(entry.sourceUrlId, 0);
+ expect(entry.sourceColumn, 0);
+ expect(entry.sourceLine, 0);
+ expect(entry.sourceNameId, null);
+ });
+
+ test('parse with source location and name', () {
+ var map = parse(jsonEncode(_mapWithSourceLocationAndName)) as SingleMapping;
+ expect(map.lines.length, 1);
+ expect(map.lines.first.entries.length, 1);
+ var entry = map.lines.first.entries.first;
+
+ expect(entry.sourceUrlId, 0);
+ expect(entry.sourceUrlId, 0);
+ expect(entry.sourceColumn, 0);
+ expect(entry.sourceLine, 0);
+ expect(entry.sourceNameId, 0);
+ });
+
+ test('parse with source root', () {
+ var inputMap = Map.from(_mapWithSourceLocation);
+ inputMap['sourceRoot'] = '/pkg/';
+ var mapping = parseJson(inputMap) as SingleMapping;
+ expect(mapping.spanFor(0, 0)?.sourceUrl, Uri.parse('/pkg/input.dart'));
+ expect(
+ mapping
+ .spanForLocation(
+ SourceLocation(0, sourceUrl: Uri.parse('ignored.dart')))
+ ?.sourceUrl,
+ Uri.parse('/pkg/input.dart'));
+
+ var newSourceRoot = '/new/';
+
+ mapping.sourceRoot = newSourceRoot;
+ inputMap['sourceRoot'] = newSourceRoot;
+
+ expect(mapping.toJson(), equals(inputMap));
+ });
+
+ test('parse with map URL', () {
+ var inputMap = Map.from(_mapWithSourceLocation);
+ inputMap['sourceRoot'] = 'pkg/';
+ var mapping = parseJson(inputMap, mapUrl: 'file:///path/to/map');
+ expect(mapping.spanFor(0, 0)?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input.dart'));
+ });
+
+ group('parse with bundle', () {
+ var mapping =
+ parseJsonExtended(_sourceMapBundle, mapUrl: 'file:///path/to/map');
+
+ test('simple', () {
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.file('/path/to/output.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.file('/path/to/output2.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.file('/path/to/3/output.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+
+ expect(
+ mapping.spanFor(0, 0, uri: 'file:///path/to/output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+ expect(
+ mapping.spanFor(0, 0, uri: 'file:///path/to/output2.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+ expect(
+ mapping
+ .spanFor(0, 0, uri: 'file:///path/to/3/output.dart')
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+ });
+
+ test('package uris', () {
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.parse('package:1/output.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.parse('package:2/output2.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.parse('package:3/output.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+
+ expect(mapping.spanFor(0, 0, uri: 'package:1/output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+ expect(mapping.spanFor(0, 0, uri: 'package:2/output2.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+ expect(mapping.spanFor(0, 0, uri: 'package:3/output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+ });
+
+ test('unmapped path', () {
+ var span = mapping.spanFor(0, 0, uri: 'unmapped_output.dart')!;
+ expect(span.sourceUrl, Uri.parse('unmapped_output.dart'));
+ expect(span.start.line, equals(0));
+ expect(span.start.column, equals(0));
+
+ span = mapping.spanFor(10, 5, uri: 'unmapped_output.dart')!;
+ expect(span.sourceUrl, Uri.parse('unmapped_output.dart'));
+ expect(span.start.line, equals(10));
+ expect(span.start.column, equals(5));
+ });
+
+ test('missing path', () {
+ expect(() => mapping.spanFor(0, 0), throwsA(anything));
+ });
+
+ test('incomplete paths', () {
+ expect(mapping.spanFor(0, 0, uri: 'output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+ expect(mapping.spanFor(0, 0, uri: 'output2.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+ expect(mapping.spanFor(0, 0, uri: '3/output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+ });
+
+ test('parseExtended', () {
+ var mapping = parseExtended(jsonEncode(_sourceMapBundle),
+ mapUrl: 'file:///path/to/map');
+
+ expect(mapping.spanFor(0, 0, uri: 'output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+ expect(mapping.spanFor(0, 0, uri: 'output2.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+ expect(mapping.spanFor(0, 0, uri: '3/output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+ });
+
+ test('build bundle incrementally', () {
+ var mapping = MappingBundle();
+
+ mapping.addMapping(parseJson(_mapWithSourceLocationAndName1,
+ mapUrl: 'file:///path/to/map') as SingleMapping);
+ expect(mapping.spanFor(0, 0, uri: 'output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+
+ expect(mapping.containsMapping('output2.dart'), isFalse);
+ mapping.addMapping(parseJson(_mapWithSourceLocationAndName2,
+ mapUrl: 'file:///path/to/map') as SingleMapping);
+ expect(mapping.containsMapping('output2.dart'), isTrue);
+ expect(mapping.spanFor(0, 0, uri: 'output2.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+
+ expect(mapping.containsMapping('3/output.dart'), isFalse);
+ mapping.addMapping(parseJson(_mapWithSourceLocationAndName3,
+ mapUrl: 'file:///path/to/map') as SingleMapping);
+ expect(mapping.containsMapping('3/output.dart'), isTrue);
+ expect(mapping.spanFor(0, 0, uri: '3/output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+ });
+
+ // Test that the source map can handle cases where the uri passed in is
+ // not from the expected host but it is still unambiguous which source
+ // map should be used.
+ test('different paths', () {
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.parse('http://localhost/output.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.parse('http://localhost/output2.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+ expect(
+ mapping
+ .spanForLocation(SourceLocation(0,
+ sourceUrl: Uri.parse('http://localhost/3/output.dart')))
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+
+ expect(
+ mapping.spanFor(0, 0, uri: 'http://localhost/output.dart')?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input1.dart'));
+ expect(
+ mapping
+ .spanFor(0, 0, uri: 'http://localhost/output2.dart')
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input2.dart'));
+ expect(
+ mapping
+ .spanFor(0, 0, uri: 'http://localhost/3/output.dart')
+ ?.sourceUrl,
+ Uri.parse('file:///path/to/pkg/input3.dart'));
+ });
+ });
+
+ test('parse and re-emit', () {
+ for (var expected in [
+ expectedMap,
+ _mapWithNoSourceLocation,
+ _mapWithSourceLocation,
+ _mapWithSourceLocationAndName
+ ]) {
+ var mapping = parseJson(expected) as SingleMapping;
+ expect(mapping.toJson(), equals(expected));
+
+ mapping = parseJsonExtended(expected) as SingleMapping;
+ expect(mapping.toJson(), equals(expected));
+ }
+
+ var mapping = parseJsonExtended(_sourceMapBundle) as MappingBundle;
+ expect(mapping.toJson(), equals(_sourceMapBundle));
+ });
+
+ test('parse extensions', () {
+ var map = Map.from(expectedMap);
+ map['x_foo'] = 'a';
+ map['x_bar'] = [3];
+ var mapping = parseJson(map) as SingleMapping;
+ expect(mapping.toJson(), equals(map));
+ expect(mapping.extensions['x_foo'], equals('a'));
+ expect((mapping.extensions['x_bar'] as List).first, equals(3));
+ });
+
+ group('source files', () {
+ group('from fromEntries()', () {
+ test('are null for non-FileLocations', () {
+ var mapping = SingleMapping.fromEntries([
+ Entry(SourceLocation(10, line: 1, column: 8), outputVar1.start, null)
+ ]);
+ expect(mapping.files, equals([null]));
+ });
+
+ test("use a file location's file", () {
+ var mapping = SingleMapping.fromEntries(
+ [Entry(inputVar1.start, outputVar1.start, null)]);
+ expect(mapping.files, equals([input]));
+ });
+ });
+
+ group('from parse()', () {
+ group('are null', () {
+ test('with no sourcesContent field', () {
+ var mapping = parseJson(expectedMap) as SingleMapping;
+ expect(mapping.files, equals([null]));
+ });
+
+ test('with null sourcesContent values', () {
+ var map = Map.from(expectedMap);
+ map['sourcesContent'] = [null];
+ var mapping = parseJson(map) as SingleMapping;
+ expect(mapping.files, equals([null]));
+ });
+
+ test('with a too-short sourcesContent', () {
+ var map = Map.from(expectedMap);
+ map['sourcesContent'] = [];
+ var mapping = parseJson(map) as SingleMapping;
+ expect(mapping.files, equals([null]));
+ });
+ });
+
+ test('are parsed from sourcesContent', () {
+ var map = Map.from(expectedMap);
+ map['sourcesContent'] = ['hello, world!'];
+ var mapping = parseJson(map) as SingleMapping;
+
+ var file = mapping.files[0]!;
+ expect(file.url, equals(Uri.parse('input.dart')));
+ expect(file.getText(0), equals('hello, world!'));
+ });
+ });
+ });
+}
diff --git a/pkgs/source_maps/test/printer_test.dart b/pkgs/source_maps/test/printer_test.dart
new file mode 100644
index 0000000..89265e3
--- /dev/null
+++ b/pkgs/source_maps/test/printer_test.dart
@@ -0,0 +1,126 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:source_maps/source_maps.dart';
+import 'package:source_span/source_span.dart';
+import 'package:test/test.dart';
+
+import 'common.dart';
+
+void main() {
+ test('printer', () {
+ var printer = Printer('output.dart');
+ printer
+ ..add('var ')
+ ..mark(inputVar1)
+ ..add('x = 3;\n')
+ ..mark(inputFunction)
+ ..add('f(')
+ ..mark(inputVar2)
+ ..add('y) => ')
+ ..mark(inputExpr)
+ ..add('x + y;\n');
+ expect(printer.text, outputContent);
+ expect(printer.map, jsonEncode(expectedMap));
+ });
+
+ test('printer projecting marks', () {
+ var out = inputContent.replaceAll('long', '_s');
+ var printer = Printer('output2.dart');
+
+ var segments = inputContent.split('long');
+ expect(segments.length, 6);
+ printer
+ ..mark(ispan(0, 0))
+ ..add(segments[0], projectMarks: true)
+ ..mark(inputVar1)
+ ..add('_s')
+ ..add(segments[1], projectMarks: true)
+ ..mark(inputFunction)
+ ..add('_s')
+ ..add(segments[2], projectMarks: true)
+ ..mark(inputVar2)
+ ..add('_s')
+ ..add(segments[3], projectMarks: true)
+ ..mark(inputExpr)
+ ..add('_s')
+ ..add(segments[4], projectMarks: true)
+ ..add('_s')
+ ..add(segments[5], projectMarks: true);
+
+ expect(printer.text, out);
+ // 8 new lines in the source map:
+ expect(printer.map.split(';').length, 8);
+
+ SourceMapSpan asFixed(SourceMapSpan s) =>
+ SourceMapSpan(s.start, s.end, s.text, isIdentifier: s.isIdentifier);
+
+ // The result is the same if we use fixed positions
+ var printer2 = Printer('output2.dart');
+ printer2
+ ..mark(SourceLocation(0, sourceUrl: 'input.dart').pointSpan())
+ ..add(segments[0], projectMarks: true)
+ ..mark(asFixed(inputVar1))
+ ..add('_s')
+ ..add(segments[1], projectMarks: true)
+ ..mark(asFixed(inputFunction))
+ ..add('_s')
+ ..add(segments[2], projectMarks: true)
+ ..mark(asFixed(inputVar2))
+ ..add('_s')
+ ..add(segments[3], projectMarks: true)
+ ..mark(asFixed(inputExpr))
+ ..add('_s')
+ ..add(segments[4], projectMarks: true)
+ ..add('_s')
+ ..add(segments[5], projectMarks: true);
+
+ expect(printer2.text, out);
+ expect(printer2.map, printer.map);
+ });
+
+ group('nested printer', () {
+ test('simple use', () {
+ var printer = NestedPrinter();
+ printer
+ ..add('var ')
+ ..add('x = 3;\n', span: inputVar1)
+ ..add('f(', span: inputFunction)
+ ..add('y) => ', span: inputVar2)
+ ..add('x + y;\n', span: inputExpr)
+ ..build('output.dart');
+ expect(printer.text, outputContent);
+ expect(printer.map, jsonEncode(expectedMap));
+ });
+
+ test('nested use', () {
+ var printer = NestedPrinter();
+ printer
+ ..add('var ')
+ ..add(NestedPrinter()..add('x = 3;\n', span: inputVar1))
+ ..add('f(', span: inputFunction)
+ ..add(NestedPrinter()..add('y) => ', span: inputVar2))
+ ..add('x + y;\n', span: inputExpr)
+ ..build('output.dart');
+ expect(printer.text, outputContent);
+ expect(printer.map, jsonEncode(expectedMap));
+ });
+
+ test('add indentation', () {
+ var out = inputContent.replaceAll('long', '_s');
+ var lines = inputContent.trim().split('\n');
+ expect(lines.length, 7);
+ var printer = NestedPrinter();
+ for (var i = 0; i < lines.length; i++) {
+ if (i == 5) printer.indent++;
+ printer.addLine(lines[i].replaceAll('long', '_s').trim());
+ if (i == 5) printer.indent--;
+ }
+ printer.build('output.dart');
+ expect(printer.text, out);
+ });
+ });
+}
diff --git a/pkgs/source_maps/test/refactor_test.dart b/pkgs/source_maps/test/refactor_test.dart
new file mode 100644
index 0000000..5bc3818
--- /dev/null
+++ b/pkgs/source_maps/test/refactor_test.dart
@@ -0,0 +1,199 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_maps/parser.dart' show Mapping, parse;
+import 'package:source_maps/refactor.dart';
+import 'package:source_span/source_span.dart';
+import 'package:term_glyph/term_glyph.dart' as term_glyph;
+import 'package:test/test.dart';
+
+void main() {
+ setUpAll(() {
+ term_glyph.ascii = true;
+ });
+
+ group('conflict detection', () {
+ var original = '0123456789abcdefghij';
+ var file = SourceFile.fromString(original);
+
+ test('no conflict, in order', () {
+ var txn = TextEditTransaction(original, file);
+ txn.edit(2, 4, '.');
+ txn.edit(5, 5, '|');
+ txn.edit(6, 6, '-');
+ txn.edit(6, 7, '_');
+ expect((txn.commit()..build('')).text, '01.4|5-_789abcdefghij');
+ });
+
+ test('no conflict, out of order', () {
+ var txn = TextEditTransaction(original, file);
+ txn.edit(2, 4, '.');
+ txn.edit(5, 5, '|');
+
+ // Regresion test for issue #404: there is no conflict/overlap for edits
+ // that don't remove any of the original code.
+ txn.edit(6, 7, '_');
+ txn.edit(6, 6, '-');
+ expect((txn.commit()..build('')).text, '01.4|5-_789abcdefghij');
+ });
+
+ test('conflict', () {
+ var txn = TextEditTransaction(original, file);
+ txn.edit(2, 4, '.');
+ txn.edit(3, 3, '-');
+ expect(
+ () => txn.commit(),
+ throwsA(
+ predicate((e) => e.toString().contains('overlapping edits'))));
+ });
+ });
+
+ test('generated source maps', () {
+ var original =
+ '0123456789\n0*23456789\n01*3456789\nabcdefghij\nabcd*fghij\n';
+ var file = SourceFile.fromString(original);
+ var txn = TextEditTransaction(original, file);
+ txn.edit(27, 29, '__\n ');
+ txn.edit(34, 35, '___');
+ var printer = (txn.commit()..build(''));
+ var output = printer.text;
+ var map = parse(printer.map!);
+ expect(output,
+ '0123456789\n0*23456789\n01*34__\n 789\na___cdefghij\nabcd*fghij\n');
+
+ // Line 1 and 2 are unmodified: mapping any column returns the beginning
+ // of the corresponding line:
+ expect(
+ _span(1, 1, map, file),
+ 'line 1, column 1: \n'
+ ' ,\n'
+ '1 | 0123456789\n'
+ ' | ^\n'
+ " '");
+ expect(
+ _span(1, 5, map, file),
+ 'line 1, column 1: \n'
+ ' ,\n'
+ '1 | 0123456789\n'
+ ' | ^\n'
+ " '");
+ expect(
+ _span(2, 1, map, file),
+ 'line 2, column 1: \n'
+ ' ,\n'
+ '2 | 0*23456789\n'
+ ' | ^\n'
+ " '");
+ expect(
+ _span(2, 8, map, file),
+ 'line 2, column 1: \n'
+ ' ,\n'
+ '2 | 0*23456789\n'
+ ' | ^\n'
+ " '");
+
+ // Line 3 is modified part way: mappings before the edits have the right
+ // mapping, after the edits the mapping is null.
+ expect(
+ _span(3, 1, map, file),
+ 'line 3, column 1: \n'
+ ' ,\n'
+ '3 | 01*3456789\n'
+ ' | ^\n'
+ " '");
+ expect(
+ _span(3, 5, map, file),
+ 'line 3, column 1: \n'
+ ' ,\n'
+ '3 | 01*3456789\n'
+ ' | ^\n'
+ " '");
+
+ // Start of edits map to beginning of the edit secion:
+ expect(
+ _span(3, 6, map, file),
+ 'line 3, column 6: \n'
+ ' ,\n'
+ '3 | 01*3456789\n'
+ ' | ^\n'
+ " '");
+ expect(
+ _span(3, 7, map, file),
+ 'line 3, column 6: \n'
+ ' ,\n'
+ '3 | 01*3456789\n'
+ ' | ^\n'
+ " '");
+
+ // Lines added have no mapping (they should inherit the last mapping),
+ // but the end of the edit region continues were we left off:
+ expect(_span(4, 1, map, file), isNull);
+ expect(
+ _span(4, 5, map, file),
+ 'line 3, column 8: \n'
+ ' ,\n'
+ '3 | 01*3456789\n'
+ ' | ^\n'
+ " '");
+
+ // Subsequent lines are still mapped correctly:
+ // a (in a___cd...)
+ expect(
+ _span(5, 1, map, file),
+ 'line 4, column 1: \n'
+ ' ,\n'
+ '4 | abcdefghij\n'
+ ' | ^\n'
+ " '");
+ // _ (in a___cd...)
+ expect(
+ _span(5, 2, map, file),
+ 'line 4, column 2: \n'
+ ' ,\n'
+ '4 | abcdefghij\n'
+ ' | ^\n'
+ " '");
+ // _ (in a___cd...)
+ expect(
+ _span(5, 3, map, file),
+ 'line 4, column 2: \n'
+ ' ,\n'
+ '4 | abcdefghij\n'
+ ' | ^\n'
+ " '");
+ // _ (in a___cd...)
+ expect(
+ _span(5, 4, map, file),
+ 'line 4, column 2: \n'
+ ' ,\n'
+ '4 | abcdefghij\n'
+ ' | ^\n'
+ " '");
+ // c (in a___cd...)
+ expect(
+ _span(5, 5, map, file),
+ 'line 4, column 3: \n'
+ ' ,\n'
+ '4 | abcdefghij\n'
+ ' | ^\n'
+ " '");
+ expect(
+ _span(6, 1, map, file),
+ 'line 5, column 1: \n'
+ ' ,\n'
+ '5 | abcd*fghij\n'
+ ' | ^\n'
+ " '");
+ expect(
+ _span(6, 8, map, file),
+ 'line 5, column 1: \n'
+ ' ,\n'
+ '5 | abcd*fghij\n'
+ ' | ^\n'
+ " '");
+ });
+}
+
+String? _span(int line, int column, Mapping map, SourceFile file) =>
+ map.spanFor(line - 1, column - 1, files: {'': file})?.message('').trim();
diff --git a/pkgs/source_maps/test/utils_test.dart b/pkgs/source_maps/test/utils_test.dart
new file mode 100644
index 0000000..4abdce2
--- /dev/null
+++ b/pkgs/source_maps/test/utils_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Tests for the binary search utility algorithm.
+library test.utils_test;
+
+import 'package:source_maps/src/utils.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('binary search', () {
+ test('empty', () {
+ expect(binarySearch([], (x) => true), -1);
+ });
+
+ test('single element', () {
+ expect(binarySearch([1], (x) => true), 0);
+ expect(binarySearch([1], (x) => false), 1);
+ });
+
+ test('no matches', () {
+ var list = [1, 2, 3, 4, 5, 6, 7];
+ expect(binarySearch(list, (x) => false), list.length);
+ });
+
+ test('all match', () {
+ var list = [1, 2, 3, 4, 5, 6, 7];
+ expect(binarySearch(list, (x) => true), 0);
+ });
+
+ test('compare with linear search', () {
+ for (var size = 0; size < 100; size++) {
+ var list = <int>[];
+ for (var i = 0; i < size; i++) {
+ list.add(i);
+ }
+ for (var pos = 0; pos <= size; pos++) {
+ expect(binarySearch(list, (x) => x >= pos),
+ _linearSearch(list, (x) => x >= pos));
+ }
+ }
+ });
+ });
+}
+
+int _linearSearch<T>(List<T> list, bool Function(T) predicate) {
+ if (list.isEmpty) return -1;
+ for (var i = 0; i < list.length; i++) {
+ if (predicate(list[i])) return i;
+ }
+ return list.length;
+}
diff --git a/pkgs/source_maps/test/vlq_test.dart b/pkgs/source_maps/test/vlq_test.dart
new file mode 100644
index 0000000..4568cff
--- /dev/null
+++ b/pkgs/source_maps/test/vlq_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math';
+
+import 'package:source_maps/src/vlq.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('encode and decode - simple values', () {
+ expect(encodeVlq(1).join(''), 'C');
+ expect(encodeVlq(2).join(''), 'E');
+ expect(encodeVlq(3).join(''), 'G');
+ expect(encodeVlq(100).join(''), 'oG');
+ expect(decodeVlq('C'.split('').iterator), 1);
+ expect(decodeVlq('E'.split('').iterator), 2);
+ expect(decodeVlq('G'.split('').iterator), 3);
+ expect(decodeVlq('oG'.split('').iterator), 100);
+ });
+
+ test('encode and decode', () {
+ for (var i = -10000; i < 10000; i++) {
+ _checkEncodeDecode(i);
+ }
+ });
+
+ test('only 32-bit ints allowed', () {
+ var maxInt = (pow(2, 31) as int) - 1;
+ var minInt = -(pow(2, 31) as int);
+ _checkEncodeDecode(maxInt - 1);
+ _checkEncodeDecode(minInt + 1);
+ _checkEncodeDecode(maxInt);
+ _checkEncodeDecode(minInt);
+
+ expect(encodeVlq(minInt).join(''), 'hgggggE');
+ expect(decodeVlq('hgggggE'.split('').iterator), minInt);
+
+ expect(() => encodeVlq(maxInt + 1), throwsA(anything));
+ expect(() => encodeVlq(maxInt + 2), throwsA(anything));
+ expect(() => encodeVlq(minInt - 1), throwsA(anything));
+ expect(() => encodeVlq(minInt - 2), throwsA(anything));
+
+ // if we allowed more than 32 bits, these would be the expected encodings
+ // for the large numbers above.
+ expect(() => decodeVlq('ggggggE'.split('').iterator), throwsA(anything));
+ expect(() => decodeVlq('igggggE'.split('').iterator), throwsA(anything));
+ expect(() => decodeVlq('jgggggE'.split('').iterator), throwsA(anything));
+ expect(() => decodeVlq('lgggggE'.split('').iterator), throwsA(anything));
+ },
+ // This test uses integers so large they overflow in JS.
+ testOn: 'dart-vm');
+}
+
+void _checkEncodeDecode(int value) {
+ var encoded = encodeVlq(value);
+ expect(decodeVlq(encoded.iterator), value);
+ expect(decodeVlq(encoded.join('').split('').iterator), value);
+}
diff --git a/pkgs/source_span/.gitignore b/pkgs/source_span/.gitignore
new file mode 100644
index 0000000..ab3cb76
--- /dev/null
+++ b/pkgs/source_span/.gitignore
@@ -0,0 +1,16 @@
+# Don’t commit the following directories created by pub.
+.buildlog
+.dart_tool/
+.pub/
+build/
+packages
+.packages
+
+# Or the files created by dart2js.
+*.dart.js
+*.js_
+*.js.deps
+*.js.map
+
+# Include when developing application packages.
+pubspec.lock
diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md
new file mode 100644
index 0000000..b8319d7
--- /dev/null
+++ b/pkgs/source_span/CHANGELOG.md
@@ -0,0 +1,240 @@
+## 1.10.1
+
+* Require Dart 3.1
+* Move to `dart-lang/tools` monorepo.
+
+## 1.10.0
+
+* Add a `SourceFile.codeUnits` property.
+* Require Dart 2.18
+* Add an API usage example in `example/`.
+
+## 1.9.1
+
+* Properly handle multi-line labels for multi-span highlights.
+
+* Populate the pubspec `repository` field.
+
+## 1.9.0
+
+* Add `SourceSpanWithContextExtension.subspan` that returns a
+ `SourceSpanWithContext` rather than a plain `SourceSpan`.
+
+## 1.8.2
+
+* Fix a bug where highlighting multiple spans with `null` URLs could cause an
+ assertion error. Now when multiple spans are passed with `null` URLs, they're
+ highlighted as though they all come from different source files.
+
+## 1.8.1
+
+* Fix a bug where the URL header for the highlights with multiple files would
+ get omitted only one span has a non-null URI.
+
+## 1.8.0
+
+* Stable release for null safety.
+
+## 1.7.0
+
+* Add a `SourceSpan.subspan()` extension method which returns a slice of an
+ existing source span.
+
+## 1.6.0
+
+* Add support for highlighting multiple source spans at once, providing more
+ context for span-based messages. This is exposed through the new APIs
+ `SourceSpan.highlightMultiple()` and `SourceSpan.messageMultiple()` (both
+ extension methods), `MultiSourceSpanException`, and
+ `MultiSourceSpanFormatException`.
+
+## 1.5.6
+
+* Fix padding around line numbers that are powers of 10 in
+ `FileSpan.highlight()`.
+
+## 1.5.5
+
+* Fix a bug where `FileSpan.highlight()` would crash for spans that covered a
+ trailing newline and a single additional empty line.
+
+## 1.5.4
+
+* `FileSpan.highlight()` now properly highlights point spans at the beginning of
+ lines.
+
+## 1.5.3
+
+* Fix an edge case where `FileSpan.highlight()` would put the highlight
+ indicator in the wrong position when highlighting a point span after the end
+ of a file.
+
+## 1.5.2
+
+* `SourceFile.span()` now goes to the end of the file by default, rather than
+ ending one character before the end of the file. This matches the documented
+ behavior.
+
+* `FileSpan.context` now includes the full line on which the span appears for
+ empty spans at the beginning and end of lines.
+
+* Fix an edge case where `FileSpan.highlight()` could crash when highlighting a
+ span that ended with an empty line.
+
+## 1.5.1
+
+* Produce better source span highlights for multi-line spans that cover the
+ entire last line of the span, including the newline.
+
+* Produce better source span highlights for spans that contain Windows-style
+ newlines.
+
+## 1.5.0
+
+* Improve the output of `SourceSpan.highlight()` and `SourceSpan.message()`:
+
+ * They now include line numbers.
+ * They will now print every line of a multiline span.
+ * They will now use Unicode box-drawing characters by default (this can be
+ controlled using [`term_glyph.ascii`][]).
+
+[`term_glyph.ascii`]: https://pub.dartlang.org/documentation/term_glyph/latest/term_glyph/ascii.html
+
+## 1.4.1
+
+* Set max SDK version to `<3.0.0`, and adjust other dependencies.
+
+## 1.4.0
+
+* The `new SourceFile()` constructor is deprecated. This constructed a source
+ file from a string's runes, rather than its code units, which runs counter to
+ the way Dart handles strings otherwise. The `new StringFile.fromString()`
+ constructor (see below) should be used instead.
+
+* The `new SourceFile.fromString()` constructor was added. This works like `new
+ SourceFile()`, except it uses code units rather than runes.
+
+* The current behavior when characters larger than `0xFFFF` are passed to `new
+ SourceFile.decoded()` is now considered deprecated.
+
+## 1.3.1
+
+* Properly highlight spans for lines that include tabs with
+ `SourceSpan.highlight()` and `SourceSpan.message()`.
+
+## 1.3.0
+
+* Add `SourceSpan.highlight()`, which returns just the highlighted text that
+ would be included in `SourceSpan.message()`.
+
+## 1.2.4
+
+* Fix a new strong mode error.
+
+## 1.2.3
+
+* Fix a bug where a point span at the end of a file without a trailing newline
+ would be printed incorrectly.
+
+## 1.2.2
+
+* Allow `SourceSpanException.message`, `SourceSpanFormatException.source`, and
+ `SourceSpanWithContext.context` to be overridden in strong mode.
+
+## 1.2.1
+
+* Fix the declared type of `FileSpan.start` and `FileSpan.end`. In 1.2.0 these
+ were mistakenly changed from `FileLocation` to `SourceLocation`.
+
+## 1.2.0
+
+* **Deprecated:** Extending `SourceLocation` directly is deprecated. Instead,
+ extend the new `SourceLocationBase` class or mix in the new
+ `SourceLocationMixin` mixin.
+
+* Dramatically improve the performance of `FileLocation`.
+
+## 1.1.6
+
+* Optimize `getLine()` in `SourceFile` when repeatedly called.
+
+## 1.1.5
+
+* Fixed another case in which `FileSpan.union` could throw an exception for
+ external implementations of `FileSpan`.
+
+## 1.1.4
+
+* Eliminated dart2js warning about overriding `==`, but not `hashCode`.
+
+## 1.1.3
+
+* `FileSpan.compareTo`, `FileSpan.==`, `FileSpan.union`, and `FileSpan.expand`
+ no longer throw exceptions for external implementations of `FileSpan`.
+
+* `FileSpan.hashCode` now fully agrees with `FileSpan.==`.
+
+## 1.1.2
+
+* Fixed validation in `SourceSpanWithContext` to allow multiple occurrences of
+ `text` within `context`.
+
+## 1.1.1
+
+* Fixed `FileSpan`'s context to include the full span text, not just the first
+ line of it.
+
+## 1.1.0
+
+* Added `SourceSpanWithContext`: a span that also includes the full line of text
+ that contains the span.
+
+## 1.0.3
+
+* Cleanup equality operator to accept any Object rather than just a
+ `SourceLocation`.
+
+## 1.0.2
+
+* Avoid unintentionally allocating extra objects for internal `FileSpan`
+ operations.
+
+* Ensure that `SourceSpan.operator==` works on arbitrary `Object`s.
+
+## 1.0.1
+
+* Use a more compact internal representation for `FileSpan`.
+
+## 1.0.0
+
+This package was extracted from the
+[`source_maps`](https://pub.dev/packages/source_maps) package, but the
+API has many differences. Among them:
+
+* `Span` has been renamed to `SourceSpan` and `Location` has been renamed to
+ `SourceLocation` to clarify their purpose and maintain consistency with the
+ package name. Likewise, `SpanException` is now `SourceSpanException` and
+ `SpanFormatException` is not `SourceSpanFormatException`.
+
+* `FixedSpan` and `FixedLocation` have been rolled into the `Span` and
+ `Location` classes, respectively.
+
+* `SourceFile` is more aggressive about validating its arguments. Out-of-bounds
+ lines, columns, and offsets will now throw errors rather than be silently
+ clamped.
+
+* `SourceSpan.sourceUrl`, `SourceLocation.sourceUrl`, and `SourceFile.url` now
+ return `Uri` objects rather than `String`s. The constructors allow either
+ `String`s or `Uri`s.
+
+* `Span.getLocationMessage` and `SourceFile.getLocationMessage` are now
+ `SourceSpan.message` and `SourceFile.message`, respectively. Rather than
+ taking both a `useColor` and a `color` parameter, they now take a single
+ `color` parameter that controls both whether and which color is used.
+
+* `Span.isIdentifier` has been removed. This property doesn't make sense outside
+ of a source map context.
+
+* `SourceFileSegment` has been removed. This class wasn't widely used and was
+ inconsistent in its choice of which parameters were considered relative and
+ which absolute.
diff --git a/pkgs/source_span/LICENSE b/pkgs/source_span/LICENSE
new file mode 100644
index 0000000..000cd7b
--- /dev/null
+++ b/pkgs/source_span/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/source_span/README.md b/pkgs/source_span/README.md
new file mode 100644
index 0000000..b4ce25f
--- /dev/null
+++ b/pkgs/source_span/README.md
@@ -0,0 +1,21 @@
+[](https://github.com/dart-lang/tools/actions/workflows/source_span.yaml)
+[](https://pub.dev/packages/source_span)
+[](https://pub.dev/packages/source_span/publisher)
+
+## About this package
+
+`source_span` is a library for tracking locations in source code. It's designed
+to provide a standard representation for source code locations and spans so that
+disparate packages can easily pass them among one another, and to make it easy
+to generate human-friendly messages associated with a given piece of code.
+
+The most commonly-used class is the package's namesake, `SourceSpan`. It
+represents a span of characters in some source file, and is often attached to an
+object that has been parsed to indicate where it was parsed from. It provides
+access to the text of the span via `SourceSpan.text` and can be used to produce
+human-friendly messages using `SourceSpan.message()`.
+
+When parsing code from a file, `SourceFile` is useful. Not only does it provide
+an efficient means of computing line and column numbers, `SourceFile.span()`
+returns special `FileSpan`s that are able to provide more context for their
+error messages.
diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml
new file mode 100644
index 0000000..d2ebdbf
--- /dev/null
+++ b/pkgs/source_span/analysis_options.yaml
@@ -0,0 +1,32 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+linter:
+ rules:
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_classes_with_only_static_members
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_returning_this
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - cascade_invocations
+ - join_return_with_assignment
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - prefer_const_declarations
+ - prefer_expression_function_bodies
+ - prefer_final_locals
+ - unnecessary_await_in_return
+ - unnecessary_raw_strings
+ - use_if_null_to_convert_nulls_to_bools
+ - use_raw_strings
+ - use_string_buffers
diff --git a/pkgs/source_span/example/main.dart b/pkgs/source_span/example/main.dart
new file mode 100644
index 0000000..e296765
--- /dev/null
+++ b/pkgs/source_span/example/main.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:source_span/source_span.dart';
+
+void main(List<String> args) {
+ final file = File('README.md');
+ final contents = file.readAsStringSync();
+
+ final sourceFile = SourceFile.fromString(contents, url: file.uri);
+ final spans = _parseFile(contents, sourceFile);
+
+ for (var span in spans.take(30)) {
+ print('[${span.start.line + 1}:${span.start.column + 1}] ${span.text}');
+ }
+}
+
+Iterable<SourceSpan> _parseFile(String contents, SourceFile sourceFile) sync* {
+ var wordStart = 0;
+ var inWhiteSpace = true;
+
+ for (var i = 0; i < contents.length; i++) {
+ final codeUnit = contents.codeUnitAt(i);
+
+ if (codeUnit == _eol || codeUnit == _space) {
+ if (!inWhiteSpace) {
+ inWhiteSpace = true;
+
+ // emit a word
+ yield sourceFile.span(wordStart, i);
+ }
+ } else {
+ if (inWhiteSpace) {
+ inWhiteSpace = false;
+
+ wordStart = i;
+ }
+ }
+ }
+
+ if (!inWhiteSpace) {
+ // emit a word
+ yield sourceFile.span(wordStart, contents.length);
+ }
+}
+
+const int _eol = 10;
+const int _space = 32;
diff --git a/pkgs/source_span/lib/source_span.dart b/pkgs/source_span/lib/source_span.dart
new file mode 100644
index 0000000..534a3a7
--- /dev/null
+++ b/pkgs/source_span/lib/source_span.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/file.dart';
+export 'src/location.dart';
+export 'src/location_mixin.dart';
+export 'src/span.dart';
+export 'src/span_exception.dart';
+export 'src/span_mixin.dart';
+export 'src/span_with_context.dart';
diff --git a/pkgs/source_span/lib/src/charcode.dart b/pkgs/source_span/lib/src/charcode.dart
new file mode 100644
index 0000000..5182638
--- /dev/null
+++ b/pkgs/source_span/lib/src/charcode.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// "Carriage return" control character.
+const int $cr = 0x0D;
+
+/// "Line feed" control character.
+const int $lf = 0x0A;
+
+/// Space character.
+const int $space = 0x20;
+
+/// "Horizontal Tab" control character, common name.
+const int $tab = 0x09;
diff --git a/pkgs/source_span/lib/src/colors.dart b/pkgs/source_span/lib/src/colors.dart
new file mode 100644
index 0000000..b48d468
--- /dev/null
+++ b/pkgs/source_span/lib/src/colors.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Color constants used for generating messages.
+const String red = '\u001b[31m';
+
+const String yellow = '\u001b[33m';
+
+const String blue = '\u001b[34m';
+
+const String none = '\u001b[0m';
diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart
new file mode 100644
index 0000000..74c9234
--- /dev/null
+++ b/pkgs/source_span/lib/src/file.dart
@@ -0,0 +1,454 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' as math;
+import 'dart:typed_data';
+
+import 'location.dart';
+import 'location_mixin.dart';
+import 'span.dart';
+import 'span_mixin.dart';
+import 'span_with_context.dart';
+
+// Constants to determine end-of-lines.
+const int _lf = 10;
+const int _cr = 13;
+
+/// A class representing a source file.
+///
+/// This doesn't necessarily have to correspond to a file on disk, just a chunk
+/// of text usually with a URL associated with it.
+class SourceFile {
+ /// The URL where the source file is located.
+ ///
+ /// This may be null, indicating that the URL is unknown or unavailable.
+ final Uri? url;
+
+ /// An array of offsets for each line beginning in the file.
+ ///
+ /// Each offset refers to the first character *after* the newline. If the
+ /// source file has a trailing newline, the final offset won't actually be in
+ /// the file.
+ final _lineStarts = <int>[0];
+
+ /// The code units of the characters in the file.
+ ///
+ /// If this was constructed with the deprecated `SourceFile()` constructor,
+ /// this will instead contain the code _points_ of the characters in the file
+ /// (so characters above 2^16 are represented as individual integers rather
+ /// than surrogate pairs).
+ List<int> get codeUnits => _decodedChars;
+
+ /// The code units of the characters in this file.
+ final Uint32List _decodedChars;
+
+ /// The length of the file in characters.
+ int get length => _decodedChars.length;
+
+ /// The number of lines in the file.
+ int get lines => _lineStarts.length;
+
+ /// The line that the offset fell on the last time [getLine] was called.
+ ///
+ /// In many cases, sequential calls to getLine() are for nearby, usually
+ /// increasing offsets. In that case, we can find the line for an offset
+ /// quickly by first checking to see if the offset is on the same line as the
+ /// previous result.
+ int? _cachedLine;
+
+ /// This constructor is deprecated.
+ ///
+ /// Use [SourceFile.fromString] instead.
+ @Deprecated('Will be removed in 2.0.0')
+ SourceFile(String text, {Object? url}) : this.decoded(text.runes, url: url);
+
+ /// Creates a new source file from [text].
+ ///
+ /// [url] may be either a [String], a [Uri], or `null`.
+ SourceFile.fromString(String text, {Object? url})
+ : this.decoded(text.codeUnits, url: url);
+
+ /// Creates a new source file from a list of decoded code units.
+ ///
+ /// [url] may be either a [String], a [Uri], or `null`.
+ ///
+ /// Currently, if [decodedChars] contains characters larger than `0xFFFF`,
+ /// they'll be treated as single characters rather than being split into
+ /// surrogate pairs. **This behavior is deprecated**. For
+ /// forwards-compatibility, callers should only pass in characters less than
+ /// or equal to `0xFFFF`.
+ SourceFile.decoded(Iterable<int> decodedChars, {Object? url})
+ : url = url is String ? Uri.parse(url) : url as Uri?,
+ _decodedChars = Uint32List.fromList(decodedChars.toList()) {
+ for (var i = 0; i < _decodedChars.length; i++) {
+ var c = _decodedChars[i];
+ if (c == _cr) {
+ // Return not followed by newline is treated as a newline
+ final j = i + 1;
+ if (j >= _decodedChars.length || _decodedChars[j] != _lf) c = _lf;
+ }
+ if (c == _lf) _lineStarts.add(i + 1);
+ }
+ }
+
+ /// Returns a span from [start] to [end] (exclusive).
+ ///
+ /// If [end] isn't passed, it defaults to the end of the file.
+ FileSpan span(int start, [int? end]) {
+ end ??= length;
+ return _FileSpan(this, start, end);
+ }
+
+ /// Returns a location at [offset].
+ FileLocation location(int offset) => FileLocation._(this, offset);
+
+ /// Gets the 0-based line corresponding to [offset].
+ int getLine(int offset) {
+ if (offset < 0) {
+ throw RangeError('Offset may not be negative, was $offset.');
+ } else if (offset > length) {
+ throw RangeError('Offset $offset must not be greater than the number '
+ 'of characters in the file, $length.');
+ }
+
+ if (offset < _lineStarts.first) return -1;
+ if (offset >= _lineStarts.last) return _lineStarts.length - 1;
+
+ if (_isNearCachedLine(offset)) return _cachedLine!;
+
+ _cachedLine = _binarySearch(offset) - 1;
+ return _cachedLine!;
+ }
+
+ /// Returns `true` if [offset] is near [_cachedLine].
+ ///
+ /// Checks on [_cachedLine] and the next line. If it's on the next line, it
+ /// updates [_cachedLine] to point to that.
+ bool _isNearCachedLine(int offset) {
+ if (_cachedLine == null) return false;
+ final cachedLine = _cachedLine!;
+
+ // See if it's before the cached line.
+ if (offset < _lineStarts[cachedLine]) return false;
+
+ // See if it's on the cached line.
+ if (cachedLine >= _lineStarts.length - 1 ||
+ offset < _lineStarts[cachedLine + 1]) {
+ return true;
+ }
+
+ // See if it's on the next line.
+ if (cachedLine >= _lineStarts.length - 2 ||
+ offset < _lineStarts[cachedLine + 2]) {
+ _cachedLine = cachedLine + 1;
+ return true;
+ }
+
+ return false;
+ }
+
+ /// Binary search through [_lineStarts] to find the line containing [offset].
+ ///
+ /// Returns the index of the line in [_lineStarts].
+ int _binarySearch(int offset) {
+ var min = 0;
+ var max = _lineStarts.length - 1;
+ while (min < max) {
+ final half = min + ((max - min) ~/ 2);
+ if (_lineStarts[half] > offset) {
+ max = half;
+ } else {
+ min = half + 1;
+ }
+ }
+
+ return max;
+ }
+
+ /// Gets the 0-based column corresponding to [offset].
+ ///
+ /// If [line] is passed, it's assumed to be the line containing [offset] and
+ /// is used to more efficiently compute the column.
+ int getColumn(int offset, {int? line}) {
+ if (offset < 0) {
+ throw RangeError('Offset may not be negative, was $offset.');
+ } else if (offset > length) {
+ throw RangeError('Offset $offset must be not be greater than the '
+ 'number of characters in the file, $length.');
+ }
+
+ if (line == null) {
+ line = getLine(offset);
+ } else if (line < 0) {
+ throw RangeError('Line may not be negative, was $line.');
+ } else if (line >= lines) {
+ throw RangeError('Line $line must be less than the number of '
+ 'lines in the file, $lines.');
+ }
+
+ final lineStart = _lineStarts[line];
+ if (lineStart > offset) {
+ throw RangeError('Line $line comes after offset $offset.');
+ }
+
+ return offset - lineStart;
+ }
+
+ /// Gets the offset for a [line] and [column].
+ ///
+ /// [column] defaults to 0.
+ int getOffset(int line, [int? column]) {
+ column ??= 0;
+
+ if (line < 0) {
+ throw RangeError('Line may not be negative, was $line.');
+ } else if (line >= lines) {
+ throw RangeError('Line $line must be less than the number of '
+ 'lines in the file, $lines.');
+ } else if (column < 0) {
+ throw RangeError('Column may not be negative, was $column.');
+ }
+
+ final result = _lineStarts[line] + column;
+ if (result > length ||
+ (line + 1 < lines && result >= _lineStarts[line + 1])) {
+ throw RangeError("Line $line doesn't have $column columns.");
+ }
+
+ return result;
+ }
+
+ /// Returns the text of the file from [start] to [end] (exclusive).
+ ///
+ /// If [end] isn't passed, it defaults to the end of the file.
+ String getText(int start, [int? end]) =>
+ String.fromCharCodes(_decodedChars.sublist(start, end));
+}
+
+/// A [SourceLocation] within a [SourceFile].
+///
+/// Unlike the base [SourceLocation], [FileLocation] lazily computes its line
+/// and column values based on its offset and the contents of [file].
+///
+/// A [FileLocation] can be created using [SourceFile.location].
+class FileLocation extends SourceLocationMixin implements SourceLocation {
+ /// The [file] that `this` belongs to.
+ final SourceFile file;
+
+ @override
+ final int offset;
+
+ @override
+ Uri? get sourceUrl => file.url;
+
+ @override
+ int get line => file.getLine(offset);
+
+ @override
+ int get column => file.getColumn(offset);
+
+ FileLocation._(this.file, this.offset) {
+ if (offset < 0) {
+ throw RangeError('Offset may not be negative, was $offset.');
+ } else if (offset > file.length) {
+ throw RangeError('Offset $offset must not be greater than the number '
+ 'of characters in the file, ${file.length}.');
+ }
+ }
+
+ @override
+ FileSpan pointSpan() => _FileSpan(file, offset, offset);
+}
+
+/// A [SourceSpan] within a [SourceFile].
+///
+/// Unlike the base [SourceSpan], [FileSpan] lazily computes its line and column
+/// values based on its offset and the contents of [file]. [SourceSpan.message]
+/// is also able to provide more context then [SourceSpan.message], and
+/// [SourceSpan.union] will return a [FileSpan] if possible.
+///
+/// A [FileSpan] can be created using [SourceFile.span].
+abstract class FileSpan implements SourceSpanWithContext {
+ /// The [file] that `this` belongs to.
+ SourceFile get file;
+
+ @override
+ FileLocation get start;
+
+ @override
+ FileLocation get end;
+
+ /// Returns a new span that covers both `this` and [other].
+ ///
+ /// Unlike [union], [other] may be disjoint from `this`. If it is, the text
+ /// between the two will be covered by the returned span.
+ FileSpan expand(FileSpan other);
+}
+
+/// The implementation of [FileSpan].
+///
+/// This is split into a separate class so that `is _FileSpan` checks can be run
+/// to make certain operations more efficient. If we used `is FileSpan`, that
+/// would break if external classes implemented the interface.
+class _FileSpan extends SourceSpanMixin implements FileSpan {
+ @override
+ final SourceFile file;
+
+ /// The offset of the beginning of the span.
+ ///
+ /// [start] is lazily generated from this to avoid allocating unnecessary
+ /// objects.
+ final int _start;
+
+ /// The offset of the end of the span.
+ ///
+ /// [end] is lazily generated from this to avoid allocating unnecessary
+ /// objects.
+ final int _end;
+
+ @override
+ Uri? get sourceUrl => file.url;
+
+ @override
+ int get length => _end - _start;
+
+ @override
+ FileLocation get start => FileLocation._(file, _start);
+
+ @override
+ FileLocation get end => FileLocation._(file, _end);
+
+ @override
+ String get text => file.getText(_start, _end);
+
+ @override
+ String get context {
+ final endLine = file.getLine(_end);
+ final endColumn = file.getColumn(_end);
+
+ int? endOffset;
+ if (endColumn == 0 && endLine != 0) {
+ // If [end] is at the very beginning of the line, the span covers the
+ // previous newline, so we only want to include the previous line in the
+ // context...
+
+ if (length == 0) {
+ // ...unless this is a point span, in which case we want to include the
+ // next line (or the empty string if this is the end of the file).
+ return endLine == file.lines - 1
+ ? ''
+ : file.getText(
+ file.getOffset(endLine), file.getOffset(endLine + 1));
+ }
+
+ endOffset = _end;
+ } else if (endLine == file.lines - 1) {
+ // If the span covers the last line of the file, the context should go all
+ // the way to the end of the file.
+ endOffset = file.length;
+ } else {
+ // Otherwise, the context should cover the full line on which [end]
+ // appears.
+ endOffset = file.getOffset(endLine + 1);
+ }
+
+ return file.getText(file.getOffset(file.getLine(_start)), endOffset);
+ }
+
+ _FileSpan(this.file, this._start, this._end) {
+ if (_end < _start) {
+ throw ArgumentError('End $_end must come after start $_start.');
+ } else if (_end > file.length) {
+ throw RangeError('End $_end must not be greater than the number '
+ 'of characters in the file, ${file.length}.');
+ } else if (_start < 0) {
+ throw RangeError('Start may not be negative, was $_start.');
+ }
+ }
+
+ @override
+ int compareTo(SourceSpan other) {
+ if (other is! _FileSpan) return super.compareTo(other);
+
+ final result = _start.compareTo(other._start);
+ return result == 0 ? _end.compareTo(other._end) : result;
+ }
+
+ @override
+ SourceSpan union(SourceSpan other) {
+ if (other is! FileSpan) return super.union(other);
+
+ final span = expand(other);
+
+ if (other is _FileSpan) {
+ if (_start > other._end || other._start > _end) {
+ throw ArgumentError('Spans $this and $other are disjoint.');
+ }
+ } else {
+ if (_start > other.end.offset || other.start.offset > _end) {
+ throw ArgumentError('Spans $this and $other are disjoint.');
+ }
+ }
+
+ return span;
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (other is! FileSpan) return super == other;
+ if (other is! _FileSpan) {
+ return super == other && sourceUrl == other.sourceUrl;
+ }
+
+ return _start == other._start &&
+ _end == other._end &&
+ sourceUrl == other.sourceUrl;
+ }
+
+ @override
+ int get hashCode => Object.hash(_start, _end, sourceUrl);
+
+ /// Returns a new span that covers both `this` and [other].
+ ///
+ /// Unlike [union], [other] may be disjoint from `this`. If it is, the text
+ /// between the two will be covered by the returned span.
+ @override
+ FileSpan expand(FileSpan other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw ArgumentError('Source URLs "$sourceUrl" and '
+ " \"${other.sourceUrl}\" don't match.");
+ }
+
+ if (other is _FileSpan) {
+ final start = math.min(_start, other._start);
+ final end = math.max(_end, other._end);
+ return _FileSpan(file, start, end);
+ } else {
+ final start = math.min(_start, other.start.offset);
+ final end = math.max(_end, other.end.offset);
+ return _FileSpan(file, start, end);
+ }
+ }
+
+ /// See `SourceSpanExtension.subspan`.
+ FileSpan subspan(int start, [int? end]) {
+ RangeError.checkValidRange(start, end, length);
+ if (start == 0 && (end == null || end == length)) return this;
+ return file.span(_start + start, end == null ? _end : _start + end);
+ }
+}
+
+// TODO(#52): Move these to instance methods in the next breaking release.
+/// Extension methods on the [FileSpan] API.
+extension FileSpanExtension on FileSpan {
+ /// See `SourceSpanExtension.subspan`.
+ FileSpan subspan(int start, [int? end]) {
+ RangeError.checkValidRange(start, end, length);
+ if (start == 0 && (end == null || end == length)) return this;
+
+ final startOffset = this.start.offset;
+ return file.span(
+ startOffset + start, end == null ? this.end.offset : startOffset + end);
+ }
+}
diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart
new file mode 100644
index 0000000..19e04d0
--- /dev/null
+++ b/pkgs/source_span/lib/src/highlighter.dart
@@ -0,0 +1,727 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' as math;
+
+import 'package:collection/collection.dart';
+import 'package:path/path.dart' as p;
+import 'package:term_glyph/term_glyph.dart' as glyph;
+
+import 'charcode.dart';
+import 'colors.dart' as colors;
+import 'location.dart';
+import 'span.dart';
+import 'span_with_context.dart';
+import 'utils.dart';
+
+/// A class for writing a chunk of text with a particular span highlighted.
+class Highlighter {
+ /// The lines to display, including context around the highlighted spans.
+ final List<_Line> _lines;
+
+ /// The color to highlight the primary [_Highlight] within its context, or
+ /// `null` if it should not be colored.
+ final String? _primaryColor;
+
+ /// The color to highlight the secondary [_Highlight]s within their context,
+ /// or `null` if they should not be colored.
+ final String? _secondaryColor;
+
+ /// The number of characters before the bar in the sidebar.
+ final int _paddingBeforeSidebar;
+
+ /// The maximum number of multiline spans that cover any part of a single
+ /// line in [_lines].
+ final int _maxMultilineSpans;
+
+ /// Whether [_lines] includes lines from multiple different files.
+ final bool _multipleFiles;
+
+ /// The buffer to which to write the result.
+ final _buffer = StringBuffer();
+
+ /// The number of spaces to render for hard tabs that appear in `_span.text`.
+ ///
+ /// We don't want to render raw tabs, because they'll mess up our character
+ /// alignment.
+ static const _spacesPerTab = 4;
+
+ /// Creates a [Highlighter] that will return a string highlighting [span]
+ /// within the text of its file when [highlight] is called.
+ ///
+ /// [color] may either be a [String], a [bool], or `null`. If it's a string,
+ /// it indicates an [ANSI terminal color escape][] that should be used to
+ /// highlight [span]'s text (for example, `"\u001b[31m"` will color red). If
+ /// it's `true`, it indicates that the text should be highlighted using the
+ /// default color. If it's `false` or `null`, it indicates that no color
+ /// should be used.
+ ///
+ /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+ Highlighter(SourceSpan span, {Object? color})
+ : this._(_collateLines([_Highlight(span, primary: true)]), () {
+ if (color == true) return colors.red;
+ if (color == false) return null;
+ return color as String?;
+ }(), null);
+
+ /// Creates a [Highlighter] that will return a string highlighting
+ /// [primarySpan] as well as all the spans in [secondarySpans] within the text
+ /// of their file when [highlight] is called.
+ ///
+ /// Each span has an associated label that will be written alongside it. For
+ /// [primarySpan] this message is [primaryLabel], and for [secondarySpans] the
+ /// labels are the map values.
+ ///
+ /// If [color] is `true`, this will use [ANSI terminal color escapes][] to
+ /// highlight the text. The [primarySpan] will be highlighted with
+ /// [primaryColor] (which defaults to red), and the [secondarySpans] will be
+ /// highlighted with [secondaryColor] (which defaults to blue). These
+ /// arguments are ignored if [color] is `false`.
+ ///
+ /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+ Highlighter.multiple(SourceSpan primarySpan, String primaryLabel,
+ Map<SourceSpan, String> secondarySpans,
+ {bool color = false, String? primaryColor, String? secondaryColor})
+ : this._(
+ _collateLines([
+ _Highlight(primarySpan, label: primaryLabel, primary: true),
+ for (var entry in secondarySpans.entries)
+ _Highlight(entry.key, label: entry.value)
+ ]),
+ color ? (primaryColor ?? colors.red) : null,
+ color ? (secondaryColor ?? colors.blue) : null);
+
+ Highlighter._(this._lines, this._primaryColor, this._secondaryColor)
+ : _paddingBeforeSidebar = 1 +
+ math.max<int>(
+ // In a purely mathematical world, floor(log10(n)) would give the
+ // number of digits in n, but floating point errors render that
+ // unreliable in practice.
+ (_lines.last.number + 1).toString().length,
+ // If [_lines] aren't contiguous, we'll write "..." in place of a
+ // line number.
+ _contiguous(_lines) ? 0 : 3,
+ ),
+ _maxMultilineSpans = _lines
+ .map((line) => line.highlights
+ .where((highlight) => isMultiline(highlight.span))
+ .length)
+ .reduce(math.max),
+ _multipleFiles = !isAllTheSame(_lines.map((line) => line.url));
+
+ /// Returns whether [lines] contains any adjacent lines from the same source
+ /// file that aren't adjacent in the original file.
+ static bool _contiguous(List<_Line> lines) {
+ for (var i = 0; i < lines.length - 1; i++) {
+ final thisLine = lines[i];
+ final nextLine = lines[i + 1];
+ if (thisLine.number + 1 != nextLine.number &&
+ thisLine.url == nextLine.url) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// Collect all the source lines from the contexts of all spans in
+ /// [highlights], and associates them with the highlights that cover them.
+ static List<_Line> _collateLines(List<_Highlight> highlights) {
+ // Assign spans without URLs opaque Objects as keys. Each such Object will
+ // be different, but they can then be used later on to determine which lines
+ // came from the same span even if they'd all otherwise have `null` URLs.
+ final highlightsByUrl = groupBy<_Highlight, Object>(
+ highlights, (highlight) => highlight.span.sourceUrl ?? Object());
+ for (var list in highlightsByUrl.values) {
+ list.sort((highlight1, highlight2) =>
+ highlight1.span.compareTo(highlight2.span));
+ }
+
+ return highlightsByUrl.entries.expand((entry) {
+ final url = entry.key;
+ final highlightsForFile = entry.value;
+
+ // First, create a list of all the lines in the current file that we have
+ // context for along with their line numbers.
+ final lines = <_Line>[];
+ for (var highlight in highlightsForFile) {
+ final context = highlight.span.context;
+ // If [highlight.span.context] contains lines prior to the one
+ // [highlight.span.text] appears on, write those first.
+ final lineStart = findLineStart(
+ context, highlight.span.text, highlight.span.start.column)!;
+
+ final linesBeforeSpan =
+ '\n'.allMatches(context.substring(0, lineStart)).length;
+
+ var lineNumber = highlight.span.start.line - linesBeforeSpan;
+ for (var line in context.split('\n')) {
+ // Only add a line if it hasn't already been added for a previous span
+ if (lines.isEmpty || lineNumber > lines.last.number) {
+ lines.add(_Line(line, lineNumber, url));
+ }
+ lineNumber++;
+ }
+ }
+
+ // Next, associate each line with each highlights that covers it.
+ final activeHighlights = <_Highlight>[];
+ var highlightIndex = 0;
+ for (var line in lines) {
+ activeHighlights
+ .removeWhere((highlight) => highlight.span.end.line < line.number);
+
+ final oldHighlightLength = activeHighlights.length;
+ for (var highlight in highlightsForFile.skip(highlightIndex)) {
+ if (highlight.span.start.line > line.number) break;
+ activeHighlights.add(highlight);
+ }
+ highlightIndex += activeHighlights.length - oldHighlightLength;
+
+ line.highlights.addAll(activeHighlights);
+ }
+
+ return lines;
+ }).toList();
+ }
+
+ /// Returns the highlighted span text.
+ ///
+ /// This method should only be called once.
+ String highlight() {
+ _writeFileStart(_lines.first.url);
+
+ // Each index of this list represents a column after the sidebar that could
+ // contain a line indicating an active highlight. If it's `null`, that
+ // column is empty; if it contains a highlight, it should be drawn for that
+ // column.
+ final highlightsByColumn =
+ List<_Highlight?>.filled(_maxMultilineSpans, null);
+
+ for (var i = 0; i < _lines.length; i++) {
+ final line = _lines[i];
+ if (i > 0) {
+ final lastLine = _lines[i - 1];
+ if (lastLine.url != line.url) {
+ _writeSidebar(end: glyph.upEnd);
+ _buffer.writeln();
+ _writeFileStart(line.url);
+ } else if (lastLine.number + 1 != line.number) {
+ _writeSidebar(text: '...');
+ _buffer.writeln();
+ }
+ }
+
+ // If a highlight covers the entire first line other than initial
+ // whitespace, don't bother pointing out exactly where it begins. Iterate
+ // in reverse so that longer highlights (which are sorted after shorter
+ // highlights) appear further out, leading to fewer crossed lines.
+ for (var highlight in line.highlights.reversed) {
+ if (isMultiline(highlight.span) &&
+ highlight.span.start.line == line.number &&
+ _isOnlyWhitespace(
+ line.text.substring(0, highlight.span.start.column))) {
+ replaceFirstNull(highlightsByColumn, highlight);
+ }
+ }
+
+ _writeSidebar(line: line.number);
+ _buffer.write(' ');
+ _writeMultilineHighlights(line, highlightsByColumn);
+ if (highlightsByColumn.isNotEmpty) _buffer.write(' ');
+
+ final primaryIdx =
+ line.highlights.indexWhere((highlight) => highlight.isPrimary);
+ final primary = primaryIdx == -1 ? null : line.highlights[primaryIdx];
+
+ if (primary != null) {
+ _writeHighlightedText(
+ line.text,
+ primary.span.start.line == line.number
+ ? primary.span.start.column
+ : 0,
+ primary.span.end.line == line.number
+ ? primary.span.end.column
+ : line.text.length,
+ color: _primaryColor);
+ } else {
+ _writeText(line.text);
+ }
+ _buffer.writeln();
+
+ // Always write the primary span's indicator first so that it's right next
+ // to the highlighted text.
+ if (primary != null) _writeIndicator(line, primary, highlightsByColumn);
+ for (var highlight in line.highlights) {
+ if (highlight.isPrimary) continue;
+ _writeIndicator(line, highlight, highlightsByColumn);
+ }
+ }
+
+ _writeSidebar(end: glyph.upEnd);
+ return _buffer.toString();
+ }
+
+ /// Writes the beginning of the file highlight for the file with the given
+ /// [url] (or opaque object if it comes from a span with a null URL).
+ void _writeFileStart(Object url) {
+ if (!_multipleFiles || url is! Uri) {
+ _writeSidebar(end: glyph.downEnd);
+ } else {
+ _writeSidebar(end: glyph.topLeftCorner);
+ _colorize(() => _buffer.write('${glyph.horizontalLine * 2}>'),
+ color: colors.blue);
+ _buffer.write(' ${p.prettyUri(url)}');
+ }
+ _buffer.writeln();
+ }
+
+ /// Writes the post-sidebar highlight bars for [line] according to
+ /// [highlightsByColumn].
+ ///
+ /// If [current] is passed, it's the highlight for which an indicator is being
+ /// written. If it appears in [highlightsByColumn], a horizontal line is
+ /// written from its column to the rightmost column.
+ void _writeMultilineHighlights(
+ _Line line, List<_Highlight?> highlightsByColumn,
+ {_Highlight? current}) {
+ // Whether we've written a sidebar indicator for opening a new span on this
+ // line, and which color should be used for that indicator's rightward line.
+ var openedOnThisLine = false;
+ String? openedOnThisLineColor;
+
+ final currentColor = current == null
+ ? null
+ : current.isPrimary
+ ? _primaryColor
+ : _secondaryColor;
+ var foundCurrent = false;
+ for (var highlight in highlightsByColumn) {
+ final startLine = highlight?.span.start.line;
+ final endLine = highlight?.span.end.line;
+ if (current != null && highlight == current) {
+ foundCurrent = true;
+ assert(startLine == line.number || endLine == line.number);
+ _colorize(() {
+ _buffer.write(startLine == line.number
+ ? glyph.topLeftCorner
+ : glyph.bottomLeftCorner);
+ }, color: currentColor);
+ } else if (foundCurrent) {
+ _colorize(() {
+ _buffer.write(highlight == null ? glyph.horizontalLine : glyph.cross);
+ }, color: currentColor);
+ } else if (highlight == null) {
+ if (openedOnThisLine) {
+ _colorize(() => _buffer.write(glyph.horizontalLine),
+ color: openedOnThisLineColor);
+ } else {
+ _buffer.write(' ');
+ }
+ } else {
+ _colorize(() {
+ final vertical = openedOnThisLine ? glyph.cross : glyph.verticalLine;
+ if (current != null) {
+ _buffer.write(vertical);
+ } else if (startLine == line.number) {
+ _colorize(() {
+ _buffer
+ .write(glyph.glyphOrAscii(openedOnThisLine ? '┬' : '┌', '/'));
+ }, color: openedOnThisLineColor);
+ openedOnThisLine = true;
+ openedOnThisLineColor ??=
+ highlight.isPrimary ? _primaryColor : _secondaryColor;
+ } else if (endLine == line.number &&
+ highlight.span.end.column == line.text.length) {
+ _buffer.write(highlight.label == null
+ ? glyph.glyphOrAscii('└', r'\')
+ : vertical);
+ } else {
+ _colorize(() {
+ _buffer.write(vertical);
+ }, color: openedOnThisLineColor);
+ }
+ }, color: highlight.isPrimary ? _primaryColor : _secondaryColor);
+ }
+ }
+ }
+
+ // Writes [text], with text between [startColumn] and [endColumn] colorized in
+ // the same way as [_colorize].
+ void _writeHighlightedText(String text, int startColumn, int endColumn,
+ {required String? color}) {
+ _writeText(text.substring(0, startColumn));
+ _colorize(() => _writeText(text.substring(startColumn, endColumn)),
+ color: color);
+ _writeText(text.substring(endColumn, text.length));
+ }
+
+ /// Writes an indicator for where [highlight] starts, ends, or both below
+ /// [line].
+ ///
+ /// This may either add or remove [highlight] from [highlightsByColumn].
+ void _writeIndicator(
+ _Line line, _Highlight highlight, List<_Highlight?> highlightsByColumn) {
+ final color = highlight.isPrimary ? _primaryColor : _secondaryColor;
+ if (!isMultiline(highlight.span)) {
+ _writeSidebar();
+ _buffer.write(' ');
+ _writeMultilineHighlights(line, highlightsByColumn, current: highlight);
+ if (highlightsByColumn.isNotEmpty) _buffer.write(' ');
+
+ final underlineLength = _colorize(() {
+ final start = _buffer.length;
+ _writeUnderline(line, highlight.span,
+ highlight.isPrimary ? '^' : glyph.horizontalLineBold);
+ return _buffer.length - start;
+ }, color: color);
+ _writeLabel(highlight, highlightsByColumn, underlineLength);
+ } else if (highlight.span.start.line == line.number) {
+ if (highlightsByColumn.contains(highlight)) return;
+ replaceFirstNull(highlightsByColumn, highlight);
+
+ _writeSidebar();
+ _buffer.write(' ');
+ _writeMultilineHighlights(line, highlightsByColumn, current: highlight);
+ _colorize(() => _writeArrow(line, highlight.span.start.column),
+ color: color);
+ _buffer.writeln();
+ } else if (highlight.span.end.line == line.number) {
+ final coversWholeLine = highlight.span.end.column == line.text.length;
+ if (coversWholeLine && highlight.label == null) {
+ replaceWithNull(highlightsByColumn, highlight);
+ return;
+ }
+
+ _writeSidebar();
+ _buffer.write(' ');
+ _writeMultilineHighlights(line, highlightsByColumn, current: highlight);
+
+ final underlineLength = _colorize(() {
+ final start = _buffer.length;
+ if (coversWholeLine) {
+ _buffer.write(glyph.horizontalLine * 3);
+ } else {
+ _writeArrow(line, math.max(highlight.span.end.column - 1, 0),
+ beginning: false);
+ }
+ return _buffer.length - start;
+ }, color: color);
+ _writeLabel(highlight, highlightsByColumn, underlineLength);
+ replaceWithNull(highlightsByColumn, highlight);
+ }
+ }
+
+ /// Underlines the portion of [line] covered by [span] with repeated instances
+ /// of [character].
+ void _writeUnderline(_Line line, SourceSpan span, String character) {
+ assert(!isMultiline(span));
+ assert(line.text.contains(span.text),
+ '"${line.text}" should contain "${span.text}"');
+
+ var startColumn = span.start.column;
+ var endColumn = span.end.column;
+
+ // Adjust the start and end columns to account for any tabs that were
+ // converted to spaces.
+ final tabsBefore = _countTabs(line.text.substring(0, startColumn));
+ final tabsInside = _countTabs(line.text.substring(startColumn, endColumn));
+ startColumn += tabsBefore * (_spacesPerTab - 1);
+ endColumn += (tabsBefore + tabsInside) * (_spacesPerTab - 1);
+
+ _buffer
+ ..write(' ' * startColumn)
+ ..write(character * math.max(endColumn - startColumn, 1));
+ }
+
+ /// Write an arrow pointing to column [column] in [line].
+ ///
+ /// If the arrow points to a tab character, this will point to the beginning
+ /// of the tab if [beginning] is `true` and the end if it's `false`.
+ void _writeArrow(_Line line, int column, {bool beginning = true}) {
+ final tabs =
+ _countTabs(line.text.substring(0, column + (beginning ? 0 : 1)));
+ _buffer
+ ..write(glyph.horizontalLine * (1 + column + tabs * (_spacesPerTab - 1)))
+ ..write('^');
+ }
+
+ /// Writes [highlight]'s label.
+ ///
+ /// The `_buffer` is assumed to be written to the point where the first line
+ /// of `highlight.label` can be written after a space, but this takes care of
+ /// writing indentation and highlight columns for later lines.
+ ///
+ /// The [highlightsByColumn] are used to write ongoing highlight lines if the
+ /// label is more than one line long.
+ ///
+ /// The [underlineLength] is the length of the line written between the
+ /// highlights and the beginning of the first label.
+ void _writeLabel(_Highlight highlight, List<_Highlight?> highlightsByColumn,
+ int underlineLength) {
+ final label = highlight.label;
+ if (label == null) {
+ _buffer.writeln();
+ return;
+ }
+
+ final lines = label.split('\n');
+ final color = highlight.isPrimary ? _primaryColor : _secondaryColor;
+ _colorize(() => _buffer.write(' ${lines.first}'), color: color);
+ _buffer.writeln();
+
+ for (var text in lines.skip(1)) {
+ _writeSidebar();
+ _buffer.write(' ');
+ for (var columnHighlight in highlightsByColumn) {
+ if (columnHighlight == null || columnHighlight == highlight) {
+ _buffer.write(' ');
+ } else {
+ _buffer.write(glyph.verticalLine);
+ }
+ }
+
+ _buffer.write(' ' * underlineLength);
+ _colorize(() => _buffer.write(' $text'), color: color);
+ _buffer.writeln();
+ }
+ }
+
+ /// Writes a snippet from the source text, converting hard tab characters into
+ /// plain indentation.
+ void _writeText(String text) {
+ for (var char in text.codeUnits) {
+ if (char == $tab) {
+ _buffer.write(' ' * _spacesPerTab);
+ } else {
+ _buffer.writeCharCode(char);
+ }
+ }
+ }
+
+ // Writes a sidebar to [buffer] that includes [line] as the line number if
+ // given and writes [end] at the end (defaults to [glyphs.verticalLine]).
+ //
+ // If [text] is given, it's used in place of the line number. It can't be
+ // passed at the same time as [line].
+ void _writeSidebar({int? line, String? text, String? end}) {
+ assert(line == null || text == null);
+
+ // Add 1 to line to convert from computer-friendly 0-indexed line numbers to
+ // human-friendly 1-indexed line numbers.
+ if (line != null) text = (line + 1).toString();
+ _colorize(() {
+ _buffer
+ ..write((text ?? '').padRight(_paddingBeforeSidebar))
+ ..write(end ?? glyph.verticalLine);
+ }, color: colors.blue);
+ }
+
+ /// Returns the number of hard tabs in [text].
+ int _countTabs(String text) {
+ var count = 0;
+ for (var char in text.codeUnits) {
+ if (char == $tab) count++;
+ }
+ return count;
+ }
+
+ /// Returns whether [text] contains only space or tab characters.
+ bool _isOnlyWhitespace(String text) {
+ for (var char in text.codeUnits) {
+ if (char != $space && char != $tab) return false;
+ }
+ return true;
+ }
+
+ /// Colors all text written to [_buffer] during [callback], if colorization is
+ /// enabled and [color] is not `null`.
+ T _colorize<T>(T Function() callback, {required String? color}) {
+ if (_primaryColor != null && color != null) _buffer.write(color);
+ final result = callback();
+ if (_primaryColor != null && color != null) _buffer.write(colors.none);
+ return result;
+ }
+}
+
+/// Information about how to highlight a single section of a source file.
+class _Highlight {
+ /// The section of the source file to highlight.
+ ///
+ /// This is normalized to make it easier for [Highlighter] to work with.
+ final SourceSpanWithContext span;
+
+ /// Whether this is the primary span in the highlight.
+ ///
+ /// The primary span is highlighted with a different character and colored
+ /// differently than non-primary spans.
+ final bool isPrimary;
+
+ /// The label to include inline when highlighting [span].
+ ///
+ /// This helps distinguish clarify what each highlight means when multiple are
+ /// used in the same message.
+ final String? label;
+
+ _Highlight(SourceSpan span, {String? label, bool primary = false})
+ : span = (() {
+ var newSpan = _normalizeContext(span);
+ newSpan = _normalizeNewlines(newSpan);
+ newSpan = _normalizeTrailingNewline(newSpan);
+ return _normalizeEndOfLine(newSpan);
+ })(),
+ isPrimary = primary,
+ label = label?.replaceAll('\r\n', '\n');
+
+ /// Normalizes [span] to ensure that it's a [SourceSpanWithContext] whose
+ /// context actually contains its text at the expected column.
+ ///
+ /// If it's not already a [SourceSpanWithContext], adjust the start and end
+ /// locations' line and column fields so that the highlighter can assume they
+ /// match up with the context.
+ static SourceSpanWithContext _normalizeContext(SourceSpan span) =>
+ span is SourceSpanWithContext &&
+ findLineStart(span.context, span.text, span.start.column) != null
+ ? span
+ : SourceSpanWithContext(
+ SourceLocation(span.start.offset,
+ sourceUrl: span.sourceUrl, line: 0, column: 0),
+ SourceLocation(span.end.offset,
+ sourceUrl: span.sourceUrl,
+ line: countCodeUnits(span.text, $lf),
+ column: _lastLineLength(span.text)),
+ span.text,
+ span.text);
+
+ /// Normalizes [span] to replace Windows-style newlines with Unix-style
+ /// newlines.
+ static SourceSpanWithContext _normalizeNewlines(SourceSpanWithContext span) {
+ final text = span.text;
+ if (!text.contains('\r\n')) return span;
+
+ var endOffset = span.end.offset;
+ for (var i = 0; i < text.length - 1; i++) {
+ if (text.codeUnitAt(i) == $cr && text.codeUnitAt(i + 1) == $lf) {
+ endOffset--;
+ }
+ }
+
+ return SourceSpanWithContext(
+ span.start,
+ SourceLocation(endOffset,
+ sourceUrl: span.sourceUrl,
+ line: span.end.line,
+ column: span.end.column),
+ text.replaceAll('\r\n', '\n'),
+ span.context.replaceAll('\r\n', '\n'));
+ }
+
+ /// Normalizes [span] to remove a trailing newline from `span.context`.
+ ///
+ /// If necessary, also adjust `span.end` so that it doesn't point past where
+ /// the trailing newline used to be.
+ static SourceSpanWithContext _normalizeTrailingNewline(
+ SourceSpanWithContext span) {
+ if (!span.context.endsWith('\n')) return span;
+
+ // If there's a full blank line on the end of [span.context], it's probably
+ // significant, so we shouldn't trim it.
+ if (span.text.endsWith('\n\n')) return span;
+
+ final context = span.context.substring(0, span.context.length - 1);
+ var text = span.text;
+ var start = span.start;
+ var end = span.end;
+ if (span.text.endsWith('\n') && _isTextAtEndOfContext(span)) {
+ text = span.text.substring(0, span.text.length - 1);
+ if (text.isEmpty) {
+ end = start;
+ } else {
+ end = SourceLocation(span.end.offset - 1,
+ sourceUrl: span.sourceUrl,
+ line: span.end.line - 1,
+ column: _lastLineLength(context));
+ start = span.start.offset == span.end.offset ? end : span.start;
+ }
+ }
+ return SourceSpanWithContext(start, end, text, context);
+ }
+
+ /// Normalizes [span] so that the end location is at the end of a line rather
+ /// than at the beginning of the next line.
+ static SourceSpanWithContext _normalizeEndOfLine(SourceSpanWithContext span) {
+ if (span.end.column != 0) return span;
+ if (span.end.line == span.start.line) return span;
+
+ final text = span.text.substring(0, span.text.length - 1);
+
+ return SourceSpanWithContext(
+ span.start,
+ SourceLocation(span.end.offset - 1,
+ sourceUrl: span.sourceUrl,
+ line: span.end.line - 1,
+ column: text.length - text.lastIndexOf('\n') - 1),
+ text,
+ // If the context also ends with a newline, it's possible that we don't
+ // have the full context for that line, so we shouldn't print it at all.
+ span.context.endsWith('\n')
+ ? span.context.substring(0, span.context.length - 1)
+ : span.context);
+ }
+
+ /// Returns the length of the last line in [text], whether or not it ends in a
+ /// newline.
+ static int _lastLineLength(String text) {
+ if (text.isEmpty) {
+ return 0;
+ } else if (text.codeUnitAt(text.length - 1) == $lf) {
+ return text.length == 1
+ ? 0
+ : text.length - text.lastIndexOf('\n', text.length - 2) - 1;
+ } else {
+ return text.length - text.lastIndexOf('\n') - 1;
+ }
+ }
+
+ /// Returns whether [span]'s text runs all the way to the end of its context.
+ static bool _isTextAtEndOfContext(SourceSpanWithContext span) =>
+ findLineStart(span.context, span.text, span.start.column)! +
+ span.start.column +
+ span.length ==
+ span.context.length;
+
+ @override
+ String toString() {
+ final buffer = StringBuffer();
+ if (isPrimary) buffer.write('primary ');
+ buffer.write('${span.start.line}:${span.start.column}-'
+ '${span.end.line}:${span.end.column}');
+ if (label != null) buffer.write(' ($label)');
+ return buffer.toString();
+ }
+}
+
+/// A single line of the source file being highlighted.
+class _Line {
+ /// The text of the line, not including the trailing newline.
+ final String text;
+
+ /// The 0-based line number in the source file.
+ final int number;
+
+ /// The URL of the source file in which this line appears.
+ ///
+ /// For lines created from spans without an explicit URL, this is an opaque
+ /// object that differs between lines that come from different spans.
+ final Object url;
+
+ /// All highlights that cover any portion of this line, in source span order.
+ ///
+ /// This is populated after the initial line is created.
+ final highlights = <_Highlight>[];
+
+ _Line(this.text, this.number, this.url);
+
+ @override
+ String toString() => '$number: "$text" (${highlights.join(', ')})';
+}
diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart
new file mode 100644
index 0000000..8f22d7b
--- /dev/null
+++ b/pkgs/source_span/lib/src/location.dart
@@ -0,0 +1,102 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'span.dart';
+
+// TODO(nweiz): Use SourceLocationMixin once we decide to cut a release with
+// breaking changes. See SourceLocationMixin for details.
+
+/// A class that describes a single location within a source file.
+///
+/// This class should not be extended. Instead, [SourceLocationBase] should be
+/// extended instead.
+class SourceLocation implements Comparable<SourceLocation> {
+ /// URL of the source containing this location.
+ ///
+ /// This may be null, indicating that the source URL is unknown or
+ /// unavailable.
+ final Uri? sourceUrl;
+
+ /// The 0-based offset of this location in the source.
+ final int offset;
+
+ /// The 0-based line of this location in the source.
+ final int line;
+
+ /// The 0-based column of this location in the source
+ final int column;
+
+ /// Returns a representation of this location in the `source:line:column`
+ /// format used by text editors.
+ ///
+ /// This prints 1-based lines and columns.
+ String get toolString {
+ final source = sourceUrl ?? 'unknown source';
+ return '$source:${line + 1}:${column + 1}';
+ }
+
+ /// Creates a new location indicating [offset] within [sourceUrl].
+ ///
+ /// [line] and [column] default to assuming the source is a single line. This
+ /// means that [line] defaults to 0 and [column] defaults to [offset].
+ ///
+ /// [sourceUrl] may be either a [String], a [Uri], or `null`.
+ SourceLocation(this.offset, {Object? sourceUrl, int? line, int? column})
+ : sourceUrl =
+ sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri?,
+ line = line ?? 0,
+ column = column ?? offset {
+ if (offset < 0) {
+ throw RangeError('Offset may not be negative, was $offset.');
+ } else if (line != null && line < 0) {
+ throw RangeError('Line may not be negative, was $line.');
+ } else if (column != null && column < 0) {
+ throw RangeError('Column may not be negative, was $column.');
+ }
+ }
+
+ /// Returns the distance in characters between `this` and [other].
+ ///
+ /// This always returns a non-negative value.
+ int distance(SourceLocation other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw ArgumentError('Source URLs "$sourceUrl" and '
+ "\"${other.sourceUrl}\" don't match.");
+ }
+ return (offset - other.offset).abs();
+ }
+
+ /// Returns a span that covers only a single point: this location.
+ SourceSpan pointSpan() => SourceSpan(this, this, '');
+
+ /// Compares two locations.
+ ///
+ /// [other] must have the same source URL as `this`.
+ @override
+ int compareTo(SourceLocation other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw ArgumentError('Source URLs "$sourceUrl" and '
+ "\"${other.sourceUrl}\" don't match.");
+ }
+ return offset - other.offset;
+ }
+
+ @override
+ bool operator ==(Object other) =>
+ other is SourceLocation &&
+ sourceUrl == other.sourceUrl &&
+ offset == other.offset;
+
+ @override
+ int get hashCode => (sourceUrl?.hashCode ?? 0) + offset;
+
+ @override
+ String toString() => '<$runtimeType: $offset $toolString>';
+}
+
+/// A base class for source locations with [offset], [line], and [column] known
+/// at construction time.
+class SourceLocationBase extends SourceLocation {
+ SourceLocationBase(super.offset, {super.sourceUrl, super.line, super.column});
+}
diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart
new file mode 100644
index 0000000..a44f5e2
--- /dev/null
+++ b/pkgs/source_span/lib/src/location_mixin.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'location.dart';
+import 'span.dart';
+
+// Note: this class duplicates a lot of functionality of [SourceLocation]. This
+// is because in order for SourceLocation to use SourceLocationMixin,
+// SourceLocationMixin couldn't implement SourceLocation. In SourceSpan we
+// handle this by making the class itself non-extensible, but that would be a
+// breaking change for SourceLocation. So until we want to endure the pain of
+// cutting a release with breaking changes, we duplicate the code here.
+
+/// A mixin for easily implementing [SourceLocation].
+abstract class SourceLocationMixin implements SourceLocation {
+ @override
+ String get toolString {
+ final source = sourceUrl ?? 'unknown source';
+ return '$source:${line + 1}:${column + 1}';
+ }
+
+ @override
+ int distance(SourceLocation other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw ArgumentError('Source URLs "$sourceUrl" and '
+ "\"${other.sourceUrl}\" don't match.");
+ }
+ return (offset - other.offset).abs();
+ }
+
+ @override
+ SourceSpan pointSpan() => SourceSpan(this, this, '');
+
+ @override
+ int compareTo(SourceLocation other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw ArgumentError('Source URLs "$sourceUrl" and '
+ "\"${other.sourceUrl}\" don't match.");
+ }
+ return offset - other.offset;
+ }
+
+ @override
+ bool operator ==(Object other) =>
+ other is SourceLocation &&
+ sourceUrl == other.sourceUrl &&
+ offset == other.offset;
+
+ @override
+ int get hashCode => (sourceUrl?.hashCode ?? 0) + offset;
+
+ @override
+ String toString() => '<$runtimeType: $offset $toolString>';
+}
diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart
new file mode 100644
index 0000000..941dedc
--- /dev/null
+++ b/pkgs/source_span/lib/src/span.dart
@@ -0,0 +1,193 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:path/path.dart' as p;
+import 'package:term_glyph/term_glyph.dart' as glyph;
+
+import 'file.dart';
+import 'highlighter.dart';
+import 'location.dart';
+import 'span_mixin.dart';
+import 'span_with_context.dart';
+import 'utils.dart';
+
+/// A class that describes a segment of source text.
+abstract class SourceSpan implements Comparable<SourceSpan> {
+ /// The start location of this span.
+ SourceLocation get start;
+
+ /// The end location of this span, exclusive.
+ SourceLocation get end;
+
+ /// The source text for this span.
+ String get text;
+
+ /// The URL of the source (typically a file) of this span.
+ ///
+ /// This may be null, indicating that the source URL is unknown or
+ /// unavailable.
+ Uri? get sourceUrl;
+
+ /// The length of this span, in characters.
+ int get length;
+
+ /// Creates a new span from [start] to [end] (exclusive) containing [text].
+ ///
+ /// [start] and [end] must have the same source URL and [start] must come
+ /// before [end]. [text] must have a number of characters equal to the
+ /// distance between [start] and [end].
+ factory SourceSpan(SourceLocation start, SourceLocation end, String text) =>
+ SourceSpanBase(start, end, text);
+
+ /// Creates a new span that's the union of `this` and [other].
+ ///
+ /// The two spans must have the same source URL and may not be disjoint.
+ /// [text] is computed by combining `this.text` and `other.text`.
+ SourceSpan union(SourceSpan other);
+
+ /// Compares two spans.
+ ///
+ /// [other] must have the same source URL as `this`. This orders spans by
+ /// [start] then [length].
+ @override
+ int compareTo(SourceSpan other);
+
+ /// Formats [message] in a human-friendly way associated with this span.
+ ///
+ /// [color] may either be a [String], a [bool], or `null`. If it's a string,
+ /// it indicates an [ANSI terminal color escape][] that should
+ /// be used to highlight the span's text (for example, `"\u001b[31m"` will
+ /// color red). If it's `true`, it indicates that the text should be
+ /// highlighted using the default color. If it's `false` or `null`, it
+ /// indicates that the text shouldn't be highlighted.
+ ///
+ /// This uses the full range of Unicode characters to highlight the source
+ /// span if [glyph.ascii] is `false` (the default), but only uses ASCII
+ /// characters if it's `true`.
+ ///
+ /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+ String message(String message, {Object? color});
+
+ /// Prints the text associated with this span in a user-friendly way.
+ ///
+ /// This is identical to [message], except that it doesn't print the file
+ /// name, line number, column number, or message. If [length] is 0 and this
+ /// isn't a [SourceSpanWithContext], returns an empty string.
+ ///
+ /// [color] may either be a [String], a [bool], or `null`. If it's a string,
+ /// it indicates an [ANSI terminal color escape][] that should
+ /// be used to highlight the span's text (for example, `"\u001b[31m"` will
+ /// color red). If it's `true`, it indicates that the text should be
+ /// highlighted using the default color. If it's `false` or `null`, it
+ /// indicates that the text shouldn't be highlighted.
+ ///
+ /// This uses the full range of Unicode characters to highlight the source
+ /// span if [glyph.ascii] is `false` (the default), but only uses ASCII
+ /// characters if it's `true`.
+ ///
+ /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+ String highlight({Object? color});
+}
+
+/// A base class for source spans with [start], [end], and [text] known at
+/// construction time.
+class SourceSpanBase extends SourceSpanMixin {
+ @override
+ final SourceLocation start;
+ @override
+ final SourceLocation end;
+ @override
+ final String text;
+
+ SourceSpanBase(this.start, this.end, this.text) {
+ if (end.sourceUrl != start.sourceUrl) {
+ throw ArgumentError('Source URLs "${start.sourceUrl}" and '
+ " \"${end.sourceUrl}\" don't match.");
+ } else if (end.offset < start.offset) {
+ throw ArgumentError('End $end must come after start $start.');
+ } else if (text.length != start.distance(end)) {
+ throw ArgumentError('Text "$text" must be ${start.distance(end)} '
+ 'characters long.');
+ }
+ }
+}
+
+// TODO(#52): Move these to instance methods in the next breaking release.
+/// Extension methods on the base [SourceSpan] API.
+extension SourceSpanExtension on SourceSpan {
+ /// Like [SourceSpan.message], but also highlights [secondarySpans] to provide
+ /// the user with additional context.
+ ///
+ /// Each span takes a label ([label] for this span, and the values of the
+ /// [secondarySpans] map for the secondary spans) that's used to indicate to
+ /// the user what that particular span represents.
+ ///
+ /// If [color] is `true`, [ANSI terminal color escapes][] are used to color
+ /// the resulting string. By default this span is colored red and the
+ /// secondary spans are colored blue, but that can be customized by passing
+ /// ANSI escape strings to [primaryColor] or [secondaryColor].
+ ///
+ /// [ANSI terminal color escapes]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+ ///
+ /// Each span in [secondarySpans] must refer to the same document as this
+ /// span. Throws an [ArgumentError] if any secondary span has a different
+ /// source URL than this span.
+ ///
+ /// Note that while this will work with plain [SourceSpan]s, it will produce
+ /// much more useful output with [SourceSpanWithContext]s (including
+ /// [FileSpan]s).
+ String messageMultiple(
+ String message, String label, Map<SourceSpan, String> secondarySpans,
+ {bool color = false, String? primaryColor, String? secondaryColor}) {
+ final buffer = StringBuffer()
+ ..write('line ${start.line + 1}, column ${start.column + 1}');
+ if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}');
+ buffer
+ ..writeln(': $message')
+ ..write(highlightMultiple(label, secondarySpans,
+ color: color,
+ primaryColor: primaryColor,
+ secondaryColor: secondaryColor));
+ return buffer.toString();
+ }
+
+ /// Like [SourceSpan.highlight], but also highlights [secondarySpans] to
+ /// provide the user with additional context.
+ ///
+ /// Each span takes a label ([label] for this span, and the values of the
+ /// [secondarySpans] map for the secondary spans) that's used to indicate to
+ /// the user what that particular span represents.
+ ///
+ /// If [color] is `true`, [ANSI terminal color escapes][] are used to color
+ /// the resulting string. By default this span is colored red and the
+ /// secondary spans are colored blue, but that can be customized by passing
+ /// ANSI escape strings to [primaryColor] or [secondaryColor].
+ ///
+ /// [ANSI terminal color escapes]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
+ ///
+ /// Each span in [secondarySpans] must refer to the same document as this
+ /// span. Throws an [ArgumentError] if any secondary span has a different
+ /// source URL than this span.
+ ///
+ /// Note that while this will work with plain [SourceSpan]s, it will produce
+ /// much more useful output with [SourceSpanWithContext]s (including
+ /// [FileSpan]s).
+ String highlightMultiple(String label, Map<SourceSpan, String> secondarySpans,
+ {bool color = false, String? primaryColor, String? secondaryColor}) =>
+ Highlighter.multiple(this, label, secondarySpans,
+ color: color,
+ primaryColor: primaryColor,
+ secondaryColor: secondaryColor)
+ .highlight();
+
+ /// Returns a span from [start] code units (inclusive) to [end] code units
+ /// (exclusive) after the beginning of this span.
+ SourceSpan subspan(int start, [int? end]) {
+ RangeError.checkValidRange(start, end, length);
+ if (start == 0 && (end == null || end == length)) return this;
+
+ final locations = subspanLocations(this, start, end);
+ return SourceSpan(locations[0], locations[1], text.substring(start, end));
+ }
+}
diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart
new file mode 100644
index 0000000..90ad690
--- /dev/null
+++ b/pkgs/source_span/lib/src/span_exception.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'span.dart';
+
+/// A class for exceptions that have source span information attached.
+class SourceSpanException implements Exception {
+ // This is a getter so that subclasses can override it.
+ /// A message describing the exception.
+ String get message => _message;
+ final String _message;
+
+ // This is a getter so that subclasses can override it.
+ /// The span associated with this exception.
+ ///
+ /// This may be `null` if the source location can't be determined.
+ SourceSpan? get span => _span;
+ final SourceSpan? _span;
+
+ SourceSpanException(this._message, this._span);
+
+ /// Returns a string representation of `this`.
+ ///
+ /// [color] may either be a [String], a [bool], or `null`. If it's a string,
+ /// it indicates an ANSI terminal color escape that should be used to
+ /// highlight the span's text. If it's `true`, it indicates that the text
+ /// should be highlighted using the default color. If it's `false` or `null`,
+ /// it indicates that the text shouldn't be highlighted.
+ @override
+ String toString({Object? color}) {
+ if (span == null) return message;
+ return 'Error on ${span!.message(message, color: color)}';
+ }
+}
+
+/// A [SourceSpanException] that's also a [FormatException].
+class SourceSpanFormatException extends SourceSpanException
+ implements FormatException {
+ @override
+ final dynamic source;
+
+ @override
+ int? get offset => span?.start.offset;
+
+ SourceSpanFormatException(super.message, super.span, [this.source]);
+}
+
+/// A [SourceSpanException] that also highlights some secondary spans to provide
+/// the user with extra context.
+///
+/// Each span has a label ([primaryLabel] for the primary, and the values of the
+/// [secondarySpans] map for the secondary spans) that's used to indicate to the
+/// user what that particular span represents.
+class MultiSourceSpanException extends SourceSpanException {
+ /// A label to attach to [span] that provides additional information and helps
+ /// distinguish it from [secondarySpans].
+ final String primaryLabel;
+
+ /// A map whose keys are secondary spans that should be highlighted.
+ ///
+ /// Each span's value is a label to attach to that span that provides
+ /// additional information and helps distinguish it from [secondarySpans].
+ final Map<SourceSpan, String> secondarySpans;
+
+ MultiSourceSpanException(super.message, super.span, this.primaryLabel,
+ Map<SourceSpan, String> secondarySpans)
+ : secondarySpans = Map.unmodifiable(secondarySpans);
+
+ /// Returns a string representation of `this`.
+ ///
+ /// [color] may either be a [String], a [bool], or `null`. If it's a string,
+ /// it indicates an ANSI terminal color escape that should be used to
+ /// highlight the primary span's text. If it's `true`, it indicates that the
+ /// text should be highlighted using the default color. If it's `false` or
+ /// `null`, it indicates that the text shouldn't be highlighted.
+ ///
+ /// If [color] is `true` or a string, [secondaryColor] is used to highlight
+ /// [secondarySpans].
+ @override
+ String toString({Object? color, String? secondaryColor}) {
+ if (span == null) return message;
+
+ var useColor = false;
+ String? primaryColor;
+ if (color is String) {
+ useColor = true;
+ primaryColor = color;
+ } else if (color == true) {
+ useColor = true;
+ }
+
+ final formatted = span!.messageMultiple(
+ message, primaryLabel, secondarySpans,
+ color: useColor,
+ primaryColor: primaryColor,
+ secondaryColor: secondaryColor);
+ return 'Error on $formatted';
+ }
+}
+
+/// A [MultiSourceSpanException] that's also a [FormatException].
+class MultiSourceSpanFormatException extends MultiSourceSpanException
+ implements FormatException {
+ @override
+ final dynamic source;
+
+ @override
+ int? get offset => span?.start.offset;
+
+ MultiSourceSpanFormatException(
+ super.message, super.span, super.primaryLabel, super.secondarySpans,
+ [this.source]);
+}
diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart
new file mode 100644
index 0000000..29b6119
--- /dev/null
+++ b/pkgs/source_span/lib/src/span_mixin.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:path/path.dart' as p;
+
+import 'highlighter.dart';
+import 'span.dart';
+import 'span_with_context.dart';
+import 'utils.dart';
+
+/// A mixin for easily implementing [SourceSpan].
+///
+/// This implements the [SourceSpan] methods in terms of [start], [end], and
+/// [text]. This assumes that [start] and [end] have the same source URL, that
+/// [start] comes before [end], and that [text] has a number of characters equal
+/// to the distance between [start] and [end].
+abstract class SourceSpanMixin implements SourceSpan {
+ @override
+ Uri? get sourceUrl => start.sourceUrl;
+
+ @override
+ int get length => end.offset - start.offset;
+
+ @override
+ int compareTo(SourceSpan other) {
+ final result = start.compareTo(other.start);
+ return result == 0 ? end.compareTo(other.end) : result;
+ }
+
+ @override
+ SourceSpan union(SourceSpan other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw ArgumentError('Source URLs "$sourceUrl" and '
+ " \"${other.sourceUrl}\" don't match.");
+ }
+
+ final start = min(this.start, other.start);
+ final end = max(this.end, other.end);
+ final beginSpan = start == this.start ? this : other;
+ final endSpan = end == this.end ? this : other;
+
+ if (beginSpan.end.compareTo(endSpan.start) < 0) {
+ throw ArgumentError('Spans $this and $other are disjoint.');
+ }
+
+ final text = beginSpan.text +
+ endSpan.text.substring(beginSpan.end.distance(endSpan.start));
+ return SourceSpan(start, end, text);
+ }
+
+ @override
+ String message(String message, {Object? color}) {
+ final buffer = StringBuffer()
+ ..write('line ${start.line + 1}, column ${start.column + 1}');
+ if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}');
+ buffer.write(': $message');
+
+ final highlight = this.highlight(color: color);
+ if (highlight.isNotEmpty) {
+ buffer
+ ..writeln()
+ ..write(highlight);
+ }
+
+ return buffer.toString();
+ }
+
+ @override
+ String highlight({Object? color}) {
+ if (this is! SourceSpanWithContext && length == 0) return '';
+ return Highlighter(this, color: color).highlight();
+ }
+
+ @override
+ bool operator ==(Object other) =>
+ other is SourceSpan && start == other.start && end == other.end;
+
+ @override
+ int get hashCode => Object.hash(start, end);
+
+ @override
+ String toString() => '<$runtimeType: from $start to $end "$text">';
+}
diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart
new file mode 100644
index 0000000..776c789
--- /dev/null
+++ b/pkgs/source_span/lib/src/span_with_context.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'location.dart';
+import 'span.dart';
+import 'utils.dart';
+
+/// A class that describes a segment of source text with additional context.
+class SourceSpanWithContext extends SourceSpanBase {
+ // This is a getter so that subclasses can override it.
+ /// Text around the span, which includes the line containing this span.
+ String get context => _context;
+ final String _context;
+
+ /// Creates a new span from [start] to [end] (exclusive) containing [text], in
+ /// the given [context].
+ ///
+ /// [start] and [end] must have the same source URL and [start] must come
+ /// before [end]. [text] must have a number of characters equal to the
+ /// distance between [start] and [end]. [context] must contain [text], and
+ /// [text] should start at `start.column` from the beginning of a line in
+ /// [context].
+ SourceSpanWithContext(
+ SourceLocation start, SourceLocation end, String text, this._context)
+ : super(start, end, text) {
+ if (!context.contains(text)) {
+ throw ArgumentError('The context line "$context" must contain "$text".');
+ }
+
+ if (findLineStart(context, text, start.column) == null) {
+ throw ArgumentError('The span text "$text" must start at '
+ 'column ${start.column + 1} in a line within "$context".');
+ }
+ }
+}
+
+// TODO(#52): Move these to instance methods in the next breaking release.
+/// Extension methods on the base [SourceSpan] API.
+extension SourceSpanWithContextExtension on SourceSpanWithContext {
+ /// Returns a span from [start] code units (inclusive) to [end] code units
+ /// (exclusive) after the beginning of this span.
+ SourceSpanWithContext subspan(int start, [int? end]) {
+ RangeError.checkValidRange(start, end, length);
+ if (start == 0 && (end == null || end == length)) return this;
+
+ final locations = subspanLocations(this, start, end);
+ return SourceSpanWithContext(
+ locations[0], locations[1], text.substring(start, end), context);
+ }
+}
diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart
new file mode 100644
index 0000000..aba14ec
--- /dev/null
+++ b/pkgs/source_span/lib/src/utils.dart
@@ -0,0 +1,145 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'charcode.dart';
+import 'location.dart';
+import 'span.dart';
+import 'span_with_context.dart';
+
+/// Returns the minimum of [obj1] and [obj2] according to
+/// [Comparable.compareTo].
+T min<T extends Comparable<T>>(T obj1, T obj2) =>
+ obj1.compareTo(obj2) > 0 ? obj2 : obj1;
+
+/// Returns the maximum of [obj1] and [obj2] according to
+/// [Comparable.compareTo].
+T max<T extends Comparable<T>>(T obj1, T obj2) =>
+ obj1.compareTo(obj2) > 0 ? obj1 : obj2;
+
+/// Returns whether all elements of [iter] are the same value, according to
+/// `==`.
+bool isAllTheSame(Iterable<Object?> iter) {
+ if (iter.isEmpty) return true;
+ final firstValue = iter.first;
+ for (var value in iter.skip(1)) {
+ if (value != firstValue) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/// Returns whether [span] covers multiple lines.
+bool isMultiline(SourceSpan span) => span.start.line != span.end.line;
+
+/// Sets the first `null` element of [list] to [element].
+void replaceFirstNull<E>(List<E?> list, E element) {
+ final index = list.indexOf(null);
+ if (index < 0) throw ArgumentError('$list contains no null elements.');
+ list[index] = element;
+}
+
+/// Sets the element of [list] that currently contains [element] to `null`.
+void replaceWithNull<E>(List<E?> list, E element) {
+ final index = list.indexOf(element);
+ if (index < 0) {
+ throw ArgumentError('$list contains no elements matching $element.');
+ }
+
+ list[index] = null;
+}
+
+/// Returns the number of instances of [codeUnit] in [string].
+int countCodeUnits(String string, int codeUnit) {
+ var count = 0;
+ for (var codeUnitToCheck in string.codeUnits) {
+ if (codeUnitToCheck == codeUnit) count++;
+ }
+ return count;
+}
+
+/// Finds a line in [context] containing [text] at the specified [column].
+///
+/// Returns the index in [context] where that line begins, or null if none
+/// exists.
+int? findLineStart(String context, String text, int column) {
+ // If the text is empty, we just want to find the first line that has at least
+ // [column] characters.
+ if (text.isEmpty) {
+ var beginningOfLine = 0;
+ while (true) {
+ final index = context.indexOf('\n', beginningOfLine);
+ if (index == -1) {
+ return context.length - beginningOfLine >= column
+ ? beginningOfLine
+ : null;
+ }
+
+ if (index - beginningOfLine >= column) return beginningOfLine;
+ beginningOfLine = index + 1;
+ }
+ }
+
+ var index = context.indexOf(text);
+ while (index != -1) {
+ // Start looking before [index] in case [text] starts with a newline.
+ final lineStart = index == 0 ? 0 : context.lastIndexOf('\n', index - 1) + 1;
+ final textColumn = index - lineStart;
+ if (column == textColumn) return lineStart;
+ index = context.indexOf(text, index + 1);
+ }
+ // ignore: avoid_returning_null
+ return null;
+}
+
+/// Returns a two-element list containing the start and end locations of the
+/// span from [start] code units (inclusive) to [end] code units (exclusive)
+/// after the beginning of [span].
+///
+/// This is factored out so it can be shared between
+/// [SourceSpanExtension.subspan] and [SourceSpanWithContextExtension.subspan].
+List<SourceLocation> subspanLocations(SourceSpan span, int start, [int? end]) {
+ final text = span.text;
+ final startLocation = span.start;
+ var line = startLocation.line;
+ var column = startLocation.column;
+
+ // Adjust [line] and [column] as necessary if the character at [i] in [text]
+ // is a newline.
+ void consumeCodePoint(int i) {
+ final codeUnit = text.codeUnitAt(i);
+ if (codeUnit == $lf ||
+ // A carriage return counts as a newline, but only if it's not
+ // followed by a line feed.
+ (codeUnit == $cr &&
+ (i + 1 == text.length || text.codeUnitAt(i + 1) != $lf))) {
+ line += 1;
+ column = 0;
+ } else {
+ column += 1;
+ }
+ }
+
+ for (var i = 0; i < start; i++) {
+ consumeCodePoint(i);
+ }
+
+ final newStartLocation = SourceLocation(startLocation.offset + start,
+ sourceUrl: span.sourceUrl, line: line, column: column);
+
+ SourceLocation newEndLocation;
+ if (end == null || end == span.length) {
+ newEndLocation = span.end;
+ } else if (end == start) {
+ newEndLocation = newStartLocation;
+ } else {
+ for (var i = start; i < end; i++) {
+ consumeCodePoint(i);
+ }
+ newEndLocation = SourceLocation(startLocation.offset + end,
+ sourceUrl: span.sourceUrl, line: line, column: column);
+ }
+
+ return [newStartLocation, newEndLocation];
+}
diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml
new file mode 100644
index 0000000..8757b2d
--- /dev/null
+++ b/pkgs/source_span/pubspec.yaml
@@ -0,0 +1,17 @@
+name: source_span
+version: 1.10.1
+description: >-
+ Provides a standard representation for source code locations and spans.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/source_span
+
+environment:
+ sdk: ^3.1.0
+
+dependencies:
+ collection: ^1.15.0
+ path: ^1.8.0
+ term_glyph: ^1.2.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.0
diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart
new file mode 100644
index 0000000..dff51ee
--- /dev/null
+++ b/pkgs/source_span/test/file_test.dart
@@ -0,0 +1,530 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+import 'package:test/test.dart';
+
+void main() {
+ late SourceFile file;
+ setUp(() {
+ file = SourceFile.fromString('''
+foo bar baz
+whiz bang boom
+zip zap zop''', url: 'foo.dart');
+ });
+
+ group('errors', () {
+ group('for span()', () {
+ test('end must come after start', () {
+ expect(() => file.span(10, 5), throwsArgumentError);
+ });
+
+ test('start may not be negative', () {
+ expect(() => file.span(-1, 5), throwsRangeError);
+ });
+
+ test('end may not be outside the file', () {
+ expect(() => file.span(10, 100), throwsRangeError);
+ });
+ });
+
+ group('for location()', () {
+ test('offset may not be negative', () {
+ expect(() => file.location(-1), throwsRangeError);
+ });
+
+ test('offset may not be outside the file', () {
+ expect(() => file.location(100), throwsRangeError);
+ });
+ });
+
+ group('for getLine()', () {
+ test('offset may not be negative', () {
+ expect(() => file.getLine(-1), throwsRangeError);
+ });
+
+ test('offset may not be outside the file', () {
+ expect(() => file.getLine(100), throwsRangeError);
+ });
+ });
+
+ group('for getColumn()', () {
+ test('offset may not be negative', () {
+ expect(() => file.getColumn(-1), throwsRangeError);
+ });
+
+ test('offset may not be outside the file', () {
+ expect(() => file.getColumn(100), throwsRangeError);
+ });
+
+ test('line may not be negative', () {
+ expect(() => file.getColumn(1, line: -1), throwsRangeError);
+ });
+
+ test('line may not be outside the file', () {
+ expect(() => file.getColumn(1, line: 100), throwsRangeError);
+ });
+
+ test('line must be accurate', () {
+ expect(() => file.getColumn(1, line: 1), throwsRangeError);
+ });
+ });
+
+ group('getOffset()', () {
+ test('line may not be negative', () {
+ expect(() => file.getOffset(-1), throwsRangeError);
+ });
+
+ test('column may not be negative', () {
+ expect(() => file.getOffset(1, -1), throwsRangeError);
+ });
+
+ test('line may not be outside the file', () {
+ expect(() => file.getOffset(100), throwsRangeError);
+ });
+
+ test('column may not be outside the file', () {
+ expect(() => file.getOffset(2, 100), throwsRangeError);
+ });
+
+ test('column may not be outside the line', () {
+ expect(() => file.getOffset(1, 20), throwsRangeError);
+ });
+ });
+
+ group('for getText()', () {
+ test('end must come after start', () {
+ expect(() => file.getText(10, 5), throwsArgumentError);
+ });
+
+ test('start may not be negative', () {
+ expect(() => file.getText(-1, 5), throwsRangeError);
+ });
+
+ test('end may not be outside the file', () {
+ expect(() => file.getText(10, 100), throwsRangeError);
+ });
+ });
+
+ group('for span().union()', () {
+ test('source URLs must match', () {
+ final other = SourceSpan(SourceLocation(10), SourceLocation(11), '_');
+
+ expect(() => file.span(9, 10).union(other), throwsArgumentError);
+ });
+
+ test('spans may not be disjoint', () {
+ expect(() => file.span(9, 10).union(file.span(11, 12)),
+ throwsArgumentError);
+ });
+ });
+
+ test('for span().expand() source URLs must match', () {
+ final other = SourceFile.fromString('''
+foo bar baz
+whiz bang boom
+zip zap zop''', url: 'bar.dart').span(10, 11);
+
+ expect(() => file.span(9, 10).expand(other), throwsArgumentError);
+ });
+ });
+
+ test('fields work correctly', () {
+ expect(file.url, equals(Uri.parse('foo.dart')));
+ expect(file.lines, equals(3));
+ expect(file.length, equals(38));
+ });
+
+ group('new SourceFile()', () {
+ test('handles CRLF correctly', () {
+ expect(SourceFile.fromString('foo\r\nbar').getLine(6), equals(1));
+ });
+
+ test('handles a lone CR correctly', () {
+ expect(SourceFile.fromString('foo\rbar').getLine(5), equals(1));
+ });
+ });
+
+ group('span()', () {
+ test('returns a span between the given offsets', () {
+ final span = file.span(5, 10);
+ expect(span.start, equals(file.location(5)));
+ expect(span.end, equals(file.location(10)));
+ });
+
+ test('end defaults to the end of the file', () {
+ final span = file.span(5);
+ expect(span.start, equals(file.location(5)));
+ expect(span.end, equals(file.location(file.length)));
+ });
+ });
+
+ group('getLine()', () {
+ test('works for a middle character on the line', () {
+ expect(file.getLine(15), equals(1));
+ });
+
+ test('works for the first character of a line', () {
+ expect(file.getLine(12), equals(1));
+ });
+
+ test('works for a newline character', () {
+ expect(file.getLine(11), equals(0));
+ });
+
+ test('works for the last offset', () {
+ expect(file.getLine(file.length), equals(2));
+ });
+ });
+
+ group('getColumn()', () {
+ test('works for a middle character on the line', () {
+ expect(file.getColumn(15), equals(3));
+ });
+
+ test('works for the first character of a line', () {
+ expect(file.getColumn(12), equals(0));
+ });
+
+ test('works for a newline character', () {
+ expect(file.getColumn(11), equals(11));
+ });
+
+ test('works when line is passed as well', () {
+ expect(file.getColumn(12, line: 1), equals(0));
+ });
+
+ test('works for the last offset', () {
+ expect(file.getColumn(file.length), equals(11));
+ });
+ });
+
+ group('getOffset()', () {
+ test('works for a middle character on the line', () {
+ expect(file.getOffset(1, 3), equals(15));
+ });
+
+ test('works for the first character of a line', () {
+ expect(file.getOffset(1), equals(12));
+ });
+
+ test('works for a newline character', () {
+ expect(file.getOffset(0, 11), equals(11));
+ });
+
+ test('works for the last offset', () {
+ expect(file.getOffset(2, 11), equals(file.length));
+ });
+ });
+
+ group('getText()', () {
+ test('returns a substring of the source', () {
+ expect(file.getText(8, 15), equals('baz\nwhi'));
+ });
+
+ test('end defaults to the end of the file', () {
+ expect(file.getText(20), equals('g boom\nzip zap zop'));
+ });
+ });
+
+ group('FileLocation', () {
+ test('reports the correct line number', () {
+ expect(file.location(15).line, equals(1));
+ });
+
+ test('reports the correct column number', () {
+ expect(file.location(15).column, equals(3));
+ });
+
+ test('pointSpan() returns a FileSpan', () {
+ final location = file.location(15);
+ final span = location.pointSpan();
+ expect(span, isA<FileSpan>());
+ expect(span.start, equals(location));
+ expect(span.end, equals(location));
+ expect(span.text, isEmpty);
+ });
+ });
+
+ group('FileSpan', () {
+ test('text returns a substring of the source', () {
+ expect(file.span(8, 15).text, equals('baz\nwhi'));
+ });
+
+ test('text includes the last char when end is defaulted to EOF', () {
+ expect(file.span(29).text, equals('p zap zop'));
+ });
+
+ group('context', () {
+ test("contains the span's text", () {
+ final span = file.span(8, 15);
+ expect(span.context.contains(span.text), isTrue);
+ expect(span.context, equals('foo bar baz\nwhiz bang boom\n'));
+ });
+
+ test('contains the previous line for a point span at the end of a line',
+ () {
+ final span = file.span(25, 25);
+ expect(span.context, equals('whiz bang boom\n'));
+ });
+
+ test('contains the next line for a point span at the beginning of a line',
+ () {
+ final span = file.span(12, 12);
+ expect(span.context, equals('whiz bang boom\n'));
+ });
+
+ group('for a point span at the end of a file', () {
+ test('without a newline, contains the last line', () {
+ final span = file.span(file.length, file.length);
+ expect(span.context, equals('zip zap zop'));
+ });
+
+ test('with a newline, contains an empty line', () {
+ file = SourceFile.fromString('''
+foo bar baz
+whiz bang boom
+zip zap zop
+''', url: 'foo.dart');
+
+ final span = file.span(file.length, file.length);
+ expect(span.context, isEmpty);
+ });
+ });
+ });
+
+ group('union()', () {
+ late FileSpan span;
+ setUp(() {
+ span = file.span(5, 12);
+ });
+
+ test('works with a preceding adjacent span', () {
+ final other = file.span(0, 5);
+ final result = span.union(other);
+ expect(result.start, equals(other.start));
+ expect(result.end, equals(span.end));
+ expect(result.text, equals('foo bar baz\n'));
+ });
+
+ test('works with a preceding overlapping span', () {
+ final other = file.span(0, 8);
+ final result = span.union(other);
+ expect(result.start, equals(other.start));
+ expect(result.end, equals(span.end));
+ expect(result.text, equals('foo bar baz\n'));
+ });
+
+ test('works with a following adjacent span', () {
+ final other = file.span(12, 16);
+ final result = span.union(other);
+ expect(result.start, equals(span.start));
+ expect(result.end, equals(other.end));
+ expect(result.text, equals('ar baz\nwhiz'));
+ });
+
+ test('works with a following overlapping span', () {
+ final other = file.span(9, 16);
+ final result = span.union(other);
+ expect(result.start, equals(span.start));
+ expect(result.end, equals(other.end));
+ expect(result.text, equals('ar baz\nwhiz'));
+ });
+
+ test('works with an internal overlapping span', () {
+ final other = file.span(7, 10);
+ expect(span.union(other), equals(span));
+ });
+
+ test('works with an external overlapping span', () {
+ final other = file.span(0, 16);
+ expect(span.union(other), equals(other));
+ });
+
+ test('returns a FileSpan for a FileSpan input', () {
+ expect(span.union(file.span(0, 5)), isA<FileSpan>());
+ });
+
+ test('returns a base SourceSpan for a SourceSpan input', () {
+ final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'),
+ SourceLocation(5, sourceUrl: 'foo.dart'), 'hey, ');
+ final result = span.union(other);
+ expect(result, isNot(isA<FileSpan>()));
+ expect(result.start, equals(other.start));
+ expect(result.end, equals(span.end));
+ expect(result.text, equals('hey, ar baz\n'));
+ });
+ });
+
+ group('expand()', () {
+ late FileSpan span;
+ setUp(() {
+ span = file.span(5, 12);
+ });
+
+ test('works with a preceding nonadjacent span', () {
+ final other = file.span(0, 3);
+ final result = span.expand(other);
+ expect(result.start, equals(other.start));
+ expect(result.end, equals(span.end));
+ expect(result.text, equals('foo bar baz\n'));
+ });
+
+ test('works with a preceding overlapping span', () {
+ final other = file.span(0, 8);
+ final result = span.expand(other);
+ expect(result.start, equals(other.start));
+ expect(result.end, equals(span.end));
+ expect(result.text, equals('foo bar baz\n'));
+ });
+
+ test('works with a following nonadjacent span', () {
+ final other = file.span(14, 16);
+ final result = span.expand(other);
+ expect(result.start, equals(span.start));
+ expect(result.end, equals(other.end));
+ expect(result.text, equals('ar baz\nwhiz'));
+ });
+
+ test('works with a following overlapping span', () {
+ final other = file.span(9, 16);
+ final result = span.expand(other);
+ expect(result.start, equals(span.start));
+ expect(result.end, equals(other.end));
+ expect(result.text, equals('ar baz\nwhiz'));
+ });
+
+ test('works with an internal overlapping span', () {
+ final other = file.span(7, 10);
+ expect(span.expand(other), equals(span));
+ });
+
+ test('works with an external overlapping span', () {
+ final other = file.span(0, 16);
+ expect(span.expand(other), equals(other));
+ });
+ });
+
+ group('subspan()', () {
+ late FileSpan span;
+ setUp(() {
+ span = file.span(5, 11); // "ar baz"
+ });
+
+ group('errors', () {
+ test('start must be greater than zero', () {
+ expect(() => span.subspan(-1), throwsRangeError);
+ });
+
+ test('start must be less than or equal to length', () {
+ expect(() => span.subspan(span.length + 1), throwsRangeError);
+ });
+
+ test('end must be greater than start', () {
+ expect(() => span.subspan(2, 1), throwsRangeError);
+ });
+
+ test('end must be less than or equal to length', () {
+ expect(() => span.subspan(0, span.length + 1), throwsRangeError);
+ });
+ });
+
+ test('preserves the source URL', () {
+ final result = span.subspan(1, 2);
+ expect(result.start.sourceUrl, equals(span.sourceUrl));
+ expect(result.end.sourceUrl, equals(span.sourceUrl));
+ });
+
+ group('returns the original span', () {
+ test('with an implicit end',
+ () => expect(span.subspan(0), equals(span)));
+
+ test('with an explicit end',
+ () => expect(span.subspan(0, span.length), equals(span)));
+ });
+
+ group('within a single line', () {
+ test('returns a strict substring of the original span', () {
+ final result = span.subspan(1, 5);
+ expect(result.text, equals('r ba'));
+ expect(result.start.offset, equals(6));
+ expect(result.start.line, equals(0));
+ expect(result.start.column, equals(6));
+ expect(result.end.offset, equals(10));
+ expect(result.end.line, equals(0));
+ expect(result.end.column, equals(10));
+ });
+
+ test('an implicit end goes to the end of the original span', () {
+ final result = span.subspan(1);
+ expect(result.text, equals('r baz'));
+ expect(result.start.offset, equals(6));
+ expect(result.start.line, equals(0));
+ expect(result.start.column, equals(6));
+ expect(result.end.offset, equals(11));
+ expect(result.end.line, equals(0));
+ expect(result.end.column, equals(11));
+ });
+
+ test('can return an empty span', () {
+ final result = span.subspan(3, 3);
+ expect(result.text, isEmpty);
+ expect(result.start.offset, equals(8));
+ expect(result.start.line, equals(0));
+ expect(result.start.column, equals(8));
+ expect(result.end, equals(result.start));
+ });
+ });
+
+ group('across multiple lines', () {
+ setUp(() {
+ span = file.span(22, 30); // "boom\nzip"
+ });
+
+ test('with start and end in the middle of a line', () {
+ final result = span.subspan(3, 6);
+ expect(result.text, equals('m\nz'));
+ expect(result.start.offset, equals(25));
+ expect(result.start.line, equals(1));
+ expect(result.start.column, equals(13));
+ expect(result.end.offset, equals(28));
+ expect(result.end.line, equals(2));
+ expect(result.end.column, equals(1));
+ });
+
+ test('with start at the end of a line', () {
+ final result = span.subspan(4, 6);
+ expect(result.text, equals('\nz'));
+ expect(result.start.offset, equals(26));
+ expect(result.start.line, equals(1));
+ expect(result.start.column, equals(14));
+ });
+
+ test('with start at the beginning of a line', () {
+ final result = span.subspan(5, 6);
+ expect(result.text, equals('z'));
+ expect(result.start.offset, equals(27));
+ expect(result.start.line, equals(2));
+ expect(result.start.column, equals(0));
+ });
+
+ test('with end at the end of a line', () {
+ final result = span.subspan(3, 4);
+ expect(result.text, equals('m'));
+ expect(result.end.offset, equals(26));
+ expect(result.end.line, equals(1));
+ expect(result.end.column, equals(14));
+ });
+
+ test('with end at the beginning of a line', () {
+ final result = span.subspan(3, 5);
+ expect(result.text, equals('m\n'));
+ expect(result.end.offset, equals(27));
+ expect(result.end.line, equals(2));
+ expect(result.end.column, equals(0));
+ });
+ });
+ });
+ });
+}
diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart
new file mode 100644
index 0000000..93c42db
--- /dev/null
+++ b/pkgs/source_span/test/highlight_test.dart
@@ -0,0 +1,605 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: prefer_interpolation_to_compose_strings
+
+import 'package:source_span/source_span.dart';
+import 'package:source_span/src/colors.dart' as colors;
+import 'package:term_glyph/term_glyph.dart' as glyph;
+import 'package:test/test.dart';
+
+void main() {
+ late bool oldAscii;
+ setUpAll(() {
+ oldAscii = glyph.ascii;
+ glyph.ascii = true;
+ });
+
+ tearDownAll(() {
+ glyph.ascii = oldAscii;
+ });
+
+ late SourceFile file;
+ setUp(() {
+ file = SourceFile.fromString('''
+foo bar baz
+whiz bang boom
+zip zap zop
+''');
+ });
+
+ test('points to the span in the source', () {
+ expect(file.span(4, 7).highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^^^
+ '"""));
+ });
+
+ test('gracefully handles a missing source URL', () {
+ final span = SourceFile.fromString('foo bar baz').span(4, 7);
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^^^
+ '"""));
+ });
+
+ group('highlights a point span', () {
+ test('in the middle of a line', () {
+ expect(file.location(4).pointSpan().highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^
+ '"""));
+ });
+
+ test('at the beginning of the file', () {
+ expect(file.location(0).pointSpan().highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^
+ '"""));
+ });
+
+ test('at the beginning of a line', () {
+ expect(file.location(12).pointSpan().highlight(), equals("""
+ ,
+2 | whiz bang boom
+ | ^
+ '"""));
+ });
+
+ test('at the end of a line', () {
+ expect(file.location(11).pointSpan().highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^
+ '"""));
+ });
+
+ test('at the end of the file', () {
+ expect(file.location(38).pointSpan().highlight(), equals("""
+ ,
+3 | zip zap zop
+ | ^
+ '"""));
+ });
+
+ test('after the end of the file', () {
+ expect(file.location(39).pointSpan().highlight(), equals("""
+ ,
+4 |
+ | ^
+ '"""));
+ });
+
+ test('at the end of the file with no trailing newline', () {
+ file = SourceFile.fromString('zip zap zop');
+ expect(file.location(10).pointSpan().highlight(), equals("""
+ ,
+1 | zip zap zop
+ | ^
+ '"""));
+ });
+
+ test('after the end of the file with no trailing newline', () {
+ file = SourceFile.fromString('zip zap zop');
+ expect(file.location(11).pointSpan().highlight(), equals("""
+ ,
+1 | zip zap zop
+ | ^
+ '"""));
+ });
+
+ test('in an empty file', () {
+ expect(SourceFile.fromString('').location(0).pointSpan().highlight(),
+ equals("""
+ ,
+1 |
+ | ^
+ '"""));
+ });
+
+ test('on an empty line', () {
+ final file = SourceFile.fromString('foo\n\nbar');
+ expect(file.location(4).pointSpan().highlight(), equals("""
+ ,
+2 |
+ | ^
+ '"""));
+ });
+ });
+
+ test('highlights a single-line file without a newline', () {
+ expect(SourceFile.fromString('foo bar').span(0, 7).highlight(), equals("""
+ ,
+1 | foo bar
+ | ^^^^^^^
+ '"""));
+ });
+
+ test('highlights text including a trailing newline', () {
+ expect(file.span(8, 12).highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^^^
+ '"""));
+ });
+
+ test('highlights a single empty line', () {
+ expect(
+ SourceFile.fromString('foo\n\nbar').span(4, 5).highlight(), equals("""
+ ,
+2 |
+ | ^
+ '"""));
+ });
+
+ test('highlights a trailing newline', () {
+ expect(file.span(11, 12).highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^
+ '"""));
+ });
+
+ group('with a multiline span', () {
+ test('highlights the middle of the first and last lines', () {
+ expect(file.span(4, 34).highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+3 | | zip zap zop
+ | '-------^
+ '"""));
+ });
+
+ test('works when it begins at the end of a line', () {
+ expect(file.span(11, 34).highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,------------^
+2 | | whiz bang boom
+3 | | zip zap zop
+ | '-------^
+ '"""));
+ });
+
+ test('works when it ends at the beginning of a line', () {
+ expect(file.span(4, 28).highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+3 | | zip zap zop
+ | '-^
+ '"""));
+ });
+
+ test('highlights the full first line', () {
+ expect(file.span(0, 34).highlight(), equals("""
+ ,
+1 | / foo bar baz
+2 | | whiz bang boom
+3 | | zip zap zop
+ | '-------^
+ '"""));
+ });
+
+ test("highlights the full first line even if it's indented", () {
+ final file = SourceFile.fromString('''
+ foo bar baz
+ whiz bang boom
+ zip zap zop
+''');
+
+ expect(file.span(2, 38).highlight(), equals("""
+ ,
+1 | / foo bar baz
+2 | | whiz bang boom
+3 | | zip zap zop
+ | '-------^
+ '"""));
+ });
+
+ test("highlights the full first line if it's empty", () {
+ final file = SourceFile.fromString('''
+foo
+
+bar
+''');
+
+ expect(file.span(4, 9).highlight(), equals(r"""
+ ,
+2 | /
+3 | \ bar
+ '"""));
+ });
+
+ test('highlights the full last line', () {
+ expect(file.span(4, 27).highlight(), equals(r"""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | \ whiz bang boom
+ '"""));
+ });
+
+ test('highlights the full last line with no trailing newline', () {
+ expect(file.span(4, 26).highlight(), equals(r"""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | \ whiz bang boom
+ '"""));
+ });
+
+ test('highlights the full last line with a trailing Windows newline', () {
+ final file = SourceFile.fromString('''
+foo bar baz\r
+whiz bang boom\r
+zip zap zop\r
+''');
+
+ expect(file.span(4, 29).highlight(), equals(r"""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | \ whiz bang boom
+ '"""));
+ });
+
+ test('highlights the full last line at the end of the file', () {
+ expect(file.span(4, 39).highlight(), equals(r"""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+3 | \ zip zap zop
+ '"""));
+ });
+
+ test(
+ 'highlights the full last line at the end of the file with no trailing '
+ 'newline', () {
+ final file = SourceFile.fromString('''
+foo bar baz
+whiz bang boom
+zip zap zop''');
+
+ expect(file.span(4, 38).highlight(), equals(r"""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+3 | \ zip zap zop
+ '"""));
+ });
+
+ test("highlights the full last line if it's empty", () {
+ final file = SourceFile.fromString('''
+foo
+
+bar
+''');
+
+ expect(file.span(0, 5).highlight(), equals(r"""
+ ,
+1 | / foo
+2 | \
+ '"""));
+ });
+
+ test('highlights multiple empty lines', () {
+ final file = SourceFile.fromString('foo\n\n\n\nbar');
+ expect(file.span(4, 7).highlight(), equals(r"""
+ ,
+2 | /
+3 | |
+4 | \
+ '"""));
+ });
+
+ // Regression test for #32
+ test('highlights the end of a line and an empty line', () {
+ final file = SourceFile.fromString('foo\n\n');
+ expect(file.span(3, 5).highlight(), equals(r"""
+ ,
+1 | foo
+ | ,----^
+2 | \
+ '"""));
+ });
+ });
+
+ group('prints tabs as spaces', () {
+ group('in a single-line span', () {
+ test('before the highlighted section', () {
+ final span = SourceFile.fromString('foo\tbar baz').span(4, 7);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^^^
+ '"""));
+ });
+
+ test('within the highlighted section', () {
+ final span = SourceFile.fromString('foo bar\tbaz bang').span(4, 11);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz bang
+ | ^^^^^^^^^^
+ '"""));
+ });
+
+ test('after the highlighted section', () {
+ final span = SourceFile.fromString('foo bar\tbaz').span(4, 7);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ^^^
+ '"""));
+ });
+ });
+
+ group('in a multi-line span', () {
+ test('before the highlighted section', () {
+ final span = SourceFile.fromString('''
+foo\tbar baz
+whiz bang boom
+''').span(4, 21);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,--------^
+2 | | whiz bang boom
+ | '---------^
+ '"""));
+ });
+
+ test('within the first highlighted line', () {
+ final span = SourceFile.fromString('''
+foo bar\tbaz
+whiz bang boom
+''').span(4, 21);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+ | '---------^
+ '"""));
+ });
+
+ test('at the beginning of the first highlighted line', () {
+ final span = SourceFile.fromString('''
+foo bar\tbaz
+whiz bang boom
+''').span(7, 21);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,--------^
+2 | | whiz bang boom
+ | '---------^
+ '"""));
+ });
+
+ test('within a middle highlighted line', () {
+ final span = SourceFile.fromString('''
+foo bar baz
+whiz\tbang boom
+zip zap zop
+''').span(4, 34);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+3 | | zip zap zop
+ | '-------^
+ '"""));
+ });
+
+ test('within the last highlighted line', () {
+ final span = SourceFile.fromString('''
+foo bar baz
+whiz\tbang boom
+''').span(4, 21);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+ | '------------^
+ '"""));
+ });
+
+ test('at the end of the last highlighted line', () {
+ final span = SourceFile.fromString('''
+foo bar baz
+whiz\tbang boom
+''').span(4, 17);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+ | '--------^
+ '"""));
+ });
+
+ test('after the highlighted section', () {
+ final span = SourceFile.fromString('''
+foo bar baz
+whiz bang\tboom
+''').span(4, 21);
+
+ expect(span.highlight(), equals("""
+ ,
+1 | foo bar baz
+ | ,-----^
+2 | | whiz bang boom
+ | '---------^
+ '"""));
+ });
+ });
+ });
+
+ group('supports lines of preceding and following context for a span', () {
+ test('within a single line', () {
+ final span = SourceSpanWithContext(
+ SourceLocation(20, line: 2, column: 5, sourceUrl: 'foo.dart'),
+ SourceLocation(27, line: 2, column: 12, sourceUrl: 'foo.dart'),
+ 'foo bar',
+ 'previous\nlines\n-----foo bar-----\nfollowing line\n');
+
+ expect(span.highlight(), equals("""
+ ,
+1 | previous
+2 | lines
+3 | -----foo bar-----
+ | ^^^^^^^
+4 | following line
+ '"""));
+ });
+
+ test('covering a full line', () {
+ final span = SourceSpanWithContext(
+ SourceLocation(15, line: 2, column: 0, sourceUrl: 'foo.dart'),
+ SourceLocation(33, line: 3, column: 0, sourceUrl: 'foo.dart'),
+ '-----foo bar-----\n',
+ 'previous\nlines\n-----foo bar-----\nfollowing line\n');
+
+ expect(span.highlight(), equals("""
+ ,
+1 | previous
+2 | lines
+3 | -----foo bar-----
+ | ^^^^^^^^^^^^^^^^^
+4 | following line
+ '"""));
+ });
+
+ test('covering multiple full lines', () {
+ final span = SourceSpanWithContext(
+ SourceLocation(15, line: 2, column: 0, sourceUrl: 'foo.dart'),
+ SourceLocation(23, line: 4, column: 0, sourceUrl: 'foo.dart'),
+ 'foo\nbar\n',
+ 'previous\nlines\nfoo\nbar\nfollowing line\n');
+
+ expect(span.highlight(), equals(r"""
+ ,
+1 | previous
+2 | lines
+3 | / foo
+4 | \ bar
+5 | following line
+ '"""));
+ });
+ });
+
+ group('colors', () {
+ test("doesn't colorize if color is false", () {
+ expect(file.span(4, 7).highlight(color: false), equals("""
+ ,
+1 | foo bar baz
+ | ^^^
+ '"""));
+ });
+
+ test('colorizes if color is true', () {
+ expect(file.span(4, 7).highlight(color: true), equals('''
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} foo ${colors.red}bar${colors.none} baz
+${colors.blue} |${colors.none} ${colors.red} ^^^${colors.none}
+${colors.blue} '${colors.none}'''));
+ });
+
+ test("uses the given color if it's passed", () {
+ expect(file.span(4, 7).highlight(color: colors.yellow), equals('''
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} foo ${colors.yellow}bar${colors.none} baz
+${colors.blue} |${colors.none} ${colors.yellow} ^^^${colors.none}
+${colors.blue} '${colors.none}'''));
+ });
+
+ test('colorizes a multiline span', () {
+ expect(file.span(4, 34).highlight(color: true), equals('''
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} foo ${colors.red}bar baz${colors.none}
+${colors.blue} |${colors.none} ${colors.red},${colors.none}${colors.red}-----^${colors.none}
+${colors.blue}2 |${colors.none} ${colors.red}|${colors.none} ${colors.red}whiz bang boom${colors.none}
+${colors.blue}3 |${colors.none} ${colors.red}|${colors.none} ${colors.red}zip zap${colors.none} zop
+${colors.blue} |${colors.none} ${colors.red}'${colors.none}${colors.red}-------^${colors.none}
+${colors.blue} '${colors.none}'''));
+ });
+
+ test('colorizes a multiline span that highlights full lines', () {
+ expect(file.span(0, 39).highlight(color: true), equals('''
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} ${colors.red}/${colors.none} ${colors.red}foo bar baz${colors.none}
+${colors.blue}2 |${colors.none} ${colors.red}|${colors.none} ${colors.red}whiz bang boom${colors.none}
+${colors.blue}3 |${colors.none} ${colors.red}\\${colors.none} ${colors.red}zip zap zop${colors.none}
+${colors.blue} '${colors.none}'''));
+ });
+ });
+
+ group('line numbers have appropriate padding', () {
+ test('with line number 9', () {
+ expect(
+ SourceFile.fromString('\n' * 8 + 'foo bar baz\n')
+ .span(8, 11)
+ .highlight(),
+ equals("""
+ ,
+9 | foo bar baz
+ | ^^^
+ '"""));
+ });
+
+ test('with line number 10', () {
+ expect(
+ SourceFile.fromString('\n' * 9 + 'foo bar baz\n')
+ .span(9, 12)
+ .highlight(),
+ equals("""
+ ,
+10 | foo bar baz
+ | ^^^
+ '"""));
+ });
+ });
+}
diff --git a/pkgs/source_span/test/location_test.dart b/pkgs/source_span/test/location_test.dart
new file mode 100644
index 0000000..bbe259b
--- /dev/null
+++ b/pkgs/source_span/test/location_test.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+import 'package:test/test.dart';
+
+void main() {
+ late SourceLocation location;
+ setUp(() {
+ location = SourceLocation(15, line: 2, column: 6, sourceUrl: 'foo.dart');
+ });
+
+ group('errors', () {
+ group('for new SourceLocation()', () {
+ test('offset may not be negative', () {
+ expect(() => SourceLocation(-1), throwsRangeError);
+ });
+
+ test('line may not be negative', () {
+ expect(() => SourceLocation(0, line: -1), throwsRangeError);
+ });
+
+ test('column may not be negative', () {
+ expect(() => SourceLocation(0, column: -1), throwsRangeError);
+ });
+ });
+
+ test('for distance() source URLs must match', () {
+ expect(() => location.distance(SourceLocation(0)), throwsArgumentError);
+ });
+
+ test('for compareTo() source URLs must match', () {
+ expect(() => location.compareTo(SourceLocation(0)), throwsArgumentError);
+ });
+ });
+
+ test('fields work correctly', () {
+ expect(location.sourceUrl, equals(Uri.parse('foo.dart')));
+ expect(location.offset, equals(15));
+ expect(location.line, equals(2));
+ expect(location.column, equals(6));
+ });
+
+ group('toolString', () {
+ test('returns a computer-readable representation', () {
+ expect(location.toolString, equals('foo.dart:3:7'));
+ });
+
+ test('gracefully handles a missing source URL', () {
+ final location = SourceLocation(15, line: 2, column: 6);
+ expect(location.toolString, equals('unknown source:3:7'));
+ });
+ });
+
+ test('distance returns the absolute distance between locations', () {
+ final other = SourceLocation(10, sourceUrl: 'foo.dart');
+ expect(location.distance(other), equals(5));
+ expect(other.distance(location), equals(5));
+ });
+
+ test('pointSpan returns an empty span at location', () {
+ final span = location.pointSpan();
+ expect(span.start, equals(location));
+ expect(span.end, equals(location));
+ expect(span.text, isEmpty);
+ });
+
+ group('compareTo()', () {
+ test('sorts by offset', () {
+ final other = SourceLocation(20, sourceUrl: 'foo.dart');
+ expect(location.compareTo(other), lessThan(0));
+ expect(other.compareTo(location), greaterThan(0));
+ });
+
+ test('considers equal locations equal', () {
+ expect(location.compareTo(location), equals(0));
+ });
+ });
+
+ group('equality', () {
+ test('two locations with the same offset and source are equal', () {
+ final other = SourceLocation(15, sourceUrl: 'foo.dart');
+ expect(location, equals(other));
+ });
+
+ test("a different offset isn't equal", () {
+ final other = SourceLocation(10, sourceUrl: 'foo.dart');
+ expect(location, isNot(equals(other)));
+ });
+
+ test("a different source isn't equal", () {
+ final other = SourceLocation(15, sourceUrl: 'bar.dart');
+ expect(location, isNot(equals(other)));
+ });
+ });
+}
diff --git a/pkgs/source_span/test/multiple_highlight_test.dart b/pkgs/source_span/test/multiple_highlight_test.dart
new file mode 100644
index 0000000..139d53c
--- /dev/null
+++ b/pkgs/source_span/test/multiple_highlight_test.dart
@@ -0,0 +1,423 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+import 'package:term_glyph/term_glyph.dart' as glyph;
+import 'package:test/test.dart';
+
+void main() {
+ late bool oldAscii;
+ setUpAll(() {
+ oldAscii = glyph.ascii;
+ glyph.ascii = true;
+ });
+
+ tearDownAll(() {
+ glyph.ascii = oldAscii;
+ });
+
+ late SourceFile file;
+ setUp(() {
+ file = SourceFile.fromString('''
+foo bar baz
+whiz bang boom
+zip zap zop
+fwee fwoo fwip
+argle bargle boo
+gibble bibble bop
+''', url: 'file1.txt');
+ });
+
+ test('highlights spans on separate lines', () {
+ expect(
+ file.span(17, 21).highlightMultiple(
+ 'one', {file.span(31, 34): 'two', file.span(4, 7): 'three'}),
+ equals("""
+ ,
+1 | foo bar baz
+ | === three
+2 | whiz bang boom
+ | ^^^^ one
+3 | zip zap zop
+ | === two
+ '"""));
+ });
+
+ test('highlights spans on the same line', () {
+ expect(
+ file.span(17, 21).highlightMultiple(
+ 'one', {file.span(22, 26): 'two', file.span(12, 16): 'three'}),
+ equals("""
+ ,
+2 | whiz bang boom
+ | ^^^^ one
+ | ==== three
+ | ==== two
+ '"""));
+ });
+
+ test('highlights overlapping spans on the same line', () {
+ expect(
+ file.span(17, 21).highlightMultiple(
+ 'one', {file.span(20, 26): 'two', file.span(12, 18): 'three'}),
+ equals("""
+ ,
+2 | whiz bang boom
+ | ^^^^ one
+ | ====== three
+ | ====== two
+ '"""));
+ });
+
+ test('highlights multiple multiline spans', () {
+ expect(
+ file.span(27, 54).highlightMultiple(
+ 'one', {file.span(54, 89): 'two', file.span(0, 27): 'three'}),
+ equals("""
+ ,
+1 | / foo bar baz
+2 | | whiz bang boom
+ | '--- three
+3 | / zip zap zop
+4 | | fwee fwoo fwip
+ | '--- one
+5 | / argle bargle boo
+6 | | gibble bibble bop
+ | '--- two
+ '"""));
+ });
+
+ test('highlights multiple overlapping multiline spans', () {
+ expect(
+ file.span(12, 70).highlightMultiple(
+ 'one', {file.span(54, 89): 'two', file.span(0, 27): 'three'}),
+ equals("""
+ ,
+1 | /- foo bar baz
+2 | |/ whiz bang boom
+ | '+--- three
+3 | | zip zap zop
+4 | | fwee fwoo fwip
+5 | /+ argle bargle boo
+ | |'--- one
+6 | | gibble bibble bop
+ | '---- two
+ '"""));
+ });
+
+ test('highlights many layers of overlaps', () {
+ expect(
+ file.span(0, 54).highlightMultiple('one', {
+ file.span(12, 77): 'two',
+ file.span(27, 84): 'three',
+ file.span(39, 88): 'four'
+ }),
+ equals("""
+ ,
+1 | /--- foo bar baz
+2 | |/-- whiz bang boom
+3 | ||/- zip zap zop
+4 | |||/ fwee fwoo fwip
+ | '+++--- one
+5 | ||| argle bargle boo
+6 | ||| gibble bibble bop
+ | '++------^ two
+ | '+-------------^ three
+ | '--- four
+ '"""));
+ });
+
+ group("highlights a multiline span that's a subset", () {
+ test('with no first or last line overlap', () {
+ expect(
+ file
+ .span(27, 53)
+ .highlightMultiple('inner', {file.span(12, 70): 'outer'}),
+ equals("""
+ ,
+2 | /- whiz bang boom
+3 | |/ zip zap zop
+4 | || fwee fwoo fwip
+ | |'--- inner
+5 | | argle bargle boo
+ | '---- outer
+ '"""));
+ });
+
+ test('overlapping the whole first line', () {
+ expect(
+ file
+ .span(12, 53)
+ .highlightMultiple('inner', {file.span(12, 70): 'outer'}),
+ equals("""
+ ,
+2 | // whiz bang boom
+3 | || zip zap zop
+4 | || fwee fwoo fwip
+ | |'--- inner
+5 | | argle bargle boo
+ | '---- outer
+ '"""));
+ });
+
+ test('overlapping part of first line', () {
+ expect(
+ file
+ .span(17, 53)
+ .highlightMultiple('inner', {file.span(12, 70): 'outer'}),
+ equals("""
+ ,
+2 | /- whiz bang boom
+ | |,------^
+3 | || zip zap zop
+4 | || fwee fwoo fwip
+ | |'--- inner
+5 | | argle bargle boo
+ | '---- outer
+ '"""));
+ });
+
+ test('overlapping the whole last line', () {
+ expect(
+ file
+ .span(27, 70)
+ .highlightMultiple('inner', {file.span(12, 70): 'outer'}),
+ equals("""
+ ,
+2 | /- whiz bang boom
+3 | |/ zip zap zop
+4 | || fwee fwoo fwip
+5 | || argle bargle boo
+ | |'--- inner
+ | '---- outer
+ '"""));
+ });
+
+ test('overlapping part of the last line', () {
+ expect(
+ file
+ .span(27, 66)
+ .highlightMultiple('inner', {file.span(12, 70): 'outer'}),
+ equals("""
+ ,
+2 | /- whiz bang boom
+3 | |/ zip zap zop
+4 | || fwee fwoo fwip
+5 | || argle bargle boo
+ | |'------------^ inner
+ | '---- outer
+ '"""));
+ });
+ });
+
+ group('a single-line span in a multiline span', () {
+ test('on the first line', () {
+ expect(
+ file
+ .span(17, 21)
+ .highlightMultiple('inner', {file.span(12, 70): 'outer'}),
+ equals("""
+ ,
+2 | / whiz bang boom
+ | | ^^^^ inner
+3 | | zip zap zop
+4 | | fwee fwoo fwip
+5 | | argle bargle boo
+ | '--- outer
+ '"""));
+ });
+
+ test('in the middle', () {
+ expect(
+ file
+ .span(31, 34)
+ .highlightMultiple('inner', {file.span(12, 70): 'outer'}),
+ equals("""
+ ,
+2 | / whiz bang boom
+3 | | zip zap zop
+ | | ^^^ inner
+4 | | fwee fwoo fwip
+5 | | argle bargle boo
+ | '--- outer
+ '"""));
+ });
+
+ test('on the last line', () {
+ expect(
+ file
+ .span(60, 66)
+ .highlightMultiple('inner', {file.span(12, 70): 'outer'}),
+ equals("""
+ ,
+2 | / whiz bang boom
+3 | | zip zap zop
+4 | | fwee fwoo fwip
+5 | | argle bargle boo
+ | | ^^^^^^ inner
+ | '--- outer
+ '"""));
+ });
+ });
+
+ group('writes headers when highlighting multiple files', () {
+ test('writes all file URLs', () {
+ final span2 = SourceFile.fromString('''
+quibble bibble boop
+''', url: 'file2.txt').span(8, 14);
+
+ expect(
+ file.span(31, 34).highlightMultiple('one', {span2: 'two'}), equals("""
+ ,--> file1.txt
+3 | zip zap zop
+ | ^^^ one
+ '
+ ,--> file2.txt
+1 | quibble bibble boop
+ | ====== two
+ '"""));
+ });
+
+ test('allows secondary spans to have null URL', () {
+ final span2 = SourceSpan(SourceLocation(1), SourceLocation(4), 'foo');
+
+ expect(
+ file.span(31, 34).highlightMultiple('one', {span2: 'two'}), equals("""
+ ,--> file1.txt
+3 | zip zap zop
+ | ^^^ one
+ '
+ ,
+1 | foo
+ | === two
+ '"""));
+ });
+
+ test('allows primary span to have null URL', () {
+ final span1 = SourceSpan(SourceLocation(1), SourceLocation(4), 'foo');
+
+ expect(
+ span1.highlightMultiple('one', {file.span(31, 34): 'two'}), equals("""
+ ,
+1 | foo
+ | ^^^ one
+ '
+ ,--> file1.txt
+3 | zip zap zop
+ | === two
+ '"""));
+ });
+ });
+
+ test('highlights multiple null URLs as separate files', () {
+ final span1 = SourceSpan(SourceLocation(1), SourceLocation(4), 'foo');
+ final span2 = SourceSpan(SourceLocation(1), SourceLocation(4), 'bar');
+
+ expect(span1.highlightMultiple('one', {span2: 'two'}), equals("""
+ ,
+1 | foo
+ | ^^^ one
+ '
+ ,
+1 | bar
+ | === two
+ '"""));
+ });
+
+ group('indents mutli-line labels', () {
+ test('for the primary label', () {
+ expect(file.span(17, 21).highlightMultiple('line 1\nline 2\nline 3', {}),
+ equals("""
+ ,
+2 | whiz bang boom
+ | ^^^^ line 1
+ | line 2
+ | line 3
+ '"""));
+ });
+
+ group('for a secondary label', () {
+ test('on the same line', () {
+ expect(
+ file.span(17, 21).highlightMultiple(
+ 'primary', {file.span(22, 26): 'line 1\nline 2\nline 3'}),
+ equals("""
+ ,
+2 | whiz bang boom
+ | ^^^^ primary
+ | ==== line 1
+ | line 2
+ | line 3
+ '"""));
+ });
+
+ test('on a different line', () {
+ expect(
+ file.span(17, 21).highlightMultiple(
+ 'primary', {file.span(31, 34): 'line 1\nline 2\nline 3'}),
+ equals("""
+ ,
+2 | whiz bang boom
+ | ^^^^ primary
+3 | zip zap zop
+ | === line 1
+ | line 2
+ | line 3
+ '"""));
+ });
+ });
+
+ group('for a multiline span', () {
+ test('that covers the whole last line', () {
+ expect(
+ file.span(12, 70).highlightMultiple('line 1\nline 2\nline 3', {}),
+ equals("""
+ ,
+2 | / whiz bang boom
+3 | | zip zap zop
+4 | | fwee fwoo fwip
+5 | | argle bargle boo
+ | '--- line 1
+ | line 2
+ | line 3
+ '"""));
+ });
+
+ test('that covers part of the last line', () {
+ expect(
+ file.span(12, 66).highlightMultiple('line 1\nline 2\nline 3', {}),
+ equals("""
+ ,
+2 | / whiz bang boom
+3 | | zip zap zop
+4 | | fwee fwoo fwip
+5 | | argle bargle boo
+ | '------------^ line 1
+ | line 2
+ | line 3
+ '"""));
+ });
+ });
+
+ test('with an overlapping span', () {
+ expect(
+ file.span(12, 70).highlightMultiple('line 1\nline 2\nline 3',
+ {file.span(54, 89): 'two', file.span(0, 27): 'three'}),
+ equals("""
+ ,
+1 | /- foo bar baz
+2 | |/ whiz bang boom
+ | '+--- three
+3 | | zip zap zop
+4 | | fwee fwoo fwip
+5 | /+ argle bargle boo
+ | |'--- line 1
+ | | line 2
+ | | line 3
+6 | | gibble bibble bop
+ | '---- two
+ '"""));
+ });
+ });
+}
diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart
new file mode 100644
index 0000000..22c498e
--- /dev/null
+++ b/pkgs/source_span/test/span_test.dart
@@ -0,0 +1,432 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/source_span.dart';
+import 'package:source_span/src/colors.dart' as colors;
+import 'package:term_glyph/term_glyph.dart' as glyph;
+import 'package:test/test.dart';
+
+void main() {
+ late bool oldAscii;
+
+ setUpAll(() {
+ oldAscii = glyph.ascii;
+ glyph.ascii = true;
+ });
+
+ tearDownAll(() {
+ glyph.ascii = oldAscii;
+ });
+
+ late SourceSpan span;
+ setUp(() {
+ span = SourceSpan(SourceLocation(5, sourceUrl: 'foo.dart'),
+ SourceLocation(12, sourceUrl: 'foo.dart'), 'foo bar');
+ });
+
+ group('errors', () {
+ group('for new SourceSpan()', () {
+ test('source URLs must match', () {
+ final start = SourceLocation(0, sourceUrl: 'foo.dart');
+ final end = SourceLocation(1, sourceUrl: 'bar.dart');
+ expect(() => SourceSpan(start, end, '_'), throwsArgumentError);
+ });
+
+ test('end must come after start', () {
+ final start = SourceLocation(1);
+ final end = SourceLocation(0);
+ expect(() => SourceSpan(start, end, '_'), throwsArgumentError);
+ });
+
+ test('text must be the right length', () {
+ final start = SourceLocation(0);
+ final end = SourceLocation(1);
+ expect(() => SourceSpan(start, end, 'abc'), throwsArgumentError);
+ });
+ });
+
+ group('for new SourceSpanWithContext()', () {
+ test('context must contain text', () {
+ final start = SourceLocation(2);
+ final end = SourceLocation(5);
+ expect(() => SourceSpanWithContext(start, end, 'abc', '--axc--'),
+ throwsArgumentError);
+ });
+
+ test('text starts at start.column in context', () {
+ final start = SourceLocation(3);
+ final end = SourceLocation(5);
+ expect(() => SourceSpanWithContext(start, end, 'abc', '--abc--'),
+ throwsArgumentError);
+ });
+
+ test('text starts at start.column of line in multi-line context', () {
+ final start = SourceLocation(4, line: 55, column: 3);
+ final end = SourceLocation(7, line: 55, column: 6);
+ expect(() => SourceSpanWithContext(start, end, 'abc', '\n--abc--'),
+ throwsArgumentError);
+ expect(() => SourceSpanWithContext(start, end, 'abc', '\n----abc--'),
+ throwsArgumentError);
+ expect(() => SourceSpanWithContext(start, end, 'abc', '\n\n--abc--'),
+ throwsArgumentError);
+
+ // However, these are valid:
+ SourceSpanWithContext(start, end, 'abc', '\n---abc--');
+ SourceSpanWithContext(start, end, 'abc', '\n\n---abc--');
+ });
+
+ test('text can occur multiple times in context', () {
+ final start1 = SourceLocation(4, line: 55, column: 2);
+ final end1 = SourceLocation(7, line: 55, column: 5);
+ final start2 = SourceLocation(4, line: 55, column: 8);
+ final end2 = SourceLocation(7, line: 55, column: 11);
+ SourceSpanWithContext(start1, end1, 'abc', '--abc---abc--\n');
+ SourceSpanWithContext(start1, end1, 'abc', '--abc--abc--\n');
+ SourceSpanWithContext(start2, end2, 'abc', '--abc---abc--\n');
+ SourceSpanWithContext(start2, end2, 'abc', '---abc--abc--\n');
+ expect(
+ () => SourceSpanWithContext(start1, end1, 'abc', '---abc--abc--\n'),
+ throwsArgumentError);
+ expect(
+ () => SourceSpanWithContext(start2, end2, 'abc', '--abc--abc--\n'),
+ throwsArgumentError);
+ });
+ });
+
+ group('for union()', () {
+ test('source URLs must match', () {
+ final other = SourceSpan(SourceLocation(12, sourceUrl: 'bar.dart'),
+ SourceLocation(13, sourceUrl: 'bar.dart'), '_');
+
+ expect(() => span.union(other), throwsArgumentError);
+ });
+
+ test('spans may not be disjoint', () {
+ final other = SourceSpan(SourceLocation(13, sourceUrl: 'foo.dart'),
+ SourceLocation(14, sourceUrl: 'foo.dart'), '_');
+
+ expect(() => span.union(other), throwsArgumentError);
+ });
+ });
+
+ test('for compareTo() source URLs must match', () {
+ final other = SourceSpan(SourceLocation(12, sourceUrl: 'bar.dart'),
+ SourceLocation(13, sourceUrl: 'bar.dart'), '_');
+
+ expect(() => span.compareTo(other), throwsArgumentError);
+ });
+ });
+
+ test('fields work correctly', () {
+ expect(span.start, equals(SourceLocation(5, sourceUrl: 'foo.dart')));
+ expect(span.end, equals(SourceLocation(12, sourceUrl: 'foo.dart')));
+ expect(span.sourceUrl, equals(Uri.parse('foo.dart')));
+ expect(span.length, equals(7));
+ });
+
+ group('union()', () {
+ test('works with a preceding adjacent span', () {
+ final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'),
+ SourceLocation(5, sourceUrl: 'foo.dart'), 'hey, ');
+
+ final result = span.union(other);
+ expect(result.start, equals(other.start));
+ expect(result.end, equals(span.end));
+ expect(result.text, equals('hey, foo bar'));
+ });
+
+ test('works with a preceding overlapping span', () {
+ final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'),
+ SourceLocation(8, sourceUrl: 'foo.dart'), 'hey, foo');
+
+ final result = span.union(other);
+ expect(result.start, equals(other.start));
+ expect(result.end, equals(span.end));
+ expect(result.text, equals('hey, foo bar'));
+ });
+
+ test('works with a following adjacent span', () {
+ final other = SourceSpan(SourceLocation(12, sourceUrl: 'foo.dart'),
+ SourceLocation(16, sourceUrl: 'foo.dart'), ' baz');
+
+ final result = span.union(other);
+ expect(result.start, equals(span.start));
+ expect(result.end, equals(other.end));
+ expect(result.text, equals('foo bar baz'));
+ });
+
+ test('works with a following overlapping span', () {
+ final other = SourceSpan(SourceLocation(9, sourceUrl: 'foo.dart'),
+ SourceLocation(16, sourceUrl: 'foo.dart'), 'bar baz');
+
+ final result = span.union(other);
+ expect(result.start, equals(span.start));
+ expect(result.end, equals(other.end));
+ expect(result.text, equals('foo bar baz'));
+ });
+
+ test('works with an internal overlapping span', () {
+ final other = SourceSpan(SourceLocation(7, sourceUrl: 'foo.dart'),
+ SourceLocation(10, sourceUrl: 'foo.dart'), 'o b');
+
+ expect(span.union(other), equals(span));
+ });
+
+ test('works with an external overlapping span', () {
+ final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'),
+ SourceLocation(16, sourceUrl: 'foo.dart'), 'hey, foo bar baz');
+
+ expect(span.union(other), equals(other));
+ });
+ });
+
+ group('subspan()', () {
+ group('errors', () {
+ test('start must be greater than zero', () {
+ expect(() => span.subspan(-1), throwsRangeError);
+ });
+
+ test('start must be less than or equal to length', () {
+ expect(() => span.subspan(span.length + 1), throwsRangeError);
+ });
+
+ test('end must be greater than start', () {
+ expect(() => span.subspan(2, 1), throwsRangeError);
+ });
+
+ test('end must be less than or equal to length', () {
+ expect(() => span.subspan(0, span.length + 1), throwsRangeError);
+ });
+ });
+
+ test('preserves the source URL', () {
+ final result = span.subspan(1, 2);
+ expect(result.start.sourceUrl, equals(span.sourceUrl));
+ expect(result.end.sourceUrl, equals(span.sourceUrl));
+ });
+
+ test('preserves the context', () {
+ final start = SourceLocation(2);
+ final end = SourceLocation(5);
+ final span = SourceSpanWithContext(start, end, 'abc', '--abc--');
+ expect(span.subspan(1, 2).context, equals('--abc--'));
+ });
+
+ group('returns the original span', () {
+ test('with an implicit end', () => expect(span.subspan(0), equals(span)));
+
+ test('with an explicit end',
+ () => expect(span.subspan(0, span.length), equals(span)));
+ });
+
+ group('within a single line', () {
+ test('returns a strict substring of the original span', () {
+ final result = span.subspan(1, 5);
+ expect(result.text, equals('oo b'));
+ expect(result.start.offset, equals(6));
+ expect(result.start.line, equals(0));
+ expect(result.start.column, equals(6));
+ expect(result.end.offset, equals(10));
+ expect(result.end.line, equals(0));
+ expect(result.end.column, equals(10));
+ });
+
+ test('an implicit end goes to the end of the original span', () {
+ final result = span.subspan(1);
+ expect(result.text, equals('oo bar'));
+ expect(result.start.offset, equals(6));
+ expect(result.start.line, equals(0));
+ expect(result.start.column, equals(6));
+ expect(result.end.offset, equals(12));
+ expect(result.end.line, equals(0));
+ expect(result.end.column, equals(12));
+ });
+
+ test('can return an empty span', () {
+ final result = span.subspan(3, 3);
+ expect(result.text, isEmpty);
+ expect(result.start.offset, equals(8));
+ expect(result.start.line, equals(0));
+ expect(result.start.column, equals(8));
+ expect(result.end, equals(result.start));
+ });
+ });
+
+ group('across multiple lines', () {
+ setUp(() {
+ span = SourceSpan(
+ SourceLocation(5, line: 2, column: 0),
+ SourceLocation(16, line: 4, column: 3),
+ 'foo\n'
+ 'bar\n'
+ 'baz');
+ });
+
+ test('with start and end in the middle of a line', () {
+ final result = span.subspan(2, 5);
+ expect(result.text, equals('o\nb'));
+ expect(result.start.offset, equals(7));
+ expect(result.start.line, equals(2));
+ expect(result.start.column, equals(2));
+ expect(result.end.offset, equals(10));
+ expect(result.end.line, equals(3));
+ expect(result.end.column, equals(1));
+ });
+
+ test('with start at the end of a line', () {
+ final result = span.subspan(3, 5);
+ expect(result.text, equals('\nb'));
+ expect(result.start.offset, equals(8));
+ expect(result.start.line, equals(2));
+ expect(result.start.column, equals(3));
+ });
+
+ test('with start at the beginning of a line', () {
+ final result = span.subspan(4, 5);
+ expect(result.text, equals('b'));
+ expect(result.start.offset, equals(9));
+ expect(result.start.line, equals(3));
+ expect(result.start.column, equals(0));
+ });
+
+ test('with end at the end of a line', () {
+ final result = span.subspan(2, 3);
+ expect(result.text, equals('o'));
+ expect(result.end.offset, equals(8));
+ expect(result.end.line, equals(2));
+ expect(result.end.column, equals(3));
+ });
+
+ test('with end at the beginning of a line', () {
+ final result = span.subspan(2, 4);
+ expect(result.text, equals('o\n'));
+ expect(result.end.offset, equals(9));
+ expect(result.end.line, equals(3));
+ expect(result.end.column, equals(0));
+ });
+ });
+ });
+
+ group('message()', () {
+ test('prints the text being described', () {
+ expect(span.message('oh no'), equals("""
+line 1, column 6 of foo.dart: oh no
+ ,
+1 | foo bar
+ | ^^^^^^^
+ '"""));
+ });
+
+ test('gracefully handles a missing source URL', () {
+ final span = SourceSpan(SourceLocation(5), SourceLocation(12), 'foo bar');
+
+ expect(span.message('oh no'), equalsIgnoringWhitespace("""
+line 1, column 6: oh no
+ ,
+1 | foo bar
+ | ^^^^^^^
+ '"""));
+ });
+
+ test('gracefully handles empty text', () {
+ final span = SourceSpan(SourceLocation(5), SourceLocation(5), '');
+
+ expect(span.message('oh no'), equals('line 1, column 6: oh no'));
+ });
+
+ test("doesn't colorize if color is false", () {
+ expect(span.message('oh no', color: false), equals("""
+line 1, column 6 of foo.dart: oh no
+ ,
+1 | foo bar
+ | ^^^^^^^
+ '"""));
+ });
+
+ test('colorizes if color is true', () {
+ expect(span.message('oh no', color: true), equals("""
+line 1, column 6 of foo.dart: oh no
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} ${colors.red}foo bar${colors.none}
+${colors.blue} |${colors.none} ${colors.red}^^^^^^^${colors.none}
+${colors.blue} '${colors.none}"""));
+ });
+
+ test("uses the given color if it's passed", () {
+ expect(span.message('oh no', color: colors.yellow), equals("""
+line 1, column 6 of foo.dart: oh no
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} ${colors.yellow}foo bar${colors.none}
+${colors.blue} |${colors.none} ${colors.yellow}^^^^^^^${colors.none}
+${colors.blue} '${colors.none}"""));
+ });
+
+ test('with context, underlines the right column', () {
+ final spanWithContext = SourceSpanWithContext(
+ SourceLocation(5, sourceUrl: 'foo.dart'),
+ SourceLocation(12, sourceUrl: 'foo.dart'),
+ 'foo bar',
+ '-----foo bar-----');
+
+ expect(spanWithContext.message('oh no', color: colors.yellow), equals("""
+line 1, column 6 of foo.dart: oh no
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} -----${colors.yellow}foo bar${colors.none}-----
+${colors.blue} |${colors.none} ${colors.yellow} ^^^^^^^${colors.none}
+${colors.blue} '${colors.none}"""));
+ });
+ });
+
+ group('compareTo()', () {
+ test('sorts by start location first', () {
+ final other = SourceSpan(SourceLocation(6, sourceUrl: 'foo.dart'),
+ SourceLocation(14, sourceUrl: 'foo.dart'), 'oo bar b');
+
+ expect(span.compareTo(other), lessThan(0));
+ expect(other.compareTo(span), greaterThan(0));
+ });
+
+ test('sorts by length second', () {
+ final other = SourceSpan(SourceLocation(5, sourceUrl: 'foo.dart'),
+ SourceLocation(14, sourceUrl: 'foo.dart'), 'foo bar b');
+
+ expect(span.compareTo(other), lessThan(0));
+ expect(other.compareTo(span), greaterThan(0));
+ });
+
+ test('considers equal spans equal', () {
+ expect(span.compareTo(span), equals(0));
+ });
+ });
+
+ group('equality', () {
+ test('two spans with the same locations are equal', () {
+ final other = SourceSpan(SourceLocation(5, sourceUrl: 'foo.dart'),
+ SourceLocation(12, sourceUrl: 'foo.dart'), 'foo bar');
+
+ expect(span, equals(other));
+ });
+
+ test("a different start isn't equal", () {
+ final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'),
+ SourceLocation(12, sourceUrl: 'foo.dart'), 'hey, foo bar');
+
+ expect(span, isNot(equals(other)));
+ });
+
+ test("a different end isn't equal", () {
+ final other = SourceSpan(SourceLocation(5, sourceUrl: 'foo.dart'),
+ SourceLocation(16, sourceUrl: 'foo.dart'), 'foo bar baz');
+
+ expect(span, isNot(equals(other)));
+ });
+
+ test("a different source URL isn't equal", () {
+ final other = SourceSpan(SourceLocation(5, sourceUrl: 'bar.dart'),
+ SourceLocation(12, sourceUrl: 'bar.dart'), 'foo bar');
+
+ expect(span, isNot(equals(other)));
+ });
+ });
+}
diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart
new file mode 100644
index 0000000..91397c0
--- /dev/null
+++ b/pkgs/source_span/test/utils_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:source_span/src/utils.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('find line start', () {
+ test('skip entries in wrong column', () {
+ const context = '0_bb\n1_bbb\n2b____\n3bbb\n';
+ final index = findLineStart(context, 'b', 1)!;
+ expect(index, 11);
+ expect(context.substring(index - 1, index + 3), '\n2b_');
+ });
+
+ test('end of line column for empty text', () {
+ const context = '0123\n56789\nabcdefgh\n';
+ final index = findLineStart(context, '', 5)!;
+ expect(index, 5);
+ expect(context[index], '5');
+ });
+
+ test('column at the end of the file for empty text', () {
+ var context = '0\n2\n45\n';
+ var index = findLineStart(context, '', 2)!;
+ expect(index, 4);
+ expect(context[index], '4');
+
+ context = '0\n2\n45';
+ index = findLineStart(context, '', 2)!;
+ expect(index, 4);
+ });
+
+ test('empty text in empty context', () {
+ final index = findLineStart('', '', 0);
+ expect(index, 0);
+ });
+
+ test('found on the first line', () {
+ const context = '0\n2\n45\n';
+ final index = findLineStart(context, '0', 0);
+ expect(index, 0);
+ });
+
+ test('finds text that starts with a newline', () {
+ const context = '0\n2\n45\n';
+ final index = findLineStart(context, '\n2', 1);
+ expect(index, 0);
+ });
+
+ test('not found', () {
+ const context = '0\n2\n45\n';
+ final index = findLineStart(context, '0', 1);
+ expect(index, isNull);
+ });
+ });
+}
diff --git a/pkgs/sse/.gitignore b/pkgs/sse/.gitignore
new file mode 100644
index 0000000..1467782
--- /dev/null
+++ b/pkgs/sse/.gitignore
@@ -0,0 +1,3 @@
+.dart_tool
+pubspec.lock
+test/web/index.dart.js.deps
diff --git a/pkgs/sse/AUTHORS b/pkgs/sse/AUTHORS
new file mode 100644
index 0000000..7c12ae6
--- /dev/null
+++ b/pkgs/sse/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the Dart project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/pkgs/sse/CHANGELOG.md b/pkgs/sse/CHANGELOG.md
new file mode 100644
index 0000000..0387ba9
--- /dev/null
+++ b/pkgs/sse/CHANGELOG.md
@@ -0,0 +1,178 @@
+## 4.1.7
+
+- Move to `dart-lang/tools` monorepo.
+
+## 4.1.6
+
+- Require package `web: '>=0.5.0 <2.0.0'`.
+
+## 4.1.5
+
+- Drop unneeded dependency on `package:js`.
+- Update the minimum Dart SDK version to `3.3.0`.
+- Support the latest `package:web`.
+
+## 4.1.4
+
+- Fix incorrect cast causing failure with `dart2wasm`.
+
+## 4.1.3
+
+- Update the minimum Dart SDK version to `3.2.0`.
+
+## 4.1.2
+
+- Send `fetch` requests instead of `XHR` requests.
+- Add an optional `debugKey` parameter to `SseClient` to include in logging.
+- Add a dependency on `package:js`.
+- Update the minimum Dart SDK version to `2.16.0`.
+
+## 4.1.1
+
+- Apply `keepAlive` logic to `SocketException`s.
+- Switch from using `package:pedantic` to `package:lints`
+- Rev the minimum required SDK to 2.15.
+- Populate the pubspec `repository` field.
+
+## 4.1.0
+
+- Limit the number of concurrent requests to prevent Chrome from automatically
+ dropping them on the floor.
+
+## 4.0.0
+
+- Support null safety.
+
+## 3.8.3
+
+- Require the latest shelf and remove dead code.
+
+## 3.8.2
+
+- Complete `onConnected` with an error if the `SseClient` receives an error
+ before the connection is successfully opened.
+
+## 3.8.1
+
+- Fix an issue where closing the `SseConnection` stream would result in an
+ error.
+
+## 3.8.0
+
+- Add `onConnected` to replace `onOpen`.
+- Fix an issue where failed requests would not add a `done` event to the
+ connection `sink`.
+
+## 3.7.0
+
+- Deprecate the client's `onOpen` getter. Messages will now be buffered until a
+ connection is established.
+
+## 3.6.1
+
+- Drop dependency on `package:uuid`.
+
+## 3.6.0
+
+- Improve performance by buffering out of order messages in the server instead
+ of the client.
+
+\*\* Note \*\* This is not modelled as a breaking change as the server can
+handle messages from older clients. However, clients should be using the latest
+server if they require order guarantees.
+
+## 3.5.0
+
+- Add new `shutdown` methods on `SseHandler` and `SseConnection` to allow
+ closing connections immediately, ignoring any keep-alive periods.
+
+## 3.4.0
+
+- Remove `onClose` from `SseConnection` and ensure the corresponding
+ `sink.close` correctly fires.
+
+## 3.3.0
+
+- Add an `onClose` event to the `SseConnection`. This allows consumers to listen
+ to this event in lue of `sseConnection.sink.done` as that is not guaranteed to
+ fire.
+
+## 3.2.2
+
+- Fix an issue where `keepAlive` may cause state errors when attempting to send
+ messages on a closed stream.
+
+## 3.2.1
+
+- Fix an issue where `keepAlive` would only allow a single reconnection.
+
+## 3.2.0
+
+- Re-expose `isInKeepAlivePeriod` flag on `SseConnection`. This flag will be
+ `true` when a connection has been dropped and is in the keep-alive period
+ waiting for a client to reconnect.
+
+## 3.1.2
+
+- Fix an issue where the `SseClient` would not send a `done` event when there
+ was an error with the SSE connection.
+
+## 3.1.1
+
+- Make `isInKeepAlive` on `SseConnection` private.
+
+**Note that this is a breaking change but in actuality no one should be
+depending on this API.**
+
+## 3.1.0
+
+- Add optional `keepAlive` parameter to the `SseHandler`. If `keepAlive` is
+ supplied, the connection will remain active for this period after a disconnect
+ and can be reconnected transparently. If there is no reconnect within that
+ period, the connection will be closed normally.
+
+## 3.0.0
+
+- Add retry logic.
+
+**Possible Breaking Change Error messages may now be delayed up to 5 seconds in
+the client.**
+
+## 2.1.2
+
+- Remove `package:http` dependency.
+
+## 2.1.1
+
+- Use proper headers delimiter.
+
+## 2.1.0
+
+- Support Firefox.
+
+## 2.0.3
+
+- Fix an issue where messages could come out of order.
+
+## 2.0.2
+
+- Support the latest `package:stream_channel`.
+- Require Dart SDK `>=2.1.0 <3.0.0`.
+
+## 2.0.1
+
+- Update to `package:uuid` version 2.0.
+
+## 2.0.0
+
+- No longer expose `close` and `onClose` on an `SseConnection`. This is simply
+ handled by the underlying `stream` / `sink`.
+- Fix a bug where resources of the `SseConnection` were not properly closed.
+
+## 1.0.0
+
+- Internal cleanup.
+
+## 0.0.1
+
+- Initial commit.
diff --git a/pkgs/sse/LICENSE b/pkgs/sse/LICENSE
new file mode 100644
index 0000000..a0d5f54
--- /dev/null
+++ b/pkgs/sse/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2019, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkgs/sse/README.md b/pkgs/sse/README.md
new file mode 100644
index 0000000..ef51415
--- /dev/null
+++ b/pkgs/sse/README.md
@@ -0,0 +1,14 @@
+[](https://github.com/dart-lang/tools/actions/workflows/sse.yaml)
+[](https://pub.dev/packages/sse)
+[](https://pub.dev/packages/sse/publisher)
+
+This package provides support for bi-directional communication through Server
+Sent Events and corresponding POST requests.
+
+This package is not intended to be a general purpose SSE package, but instead is
+a bidirectional protocol for use when Websockets are unavailable. That is, both
+the client and the server expose a `sink` and `stream` on which to send and
+receive messages respectively.
+
+Both the server and client have implicit assumptions on each other and therefore
+a client from this package must be paired with a server from this package.
diff --git a/pkgs/sse/analysis_options.yaml b/pkgs/sse/analysis_options.yaml
new file mode 100644
index 0000000..6729bd9
--- /dev/null
+++ b/pkgs/sse/analysis_options.yaml
@@ -0,0 +1,13 @@
+# https://dart.dev/guides/language/analysis-options
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+
+linter:
+ rules:
+ - avoid_unused_constructor_parameters
+ - cancel_subscriptions
+ - literal_only_boolean_expressions
+ - no_adjacent_strings_in_list
diff --git a/pkgs/sse/example/index.dart b/pkgs/sse/example/index.dart
new file mode 100644
index 0000000..0ed7596
--- /dev/null
+++ b/pkgs/sse/example/index.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:sse/client/sse_client.dart';
+
+/// A basic example which should be used in a browser that supports SSE.
+void main() {
+ var channel = SseClient('/sseHandler');
+
+ channel.stream.listen((s) {
+ // Listen for messages and send them back.
+ channel.sink.add(s);
+ });
+}
diff --git a/pkgs/sse/example/server.dart b/pkgs/sse/example/server.dart
new file mode 100644
index 0000000..b6ee750
--- /dev/null
+++ b/pkgs/sse/example/server.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:shelf/shelf_io.dart' as io;
+import 'package:sse/server/sse_handler.dart';
+
+/// A basic server which sets up an SSE handler.
+///
+/// When a client connects it will send a simple message and print the
+/// response.
+void main() async {
+ var handler = SseHandler(Uri.parse('/sseHandler'));
+ await io.serve(handler.handler, 'localhost', 0);
+ var connections = handler.connections;
+ while (await connections.hasNext) {
+ var connection = await connections.next;
+ connection.sink.add('foo');
+ connection.stream.listen(print);
+ }
+}
diff --git a/pkgs/sse/lib/client/sse_client.dart b/pkgs/sse/lib/client/sse_client.dart
new file mode 100644
index 0000000..4d3df49
--- /dev/null
+++ b/pkgs/sse/lib/client/sse_client.dart
@@ -0,0 +1,166 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:js_interop';
+
+import 'package:logging/logging.dart';
+import 'package:pool/pool.dart';
+import 'package:stream_channel/stream_channel.dart';
+import 'package:web/web.dart';
+
+import '../src/util/uuid.dart';
+
+/// Limit for the number of concurrent outgoing requests.
+///
+/// Chrome drops outgoing requests on the floor after some threshold. To prevent
+/// these errors we buffer outgoing requests with a pool.
+///
+/// Note Chrome's limit is 6000. So this gives us plenty of headroom.
+final _requestPool = Pool(1000);
+
+/// A client for bi-directional sse communication.
+///
+/// The client can send any JSON-encodable messages to the server by adding
+/// them to the [sink] and listen to messages from the server on the [stream].
+class SseClient extends StreamChannelMixin<String?> {
+ final String _clientId;
+
+ final _incomingController = StreamController<String>();
+
+ final _outgoingController = StreamController<String>();
+
+ final _logger = Logger('SseClient');
+
+ final _onConnected = Completer<void>();
+
+ int _lastMessageId = -1;
+
+ late EventSource _eventSource;
+
+ late String _serverUrl;
+
+ Timer? _errorTimer;
+
+ /// [serverUrl] is the URL under which the server is listening for
+ /// incoming bi-directional SSE connections. [debugKey] is an optional key
+ /// that can be used to identify the SSE connection.
+ SseClient(String serverUrl, {String? debugKey})
+ : _clientId = debugKey == null
+ ? generateUuidV4()
+ : '$debugKey-${generateUuidV4()}' {
+ _serverUrl = '$serverUrl?sseClientId=$_clientId';
+ _eventSource =
+ EventSource(_serverUrl, EventSourceInit(withCredentials: true));
+ _eventSource.onOpen.first.whenComplete(() {
+ _onConnected.complete();
+ _outgoingController.stream
+ .listen(_onOutgoingMessage, onDone: _onOutgoingDone);
+ });
+ _eventSource.addEventListener('message', _onIncomingMessage.toJS);
+ _eventSource.addEventListener('control', _onIncomingControlMessage.toJS);
+
+ _eventSource.onOpen.listen((_) {
+ _errorTimer?.cancel();
+ });
+ _eventSource.onError.listen((error) {
+ if (!(_errorTimer?.isActive ?? false)) {
+ // By default the SSE client uses keep-alive.
+ // Allow for a retry to connect before giving up.
+ _errorTimer = Timer(const Duration(seconds: 5), () {
+ _closeWithError(error);
+ });
+ }
+ });
+ }
+
+ @Deprecated('Use onConnected instead.')
+ Stream<Event> get onOpen => _eventSource.onOpen;
+
+ Future<void> get onConnected => _onConnected.future;
+
+ /// Add messages to this [StreamSink] to send them to the server.
+ ///
+ /// The message added to the sink has to be JSON encodable. Messages that fail
+ /// to encode will be logged through a [Logger].
+ @override
+ StreamSink<String> get sink => _outgoingController.sink;
+
+ /// [Stream] of messages sent from the server to this client.
+ ///
+ /// A message is a decoded JSON object.
+ @override
+ Stream<String> get stream => _incomingController.stream;
+
+ void close() {
+ _eventSource.close();
+ // If the initial connection was never established. Add a listener so close
+ // adds a done event to [sink].
+ if (!_onConnected.isCompleted) _outgoingController.stream.drain<void>();
+ _incomingController.close();
+ _outgoingController.close();
+ }
+
+ void _closeWithError(Object error) {
+ _incomingController.addError(error);
+ close();
+ if (!_onConnected.isCompleted) {
+ // This call must happen after the call to close() which checks
+ // whether the completer was completed earlier.
+ _onConnected.completeError(error);
+ }
+ }
+
+ void _onIncomingControlMessage(Event message) {
+ var data = (message as MessageEvent).data;
+ if (data.dartify() == 'close') {
+ close();
+ } else {
+ throw UnsupportedError('[$_clientId] Illegal Control Message "$data"');
+ }
+ }
+
+ void _onIncomingMessage(Event message) {
+ var decoded =
+ jsonDecode(((message as MessageEvent).data as JSString).toDart);
+ _incomingController.add(decoded as String);
+ }
+
+ void _onOutgoingDone() {
+ close();
+ }
+
+ void _onOutgoingMessage(String? message) async {
+ String? encodedMessage;
+ await _requestPool.withResource(() async {
+ try {
+ encodedMessage = jsonEncode(message);
+ // ignore: avoid_catching_errors
+ } on JsonUnsupportedObjectError catch (e) {
+ _logger.warning('[$_clientId] Unable to encode outgoing message: $e');
+ // ignore: avoid_catching_errors
+ } on ArgumentError catch (e) {
+ _logger.warning('[$_clientId] Invalid argument: $e');
+ }
+ try {
+ final url = '$_serverUrl&messageId=${++_lastMessageId}';
+ await _fetch(
+ url,
+ RequestInit(
+ method: 'POST',
+ body: encodedMessage?.toJS,
+ credentials: 'include'));
+ } catch (error) {
+ final augmentedError =
+ '[$_clientId] SSE client failed to send $message:\n $error';
+ _logger.severe(augmentedError);
+ _closeWithError(augmentedError);
+ }
+ });
+ }
+}
+
+Future<void> _fetch(String resourceUrl, RequestInit options) =>
+ window.fetch(resourceUrl.toJS, options).toDart;
diff --git a/pkgs/sse/lib/server/sse_handler.dart b/pkgs/sse/lib/server/sse_handler.dart
new file mode 100644
index 0000000..bfed935
--- /dev/null
+++ b/pkgs/sse/lib/server/sse_handler.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'package:sse/src/server/sse_handler.dart' show SseConnection, SseHandler;
diff --git a/pkgs/sse/lib/src/server/sse_handler.dart b/pkgs/sse/lib/src/server/sse_handler.dart
new file mode 100644
index 0000000..376fe27
--- /dev/null
+++ b/pkgs/sse/lib/src/server/sse_handler.dart
@@ -0,0 +1,299 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:async/async.dart';
+import 'package:collection/collection.dart';
+import 'package:logging/logging.dart';
+import 'package:shelf/shelf.dart' as shelf;
+import 'package:stream_channel/stream_channel.dart';
+
+// RFC 2616 requires carriage return delimiters.
+String _sseHeaders(String? origin) => 'HTTP/1.1 200 OK\r\n'
+ 'Content-Type: text/event-stream\r\n'
+ 'Cache-Control: no-cache\r\n'
+ 'Connection: keep-alive\r\n'
+ 'Access-Control-Allow-Credentials: true\r\n'
+ "${origin != null ? 'Access-Control-Allow-Origin: $origin\r\n' : ''}"
+ '\r\n\r\n';
+
+class _SseMessage {
+ final int id;
+ final String message;
+ _SseMessage(this.id, this.message);
+}
+
+/// A bi-directional SSE connection between server and browser.
+class SseConnection extends StreamChannelMixin<String> {
+ /// Incoming messages from the Browser client.
+ final _incomingController = StreamController<String>();
+
+ /// Outgoing messages to the Browser client.
+ final _outgoingController = StreamController<String>();
+
+ Sink _sink;
+
+ /// How long to wait after a connection drops before considering it closed.
+ final Duration? _keepAlive;
+
+ /// A timer counting down the KeepAlive period (null if hasn't disconnected).
+ Timer? _keepAliveTimer;
+
+ /// Whether this connection is currently in the KeepAlive timeout period.
+ bool get isInKeepAlivePeriod => _keepAliveTimer?.isActive ?? false;
+
+ /// The id of the last processed incoming message.
+ int _lastProcessedId = -1;
+
+ /// Incoming messages that have yet to be processed.
+ final _pendingMessages =
+ HeapPriorityQueue<_SseMessage>((a, b) => a.id.compareTo(b.id));
+
+ final _closedCompleter = Completer<void>();
+
+ /// Wraps the `_outgoingController.stream` to buffer events to enable keep
+ /// alive.
+ late StreamQueue _outgoingStreamQueue;
+
+ /// Creates an [SseConnection] for the supplied [_sink].
+ ///
+ /// If [keepAlive] is supplied, the connection will remain active for this
+ /// period after a disconnect and can be reconnected transparently. If there
+ /// is no reconnect within that period, the connection will be closed
+ /// normally.
+ ///
+ /// If [keepAlive] is not supplied, the connection will be closed immediately
+ /// after a disconnect.
+ SseConnection(this._sink, {Duration? keepAlive}) : _keepAlive = keepAlive {
+ _outgoingStreamQueue = StreamQueue(_outgoingController.stream);
+ unawaited(_setUpListener());
+ _outgoingController.onCancel = _close;
+ _incomingController.onCancel = _close;
+ }
+
+ Future<void> _setUpListener() async {
+ while (
+ !_outgoingController.isClosed && await _outgoingStreamQueue.hasNext) {
+ // If we're in a KeepAlive timeout, there's nowhere to send messages so
+ // wait a short period and check again.
+ if (isInKeepAlivePeriod) {
+ await Future<void>.delayed(const Duration(milliseconds: 200));
+ continue;
+ }
+
+ // Peek the data so we don't remove it from the stream if we're unable to
+ // send it.
+ final data = await _outgoingStreamQueue.peek;
+
+ // Ignore outgoing messages since the connection may have closed while
+ // waiting for the keep alive.
+ if (_closedCompleter.isCompleted) break;
+
+ try {
+ // JSON encode the message to escape new lines.
+ _sink.add('data: ${json.encode(data)}\n');
+ _sink.add('\n');
+ await _outgoingStreamQueue.next; // Consume from stream if no errors.
+ } catch (e) {
+ if ((e is StateError || e is SocketException) &&
+ (_keepAlive != null && !_closedCompleter.isCompleted)) {
+ // If we got here then the sink may have closed but the stream.onDone
+ // hasn't fired yet, so pause the subscription and skip calling
+ // `next` so the message remains in the queue to try again.
+ _handleDisconnect();
+ } else {
+ rethrow;
+ }
+ }
+ }
+ }
+
+ /// The message added to the sink has to be JSON encodable.
+ @override
+ StreamSink<String> get sink => _outgoingController.sink;
+
+ // Add messages to this [StreamSink] to send them to the server.
+ /// [Stream] of messages sent from the server to this client.
+ ///
+ /// A message is a decoded JSON object.
+ @override
+ Stream<String> get stream => _incomingController.stream;
+
+ /// Adds an incoming [message] to the [stream].
+ ///
+ /// This will buffer messages to guarantee order.
+ void _addIncomingMessage(int id, String message) {
+ _pendingMessages.add(_SseMessage(id, message));
+ while (_pendingMessages.isNotEmpty) {
+ var pendingMessage = _pendingMessages.first;
+ // Only process the next incremental message.
+ if (pendingMessage.id - _lastProcessedId <= 1) {
+ _incomingController.sink.add(pendingMessage.message);
+ _lastProcessedId = pendingMessage.id;
+ _pendingMessages.removeFirst();
+ } else {
+ // A message came out of order. Wait until we receive the previous
+ // messages to process.
+ break;
+ }
+ }
+ }
+
+ void _acceptReconnection(Sink sink) {
+ _keepAliveTimer?.cancel();
+ _sink = sink;
+ }
+
+ void _handleDisconnect() {
+ if (_keepAlive == null) {
+ // Close immediately if we're not keeping alive.
+ _close();
+ } else if (!isInKeepAlivePeriod && !_closedCompleter.isCompleted) {
+ // Otherwise if we didn't already have an active timer and we've not
+ // already been completely closed, set a timer to close after the timeout
+ // period.
+ // If the connection comes back, this will be cancelled and all messages
+ // left in the queue tried again.
+ _keepAliveTimer = Timer(_keepAlive, _close);
+ }
+ }
+
+ void _close() {
+ if (!_closedCompleter.isCompleted) {
+ _closedCompleter.complete();
+ // Cancel any existing timer in case we were told to explicitly shut down
+ // to avoid keeping the process alive.
+ _keepAliveTimer?.cancel();
+ _sink.close();
+ if (!_outgoingController.isClosed) {
+ _outgoingStreamQueue.cancel(immediate: true);
+ _outgoingController.close();
+ }
+ if (!_incomingController.isClosed) _incomingController.close();
+ }
+ }
+
+ /// Immediately close the connection, ignoring any keepAlive period.
+ void shutdown() {
+ _close();
+ }
+}
+
+/// [SseHandler] handles requests on a user defined path to create
+/// two-way communications of JSON encodable data between server and clients.
+///
+/// A server sends messages to a client through an SSE channel, while
+/// a client sends message to a server through HTTP POST requests.
+class SseHandler {
+ final _logger = Logger('SseHandler');
+ final Uri _uri;
+ final Duration? _keepAlive;
+ final _connections = <String?, SseConnection>{};
+ final _connectionController = StreamController<SseConnection>();
+
+ StreamQueue<SseConnection>? _connectionsStream;
+
+ /// [_uri] is the URL under which the server is listening for
+ /// incoming bi-directional SSE connections.
+ ///
+ /// If [keepAlive] is supplied, connections will remain active for this
+ /// period after a disconnect and can be reconnected transparently. If there
+ /// is no reconnect within that period, the connection will be closed
+ /// normally.
+ ///
+ /// If [keepAlive] is not supplied, connections will be closed immediately
+ /// after a disconnect.
+ SseHandler(this._uri, {Duration? keepAlive}) : _keepAlive = keepAlive;
+
+ StreamQueue<SseConnection> get connections =>
+ _connectionsStream ??= StreamQueue(_connectionController.stream);
+
+ shelf.Handler get handler => _handle;
+
+ int get numberOfClients => _connections.length;
+
+ shelf.Response _createSseConnection(shelf.Request req, String path) {
+ req.hijack((channel) async {
+ var sink = utf8.encoder.startChunkedConversion(channel.sink);
+ sink.add(_sseHeaders(req.headers['origin']));
+ var clientId = req.url.queryParameters['sseClientId'];
+
+ // Check if we already have a connection for this ID that is in the
+ // process of timing out
+ // (in which case we can reconnect it transparently).
+ if (_connections[clientId] != null &&
+ _connections[clientId]!.isInKeepAlivePeriod) {
+ _connections[clientId]!._acceptReconnection(sink);
+ } else {
+ var connection = SseConnection(sink, keepAlive: _keepAlive);
+ _connections[clientId] = connection;
+ unawaited(connection._closedCompleter.future.then((_) {
+ _connections.remove(clientId);
+ }));
+ _connectionController.add(connection);
+ }
+ // Remove connection when it is remotely closed or the stream is
+ // cancelled.
+ channel.stream.listen((_) {
+ // SSE is unidirectional. Responses are handled through POST requests.
+ }, onDone: () {
+ _connections[clientId]?._handleDisconnect();
+ });
+ });
+ }
+
+ String _getOriginalPath(shelf.Request req) => req.requestedUri.path;
+
+ Future<shelf.Response> _handle(shelf.Request req) async {
+ var path = _getOriginalPath(req);
+ if (_uri.path != path) {
+ return shelf.Response.notFound('');
+ }
+
+ if (req.headers['accept'] == 'text/event-stream' && req.method == 'GET') {
+ return _createSseConnection(req, path);
+ }
+
+ if (req.headers['accept'] != 'text/event-stream' && req.method == 'POST') {
+ return _handleIncomingMessage(req, path);
+ }
+
+ return shelf.Response.notFound('');
+ }
+
+ Future<shelf.Response> _handleIncomingMessage(
+ shelf.Request req, String path) async {
+ String? clientId;
+ try {
+ clientId = req.url.queryParameters['sseClientId'];
+ var messageId = int.parse(req.url.queryParameters['messageId'] ?? '0');
+ var message = await req.readAsString();
+ var jsonObject = json.decode(message) as String;
+ _connections[clientId]?._addIncomingMessage(messageId, jsonObject);
+ } catch (e, st) {
+ _logger.fine('[$clientId] Failed to handle incoming message. $e $st');
+ }
+ return shelf.Response.ok('', headers: {
+ 'access-control-allow-credentials': 'true',
+ 'access-control-allow-origin': _originFor(req),
+ });
+ }
+
+ String _originFor(shelf.Request req) =>
+ // Firefox does not set header "origin".
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1508661
+ req.headers['origin'] ?? req.headers['host']!;
+
+ /// Immediately close all connections, ignoring any keepAlive periods.
+ void shutdown() {
+ for (final connection in _connections.values) {
+ connection.shutdown();
+ }
+ }
+}
+
+void closeSink(SseConnection connection) => connection._sink.close();
diff --git a/pkgs/sse/lib/src/util/uuid.dart b/pkgs/sse/lib/src/util/uuid.dart
new file mode 100644
index 0000000..a1aa398
--- /dev/null
+++ b/pkgs/sse/lib/src/util/uuid.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' show Random;
+
+/// Returns a unique ID in the format:
+///
+/// f47ac10b-58cc-4372-a567-0e02b2c3d479
+///
+/// The generated uuids are 128 bit numbers encoded in a specific string format.
+/// For more information, see
+/// [en.wikipedia.org/wiki/Universally_unique_identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier).
+String generateUuidV4() {
+ final random = Random();
+
+ int generateBits(int bitCount) => random.nextInt(1 << bitCount);
+
+ String printDigits(int value, int count) =>
+ value.toRadixString(16).padLeft(count, '0');
+ String bitsDigits(int bitCount, int digitCount) =>
+ printDigits(generateBits(bitCount), digitCount);
+
+ // Generate xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx / 8-4-4-4-12.
+ var special = 8 + random.nextInt(4);
+
+ return '${bitsDigits(16, 4)}${bitsDigits(16, 4)}-'
+ '${bitsDigits(16, 4)}-'
+ '4${bitsDigits(12, 3)}-'
+ '${printDigits(special, 1)}${bitsDigits(12, 3)}-'
+ '${bitsDigits(16, 4)}${bitsDigits(16, 4)}${bitsDigits(16, 4)}';
+}
diff --git a/pkgs/sse/pubspec.yaml b/pkgs/sse/pubspec.yaml
new file mode 100644
index 0000000..bd70f74
--- /dev/null
+++ b/pkgs/sse/pubspec.yaml
@@ -0,0 +1,25 @@
+name: sse
+version: 4.1.7
+description: >-
+ Provides client and server functionality for setting up bi-directional
+ communication through Server Sent Events (SSE) and corresponding POST
+ requests.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/sse
+
+environment:
+ sdk: ^3.3.0
+
+dependencies:
+ async: ^2.0.8
+ collection: ^1.0.0
+ logging: ^1.0.0
+ pool: ^1.5.0
+ shelf: ^1.1.0
+ stream_channel: ^2.0.0
+ web: '>=0.5.0 <2.0.0'
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ shelf_static: ^1.0.0
+ test: ^1.16.6
+ webdriver: ^3.0.0
diff --git a/pkgs/sse/test/sse_test.dart b/pkgs/sse/test/sse_test.dart
new file mode 100644
index 0000000..0455baa
--- /dev/null
+++ b/pkgs/sse/test/sse_test.dart
@@ -0,0 +1,270 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:async/async.dart';
+import 'package:shelf/shelf.dart' as shelf;
+import 'package:shelf/shelf_io.dart' as io;
+import 'package:shelf_static/shelf_static.dart';
+import 'package:sse/server/sse_handler.dart';
+import 'package:sse/src/server/sse_handler.dart' show closeSink;
+import 'package:test/test.dart';
+import 'package:webdriver/async_io.dart';
+
+void main() {
+ late HttpServer server;
+ late WebDriver webdriver;
+ late SseHandler handler;
+ late Process chromeDriver;
+
+ setUpAll(() async {
+ try {
+ chromeDriver = await Process.start(
+ 'chromedriver', ['--port=4444', '--url-base=wd/hub']);
+ } catch (e) {
+ throw StateError(
+ 'Could not start ChromeDriver. Is it installed?\nError: $e');
+ }
+ });
+
+ tearDownAll(() {
+ chromeDriver.kill();
+ });
+
+ group('SSE', () {
+ setUp(() async {
+ handler = SseHandler(Uri.parse('/test'));
+
+ var cascade = shelf.Cascade()
+ .add(handler.handler)
+ .add(_faviconHandler)
+ .add(createStaticHandler('test/web',
+ listDirectories: true, defaultDocument: 'index.html'));
+
+ server = await io.serve(cascade.handler, 'localhost', 0);
+ var capabilities = Capabilities.chrome
+ ..addAll({
+ Capabilities.chromeOptions: {
+ 'args': ['--headless']
+ }
+ });
+ webdriver = await createDriver(desired: capabilities);
+ });
+
+ tearDown(() async {
+ await webdriver.quit();
+ await server.close();
+ });
+
+ test('can round trip messages', () async {
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ connection.sink.add('blah');
+ expect(await connection.stream.first, 'blah');
+ });
+
+ test('can send a significant number of requests', () async {
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ var limit = 7000;
+ for (var i = 0; i < limit; i++) {
+ connection.sink.add('$i');
+ }
+ await connection.stream.take(limit).drain<void>();
+ });
+
+ test('messages arrive in-order', () async {
+ expect(handler.numberOfClients, 0);
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ expect(handler.numberOfClients, 1);
+
+ var expected = <String>[];
+ var count = 100;
+ for (var i = 0; i < count; i++) {
+ expected.add(i.toString());
+ }
+ connection.sink.add('send $count');
+
+ expect(await connection.stream.take(count).toList(), equals(expected));
+ });
+
+ test('multiple clients can connect', () async {
+ var connections = handler.connections;
+ await webdriver.get('http://localhost:${server.port}');
+ await connections.next;
+ await webdriver.get('http://localhost:${server.port}');
+ await connections.next;
+ });
+
+ test('routes data correctly', () async {
+ var connections = handler.connections;
+ await webdriver.get('http://localhost:${server.port}');
+ var connectionA = await connections.next;
+ connectionA.sink.add('foo');
+ expect(await connectionA.stream.first, 'foo');
+
+ await webdriver.get('http://localhost:${server.port}');
+ var connectionB = await connections.next;
+ connectionB.sink.add('bar');
+ expect(await connectionB.stream.first, 'bar');
+ });
+
+ test('can close from the server', () async {
+ expect(handler.numberOfClients, 0);
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ expect(handler.numberOfClients, 1);
+ await connection.sink.close();
+ await pumpEventQueue();
+ expect(handler.numberOfClients, 0);
+ });
+
+ test('client reconnects after being disconnected', () async {
+ expect(handler.numberOfClients, 0);
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ expect(handler.numberOfClients, 1);
+ await connection.sink.close();
+ await pumpEventQueue();
+ expect(handler.numberOfClients, 0);
+
+ // Ensure the client reconnects
+ await handler.connections.next;
+ });
+
+ test('can close from the client-side', () async {
+ expect(handler.numberOfClients, 0);
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ expect(handler.numberOfClients, 1);
+
+ var closeButton = await webdriver.findElement(const By.tagName('button'));
+ await closeButton.click();
+
+ // Should complete since the connection is closed.
+ await connection.stream.drain<void>();
+ expect(handler.numberOfClients, 0);
+ });
+
+ test('cancelling the listener closes the connection', () async {
+ expect(handler.numberOfClients, 0);
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ expect(handler.numberOfClients, 1);
+
+ var sub = connection.stream.listen((_) {});
+ await sub.cancel();
+ await pumpEventQueue();
+ expect(handler.numberOfClients, 0);
+ });
+
+ test('disconnects when navigating away', () async {
+ await webdriver.get('http://localhost:${server.port}');
+ expect(handler.numberOfClients, 1);
+
+ await webdriver.get('chrome://version/');
+ expect(handler.numberOfClients, 0);
+ });
+ });
+
+ group('SSE with server keep-alive', () {
+ setUp(() async {
+ handler =
+ SseHandler(Uri.parse('/test'), keepAlive: const Duration(seconds: 5));
+
+ var cascade = shelf.Cascade()
+ .add(handler.handler)
+ .add(_faviconHandler)
+ .add(createStaticHandler('test/web',
+ listDirectories: true, defaultDocument: 'index.html'));
+
+ server = await io.serve(cascade.handler, 'localhost', 0);
+ var capabilities = Capabilities.chrome
+ ..addAll({
+ Capabilities.chromeOptions: {
+ 'args': ['--headless']
+ }
+ });
+ webdriver = await createDriver(desired: capabilities);
+ });
+
+ tearDown(() async {
+ await webdriver.quit();
+ await server.close();
+ });
+
+ test('client reconnect use the same connection', () async {
+ expect(handler.numberOfClients, 0);
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ expect(handler.numberOfClients, 1);
+
+ // Close the underlying connection.
+ closeSink(connection);
+ // Ensure we can still round-trip data on the original connection and that
+ // the connection is no longer marked keep-alive once it's reconnected.
+ connection.sink.add('bar');
+ var queue = StreamQueue(connection.stream);
+ expect(await queue.next, 'bar');
+
+ // Now check that we can reconnect multiple times.
+ closeSink(connection);
+ connection.sink.add('bar');
+ expect(await queue.next, 'bar');
+ expect(handler.numberOfClients, 1);
+ });
+
+ test('messages sent during disconnect arrive in-order', () async {
+ expect(handler.numberOfClients, 0);
+ await webdriver.get('http://localhost:${server.port}');
+ var connection = await handler.connections.next;
+ expect(handler.numberOfClients, 1);
+
+ // Close the underlying connection.
+ closeSink(connection);
+ connection.sink.add('one');
+ connection.sink.add('two');
+ await pumpEventQueue();
+
+ // Ensure there's still a connection.
+ expect(handler.numberOfClients, 1);
+
+ // Ensure messages arrive in the same order
+ expect(await connection.stream.take(2).toList(), equals(['one', 'two']));
+ });
+
+ test('explicit shutdown does not wait for keepAlive', () async {
+ expect(handler.numberOfClients, 0);
+ await webdriver.get('http://localhost:${server.port}');
+ await handler.connections.next;
+ expect(handler.numberOfClients, 1);
+
+ // Close the underlying connection.
+ handler.shutdown();
+
+ // Wait for a short period to allow the connection to close, but not
+ // long enough that the 30second keep-alive may have expired.
+ var maxPumps = 50;
+ while (handler.numberOfClients > 0 && maxPumps-- > 0) {
+ await pumpEventQueue(times: 1);
+ }
+
+ // Ensure there are not connected clients.
+ expect(handler.numberOfClients, 0);
+ });
+ }, timeout: const Timeout(Duration(seconds: 120)));
+}
+
+FutureOr<shelf.Response> _faviconHandler(shelf.Request request) {
+ if (request.url.path.endsWith('favicon.ico')) {
+ return shelf.Response.ok('');
+ }
+ return shelf.Response.notFound('');
+}
diff --git a/pkgs/sse/test/web/index.dart b/pkgs/sse/test/web/index.dart
new file mode 100644
index 0000000..c4d78cd
--- /dev/null
+++ b/pkgs/sse/test/web/index.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:sse/client/sse_client.dart';
+import 'package:web/web.dart';
+
+void main() {
+ var channel = SseClient('/test');
+
+ document.querySelector('button')!.onClick.listen((_) {
+ channel.sink.close();
+ });
+
+ channel.stream.listen((s) {
+ if (s.startsWith('send ')) {
+ var count = int.parse(s.split(' ').last);
+ for (var i = 0; i < count; i++) {
+ channel.sink.add('$i');
+ }
+ } else {
+ channel.sink.add(s);
+ }
+ });
+}
diff --git a/pkgs/sse/test/web/index.dart.js b/pkgs/sse/test/web/index.dart.js
new file mode 100644
index 0000000..e1b37b9
--- /dev/null
+++ b/pkgs/sse/test/web/index.dart.js
@@ -0,0 +1,8851 @@
+// Generated by dart2js (NullSafetyMode.sound, csp, intern-composite-values), the Dart to JavaScript compiler version: 3.4.0-157.0.dev.
+// The code supports the following hooks:
+// dartPrint(message):
+// if this function is defined it is called instead of the Dart [print]
+// method.
+//
+// dartMainRunner(main, args):
+// if this function is defined, the Dart [main] method will not be invoked
+// directly. Instead, a closure that will invoke [main], and its arguments
+// [args] is passed to [dartMainRunner].
+//
+// dartDeferredLibraryLoader(uri, successCallback, errorCallback, loadId, loadPriority):
+// if this function is defined, it will be called when a deferred library
+// is loaded. It should load and eval the javascript of `uri`, and call
+// successCallback. If it fails to do so, it should call errorCallback with
+// an error. The loadId argument is the deferred import that resulted in
+// this uri being loaded. The loadPriority argument is the priority the
+// library should be loaded with as specified in the code via the
+// load-priority annotation (0: normal, 1: high).
+// dartDeferredLibraryMultiLoader(uris, successCallback, errorCallback, loadId, loadPriority):
+// if this function is defined, it will be called when a deferred library
+// is loaded. It should load and eval the javascript of every URI in `uris`,
+// and call successCallback. If it fails to do so, it should call
+// errorCallback with an error. The loadId argument is the deferred import
+// that resulted in this uri being loaded. The loadPriority argument is the
+// priority the library should be loaded with as specified in the code via
+// the load-priority annotation (0: normal, 1: high).
+//
+// dartCallInstrumentation(id, qualifiedName):
+// if this function is defined, it will be called at each entry of a
+// method or constructor. Used only when compiling programs with
+// --experiment-call-instrumentation.
+(function dartProgram() {
+ function copyProperties(from, to) {
+ var keys = Object.keys(from);
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ to[key] = from[key];
+ }
+ }
+ function mixinPropertiesHard(from, to) {
+ var keys = Object.keys(from);
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ if (!to.hasOwnProperty(key)) {
+ to[key] = from[key];
+ }
+ }
+ }
+ function mixinPropertiesEasy(from, to) {
+ Object.assign(to, from);
+ }
+ var supportsDirectProtoAccess = function() {
+ var cls = function() {
+ };
+ cls.prototype = {p: {}};
+ var object = new cls();
+ if (!(Object.getPrototypeOf(object) && Object.getPrototypeOf(object).p === cls.prototype.p))
+ return false;
+ try {
+ if (typeof navigator != "undefined" && typeof navigator.userAgent == "string" && navigator.userAgent.indexOf("Chrome/") >= 0)
+ return true;
+ if (typeof version == "function" && version.length == 0) {
+ var v = version();
+ if (/^\d+\.\d+\.\d+\.\d+$/.test(v))
+ return true;
+ }
+ } catch (_) {
+ }
+ return false;
+ }();
+ function inherit(cls, sup) {
+ cls.prototype.constructor = cls;
+ cls.prototype["$is" + cls.name] = cls;
+ if (sup != null) {
+ if (supportsDirectProtoAccess) {
+ Object.setPrototypeOf(cls.prototype, sup.prototype);
+ return;
+ }
+ var clsPrototype = Object.create(sup.prototype);
+ copyProperties(cls.prototype, clsPrototype);
+ cls.prototype = clsPrototype;
+ }
+ }
+ function inheritMany(sup, classes) {
+ for (var i = 0; i < classes.length; i++) {
+ inherit(classes[i], sup);
+ }
+ }
+ function mixinEasy(cls, mixin) {
+ mixinPropertiesEasy(mixin.prototype, cls.prototype);
+ cls.prototype.constructor = cls;
+ }
+ function mixinHard(cls, mixin) {
+ mixinPropertiesHard(mixin.prototype, cls.prototype);
+ cls.prototype.constructor = cls;
+ }
+ function lazy(holder, name, getterName, initializer) {
+ var uninitializedSentinel = holder;
+ holder[name] = uninitializedSentinel;
+ holder[getterName] = function() {
+ if (holder[name] === uninitializedSentinel) {
+ holder[name] = initializer();
+ }
+ holder[getterName] = function() {
+ return this[name];
+ };
+ return holder[name];
+ };
+ }
+ function lazyFinal(holder, name, getterName, initializer) {
+ var uninitializedSentinel = holder;
+ holder[name] = uninitializedSentinel;
+ holder[getterName] = function() {
+ if (holder[name] === uninitializedSentinel) {
+ var value = initializer();
+ if (holder[name] !== uninitializedSentinel) {
+ A.throwLateFieldADI(name);
+ }
+ holder[name] = value;
+ }
+ var finalValue = holder[name];
+ holder[getterName] = function() {
+ return finalValue;
+ };
+ return finalValue;
+ };
+ }
+ function makeConstList(list) {
+ list.immutable$list = Array;
+ list.fixed$length = Array;
+ return list;
+ }
+ function convertToFastObject(properties) {
+ function t() {
+ }
+ t.prototype = properties;
+ new t();
+ return properties;
+ }
+ function convertAllToFastObject(arrayOfObjects) {
+ for (var i = 0; i < arrayOfObjects.length; ++i) {
+ convertToFastObject(arrayOfObjects[i]);
+ }
+ }
+ var functionCounter = 0;
+ function instanceTearOffGetter(isIntercepted, parameters) {
+ var cache = null;
+ return isIntercepted ? function(receiver) {
+ if (cache === null)
+ cache = A.closureFromTearOff(parameters);
+ return new cache(receiver, this);
+ } : function() {
+ if (cache === null)
+ cache = A.closureFromTearOff(parameters);
+ return new cache(this, null);
+ };
+ }
+ function staticTearOffGetter(parameters) {
+ var cache = null;
+ return function() {
+ if (cache === null)
+ cache = A.closureFromTearOff(parameters).prototype;
+ return cache;
+ };
+ }
+ var typesOffset = 0;
+ function tearOffParameters(container, isStatic, isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex, needsDirectAccess) {
+ if (typeof funType == "number") {
+ funType += typesOffset;
+ }
+ return {co: container, iS: isStatic, iI: isIntercepted, rC: requiredParameterCount, dV: optionalParameterDefaultValues, cs: callNames, fs: funsOrNames, fT: funType, aI: applyIndex || 0, nDA: needsDirectAccess};
+ }
+ function installStaticTearOff(holder, getterName, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex) {
+ var parameters = tearOffParameters(holder, true, false, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex, false);
+ var getterFunction = staticTearOffGetter(parameters);
+ holder[getterName] = getterFunction;
+ }
+ function installInstanceTearOff(prototype, getterName, isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex, needsDirectAccess) {
+ isIntercepted = !!isIntercepted;
+ var parameters = tearOffParameters(prototype, false, isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, funsOrNames, funType, applyIndex, !!needsDirectAccess);
+ var getterFunction = instanceTearOffGetter(isIntercepted, parameters);
+ prototype[getterName] = getterFunction;
+ }
+ function setOrUpdateInterceptorsByTag(newTags) {
+ var tags = init.interceptorsByTag;
+ if (!tags) {
+ init.interceptorsByTag = newTags;
+ return;
+ }
+ copyProperties(newTags, tags);
+ }
+ function setOrUpdateLeafTags(newTags) {
+ var tags = init.leafTags;
+ if (!tags) {
+ init.leafTags = newTags;
+ return;
+ }
+ copyProperties(newTags, tags);
+ }
+ function updateTypes(newTypes) {
+ var types = init.types;
+ var length = types.length;
+ types.push.apply(types, newTypes);
+ return length;
+ }
+ function updateHolder(holder, newHolder) {
+ copyProperties(newHolder, holder);
+ return holder;
+ }
+ var hunkHelpers = function() {
+ var mkInstance = function(isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, applyIndex) {
+ return function(container, getterName, name, funType) {
+ return installInstanceTearOff(container, getterName, isIntercepted, requiredParameterCount, optionalParameterDefaultValues, callNames, [name], funType, applyIndex, false);
+ };
+ },
+ mkStatic = function(requiredParameterCount, optionalParameterDefaultValues, callNames, applyIndex) {
+ return function(container, getterName, name, funType) {
+ return installStaticTearOff(container, getterName, requiredParameterCount, optionalParameterDefaultValues, callNames, [name], funType, applyIndex);
+ };
+ };
+ return {inherit: inherit, inheritMany: inheritMany, mixin: mixinEasy, mixinHard: mixinHard, installStaticTearOff: installStaticTearOff, installInstanceTearOff: installInstanceTearOff, _instance_0u: mkInstance(0, 0, null, ["call$0"], 0), _instance_1u: mkInstance(0, 1, null, ["call$1"], 0), _instance_2u: mkInstance(0, 2, null, ["call$2"], 0), _instance_0i: mkInstance(1, 0, null, ["call$0"], 0), _instance_1i: mkInstance(1, 1, null, ["call$1"], 0), _instance_2i: mkInstance(1, 2, null, ["call$2"], 0), _static_0: mkStatic(0, null, ["call$0"], 0), _static_1: mkStatic(1, null, ["call$1"], 0), _static_2: mkStatic(2, null, ["call$2"], 0), makeConstList: makeConstList, lazy: lazy, lazyFinal: lazyFinal, updateHolder: updateHolder, convertToFastObject: convertToFastObject, updateTypes: updateTypes, setOrUpdateInterceptorsByTag: setOrUpdateInterceptorsByTag, setOrUpdateLeafTags: setOrUpdateLeafTags};
+ }();
+ function initializeDeferredHunk(hunk) {
+ typesOffset = init.types.length;
+ hunk(hunkHelpers, init, holders, $);
+ }
+ var J = {
+ makeDispatchRecord(interceptor, proto, extension, indexability) {
+ return {i: interceptor, p: proto, e: extension, x: indexability};
+ },
+ getNativeInterceptor(object) {
+ var proto, objectProto, $constructor, interceptor, t1,
+ record = object[init.dispatchPropertyName];
+ if (record == null)
+ if ($.initNativeDispatchFlag == null) {
+ A.initNativeDispatch();
+ record = object[init.dispatchPropertyName];
+ }
+ if (record != null) {
+ proto = record.p;
+ if (false === proto)
+ return record.i;
+ if (true === proto)
+ return object;
+ objectProto = Object.getPrototypeOf(object);
+ if (proto === objectProto)
+ return record.i;
+ if (record.e === objectProto)
+ throw A.wrapException(A.UnimplementedError$("Return interceptor for " + A.S(proto(object, record))));
+ }
+ $constructor = object.constructor;
+ if ($constructor == null)
+ interceptor = null;
+ else {
+ t1 = $._JS_INTEROP_INTERCEPTOR_TAG;
+ if (t1 == null)
+ t1 = $._JS_INTEROP_INTERCEPTOR_TAG = init.getIsolateTag("_$dart_js");
+ interceptor = $constructor[t1];
+ }
+ if (interceptor != null)
+ return interceptor;
+ interceptor = A.lookupAndCacheInterceptor(object);
+ if (interceptor != null)
+ return interceptor;
+ if (typeof object == "function")
+ return B.JavaScriptFunction_methods;
+ proto = Object.getPrototypeOf(object);
+ if (proto == null)
+ return B.PlainJavaScriptObject_methods;
+ if (proto === Object.prototype)
+ return B.PlainJavaScriptObject_methods;
+ if (typeof $constructor == "function") {
+ t1 = $._JS_INTEROP_INTERCEPTOR_TAG;
+ if (t1 == null)
+ t1 = $._JS_INTEROP_INTERCEPTOR_TAG = init.getIsolateTag("_$dart_js");
+ Object.defineProperty($constructor, t1, {value: B.UnknownJavaScriptObject_methods, enumerable: false, writable: true, configurable: true});
+ return B.UnknownJavaScriptObject_methods;
+ }
+ return B.UnknownJavaScriptObject_methods;
+ },
+ JSArray_JSArray$fixed($length, $E) {
+ if ($length < 0 || $length > 4294967295)
+ throw A.wrapException(A.RangeError$range($length, 0, 4294967295, "length", null));
+ return J.JSArray_JSArray$markFixed(new Array($length), $E);
+ },
+ JSArray_JSArray$growable($length, $E) {
+ if ($length < 0)
+ throw A.wrapException(A.ArgumentError$("Length must be a non-negative integer: " + $length, null));
+ return A._setArrayType(new Array($length), $E._eval$1("JSArray<0>"));
+ },
+ JSArray_JSArray$markFixed(allocation, $E) {
+ return J.JSArray_markFixedList(A._setArrayType(allocation, $E._eval$1("JSArray<0>")), $E);
+ },
+ JSArray_markFixedList(list, $T) {
+ list.fixed$length = Array;
+ return list;
+ },
+ JSArray_markUnmodifiableList(list) {
+ list.fixed$length = Array;
+ list.immutable$list = Array;
+ return list;
+ },
+ getInterceptor$(receiver) {
+ if (typeof receiver == "number") {
+ if (Math.floor(receiver) == receiver)
+ return J.JSInt.prototype;
+ return J.JSNumNotInt.prototype;
+ }
+ if (typeof receiver == "string")
+ return J.JSString.prototype;
+ if (receiver == null)
+ return J.JSNull.prototype;
+ if (typeof receiver == "boolean")
+ return J.JSBool.prototype;
+ if (Array.isArray(receiver))
+ return J.JSArray.prototype;
+ if (typeof receiver != "object") {
+ if (typeof receiver == "function")
+ return J.JavaScriptFunction.prototype;
+ if (typeof receiver == "symbol")
+ return J.JavaScriptSymbol.prototype;
+ if (typeof receiver == "bigint")
+ return J.JavaScriptBigInt.prototype;
+ return receiver;
+ }
+ if (receiver instanceof A.Object)
+ return receiver;
+ return J.getNativeInterceptor(receiver);
+ },
+ getInterceptor$asx(receiver) {
+ if (typeof receiver == "string")
+ return J.JSString.prototype;
+ if (receiver == null)
+ return receiver;
+ if (Array.isArray(receiver))
+ return J.JSArray.prototype;
+ if (typeof receiver != "object") {
+ if (typeof receiver == "function")
+ return J.JavaScriptFunction.prototype;
+ if (typeof receiver == "symbol")
+ return J.JavaScriptSymbol.prototype;
+ if (typeof receiver == "bigint")
+ return J.JavaScriptBigInt.prototype;
+ return receiver;
+ }
+ if (receiver instanceof A.Object)
+ return receiver;
+ return J.getNativeInterceptor(receiver);
+ },
+ getInterceptor$ax(receiver) {
+ if (receiver == null)
+ return receiver;
+ if (Array.isArray(receiver))
+ return J.JSArray.prototype;
+ if (typeof receiver != "object") {
+ if (typeof receiver == "function")
+ return J.JavaScriptFunction.prototype;
+ if (typeof receiver == "symbol")
+ return J.JavaScriptSymbol.prototype;
+ if (typeof receiver == "bigint")
+ return J.JavaScriptBigInt.prototype;
+ return receiver;
+ }
+ if (receiver instanceof A.Object)
+ return receiver;
+ return J.getNativeInterceptor(receiver);
+ },
+ getInterceptor$s(receiver) {
+ if (typeof receiver == "string")
+ return J.JSString.prototype;
+ if (receiver == null)
+ return receiver;
+ if (!(receiver instanceof A.Object))
+ return J.UnknownJavaScriptObject.prototype;
+ return receiver;
+ },
+ get$hashCode$(receiver) {
+ return J.getInterceptor$(receiver).get$hashCode(receiver);
+ },
+ get$iterator$ax(receiver) {
+ return J.getInterceptor$ax(receiver).get$iterator(receiver);
+ },
+ get$length$asx(receiver) {
+ return J.getInterceptor$asx(receiver).get$length(receiver);
+ },
+ get$runtimeType$(receiver) {
+ return J.getInterceptor$(receiver).get$runtimeType(receiver);
+ },
+ $eq$(receiver, a0) {
+ if (receiver == null)
+ return a0 == null;
+ if (typeof receiver != "object")
+ return a0 != null && receiver === a0;
+ return J.getInterceptor$(receiver).$eq(receiver, a0);
+ },
+ matchAsPrefix$2$s(receiver, a0, a1) {
+ return J.getInterceptor$s(receiver).matchAsPrefix$2(receiver, a0, a1);
+ },
+ noSuchMethod$1$(receiver, a0) {
+ return J.getInterceptor$(receiver).noSuchMethod$1(receiver, a0);
+ },
+ toString$0$(receiver) {
+ return J.getInterceptor$(receiver).toString$0(receiver);
+ },
+ Interceptor: function Interceptor() {
+ },
+ JSBool: function JSBool() {
+ },
+ JSNull: function JSNull() {
+ },
+ JavaScriptObject: function JavaScriptObject() {
+ },
+ LegacyJavaScriptObject: function LegacyJavaScriptObject() {
+ },
+ PlainJavaScriptObject: function PlainJavaScriptObject() {
+ },
+ UnknownJavaScriptObject: function UnknownJavaScriptObject() {
+ },
+ JavaScriptFunction: function JavaScriptFunction() {
+ },
+ JavaScriptBigInt: function JavaScriptBigInt() {
+ },
+ JavaScriptSymbol: function JavaScriptSymbol() {
+ },
+ JSArray: function JSArray(t0) {
+ this.$ti = t0;
+ },
+ JSUnmodifiableArray: function JSUnmodifiableArray(t0) {
+ this.$ti = t0;
+ },
+ ArrayIterator: function ArrayIterator(t0, t1, t2) {
+ var _ = this;
+ _._iterable = t0;
+ _._length = t1;
+ _._index = 0;
+ _._current = null;
+ _.$ti = t2;
+ },
+ JSNumber: function JSNumber() {
+ },
+ JSInt: function JSInt() {
+ },
+ JSNumNotInt: function JSNumNotInt() {
+ },
+ JSString: function JSString() {
+ }
+ },
+ A = {JS_CONST: function JS_CONST() {
+ },
+ checkNotNullable(value, $name, $T) {
+ return value;
+ },
+ isToStringVisiting(object) {
+ var t1, i;
+ for (t1 = $.toStringVisiting.length, i = 0; i < t1; ++i)
+ if (object === $.toStringVisiting[i])
+ return true;
+ return false;
+ },
+ IterableElementError_noElement() {
+ return new A.StateError("No element");
+ },
+ IterableElementError_tooFew() {
+ return new A.StateError("Too few elements");
+ },
+ LateError: function LateError(t0) {
+ this._message = t0;
+ },
+ nullFuture_closure: function nullFuture_closure() {
+ },
+ EfficientLengthIterable: function EfficientLengthIterable() {
+ },
+ ListIterable: function ListIterable() {
+ },
+ ListIterator: function ListIterator(t0, t1, t2) {
+ var _ = this;
+ _.__internal$_iterable = t0;
+ _.__internal$_length = t1;
+ _.__internal$_index = 0;
+ _.__internal$_current = null;
+ _.$ti = t2;
+ },
+ FixedLengthListMixin: function FixedLengthListMixin() {
+ },
+ Symbol: function Symbol(t0) {
+ this._name = t0;
+ },
+ unminifyOrTag(rawClassName) {
+ var preserved = init.mangledGlobalNames[rawClassName];
+ if (preserved != null)
+ return preserved;
+ return rawClassName;
+ },
+ isJsIndexable(object, record) {
+ var result;
+ if (record != null) {
+ result = record.x;
+ if (result != null)
+ return result;
+ }
+ return type$.JavaScriptIndexingBehavior_dynamic._is(object);
+ },
+ S(value) {
+ var result;
+ if (typeof value == "string")
+ return value;
+ if (typeof value == "number") {
+ if (value !== 0)
+ return "" + value;
+ } else if (true === value)
+ return "true";
+ else if (false === value)
+ return "false";
+ else if (value == null)
+ return "null";
+ result = J.toString$0$(value);
+ return result;
+ },
+ Primitives_objectHashCode(object) {
+ var hash,
+ property = $.Primitives__identityHashCodeProperty;
+ if (property == null)
+ property = $.Primitives__identityHashCodeProperty = Symbol("identityHashCode");
+ hash = object[property];
+ if (hash == null) {
+ hash = Math.random() * 0x3fffffff | 0;
+ object[property] = hash;
+ }
+ return hash;
+ },
+ Primitives_parseInt(source, radix) {
+ var decimalMatch, maxCharCode, digitsPart, t1, i, _null = null,
+ match = /^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i.exec(source);
+ if (match == null)
+ return _null;
+ if (3 >= match.length)
+ return A.ioore(match, 3);
+ decimalMatch = match[3];
+ if (radix == null) {
+ if (decimalMatch != null)
+ return parseInt(source, 10);
+ if (match[2] != null)
+ return parseInt(source, 16);
+ return _null;
+ }
+ if (radix < 2 || radix > 36)
+ throw A.wrapException(A.RangeError$range(radix, 2, 36, "radix", _null));
+ if (radix === 10 && decimalMatch != null)
+ return parseInt(source, 10);
+ if (radix < 10 || decimalMatch == null) {
+ maxCharCode = radix <= 10 ? 47 + radix : 86 + radix;
+ digitsPart = match[1];
+ for (t1 = digitsPart.length, i = 0; i < t1; ++i)
+ if ((digitsPart.charCodeAt(i) | 32) > maxCharCode)
+ return _null;
+ }
+ return parseInt(source, radix);
+ },
+ Primitives_objectTypeName(object) {
+ return A.Primitives__objectTypeNameNewRti(object);
+ },
+ Primitives__objectTypeNameNewRti(object) {
+ var interceptor, dispatchName, $constructor, constructorName;
+ if (object instanceof A.Object)
+ return A._rtiToString(A.instanceType(object), null);
+ interceptor = J.getInterceptor$(object);
+ if (interceptor === B.Interceptor_methods || interceptor === B.JavaScriptObject_methods || type$.UnknownJavaScriptObject._is(object)) {
+ dispatchName = B.C_JS_CONST(object);
+ if (dispatchName !== "Object" && dispatchName !== "")
+ return dispatchName;
+ $constructor = object.constructor;
+ if (typeof $constructor == "function") {
+ constructorName = $constructor.name;
+ if (typeof constructorName == "string" && constructorName !== "Object" && constructorName !== "")
+ return constructorName;
+ }
+ }
+ return A._rtiToString(A.instanceType(object), null);
+ },
+ Primitives_safeToString(object) {
+ if (typeof object == "number" || A._isBool(object))
+ return J.toString$0$(object);
+ if (typeof object == "string")
+ return JSON.stringify(object);
+ if (object instanceof A.Closure)
+ return object.toString$0(0);
+ return "Instance of '" + A.Primitives_objectTypeName(object) + "'";
+ },
+ Primitives_stringFromCharCode(charCode) {
+ var bits;
+ if (0 <= charCode) {
+ if (charCode <= 65535)
+ return String.fromCharCode(charCode);
+ if (charCode <= 1114111) {
+ bits = charCode - 65536;
+ return String.fromCharCode((B.JSInt_methods._shrOtherPositive$1(bits, 10) | 55296) >>> 0, bits & 1023 | 56320);
+ }
+ }
+ throw A.wrapException(A.RangeError$range(charCode, 0, 1114111, null, null));
+ },
+ Primitives_lazyAsJsDate(receiver) {
+ if (receiver.date === void 0)
+ receiver.date = new Date(receiver._value);
+ return receiver.date;
+ },
+ Primitives_getYear(receiver) {
+ return receiver.isUtc ? A.Primitives_lazyAsJsDate(receiver).getUTCFullYear() + 0 : A.Primitives_lazyAsJsDate(receiver).getFullYear() + 0;
+ },
+ Primitives_getMonth(receiver) {
+ return receiver.isUtc ? A.Primitives_lazyAsJsDate(receiver).getUTCMonth() + 1 : A.Primitives_lazyAsJsDate(receiver).getMonth() + 1;
+ },
+ Primitives_getDay(receiver) {
+ return receiver.isUtc ? A.Primitives_lazyAsJsDate(receiver).getUTCDate() + 0 : A.Primitives_lazyAsJsDate(receiver).getDate() + 0;
+ },
+ Primitives_getHours(receiver) {
+ return receiver.isUtc ? A.Primitives_lazyAsJsDate(receiver).getUTCHours() + 0 : A.Primitives_lazyAsJsDate(receiver).getHours() + 0;
+ },
+ Primitives_getMinutes(receiver) {
+ return receiver.isUtc ? A.Primitives_lazyAsJsDate(receiver).getUTCMinutes() + 0 : A.Primitives_lazyAsJsDate(receiver).getMinutes() + 0;
+ },
+ Primitives_getSeconds(receiver) {
+ return receiver.isUtc ? A.Primitives_lazyAsJsDate(receiver).getUTCSeconds() + 0 : A.Primitives_lazyAsJsDate(receiver).getSeconds() + 0;
+ },
+ Primitives_getMilliseconds(receiver) {
+ return receiver.isUtc ? A.Primitives_lazyAsJsDate(receiver).getUTCMilliseconds() + 0 : A.Primitives_lazyAsJsDate(receiver).getMilliseconds() + 0;
+ },
+ Primitives_functionNoSuchMethod($function, positionalArguments, namedArguments) {
+ var $arguments, namedArgumentList, t1 = {};
+ t1.argumentCount = 0;
+ $arguments = [];
+ namedArgumentList = [];
+ t1.argumentCount = positionalArguments.length;
+ B.JSArray_methods.addAll$1($arguments, positionalArguments);
+ t1.names = "";
+ if (namedArguments != null && namedArguments.__js_helper$_length !== 0)
+ namedArguments.forEach$1(0, new A.Primitives_functionNoSuchMethod_closure(t1, namedArgumentList, $arguments));
+ return J.noSuchMethod$1$($function, new A.JSInvocationMirror(B.Symbol_call, 0, $arguments, namedArgumentList, 0));
+ },
+ Primitives_applyFunction($function, positionalArguments, namedArguments) {
+ var t1, argumentCount, jsStub;
+ if (Array.isArray(positionalArguments))
+ t1 = namedArguments == null || namedArguments.__js_helper$_length === 0;
+ else
+ t1 = false;
+ if (t1) {
+ argumentCount = positionalArguments.length;
+ if (argumentCount === 0) {
+ if (!!$function.call$0)
+ return $function.call$0();
+ } else if (argumentCount === 1) {
+ if (!!$function.call$1)
+ return $function.call$1(positionalArguments[0]);
+ } else if (argumentCount === 2) {
+ if (!!$function.call$2)
+ return $function.call$2(positionalArguments[0], positionalArguments[1]);
+ } else if (argumentCount === 3) {
+ if (!!$function.call$3)
+ return $function.call$3(positionalArguments[0], positionalArguments[1], positionalArguments[2]);
+ } else if (argumentCount === 4) {
+ if (!!$function.call$4)
+ return $function.call$4(positionalArguments[0], positionalArguments[1], positionalArguments[2], positionalArguments[3]);
+ } else if (argumentCount === 5)
+ if (!!$function.call$5)
+ return $function.call$5(positionalArguments[0], positionalArguments[1], positionalArguments[2], positionalArguments[3], positionalArguments[4]);
+ jsStub = $function["call" + "$" + argumentCount];
+ if (jsStub != null)
+ return jsStub.apply($function, positionalArguments);
+ }
+ return A.Primitives__generalApplyFunction($function, positionalArguments, namedArguments);
+ },
+ Primitives__generalApplyFunction($function, positionalArguments, namedArguments) {
+ var defaultValuesClosure, t1, defaultValues, interceptor, jsFunction, maxArguments, missingDefaults, keys, _i, defaultValue, used, key,
+ $arguments = Array.isArray(positionalArguments) ? positionalArguments : A.List_List$of(positionalArguments, true, type$.dynamic),
+ argumentCount = $arguments.length,
+ requiredParameterCount = $function.$requiredArgCount;
+ if (argumentCount < requiredParameterCount)
+ return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
+ defaultValuesClosure = $function.$defaultValues;
+ t1 = defaultValuesClosure == null;
+ defaultValues = !t1 ? defaultValuesClosure() : null;
+ interceptor = J.getInterceptor$($function);
+ jsFunction = interceptor["call*"];
+ if (typeof jsFunction == "string")
+ jsFunction = interceptor[jsFunction];
+ if (t1) {
+ if (namedArguments != null && namedArguments.__js_helper$_length !== 0)
+ return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
+ if (argumentCount === requiredParameterCount)
+ return jsFunction.apply($function, $arguments);
+ return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
+ }
+ if (Array.isArray(defaultValues)) {
+ if (namedArguments != null && namedArguments.__js_helper$_length !== 0)
+ return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
+ maxArguments = requiredParameterCount + defaultValues.length;
+ if (argumentCount > maxArguments)
+ return A.Primitives_functionNoSuchMethod($function, $arguments, null);
+ if (argumentCount < maxArguments) {
+ missingDefaults = defaultValues.slice(argumentCount - requiredParameterCount);
+ if ($arguments === positionalArguments)
+ $arguments = A.List_List$of($arguments, true, type$.dynamic);
+ B.JSArray_methods.addAll$1($arguments, missingDefaults);
+ }
+ return jsFunction.apply($function, $arguments);
+ } else {
+ if (argumentCount > requiredParameterCount)
+ return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
+ if ($arguments === positionalArguments)
+ $arguments = A.List_List$of($arguments, true, type$.dynamic);
+ keys = Object.keys(defaultValues);
+ if (namedArguments == null)
+ for (t1 = keys.length, _i = 0; _i < keys.length; keys.length === t1 || (0, A.throwConcurrentModificationError)(keys), ++_i) {
+ defaultValue = defaultValues[A._asString(keys[_i])];
+ if (B.C__Required === defaultValue)
+ return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
+ B.JSArray_methods.add$1($arguments, defaultValue);
+ }
+ else {
+ for (t1 = keys.length, used = 0, _i = 0; _i < keys.length; keys.length === t1 || (0, A.throwConcurrentModificationError)(keys), ++_i) {
+ key = A._asString(keys[_i]);
+ if (namedArguments.containsKey$1(key)) {
+ ++used;
+ B.JSArray_methods.add$1($arguments, namedArguments.$index(0, key));
+ } else {
+ defaultValue = defaultValues[key];
+ if (B.C__Required === defaultValue)
+ return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
+ B.JSArray_methods.add$1($arguments, defaultValue);
+ }
+ }
+ if (used !== namedArguments.__js_helper$_length)
+ return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
+ }
+ return jsFunction.apply($function, $arguments);
+ }
+ },
+ ioore(receiver, index) {
+ if (receiver == null)
+ J.get$length$asx(receiver);
+ throw A.wrapException(A.diagnoseIndexError(receiver, index));
+ },
+ diagnoseIndexError(indexable, index) {
+ var $length, _s5_ = "index";
+ if (!A._isInt(index))
+ return new A.ArgumentError(true, index, _s5_, null);
+ $length = A._asInt(J.get$length$asx(indexable));
+ if (index < 0 || index >= $length)
+ return A.IndexError$withLength(index, $length, indexable, null, _s5_);
+ return A.RangeError$value(index, _s5_);
+ },
+ wrapException(ex) {
+ return A.initializeExceptionWrapper(new Error(), ex);
+ },
+ initializeExceptionWrapper(wrapper, ex) {
+ var t1;
+ if (ex == null)
+ ex = new A.TypeError();
+ wrapper.dartException = ex;
+ t1 = A.toStringWrapper;
+ if ("defineProperty" in Object) {
+ Object.defineProperty(wrapper, "message", {get: t1});
+ wrapper.name = "";
+ } else
+ wrapper.toString = t1;
+ return wrapper;
+ },
+ toStringWrapper() {
+ return J.toString$0$(this.dartException);
+ },
+ throwExpression(ex) {
+ throw A.wrapException(ex);
+ },
+ throwExpressionWithWrapper(ex, wrapper) {
+ throw A.initializeExceptionWrapper(wrapper, ex);
+ },
+ throwConcurrentModificationError(collection) {
+ throw A.wrapException(A.ConcurrentModificationError$(collection));
+ },
+ TypeErrorDecoder_extractPattern(message) {
+ var match, $arguments, argumentsExpr, expr, method, receiver;
+ message = A.quoteStringForRegExp(message.replace(String({}), "$receiver$"));
+ match = message.match(/\\\$[a-zA-Z]+\\\$/g);
+ if (match == null)
+ match = A._setArrayType([], type$.JSArray_String);
+ $arguments = match.indexOf("\\$arguments\\$");
+ argumentsExpr = match.indexOf("\\$argumentsExpr\\$");
+ expr = match.indexOf("\\$expr\\$");
+ method = match.indexOf("\\$method\\$");
+ receiver = match.indexOf("\\$receiver\\$");
+ return new A.TypeErrorDecoder(message.replace(new RegExp("\\\\\\$arguments\\\\\\$", "g"), "((?:x|[^x])*)").replace(new RegExp("\\\\\\$argumentsExpr\\\\\\$", "g"), "((?:x|[^x])*)").replace(new RegExp("\\\\\\$expr\\\\\\$", "g"), "((?:x|[^x])*)").replace(new RegExp("\\\\\\$method\\\\\\$", "g"), "((?:x|[^x])*)").replace(new RegExp("\\\\\\$receiver\\\\\\$", "g"), "((?:x|[^x])*)"), $arguments, argumentsExpr, expr, method, receiver);
+ },
+ TypeErrorDecoder_provokeCallErrorOn(expression) {
+ return function($expr$) {
+ var $argumentsExpr$ = "$arguments$";
+ try {
+ $expr$.$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+ }(expression);
+ },
+ TypeErrorDecoder_provokePropertyErrorOn(expression) {
+ return function($expr$) {
+ try {
+ $expr$.$method$;
+ } catch (e) {
+ return e.message;
+ }
+ }(expression);
+ },
+ JsNoSuchMethodError$(_message, match) {
+ var t1 = match == null,
+ t2 = t1 ? null : match.method;
+ return new A.JsNoSuchMethodError(_message, t2, t1 ? null : match.receiver);
+ },
+ unwrapException(ex) {
+ var t1;
+ if (ex == null)
+ return new A.NullThrownFromJavaScriptException(ex);
+ if (ex instanceof A.ExceptionAndStackTrace) {
+ t1 = ex.dartException;
+ return A.saveStackTrace(ex, t1 == null ? type$.Object._as(t1) : t1);
+ }
+ if (typeof ex !== "object")
+ return ex;
+ if ("dartException" in ex)
+ return A.saveStackTrace(ex, ex.dartException);
+ return A._unwrapNonDartException(ex);
+ },
+ saveStackTrace(ex, error) {
+ if (type$.Error._is(error))
+ if (error.$thrownJsError == null)
+ error.$thrownJsError = ex;
+ return error;
+ },
+ _unwrapNonDartException(ex) {
+ var message, number, ieErrorCode, nsme, notClosure, nullCall, nullLiteralCall, undefCall, undefLiteralCall, nullProperty, undefProperty, undefLiteralProperty, match;
+ if (!("message" in ex))
+ return ex;
+ message = ex.message;
+ if ("number" in ex && typeof ex.number == "number") {
+ number = ex.number;
+ ieErrorCode = number & 65535;
+ if ((B.JSInt_methods._shrOtherPositive$1(number, 16) & 8191) === 10)
+ switch (ieErrorCode) {
+ case 438:
+ return A.saveStackTrace(ex, A.JsNoSuchMethodError$(A.S(message) + " (Error " + ieErrorCode + ")", null));
+ case 445:
+ case 5007:
+ A.S(message);
+ return A.saveStackTrace(ex, new A.NullError());
+ }
+ }
+ if (ex instanceof TypeError) {
+ nsme = $.$get$TypeErrorDecoder_noSuchMethodPattern();
+ notClosure = $.$get$TypeErrorDecoder_notClosurePattern();
+ nullCall = $.$get$TypeErrorDecoder_nullCallPattern();
+ nullLiteralCall = $.$get$TypeErrorDecoder_nullLiteralCallPattern();
+ undefCall = $.$get$TypeErrorDecoder_undefinedCallPattern();
+ undefLiteralCall = $.$get$TypeErrorDecoder_undefinedLiteralCallPattern();
+ nullProperty = $.$get$TypeErrorDecoder_nullPropertyPattern();
+ $.$get$TypeErrorDecoder_nullLiteralPropertyPattern();
+ undefProperty = $.$get$TypeErrorDecoder_undefinedPropertyPattern();
+ undefLiteralProperty = $.$get$TypeErrorDecoder_undefinedLiteralPropertyPattern();
+ match = nsme.matchTypeError$1(message);
+ if (match != null)
+ return A.saveStackTrace(ex, A.JsNoSuchMethodError$(A._asString(message), match));
+ else {
+ match = notClosure.matchTypeError$1(message);
+ if (match != null) {
+ match.method = "call";
+ return A.saveStackTrace(ex, A.JsNoSuchMethodError$(A._asString(message), match));
+ } else if (nullCall.matchTypeError$1(message) != null || nullLiteralCall.matchTypeError$1(message) != null || undefCall.matchTypeError$1(message) != null || undefLiteralCall.matchTypeError$1(message) != null || nullProperty.matchTypeError$1(message) != null || nullLiteralCall.matchTypeError$1(message) != null || undefProperty.matchTypeError$1(message) != null || undefLiteralProperty.matchTypeError$1(message) != null) {
+ A._asString(message);
+ return A.saveStackTrace(ex, new A.NullError());
+ }
+ }
+ return A.saveStackTrace(ex, new A.UnknownJsTypeError(typeof message == "string" ? message : ""));
+ }
+ if (ex instanceof RangeError) {
+ if (typeof message == "string" && message.indexOf("call stack") !== -1)
+ return new A.StackOverflowError();
+ message = function(ex) {
+ try {
+ return String(ex);
+ } catch (e) {
+ }
+ return null;
+ }(ex);
+ return A.saveStackTrace(ex, new A.ArgumentError(false, null, null, typeof message == "string" ? message.replace(/^RangeError:\s*/, "") : message));
+ }
+ if (typeof InternalError == "function" && ex instanceof InternalError)
+ if (typeof message == "string" && message === "too much recursion")
+ return new A.StackOverflowError();
+ return ex;
+ },
+ getTraceFromException(exception) {
+ var trace;
+ if (exception instanceof A.ExceptionAndStackTrace)
+ return exception.stackTrace;
+ if (exception == null)
+ return new A._StackTrace(exception);
+ trace = exception.$cachedTrace;
+ if (trace != null)
+ return trace;
+ trace = new A._StackTrace(exception);
+ if (typeof exception === "object")
+ exception.$cachedTrace = trace;
+ return trace;
+ },
+ objectHashCode(object) {
+ if (object == null)
+ return J.get$hashCode$(object);
+ if (typeof object == "object")
+ return A.Primitives_objectHashCode(object);
+ return J.get$hashCode$(object);
+ },
+ _invokeClosure(closure, numberOfArguments, arg1, arg2, arg3, arg4) {
+ type$.Function._as(closure);
+ switch (A._asInt(numberOfArguments)) {
+ case 0:
+ return closure.call$0();
+ case 1:
+ return closure.call$1(arg1);
+ case 2:
+ return closure.call$2(arg1, arg2);
+ case 3:
+ return closure.call$3(arg1, arg2, arg3);
+ case 4:
+ return closure.call$4(arg1, arg2, arg3, arg4);
+ }
+ throw A.wrapException(new A._Exception("Unsupported number of arguments for wrapped closure"));
+ },
+ convertDartClosureToJS(closure, arity) {
+ var $function = closure.$identity;
+ if (!!$function)
+ return $function;
+ $function = A.convertDartClosureToJSUncached(closure, arity);
+ closure.$identity = $function;
+ return $function;
+ },
+ convertDartClosureToJSUncached(closure, arity) {
+ var entry;
+ switch (arity) {
+ case 0:
+ entry = closure.call$0;
+ break;
+ case 1:
+ entry = closure.call$1;
+ break;
+ case 2:
+ entry = closure.call$2;
+ break;
+ case 3:
+ entry = closure.call$3;
+ break;
+ case 4:
+ entry = closure.call$4;
+ break;
+ default:
+ entry = null;
+ }
+ if (entry != null)
+ return entry.bind(closure);
+ return function(closure, arity, invoke) {
+ return function(a1, a2, a3, a4) {
+ return invoke(closure, arity, a1, a2, a3, a4);
+ };
+ }(closure, arity, A._invokeClosure);
+ },
+ Closure_fromTearOff(parameters) {
+ var $prototype, $constructor, t2, trampoline, applyTrampoline, i, stub, stub0, stubName, stubCallName,
+ container = parameters.co,
+ isStatic = parameters.iS,
+ isIntercepted = parameters.iI,
+ needsDirectAccess = parameters.nDA,
+ applyTrampolineIndex = parameters.aI,
+ funsOrNames = parameters.fs,
+ callNames = parameters.cs,
+ $name = funsOrNames[0],
+ callName = callNames[0],
+ $function = container[$name],
+ t1 = parameters.fT;
+ t1.toString;
+ $prototype = isStatic ? Object.create(new A.StaticClosure().constructor.prototype) : Object.create(new A.BoundClosure(null, null).constructor.prototype);
+ $prototype.$initialize = $prototype.constructor;
+ $constructor = isStatic ? function static_tear_off() {
+ this.$initialize();
+ } : function tear_off(a, b) {
+ this.$initialize(a, b);
+ };
+ $prototype.constructor = $constructor;
+ $constructor.prototype = $prototype;
+ $prototype.$_name = $name;
+ $prototype.$_target = $function;
+ t2 = !isStatic;
+ if (t2)
+ trampoline = A.Closure_forwardCallTo($name, $function, isIntercepted, needsDirectAccess);
+ else {
+ $prototype.$static_name = $name;
+ trampoline = $function;
+ }
+ $prototype.$signature = A.Closure__computeSignatureFunctionNewRti(t1, isStatic, isIntercepted);
+ $prototype[callName] = trampoline;
+ for (applyTrampoline = trampoline, i = 1; i < funsOrNames.length; ++i) {
+ stub = funsOrNames[i];
+ if (typeof stub == "string") {
+ stub0 = container[stub];
+ stubName = stub;
+ stub = stub0;
+ } else
+ stubName = "";
+ stubCallName = callNames[i];
+ if (stubCallName != null) {
+ if (t2)
+ stub = A.Closure_forwardCallTo(stubName, stub, isIntercepted, needsDirectAccess);
+ $prototype[stubCallName] = stub;
+ }
+ if (i === applyTrampolineIndex)
+ applyTrampoline = stub;
+ }
+ $prototype["call*"] = applyTrampoline;
+ $prototype.$requiredArgCount = parameters.rC;
+ $prototype.$defaultValues = parameters.dV;
+ return $constructor;
+ },
+ Closure__computeSignatureFunctionNewRti(functionType, isStatic, isIntercepted) {
+ if (typeof functionType == "number")
+ return functionType;
+ if (typeof functionType == "string") {
+ if (isStatic)
+ throw A.wrapException("Cannot compute signature for static tearoff.");
+ return function(recipe, evalOnReceiver) {
+ return function() {
+ return evalOnReceiver(this, recipe);
+ };
+ }(functionType, A.BoundClosure_evalRecipe);
+ }
+ throw A.wrapException("Error in functionType of tearoff");
+ },
+ Closure_cspForwardCall(arity, needsDirectAccess, stubName, $function) {
+ var getReceiver = A.BoundClosure_receiverOf;
+ switch (needsDirectAccess ? -1 : arity) {
+ case 0:
+ return function(entry, receiverOf) {
+ return function() {
+ return receiverOf(this)[entry]();
+ };
+ }(stubName, getReceiver);
+ case 1:
+ return function(entry, receiverOf) {
+ return function(a) {
+ return receiverOf(this)[entry](a);
+ };
+ }(stubName, getReceiver);
+ case 2:
+ return function(entry, receiverOf) {
+ return function(a, b) {
+ return receiverOf(this)[entry](a, b);
+ };
+ }(stubName, getReceiver);
+ case 3:
+ return function(entry, receiverOf) {
+ return function(a, b, c) {
+ return receiverOf(this)[entry](a, b, c);
+ };
+ }(stubName, getReceiver);
+ case 4:
+ return function(entry, receiverOf) {
+ return function(a, b, c, d) {
+ return receiverOf(this)[entry](a, b, c, d);
+ };
+ }(stubName, getReceiver);
+ case 5:
+ return function(entry, receiverOf) {
+ return function(a, b, c, d, e) {
+ return receiverOf(this)[entry](a, b, c, d, e);
+ };
+ }(stubName, getReceiver);
+ default:
+ return function(f, receiverOf) {
+ return function() {
+ return f.apply(receiverOf(this), arguments);
+ };
+ }($function, getReceiver);
+ }
+ },
+ Closure_forwardCallTo(stubName, $function, isIntercepted, needsDirectAccess) {
+ if (isIntercepted)
+ return A.Closure_forwardInterceptedCallTo(stubName, $function, needsDirectAccess);
+ return A.Closure_cspForwardCall($function.length, needsDirectAccess, stubName, $function);
+ },
+ Closure_cspForwardInterceptedCall(arity, needsDirectAccess, stubName, $function) {
+ var getReceiver = A.BoundClosure_receiverOf,
+ getInterceptor = A.BoundClosure_interceptorOf;
+ switch (needsDirectAccess ? -1 : arity) {
+ case 0:
+ throw A.wrapException(new A.RuntimeError("Intercepted function with no arguments."));
+ case 1:
+ return function(entry, interceptorOf, receiverOf) {
+ return function() {
+ return interceptorOf(this)[entry](receiverOf(this));
+ };
+ }(stubName, getInterceptor, getReceiver);
+ case 2:
+ return function(entry, interceptorOf, receiverOf) {
+ return function(a) {
+ return interceptorOf(this)[entry](receiverOf(this), a);
+ };
+ }(stubName, getInterceptor, getReceiver);
+ case 3:
+ return function(entry, interceptorOf, receiverOf) {
+ return function(a, b) {
+ return interceptorOf(this)[entry](receiverOf(this), a, b);
+ };
+ }(stubName, getInterceptor, getReceiver);
+ case 4:
+ return function(entry, interceptorOf, receiverOf) {
+ return function(a, b, c) {
+ return interceptorOf(this)[entry](receiverOf(this), a, b, c);
+ };
+ }(stubName, getInterceptor, getReceiver);
+ case 5:
+ return function(entry, interceptorOf, receiverOf) {
+ return function(a, b, c, d) {
+ return interceptorOf(this)[entry](receiverOf(this), a, b, c, d);
+ };
+ }(stubName, getInterceptor, getReceiver);
+ case 6:
+ return function(entry, interceptorOf, receiverOf) {
+ return function(a, b, c, d, e) {
+ return interceptorOf(this)[entry](receiverOf(this), a, b, c, d, e);
+ };
+ }(stubName, getInterceptor, getReceiver);
+ default:
+ return function(f, interceptorOf, receiverOf) {
+ return function() {
+ var a = [receiverOf(this)];
+ Array.prototype.push.apply(a, arguments);
+ return f.apply(interceptorOf(this), a);
+ };
+ }($function, getInterceptor, getReceiver);
+ }
+ },
+ Closure_forwardInterceptedCallTo(stubName, $function, needsDirectAccess) {
+ var arity, t1;
+ if ($.BoundClosure__interceptorFieldNameCache == null)
+ $.BoundClosure__interceptorFieldNameCache = A.BoundClosure__computeFieldNamed("interceptor");
+ if ($.BoundClosure__receiverFieldNameCache == null)
+ $.BoundClosure__receiverFieldNameCache = A.BoundClosure__computeFieldNamed("receiver");
+ arity = $function.length;
+ t1 = A.Closure_cspForwardInterceptedCall(arity, needsDirectAccess, stubName, $function);
+ return t1;
+ },
+ closureFromTearOff(parameters) {
+ return A.Closure_fromTearOff(parameters);
+ },
+ BoundClosure_evalRecipe(closure, recipe) {
+ return A._Universe_evalInEnvironment(init.typeUniverse, A.instanceType(closure._receiver), recipe);
+ },
+ BoundClosure_receiverOf(closure) {
+ return closure._receiver;
+ },
+ BoundClosure_interceptorOf(closure) {
+ return closure._interceptor;
+ },
+ BoundClosure__computeFieldNamed(fieldName) {
+ var t1, i, $name,
+ template = new A.BoundClosure("receiver", "interceptor"),
+ names = J.JSArray_markFixedList(Object.getOwnPropertyNames(template), type$.nullable_Object);
+ for (t1 = names.length, i = 0; i < t1; ++i) {
+ $name = names[i];
+ if (template[$name] === fieldName)
+ return $name;
+ }
+ throw A.wrapException(A.ArgumentError$("Field name " + fieldName + " not found.", null));
+ },
+ throwCyclicInit(staticName) {
+ throw A.wrapException(new A._CyclicInitializationError(staticName));
+ },
+ getIsolateAffinityTag($name) {
+ return init.getIsolateTag($name);
+ },
+ lookupAndCacheInterceptor(obj) {
+ var interceptor, interceptorClass, altTag, mark, t1,
+ tag = A._asString($.getTagFunction.call$1(obj)),
+ record = $.dispatchRecordsForInstanceTags[tag];
+ if (record != null) {
+ Object.defineProperty(obj, init.dispatchPropertyName, {value: record, enumerable: false, writable: true, configurable: true});
+ return record.i;
+ }
+ interceptor = $.interceptorsForUncacheableTags[tag];
+ if (interceptor != null)
+ return interceptor;
+ interceptorClass = init.interceptorsByTag[tag];
+ if (interceptorClass == null) {
+ altTag = A._asStringQ($.alternateTagFunction.call$2(obj, tag));
+ if (altTag != null) {
+ record = $.dispatchRecordsForInstanceTags[altTag];
+ if (record != null) {
+ Object.defineProperty(obj, init.dispatchPropertyName, {value: record, enumerable: false, writable: true, configurable: true});
+ return record.i;
+ }
+ interceptor = $.interceptorsForUncacheableTags[altTag];
+ if (interceptor != null)
+ return interceptor;
+ interceptorClass = init.interceptorsByTag[altTag];
+ tag = altTag;
+ }
+ }
+ if (interceptorClass == null)
+ return null;
+ interceptor = interceptorClass.prototype;
+ mark = tag[0];
+ if (mark === "!") {
+ record = A.makeLeafDispatchRecord(interceptor);
+ $.dispatchRecordsForInstanceTags[tag] = record;
+ Object.defineProperty(obj, init.dispatchPropertyName, {value: record, enumerable: false, writable: true, configurable: true});
+ return record.i;
+ }
+ if (mark === "~") {
+ $.interceptorsForUncacheableTags[tag] = interceptor;
+ return interceptor;
+ }
+ if (mark === "-") {
+ t1 = A.makeLeafDispatchRecord(interceptor);
+ Object.defineProperty(Object.getPrototypeOf(obj), init.dispatchPropertyName, {value: t1, enumerable: false, writable: true, configurable: true});
+ return t1.i;
+ }
+ if (mark === "+")
+ return A.patchInteriorProto(obj, interceptor);
+ if (mark === "*")
+ throw A.wrapException(A.UnimplementedError$(tag));
+ if (init.leafTags[tag] === true) {
+ t1 = A.makeLeafDispatchRecord(interceptor);
+ Object.defineProperty(Object.getPrototypeOf(obj), init.dispatchPropertyName, {value: t1, enumerable: false, writable: true, configurable: true});
+ return t1.i;
+ } else
+ return A.patchInteriorProto(obj, interceptor);
+ },
+ patchInteriorProto(obj, interceptor) {
+ var proto = Object.getPrototypeOf(obj);
+ Object.defineProperty(proto, init.dispatchPropertyName, {value: J.makeDispatchRecord(interceptor, proto, null, null), enumerable: false, writable: true, configurable: true});
+ return interceptor;
+ },
+ makeLeafDispatchRecord(interceptor) {
+ return J.makeDispatchRecord(interceptor, false, null, !!interceptor.$isJavaScriptIndexingBehavior);
+ },
+ makeDefaultDispatchRecord(tag, interceptorClass, proto) {
+ var interceptor = interceptorClass.prototype;
+ if (init.leafTags[tag] === true)
+ return A.makeLeafDispatchRecord(interceptor);
+ else
+ return J.makeDispatchRecord(interceptor, proto, null, null);
+ },
+ initNativeDispatch() {
+ if (true === $.initNativeDispatchFlag)
+ return;
+ $.initNativeDispatchFlag = true;
+ A.initNativeDispatchContinue();
+ },
+ initNativeDispatchContinue() {
+ var map, tags, fun, i, tag, proto, record, interceptorClass;
+ $.dispatchRecordsForInstanceTags = Object.create(null);
+ $.interceptorsForUncacheableTags = Object.create(null);
+ A.initHooks();
+ map = init.interceptorsByTag;
+ tags = Object.getOwnPropertyNames(map);
+ if (typeof window != "undefined") {
+ window;
+ fun = function() {
+ };
+ for (i = 0; i < tags.length; ++i) {
+ tag = tags[i];
+ proto = $.prototypeForTagFunction.call$1(tag);
+ if (proto != null) {
+ record = A.makeDefaultDispatchRecord(tag, map[tag], proto);
+ if (record != null) {
+ Object.defineProperty(proto, init.dispatchPropertyName, {value: record, enumerable: false, writable: true, configurable: true});
+ fun.prototype = proto;
+ }
+ }
+ }
+ }
+ for (i = 0; i < tags.length; ++i) {
+ tag = tags[i];
+ if (/^[A-Za-z_]/.test(tag)) {
+ interceptorClass = map[tag];
+ map["!" + tag] = interceptorClass;
+ map["~" + tag] = interceptorClass;
+ map["-" + tag] = interceptorClass;
+ map["+" + tag] = interceptorClass;
+ map["*" + tag] = interceptorClass;
+ }
+ }
+ },
+ initHooks() {
+ var transformers, i, transformer, getTag, getUnknownTag, prototypeForTag,
+ hooks = B.C_JS_CONST0();
+ hooks = A.applyHooksTransformer(B.C_JS_CONST1, A.applyHooksTransformer(B.C_JS_CONST2, A.applyHooksTransformer(B.C_JS_CONST3, A.applyHooksTransformer(B.C_JS_CONST3, A.applyHooksTransformer(B.C_JS_CONST4, A.applyHooksTransformer(B.C_JS_CONST5, A.applyHooksTransformer(B.C_JS_CONST6(B.C_JS_CONST), hooks)))))));
+ if (typeof dartNativeDispatchHooksTransformer != "undefined") {
+ transformers = dartNativeDispatchHooksTransformer;
+ if (typeof transformers == "function")
+ transformers = [transformers];
+ if (Array.isArray(transformers))
+ for (i = 0; i < transformers.length; ++i) {
+ transformer = transformers[i];
+ if (typeof transformer == "function")
+ hooks = transformer(hooks) || hooks;
+ }
+ }
+ getTag = hooks.getTag;
+ getUnknownTag = hooks.getUnknownTag;
+ prototypeForTag = hooks.prototypeForTag;
+ $.getTagFunction = new A.initHooks_closure(getTag);
+ $.alternateTagFunction = new A.initHooks_closure0(getUnknownTag);
+ $.prototypeForTagFunction = new A.initHooks_closure1(prototypeForTag);
+ },
+ applyHooksTransformer(transformer, hooks) {
+ return transformer(hooks) || hooks;
+ },
+ createRecordTypePredicate(shape, fieldRtis) {
+ var $length = fieldRtis.length,
+ $function = init.rttc["" + $length + ";" + shape];
+ if ($function == null)
+ return null;
+ if ($length === 0)
+ return $function;
+ if ($length === $function.length)
+ return $function.apply(null, fieldRtis);
+ return $function(fieldRtis);
+ },
+ quoteStringForRegExp(string) {
+ if (/[[\]{}()*+?.\\^$|]/.test(string))
+ return string.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&");
+ return string;
+ },
+ ConstantMapView: function ConstantMapView(t0, t1) {
+ this._collection$_map = t0;
+ this.$ti = t1;
+ },
+ ConstantMap: function ConstantMap() {
+ },
+ ConstantStringMap: function ConstantStringMap(t0, t1, t2) {
+ this._jsIndex = t0;
+ this._values = t1;
+ this.$ti = t2;
+ },
+ JSInvocationMirror: function JSInvocationMirror(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._memberName = t0;
+ _.__js_helper$_kind = t1;
+ _._arguments = t2;
+ _._namedArgumentNames = t3;
+ _._typeArgumentCount = t4;
+ },
+ Primitives_functionNoSuchMethod_closure: function Primitives_functionNoSuchMethod_closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.namedArgumentList = t1;
+ this.$arguments = t2;
+ },
+ TypeErrorDecoder: function TypeErrorDecoder(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _._pattern = t0;
+ _._arguments = t1;
+ _._argumentsExpr = t2;
+ _._expr = t3;
+ _._method = t4;
+ _._receiver = t5;
+ },
+ NullError: function NullError() {
+ },
+ JsNoSuchMethodError: function JsNoSuchMethodError(t0, t1, t2) {
+ this.__js_helper$_message = t0;
+ this._method = t1;
+ this._receiver = t2;
+ },
+ UnknownJsTypeError: function UnknownJsTypeError(t0) {
+ this.__js_helper$_message = t0;
+ },
+ NullThrownFromJavaScriptException: function NullThrownFromJavaScriptException(t0) {
+ this._irritant = t0;
+ },
+ ExceptionAndStackTrace: function ExceptionAndStackTrace(t0, t1) {
+ this.dartException = t0;
+ this.stackTrace = t1;
+ },
+ _StackTrace: function _StackTrace(t0) {
+ this._exception = t0;
+ this._trace = null;
+ },
+ Closure: function Closure() {
+ },
+ Closure0Args: function Closure0Args() {
+ },
+ Closure2Args: function Closure2Args() {
+ },
+ TearOffClosure: function TearOffClosure() {
+ },
+ StaticClosure: function StaticClosure() {
+ },
+ BoundClosure: function BoundClosure(t0, t1) {
+ this._receiver = t0;
+ this._interceptor = t1;
+ },
+ _CyclicInitializationError: function _CyclicInitializationError(t0) {
+ this.variableName = t0;
+ },
+ RuntimeError: function RuntimeError(t0) {
+ this.message = t0;
+ },
+ _Required: function _Required() {
+ },
+ JsLinkedHashMap: function JsLinkedHashMap(t0) {
+ var _ = this;
+ _.__js_helper$_length = 0;
+ _._last = _._first = _.__js_helper$_rest = _._nums = _._strings = null;
+ _._modifications = 0;
+ _.$ti = t0;
+ },
+ LinkedHashMapCell: function LinkedHashMapCell(t0, t1) {
+ this.hashMapCellKey = t0;
+ this.hashMapCellValue = t1;
+ this._next = null;
+ },
+ LinkedHashMapKeyIterable: function LinkedHashMapKeyIterable(t0, t1) {
+ this._map = t0;
+ this.$ti = t1;
+ },
+ LinkedHashMapKeyIterator: function LinkedHashMapKeyIterator(t0, t1, t2) {
+ var _ = this;
+ _._map = t0;
+ _._modifications = t1;
+ _.__js_helper$_current = _._cell = null;
+ _.$ti = t2;
+ },
+ initHooks_closure: function initHooks_closure(t0) {
+ this.getTag = t0;
+ },
+ initHooks_closure0: function initHooks_closure0(t0) {
+ this.getUnknownTag = t0;
+ },
+ initHooks_closure1: function initHooks_closure1(t0) {
+ this.prototypeForTag = t0;
+ },
+ StringMatch: function StringMatch(t0, t1) {
+ this.start = t0;
+ this.pattern = t1;
+ },
+ _checkValidIndex(index, list, $length) {
+ if (index >>> 0 !== index || index >= $length)
+ throw A.wrapException(A.diagnoseIndexError(list, index));
+ },
+ NativeByteBuffer: function NativeByteBuffer() {
+ },
+ NativeTypedData: function NativeTypedData() {
+ },
+ NativeByteData: function NativeByteData() {
+ },
+ NativeTypedArray: function NativeTypedArray() {
+ },
+ NativeTypedArrayOfDouble: function NativeTypedArrayOfDouble() {
+ },
+ NativeTypedArrayOfInt: function NativeTypedArrayOfInt() {
+ },
+ NativeFloat32List: function NativeFloat32List() {
+ },
+ NativeFloat64List: function NativeFloat64List() {
+ },
+ NativeInt16List: function NativeInt16List() {
+ },
+ NativeInt32List: function NativeInt32List() {
+ },
+ NativeInt8List: function NativeInt8List() {
+ },
+ NativeUint16List: function NativeUint16List() {
+ },
+ NativeUint32List: function NativeUint32List() {
+ },
+ NativeUint8ClampedList: function NativeUint8ClampedList() {
+ },
+ NativeUint8List: function NativeUint8List() {
+ },
+ _NativeTypedArrayOfDouble_NativeTypedArray_ListMixin: function _NativeTypedArrayOfDouble_NativeTypedArray_ListMixin() {
+ },
+ _NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin: function _NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin() {
+ },
+ _NativeTypedArrayOfInt_NativeTypedArray_ListMixin: function _NativeTypedArrayOfInt_NativeTypedArray_ListMixin() {
+ },
+ _NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin: function _NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin() {
+ },
+ Rti__getQuestionFromStar(universe, rti) {
+ var question = rti._precomputed1;
+ return question == null ? rti._precomputed1 = A._Universe__lookupQuestionRti(universe, rti._primary, true) : question;
+ },
+ Rti__getFutureFromFutureOr(universe, rti) {
+ var future = rti._precomputed1;
+ return future == null ? rti._precomputed1 = A._Universe__lookupInterfaceRti(universe, "Future", [rti._primary]) : future;
+ },
+ Rti__isUnionOfFunctionType(rti) {
+ var kind = rti._kind;
+ if (kind === 6 || kind === 7 || kind === 8)
+ return A.Rti__isUnionOfFunctionType(rti._primary);
+ return kind === 12 || kind === 13;
+ },
+ Rti__getCanonicalRecipe(rti) {
+ return rti._canonicalRecipe;
+ },
+ findType(recipe) {
+ return A._Universe_eval(init.typeUniverse, recipe, false);
+ },
+ _substitute(universe, rti, typeArguments, depth) {
+ var baseType, substitutedBaseType, interfaceTypeArguments, substitutedInterfaceTypeArguments, base, substitutedBase, $arguments, substitutedArguments, t1, fields, substitutedFields, returnType, substitutedReturnType, functionParameters, substitutedFunctionParameters, bounds, substitutedBounds, index, argument,
+ kind = rti._kind;
+ switch (kind) {
+ case 5:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return rti;
+ case 6:
+ baseType = rti._primary;
+ substitutedBaseType = A._substitute(universe, baseType, typeArguments, depth);
+ if (substitutedBaseType === baseType)
+ return rti;
+ return A._Universe__lookupStarRti(universe, substitutedBaseType, true);
+ case 7:
+ baseType = rti._primary;
+ substitutedBaseType = A._substitute(universe, baseType, typeArguments, depth);
+ if (substitutedBaseType === baseType)
+ return rti;
+ return A._Universe__lookupQuestionRti(universe, substitutedBaseType, true);
+ case 8:
+ baseType = rti._primary;
+ substitutedBaseType = A._substitute(universe, baseType, typeArguments, depth);
+ if (substitutedBaseType === baseType)
+ return rti;
+ return A._Universe__lookupFutureOrRti(universe, substitutedBaseType, true);
+ case 9:
+ interfaceTypeArguments = rti._rest;
+ substitutedInterfaceTypeArguments = A._substituteArray(universe, interfaceTypeArguments, typeArguments, depth);
+ if (substitutedInterfaceTypeArguments === interfaceTypeArguments)
+ return rti;
+ return A._Universe__lookupInterfaceRti(universe, rti._primary, substitutedInterfaceTypeArguments);
+ case 10:
+ base = rti._primary;
+ substitutedBase = A._substitute(universe, base, typeArguments, depth);
+ $arguments = rti._rest;
+ substitutedArguments = A._substituteArray(universe, $arguments, typeArguments, depth);
+ if (substitutedBase === base && substitutedArguments === $arguments)
+ return rti;
+ return A._Universe__lookupBindingRti(universe, substitutedBase, substitutedArguments);
+ case 11:
+ t1 = rti._primary;
+ fields = rti._rest;
+ substitutedFields = A._substituteArray(universe, fields, typeArguments, depth);
+ if (substitutedFields === fields)
+ return rti;
+ return A._Universe__lookupRecordRti(universe, t1, substitutedFields);
+ case 12:
+ returnType = rti._primary;
+ substitutedReturnType = A._substitute(universe, returnType, typeArguments, depth);
+ functionParameters = rti._rest;
+ substitutedFunctionParameters = A._substituteFunctionParameters(universe, functionParameters, typeArguments, depth);
+ if (substitutedReturnType === returnType && substitutedFunctionParameters === functionParameters)
+ return rti;
+ return A._Universe__lookupFunctionRti(universe, substitutedReturnType, substitutedFunctionParameters);
+ case 13:
+ bounds = rti._rest;
+ depth += bounds.length;
+ substitutedBounds = A._substituteArray(universe, bounds, typeArguments, depth);
+ base = rti._primary;
+ substitutedBase = A._substitute(universe, base, typeArguments, depth);
+ if (substitutedBounds === bounds && substitutedBase === base)
+ return rti;
+ return A._Universe__lookupGenericFunctionRti(universe, substitutedBase, substitutedBounds, true);
+ case 14:
+ index = rti._primary;
+ if (index < depth)
+ return rti;
+ argument = typeArguments[index - depth];
+ if (argument == null)
+ return rti;
+ return argument;
+ default:
+ throw A.wrapException(A.AssertionError$("Attempted to substitute unexpected RTI kind " + kind));
+ }
+ },
+ _substituteArray(universe, rtiArray, typeArguments, depth) {
+ var changed, i, rti, substitutedRti,
+ $length = rtiArray.length,
+ result = A._Utils_newArrayOrEmpty($length);
+ for (changed = false, i = 0; i < $length; ++i) {
+ rti = rtiArray[i];
+ substitutedRti = A._substitute(universe, rti, typeArguments, depth);
+ if (substitutedRti !== rti)
+ changed = true;
+ result[i] = substitutedRti;
+ }
+ return changed ? result : rtiArray;
+ },
+ _substituteNamed(universe, namedArray, typeArguments, depth) {
+ var changed, i, t1, t2, rti, substitutedRti,
+ $length = namedArray.length,
+ result = A._Utils_newArrayOrEmpty($length);
+ for (changed = false, i = 0; i < $length; i += 3) {
+ t1 = namedArray[i];
+ t2 = namedArray[i + 1];
+ rti = namedArray[i + 2];
+ substitutedRti = A._substitute(universe, rti, typeArguments, depth);
+ if (substitutedRti !== rti)
+ changed = true;
+ result.splice(i, 3, t1, t2, substitutedRti);
+ }
+ return changed ? result : namedArray;
+ },
+ _substituteFunctionParameters(universe, functionParameters, typeArguments, depth) {
+ var result,
+ requiredPositional = functionParameters._requiredPositional,
+ substitutedRequiredPositional = A._substituteArray(universe, requiredPositional, typeArguments, depth),
+ optionalPositional = functionParameters._optionalPositional,
+ substitutedOptionalPositional = A._substituteArray(universe, optionalPositional, typeArguments, depth),
+ named = functionParameters._named,
+ substitutedNamed = A._substituteNamed(universe, named, typeArguments, depth);
+ if (substitutedRequiredPositional === requiredPositional && substitutedOptionalPositional === optionalPositional && substitutedNamed === named)
+ return functionParameters;
+ result = new A._FunctionParameters();
+ result._requiredPositional = substitutedRequiredPositional;
+ result._optionalPositional = substitutedOptionalPositional;
+ result._named = substitutedNamed;
+ return result;
+ },
+ _setArrayType(target, rti) {
+ target[init.arrayRti] = rti;
+ return target;
+ },
+ closureFunctionType(closure) {
+ var signature = closure.$signature;
+ if (signature != null) {
+ if (typeof signature == "number")
+ return A.getTypeFromTypesTable(signature);
+ return closure.$signature();
+ }
+ return null;
+ },
+ instanceOrFunctionType(object, testRti) {
+ var rti;
+ if (A.Rti__isUnionOfFunctionType(testRti))
+ if (object instanceof A.Closure) {
+ rti = A.closureFunctionType(object);
+ if (rti != null)
+ return rti;
+ }
+ return A.instanceType(object);
+ },
+ instanceType(object) {
+ if (object instanceof A.Object)
+ return A._instanceType(object);
+ if (Array.isArray(object))
+ return A._arrayInstanceType(object);
+ return A._instanceTypeFromConstructor(J.getInterceptor$(object));
+ },
+ _arrayInstanceType(object) {
+ var rti = object[init.arrayRti],
+ defaultRti = type$.JSArray_dynamic;
+ if (rti == null)
+ return defaultRti;
+ if (rti.constructor !== defaultRti.constructor)
+ return defaultRti;
+ return rti;
+ },
+ _instanceType(object) {
+ var rti = object.$ti;
+ return rti != null ? rti : A._instanceTypeFromConstructor(object);
+ },
+ _instanceTypeFromConstructor(instance) {
+ var $constructor = instance.constructor,
+ probe = $constructor.$ccache;
+ if (probe != null)
+ return probe;
+ return A._instanceTypeFromConstructorMiss(instance, $constructor);
+ },
+ _instanceTypeFromConstructorMiss(instance, $constructor) {
+ var effectiveConstructor = instance instanceof A.Closure ? Object.getPrototypeOf(Object.getPrototypeOf(instance)).constructor : $constructor,
+ rti = A._Universe_findErasedType(init.typeUniverse, effectiveConstructor.name);
+ $constructor.$ccache = rti;
+ return rti;
+ },
+ getTypeFromTypesTable(index) {
+ var rti,
+ table = init.types,
+ type = table[index];
+ if (typeof type == "string") {
+ rti = A._Universe_eval(init.typeUniverse, type, false);
+ table[index] = rti;
+ return rti;
+ }
+ return type;
+ },
+ getRuntimeTypeOfDartObject(object) {
+ return A.createRuntimeType(A._instanceType(object));
+ },
+ _structuralTypeOf(object) {
+ var functionRti = object instanceof A.Closure ? A.closureFunctionType(object) : null;
+ if (functionRti != null)
+ return functionRti;
+ if (type$.TrustedGetRuntimeType._is(object))
+ return J.get$runtimeType$(object)._rti;
+ if (Array.isArray(object))
+ return A._arrayInstanceType(object);
+ return A.instanceType(object);
+ },
+ createRuntimeType(rti) {
+ var t1 = rti._cachedRuntimeType;
+ return t1 == null ? rti._cachedRuntimeType = A._createRuntimeType(rti) : t1;
+ },
+ _createRuntimeType(rti) {
+ var starErasedRti, t1,
+ s = rti._canonicalRecipe,
+ starErasedRecipe = s.replace(/\*/g, "");
+ if (starErasedRecipe === s)
+ return rti._cachedRuntimeType = new A._Type(rti);
+ starErasedRti = A._Universe_eval(init.typeUniverse, starErasedRecipe, true);
+ t1 = starErasedRti._cachedRuntimeType;
+ return t1 == null ? starErasedRti._cachedRuntimeType = A._createRuntimeType(starErasedRti) : t1;
+ },
+ typeLiteral(recipe) {
+ return A.createRuntimeType(A._Universe_eval(init.typeUniverse, recipe, false));
+ },
+ _installSpecializedIsTest(object) {
+ var t1, unstarred, unstarredKind, isFn, $name, predicate, testRti = this;
+ if (testRti === type$.Object)
+ return A._finishIsFn(testRti, object, A._isObject);
+ if (!A.isSoundTopType(testRti))
+ t1 = testRti === type$.legacy_Object;
+ else
+ t1 = true;
+ if (t1)
+ return A._finishIsFn(testRti, object, A._isTop);
+ t1 = testRti._kind;
+ if (t1 === 7)
+ return A._finishIsFn(testRti, object, A._generalNullableIsTestImplementation);
+ if (t1 === 1)
+ return A._finishIsFn(testRti, object, A._isNever);
+ unstarred = t1 === 6 ? testRti._primary : testRti;
+ unstarredKind = unstarred._kind;
+ if (unstarredKind === 8)
+ return A._finishIsFn(testRti, object, A._isFutureOr);
+ if (unstarred === type$.int)
+ isFn = A._isInt;
+ else if (unstarred === type$.double || unstarred === type$.num)
+ isFn = A._isNum;
+ else if (unstarred === type$.String)
+ isFn = A._isString;
+ else
+ isFn = unstarred === type$.bool ? A._isBool : null;
+ if (isFn != null)
+ return A._finishIsFn(testRti, object, isFn);
+ if (unstarredKind === 9) {
+ $name = unstarred._primary;
+ if (unstarred._rest.every(A.isDefinitelyTopType)) {
+ testRti._specializedTestResource = "$is" + $name;
+ if ($name === "List")
+ return A._finishIsFn(testRti, object, A._isListTestViaProperty);
+ return A._finishIsFn(testRti, object, A._isTestViaProperty);
+ }
+ } else if (unstarredKind === 11) {
+ predicate = A.createRecordTypePredicate(unstarred._primary, unstarred._rest);
+ return A._finishIsFn(testRti, object, predicate == null ? A._isNever : predicate);
+ }
+ return A._finishIsFn(testRti, object, A._generalIsTestImplementation);
+ },
+ _finishIsFn(testRti, object, isFn) {
+ testRti._is = isFn;
+ return testRti._is(object);
+ },
+ _installSpecializedAsCheck(object) {
+ var t1, testRti = this,
+ asFn = A._generalAsCheckImplementation;
+ if (!A.isSoundTopType(testRti))
+ t1 = testRti === type$.legacy_Object;
+ else
+ t1 = true;
+ if (t1)
+ asFn = A._asTop;
+ else if (testRti === type$.Object)
+ asFn = A._asObject;
+ else {
+ t1 = A.isNullable(testRti);
+ if (t1)
+ asFn = A._generalNullableAsCheckImplementation;
+ }
+ testRti._as = asFn;
+ return testRti._as(object);
+ },
+ _nullIs(testRti) {
+ var t1,
+ kind = testRti._kind;
+ if (!A.isSoundTopType(testRti))
+ if (!(testRti === type$.legacy_Object))
+ if (!(testRti === type$.legacy_Never))
+ if (kind !== 7)
+ if (!(kind === 6 && A._nullIs(testRti._primary)))
+ t1 = kind === 8 && A._nullIs(testRti._primary) || testRti === type$.Null || testRti === type$.JSNull;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ return t1;
+ },
+ _generalIsTestImplementation(object) {
+ var testRti = this;
+ if (object == null)
+ return A._nullIs(testRti);
+ return A.isSubtype(init.typeUniverse, A.instanceOrFunctionType(object, testRti), testRti);
+ },
+ _generalNullableIsTestImplementation(object) {
+ if (object == null)
+ return true;
+ return this._primary._is(object);
+ },
+ _isTestViaProperty(object) {
+ var tag, testRti = this;
+ if (object == null)
+ return A._nullIs(testRti);
+ tag = testRti._specializedTestResource;
+ if (object instanceof A.Object)
+ return !!object[tag];
+ return !!J.getInterceptor$(object)[tag];
+ },
+ _isListTestViaProperty(object) {
+ var tag, testRti = this;
+ if (object == null)
+ return A._nullIs(testRti);
+ if (typeof object != "object")
+ return false;
+ if (Array.isArray(object))
+ return true;
+ tag = testRti._specializedTestResource;
+ if (object instanceof A.Object)
+ return !!object[tag];
+ return !!J.getInterceptor$(object)[tag];
+ },
+ _generalAsCheckImplementation(object) {
+ var testRti = this;
+ if (object == null) {
+ if (A.isNullable(testRti))
+ return object;
+ } else if (testRti._is(object))
+ return object;
+ A._failedAsCheck(object, testRti);
+ },
+ _generalNullableAsCheckImplementation(object) {
+ var testRti = this;
+ if (object == null)
+ return object;
+ else if (testRti._is(object))
+ return object;
+ A._failedAsCheck(object, testRti);
+ },
+ _failedAsCheck(object, testRti) {
+ throw A.wrapException(A._TypeError$fromMessage(A._Error_compose(object, A._rtiToString(testRti, null))));
+ },
+ _Error_compose(object, checkedTypeDescription) {
+ return A.Error_safeToString(object) + ": type '" + A._rtiToString(A._structuralTypeOf(object), null) + "' is not a subtype of type '" + checkedTypeDescription + "'";
+ },
+ _TypeError$fromMessage(message) {
+ return new A._TypeError("TypeError: " + message);
+ },
+ _TypeError__TypeError$forType(object, type) {
+ return new A._TypeError("TypeError: " + A._Error_compose(object, type));
+ },
+ _isFutureOr(object) {
+ var testRti = this,
+ unstarred = testRti._kind === 6 ? testRti._primary : testRti;
+ return unstarred._primary._is(object) || A.Rti__getFutureFromFutureOr(init.typeUniverse, unstarred)._is(object);
+ },
+ _isObject(object) {
+ return object != null;
+ },
+ _asObject(object) {
+ if (object != null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "Object"));
+ },
+ _isTop(object) {
+ return true;
+ },
+ _asTop(object) {
+ return object;
+ },
+ _isNever(object) {
+ return false;
+ },
+ _isBool(object) {
+ return true === object || false === object;
+ },
+ _asBool(object) {
+ if (true === object)
+ return true;
+ if (false === object)
+ return false;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "bool"));
+ },
+ _asBoolS(object) {
+ if (true === object)
+ return true;
+ if (false === object)
+ return false;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "bool"));
+ },
+ _asBoolQ(object) {
+ if (true === object)
+ return true;
+ if (false === object)
+ return false;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "bool?"));
+ },
+ _asDouble(object) {
+ if (typeof object == "number")
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "double"));
+ },
+ _asDoubleS(object) {
+ if (typeof object == "number")
+ return object;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "double"));
+ },
+ _asDoubleQ(object) {
+ if (typeof object == "number")
+ return object;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "double?"));
+ },
+ _isInt(object) {
+ return typeof object == "number" && Math.floor(object) === object;
+ },
+ _asInt(object) {
+ if (typeof object == "number" && Math.floor(object) === object)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "int"));
+ },
+ _asIntS(object) {
+ if (typeof object == "number" && Math.floor(object) === object)
+ return object;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "int"));
+ },
+ _asIntQ(object) {
+ if (typeof object == "number" && Math.floor(object) === object)
+ return object;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "int?"));
+ },
+ _isNum(object) {
+ return typeof object == "number";
+ },
+ _asNum(object) {
+ if (typeof object == "number")
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "num"));
+ },
+ _asNumS(object) {
+ if (typeof object == "number")
+ return object;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "num"));
+ },
+ _asNumQ(object) {
+ if (typeof object == "number")
+ return object;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "num?"));
+ },
+ _isString(object) {
+ return typeof object == "string";
+ },
+ _asString(object) {
+ if (typeof object == "string")
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "String"));
+ },
+ _asStringS(object) {
+ if (typeof object == "string")
+ return object;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "String"));
+ },
+ _asStringQ(object) {
+ if (typeof object == "string")
+ return object;
+ if (object == null)
+ return object;
+ throw A.wrapException(A._TypeError__TypeError$forType(object, "String?"));
+ },
+ _rtiArrayToString(array, genericContext) {
+ var s, sep, i;
+ for (s = "", sep = "", i = 0; i < array.length; ++i, sep = ", ")
+ s += sep + A._rtiToString(array[i], genericContext);
+ return s;
+ },
+ _recordRtiToString(recordType, genericContext) {
+ var fieldCount, names, namesIndex, s, comma, i,
+ partialShape = recordType._primary,
+ fields = recordType._rest;
+ if ("" === partialShape)
+ return "(" + A._rtiArrayToString(fields, genericContext) + ")";
+ fieldCount = fields.length;
+ names = partialShape.split(",");
+ namesIndex = names.length - fieldCount;
+ for (s = "(", comma = "", i = 0; i < fieldCount; ++i, comma = ", ") {
+ s += comma;
+ if (namesIndex === 0)
+ s += "{";
+ s += A._rtiToString(fields[i], genericContext);
+ if (namesIndex >= 0)
+ s += " " + names[namesIndex];
+ ++namesIndex;
+ }
+ return s + "})";
+ },
+ _functionRtiToString(functionType, genericContext, bounds) {
+ var boundsLength, outerContextLength, offset, i, t1, t2, typeParametersText, typeSep, t3, t4, boundRti, kind, parameters, requiredPositional, requiredPositionalLength, optionalPositional, optionalPositionalLength, named, namedLength, returnTypeText, argumentsText, sep, _s2_ = ", ";
+ if (bounds != null) {
+ boundsLength = bounds.length;
+ if (genericContext == null) {
+ genericContext = A._setArrayType([], type$.JSArray_String);
+ outerContextLength = null;
+ } else
+ outerContextLength = genericContext.length;
+ offset = genericContext.length;
+ for (i = boundsLength; i > 0; --i)
+ B.JSArray_methods.add$1(genericContext, "T" + (offset + i));
+ for (t1 = type$.nullable_Object, t2 = type$.legacy_Object, typeParametersText = "<", typeSep = "", i = 0; i < boundsLength; ++i, typeSep = _s2_) {
+ t3 = genericContext.length;
+ t4 = t3 - 1 - i;
+ if (!(t4 >= 0))
+ return A.ioore(genericContext, t4);
+ typeParametersText = B.JSString_methods.$add(typeParametersText + typeSep, genericContext[t4]);
+ boundRti = bounds[i];
+ kind = boundRti._kind;
+ if (!(kind === 2 || kind === 3 || kind === 4 || kind === 5 || boundRti === t1))
+ t3 = boundRti === t2;
+ else
+ t3 = true;
+ if (!t3)
+ typeParametersText += " extends " + A._rtiToString(boundRti, genericContext);
+ }
+ typeParametersText += ">";
+ } else {
+ typeParametersText = "";
+ outerContextLength = null;
+ }
+ t1 = functionType._primary;
+ parameters = functionType._rest;
+ requiredPositional = parameters._requiredPositional;
+ requiredPositionalLength = requiredPositional.length;
+ optionalPositional = parameters._optionalPositional;
+ optionalPositionalLength = optionalPositional.length;
+ named = parameters._named;
+ namedLength = named.length;
+ returnTypeText = A._rtiToString(t1, genericContext);
+ for (argumentsText = "", sep = "", i = 0; i < requiredPositionalLength; ++i, sep = _s2_)
+ argumentsText += sep + A._rtiToString(requiredPositional[i], genericContext);
+ if (optionalPositionalLength > 0) {
+ argumentsText += sep + "[";
+ for (sep = "", i = 0; i < optionalPositionalLength; ++i, sep = _s2_)
+ argumentsText += sep + A._rtiToString(optionalPositional[i], genericContext);
+ argumentsText += "]";
+ }
+ if (namedLength > 0) {
+ argumentsText += sep + "{";
+ for (sep = "", i = 0; i < namedLength; i += 3, sep = _s2_) {
+ argumentsText += sep;
+ if (named[i + 1])
+ argumentsText += "required ";
+ argumentsText += A._rtiToString(named[i + 2], genericContext) + " " + named[i];
+ }
+ argumentsText += "}";
+ }
+ if (outerContextLength != null) {
+ genericContext.toString;
+ genericContext.length = outerContextLength;
+ }
+ return typeParametersText + "(" + argumentsText + ") => " + returnTypeText;
+ },
+ _rtiToString(rti, genericContext) {
+ var questionArgument, s, argumentKind, $name, $arguments, t1, t2,
+ kind = rti._kind;
+ if (kind === 5)
+ return "erased";
+ if (kind === 2)
+ return "dynamic";
+ if (kind === 3)
+ return "void";
+ if (kind === 1)
+ return "Never";
+ if (kind === 4)
+ return "any";
+ if (kind === 6)
+ return A._rtiToString(rti._primary, genericContext);
+ if (kind === 7) {
+ questionArgument = rti._primary;
+ s = A._rtiToString(questionArgument, genericContext);
+ argumentKind = questionArgument._kind;
+ return (argumentKind === 12 || argumentKind === 13 ? "(" + s + ")" : s) + "?";
+ }
+ if (kind === 8)
+ return "FutureOr<" + A._rtiToString(rti._primary, genericContext) + ">";
+ if (kind === 9) {
+ $name = A._unminifyOrTag(rti._primary);
+ $arguments = rti._rest;
+ return $arguments.length > 0 ? $name + ("<" + A._rtiArrayToString($arguments, genericContext) + ">") : $name;
+ }
+ if (kind === 11)
+ return A._recordRtiToString(rti, genericContext);
+ if (kind === 12)
+ return A._functionRtiToString(rti, genericContext, null);
+ if (kind === 13)
+ return A._functionRtiToString(rti._primary, genericContext, rti._rest);
+ if (kind === 14) {
+ t1 = rti._primary;
+ t2 = genericContext.length;
+ t1 = t2 - 1 - t1;
+ if (!(t1 >= 0 && t1 < t2))
+ return A.ioore(genericContext, t1);
+ return genericContext[t1];
+ }
+ return "?";
+ },
+ _unminifyOrTag(rawClassName) {
+ var preserved = init.mangledGlobalNames[rawClassName];
+ if (preserved != null)
+ return preserved;
+ return rawClassName;
+ },
+ _Universe_findRule(universe, targetType) {
+ var rule = universe.tR[targetType];
+ for (; typeof rule == "string";)
+ rule = universe.tR[rule];
+ return rule;
+ },
+ _Universe_findErasedType(universe, cls) {
+ var $length, erased, $arguments, i, $interface,
+ t1 = universe.eT,
+ probe = t1[cls];
+ if (probe == null)
+ return A._Universe_eval(universe, cls, false);
+ else if (typeof probe == "number") {
+ $length = probe;
+ erased = A._Universe__lookupTerminalRti(universe, 5, "#");
+ $arguments = A._Utils_newArrayOrEmpty($length);
+ for (i = 0; i < $length; ++i)
+ $arguments[i] = erased;
+ $interface = A._Universe__lookupInterfaceRti(universe, cls, $arguments);
+ t1[cls] = $interface;
+ return $interface;
+ } else
+ return probe;
+ },
+ _Universe_addRules(universe, rules) {
+ return A._Utils_objectAssign(universe.tR, rules);
+ },
+ _Universe_addErasedTypes(universe, types) {
+ return A._Utils_objectAssign(universe.eT, types);
+ },
+ _Universe_eval(universe, recipe, normalize) {
+ var rti,
+ t1 = universe.eC,
+ probe = t1.get(recipe);
+ if (probe != null)
+ return probe;
+ rti = A._Parser_parse(A._Parser_create(universe, null, recipe, normalize));
+ t1.set(recipe, rti);
+ return rti;
+ },
+ _Universe_evalInEnvironment(universe, environment, recipe) {
+ var probe, rti,
+ cache = environment._evalCache;
+ if (cache == null)
+ cache = environment._evalCache = new Map();
+ probe = cache.get(recipe);
+ if (probe != null)
+ return probe;
+ rti = A._Parser_parse(A._Parser_create(universe, environment, recipe, true));
+ cache.set(recipe, rti);
+ return rti;
+ },
+ _Universe_bind(universe, environment, argumentsRti) {
+ var argumentsRecipe, probe, rti,
+ cache = environment._bindCache;
+ if (cache == null)
+ cache = environment._bindCache = new Map();
+ argumentsRecipe = argumentsRti._canonicalRecipe;
+ probe = cache.get(argumentsRecipe);
+ if (probe != null)
+ return probe;
+ rti = A._Universe__lookupBindingRti(universe, environment, argumentsRti._kind === 10 ? argumentsRti._rest : [argumentsRti]);
+ cache.set(argumentsRecipe, rti);
+ return rti;
+ },
+ _Universe__installTypeTests(universe, rti) {
+ rti._as = A._installSpecializedAsCheck;
+ rti._is = A._installSpecializedIsTest;
+ return rti;
+ },
+ _Universe__lookupTerminalRti(universe, kind, key) {
+ var rti, t1,
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ rti = new A.Rti(null, null);
+ rti._kind = kind;
+ rti._canonicalRecipe = key;
+ t1 = A._Universe__installTypeTests(universe, rti);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__lookupStarRti(universe, baseType, normalize) {
+ var t1,
+ key = baseType._canonicalRecipe + "*",
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ t1 = A._Universe__createStarRti(universe, baseType, key, normalize);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__createStarRti(universe, baseType, key, normalize) {
+ var baseKind, t1, rti;
+ if (normalize) {
+ baseKind = baseType._kind;
+ if (!A.isSoundTopType(baseType))
+ t1 = baseType === type$.Null || baseType === type$.JSNull || baseKind === 7 || baseKind === 6;
+ else
+ t1 = true;
+ if (t1)
+ return baseType;
+ }
+ rti = new A.Rti(null, null);
+ rti._kind = 6;
+ rti._primary = baseType;
+ rti._canonicalRecipe = key;
+ return A._Universe__installTypeTests(universe, rti);
+ },
+ _Universe__lookupQuestionRti(universe, baseType, normalize) {
+ var t1,
+ key = baseType._canonicalRecipe + "?",
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ t1 = A._Universe__createQuestionRti(universe, baseType, key, normalize);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__createQuestionRti(universe, baseType, key, normalize) {
+ var baseKind, t1, starArgument, rti;
+ if (normalize) {
+ baseKind = baseType._kind;
+ if (!A.isSoundTopType(baseType))
+ if (!(baseType === type$.Null || baseType === type$.JSNull))
+ if (baseKind !== 7)
+ t1 = baseKind === 8 && A.isNullable(baseType._primary);
+ else
+ t1 = true;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ if (t1)
+ return baseType;
+ else if (baseKind === 1 || baseType === type$.legacy_Never)
+ return type$.Null;
+ else if (baseKind === 6) {
+ starArgument = baseType._primary;
+ if (starArgument._kind === 8 && A.isNullable(starArgument._primary))
+ return starArgument;
+ else
+ return A.Rti__getQuestionFromStar(universe, baseType);
+ }
+ }
+ rti = new A.Rti(null, null);
+ rti._kind = 7;
+ rti._primary = baseType;
+ rti._canonicalRecipe = key;
+ return A._Universe__installTypeTests(universe, rti);
+ },
+ _Universe__lookupFutureOrRti(universe, baseType, normalize) {
+ var t1,
+ key = baseType._canonicalRecipe + "/",
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ t1 = A._Universe__createFutureOrRti(universe, baseType, key, normalize);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__createFutureOrRti(universe, baseType, key, normalize) {
+ var t1, rti;
+ if (normalize) {
+ t1 = baseType._kind;
+ if (A.isSoundTopType(baseType) || baseType === type$.Object || baseType === type$.legacy_Object)
+ return baseType;
+ else if (t1 === 1)
+ return A._Universe__lookupInterfaceRti(universe, "Future", [baseType]);
+ else if (baseType === type$.Null || baseType === type$.JSNull)
+ return type$.nullable_Future_Null;
+ }
+ rti = new A.Rti(null, null);
+ rti._kind = 8;
+ rti._primary = baseType;
+ rti._canonicalRecipe = key;
+ return A._Universe__installTypeTests(universe, rti);
+ },
+ _Universe__lookupGenericFunctionParameterRti(universe, index) {
+ var rti, t1,
+ key = "" + index + "^",
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ rti = new A.Rti(null, null);
+ rti._kind = 14;
+ rti._primary = index;
+ rti._canonicalRecipe = key;
+ t1 = A._Universe__installTypeTests(universe, rti);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__canonicalRecipeJoin($arguments) {
+ var s, sep, i,
+ $length = $arguments.length;
+ for (s = "", sep = "", i = 0; i < $length; ++i, sep = ",")
+ s += sep + $arguments[i]._canonicalRecipe;
+ return s;
+ },
+ _Universe__canonicalRecipeJoinNamed($arguments) {
+ var s, sep, i, t1, nameSep,
+ $length = $arguments.length;
+ for (s = "", sep = "", i = 0; i < $length; i += 3, sep = ",") {
+ t1 = $arguments[i];
+ nameSep = $arguments[i + 1] ? "!" : ":";
+ s += sep + t1 + nameSep + $arguments[i + 2]._canonicalRecipe;
+ }
+ return s;
+ },
+ _Universe__lookupInterfaceRti(universe, $name, $arguments) {
+ var probe, rti, t1,
+ s = $name;
+ if ($arguments.length > 0)
+ s += "<" + A._Universe__canonicalRecipeJoin($arguments) + ">";
+ probe = universe.eC.get(s);
+ if (probe != null)
+ return probe;
+ rti = new A.Rti(null, null);
+ rti._kind = 9;
+ rti._primary = $name;
+ rti._rest = $arguments;
+ if ($arguments.length > 0)
+ rti._precomputed1 = $arguments[0];
+ rti._canonicalRecipe = s;
+ t1 = A._Universe__installTypeTests(universe, rti);
+ universe.eC.set(s, t1);
+ return t1;
+ },
+ _Universe__lookupBindingRti(universe, base, $arguments) {
+ var newBase, newArguments, key, probe, rti, t1;
+ if (base._kind === 10) {
+ newBase = base._primary;
+ newArguments = base._rest.concat($arguments);
+ } else {
+ newArguments = $arguments;
+ newBase = base;
+ }
+ key = newBase._canonicalRecipe + (";<" + A._Universe__canonicalRecipeJoin(newArguments) + ">");
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ rti = new A.Rti(null, null);
+ rti._kind = 10;
+ rti._primary = newBase;
+ rti._rest = newArguments;
+ rti._canonicalRecipe = key;
+ t1 = A._Universe__installTypeTests(universe, rti);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__lookupRecordRti(universe, partialShapeTag, fields) {
+ var rti, t1,
+ key = "+" + (partialShapeTag + "(" + A._Universe__canonicalRecipeJoin(fields) + ")"),
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ rti = new A.Rti(null, null);
+ rti._kind = 11;
+ rti._primary = partialShapeTag;
+ rti._rest = fields;
+ rti._canonicalRecipe = key;
+ t1 = A._Universe__installTypeTests(universe, rti);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__lookupFunctionRti(universe, returnType, parameters) {
+ var sep, key, probe, rti, t1,
+ s = returnType._canonicalRecipe,
+ requiredPositional = parameters._requiredPositional,
+ requiredPositionalLength = requiredPositional.length,
+ optionalPositional = parameters._optionalPositional,
+ optionalPositionalLength = optionalPositional.length,
+ named = parameters._named,
+ namedLength = named.length,
+ recipe = "(" + A._Universe__canonicalRecipeJoin(requiredPositional);
+ if (optionalPositionalLength > 0) {
+ sep = requiredPositionalLength > 0 ? "," : "";
+ recipe += sep + "[" + A._Universe__canonicalRecipeJoin(optionalPositional) + "]";
+ }
+ if (namedLength > 0) {
+ sep = requiredPositionalLength > 0 ? "," : "";
+ recipe += sep + "{" + A._Universe__canonicalRecipeJoinNamed(named) + "}";
+ }
+ key = s + (recipe + ")");
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ rti = new A.Rti(null, null);
+ rti._kind = 12;
+ rti._primary = returnType;
+ rti._rest = parameters;
+ rti._canonicalRecipe = key;
+ t1 = A._Universe__installTypeTests(universe, rti);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__lookupGenericFunctionRti(universe, baseFunctionType, bounds, normalize) {
+ var t1,
+ key = baseFunctionType._canonicalRecipe + ("<" + A._Universe__canonicalRecipeJoin(bounds) + ">"),
+ probe = universe.eC.get(key);
+ if (probe != null)
+ return probe;
+ t1 = A._Universe__createGenericFunctionRti(universe, baseFunctionType, bounds, key, normalize);
+ universe.eC.set(key, t1);
+ return t1;
+ },
+ _Universe__createGenericFunctionRti(universe, baseFunctionType, bounds, key, normalize) {
+ var $length, typeArguments, count, i, bound, substitutedBase, substitutedBounds, rti;
+ if (normalize) {
+ $length = bounds.length;
+ typeArguments = A._Utils_newArrayOrEmpty($length);
+ for (count = 0, i = 0; i < $length; ++i) {
+ bound = bounds[i];
+ if (bound._kind === 1) {
+ typeArguments[i] = bound;
+ ++count;
+ }
+ }
+ if (count > 0) {
+ substitutedBase = A._substitute(universe, baseFunctionType, typeArguments, 0);
+ substitutedBounds = A._substituteArray(universe, bounds, typeArguments, 0);
+ return A._Universe__lookupGenericFunctionRti(universe, substitutedBase, substitutedBounds, bounds !== substitutedBounds);
+ }
+ }
+ rti = new A.Rti(null, null);
+ rti._kind = 13;
+ rti._primary = baseFunctionType;
+ rti._rest = bounds;
+ rti._canonicalRecipe = key;
+ return A._Universe__installTypeTests(universe, rti);
+ },
+ _Parser_create(universe, environment, recipe, normalize) {
+ return {u: universe, e: environment, r: recipe, s: [], p: 0, n: normalize};
+ },
+ _Parser_parse(parser) {
+ var t2, i, ch, t3, array, end, item,
+ source = parser.r,
+ t1 = parser.s;
+ for (t2 = source.length, i = 0; i < t2;) {
+ ch = source.charCodeAt(i);
+ if (ch >= 48 && ch <= 57)
+ i = A._Parser_handleDigit(i + 1, ch, source, t1);
+ else if ((((ch | 32) >>> 0) - 97 & 65535) < 26 || ch === 95 || ch === 36 || ch === 124)
+ i = A._Parser_handleIdentifier(parser, i, source, t1, false);
+ else if (ch === 46)
+ i = A._Parser_handleIdentifier(parser, i, source, t1, true);
+ else {
+ ++i;
+ switch (ch) {
+ case 44:
+ break;
+ case 58:
+ t1.push(false);
+ break;
+ case 33:
+ t1.push(true);
+ break;
+ case 59:
+ t1.push(A._Parser_toType(parser.u, parser.e, t1.pop()));
+ break;
+ case 94:
+ t1.push(A._Universe__lookupGenericFunctionParameterRti(parser.u, t1.pop()));
+ break;
+ case 35:
+ t1.push(A._Universe__lookupTerminalRti(parser.u, 5, "#"));
+ break;
+ case 64:
+ t1.push(A._Universe__lookupTerminalRti(parser.u, 2, "@"));
+ break;
+ case 126:
+ t1.push(A._Universe__lookupTerminalRti(parser.u, 3, "~"));
+ break;
+ case 60:
+ t1.push(parser.p);
+ parser.p = t1.length;
+ break;
+ case 62:
+ A._Parser_handleTypeArguments(parser, t1);
+ break;
+ case 38:
+ A._Parser_handleExtendedOperations(parser, t1);
+ break;
+ case 42:
+ t3 = parser.u;
+ t1.push(A._Universe__lookupStarRti(t3, A._Parser_toType(t3, parser.e, t1.pop()), parser.n));
+ break;
+ case 63:
+ t3 = parser.u;
+ t1.push(A._Universe__lookupQuestionRti(t3, A._Parser_toType(t3, parser.e, t1.pop()), parser.n));
+ break;
+ case 47:
+ t3 = parser.u;
+ t1.push(A._Universe__lookupFutureOrRti(t3, A._Parser_toType(t3, parser.e, t1.pop()), parser.n));
+ break;
+ case 40:
+ t1.push(-3);
+ t1.push(parser.p);
+ parser.p = t1.length;
+ break;
+ case 41:
+ A._Parser_handleArguments(parser, t1);
+ break;
+ case 91:
+ t1.push(parser.p);
+ parser.p = t1.length;
+ break;
+ case 93:
+ array = t1.splice(parser.p);
+ A._Parser_toTypes(parser.u, parser.e, array);
+ parser.p = t1.pop();
+ t1.push(array);
+ t1.push(-1);
+ break;
+ case 123:
+ t1.push(parser.p);
+ parser.p = t1.length;
+ break;
+ case 125:
+ array = t1.splice(parser.p);
+ A._Parser_toTypesNamed(parser.u, parser.e, array);
+ parser.p = t1.pop();
+ t1.push(array);
+ t1.push(-2);
+ break;
+ case 43:
+ end = source.indexOf("(", i);
+ t1.push(source.substring(i, end));
+ t1.push(-4);
+ t1.push(parser.p);
+ parser.p = t1.length;
+ i = end + 1;
+ break;
+ default:
+ throw "Bad character " + ch;
+ }
+ }
+ }
+ item = t1.pop();
+ return A._Parser_toType(parser.u, parser.e, item);
+ },
+ _Parser_handleDigit(i, digit, source, stack) {
+ var t1, ch,
+ value = digit - 48;
+ for (t1 = source.length; i < t1; ++i) {
+ ch = source.charCodeAt(i);
+ if (!(ch >= 48 && ch <= 57))
+ break;
+ value = value * 10 + (ch - 48);
+ }
+ stack.push(value);
+ return i;
+ },
+ _Parser_handleIdentifier(parser, start, source, stack, hasPeriod) {
+ var t1, ch, t2, string, environment, recipe,
+ i = start + 1;
+ for (t1 = source.length; i < t1; ++i) {
+ ch = source.charCodeAt(i);
+ if (ch === 46) {
+ if (hasPeriod)
+ break;
+ hasPeriod = true;
+ } else {
+ if (!((((ch | 32) >>> 0) - 97 & 65535) < 26 || ch === 95 || ch === 36 || ch === 124))
+ t2 = ch >= 48 && ch <= 57;
+ else
+ t2 = true;
+ if (!t2)
+ break;
+ }
+ }
+ string = source.substring(start, i);
+ if (hasPeriod) {
+ t1 = parser.u;
+ environment = parser.e;
+ if (environment._kind === 10)
+ environment = environment._primary;
+ recipe = A._Universe_findRule(t1, environment._primary)[string];
+ if (recipe == null)
+ A.throwExpression('No "' + string + '" in "' + A.Rti__getCanonicalRecipe(environment) + '"');
+ stack.push(A._Universe_evalInEnvironment(t1, environment, recipe));
+ } else
+ stack.push(string);
+ return i;
+ },
+ _Parser_handleTypeArguments(parser, stack) {
+ var base,
+ t1 = parser.u,
+ $arguments = A._Parser_collectArray(parser, stack),
+ head = stack.pop();
+ if (typeof head == "string")
+ stack.push(A._Universe__lookupInterfaceRti(t1, head, $arguments));
+ else {
+ base = A._Parser_toType(t1, parser.e, head);
+ switch (base._kind) {
+ case 12:
+ stack.push(A._Universe__lookupGenericFunctionRti(t1, base, $arguments, parser.n));
+ break;
+ default:
+ stack.push(A._Universe__lookupBindingRti(t1, base, $arguments));
+ break;
+ }
+ }
+ },
+ _Parser_handleArguments(parser, stack) {
+ var optionalPositional, named, requiredPositional, returnType, parameters, _null = null,
+ t1 = parser.u,
+ head = stack.pop();
+ if (typeof head == "number")
+ switch (head) {
+ case -1:
+ optionalPositional = stack.pop();
+ named = _null;
+ break;
+ case -2:
+ named = stack.pop();
+ optionalPositional = _null;
+ break;
+ default:
+ stack.push(head);
+ named = _null;
+ optionalPositional = named;
+ break;
+ }
+ else {
+ stack.push(head);
+ named = _null;
+ optionalPositional = named;
+ }
+ requiredPositional = A._Parser_collectArray(parser, stack);
+ head = stack.pop();
+ switch (head) {
+ case -3:
+ head = stack.pop();
+ if (optionalPositional == null)
+ optionalPositional = t1.sEA;
+ if (named == null)
+ named = t1.sEA;
+ returnType = A._Parser_toType(t1, parser.e, head);
+ parameters = new A._FunctionParameters();
+ parameters._requiredPositional = requiredPositional;
+ parameters._optionalPositional = optionalPositional;
+ parameters._named = named;
+ stack.push(A._Universe__lookupFunctionRti(t1, returnType, parameters));
+ return;
+ case -4:
+ stack.push(A._Universe__lookupRecordRti(t1, stack.pop(), requiredPositional));
+ return;
+ default:
+ throw A.wrapException(A.AssertionError$("Unexpected state under `()`: " + A.S(head)));
+ }
+ },
+ _Parser_handleExtendedOperations(parser, stack) {
+ var $top = stack.pop();
+ if (0 === $top) {
+ stack.push(A._Universe__lookupTerminalRti(parser.u, 1, "0&"));
+ return;
+ }
+ if (1 === $top) {
+ stack.push(A._Universe__lookupTerminalRti(parser.u, 4, "1&"));
+ return;
+ }
+ throw A.wrapException(A.AssertionError$("Unexpected extended operation " + A.S($top)));
+ },
+ _Parser_collectArray(parser, stack) {
+ var array = stack.splice(parser.p);
+ A._Parser_toTypes(parser.u, parser.e, array);
+ parser.p = stack.pop();
+ return array;
+ },
+ _Parser_toType(universe, environment, item) {
+ if (typeof item == "string")
+ return A._Universe__lookupInterfaceRti(universe, item, universe.sEA);
+ else if (typeof item == "number") {
+ environment.toString;
+ return A._Parser_indexToType(universe, environment, item);
+ } else
+ return item;
+ },
+ _Parser_toTypes(universe, environment, items) {
+ var i,
+ $length = items.length;
+ for (i = 0; i < $length; ++i)
+ items[i] = A._Parser_toType(universe, environment, items[i]);
+ },
+ _Parser_toTypesNamed(universe, environment, items) {
+ var i,
+ $length = items.length;
+ for (i = 2; i < $length; i += 3)
+ items[i] = A._Parser_toType(universe, environment, items[i]);
+ },
+ _Parser_indexToType(universe, environment, index) {
+ var typeArguments, len,
+ kind = environment._kind;
+ if (kind === 10) {
+ if (index === 0)
+ return environment._primary;
+ typeArguments = environment._rest;
+ len = typeArguments.length;
+ if (index <= len)
+ return typeArguments[index - 1];
+ index -= len;
+ environment = environment._primary;
+ kind = environment._kind;
+ } else if (index === 0)
+ return environment;
+ if (kind !== 9)
+ throw A.wrapException(A.AssertionError$("Indexed base must be an interface type"));
+ typeArguments = environment._rest;
+ if (index <= typeArguments.length)
+ return typeArguments[index - 1];
+ throw A.wrapException(A.AssertionError$("Bad index " + index + " for " + environment.toString$0(0)));
+ },
+ isSubtype(universe, s, t) {
+ var result,
+ sCache = s._isSubtypeCache;
+ if (sCache == null)
+ sCache = s._isSubtypeCache = new Map();
+ result = sCache.get(t);
+ if (result == null) {
+ result = A._isSubtype(universe, s, null, t, null, false) ? 1 : 0;
+ sCache.set(t, result);
+ }
+ if (0 === result)
+ return false;
+ if (1 === result)
+ return true;
+ return true;
+ },
+ _isSubtype(universe, s, sEnv, t, tEnv, isLegacy) {
+ var t1, sKind, leftTypeVariable, tKind, t2, sBounds, tBounds, sLength, i, sBound, tBound;
+ if (s === t)
+ return true;
+ if (!A.isSoundTopType(t))
+ t1 = t === type$.legacy_Object;
+ else
+ t1 = true;
+ if (t1)
+ return true;
+ sKind = s._kind;
+ if (sKind === 4)
+ return true;
+ if (A.isSoundTopType(s))
+ return false;
+ t1 = s._kind;
+ if (t1 === 1)
+ return true;
+ leftTypeVariable = sKind === 14;
+ if (leftTypeVariable)
+ if (A._isSubtype(universe, sEnv[s._primary], sEnv, t, tEnv, false))
+ return true;
+ tKind = t._kind;
+ t1 = s === type$.Null || s === type$.JSNull;
+ if (t1) {
+ if (tKind === 8)
+ return A._isSubtype(universe, s, sEnv, t._primary, tEnv, false);
+ return t === type$.Null || t === type$.JSNull || tKind === 7 || tKind === 6;
+ }
+ if (t === type$.Object) {
+ if (sKind === 8)
+ return A._isSubtype(universe, s._primary, sEnv, t, tEnv, false);
+ if (sKind === 6)
+ return A._isSubtype(universe, s._primary, sEnv, t, tEnv, false);
+ return sKind !== 7;
+ }
+ if (sKind === 6)
+ return A._isSubtype(universe, s._primary, sEnv, t, tEnv, false);
+ if (tKind === 6) {
+ t1 = A.Rti__getQuestionFromStar(universe, t);
+ return A._isSubtype(universe, s, sEnv, t1, tEnv, false);
+ }
+ if (sKind === 8) {
+ if (!A._isSubtype(universe, s._primary, sEnv, t, tEnv, false))
+ return false;
+ return A._isSubtype(universe, A.Rti__getFutureFromFutureOr(universe, s), sEnv, t, tEnv, false);
+ }
+ if (sKind === 7) {
+ t1 = A._isSubtype(universe, type$.Null, sEnv, t, tEnv, false);
+ return t1 && A._isSubtype(universe, s._primary, sEnv, t, tEnv, false);
+ }
+ if (tKind === 8) {
+ if (A._isSubtype(universe, s, sEnv, t._primary, tEnv, false))
+ return true;
+ return A._isSubtype(universe, s, sEnv, A.Rti__getFutureFromFutureOr(universe, t), tEnv, false);
+ }
+ if (tKind === 7) {
+ t1 = A._isSubtype(universe, s, sEnv, type$.Null, tEnv, false);
+ return t1 || A._isSubtype(universe, s, sEnv, t._primary, tEnv, false);
+ }
+ if (leftTypeVariable)
+ return false;
+ t1 = sKind !== 12;
+ if ((!t1 || sKind === 13) && t === type$.Function)
+ return true;
+ t2 = sKind === 11;
+ if (t2 && t === type$.Record)
+ return true;
+ if (tKind === 13) {
+ if (s === type$.JavaScriptFunction)
+ return true;
+ if (sKind !== 13)
+ return false;
+ sBounds = s._rest;
+ tBounds = t._rest;
+ sLength = sBounds.length;
+ if (sLength !== tBounds.length)
+ return false;
+ sEnv = sEnv == null ? sBounds : sBounds.concat(sEnv);
+ tEnv = tEnv == null ? tBounds : tBounds.concat(tEnv);
+ for (i = 0; i < sLength; ++i) {
+ sBound = sBounds[i];
+ tBound = tBounds[i];
+ if (!A._isSubtype(universe, sBound, sEnv, tBound, tEnv, false) || !A._isSubtype(universe, tBound, tEnv, sBound, sEnv, false))
+ return false;
+ }
+ return A._isFunctionSubtype(universe, s._primary, sEnv, t._primary, tEnv, false);
+ }
+ if (tKind === 12) {
+ if (s === type$.JavaScriptFunction)
+ return true;
+ if (t1)
+ return false;
+ return A._isFunctionSubtype(universe, s, sEnv, t, tEnv, false);
+ }
+ if (sKind === 9) {
+ if (tKind !== 9)
+ return false;
+ return A._isInterfaceSubtype(universe, s, sEnv, t, tEnv, false);
+ }
+ if (t2 && tKind === 11)
+ return A._isRecordSubtype(universe, s, sEnv, t, tEnv, false);
+ return false;
+ },
+ _isFunctionSubtype(universe, s, sEnv, t, tEnv, isLegacy) {
+ var sParameters, tParameters, sRequiredPositional, tRequiredPositional, sRequiredPositionalLength, tRequiredPositionalLength, requiredPositionalDelta, sOptionalPositional, tOptionalPositional, sOptionalPositionalLength, tOptionalPositionalLength, i, t1, sNamed, tNamed, sNamedLength, tNamedLength, sIndex, tIndex, tName, sName, sIsRequired;
+ if (!A._isSubtype(universe, s._primary, sEnv, t._primary, tEnv, false))
+ return false;
+ sParameters = s._rest;
+ tParameters = t._rest;
+ sRequiredPositional = sParameters._requiredPositional;
+ tRequiredPositional = tParameters._requiredPositional;
+ sRequiredPositionalLength = sRequiredPositional.length;
+ tRequiredPositionalLength = tRequiredPositional.length;
+ if (sRequiredPositionalLength > tRequiredPositionalLength)
+ return false;
+ requiredPositionalDelta = tRequiredPositionalLength - sRequiredPositionalLength;
+ sOptionalPositional = sParameters._optionalPositional;
+ tOptionalPositional = tParameters._optionalPositional;
+ sOptionalPositionalLength = sOptionalPositional.length;
+ tOptionalPositionalLength = tOptionalPositional.length;
+ if (sRequiredPositionalLength + sOptionalPositionalLength < tRequiredPositionalLength + tOptionalPositionalLength)
+ return false;
+ for (i = 0; i < sRequiredPositionalLength; ++i) {
+ t1 = sRequiredPositional[i];
+ if (!A._isSubtype(universe, tRequiredPositional[i], tEnv, t1, sEnv, false))
+ return false;
+ }
+ for (i = 0; i < requiredPositionalDelta; ++i) {
+ t1 = sOptionalPositional[i];
+ if (!A._isSubtype(universe, tRequiredPositional[sRequiredPositionalLength + i], tEnv, t1, sEnv, false))
+ return false;
+ }
+ for (i = 0; i < tOptionalPositionalLength; ++i) {
+ t1 = sOptionalPositional[requiredPositionalDelta + i];
+ if (!A._isSubtype(universe, tOptionalPositional[i], tEnv, t1, sEnv, false))
+ return false;
+ }
+ sNamed = sParameters._named;
+ tNamed = tParameters._named;
+ sNamedLength = sNamed.length;
+ tNamedLength = tNamed.length;
+ for (sIndex = 0, tIndex = 0; tIndex < tNamedLength; tIndex += 3) {
+ tName = tNamed[tIndex];
+ for (; true;) {
+ if (sIndex >= sNamedLength)
+ return false;
+ sName = sNamed[sIndex];
+ sIndex += 3;
+ if (tName < sName)
+ return false;
+ sIsRequired = sNamed[sIndex - 2];
+ if (sName < tName) {
+ if (sIsRequired)
+ return false;
+ continue;
+ }
+ t1 = tNamed[tIndex + 1];
+ if (sIsRequired && !t1)
+ return false;
+ t1 = sNamed[sIndex - 1];
+ if (!A._isSubtype(universe, tNamed[tIndex + 2], tEnv, t1, sEnv, false))
+ return false;
+ break;
+ }
+ }
+ for (; sIndex < sNamedLength;) {
+ if (sNamed[sIndex + 1])
+ return false;
+ sIndex += 3;
+ }
+ return true;
+ },
+ _isInterfaceSubtype(universe, s, sEnv, t, tEnv, isLegacy) {
+ var rule, recipes, $length, supertypeArgs, i,
+ sName = s._primary,
+ tName = t._primary;
+ for (; sName !== tName;) {
+ rule = universe.tR[sName];
+ if (rule == null)
+ return false;
+ if (typeof rule == "string") {
+ sName = rule;
+ continue;
+ }
+ recipes = rule[tName];
+ if (recipes == null)
+ return false;
+ $length = recipes.length;
+ supertypeArgs = $length > 0 ? new Array($length) : init.typeUniverse.sEA;
+ for (i = 0; i < $length; ++i)
+ supertypeArgs[i] = A._Universe_evalInEnvironment(universe, s, recipes[i]);
+ return A._areArgumentsSubtypes(universe, supertypeArgs, null, sEnv, t._rest, tEnv, false);
+ }
+ return A._areArgumentsSubtypes(universe, s._rest, null, sEnv, t._rest, tEnv, false);
+ },
+ _areArgumentsSubtypes(universe, sArgs, sVariances, sEnv, tArgs, tEnv, isLegacy) {
+ var i,
+ $length = sArgs.length;
+ for (i = 0; i < $length; ++i)
+ if (!A._isSubtype(universe, sArgs[i], sEnv, tArgs[i], tEnv, false))
+ return false;
+ return true;
+ },
+ _isRecordSubtype(universe, s, sEnv, t, tEnv, isLegacy) {
+ var i,
+ sFields = s._rest,
+ tFields = t._rest,
+ sCount = sFields.length;
+ if (sCount !== tFields.length)
+ return false;
+ if (s._primary !== t._primary)
+ return false;
+ for (i = 0; i < sCount; ++i)
+ if (!A._isSubtype(universe, sFields[i], sEnv, tFields[i], tEnv, false))
+ return false;
+ return true;
+ },
+ isNullable(t) {
+ var t1,
+ kind = t._kind;
+ if (!(t === type$.Null || t === type$.JSNull))
+ if (!A.isSoundTopType(t))
+ if (kind !== 7)
+ if (!(kind === 6 && A.isNullable(t._primary)))
+ t1 = kind === 8 && A.isNullable(t._primary);
+ else
+ t1 = true;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ else
+ t1 = true;
+ return t1;
+ },
+ isDefinitelyTopType(t) {
+ var t1;
+ if (!A.isSoundTopType(t))
+ t1 = t === type$.legacy_Object;
+ else
+ t1 = true;
+ return t1;
+ },
+ isSoundTopType(t) {
+ var kind = t._kind;
+ return kind === 2 || kind === 3 || kind === 4 || kind === 5 || t === type$.nullable_Object;
+ },
+ _Utils_objectAssign(o, other) {
+ var i, key,
+ keys = Object.keys(other),
+ $length = keys.length;
+ for (i = 0; i < $length; ++i) {
+ key = keys[i];
+ o[key] = other[key];
+ }
+ },
+ _Utils_newArrayOrEmpty($length) {
+ return $length > 0 ? new Array($length) : init.typeUniverse.sEA;
+ },
+ Rti: function Rti(t0, t1) {
+ var _ = this;
+ _._as = t0;
+ _._is = t1;
+ _._cachedRuntimeType = _._specializedTestResource = _._isSubtypeCache = _._precomputed1 = null;
+ _._kind = 0;
+ _._canonicalRecipe = _._bindCache = _._evalCache = _._rest = _._primary = null;
+ },
+ _FunctionParameters: function _FunctionParameters() {
+ this._named = this._optionalPositional = this._requiredPositional = null;
+ },
+ _Type: function _Type(t0) {
+ this._rti = t0;
+ },
+ _Error: function _Error() {
+ },
+ _TypeError: function _TypeError(t0) {
+ this.__rti$_message = t0;
+ },
+ _AsyncRun__initializeScheduleImmediate() {
+ var div, span, t1 = {};
+ if (self.scheduleImmediate != null)
+ return A.async__AsyncRun__scheduleImmediateJsOverride$closure();
+ if (self.MutationObserver != null && self.document != null) {
+ div = self.document.createElement("div");
+ span = self.document.createElement("span");
+ t1.storedCallback = null;
+ new self.MutationObserver(A.convertDartClosureToJS(new A._AsyncRun__initializeScheduleImmediate_internalCallback(t1), 1)).observe(div, {childList: true});
+ return new A._AsyncRun__initializeScheduleImmediate_closure(t1, div, span);
+ } else if (self.setImmediate != null)
+ return A.async__AsyncRun__scheduleImmediateWithSetImmediate$closure();
+ return A.async__AsyncRun__scheduleImmediateWithTimer$closure();
+ },
+ _AsyncRun__scheduleImmediateJsOverride(callback) {
+ self.scheduleImmediate(A.convertDartClosureToJS(new A._AsyncRun__scheduleImmediateJsOverride_internalCallback(type$.void_Function._as(callback)), 0));
+ },
+ _AsyncRun__scheduleImmediateWithSetImmediate(callback) {
+ self.setImmediate(A.convertDartClosureToJS(new A._AsyncRun__scheduleImmediateWithSetImmediate_internalCallback(type$.void_Function._as(callback)), 0));
+ },
+ _AsyncRun__scheduleImmediateWithTimer(callback) {
+ A.Timer__createTimer(B.Duration_0, type$.void_Function._as(callback));
+ },
+ Timer__createTimer(duration, callback) {
+ return A._TimerImpl$(duration._duration / 1000 | 0, callback);
+ },
+ _TimerImpl$(milliseconds, callback) {
+ var t1 = new A._TimerImpl();
+ t1._TimerImpl$2(milliseconds, callback);
+ return t1;
+ },
+ _makeAsyncAwaitCompleter($T) {
+ return new A._AsyncAwaitCompleter(new A._Future($.Zone__current, $T._eval$1("_Future<0>")), $T._eval$1("_AsyncAwaitCompleter<0>"));
+ },
+ _asyncStartSync(bodyFunction, completer) {
+ bodyFunction.call$2(0, null);
+ completer.isSync = true;
+ return completer._future;
+ },
+ _asyncAwait(object, bodyFunction) {
+ A._awaitOnObject(object, bodyFunction);
+ },
+ _asyncReturn(object, completer) {
+ completer.complete$1(object);
+ },
+ _asyncRethrow(object, completer) {
+ completer.completeError$2(A.unwrapException(object), A.getTraceFromException(object));
+ },
+ _awaitOnObject(object, bodyFunction) {
+ var t1, future,
+ thenCallback = new A._awaitOnObject_closure(bodyFunction),
+ errorCallback = new A._awaitOnObject_closure0(bodyFunction);
+ if (object instanceof A._Future)
+ object._thenAwait$1$2(thenCallback, errorCallback, type$.dynamic);
+ else {
+ t1 = type$.dynamic;
+ if (object instanceof A._Future)
+ object.then$1$2$onError(thenCallback, errorCallback, t1);
+ else {
+ future = new A._Future($.Zone__current, type$._Future_dynamic);
+ future._state = 8;
+ future._resultOrListeners = object;
+ future._thenAwait$1$2(thenCallback, errorCallback, t1);
+ }
+ }
+ },
+ _wrapJsFunctionForAsync($function) {
+ var $protected = function(fn, ERROR) {
+ return function(errorCode, result) {
+ while (true) {
+ try {
+ fn(errorCode, result);
+ break;
+ } catch (error) {
+ result = error;
+ errorCode = ERROR;
+ }
+ }
+ };
+ }($function, 1);
+ return $.Zone__current.registerBinaryCallback$3$1(new A._wrapJsFunctionForAsync_closure($protected), type$.void, type$.int, type$.dynamic);
+ },
+ AsyncError$(error, stackTrace) {
+ var t1 = A.checkNotNullable(error, "error", type$.Object);
+ return new A.AsyncError(t1, stackTrace == null ? A.AsyncError_defaultStackTrace(error) : stackTrace);
+ },
+ AsyncError_defaultStackTrace(error) {
+ var stackTrace;
+ if (type$.Error._is(error)) {
+ stackTrace = error.get$stackTrace();
+ if (stackTrace != null)
+ return stackTrace;
+ }
+ return B._StringStackTrace_3uE;
+ },
+ Future_Future$sync(computation, $T) {
+ var result, error, stackTrace, future, replacement, t1, exception;
+ try {
+ result = computation.call$0();
+ t1 = $T._eval$1("Future<0>")._is(result) ? result : A._Future$value(result, $T);
+ return t1;
+ } catch (exception) {
+ error = A.unwrapException(exception);
+ stackTrace = A.getTraceFromException(exception);
+ future = new A._Future($.Zone__current, $T._eval$1("_Future<0>"));
+ type$.Object._as(error);
+ type$.nullable_StackTrace._as(stackTrace);
+ replacement = null;
+ if (replacement != null)
+ future._asyncCompleteError$2(replacement.get$error(), replacement.get$stackTrace());
+ else
+ future._asyncCompleteError$2(error, stackTrace);
+ return future;
+ }
+ },
+ Future_Future$value(value, $T) {
+ var t1 = value == null ? $T._as(value) : value,
+ t2 = new A._Future($.Zone__current, $T._eval$1("_Future<0>"));
+ t2._asyncComplete$1(t1);
+ return t2;
+ },
+ Completer_Completer($T) {
+ return new A._AsyncCompleter(new A._Future($.Zone__current, $T._eval$1("_Future<0>")), $T._eval$1("_AsyncCompleter<0>"));
+ },
+ _Future$value(value, $T) {
+ var t1 = new A._Future($.Zone__current, $T._eval$1("_Future<0>"));
+ $T._as(value);
+ t1._state = 8;
+ t1._resultOrListeners = value;
+ return t1;
+ },
+ _Future__chainCoreFutureSync(source, target) {
+ var t1, t2, listeners;
+ for (t1 = type$._Future_dynamic; t2 = source._state, (t2 & 4) !== 0;)
+ source = t1._as(source._resultOrListeners);
+ if ((t2 & 24) !== 0) {
+ listeners = target._removeListeners$0();
+ target._cloneResult$1(source);
+ A._Future__propagateToListeners(target, listeners);
+ } else {
+ listeners = type$.nullable__FutureListener_dynamic_dynamic._as(target._resultOrListeners);
+ target._setChained$1(source);
+ source._prependListeners$1(listeners);
+ }
+ },
+ _Future__chainCoreFutureAsync(source, target) {
+ var t2, t3, listeners, _box_0 = {},
+ t1 = _box_0.source = source;
+ for (t2 = type$._Future_dynamic; t3 = t1._state, (t3 & 4) !== 0; t1 = source) {
+ source = t2._as(t1._resultOrListeners);
+ _box_0.source = source;
+ }
+ if ((t3 & 24) === 0) {
+ listeners = type$.nullable__FutureListener_dynamic_dynamic._as(target._resultOrListeners);
+ target._setChained$1(t1);
+ _box_0.source._prependListeners$1(listeners);
+ return;
+ }
+ if ((t3 & 16) === 0 && target._resultOrListeners == null) {
+ target._cloneResult$1(t1);
+ return;
+ }
+ target._state ^= 2;
+ A._rootScheduleMicrotask(null, null, target._zone, type$.void_Function._as(new A._Future__chainCoreFutureAsync_closure(_box_0, target)));
+ },
+ _Future__propagateToListeners(source, listeners) {
+ var t2, t3, t4, _box_0, t5, t6, hasError, asyncError, nextListener, nextListener0, sourceResult, t7, zone, oldZone, result, current, _box_1 = {},
+ t1 = _box_1.source = source;
+ for (t2 = type$.AsyncError, t3 = type$.nullable__FutureListener_dynamic_dynamic, t4 = type$.Future_dynamic; true;) {
+ _box_0 = {};
+ t5 = t1._state;
+ t6 = (t5 & 16) === 0;
+ hasError = !t6;
+ if (listeners == null) {
+ if (hasError && (t5 & 1) === 0) {
+ asyncError = t2._as(t1._resultOrListeners);
+ A._rootHandleError(asyncError.error, asyncError.stackTrace);
+ }
+ return;
+ }
+ _box_0.listener = listeners;
+ nextListener = listeners._nextListener;
+ for (t1 = listeners; nextListener != null; t1 = nextListener, nextListener = nextListener0) {
+ t1._nextListener = null;
+ A._Future__propagateToListeners(_box_1.source, t1);
+ _box_0.listener = nextListener;
+ nextListener0 = nextListener._nextListener;
+ }
+ t5 = _box_1.source;
+ sourceResult = t5._resultOrListeners;
+ _box_0.listenerHasError = hasError;
+ _box_0.listenerValueOrError = sourceResult;
+ if (t6) {
+ t7 = t1.state;
+ t7 = (t7 & 1) !== 0 || (t7 & 15) === 8;
+ } else
+ t7 = true;
+ if (t7) {
+ zone = t1.result._zone;
+ if (hasError) {
+ t5 = t5._zone === zone;
+ t5 = !(t5 || t5);
+ } else
+ t5 = false;
+ if (t5) {
+ t2._as(sourceResult);
+ A._rootHandleError(sourceResult.error, sourceResult.stackTrace);
+ return;
+ }
+ oldZone = $.Zone__current;
+ if (oldZone !== zone)
+ $.Zone__current = zone;
+ else
+ oldZone = null;
+ t1 = t1.state;
+ if ((t1 & 15) === 8)
+ new A._Future__propagateToListeners_handleWhenCompleteCallback(_box_0, _box_1, hasError).call$0();
+ else if (t6) {
+ if ((t1 & 1) !== 0)
+ new A._Future__propagateToListeners_handleValueCallback(_box_0, sourceResult).call$0();
+ } else if ((t1 & 2) !== 0)
+ new A._Future__propagateToListeners_handleError(_box_1, _box_0).call$0();
+ if (oldZone != null)
+ $.Zone__current = oldZone;
+ t1 = _box_0.listenerValueOrError;
+ if (t1 instanceof A._Future) {
+ t5 = _box_0.listener.$ti;
+ t5 = t5._eval$1("Future<2>")._is(t1) || !t5._rest[1]._is(t1);
+ } else
+ t5 = false;
+ if (t5) {
+ t4._as(t1);
+ result = _box_0.listener.result;
+ if ((t1._state & 24) !== 0) {
+ current = t3._as(result._resultOrListeners);
+ result._resultOrListeners = null;
+ listeners = result._reverseListeners$1(current);
+ result._state = t1._state & 30 | result._state & 1;
+ result._resultOrListeners = t1._resultOrListeners;
+ _box_1.source = t1;
+ continue;
+ } else
+ A._Future__chainCoreFutureSync(t1, result);
+ return;
+ }
+ }
+ result = _box_0.listener.result;
+ current = t3._as(result._resultOrListeners);
+ result._resultOrListeners = null;
+ listeners = result._reverseListeners$1(current);
+ t1 = _box_0.listenerHasError;
+ t5 = _box_0.listenerValueOrError;
+ if (!t1) {
+ result.$ti._precomputed1._as(t5);
+ result._state = 8;
+ result._resultOrListeners = t5;
+ } else {
+ t2._as(t5);
+ result._state = result._state & 1 | 16;
+ result._resultOrListeners = t5;
+ }
+ _box_1.source = result;
+ t1 = result;
+ }
+ },
+ _registerErrorHandler(errorHandler, zone) {
+ var t1;
+ if (type$.dynamic_Function_Object_StackTrace._is(errorHandler))
+ return zone.registerBinaryCallback$3$1(errorHandler, type$.dynamic, type$.Object, type$.StackTrace);
+ t1 = type$.dynamic_Function_Object;
+ if (t1._is(errorHandler))
+ return t1._as(errorHandler);
+ throw A.wrapException(A.ArgumentError$value(errorHandler, "onError", string$.Error_));
+ },
+ _microtaskLoop() {
+ var entry, next;
+ for (entry = $._nextCallback; entry != null; entry = $._nextCallback) {
+ $._lastPriorityCallback = null;
+ next = entry.next;
+ $._nextCallback = next;
+ if (next == null)
+ $._lastCallback = null;
+ entry.callback.call$0();
+ }
+ },
+ _startMicrotaskLoop() {
+ $._isInCallbackLoop = true;
+ try {
+ A._microtaskLoop();
+ } finally {
+ $._lastPriorityCallback = null;
+ $._isInCallbackLoop = false;
+ if ($._nextCallback != null)
+ $.$get$_AsyncRun__scheduleImmediateClosure().call$1(A.async___startMicrotaskLoop$closure());
+ }
+ },
+ _scheduleAsyncCallback(callback) {
+ var newEntry = new A._AsyncCallbackEntry(callback),
+ lastCallback = $._lastCallback;
+ if (lastCallback == null) {
+ $._nextCallback = $._lastCallback = newEntry;
+ if (!$._isInCallbackLoop)
+ $.$get$_AsyncRun__scheduleImmediateClosure().call$1(A.async___startMicrotaskLoop$closure());
+ } else
+ $._lastCallback = lastCallback.next = newEntry;
+ },
+ _schedulePriorityAsyncCallback(callback) {
+ var entry, lastPriorityCallback, next,
+ t1 = $._nextCallback;
+ if (t1 == null) {
+ A._scheduleAsyncCallback(callback);
+ $._lastPriorityCallback = $._lastCallback;
+ return;
+ }
+ entry = new A._AsyncCallbackEntry(callback);
+ lastPriorityCallback = $._lastPriorityCallback;
+ if (lastPriorityCallback == null) {
+ entry.next = t1;
+ $._nextCallback = $._lastPriorityCallback = entry;
+ } else {
+ next = lastPriorityCallback.next;
+ entry.next = next;
+ $._lastPriorityCallback = lastPriorityCallback.next = entry;
+ if (next == null)
+ $._lastCallback = entry;
+ }
+ },
+ scheduleMicrotask(callback) {
+ var _null = null,
+ currentZone = $.Zone__current;
+ if (B.C__RootZone === currentZone) {
+ A._rootScheduleMicrotask(_null, _null, B.C__RootZone, callback);
+ return;
+ }
+ A._rootScheduleMicrotask(_null, _null, currentZone, type$.void_Function._as(currentZone.bindCallbackGuarded$1(callback)));
+ },
+ StreamIterator_StreamIterator(stream, $T) {
+ A.checkNotNullable(stream, "stream", type$.Object);
+ return new A._StreamIterator($T._eval$1("_StreamIterator<0>"));
+ },
+ StreamController_StreamController($T) {
+ var _null = null;
+ return new A._AsyncStreamController(_null, _null, _null, _null, $T._eval$1("_AsyncStreamController<0>"));
+ },
+ _runGuarded(notificationHandler) {
+ return;
+ },
+ _BufferingStreamSubscription__registerDataHandler(zone, handleData, $T) {
+ var t1 = handleData == null ? A.async___nullDataHandler$closure() : handleData;
+ return type$.$env_1_1_void._bind$1($T)._eval$1("1(2)")._as(t1);
+ },
+ _BufferingStreamSubscription__registerErrorHandler(zone, handleError) {
+ if (handleError == null)
+ handleError = A.async___nullErrorHandler$closure();
+ if (type$.void_Function_Object_StackTrace._is(handleError))
+ return zone.registerBinaryCallback$3$1(handleError, type$.dynamic, type$.Object, type$.StackTrace);
+ if (type$.void_Function_Object._is(handleError))
+ return type$.dynamic_Function_Object._as(handleError);
+ throw A.wrapException(A.ArgumentError$("handleError callback must take either an Object (the error), or both an Object (the error) and a StackTrace.", null));
+ },
+ _nullDataHandler(value) {
+ },
+ _nullErrorHandler(error, stackTrace) {
+ A._rootHandleError(type$.Object._as(error), type$.StackTrace._as(stackTrace));
+ },
+ _nullDoneHandler() {
+ },
+ _cancelAndValue(subscription, future, value) {
+ var cancelFuture = subscription.cancel$0(),
+ t1 = $.$get$Future__nullFuture();
+ if (cancelFuture !== t1)
+ cancelFuture.whenComplete$1(new A._cancelAndValue_closure(future, value));
+ else
+ future._complete$1(value);
+ },
+ Timer_Timer(duration, callback) {
+ var t1 = $.Zone__current;
+ if (t1 === B.C__RootZone)
+ return A.Timer__createTimer(duration, type$.void_Function._as(callback));
+ return A.Timer__createTimer(duration, type$.void_Function._as(t1.bindCallbackGuarded$1(callback)));
+ },
+ _rootHandleError(error, stackTrace) {
+ A._schedulePriorityAsyncCallback(new A._rootHandleError_closure(error, stackTrace));
+ },
+ _rootRun($self, $parent, zone, f, $R) {
+ var old,
+ t1 = $.Zone__current;
+ if (t1 === zone)
+ return f.call$0();
+ $.Zone__current = zone;
+ old = t1;
+ try {
+ t1 = f.call$0();
+ return t1;
+ } finally {
+ $.Zone__current = old;
+ }
+ },
+ _rootRunUnary($self, $parent, zone, f, arg, $R, $T) {
+ var old,
+ t1 = $.Zone__current;
+ if (t1 === zone)
+ return f.call$1(arg);
+ $.Zone__current = zone;
+ old = t1;
+ try {
+ t1 = f.call$1(arg);
+ return t1;
+ } finally {
+ $.Zone__current = old;
+ }
+ },
+ _rootRunBinary($self, $parent, zone, f, arg1, arg2, $R, T1, T2) {
+ var old,
+ t1 = $.Zone__current;
+ if (t1 === zone)
+ return f.call$2(arg1, arg2);
+ $.Zone__current = zone;
+ old = t1;
+ try {
+ t1 = f.call$2(arg1, arg2);
+ return t1;
+ } finally {
+ $.Zone__current = old;
+ }
+ },
+ _rootScheduleMicrotask($self, $parent, zone, f) {
+ type$.void_Function._as(f);
+ if (B.C__RootZone !== zone)
+ f = zone.bindCallbackGuarded$1(f);
+ A._scheduleAsyncCallback(f);
+ },
+ _AsyncRun__initializeScheduleImmediate_internalCallback: function _AsyncRun__initializeScheduleImmediate_internalCallback(t0) {
+ this._box_0 = t0;
+ },
+ _AsyncRun__initializeScheduleImmediate_closure: function _AsyncRun__initializeScheduleImmediate_closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.div = t1;
+ this.span = t2;
+ },
+ _AsyncRun__scheduleImmediateJsOverride_internalCallback: function _AsyncRun__scheduleImmediateJsOverride_internalCallback(t0) {
+ this.callback = t0;
+ },
+ _AsyncRun__scheduleImmediateWithSetImmediate_internalCallback: function _AsyncRun__scheduleImmediateWithSetImmediate_internalCallback(t0) {
+ this.callback = t0;
+ },
+ _TimerImpl: function _TimerImpl() {
+ this._handle = null;
+ },
+ _TimerImpl_internalCallback: function _TimerImpl_internalCallback(t0, t1) {
+ this.$this = t0;
+ this.callback = t1;
+ },
+ _AsyncAwaitCompleter: function _AsyncAwaitCompleter(t0, t1) {
+ this._future = t0;
+ this.isSync = false;
+ this.$ti = t1;
+ },
+ _awaitOnObject_closure: function _awaitOnObject_closure(t0) {
+ this.bodyFunction = t0;
+ },
+ _awaitOnObject_closure0: function _awaitOnObject_closure0(t0) {
+ this.bodyFunction = t0;
+ },
+ _wrapJsFunctionForAsync_closure: function _wrapJsFunctionForAsync_closure(t0) {
+ this.$protected = t0;
+ },
+ AsyncError: function AsyncError(t0, t1) {
+ this.error = t0;
+ this.stackTrace = t1;
+ },
+ _Completer: function _Completer() {
+ },
+ _AsyncCompleter: function _AsyncCompleter(t0, t1) {
+ this.future = t0;
+ this.$ti = t1;
+ },
+ _SyncCompleter: function _SyncCompleter(t0, t1) {
+ this.future = t0;
+ this.$ti = t1;
+ },
+ _FutureListener: function _FutureListener(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._nextListener = null;
+ _.result = t0;
+ _.state = t1;
+ _.callback = t2;
+ _.errorCallback = t3;
+ _.$ti = t4;
+ },
+ _Future: function _Future(t0, t1) {
+ var _ = this;
+ _._state = 0;
+ _._zone = t0;
+ _._resultOrListeners = null;
+ _.$ti = t1;
+ },
+ _Future__addListener_closure: function _Future__addListener_closure(t0, t1) {
+ this.$this = t0;
+ this.listener = t1;
+ },
+ _Future__prependListeners_closure: function _Future__prependListeners_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ _Future__chainForeignFuture_closure: function _Future__chainForeignFuture_closure(t0) {
+ this.$this = t0;
+ },
+ _Future__chainForeignFuture_closure0: function _Future__chainForeignFuture_closure0(t0) {
+ this.$this = t0;
+ },
+ _Future__chainForeignFuture_closure1: function _Future__chainForeignFuture_closure1(t0, t1, t2) {
+ this.$this = t0;
+ this.e = t1;
+ this.s = t2;
+ },
+ _Future__chainCoreFutureAsync_closure: function _Future__chainCoreFutureAsync_closure(t0, t1) {
+ this._box_0 = t0;
+ this.target = t1;
+ },
+ _Future__asyncCompleteWithValue_closure: function _Future__asyncCompleteWithValue_closure(t0, t1) {
+ this.$this = t0;
+ this.value = t1;
+ },
+ _Future__asyncCompleteError_closure: function _Future__asyncCompleteError_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.error = t1;
+ this.stackTrace = t2;
+ },
+ _Future__propagateToListeners_handleWhenCompleteCallback: function _Future__propagateToListeners_handleWhenCompleteCallback(t0, t1, t2) {
+ this._box_0 = t0;
+ this._box_1 = t1;
+ this.hasError = t2;
+ },
+ _Future__propagateToListeners_handleWhenCompleteCallback_closure: function _Future__propagateToListeners_handleWhenCompleteCallback_closure(t0) {
+ this.originalSource = t0;
+ },
+ _Future__propagateToListeners_handleValueCallback: function _Future__propagateToListeners_handleValueCallback(t0, t1) {
+ this._box_0 = t0;
+ this.sourceResult = t1;
+ },
+ _Future__propagateToListeners_handleError: function _Future__propagateToListeners_handleError(t0, t1) {
+ this._box_1 = t0;
+ this._box_0 = t1;
+ },
+ _AsyncCallbackEntry: function _AsyncCallbackEntry(t0) {
+ this.callback = t0;
+ this.next = null;
+ },
+ Stream: function Stream() {
+ },
+ Stream_length_closure: function Stream_length_closure(t0, t1) {
+ this._box_0 = t0;
+ this.$this = t1;
+ },
+ Stream_length_closure0: function Stream_length_closure0(t0, t1) {
+ this._box_0 = t0;
+ this.future = t1;
+ },
+ Stream_first_closure: function Stream_first_closure(t0) {
+ this.future = t0;
+ },
+ Stream_first_closure0: function Stream_first_closure0(t0, t1, t2) {
+ this.$this = t0;
+ this.subscription = t1;
+ this.future = t2;
+ },
+ _StreamController: function _StreamController() {
+ },
+ _StreamController__subscribe_closure: function _StreamController__subscribe_closure(t0) {
+ this.$this = t0;
+ },
+ _StreamController__recordCancel_complete: function _StreamController__recordCancel_complete(t0) {
+ this.$this = t0;
+ },
+ _AsyncStreamControllerDispatch: function _AsyncStreamControllerDispatch() {
+ },
+ _AsyncStreamController: function _AsyncStreamController(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._varData = null;
+ _._state = 0;
+ _._doneFuture = null;
+ _.onListen = t0;
+ _.onPause = t1;
+ _.onResume = t2;
+ _.onCancel = t3;
+ _.$ti = t4;
+ },
+ _ControllerStream: function _ControllerStream(t0, t1) {
+ this._controller = t0;
+ this.$ti = t1;
+ },
+ _ControllerSubscription: function _ControllerSubscription(t0, t1, t2, t3, t4, t5, t6) {
+ var _ = this;
+ _._controller = t0;
+ _._onData = t1;
+ _._onError = t2;
+ _._onDone = t3;
+ _._zone = t4;
+ _._state = t5;
+ _._pending = _._cancelFuture = null;
+ _.$ti = t6;
+ },
+ _StreamSinkWrapper: function _StreamSinkWrapper(t0, t1) {
+ this._async$_target = t0;
+ this.$ti = t1;
+ },
+ _BufferingStreamSubscription: function _BufferingStreamSubscription() {
+ },
+ _BufferingStreamSubscription_asFuture_closure: function _BufferingStreamSubscription_asFuture_closure(t0, t1) {
+ this._box_0 = t0;
+ this.result = t1;
+ },
+ _BufferingStreamSubscription_asFuture_closure0: function _BufferingStreamSubscription_asFuture_closure0(t0, t1) {
+ this.$this = t0;
+ this.result = t1;
+ },
+ _BufferingStreamSubscription_asFuture__closure: function _BufferingStreamSubscription_asFuture__closure(t0, t1, t2) {
+ this.result = t0;
+ this.error = t1;
+ this.stackTrace = t2;
+ },
+ _BufferingStreamSubscription__sendError_sendError: function _BufferingStreamSubscription__sendError_sendError(t0, t1, t2) {
+ this.$this = t0;
+ this.error = t1;
+ this.stackTrace = t2;
+ },
+ _BufferingStreamSubscription__sendDone_sendDone: function _BufferingStreamSubscription__sendDone_sendDone(t0) {
+ this.$this = t0;
+ },
+ _StreamImpl: function _StreamImpl() {
+ },
+ _DelayedEvent: function _DelayedEvent() {
+ },
+ _DelayedData: function _DelayedData(t0, t1) {
+ this.value = t0;
+ this.next = null;
+ this.$ti = t1;
+ },
+ _DelayedError: function _DelayedError(t0, t1) {
+ this.error = t0;
+ this.stackTrace = t1;
+ this.next = null;
+ },
+ _DelayedDone: function _DelayedDone() {
+ },
+ _PendingEvents: function _PendingEvents(t0) {
+ var _ = this;
+ _._state = 0;
+ _.lastPendingEvent = _.firstPendingEvent = null;
+ _.$ti = t0;
+ },
+ _PendingEvents_schedule_closure: function _PendingEvents_schedule_closure(t0, t1) {
+ this.$this = t0;
+ this.dispatch = t1;
+ },
+ _StreamIterator: function _StreamIterator(t0) {
+ this.$ti = t0;
+ },
+ _cancelAndValue_closure: function _cancelAndValue_closure(t0, t1) {
+ this.future = t0;
+ this.value = t1;
+ },
+ _Zone: function _Zone() {
+ },
+ _rootHandleError_closure: function _rootHandleError_closure(t0, t1) {
+ this.error = t0;
+ this.stackTrace = t1;
+ },
+ _RootZone: function _RootZone() {
+ },
+ _RootZone_bindCallbackGuarded_closure: function _RootZone_bindCallbackGuarded_closure(t0, t1) {
+ this.$this = t0;
+ this.f = t1;
+ },
+ _RootZone_bindUnaryCallbackGuarded_closure: function _RootZone_bindUnaryCallbackGuarded_closure(t0, t1, t2) {
+ this.$this = t0;
+ this.f = t1;
+ this.T = t2;
+ },
+ _HashMap__getTableEntry(table, key) {
+ var entry = table[key];
+ return entry === table ? null : entry;
+ },
+ _HashMap__setTableEntry(table, key, value) {
+ if (value == null)
+ table[key] = table;
+ else
+ table[key] = value;
+ },
+ _HashMap__newHashTable() {
+ var table = Object.create(null);
+ A._HashMap__setTableEntry(table, "<non-identifier-key>", table);
+ delete table["<non-identifier-key>"];
+ return table;
+ },
+ LinkedHashMap_LinkedHashMap$_empty($K, $V) {
+ return new A.JsLinkedHashMap($K._eval$1("@<0>")._bind$1($V)._eval$1("JsLinkedHashMap<1,2>"));
+ },
+ MapBase_mapToString(m) {
+ var result, t1 = {};
+ if (A.isToStringVisiting(m))
+ return "{...}";
+ result = new A.StringBuffer("");
+ try {
+ B.JSArray_methods.add$1($.toStringVisiting, m);
+ result._contents += "{";
+ t1.first = true;
+ m.forEach$1(0, new A.MapBase_mapToString_closure(t1, result));
+ result._contents += "}";
+ } finally {
+ if (0 >= $.toStringVisiting.length)
+ return A.ioore($.toStringVisiting, -1);
+ $.toStringVisiting.pop();
+ }
+ t1 = result._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ ListQueue$($E) {
+ return new A.ListQueue(A.List_List$filled(A.ListQueue__calculateCapacity(null), null, false, $E._eval$1("0?")), $E._eval$1("ListQueue<0>"));
+ },
+ ListQueue__calculateCapacity(initialCapacity) {
+ return 8;
+ },
+ _HashMap: function _HashMap() {
+ },
+ _IdentityHashMap: function _IdentityHashMap(t0) {
+ var _ = this;
+ _._collection$_length = 0;
+ _._collection$_keys = _._collection$_rest = _._collection$_nums = _._collection$_strings = null;
+ _.$ti = t0;
+ },
+ _HashMapKeyIterable: function _HashMapKeyIterable(t0, t1) {
+ this._collection$_map = t0;
+ this.$ti = t1;
+ },
+ _HashMapKeyIterator: function _HashMapKeyIterator(t0, t1, t2) {
+ var _ = this;
+ _._collection$_map = t0;
+ _._collection$_keys = t1;
+ _._offset = 0;
+ _._collection$_current = null;
+ _.$ti = t2;
+ },
+ ListBase: function ListBase() {
+ },
+ MapBase: function MapBase() {
+ },
+ MapBase_mapToString_closure: function MapBase_mapToString_closure(t0, t1) {
+ this._box_0 = t0;
+ this.result = t1;
+ },
+ _UnmodifiableMapMixin: function _UnmodifiableMapMixin() {
+ },
+ MapView: function MapView() {
+ },
+ UnmodifiableMapView: function UnmodifiableMapView() {
+ },
+ ListQueue: function ListQueue(t0, t1) {
+ var _ = this;
+ _._table = t0;
+ _._modificationCount = _._tail = _._head = 0;
+ _.$ti = t1;
+ },
+ _ListQueueIterator: function _ListQueueIterator(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._queue = t0;
+ _._end = t1;
+ _._modificationCount = t2;
+ _._position = t3;
+ _._collection$_current = null;
+ _.$ti = t4;
+ },
+ _UnmodifiableMapView_MapView__UnmodifiableMapMixin: function _UnmodifiableMapView_MapView__UnmodifiableMapMixin() {
+ },
+ _parseJson(source, reviver) {
+ var e, exception, t1, parsed = null;
+ try {
+ parsed = JSON.parse(source);
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ t1 = A.FormatException$(String(e), null, null);
+ throw A.wrapException(t1);
+ }
+ t1 = A._convertJsonToDartLazy(parsed);
+ return t1;
+ },
+ _convertJsonToDartLazy(object) {
+ var i;
+ if (object == null)
+ return null;
+ if (typeof object != "object")
+ return object;
+ if (Object.getPrototypeOf(object) !== Array.prototype)
+ return new A._JsonMap(object, Object.create(null));
+ for (i = 0; i < object.length; ++i)
+ object[i] = A._convertJsonToDartLazy(object[i]);
+ return object;
+ },
+ JsonUnsupportedObjectError$(unsupportedObject, cause, partialResult) {
+ return new A.JsonUnsupportedObjectError(unsupportedObject, cause);
+ },
+ _defaultToEncodable(object) {
+ return object.toJson$0();
+ },
+ _JsonStringStringifier$(_sink, _toEncodable) {
+ return new A._JsonStringStringifier(_sink, [], A.convert___defaultToEncodable$closure());
+ },
+ _JsonStringStringifier_stringify(object, toEncodable, indent) {
+ var t1,
+ output = new A.StringBuffer(""),
+ stringifier = A._JsonStringStringifier$(output, toEncodable);
+ stringifier.writeObject$1(object);
+ t1 = output._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ _JsonMap: function _JsonMap(t0, t1) {
+ this._original = t0;
+ this._processed = t1;
+ this._data = null;
+ },
+ _JsonMapKeyIterable: function _JsonMapKeyIterable(t0) {
+ this._parent = t0;
+ },
+ Codec: function Codec() {
+ },
+ Converter: function Converter() {
+ },
+ JsonUnsupportedObjectError: function JsonUnsupportedObjectError(t0, t1) {
+ this.unsupportedObject = t0;
+ this.cause = t1;
+ },
+ JsonCyclicError: function JsonCyclicError(t0, t1) {
+ this.unsupportedObject = t0;
+ this.cause = t1;
+ },
+ JsonCodec: function JsonCodec() {
+ },
+ JsonEncoder: function JsonEncoder(t0) {
+ this._toEncodable = t0;
+ },
+ JsonDecoder: function JsonDecoder(t0) {
+ this._reviver = t0;
+ },
+ _JsonStringifier: function _JsonStringifier() {
+ },
+ _JsonStringifier_writeMap_closure: function _JsonStringifier_writeMap_closure(t0, t1) {
+ this._box_0 = t0;
+ this.keyValueList = t1;
+ },
+ _JsonStringStringifier: function _JsonStringStringifier(t0, t1, t2) {
+ this._sink = t0;
+ this._seen = t1;
+ this._toEncodable = t2;
+ },
+ int_parse(source, radix) {
+ var value = A.Primitives_parseInt(source, radix);
+ if (value != null)
+ return value;
+ throw A.wrapException(A.FormatException$(source, null, null));
+ },
+ Error__throw(error, stackTrace) {
+ error = A.wrapException(error);
+ if (error == null)
+ error = type$.Object._as(error);
+ error.stack = stackTrace.toString$0(0);
+ throw error;
+ throw A.wrapException("unreachable");
+ },
+ List_List$filled($length, fill, growable, $E) {
+ var i,
+ result = growable ? J.JSArray_JSArray$growable($length, $E) : J.JSArray_JSArray$fixed($length, $E);
+ if ($length !== 0 && fill != null)
+ for (i = 0; i < result.length; ++i)
+ result[i] = fill;
+ return result;
+ },
+ List_List$of(elements, growable, $E) {
+ var t1 = A.List_List$_of(elements, $E);
+ return t1;
+ },
+ List_List$_of(elements, $E) {
+ var list, t1;
+ if (Array.isArray(elements))
+ return A._setArrayType(elements.slice(0), $E._eval$1("JSArray<0>"));
+ list = A._setArrayType([], $E._eval$1("JSArray<0>"));
+ for (t1 = J.get$iterator$ax(elements); t1.moveNext$0();)
+ B.JSArray_methods.add$1(list, t1.get$current());
+ return list;
+ },
+ StringBuffer__writeAll(string, objects, separator) {
+ var iterator = J.get$iterator$ax(objects);
+ if (!iterator.moveNext$0())
+ return string;
+ if (separator.length === 0) {
+ do
+ string += A.S(iterator.get$current());
+ while (iterator.moveNext$0());
+ } else {
+ string += A.S(iterator.get$current());
+ for (; iterator.moveNext$0();)
+ string = string + separator + A.S(iterator.get$current());
+ }
+ return string;
+ },
+ NoSuchMethodError_NoSuchMethodError$withInvocation(receiver, invocation) {
+ return new A.NoSuchMethodError(receiver, invocation.get$memberName(), invocation.get$positionalArguments(), invocation.get$namedArguments());
+ },
+ StackTrace_current() {
+ return A.getTraceFromException(new Error());
+ },
+ DateTime__fourDigits(n) {
+ var absN = Math.abs(n),
+ sign = n < 0 ? "-" : "";
+ if (absN >= 1000)
+ return "" + n;
+ if (absN >= 100)
+ return sign + "0" + absN;
+ if (absN >= 10)
+ return sign + "00" + absN;
+ return sign + "000" + absN;
+ },
+ DateTime__threeDigits(n) {
+ if (n >= 100)
+ return "" + n;
+ if (n >= 10)
+ return "0" + n;
+ return "00" + n;
+ },
+ DateTime__twoDigits(n) {
+ if (n >= 10)
+ return "" + n;
+ return "0" + n;
+ },
+ Error_safeToString(object) {
+ if (typeof object == "number" || A._isBool(object) || object == null)
+ return J.toString$0$(object);
+ if (typeof object == "string")
+ return JSON.stringify(object);
+ return A.Primitives_safeToString(object);
+ },
+ Error_throwWithStackTrace(error, stackTrace) {
+ A.checkNotNullable(error, "error", type$.Object);
+ A.checkNotNullable(stackTrace, "stackTrace", type$.StackTrace);
+ A.Error__throw(error, stackTrace);
+ },
+ AssertionError$(message) {
+ return new A.AssertionError(message);
+ },
+ ArgumentError$(message, $name) {
+ return new A.ArgumentError(false, null, $name, message);
+ },
+ ArgumentError$value(value, $name, message) {
+ return new A.ArgumentError(true, value, $name, message);
+ },
+ ArgumentError$notNull($name) {
+ return new A.ArgumentError(false, null, $name, "Must not be null");
+ },
+ RangeError$(message) {
+ var _null = null;
+ return new A.RangeError(_null, _null, false, _null, _null, message);
+ },
+ RangeError$value(value, $name) {
+ return new A.RangeError(null, null, true, value, $name, "Value not in range");
+ },
+ RangeError$range(invalidValue, minValue, maxValue, $name, message) {
+ return new A.RangeError(minValue, maxValue, true, invalidValue, $name, "Invalid value");
+ },
+ RangeError_checkValidRange(start, end, $length) {
+ if (0 > start || start > $length)
+ throw A.wrapException(A.RangeError$range(start, 0, $length, "start", null));
+ if (end != null) {
+ if (start > end || end > $length)
+ throw A.wrapException(A.RangeError$range(end, start, $length, "end", null));
+ return end;
+ }
+ return $length;
+ },
+ RangeError_checkNotNegative(value, $name) {
+ if (value < 0)
+ throw A.wrapException(A.RangeError$range(value, 0, null, $name, null));
+ return value;
+ },
+ IndexError$withLength(invalidValue, $length, indexable, message, $name) {
+ return new A.IndexError($length, true, invalidValue, $name, "Index out of range");
+ },
+ UnsupportedError$(message) {
+ return new A.UnsupportedError(message);
+ },
+ UnimplementedError$(message) {
+ return new A.UnimplementedError(message);
+ },
+ StateError$(message) {
+ return new A.StateError(message);
+ },
+ ConcurrentModificationError$(modifiedObject) {
+ return new A.ConcurrentModificationError(modifiedObject);
+ },
+ FormatException$(message, source, offset) {
+ return new A.FormatException(message, source, offset);
+ },
+ Iterable_iterableToShortString(iterable, leftDelimiter, rightDelimiter) {
+ var parts, t1;
+ if (A.isToStringVisiting(iterable)) {
+ if (leftDelimiter === "(" && rightDelimiter === ")")
+ return "(...)";
+ return leftDelimiter + "..." + rightDelimiter;
+ }
+ parts = A._setArrayType([], type$.JSArray_String);
+ B.JSArray_methods.add$1($.toStringVisiting, iterable);
+ try {
+ A._iterablePartsToStrings(iterable, parts);
+ } finally {
+ if (0 >= $.toStringVisiting.length)
+ return A.ioore($.toStringVisiting, -1);
+ $.toStringVisiting.pop();
+ }
+ t1 = A.StringBuffer__writeAll(leftDelimiter, type$.Iterable_dynamic._as(parts), ", ") + rightDelimiter;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ Iterable_iterableToFullString(iterable, leftDelimiter, rightDelimiter) {
+ var buffer, t1;
+ if (A.isToStringVisiting(iterable))
+ return leftDelimiter + "..." + rightDelimiter;
+ buffer = new A.StringBuffer(leftDelimiter);
+ B.JSArray_methods.add$1($.toStringVisiting, iterable);
+ try {
+ t1 = buffer;
+ t1._contents = A.StringBuffer__writeAll(t1._contents, iterable, ", ");
+ } finally {
+ if (0 >= $.toStringVisiting.length)
+ return A.ioore($.toStringVisiting, -1);
+ $.toStringVisiting.pop();
+ }
+ buffer._contents += rightDelimiter;
+ t1 = buffer._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ _iterablePartsToStrings(iterable, parts) {
+ var next, ultimateString, penultimateString, penultimate, ultimate, ultimate0, elision,
+ it = iterable.get$iterator(iterable),
+ $length = 0, count = 0;
+ while (true) {
+ if (!($length < 80 || count < 3))
+ break;
+ if (!it.moveNext$0())
+ return;
+ next = A.S(it.get$current());
+ B.JSArray_methods.add$1(parts, next);
+ $length += next.length + 2;
+ ++count;
+ }
+ if (!it.moveNext$0()) {
+ if (count <= 5)
+ return;
+ if (0 >= parts.length)
+ return A.ioore(parts, -1);
+ ultimateString = parts.pop();
+ if (0 >= parts.length)
+ return A.ioore(parts, -1);
+ penultimateString = parts.pop();
+ } else {
+ penultimate = it.get$current();
+ ++count;
+ if (!it.moveNext$0()) {
+ if (count <= 4) {
+ B.JSArray_methods.add$1(parts, A.S(penultimate));
+ return;
+ }
+ ultimateString = A.S(penultimate);
+ if (0 >= parts.length)
+ return A.ioore(parts, -1);
+ penultimateString = parts.pop();
+ $length += ultimateString.length + 2;
+ } else {
+ ultimate = it.get$current();
+ ++count;
+ for (; it.moveNext$0(); penultimate = ultimate, ultimate = ultimate0) {
+ ultimate0 = it.get$current();
+ ++count;
+ if (count > 100) {
+ while (true) {
+ if (!($length > 75 && count > 3))
+ break;
+ if (0 >= parts.length)
+ return A.ioore(parts, -1);
+ $length -= parts.pop().length + 2;
+ --count;
+ }
+ B.JSArray_methods.add$1(parts, "...");
+ return;
+ }
+ }
+ penultimateString = A.S(penultimate);
+ ultimateString = A.S(ultimate);
+ $length += ultimateString.length + penultimateString.length + 4;
+ }
+ }
+ if (count > parts.length + 2) {
+ $length += 5;
+ elision = "...";
+ } else
+ elision = null;
+ while (true) {
+ if (!($length > 80 && parts.length > 3))
+ break;
+ if (0 >= parts.length)
+ return A.ioore(parts, -1);
+ $length -= parts.pop().length + 2;
+ if (elision == null) {
+ $length += 5;
+ elision = "...";
+ }
+ }
+ if (elision != null)
+ B.JSArray_methods.add$1(parts, elision);
+ B.JSArray_methods.add$1(parts, penultimateString);
+ B.JSArray_methods.add$1(parts, ultimateString);
+ },
+ NoSuchMethodError_toString_closure: function NoSuchMethodError_toString_closure(t0, t1) {
+ this._box_0 = t0;
+ this.sb = t1;
+ },
+ DateTime: function DateTime(t0, t1) {
+ this._value = t0;
+ this.isUtc = t1;
+ },
+ Duration: function Duration(t0) {
+ this._duration = t0;
+ },
+ Error: function Error() {
+ },
+ AssertionError: function AssertionError(t0) {
+ this.message = t0;
+ },
+ TypeError: function TypeError() {
+ },
+ ArgumentError: function ArgumentError(t0, t1, t2, t3) {
+ var _ = this;
+ _._hasValue = t0;
+ _.invalidValue = t1;
+ _.name = t2;
+ _.message = t3;
+ },
+ RangeError: function RangeError(t0, t1, t2, t3, t4, t5) {
+ var _ = this;
+ _.start = t0;
+ _.end = t1;
+ _._hasValue = t2;
+ _.invalidValue = t3;
+ _.name = t4;
+ _.message = t5;
+ },
+ IndexError: function IndexError(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _.length = t0;
+ _._hasValue = t1;
+ _.invalidValue = t2;
+ _.name = t3;
+ _.message = t4;
+ },
+ NoSuchMethodError: function NoSuchMethodError(t0, t1, t2, t3) {
+ var _ = this;
+ _._core$_receiver = t0;
+ _._core$_memberName = t1;
+ _._core$_arguments = t2;
+ _._namedArguments = t3;
+ },
+ UnsupportedError: function UnsupportedError(t0) {
+ this.message = t0;
+ },
+ UnimplementedError: function UnimplementedError(t0) {
+ this.message = t0;
+ },
+ StateError: function StateError(t0) {
+ this.message = t0;
+ },
+ ConcurrentModificationError: function ConcurrentModificationError(t0) {
+ this.modifiedObject = t0;
+ },
+ OutOfMemoryError: function OutOfMemoryError() {
+ },
+ StackOverflowError: function StackOverflowError() {
+ },
+ _Exception: function _Exception(t0) {
+ this.message = t0;
+ },
+ FormatException: function FormatException(t0, t1, t2) {
+ this.message = t0;
+ this.source = t1;
+ this.offset = t2;
+ },
+ Iterable: function Iterable() {
+ },
+ Null: function Null() {
+ },
+ Object: function Object() {
+ },
+ _StringStackTrace: function _StringStackTrace(t0) {
+ this._stackTrace = t0;
+ },
+ StringBuffer: function StringBuffer(t0) {
+ this._contents = t0;
+ },
+ _convertDartFunctionFast(f) {
+ var ret,
+ existing = f.$dart_jsFunction;
+ if (existing != null)
+ return existing;
+ ret = function(_call, f) {
+ return function() {
+ return _call(f, Array.prototype.slice.apply(arguments));
+ };
+ }(A._callDartFunctionFast, f);
+ ret[$.$get$DART_CLOSURE_PROPERTY_NAME()] = f;
+ f.$dart_jsFunction = ret;
+ return ret;
+ },
+ _callDartFunctionFast(callback, $arguments) {
+ type$.List_dynamic._as($arguments);
+ type$.Function._as(callback);
+ return A.Primitives_applyFunction(callback, $arguments, null);
+ },
+ allowInterop(f, $F) {
+ if (typeof f == "function")
+ return f;
+ else
+ return $F._as(A._convertDartFunctionFast(f));
+ },
+ promiseToFuture(jsPromise, $T) {
+ var t1 = new A._Future($.Zone__current, $T._eval$1("_Future<0>")),
+ completer = new A._AsyncCompleter(t1, $T._eval$1("_AsyncCompleter<0>"));
+ jsPromise.then(A.convertDartClosureToJS(new A.promiseToFuture_closure(completer, $T), 1), A.convertDartClosureToJS(new A.promiseToFuture_closure0(completer), 1));
+ return t1;
+ },
+ _noDartifyRequired(o) {
+ return o == null || typeof o === "boolean" || typeof o === "number" || typeof o === "string" || o instanceof Int8Array || o instanceof Uint8Array || o instanceof Uint8ClampedArray || o instanceof Int16Array || o instanceof Uint16Array || o instanceof Int32Array || o instanceof Uint32Array || o instanceof Float32Array || o instanceof Float64Array || o instanceof ArrayBuffer || o instanceof DataView;
+ },
+ dartify(o) {
+ if (A._noDartifyRequired(o))
+ return o;
+ return new A.dartify_convert(new A._IdentityHashMap(type$._IdentityHashMap_of_nullable_Object_and_nullable_Object)).call$1(o);
+ },
+ promiseToFuture_closure: function promiseToFuture_closure(t0, t1) {
+ this.completer = t0;
+ this.T = t1;
+ },
+ promiseToFuture_closure0: function promiseToFuture_closure0(t0) {
+ this.completer = t0;
+ },
+ dartify_convert: function dartify_convert(t0) {
+ this._convertedObjects = t0;
+ },
+ NullRejectionException: function NullRejectionException(t0) {
+ this.isUndefined = t0;
+ },
+ _JSRandom: function _JSRandom() {
+ },
+ AsyncMemoizer: function AsyncMemoizer(t0, t1) {
+ this._completer = t0;
+ this.$ti = t1;
+ },
+ Level: function Level(t0, t1) {
+ this.name = t0;
+ this.value = t1;
+ },
+ LogRecord: function LogRecord(t0, t1, t2) {
+ this.level = t0;
+ this.message = t1;
+ this.loggerName = t2;
+ },
+ Logger_Logger($name) {
+ return $.Logger__loggers.putIfAbsent$2($name, new A.Logger_Logger_closure($name));
+ },
+ Logger: function Logger(t0, t1, t2) {
+ var _ = this;
+ _.name = t0;
+ _.parent = t1;
+ _._level = null;
+ _._children = t2;
+ },
+ Logger_Logger_closure: function Logger_Logger_closure(t0) {
+ this.name = t0;
+ },
+ Pool: function Pool(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._requestedResources = t0;
+ _._onReleaseCallbacks = t1;
+ _._onReleaseCompleters = t2;
+ _._maxAllocatedResources = t3;
+ _._allocatedResources = 0;
+ _._timer = null;
+ _._closeMemo = t4;
+ },
+ Pool__runOnRelease_closure: function Pool__runOnRelease_closure(t0) {
+ this.$this = t0;
+ },
+ Pool__runOnRelease_closure0: function Pool__runOnRelease_closure0(t0) {
+ this.$this = t0;
+ },
+ PoolResource: function PoolResource(t0) {
+ this._pool = t0;
+ this._released = false;
+ },
+ SseClient$(serverUrl) {
+ var t3, t4, t5,
+ t1 = type$.String,
+ t2 = A.StreamController_StreamController(t1);
+ t1 = A.StreamController_StreamController(t1);
+ t3 = A.Logger_Logger("SseClient");
+ t4 = $.Zone__current;
+ t5 = A.generateUuidV4();
+ t1 = new A.SseClient(t5, t2, t1, t3, new A._AsyncCompleter(new A._Future(t4, type$._Future_void), type$._AsyncCompleter_void));
+ t1.SseClient$2$debugKey(serverUrl, null);
+ return t1;
+ },
+ SseClient: function SseClient(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._clientId = t0;
+ _._incomingController = t1;
+ _._outgoingController = t2;
+ _._logger = t3;
+ _._onConnected = t4;
+ _._lastMessageId = -1;
+ _.__SseClient__serverUrl_A = _.__SseClient__eventSource_A = $;
+ _._errorTimer = null;
+ },
+ SseClient_closure: function SseClient_closure(t0) {
+ this.$this = t0;
+ },
+ SseClient_closure0: function SseClient_closure0(t0) {
+ this.$this = t0;
+ },
+ SseClient_closure1: function SseClient_closure1(t0) {
+ this.$this = t0;
+ },
+ SseClient__closure: function SseClient__closure(t0, t1) {
+ this.$this = t0;
+ this.error = t1;
+ },
+ SseClient__onOutgoingMessage_closure: function SseClient__onOutgoingMessage_closure(t0, t1, t2) {
+ this._box_0 = t0;
+ this.$this = t1;
+ this.message = t2;
+ },
+ generateUuidV4() {
+ var t1 = new A.generateUuidV4_printDigits(),
+ t2 = new A.generateUuidV4_bitsDigits(t1, new A.generateUuidV4_generateBits(B.C__JSRandom)),
+ t3 = B.C__JSRandom.nextInt$1(4);
+ return A.S(t2.call$2(16, 4)) + A.S(t2.call$2(16, 4)) + "-" + A.S(t2.call$2(16, 4)) + "-4" + A.S(t2.call$2(12, 3)) + "-" + A.S(t1.call$2(8 + t3, 1)) + A.S(t2.call$2(12, 3)) + "-" + A.S(t2.call$2(16, 4)) + A.S(t2.call$2(16, 4)) + A.S(t2.call$2(16, 4));
+ },
+ generateUuidV4_generateBits: function generateUuidV4_generateBits(t0) {
+ this.random = t0;
+ },
+ generateUuidV4_printDigits: function generateUuidV4_printDigits() {
+ },
+ generateUuidV4_bitsDigits: function generateUuidV4_bitsDigits(t0, t1) {
+ this.printDigits = t0;
+ this.generateBits = t1;
+ },
+ StreamChannelMixin: function StreamChannelMixin() {
+ },
+ _EventStreamSubscription$(_target, _eventType, onData, _useCapture, $T) {
+ var t1;
+ if (onData == null)
+ t1 = null;
+ else {
+ t1 = A._wrapZone(new A._EventStreamSubscription_closure(onData), type$.JSObject);
+ t1 = t1 == null ? null : type$.JavaScriptFunction._as(A.allowInterop(t1, type$.Function));
+ }
+ t1 = new A._EventStreamSubscription(_target, _eventType, t1, false, $T._eval$1("_EventStreamSubscription<0>"));
+ t1._tryResume$0();
+ return t1;
+ },
+ _wrapZone(callback, $T) {
+ var t1 = $.Zone__current;
+ if (t1 === B.C__RootZone)
+ return callback;
+ return t1.bindUnaryCallbackGuarded$1$1(callback, $T);
+ },
+ EventStreamProvider: function EventStreamProvider(t0, t1) {
+ this._eventType = t0;
+ this.$ti = t1;
+ },
+ _EventStream: function _EventStream(t0, t1, t2, t3) {
+ var _ = this;
+ _._target = t0;
+ _._eventType = t1;
+ _._useCapture = t2;
+ _.$ti = t3;
+ },
+ _ElementEventStreamImpl: function _ElementEventStreamImpl(t0, t1, t2, t3) {
+ var _ = this;
+ _._target = t0;
+ _._eventType = t1;
+ _._useCapture = t2;
+ _.$ti = t3;
+ },
+ _EventStreamSubscription: function _EventStreamSubscription(t0, t1, t2, t3, t4) {
+ var _ = this;
+ _._target = t0;
+ _._eventType = t1;
+ _._streams$_onData = t2;
+ _._useCapture = t3;
+ _.$ti = t4;
+ },
+ _EventStreamSubscription_closure: function _EventStreamSubscription_closure(t0) {
+ this.onData = t0;
+ },
+ _EventStreamSubscription_onData_closure: function _EventStreamSubscription_onData_closure(t0) {
+ this.handleData = t0;
+ },
+ main() {
+ var t2,
+ channel = A.SseClient$("/test"),
+ t1 = type$.nullable_JSObject._as(type$.JSObject._as(self.document).querySelector("button"));
+ t1.toString;
+ t2 = type$._ElementEventStreamImpl_JSObject;
+ A._EventStreamSubscription$(t1, "click", t2._eval$1("~(1)?")._as(new A.main_closure(channel)), false, t2._precomputed1);
+ t2 = channel._incomingController;
+ new A._ControllerStream(t2, A._instanceType(t2)._eval$1("_ControllerStream<1>")).listen$1(new A.main_closure0(channel));
+ },
+ main_closure: function main_closure(t0) {
+ this.channel = t0;
+ },
+ main_closure0: function main_closure0(t0) {
+ this.channel = t0;
+ },
+ throwLateFieldNI(fieldName) {
+ A.throwExpressionWithWrapper(new A.LateError("Field '" + fieldName + "' has not been initialized."), new Error());
+ },
+ throwLateFieldADI(fieldName) {
+ A.throwExpressionWithWrapper(new A.LateError("Field '" + fieldName + "' has been assigned during initialization."), new Error());
+ }
+ },
+ B = {};
+ var holders = [A, J, B];
+ var $ = {};
+ A.JS_CONST.prototype = {};
+ J.Interceptor.prototype = {
+ $eq(receiver, other) {
+ return receiver === other;
+ },
+ get$hashCode(receiver) {
+ return A.Primitives_objectHashCode(receiver);
+ },
+ toString$0(receiver) {
+ return "Instance of '" + A.Primitives_objectTypeName(receiver) + "'";
+ },
+ noSuchMethod$1(receiver, invocation) {
+ throw A.wrapException(A.NoSuchMethodError_NoSuchMethodError$withInvocation(receiver, type$.Invocation._as(invocation)));
+ },
+ get$runtimeType(receiver) {
+ return A.createRuntimeType(A._instanceTypeFromConstructor(this));
+ }
+ };
+ J.JSBool.prototype = {
+ toString$0(receiver) {
+ return String(receiver);
+ },
+ get$hashCode(receiver) {
+ return receiver ? 519018 : 218159;
+ },
+ get$runtimeType(receiver) {
+ return A.createRuntimeType(type$.bool);
+ },
+ $isTrustedGetRuntimeType: 1,
+ $isbool: 1
+ };
+ J.JSNull.prototype = {
+ $eq(receiver, other) {
+ return null == other;
+ },
+ toString$0(receiver) {
+ return "null";
+ },
+ get$hashCode(receiver) {
+ return 0;
+ },
+ $isTrustedGetRuntimeType: 1,
+ $isNull: 1
+ };
+ J.JavaScriptObject.prototype = {$isJSObject: 1};
+ J.LegacyJavaScriptObject.prototype = {
+ get$hashCode(receiver) {
+ return 0;
+ },
+ toString$0(receiver) {
+ return String(receiver);
+ }
+ };
+ J.PlainJavaScriptObject.prototype = {};
+ J.UnknownJavaScriptObject.prototype = {};
+ J.JavaScriptFunction.prototype = {
+ toString$0(receiver) {
+ var dartClosure = receiver[$.$get$DART_CLOSURE_PROPERTY_NAME()];
+ if (dartClosure == null)
+ return this.super$LegacyJavaScriptObject$toString(receiver);
+ return "JavaScript function for " + J.toString$0$(dartClosure);
+ },
+ $isFunction: 1
+ };
+ J.JavaScriptBigInt.prototype = {
+ get$hashCode(receiver) {
+ return 0;
+ },
+ toString$0(receiver) {
+ return String(receiver);
+ }
+ };
+ J.JavaScriptSymbol.prototype = {
+ get$hashCode(receiver) {
+ return 0;
+ },
+ toString$0(receiver) {
+ return String(receiver);
+ }
+ };
+ J.JSArray.prototype = {
+ add$1(receiver, value) {
+ A._arrayInstanceType(receiver)._precomputed1._as(value);
+ if (!!receiver.fixed$length)
+ A.throwExpression(A.UnsupportedError$("add"));
+ receiver.push(value);
+ },
+ addAll$1(receiver, collection) {
+ var t1;
+ A._arrayInstanceType(receiver)._eval$1("Iterable<1>")._as(collection);
+ if (!!receiver.fixed$length)
+ A.throwExpression(A.UnsupportedError$("addAll"));
+ if (Array.isArray(collection)) {
+ this._addAllFromArray$1(receiver, collection);
+ return;
+ }
+ for (t1 = J.get$iterator$ax(collection); t1.moveNext$0();)
+ receiver.push(t1.get$current());
+ },
+ _addAllFromArray$1(receiver, array) {
+ var len, i;
+ type$.JSArray_dynamic._as(array);
+ len = array.length;
+ if (len === 0)
+ return;
+ if (receiver === array)
+ throw A.wrapException(A.ConcurrentModificationError$(receiver));
+ for (i = 0; i < len; ++i)
+ receiver.push(array[i]);
+ },
+ get$last(receiver) {
+ var t1 = receiver.length;
+ if (t1 > 0)
+ return receiver[t1 - 1];
+ throw A.wrapException(A.IterableElementError_noElement());
+ },
+ setRange$4(receiver, start, end, iterable, skipCount) {
+ var $length, otherList, t1, i;
+ A._arrayInstanceType(receiver)._eval$1("Iterable<1>")._as(iterable);
+ if (!!receiver.immutable$list)
+ A.throwExpression(A.UnsupportedError$("setRange"));
+ A.RangeError_checkValidRange(start, end, receiver.length);
+ $length = end - start;
+ if ($length === 0)
+ return;
+ A.RangeError_checkNotNegative(skipCount, "skipCount");
+ otherList = iterable;
+ t1 = J.getInterceptor$asx(otherList);
+ if (skipCount + $length > t1.get$length(otherList))
+ throw A.wrapException(A.IterableElementError_tooFew());
+ if (skipCount < start)
+ for (i = $length - 1; i >= 0; --i)
+ receiver[start + i] = t1.$index(otherList, skipCount + i);
+ else
+ for (i = 0; i < $length; ++i)
+ receiver[start + i] = t1.$index(otherList, skipCount + i);
+ },
+ get$isNotEmpty(receiver) {
+ return receiver.length !== 0;
+ },
+ toString$0(receiver) {
+ return A.Iterable_iterableToFullString(receiver, "[", "]");
+ },
+ get$iterator(receiver) {
+ return new J.ArrayIterator(receiver, receiver.length, A._arrayInstanceType(receiver)._eval$1("ArrayIterator<1>"));
+ },
+ get$hashCode(receiver) {
+ return A.Primitives_objectHashCode(receiver);
+ },
+ get$length(receiver) {
+ return receiver.length;
+ },
+ $index(receiver, index) {
+ if (!(index >= 0 && index < receiver.length))
+ throw A.wrapException(A.diagnoseIndexError(receiver, index));
+ return receiver[index];
+ },
+ $indexSet(receiver, index, value) {
+ A._arrayInstanceType(receiver)._precomputed1._as(value);
+ if (!!receiver.immutable$list)
+ A.throwExpression(A.UnsupportedError$("indexed set"));
+ if (!(index >= 0 && index < receiver.length))
+ throw A.wrapException(A.diagnoseIndexError(receiver, index));
+ receiver[index] = value;
+ },
+ $isIterable: 1,
+ $isList: 1
+ };
+ J.JSUnmodifiableArray.prototype = {};
+ J.ArrayIterator.prototype = {
+ get$current() {
+ var t1 = this._current;
+ return t1 == null ? this.$ti._precomputed1._as(t1) : t1;
+ },
+ moveNext$0() {
+ var t2, _this = this,
+ t1 = _this._iterable,
+ $length = t1.length;
+ if (_this._length !== $length) {
+ t1 = A.throwConcurrentModificationError(t1);
+ throw A.wrapException(t1);
+ }
+ t2 = _this._index;
+ if (t2 >= $length) {
+ _this.set$_current(null);
+ return false;
+ }
+ _this.set$_current(t1[t2]);
+ ++_this._index;
+ return true;
+ },
+ set$_current(_current) {
+ this._current = this.$ti._eval$1("1?")._as(_current);
+ }
+ };
+ J.JSNumber.prototype = {
+ toRadixString$1(receiver, radix) {
+ var result, t1, t2, match, exponent;
+ if (radix < 2 || radix > 36)
+ throw A.wrapException(A.RangeError$range(radix, 2, 36, "radix", null));
+ result = receiver.toString(radix);
+ t1 = result.length;
+ t2 = t1 - 1;
+ if (!(t2 >= 0))
+ return A.ioore(result, t2);
+ if (result.charCodeAt(t2) !== 41)
+ return result;
+ match = /^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(result);
+ if (match == null)
+ A.throwExpression(A.UnsupportedError$("Unexpected toString result: " + result));
+ t1 = match.length;
+ if (1 >= t1)
+ return A.ioore(match, 1);
+ result = match[1];
+ if (3 >= t1)
+ return A.ioore(match, 3);
+ exponent = +match[3];
+ t1 = match[2];
+ if (t1 != null) {
+ result += t1;
+ exponent -= t1.length;
+ }
+ return result + B.JSString_methods.$mul("0", exponent);
+ },
+ toString$0(receiver) {
+ if (receiver === 0 && 1 / receiver < 0)
+ return "-0.0";
+ else
+ return "" + receiver;
+ },
+ get$hashCode(receiver) {
+ var absolute, floorLog2, factor, scaled,
+ intValue = receiver | 0;
+ if (receiver === intValue)
+ return intValue & 536870911;
+ absolute = Math.abs(receiver);
+ floorLog2 = Math.log(absolute) / 0.6931471805599453 | 0;
+ factor = Math.pow(2, floorLog2);
+ scaled = absolute < 1 ? absolute / factor : factor / absolute;
+ return ((scaled * 9007199254740992 | 0) + (scaled * 3542243181176521 | 0)) * 599197 + floorLog2 * 1259 & 536870911;
+ },
+ _tdivFast$1(receiver, other) {
+ return (receiver | 0) === receiver ? receiver / other | 0 : this._tdivSlow$1(receiver, other);
+ },
+ _tdivSlow$1(receiver, other) {
+ var quotient = receiver / other;
+ if (quotient >= -2147483648 && quotient <= 2147483647)
+ return quotient | 0;
+ if (quotient > 0) {
+ if (quotient !== 1 / 0)
+ return Math.floor(quotient);
+ } else if (quotient > -1 / 0)
+ return Math.ceil(quotient);
+ throw A.wrapException(A.UnsupportedError$("Result of truncating division is " + A.S(quotient) + ": " + A.S(receiver) + " ~/ " + other));
+ },
+ _shlPositive$1(receiver, other) {
+ return other > 31 ? 0 : receiver << other >>> 0;
+ },
+ _shrOtherPositive$1(receiver, other) {
+ var t1;
+ if (receiver > 0)
+ t1 = this._shrBothPositive$1(receiver, other);
+ else {
+ t1 = other > 31 ? 31 : other;
+ t1 = receiver >> t1 >>> 0;
+ }
+ return t1;
+ },
+ _shrBothPositive$1(receiver, other) {
+ return other > 31 ? 0 : receiver >>> other;
+ },
+ get$runtimeType(receiver) {
+ return A.createRuntimeType(type$.num);
+ },
+ $isdouble: 1,
+ $isnum: 1
+ };
+ J.JSInt.prototype = {
+ get$runtimeType(receiver) {
+ return A.createRuntimeType(type$.int);
+ },
+ $isTrustedGetRuntimeType: 1,
+ $isint: 1
+ };
+ J.JSNumNotInt.prototype = {
+ get$runtimeType(receiver) {
+ return A.createRuntimeType(type$.double);
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ J.JSString.prototype = {
+ matchAsPrefix$2(receiver, string, start) {
+ var t1, t2, i, t3, _null = null;
+ if (start < 0 || start > string.length)
+ throw A.wrapException(A.RangeError$range(start, 0, string.length, _null, _null));
+ t1 = receiver.length;
+ t2 = string.length;
+ if (start + t1 > t2)
+ return _null;
+ for (i = 0; i < t1; ++i) {
+ t3 = start + i;
+ if (!(t3 >= 0 && t3 < t2))
+ return A.ioore(string, t3);
+ if (string.charCodeAt(t3) !== receiver.charCodeAt(i))
+ return _null;
+ }
+ return new A.StringMatch(start, receiver);
+ },
+ $add(receiver, other) {
+ return receiver + other;
+ },
+ endsWith$1(receiver, other) {
+ var otherLength = other.length,
+ t1 = receiver.length;
+ if (otherLength > t1)
+ return false;
+ return other === this.substring$1(receiver, t1 - otherLength);
+ },
+ startsWith$2(receiver, pattern, index) {
+ var endIndex;
+ if (index < 0 || index > receiver.length)
+ throw A.wrapException(A.RangeError$range(index, 0, receiver.length, null, null));
+ if (typeof pattern == "string") {
+ endIndex = index + pattern.length;
+ if (endIndex > receiver.length)
+ return false;
+ return pattern === receiver.substring(index, endIndex);
+ }
+ return J.matchAsPrefix$2$s(pattern, receiver, index) != null;
+ },
+ startsWith$1(receiver, pattern) {
+ return this.startsWith$2(receiver, pattern, 0);
+ },
+ substring$2(receiver, start, end) {
+ return receiver.substring(start, A.RangeError_checkValidRange(start, end, receiver.length));
+ },
+ substring$1(receiver, start) {
+ return this.substring$2(receiver, start, null);
+ },
+ $mul(receiver, times) {
+ var s, result;
+ if (0 >= times)
+ return "";
+ if (times === 1 || receiver.length === 0)
+ return receiver;
+ if (times !== times >>> 0)
+ throw A.wrapException(B.C_OutOfMemoryError);
+ for (s = receiver, result = ""; true;) {
+ if ((times & 1) === 1)
+ result = s + result;
+ times = times >>> 1;
+ if (times === 0)
+ break;
+ s += s;
+ }
+ return result;
+ },
+ padLeft$2(receiver, width, padding) {
+ var delta = width - receiver.length;
+ if (delta <= 0)
+ return receiver;
+ return this.$mul(padding, delta) + receiver;
+ },
+ lastIndexOf$2(receiver, pattern, start) {
+ var t1, t2;
+ if (start == null)
+ start = receiver.length;
+ else if (start < 0 || start > receiver.length)
+ throw A.wrapException(A.RangeError$range(start, 0, receiver.length, null, null));
+ t1 = pattern.length;
+ t2 = receiver.length;
+ if (start + t1 > t2)
+ start = t2 - t1;
+ return receiver.lastIndexOf(pattern, start);
+ },
+ lastIndexOf$1(receiver, pattern) {
+ return this.lastIndexOf$2(receiver, pattern, null);
+ },
+ toString$0(receiver) {
+ return receiver;
+ },
+ get$hashCode(receiver) {
+ var t1, hash, i;
+ for (t1 = receiver.length, hash = 0, i = 0; i < t1; ++i) {
+ hash = hash + receiver.charCodeAt(i) & 536870911;
+ hash = hash + ((hash & 524287) << 10) & 536870911;
+ hash ^= hash >> 6;
+ }
+ hash = hash + ((hash & 67108863) << 3) & 536870911;
+ hash ^= hash >> 11;
+ return hash + ((hash & 16383) << 15) & 536870911;
+ },
+ get$runtimeType(receiver) {
+ return A.createRuntimeType(type$.String);
+ },
+ get$length(receiver) {
+ return receiver.length;
+ },
+ $isTrustedGetRuntimeType: 1,
+ $isPattern: 1,
+ $isString: 1
+ };
+ A.LateError.prototype = {
+ toString$0(_) {
+ return "LateInitializationError: " + this._message;
+ }
+ };
+ A.nullFuture_closure.prototype = {
+ call$0() {
+ return A.Future_Future$value(null, type$.Null);
+ },
+ $signature: 7
+ };
+ A.EfficientLengthIterable.prototype = {};
+ A.ListIterable.prototype = {
+ get$iterator(_) {
+ var _this = this;
+ return new A.ListIterator(_this, _this.get$length(_this), A._instanceType(_this)._eval$1("ListIterator<ListIterable.E>"));
+ },
+ get$isEmpty(_) {
+ return this.get$length(this) === 0;
+ }
+ };
+ A.ListIterator.prototype = {
+ get$current() {
+ var t1 = this.__internal$_current;
+ return t1 == null ? this.$ti._precomputed1._as(t1) : t1;
+ },
+ moveNext$0() {
+ var t3, _this = this,
+ t1 = _this.__internal$_iterable,
+ t2 = J.getInterceptor$asx(t1),
+ $length = t2.get$length(t1);
+ if (_this.__internal$_length !== $length)
+ throw A.wrapException(A.ConcurrentModificationError$(t1));
+ t3 = _this.__internal$_index;
+ if (t3 >= $length) {
+ _this.set$__internal$_current(null);
+ return false;
+ }
+ _this.set$__internal$_current(t2.elementAt$1(t1, t3));
+ ++_this.__internal$_index;
+ return true;
+ },
+ set$__internal$_current(_current) {
+ this.__internal$_current = this.$ti._eval$1("1?")._as(_current);
+ }
+ };
+ A.FixedLengthListMixin.prototype = {};
+ A.Symbol.prototype = {
+ get$hashCode(_) {
+ var hash = this._hashCode;
+ if (hash != null)
+ return hash;
+ hash = 664597 * B.JSString_methods.get$hashCode(this._name) & 536870911;
+ this._hashCode = hash;
+ return hash;
+ },
+ toString$0(_) {
+ return 'Symbol("' + this._name + '")';
+ },
+ $eq(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof A.Symbol && this._name === other._name;
+ },
+ $isSymbol0: 1
+ };
+ A.ConstantMapView.prototype = {};
+ A.ConstantMap.prototype = {
+ get$isEmpty(_) {
+ return this.get$length(this) === 0;
+ },
+ toString$0(_) {
+ return A.MapBase_mapToString(this);
+ },
+ $isMap: 1
+ };
+ A.ConstantStringMap.prototype = {
+ get$length(_) {
+ return this._values.length;
+ },
+ get$_keys() {
+ var keys = this.$keys;
+ if (keys == null) {
+ keys = Object.keys(this._jsIndex);
+ this.$keys = keys;
+ }
+ return keys;
+ },
+ forEach$1(_, f) {
+ var keys, values, t1, i;
+ this.$ti._eval$1("~(1,2)")._as(f);
+ keys = this.get$_keys();
+ values = this._values;
+ for (t1 = keys.length, i = 0; i < t1; ++i)
+ f.call$2(keys[i], values[i]);
+ }
+ };
+ A.JSInvocationMirror.prototype = {
+ get$memberName() {
+ var t1 = this._memberName;
+ if (t1 instanceof A.Symbol)
+ return t1;
+ return this._memberName = new A.Symbol(A._asString(t1));
+ },
+ get$positionalArguments() {
+ var t1, t2, argumentCount, list, index, _this = this;
+ if (_this.__js_helper$_kind === 1)
+ return B.List_empty;
+ t1 = _this._arguments;
+ t2 = J.getInterceptor$asx(t1);
+ argumentCount = t2.get$length(t1) - J.get$length$asx(_this._namedArgumentNames) - _this._typeArgumentCount;
+ if (argumentCount === 0)
+ return B.List_empty;
+ list = [];
+ for (index = 0; index < argumentCount; ++index)
+ list.push(t2.$index(t1, index));
+ return J.JSArray_markUnmodifiableList(list);
+ },
+ get$namedArguments() {
+ var t1, t2, namedArgumentCount, t3, t4, namedArgumentsStartIndex, map, i, _this = this;
+ if (_this.__js_helper$_kind !== 0)
+ return B.Map_empty;
+ t1 = _this._namedArgumentNames;
+ t2 = J.getInterceptor$asx(t1);
+ namedArgumentCount = t2.get$length(t1);
+ t3 = _this._arguments;
+ t4 = J.getInterceptor$asx(t3);
+ namedArgumentsStartIndex = t4.get$length(t3) - namedArgumentCount - _this._typeArgumentCount;
+ if (namedArgumentCount === 0)
+ return B.Map_empty;
+ map = new A.JsLinkedHashMap(type$.JsLinkedHashMap_Symbol_dynamic);
+ for (i = 0; i < namedArgumentCount; ++i)
+ map.$indexSet(0, new A.Symbol(A._asString(t2.$index(t1, i))), t4.$index(t3, namedArgumentsStartIndex + i));
+ return new A.ConstantMapView(map, type$.ConstantMapView_Symbol_dynamic);
+ },
+ $isInvocation: 1
+ };
+ A.Primitives_functionNoSuchMethod_closure.prototype = {
+ call$2($name, argument) {
+ var t1;
+ A._asString($name);
+ t1 = this._box_0;
+ t1.names = t1.names + "$" + $name;
+ B.JSArray_methods.add$1(this.namedArgumentList, $name);
+ B.JSArray_methods.add$1(this.$arguments, argument);
+ ++t1.argumentCount;
+ },
+ $signature: 12
+ };
+ A.TypeErrorDecoder.prototype = {
+ matchTypeError$1(message) {
+ var result, t1, _this = this,
+ match = new RegExp(_this._pattern).exec(message);
+ if (match == null)
+ return null;
+ result = Object.create(null);
+ t1 = _this._arguments;
+ if (t1 !== -1)
+ result.arguments = match[t1 + 1];
+ t1 = _this._argumentsExpr;
+ if (t1 !== -1)
+ result.argumentsExpr = match[t1 + 1];
+ t1 = _this._expr;
+ if (t1 !== -1)
+ result.expr = match[t1 + 1];
+ t1 = _this._method;
+ if (t1 !== -1)
+ result.method = match[t1 + 1];
+ t1 = _this._receiver;
+ if (t1 !== -1)
+ result.receiver = match[t1 + 1];
+ return result;
+ }
+ };
+ A.NullError.prototype = {
+ toString$0(_) {
+ return "Null check operator used on a null value";
+ }
+ };
+ A.JsNoSuchMethodError.prototype = {
+ toString$0(_) {
+ var t2, _this = this,
+ _s38_ = "NoSuchMethodError: method not found: '",
+ t1 = _this._method;
+ if (t1 == null)
+ return "NoSuchMethodError: " + _this.__js_helper$_message;
+ t2 = _this._receiver;
+ if (t2 == null)
+ return _s38_ + t1 + "' (" + _this.__js_helper$_message + ")";
+ return _s38_ + t1 + "' on '" + t2 + "' (" + _this.__js_helper$_message + ")";
+ }
+ };
+ A.UnknownJsTypeError.prototype = {
+ toString$0(_) {
+ var t1 = this.__js_helper$_message;
+ return t1.length === 0 ? "Error" : "Error: " + t1;
+ }
+ };
+ A.NullThrownFromJavaScriptException.prototype = {
+ toString$0(_) {
+ return "Throw of null ('" + (this._irritant === null ? "null" : "undefined") + "' from JavaScript)";
+ }
+ };
+ A.ExceptionAndStackTrace.prototype = {};
+ A._StackTrace.prototype = {
+ toString$0(_) {
+ var trace,
+ t1 = this._trace;
+ if (t1 != null)
+ return t1;
+ t1 = this._exception;
+ trace = t1 !== null && typeof t1 === "object" ? t1.stack : null;
+ return this._trace = trace == null ? "" : trace;
+ },
+ $isStackTrace: 1
+ };
+ A.Closure.prototype = {
+ toString$0(_) {
+ var $constructor = this.constructor,
+ $name = $constructor == null ? null : $constructor.name;
+ return "Closure '" + A.unminifyOrTag($name == null ? "unknown" : $name) + "'";
+ },
+ $isFunction: 1,
+ get$$call() {
+ return this;
+ },
+ "call*": "call$1",
+ $requiredArgCount: 1,
+ $defaultValues: null
+ };
+ A.Closure0Args.prototype = {"call*": "call$0", $requiredArgCount: 0};
+ A.Closure2Args.prototype = {"call*": "call$2", $requiredArgCount: 2};
+ A.TearOffClosure.prototype = {};
+ A.StaticClosure.prototype = {
+ toString$0(_) {
+ var $name = this.$static_name;
+ if ($name == null)
+ return "Closure of unknown static method";
+ return "Closure '" + A.unminifyOrTag($name) + "'";
+ }
+ };
+ A.BoundClosure.prototype = {
+ $eq(_, other) {
+ if (other == null)
+ return false;
+ if (this === other)
+ return true;
+ if (!(other instanceof A.BoundClosure))
+ return false;
+ return this.$_target === other.$_target && this._receiver === other._receiver;
+ },
+ get$hashCode(_) {
+ return (A.objectHashCode(this._receiver) ^ A.Primitives_objectHashCode(this.$_target)) >>> 0;
+ },
+ toString$0(_) {
+ return "Closure '" + this.$_name + "' of " + ("Instance of '" + A.Primitives_objectTypeName(this._receiver) + "'");
+ }
+ };
+ A._CyclicInitializationError.prototype = {
+ toString$0(_) {
+ return "Reading static variable '" + this.variableName + "' during its initialization";
+ }
+ };
+ A.RuntimeError.prototype = {
+ toString$0(_) {
+ return "RuntimeError: " + this.message;
+ }
+ };
+ A._Required.prototype = {};
+ A.JsLinkedHashMap.prototype = {
+ get$length(_) {
+ return this.__js_helper$_length;
+ },
+ get$isEmpty(_) {
+ return this.__js_helper$_length === 0;
+ },
+ get$keys() {
+ return new A.LinkedHashMapKeyIterable(this, A._instanceType(this)._eval$1("LinkedHashMapKeyIterable<1>"));
+ },
+ containsKey$1(key) {
+ var strings = this._strings;
+ if (strings == null)
+ return false;
+ return strings[key] != null;
+ },
+ $index(_, key) {
+ var strings, cell, t1, nums, _null = null;
+ if (typeof key == "string") {
+ strings = this._strings;
+ if (strings == null)
+ return _null;
+ cell = strings[key];
+ t1 = cell == null ? _null : cell.hashMapCellValue;
+ return t1;
+ } else if (typeof key == "number" && (key & 0x3fffffff) === key) {
+ nums = this._nums;
+ if (nums == null)
+ return _null;
+ cell = nums[key];
+ t1 = cell == null ? _null : cell.hashMapCellValue;
+ return t1;
+ } else
+ return this.internalGet$1(key);
+ },
+ internalGet$1(key) {
+ var bucket, index,
+ rest = this.__js_helper$_rest;
+ if (rest == null)
+ return null;
+ bucket = rest[this.internalComputeHashCode$1(key)];
+ index = this.internalFindBucketIndex$2(bucket, key);
+ if (index < 0)
+ return null;
+ return bucket[index].hashMapCellValue;
+ },
+ $indexSet(_, key, value) {
+ var strings, nums, rest, hash, bucket, index, _this = this,
+ t1 = A._instanceType(_this);
+ t1._precomputed1._as(key);
+ t1._rest[1]._as(value);
+ if (typeof key == "string") {
+ strings = _this._strings;
+ _this._addHashTableEntry$3(strings == null ? _this._strings = _this._newHashTable$0() : strings, key, value);
+ } else if (typeof key == "number" && (key & 0x3fffffff) === key) {
+ nums = _this._nums;
+ _this._addHashTableEntry$3(nums == null ? _this._nums = _this._newHashTable$0() : nums, key, value);
+ } else {
+ rest = _this.__js_helper$_rest;
+ if (rest == null)
+ rest = _this.__js_helper$_rest = _this._newHashTable$0();
+ hash = _this.internalComputeHashCode$1(key);
+ bucket = rest[hash];
+ if (bucket == null)
+ rest[hash] = [_this._newLinkedCell$2(key, value)];
+ else {
+ index = _this.internalFindBucketIndex$2(bucket, key);
+ if (index >= 0)
+ bucket[index].hashMapCellValue = value;
+ else
+ bucket.push(_this._newLinkedCell$2(key, value));
+ }
+ }
+ },
+ putIfAbsent$2(key, ifAbsent) {
+ var t2, value, _this = this,
+ t1 = A._instanceType(_this);
+ t1._precomputed1._as(key);
+ t1._eval$1("2()")._as(ifAbsent);
+ if (_this.containsKey$1(key)) {
+ t2 = _this.$index(0, key);
+ return t2 == null ? t1._rest[1]._as(t2) : t2;
+ }
+ value = ifAbsent.call$0();
+ _this.$indexSet(0, key, value);
+ return value;
+ },
+ forEach$1(_, action) {
+ var cell, modifications, _this = this;
+ A._instanceType(_this)._eval$1("~(1,2)")._as(action);
+ cell = _this._first;
+ modifications = _this._modifications;
+ for (; cell != null;) {
+ action.call$2(cell.hashMapCellKey, cell.hashMapCellValue);
+ if (modifications !== _this._modifications)
+ throw A.wrapException(A.ConcurrentModificationError$(_this));
+ cell = cell._next;
+ }
+ },
+ _addHashTableEntry$3(table, key, value) {
+ var cell,
+ t1 = A._instanceType(this);
+ t1._precomputed1._as(key);
+ t1._rest[1]._as(value);
+ cell = table[key];
+ if (cell == null)
+ table[key] = this._newLinkedCell$2(key, value);
+ else
+ cell.hashMapCellValue = value;
+ },
+ _newLinkedCell$2(key, value) {
+ var _this = this,
+ t1 = A._instanceType(_this),
+ cell = new A.LinkedHashMapCell(t1._precomputed1._as(key), t1._rest[1]._as(value));
+ if (_this._first == null)
+ _this._first = _this._last = cell;
+ else
+ _this._last = _this._last._next = cell;
+ ++_this.__js_helper$_length;
+ _this._modifications = _this._modifications + 1 & 1073741823;
+ return cell;
+ },
+ internalComputeHashCode$1(key) {
+ return J.get$hashCode$(key) & 1073741823;
+ },
+ internalFindBucketIndex$2(bucket, key) {
+ var $length, i;
+ if (bucket == null)
+ return -1;
+ $length = bucket.length;
+ for (i = 0; i < $length; ++i)
+ if (J.$eq$(bucket[i].hashMapCellKey, key))
+ return i;
+ return -1;
+ },
+ toString$0(_) {
+ return A.MapBase_mapToString(this);
+ },
+ _newHashTable$0() {
+ var table = Object.create(null);
+ table["<non-identifier-key>"] = table;
+ delete table["<non-identifier-key>"];
+ return table;
+ }
+ };
+ A.LinkedHashMapCell.prototype = {};
+ A.LinkedHashMapKeyIterable.prototype = {
+ get$length(_) {
+ return this._map.__js_helper$_length;
+ },
+ get$isEmpty(_) {
+ return this._map.__js_helper$_length === 0;
+ },
+ get$iterator(_) {
+ var t1 = this._map,
+ t2 = new A.LinkedHashMapKeyIterator(t1, t1._modifications, this.$ti._eval$1("LinkedHashMapKeyIterator<1>"));
+ t2._cell = t1._first;
+ return t2;
+ }
+ };
+ A.LinkedHashMapKeyIterator.prototype = {
+ get$current() {
+ return this.__js_helper$_current;
+ },
+ moveNext$0() {
+ var cell, _this = this,
+ t1 = _this._map;
+ if (_this._modifications !== t1._modifications)
+ throw A.wrapException(A.ConcurrentModificationError$(t1));
+ cell = _this._cell;
+ if (cell == null) {
+ _this.set$__js_helper$_current(null);
+ return false;
+ } else {
+ _this.set$__js_helper$_current(cell.hashMapCellKey);
+ _this._cell = cell._next;
+ return true;
+ }
+ },
+ set$__js_helper$_current(_current) {
+ this.__js_helper$_current = this.$ti._eval$1("1?")._as(_current);
+ }
+ };
+ A.initHooks_closure.prototype = {
+ call$1(o) {
+ return this.getTag(o);
+ },
+ $signature: 8
+ };
+ A.initHooks_closure0.prototype = {
+ call$2(o, tag) {
+ return this.getUnknownTag(o, tag);
+ },
+ $signature: 13
+ };
+ A.initHooks_closure1.prototype = {
+ call$1(tag) {
+ return this.prototypeForTag(A._asString(tag));
+ },
+ $signature: 14
+ };
+ A.StringMatch.prototype = {};
+ A.NativeByteBuffer.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_ByteBuffer_RkP;
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeTypedData.prototype = {};
+ A.NativeByteData.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_ByteData_zNC;
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeTypedArray.prototype = {
+ get$length(receiver) {
+ return receiver.length;
+ },
+ $isJavaScriptIndexingBehavior: 1
+ };
+ A.NativeTypedArrayOfDouble.prototype = {
+ $index(receiver, index) {
+ A._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $isIterable: 1,
+ $isList: 1
+ };
+ A.NativeTypedArrayOfInt.prototype = {$isIterable: 1, $isList: 1};
+ A.NativeFloat32List.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Float32List_LB7;
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeFloat64List.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Float64List_LB7;
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeInt16List.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Int16List_uXf;
+ },
+ $index(receiver, index) {
+ A._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeInt32List.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Int32List_O50;
+ },
+ $index(receiver, index) {
+ A._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeInt8List.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Int8List_ekJ;
+ },
+ $index(receiver, index) {
+ A._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeUint16List.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Uint16List_2bx;
+ },
+ $index(receiver, index) {
+ A._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeUint32List.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Uint32List_2bx;
+ },
+ $index(receiver, index) {
+ A._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeUint8ClampedList.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Uint8ClampedList_Jik;
+ },
+ get$length(receiver) {
+ return receiver.length;
+ },
+ $index(receiver, index) {
+ A._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A.NativeUint8List.prototype = {
+ get$runtimeType(receiver) {
+ return B.Type_Uint8List_WLA;
+ },
+ get$length(receiver) {
+ return receiver.length;
+ },
+ $index(receiver, index) {
+ A._checkValidIndex(index, receiver, receiver.length);
+ return receiver[index];
+ },
+ $isTrustedGetRuntimeType: 1
+ };
+ A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin.prototype = {};
+ A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin.prototype = {};
+ A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin.prototype = {};
+ A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin.prototype = {};
+ A.Rti.prototype = {
+ _eval$1(recipe) {
+ return A._Universe_evalInEnvironment(init.typeUniverse, this, recipe);
+ },
+ _bind$1(typeOrTuple) {
+ return A._Universe_bind(init.typeUniverse, this, typeOrTuple);
+ }
+ };
+ A._FunctionParameters.prototype = {};
+ A._Type.prototype = {
+ toString$0(_) {
+ return A._rtiToString(this._rti, null);
+ }
+ };
+ A._Error.prototype = {
+ toString$0(_) {
+ return this.__rti$_message;
+ }
+ };
+ A._TypeError.prototype = {$isTypeError: 1};
+ A._AsyncRun__initializeScheduleImmediate_internalCallback.prototype = {
+ call$1(_) {
+ var t1 = this._box_0,
+ f = t1.storedCallback;
+ t1.storedCallback = null;
+ f.call$0();
+ },
+ $signature: 4
+ };
+ A._AsyncRun__initializeScheduleImmediate_closure.prototype = {
+ call$1(callback) {
+ var t1, t2;
+ this._box_0.storedCallback = type$.void_Function._as(callback);
+ t1 = this.div;
+ t2 = this.span;
+ t1.firstChild ? t1.removeChild(t2) : t1.appendChild(t2);
+ },
+ $signature: 15
+ };
+ A._AsyncRun__scheduleImmediateJsOverride_internalCallback.prototype = {
+ call$0() {
+ this.callback.call$0();
+ },
+ $signature: 2
+ };
+ A._AsyncRun__scheduleImmediateWithSetImmediate_internalCallback.prototype = {
+ call$0() {
+ this.callback.call$0();
+ },
+ $signature: 2
+ };
+ A._TimerImpl.prototype = {
+ _TimerImpl$2(milliseconds, callback) {
+ if (self.setTimeout != null)
+ this._handle = self.setTimeout(A.convertDartClosureToJS(new A._TimerImpl_internalCallback(this, callback), 0), milliseconds);
+ else
+ throw A.wrapException(A.UnsupportedError$("`setTimeout()` not found."));
+ },
+ cancel$0() {
+ if (self.setTimeout != null) {
+ var t1 = this._handle;
+ if (t1 == null)
+ return;
+ self.clearTimeout(t1);
+ this._handle = null;
+ } else
+ throw A.wrapException(A.UnsupportedError$("Canceling a timer."));
+ },
+ $isTimer: 1
+ };
+ A._TimerImpl_internalCallback.prototype = {
+ call$0() {
+ this.$this._handle = null;
+ this.callback.call$0();
+ },
+ $signature: 0
+ };
+ A._AsyncAwaitCompleter.prototype = {
+ complete$1(value) {
+ var t2, _this = this,
+ t1 = _this.$ti;
+ t1._eval$1("1/?")._as(value);
+ if (value == null)
+ value = t1._precomputed1._as(value);
+ if (!_this.isSync)
+ _this._future._asyncComplete$1(value);
+ else {
+ t2 = _this._future;
+ if (t1._eval$1("Future<1>")._is(value))
+ t2._chainFuture$1(value);
+ else
+ t2._completeWithValue$1(value);
+ }
+ },
+ completeError$2(e, st) {
+ var t1 = this._future;
+ if (this.isSync)
+ t1._completeError$2(e, st);
+ else
+ t1._asyncCompleteError$2(e, st);
+ },
+ $isCompleter: 1
+ };
+ A._awaitOnObject_closure.prototype = {
+ call$1(result) {
+ return this.bodyFunction.call$2(0, result);
+ },
+ $signature: 3
+ };
+ A._awaitOnObject_closure0.prototype = {
+ call$2(error, stackTrace) {
+ this.bodyFunction.call$2(1, new A.ExceptionAndStackTrace(error, type$.StackTrace._as(stackTrace)));
+ },
+ $signature: 16
+ };
+ A._wrapJsFunctionForAsync_closure.prototype = {
+ call$2(errorCode, result) {
+ this.$protected(A._asInt(errorCode), result);
+ },
+ $signature: 17
+ };
+ A.AsyncError.prototype = {
+ toString$0(_) {
+ return A.S(this.error);
+ },
+ $isError: 1,
+ get$stackTrace() {
+ return this.stackTrace;
+ }
+ };
+ A._Completer.prototype = {
+ completeError$2(error, stackTrace) {
+ A.checkNotNullable(error, "error", type$.Object);
+ if ((this.future._state & 30) !== 0)
+ throw A.wrapException(A.StateError$("Future already completed"));
+ if (stackTrace == null)
+ stackTrace = A.AsyncError_defaultStackTrace(error);
+ this._completeError$2(error, stackTrace);
+ },
+ completeError$1(error) {
+ return this.completeError$2(error, null);
+ },
+ $isCompleter: 1
+ };
+ A._AsyncCompleter.prototype = {
+ complete$1(value) {
+ var t2,
+ t1 = this.$ti;
+ t1._eval$1("1/?")._as(value);
+ t2 = this.future;
+ if ((t2._state & 30) !== 0)
+ throw A.wrapException(A.StateError$("Future already completed"));
+ t2._asyncComplete$1(t1._eval$1("1/")._as(value));
+ },
+ complete$0() {
+ return this.complete$1(null);
+ },
+ _completeError$2(error, stackTrace) {
+ this.future._asyncCompleteError$2(error, stackTrace);
+ }
+ };
+ A._SyncCompleter.prototype = {
+ complete$1(value) {
+ var t2,
+ t1 = this.$ti;
+ t1._eval$1("1/?")._as(value);
+ t2 = this.future;
+ if ((t2._state & 30) !== 0)
+ throw A.wrapException(A.StateError$("Future already completed"));
+ t2._complete$1(t1._eval$1("1/")._as(value));
+ },
+ _completeError$2(error, stackTrace) {
+ this.future._completeError$2(error, stackTrace);
+ }
+ };
+ A._FutureListener.prototype = {
+ matchesErrorTest$1(asyncError) {
+ if ((this.state & 15) !== 6)
+ return true;
+ return this.result._zone.runUnary$2$2(type$.bool_Function_Object._as(this.callback), asyncError.error, type$.bool, type$.Object);
+ },
+ handleError$1(asyncError) {
+ var exception, _this = this,
+ errorCallback = _this.errorCallback,
+ result = null,
+ t1 = type$.dynamic,
+ t2 = type$.Object,
+ t3 = asyncError.error,
+ t4 = _this.result._zone;
+ if (type$.dynamic_Function_Object_StackTrace._is(errorCallback))
+ result = t4.runBinary$3$3(errorCallback, t3, asyncError.stackTrace, t1, t2, type$.StackTrace);
+ else
+ result = t4.runUnary$2$2(type$.dynamic_Function_Object._as(errorCallback), t3, t1, t2);
+ try {
+ t1 = _this.$ti._eval$1("2/")._as(result);
+ return t1;
+ } catch (exception) {
+ if (type$.TypeError._is(A.unwrapException(exception))) {
+ if ((_this.state & 1) !== 0)
+ throw A.wrapException(A.ArgumentError$("The error handler of Future.then must return a value of the returned future's type", "onError"));
+ throw A.wrapException(A.ArgumentError$("The error handler of Future.catchError must return a value of the future's type", "onError"));
+ } else
+ throw exception;
+ }
+ }
+ };
+ A._Future.prototype = {
+ _setChained$1(source) {
+ this._state = this._state & 1 | 4;
+ this._resultOrListeners = source;
+ },
+ then$1$2$onError(f, onError, $R) {
+ var currentZone, result, t2,
+ t1 = this.$ti;
+ t1._bind$1($R)._eval$1("1/(2)")._as(f);
+ currentZone = $.Zone__current;
+ if (currentZone === B.C__RootZone) {
+ if (onError != null && !type$.dynamic_Function_Object_StackTrace._is(onError) && !type$.dynamic_Function_Object._is(onError))
+ throw A.wrapException(A.ArgumentError$value(onError, "onError", string$.Error_));
+ } else {
+ $R._eval$1("@<0/>")._bind$1(t1._precomputed1)._eval$1("1(2)")._as(f);
+ if (onError != null)
+ onError = A._registerErrorHandler(onError, currentZone);
+ }
+ result = new A._Future(currentZone, $R._eval$1("_Future<0>"));
+ t2 = onError == null ? 1 : 3;
+ this._addListener$1(new A._FutureListener(result, t2, f, onError, t1._eval$1("@<1>")._bind$1($R)._eval$1("_FutureListener<1,2>")));
+ return result;
+ },
+ then$1$1(f, $R) {
+ return this.then$1$2$onError(f, null, $R);
+ },
+ _thenAwait$1$2(f, onError, $E) {
+ var result,
+ t1 = this.$ti;
+ t1._bind$1($E)._eval$1("1/(2)")._as(f);
+ result = new A._Future($.Zone__current, $E._eval$1("_Future<0>"));
+ this._addListener$1(new A._FutureListener(result, 19, f, onError, t1._eval$1("@<1>")._bind$1($E)._eval$1("_FutureListener<1,2>")));
+ return result;
+ },
+ whenComplete$1(action) {
+ var t1, result;
+ type$.dynamic_Function._as(action);
+ t1 = this.$ti;
+ result = new A._Future($.Zone__current, t1);
+ this._addListener$1(new A._FutureListener(result, 8, action, null, t1._eval$1("@<1>")._bind$1(t1._precomputed1)._eval$1("_FutureListener<1,2>")));
+ return result;
+ },
+ _setErrorObject$1(error) {
+ this._state = this._state & 1 | 16;
+ this._resultOrListeners = error;
+ },
+ _cloneResult$1(source) {
+ this._state = source._state & 30 | this._state & 1;
+ this._resultOrListeners = source._resultOrListeners;
+ },
+ _addListener$1(listener) {
+ var source, _this = this,
+ t1 = _this._state;
+ if (t1 <= 3) {
+ listener._nextListener = type$.nullable__FutureListener_dynamic_dynamic._as(_this._resultOrListeners);
+ _this._resultOrListeners = listener;
+ } else {
+ if ((t1 & 4) !== 0) {
+ source = type$._Future_dynamic._as(_this._resultOrListeners);
+ if ((source._state & 24) === 0) {
+ source._addListener$1(listener);
+ return;
+ }
+ _this._cloneResult$1(source);
+ }
+ A._rootScheduleMicrotask(null, null, _this._zone, type$.void_Function._as(new A._Future__addListener_closure(_this, listener)));
+ }
+ },
+ _prependListeners$1(listeners) {
+ var t1, existingListeners, next, cursor, next0, source, _this = this, _box_0 = {};
+ _box_0.listeners = listeners;
+ if (listeners == null)
+ return;
+ t1 = _this._state;
+ if (t1 <= 3) {
+ existingListeners = type$.nullable__FutureListener_dynamic_dynamic._as(_this._resultOrListeners);
+ _this._resultOrListeners = listeners;
+ if (existingListeners != null) {
+ next = listeners._nextListener;
+ for (cursor = listeners; next != null; cursor = next, next = next0)
+ next0 = next._nextListener;
+ cursor._nextListener = existingListeners;
+ }
+ } else {
+ if ((t1 & 4) !== 0) {
+ source = type$._Future_dynamic._as(_this._resultOrListeners);
+ if ((source._state & 24) === 0) {
+ source._prependListeners$1(listeners);
+ return;
+ }
+ _this._cloneResult$1(source);
+ }
+ _box_0.listeners = _this._reverseListeners$1(listeners);
+ A._rootScheduleMicrotask(null, null, _this._zone, type$.void_Function._as(new A._Future__prependListeners_closure(_box_0, _this)));
+ }
+ },
+ _removeListeners$0() {
+ var current = type$.nullable__FutureListener_dynamic_dynamic._as(this._resultOrListeners);
+ this._resultOrListeners = null;
+ return this._reverseListeners$1(current);
+ },
+ _reverseListeners$1(listeners) {
+ var current, prev, next;
+ for (current = listeners, prev = null; current != null; prev = current, current = next) {
+ next = current._nextListener;
+ current._nextListener = prev;
+ }
+ return prev;
+ },
+ _chainForeignFuture$1(source) {
+ var e, s, exception, _this = this;
+ _this._state ^= 2;
+ try {
+ source.then$1$2$onError(new A._Future__chainForeignFuture_closure(_this), new A._Future__chainForeignFuture_closure0(_this), type$.Null);
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ A.scheduleMicrotask(new A._Future__chainForeignFuture_closure1(_this, e, s));
+ }
+ },
+ _complete$1(value) {
+ var listeners, _this = this,
+ t1 = _this.$ti;
+ t1._eval$1("1/")._as(value);
+ if (t1._eval$1("Future<1>")._is(value))
+ if (t1._is(value))
+ A._Future__chainCoreFutureSync(value, _this);
+ else
+ _this._chainForeignFuture$1(value);
+ else {
+ listeners = _this._removeListeners$0();
+ t1._precomputed1._as(value);
+ _this._state = 8;
+ _this._resultOrListeners = value;
+ A._Future__propagateToListeners(_this, listeners);
+ }
+ },
+ _completeWithValue$1(value) {
+ var listeners, _this = this;
+ _this.$ti._precomputed1._as(value);
+ listeners = _this._removeListeners$0();
+ _this._state = 8;
+ _this._resultOrListeners = value;
+ A._Future__propagateToListeners(_this, listeners);
+ },
+ _completeError$2(error, stackTrace) {
+ var listeners;
+ type$.Object._as(error);
+ type$.StackTrace._as(stackTrace);
+ listeners = this._removeListeners$0();
+ this._setErrorObject$1(A.AsyncError$(error, stackTrace));
+ A._Future__propagateToListeners(this, listeners);
+ },
+ _asyncComplete$1(value) {
+ var t1 = this.$ti;
+ t1._eval$1("1/")._as(value);
+ if (t1._eval$1("Future<1>")._is(value)) {
+ this._chainFuture$1(value);
+ return;
+ }
+ this._asyncCompleteWithValue$1(value);
+ },
+ _asyncCompleteWithValue$1(value) {
+ var _this = this;
+ _this.$ti._precomputed1._as(value);
+ _this._state ^= 2;
+ A._rootScheduleMicrotask(null, null, _this._zone, type$.void_Function._as(new A._Future__asyncCompleteWithValue_closure(_this, value)));
+ },
+ _chainFuture$1(value) {
+ var t1 = this.$ti;
+ t1._eval$1("Future<1>")._as(value);
+ if (t1._is(value)) {
+ A._Future__chainCoreFutureAsync(value, this);
+ return;
+ }
+ this._chainForeignFuture$1(value);
+ },
+ _asyncCompleteError$2(error, stackTrace) {
+ type$.StackTrace._as(stackTrace);
+ this._state ^= 2;
+ A._rootScheduleMicrotask(null, null, this._zone, type$.void_Function._as(new A._Future__asyncCompleteError_closure(this, error, stackTrace)));
+ },
+ $isFuture: 1
+ };
+ A._Future__addListener_closure.prototype = {
+ call$0() {
+ A._Future__propagateToListeners(this.$this, this.listener);
+ },
+ $signature: 0
+ };
+ A._Future__prependListeners_closure.prototype = {
+ call$0() {
+ A._Future__propagateToListeners(this.$this, this._box_0.listeners);
+ },
+ $signature: 0
+ };
+ A._Future__chainForeignFuture_closure.prototype = {
+ call$1(value) {
+ var error, stackTrace, exception,
+ t1 = this.$this;
+ t1._state ^= 2;
+ try {
+ t1._completeWithValue$1(t1.$ti._precomputed1._as(value));
+ } catch (exception) {
+ error = A.unwrapException(exception);
+ stackTrace = A.getTraceFromException(exception);
+ t1._completeError$2(error, stackTrace);
+ }
+ },
+ $signature: 4
+ };
+ A._Future__chainForeignFuture_closure0.prototype = {
+ call$2(error, stackTrace) {
+ this.$this._completeError$2(type$.Object._as(error), type$.StackTrace._as(stackTrace));
+ },
+ $signature: 5
+ };
+ A._Future__chainForeignFuture_closure1.prototype = {
+ call$0() {
+ this.$this._completeError$2(this.e, this.s);
+ },
+ $signature: 0
+ };
+ A._Future__chainCoreFutureAsync_closure.prototype = {
+ call$0() {
+ A._Future__chainCoreFutureSync(this._box_0.source, this.target);
+ },
+ $signature: 0
+ };
+ A._Future__asyncCompleteWithValue_closure.prototype = {
+ call$0() {
+ this.$this._completeWithValue$1(this.value);
+ },
+ $signature: 0
+ };
+ A._Future__asyncCompleteError_closure.prototype = {
+ call$0() {
+ this.$this._completeError$2(this.error, this.stackTrace);
+ },
+ $signature: 0
+ };
+ A._Future__propagateToListeners_handleWhenCompleteCallback.prototype = {
+ call$0() {
+ var e, s, t1, exception, t2, originalSource, _this = this, completeResult = null;
+ try {
+ t1 = _this._box_0.listener;
+ completeResult = t1.result._zone.run$1$1(type$.dynamic_Function._as(t1.callback), type$.dynamic);
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ t1 = _this.hasError && type$.AsyncError._as(_this._box_1.source._resultOrListeners).error === e;
+ t2 = _this._box_0;
+ if (t1)
+ t2.listenerValueOrError = type$.AsyncError._as(_this._box_1.source._resultOrListeners);
+ else
+ t2.listenerValueOrError = A.AsyncError$(e, s);
+ t2.listenerHasError = true;
+ return;
+ }
+ if (completeResult instanceof A._Future && (completeResult._state & 24) !== 0) {
+ if ((completeResult._state & 16) !== 0) {
+ t1 = _this._box_0;
+ t1.listenerValueOrError = type$.AsyncError._as(completeResult._resultOrListeners);
+ t1.listenerHasError = true;
+ }
+ return;
+ }
+ if (completeResult instanceof A._Future) {
+ originalSource = _this._box_1.source;
+ t1 = _this._box_0;
+ t1.listenerValueOrError = completeResult.then$1$1(new A._Future__propagateToListeners_handleWhenCompleteCallback_closure(originalSource), type$.dynamic);
+ t1.listenerHasError = false;
+ }
+ },
+ $signature: 0
+ };
+ A._Future__propagateToListeners_handleWhenCompleteCallback_closure.prototype = {
+ call$1(_) {
+ return this.originalSource;
+ },
+ $signature: 18
+ };
+ A._Future__propagateToListeners_handleValueCallback.prototype = {
+ call$0() {
+ var e, s, t1, t2, t3, t4, t5, exception;
+ try {
+ t1 = this._box_0;
+ t2 = t1.listener;
+ t3 = t2.$ti;
+ t4 = t3._precomputed1;
+ t5 = t4._as(this.sourceResult);
+ t1.listenerValueOrError = t2.result._zone.runUnary$2$2(t3._eval$1("2/(1)")._as(t2.callback), t5, t3._eval$1("2/"), t4);
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ t1 = this._box_0;
+ t1.listenerValueOrError = A.AsyncError$(e, s);
+ t1.listenerHasError = true;
+ }
+ },
+ $signature: 0
+ };
+ A._Future__propagateToListeners_handleError.prototype = {
+ call$0() {
+ var asyncError, e, s, t1, exception, t2, _this = this;
+ try {
+ asyncError = type$.AsyncError._as(_this._box_1.source._resultOrListeners);
+ t1 = _this._box_0;
+ if (t1.listener.matchesErrorTest$1(asyncError) && t1.listener.errorCallback != null) {
+ t1.listenerValueOrError = t1.listener.handleError$1(asyncError);
+ t1.listenerHasError = false;
+ }
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ t1 = type$.AsyncError._as(_this._box_1.source._resultOrListeners);
+ t2 = _this._box_0;
+ if (t1.error === e)
+ t2.listenerValueOrError = t1;
+ else
+ t2.listenerValueOrError = A.AsyncError$(e, s);
+ t2.listenerHasError = true;
+ }
+ },
+ $signature: 0
+ };
+ A._AsyncCallbackEntry.prototype = {};
+ A.Stream.prototype = {
+ get$length(_) {
+ var t1 = {},
+ future = new A._Future($.Zone__current, type$._Future_int);
+ t1.count = 0;
+ this.listen$4$cancelOnError$onDone$onError(new A.Stream_length_closure(t1, this), true, new A.Stream_length_closure0(t1, future), future.get$_completeError());
+ return future;
+ },
+ get$first(_) {
+ var future = new A._Future($.Zone__current, A._instanceType(this)._eval$1("_Future<1>")),
+ subscription = this.listen$4$cancelOnError$onDone$onError(null, true, new A.Stream_first_closure(future), future.get$_completeError());
+ subscription.onData$1(new A.Stream_first_closure0(this, subscription, future));
+ return future;
+ }
+ };
+ A.Stream_length_closure.prototype = {
+ call$1(_) {
+ A._instanceType(this.$this)._precomputed1._as(_);
+ ++this._box_0.count;
+ },
+ $signature() {
+ return A._instanceType(this.$this)._eval$1("~(1)");
+ }
+ };
+ A.Stream_length_closure0.prototype = {
+ call$0() {
+ this.future._complete$1(this._box_0.count);
+ },
+ $signature: 0
+ };
+ A.Stream_first_closure.prototype = {
+ call$0() {
+ var e, s, t1, exception, stackTrace;
+ try {
+ t1 = A.IterableElementError_noElement();
+ throw A.wrapException(t1);
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ t1 = e;
+ stackTrace = s;
+ if (stackTrace == null)
+ stackTrace = A.AsyncError_defaultStackTrace(t1);
+ this.future._completeError$2(t1, stackTrace);
+ }
+ },
+ $signature: 0
+ };
+ A.Stream_first_closure0.prototype = {
+ call$1(value) {
+ A._cancelAndValue(this.subscription, this.future, A._instanceType(this.$this)._precomputed1._as(value));
+ },
+ $signature() {
+ return A._instanceType(this.$this)._eval$1("~(1)");
+ }
+ };
+ A._StreamController.prototype = {
+ get$_pendingEvents() {
+ var t1, _this = this;
+ if ((_this._state & 8) === 0)
+ return A._instanceType(_this)._eval$1("_PendingEvents<1>?")._as(_this._varData);
+ t1 = A._instanceType(_this);
+ return t1._eval$1("_PendingEvents<1>?")._as(t1._eval$1("_StreamControllerAddStreamState<1>")._as(_this._varData).get$_varData());
+ },
+ _ensurePendingEvents$0() {
+ var events, t1, _this = this;
+ if ((_this._state & 8) === 0) {
+ events = _this._varData;
+ if (events == null)
+ events = _this._varData = new A._PendingEvents(A._instanceType(_this)._eval$1("_PendingEvents<1>"));
+ return A._instanceType(_this)._eval$1("_PendingEvents<1>")._as(events);
+ }
+ t1 = A._instanceType(_this);
+ events = t1._eval$1("_StreamControllerAddStreamState<1>")._as(_this._varData).get$_varData();
+ return t1._eval$1("_PendingEvents<1>")._as(events);
+ },
+ get$_subscription() {
+ var varData = this._varData;
+ if ((this._state & 8) !== 0)
+ varData = type$._StreamControllerAddStreamState_nullable_Object._as(varData).get$_varData();
+ return A._instanceType(this)._eval$1("_ControllerSubscription<1>")._as(varData);
+ },
+ _badEventState$0() {
+ if ((this._state & 4) !== 0)
+ return new A.StateError("Cannot add event after closing");
+ return new A.StateError("Cannot add event while adding a stream");
+ },
+ _ensureDoneFuture$0() {
+ var t1 = this._doneFuture;
+ if (t1 == null)
+ t1 = this._doneFuture = (this._state & 2) !== 0 ? $.$get$Future__nullFuture() : new A._Future($.Zone__current, type$._Future_void);
+ return t1;
+ },
+ add$1(_, value) {
+ var t2, _this = this,
+ t1 = A._instanceType(_this);
+ t1._precomputed1._as(value);
+ t2 = _this._state;
+ if (t2 >= 4)
+ throw A.wrapException(_this._badEventState$0());
+ if ((t2 & 1) !== 0)
+ _this._sendData$1(value);
+ else if ((t2 & 3) === 0)
+ _this._ensurePendingEvents$0().add$1(0, new A._DelayedData(value, t1._eval$1("_DelayedData<1>")));
+ },
+ close$0() {
+ var _this = this,
+ t1 = _this._state;
+ if ((t1 & 4) !== 0)
+ return _this._ensureDoneFuture$0();
+ if (t1 >= 4)
+ throw A.wrapException(_this._badEventState$0());
+ t1 = _this._state = t1 | 4;
+ if ((t1 & 1) !== 0)
+ _this._sendDone$0();
+ else if ((t1 & 3) === 0)
+ _this._ensurePendingEvents$0().add$1(0, B.C__DelayedDone);
+ return _this._ensureDoneFuture$0();
+ },
+ _subscribe$4(onData, onError, onDone, cancelOnError) {
+ var t2, t3, t4, t5, t6, t7, t8, subscription, pendingEvents, addState, _this = this,
+ t1 = A._instanceType(_this);
+ t1._eval$1("~(1)?")._as(onData);
+ type$.nullable_void_Function._as(onDone);
+ if ((_this._state & 3) !== 0)
+ throw A.wrapException(A.StateError$("Stream has already been listened to."));
+ t2 = $.Zone__current;
+ t3 = cancelOnError ? 1 : 0;
+ t4 = onError != null ? 32 : 0;
+ t5 = A._BufferingStreamSubscription__registerDataHandler(t2, onData, t1._precomputed1);
+ t6 = A._BufferingStreamSubscription__registerErrorHandler(t2, onError);
+ t7 = onDone == null ? A.async___nullDoneHandler$closure() : onDone;
+ t8 = type$.void_Function;
+ subscription = new A._ControllerSubscription(_this, t5, t6, t8._as(t7), t2, t3 | t4, t1._eval$1("_ControllerSubscription<1>"));
+ pendingEvents = _this.get$_pendingEvents();
+ t4 = _this._state |= 1;
+ if ((t4 & 8) !== 0) {
+ addState = t1._eval$1("_StreamControllerAddStreamState<1>")._as(_this._varData);
+ addState.set$_varData(subscription);
+ addState.resume$0();
+ } else
+ _this._varData = subscription;
+ subscription._setPendingEvents$1(pendingEvents);
+ t1 = t8._as(new A._StreamController__subscribe_closure(_this));
+ t2 = subscription._state;
+ subscription._state = t2 | 64;
+ t1.call$0();
+ subscription._state &= 4294967231;
+ subscription._checkState$1((t2 & 4) !== 0);
+ return subscription;
+ },
+ _recordCancel$1(subscription) {
+ var result, onCancel, cancelResult, e, s, exception, result0, _this = this,
+ t1 = A._instanceType(_this);
+ t1._eval$1("StreamSubscription<1>")._as(subscription);
+ result = null;
+ if ((_this._state & 8) !== 0)
+ result = t1._eval$1("_StreamControllerAddStreamState<1>")._as(_this._varData).cancel$0();
+ _this._varData = null;
+ _this._state = _this._state & 4294967286 | 2;
+ onCancel = _this.onCancel;
+ if (onCancel != null)
+ if (result == null)
+ try {
+ cancelResult = onCancel.call$0();
+ if (cancelResult instanceof A._Future)
+ result = cancelResult;
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ result0 = new A._Future($.Zone__current, type$._Future_void);
+ result0._asyncCompleteError$2(e, s);
+ result = result0;
+ }
+ else
+ result = result.whenComplete$1(onCancel);
+ t1 = new A._StreamController__recordCancel_complete(_this);
+ if (result != null)
+ result = result.whenComplete$1(t1);
+ else
+ t1.call$0();
+ return result;
+ },
+ $isStreamController: 1,
+ $is_StreamControllerLifecycle: 1,
+ $is_EventDispatch: 1
+ };
+ A._StreamController__subscribe_closure.prototype = {
+ call$0() {
+ A._runGuarded(this.$this.onListen);
+ },
+ $signature: 0
+ };
+ A._StreamController__recordCancel_complete.prototype = {
+ call$0() {
+ var doneFuture = this.$this._doneFuture;
+ if (doneFuture != null && (doneFuture._state & 30) === 0)
+ doneFuture._asyncComplete$1(null);
+ },
+ $signature: 0
+ };
+ A._AsyncStreamControllerDispatch.prototype = {
+ _sendData$1(data) {
+ var t1 = this.$ti;
+ t1._precomputed1._as(data);
+ this.get$_subscription()._addPending$1(new A._DelayedData(data, t1._eval$1("_DelayedData<1>")));
+ },
+ _sendError$2(error, stackTrace) {
+ this.get$_subscription()._addPending$1(new A._DelayedError(error, stackTrace));
+ },
+ _sendDone$0() {
+ this.get$_subscription()._addPending$1(B.C__DelayedDone);
+ }
+ };
+ A._AsyncStreamController.prototype = {};
+ A._ControllerStream.prototype = {
+ get$hashCode(_) {
+ return (A.Primitives_objectHashCode(this._controller) ^ 892482866) >>> 0;
+ },
+ $eq(_, other) {
+ if (other == null)
+ return false;
+ if (this === other)
+ return true;
+ return other instanceof A._ControllerStream && other._controller === this._controller;
+ }
+ };
+ A._ControllerSubscription.prototype = {
+ _onCancel$0() {
+ return this._controller._recordCancel$1(this);
+ },
+ _onPause$0() {
+ var t1 = this._controller,
+ t2 = A._instanceType(t1);
+ t2._eval$1("StreamSubscription<1>")._as(this);
+ if ((t1._state & 8) !== 0)
+ t2._eval$1("_StreamControllerAddStreamState<1>")._as(t1._varData).pause$0();
+ A._runGuarded(t1.onPause);
+ },
+ _onResume$0() {
+ var t1 = this._controller,
+ t2 = A._instanceType(t1);
+ t2._eval$1("StreamSubscription<1>")._as(this);
+ if ((t1._state & 8) !== 0)
+ t2._eval$1("_StreamControllerAddStreamState<1>")._as(t1._varData).resume$0();
+ A._runGuarded(t1.onResume);
+ }
+ };
+ A._StreamSinkWrapper.prototype = {};
+ A._BufferingStreamSubscription.prototype = {
+ _setPendingEvents$1(pendingEvents) {
+ var _this = this;
+ A._instanceType(_this)._eval$1("_PendingEvents<1>?")._as(pendingEvents);
+ if (pendingEvents == null)
+ return;
+ _this.set$_pending(pendingEvents);
+ if (pendingEvents.lastPendingEvent != null) {
+ _this._state |= 128;
+ pendingEvents.schedule$1(_this);
+ }
+ },
+ onData$1(handleData) {
+ var t1 = A._instanceType(this);
+ this.set$_onData(A._BufferingStreamSubscription__registerDataHandler(this._zone, t1._eval$1("~(1)?")._as(handleData), t1._precomputed1));
+ },
+ cancel$0() {
+ var t1 = this._state &= 4294967279;
+ if ((t1 & 8) === 0)
+ this._cancel$0();
+ t1 = this._cancelFuture;
+ return t1 == null ? $.$get$Future__nullFuture() : t1;
+ },
+ asFuture$1$1(futureValue, $E) {
+ var result, _this = this, t1 = {};
+ t1.resultValue = null;
+ if (!$E._is(null))
+ throw A.wrapException(A.ArgumentError$notNull("futureValue"));
+ $E._as(futureValue);
+ t1.resultValue = futureValue;
+ result = new A._Future($.Zone__current, $E._eval$1("_Future<0>"));
+ _this.set$_onDone(new A._BufferingStreamSubscription_asFuture_closure(t1, result));
+ _this._state |= 32;
+ _this._onError = new A._BufferingStreamSubscription_asFuture_closure0(_this, result);
+ return result;
+ },
+ _cancel$0() {
+ var t2, _this = this,
+ t1 = _this._state |= 8;
+ if ((t1 & 128) !== 0) {
+ t2 = _this._pending;
+ if (t2._state === 1)
+ t2._state = 3;
+ }
+ if ((t1 & 64) === 0)
+ _this.set$_pending(null);
+ _this._cancelFuture = _this._onCancel$0();
+ },
+ _onPause$0() {
+ },
+ _onResume$0() {
+ },
+ _onCancel$0() {
+ return null;
+ },
+ _addPending$1($event) {
+ var t1, _this = this,
+ pending = _this._pending;
+ if (pending == null) {
+ pending = new A._PendingEvents(A._instanceType(_this)._eval$1("_PendingEvents<1>"));
+ _this.set$_pending(pending);
+ }
+ pending.add$1(0, $event);
+ t1 = _this._state;
+ if ((t1 & 128) === 0) {
+ t1 |= 128;
+ _this._state = t1;
+ if (t1 < 256)
+ pending.schedule$1(_this);
+ }
+ },
+ _sendData$1(data) {
+ var t2, _this = this,
+ t1 = A._instanceType(_this)._precomputed1;
+ t1._as(data);
+ t2 = _this._state;
+ _this._state = t2 | 64;
+ _this._zone.runUnaryGuarded$1$2(_this._onData, data, t1);
+ _this._state &= 4294967231;
+ _this._checkState$1((t2 & 4) !== 0);
+ },
+ _sendError$2(error, stackTrace) {
+ var cancelFuture, _this = this,
+ t1 = _this._state,
+ t2 = new A._BufferingStreamSubscription__sendError_sendError(_this, error, stackTrace);
+ if ((t1 & 1) !== 0) {
+ _this._state = t1 | 16;
+ _this._cancel$0();
+ cancelFuture = _this._cancelFuture;
+ if (cancelFuture != null && cancelFuture !== $.$get$Future__nullFuture())
+ cancelFuture.whenComplete$1(t2);
+ else
+ t2.call$0();
+ } else {
+ t2.call$0();
+ _this._checkState$1((t1 & 4) !== 0);
+ }
+ },
+ _sendDone$0() {
+ var cancelFuture, _this = this,
+ t1 = new A._BufferingStreamSubscription__sendDone_sendDone(_this);
+ _this._cancel$0();
+ _this._state |= 16;
+ cancelFuture = _this._cancelFuture;
+ if (cancelFuture != null && cancelFuture !== $.$get$Future__nullFuture())
+ cancelFuture.whenComplete$1(t1);
+ else
+ t1.call$0();
+ },
+ _checkState$1(wasInputPaused) {
+ var t2, isInputPaused, _this = this,
+ t1 = _this._state;
+ if ((t1 & 128) !== 0 && _this._pending.lastPendingEvent == null) {
+ t1 = _this._state = t1 & 4294967167;
+ if ((t1 & 4) !== 0)
+ if (t1 < 256) {
+ t2 = _this._pending;
+ t2 = t2 == null ? null : t2.lastPendingEvent == null;
+ t2 = t2 !== false;
+ } else
+ t2 = false;
+ else
+ t2 = false;
+ if (t2) {
+ t1 &= 4294967291;
+ _this._state = t1;
+ }
+ }
+ for (; true; wasInputPaused = isInputPaused) {
+ if ((t1 & 8) !== 0) {
+ _this.set$_pending(null);
+ return;
+ }
+ isInputPaused = (t1 & 4) !== 0;
+ if (wasInputPaused === isInputPaused)
+ break;
+ _this._state = t1 ^ 64;
+ if (isInputPaused)
+ _this._onPause$0();
+ else
+ _this._onResume$0();
+ t1 = _this._state &= 4294967231;
+ }
+ if ((t1 & 128) !== 0 && t1 < 256)
+ _this._pending.schedule$1(_this);
+ },
+ set$_onData(_onData) {
+ this._onData = A._instanceType(this)._eval$1("~(1)")._as(_onData);
+ },
+ set$_onDone(_onDone) {
+ this._onDone = type$.void_Function._as(_onDone);
+ },
+ set$_pending(_pending) {
+ this._pending = A._instanceType(this)._eval$1("_PendingEvents<1>?")._as(_pending);
+ },
+ $isStreamSubscription: 1,
+ $is_EventDispatch: 1
+ };
+ A._BufferingStreamSubscription_asFuture_closure.prototype = {
+ call$0() {
+ this.result._complete$1(this._box_0.resultValue);
+ },
+ $signature: 0
+ };
+ A._BufferingStreamSubscription_asFuture_closure0.prototype = {
+ call$2(error, stackTrace) {
+ var cancelFuture = this.$this.cancel$0(),
+ t1 = this.result;
+ if (cancelFuture !== $.$get$Future__nullFuture())
+ cancelFuture.whenComplete$1(new A._BufferingStreamSubscription_asFuture__closure(t1, error, stackTrace));
+ else
+ t1._completeError$2(error, stackTrace);
+ },
+ $signature: 5
+ };
+ A._BufferingStreamSubscription_asFuture__closure.prototype = {
+ call$0() {
+ this.result._completeError$2(this.error, this.stackTrace);
+ },
+ $signature: 2
+ };
+ A._BufferingStreamSubscription__sendError_sendError.prototype = {
+ call$0() {
+ var onError, t3, t4,
+ t1 = this.$this,
+ t2 = t1._state;
+ if ((t2 & 8) !== 0 && (t2 & 16) === 0)
+ return;
+ t1._state = t2 | 64;
+ onError = t1._onError;
+ t2 = this.error;
+ t3 = type$.Object;
+ t4 = t1._zone;
+ if (type$.void_Function_Object_StackTrace._is(onError))
+ t4.runBinaryGuarded$2$3(onError, t2, this.stackTrace, t3, type$.StackTrace);
+ else
+ t4.runUnaryGuarded$1$2(type$.void_Function_Object._as(onError), t2, t3);
+ t1._state &= 4294967231;
+ },
+ $signature: 0
+ };
+ A._BufferingStreamSubscription__sendDone_sendDone.prototype = {
+ call$0() {
+ var t1 = this.$this,
+ t2 = t1._state;
+ if ((t2 & 16) === 0)
+ return;
+ t1._state = t2 | 74;
+ t1._zone.runGuarded$1(t1._onDone);
+ t1._state &= 4294967231;
+ },
+ $signature: 0
+ };
+ A._StreamImpl.prototype = {
+ listen$4$cancelOnError$onDone$onError(onData, cancelOnError, onDone, onError) {
+ var t1 = this.$ti;
+ t1._eval$1("~(1)?")._as(onData);
+ type$.nullable_void_Function._as(onDone);
+ return this._controller._subscribe$4(t1._eval$1("~(1)?")._as(onData), onError, onDone, cancelOnError === true);
+ },
+ listen$1(onData) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, null, null);
+ },
+ listen$2$cancelOnError(onData, cancelOnError) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, cancelOnError, null, null);
+ },
+ listen$2$onDone(onData, onDone) {
+ return this.listen$4$cancelOnError$onDone$onError(onData, null, onDone, null);
+ }
+ };
+ A._DelayedEvent.prototype = {
+ set$next(next) {
+ this.next = type$.nullable__DelayedEvent_dynamic._as(next);
+ },
+ get$next() {
+ return this.next;
+ }
+ };
+ A._DelayedData.prototype = {
+ perform$1(dispatch) {
+ this.$ti._eval$1("_EventDispatch<1>")._as(dispatch)._sendData$1(this.value);
+ }
+ };
+ A._DelayedError.prototype = {
+ perform$1(dispatch) {
+ dispatch._sendError$2(this.error, this.stackTrace);
+ }
+ };
+ A._DelayedDone.prototype = {
+ perform$1(dispatch) {
+ dispatch._sendDone$0();
+ },
+ get$next() {
+ return null;
+ },
+ set$next(_) {
+ throw A.wrapException(A.StateError$("No events after a done."));
+ },
+ $is_DelayedEvent: 1
+ };
+ A._PendingEvents.prototype = {
+ schedule$1(dispatch) {
+ var t1, _this = this;
+ _this.$ti._eval$1("_EventDispatch<1>")._as(dispatch);
+ t1 = _this._state;
+ if (t1 === 1)
+ return;
+ if (t1 >= 1) {
+ _this._state = 1;
+ return;
+ }
+ A.scheduleMicrotask(new A._PendingEvents_schedule_closure(_this, dispatch));
+ _this._state = 1;
+ },
+ add$1(_, $event) {
+ var _this = this,
+ lastEvent = _this.lastPendingEvent;
+ if (lastEvent == null)
+ _this.firstPendingEvent = _this.lastPendingEvent = $event;
+ else {
+ lastEvent.set$next($event);
+ _this.lastPendingEvent = $event;
+ }
+ }
+ };
+ A._PendingEvents_schedule_closure.prototype = {
+ call$0() {
+ var t2, $event, nextEvent,
+ t1 = this.$this,
+ oldState = t1._state;
+ t1._state = 0;
+ if (oldState === 3)
+ return;
+ t2 = t1.$ti._eval$1("_EventDispatch<1>")._as(this.dispatch);
+ $event = t1.firstPendingEvent;
+ nextEvent = $event.get$next();
+ t1.firstPendingEvent = nextEvent;
+ if (nextEvent == null)
+ t1.lastPendingEvent = null;
+ $event.perform$1(t2);
+ },
+ $signature: 0
+ };
+ A._StreamIterator.prototype = {};
+ A._cancelAndValue_closure.prototype = {
+ call$0() {
+ return this.future._complete$1(this.value);
+ },
+ $signature: 0
+ };
+ A._Zone.prototype = {$isZone: 1};
+ A._rootHandleError_closure.prototype = {
+ call$0() {
+ A.Error_throwWithStackTrace(this.error, this.stackTrace);
+ },
+ $signature: 0
+ };
+ A._RootZone.prototype = {
+ runGuarded$1(f) {
+ var e, s, exception;
+ type$.void_Function._as(f);
+ try {
+ if (B.C__RootZone === $.Zone__current) {
+ f.call$0();
+ return;
+ }
+ A._rootRun(null, null, this, f, type$.void);
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ A._rootHandleError(type$.Object._as(e), type$.StackTrace._as(s));
+ }
+ },
+ runUnaryGuarded$1$2(f, arg, $T) {
+ var e, s, exception;
+ $T._eval$1("~(0)")._as(f);
+ $T._as(arg);
+ try {
+ if (B.C__RootZone === $.Zone__current) {
+ f.call$1(arg);
+ return;
+ }
+ A._rootRunUnary(null, null, this, f, arg, type$.void, $T);
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ A._rootHandleError(type$.Object._as(e), type$.StackTrace._as(s));
+ }
+ },
+ runBinaryGuarded$2$3(f, arg1, arg2, T1, T2) {
+ var e, s, exception;
+ T1._eval$1("@<0>")._bind$1(T2)._eval$1("~(1,2)")._as(f);
+ T1._as(arg1);
+ T2._as(arg2);
+ try {
+ if (B.C__RootZone === $.Zone__current) {
+ f.call$2(arg1, arg2);
+ return;
+ }
+ A._rootRunBinary(null, null, this, f, arg1, arg2, type$.void, T1, T2);
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ s = A.getTraceFromException(exception);
+ A._rootHandleError(type$.Object._as(e), type$.StackTrace._as(s));
+ }
+ },
+ bindCallbackGuarded$1(f) {
+ return new A._RootZone_bindCallbackGuarded_closure(this, type$.void_Function._as(f));
+ },
+ bindUnaryCallbackGuarded$1$1(f, $T) {
+ return new A._RootZone_bindUnaryCallbackGuarded_closure(this, $T._eval$1("~(0)")._as(f), $T);
+ },
+ run$1$1(f, $R) {
+ $R._eval$1("0()")._as(f);
+ if ($.Zone__current === B.C__RootZone)
+ return f.call$0();
+ return A._rootRun(null, null, this, f, $R);
+ },
+ runUnary$2$2(f, arg, $R, $T) {
+ $R._eval$1("@<0>")._bind$1($T)._eval$1("1(2)")._as(f);
+ $T._as(arg);
+ if ($.Zone__current === B.C__RootZone)
+ return f.call$1(arg);
+ return A._rootRunUnary(null, null, this, f, arg, $R, $T);
+ },
+ runBinary$3$3(f, arg1, arg2, $R, T1, T2) {
+ $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._as(f);
+ T1._as(arg1);
+ T2._as(arg2);
+ if ($.Zone__current === B.C__RootZone)
+ return f.call$2(arg1, arg2);
+ return A._rootRunBinary(null, null, this, f, arg1, arg2, $R, T1, T2);
+ },
+ registerBinaryCallback$3$1(f, $R, T1, T2) {
+ return $R._eval$1("@<0>")._bind$1(T1)._bind$1(T2)._eval$1("1(2,3)")._as(f);
+ }
+ };
+ A._RootZone_bindCallbackGuarded_closure.prototype = {
+ call$0() {
+ return this.$this.runGuarded$1(this.f);
+ },
+ $signature: 0
+ };
+ A._RootZone_bindUnaryCallbackGuarded_closure.prototype = {
+ call$1(arg) {
+ var t1 = this.T;
+ return this.$this.runUnaryGuarded$1$2(this.f, t1._as(arg), t1);
+ },
+ $signature() {
+ return this.T._eval$1("~(0)");
+ }
+ };
+ A._HashMap.prototype = {
+ get$length(_) {
+ return this._collection$_length;
+ },
+ get$isEmpty(_) {
+ return this._collection$_length === 0;
+ },
+ get$keys() {
+ return new A._HashMapKeyIterable(this, this.$ti._eval$1("_HashMapKeyIterable<1>"));
+ },
+ containsKey$1(key) {
+ var strings, nums;
+ if (typeof key == "string" && key !== "__proto__") {
+ strings = this._collection$_strings;
+ return strings == null ? false : strings[key] != null;
+ } else if (typeof key == "number" && (key & 1073741823) === key) {
+ nums = this._collection$_nums;
+ return nums == null ? false : nums[key] != null;
+ } else
+ return this._containsKey$1(key);
+ },
+ _containsKey$1(key) {
+ var rest = this._collection$_rest;
+ if (rest == null)
+ return false;
+ return this._findBucketIndex$2(this._getBucket$2(rest, key), key) >= 0;
+ },
+ $index(_, key) {
+ var strings, t1, nums;
+ if (typeof key == "string" && key !== "__proto__") {
+ strings = this._collection$_strings;
+ t1 = strings == null ? null : A._HashMap__getTableEntry(strings, key);
+ return t1;
+ } else if (typeof key == "number" && (key & 1073741823) === key) {
+ nums = this._collection$_nums;
+ t1 = nums == null ? null : A._HashMap__getTableEntry(nums, key);
+ return t1;
+ } else
+ return this._get$1(key);
+ },
+ _get$1(key) {
+ var bucket, index,
+ rest = this._collection$_rest;
+ if (rest == null)
+ return null;
+ bucket = this._getBucket$2(rest, key);
+ index = this._findBucketIndex$2(bucket, key);
+ return index < 0 ? null : bucket[index + 1];
+ },
+ $indexSet(_, key, value) {
+ var strings, nums, rest, hash, bucket, index, _this = this,
+ t1 = _this.$ti;
+ t1._precomputed1._as(key);
+ t1._rest[1]._as(value);
+ if (typeof key == "string" && key !== "__proto__") {
+ strings = _this._collection$_strings;
+ _this._collection$_addHashTableEntry$3(strings == null ? _this._collection$_strings = A._HashMap__newHashTable() : strings, key, value);
+ } else if (typeof key == "number" && (key & 1073741823) === key) {
+ nums = _this._collection$_nums;
+ _this._collection$_addHashTableEntry$3(nums == null ? _this._collection$_nums = A._HashMap__newHashTable() : nums, key, value);
+ } else {
+ rest = _this._collection$_rest;
+ if (rest == null)
+ rest = _this._collection$_rest = A._HashMap__newHashTable();
+ hash = A.objectHashCode(key) & 1073741823;
+ bucket = rest[hash];
+ if (bucket == null) {
+ A._HashMap__setTableEntry(rest, hash, [key, value]);
+ ++_this._collection$_length;
+ _this._collection$_keys = null;
+ } else {
+ index = _this._findBucketIndex$2(bucket, key);
+ if (index >= 0)
+ bucket[index + 1] = value;
+ else {
+ bucket.push(key, value);
+ ++_this._collection$_length;
+ _this._collection$_keys = null;
+ }
+ }
+ }
+ },
+ forEach$1(_, action) {
+ var keys, $length, t2, i, key, t3, _this = this,
+ t1 = _this.$ti;
+ t1._eval$1("~(1,2)")._as(action);
+ keys = _this._computeKeys$0();
+ for ($length = keys.length, t2 = t1._precomputed1, t1 = t1._rest[1], i = 0; i < $length; ++i) {
+ key = keys[i];
+ t2._as(key);
+ t3 = _this.$index(0, key);
+ action.call$2(key, t3 == null ? t1._as(t3) : t3);
+ if (keys !== _this._collection$_keys)
+ throw A.wrapException(A.ConcurrentModificationError$(_this));
+ }
+ },
+ _computeKeys$0() {
+ var strings, names, entries, index, i, nums, rest, bucket, $length, i0, _this = this,
+ result = _this._collection$_keys;
+ if (result != null)
+ return result;
+ result = A.List_List$filled(_this._collection$_length, null, false, type$.dynamic);
+ strings = _this._collection$_strings;
+ if (strings != null) {
+ names = Object.getOwnPropertyNames(strings);
+ entries = names.length;
+ for (index = 0, i = 0; i < entries; ++i) {
+ result[index] = names[i];
+ ++index;
+ }
+ } else
+ index = 0;
+ nums = _this._collection$_nums;
+ if (nums != null) {
+ names = Object.getOwnPropertyNames(nums);
+ entries = names.length;
+ for (i = 0; i < entries; ++i) {
+ result[index] = +names[i];
+ ++index;
+ }
+ }
+ rest = _this._collection$_rest;
+ if (rest != null) {
+ names = Object.getOwnPropertyNames(rest);
+ entries = names.length;
+ for (i = 0; i < entries; ++i) {
+ bucket = rest[names[i]];
+ $length = bucket.length;
+ for (i0 = 0; i0 < $length; i0 += 2) {
+ result[index] = bucket[i0];
+ ++index;
+ }
+ }
+ }
+ return _this._collection$_keys = result;
+ },
+ _collection$_addHashTableEntry$3(table, key, value) {
+ var t1 = this.$ti;
+ t1._precomputed1._as(key);
+ t1._rest[1]._as(value);
+ if (table[key] == null) {
+ ++this._collection$_length;
+ this._collection$_keys = null;
+ }
+ A._HashMap__setTableEntry(table, key, value);
+ },
+ _getBucket$2(table, key) {
+ return table[A.objectHashCode(key) & 1073741823];
+ }
+ };
+ A._IdentityHashMap.prototype = {
+ _findBucketIndex$2(bucket, key) {
+ var $length, i, t1;
+ if (bucket == null)
+ return -1;
+ $length = bucket.length;
+ for (i = 0; i < $length; i += 2) {
+ t1 = bucket[i];
+ if (t1 == null ? key == null : t1 === key)
+ return i;
+ }
+ return -1;
+ }
+ };
+ A._HashMapKeyIterable.prototype = {
+ get$length(_) {
+ return this._collection$_map._collection$_length;
+ },
+ get$isEmpty(_) {
+ return this._collection$_map._collection$_length === 0;
+ },
+ get$iterator(_) {
+ var t1 = this._collection$_map;
+ return new A._HashMapKeyIterator(t1, t1._computeKeys$0(), this.$ti._eval$1("_HashMapKeyIterator<1>"));
+ }
+ };
+ A._HashMapKeyIterator.prototype = {
+ get$current() {
+ var t1 = this._collection$_current;
+ return t1 == null ? this.$ti._precomputed1._as(t1) : t1;
+ },
+ moveNext$0() {
+ var _this = this,
+ keys = _this._collection$_keys,
+ offset = _this._offset,
+ t1 = _this._collection$_map;
+ if (keys !== t1._collection$_keys)
+ throw A.wrapException(A.ConcurrentModificationError$(t1));
+ else if (offset >= keys.length) {
+ _this.set$_collection$_current(null);
+ return false;
+ } else {
+ _this.set$_collection$_current(keys[offset]);
+ _this._offset = offset + 1;
+ return true;
+ }
+ },
+ set$_collection$_current(_current) {
+ this._collection$_current = this.$ti._eval$1("1?")._as(_current);
+ }
+ };
+ A.ListBase.prototype = {
+ get$iterator(receiver) {
+ return new A.ListIterator(receiver, this.get$length(receiver), A.instanceType(receiver)._eval$1("ListIterator<ListBase.E>"));
+ },
+ elementAt$1(receiver, index) {
+ return this.$index(receiver, index);
+ },
+ get$isNotEmpty(receiver) {
+ return this.get$length(receiver) !== 0;
+ },
+ toString$0(receiver) {
+ return A.Iterable_iterableToFullString(receiver, "[", "]");
+ }
+ };
+ A.MapBase.prototype = {
+ forEach$1(_, action) {
+ var t2, key, t3,
+ t1 = A._instanceType(this);
+ t1._eval$1("~(MapBase.K,MapBase.V)")._as(action);
+ for (t2 = this.get$keys(), t2 = t2.get$iterator(t2), t1 = t1._eval$1("MapBase.V"); t2.moveNext$0();) {
+ key = t2.get$current();
+ t3 = this.$index(0, key);
+ action.call$2(key, t3 == null ? t1._as(t3) : t3);
+ }
+ },
+ get$length(_) {
+ var t1 = this.get$keys();
+ return t1.get$length(t1);
+ },
+ get$isEmpty(_) {
+ var t1 = this.get$keys();
+ return t1.get$isEmpty(t1);
+ },
+ toString$0(_) {
+ return A.MapBase_mapToString(this);
+ },
+ $isMap: 1
+ };
+ A.MapBase_mapToString_closure.prototype = {
+ call$2(k, v) {
+ var t2,
+ t1 = this._box_0;
+ if (!t1.first)
+ this.result._contents += ", ";
+ t1.first = false;
+ t1 = this.result;
+ t2 = A.S(k);
+ t2 = t1._contents += t2;
+ t1._contents = t2 + ": ";
+ t2 = A.S(v);
+ t1._contents += t2;
+ },
+ $signature: 10
+ };
+ A._UnmodifiableMapMixin.prototype = {};
+ A.MapView.prototype = {
+ forEach$1(_, action) {
+ this._collection$_map.forEach$1(0, A._instanceType(this)._eval$1("~(1,2)")._as(action));
+ },
+ get$isEmpty(_) {
+ return this._collection$_map.__js_helper$_length === 0;
+ },
+ get$length(_) {
+ return this._collection$_map.__js_helper$_length;
+ },
+ toString$0(_) {
+ return A.MapBase_mapToString(this._collection$_map);
+ },
+ $isMap: 1
+ };
+ A.UnmodifiableMapView.prototype = {};
+ A.ListQueue.prototype = {
+ get$iterator(_) {
+ var _this = this;
+ return new A._ListQueueIterator(_this, _this._tail, _this._modificationCount, _this._head, _this.$ti._eval$1("_ListQueueIterator<1>"));
+ },
+ get$isEmpty(_) {
+ return this._head === this._tail;
+ },
+ get$length(_) {
+ return (this._tail - this._head & this._table.length - 1) >>> 0;
+ },
+ elementAt$1(_, index) {
+ var t2, t3, _this = this,
+ t1 = _this.get$length(0);
+ if (0 > index || index >= t1)
+ A.throwExpression(A.IndexError$withLength(index, t1, _this, null, "index"));
+ t1 = _this._table;
+ t2 = t1.length;
+ t3 = (_this._head + index & t2 - 1) >>> 0;
+ if (!(t3 >= 0 && t3 < t2))
+ return A.ioore(t1, t3);
+ t3 = t1[t3];
+ return t3 == null ? _this.$ti._precomputed1._as(t3) : t3;
+ },
+ toString$0(_) {
+ return A.Iterable_iterableToFullString(this, "{", "}");
+ },
+ removeFirst$0() {
+ var t2, result, _this = this,
+ t1 = _this._head;
+ if (t1 === _this._tail)
+ throw A.wrapException(A.IterableElementError_noElement());
+ ++_this._modificationCount;
+ t2 = _this._table;
+ if (!(t1 < t2.length))
+ return A.ioore(t2, t1);
+ result = t2[t1];
+ if (result == null)
+ result = _this.$ti._precomputed1._as(result);
+ B.JSArray_methods.$indexSet(t2, t1, null);
+ _this._head = (_this._head + 1 & _this._table.length - 1) >>> 0;
+ return result;
+ },
+ _add$1(element) {
+ var t2, t3, newTable, split, _this = this,
+ t1 = _this.$ti;
+ t1._precomputed1._as(element);
+ B.JSArray_methods.$indexSet(_this._table, _this._tail, element);
+ t2 = _this._tail;
+ t3 = _this._table.length;
+ t2 = (t2 + 1 & t3 - 1) >>> 0;
+ _this._tail = t2;
+ if (_this._head === t2) {
+ newTable = A.List_List$filled(t3 * 2, null, false, t1._eval$1("1?"));
+ t1 = _this._table;
+ t2 = _this._head;
+ split = t1.length - t2;
+ B.JSArray_methods.setRange$4(newTable, 0, split, t1, t2);
+ B.JSArray_methods.setRange$4(newTable, split, split + _this._head, _this._table, 0);
+ _this._head = 0;
+ _this._tail = _this._table.length;
+ _this.set$_table(newTable);
+ }
+ ++_this._modificationCount;
+ },
+ set$_table(_table) {
+ this._table = this.$ti._eval$1("List<1?>")._as(_table);
+ },
+ $isQueue: 1
+ };
+ A._ListQueueIterator.prototype = {
+ get$current() {
+ var t1 = this._collection$_current;
+ return t1 == null ? this.$ti._precomputed1._as(t1) : t1;
+ },
+ moveNext$0() {
+ var t2, t3, _this = this,
+ t1 = _this._queue;
+ if (_this._modificationCount !== t1._modificationCount)
+ A.throwExpression(A.ConcurrentModificationError$(t1));
+ t2 = _this._position;
+ if (t2 === _this._end) {
+ _this.set$_collection$_current(null);
+ return false;
+ }
+ t3 = t1._table;
+ if (!(t2 < t3.length))
+ return A.ioore(t3, t2);
+ _this.set$_collection$_current(t3[t2]);
+ _this._position = (_this._position + 1 & t1._table.length - 1) >>> 0;
+ return true;
+ },
+ set$_collection$_current(_current) {
+ this._collection$_current = this.$ti._eval$1("1?")._as(_current);
+ }
+ };
+ A._UnmodifiableMapView_MapView__UnmodifiableMapMixin.prototype = {};
+ A._JsonMap.prototype = {
+ $index(_, key) {
+ var result,
+ t1 = this._processed;
+ if (t1 == null)
+ return this._data.$index(0, key);
+ else if (typeof key != "string")
+ return null;
+ else {
+ result = t1[key];
+ return typeof result == "undefined" ? this._process$1(key) : result;
+ }
+ },
+ get$length(_) {
+ return this._processed == null ? this._data.__js_helper$_length : this._convert$_computeKeys$0().length;
+ },
+ get$isEmpty(_) {
+ return this.get$length(0) === 0;
+ },
+ get$keys() {
+ if (this._processed == null) {
+ var t1 = this._data;
+ return new A.LinkedHashMapKeyIterable(t1, A._instanceType(t1)._eval$1("LinkedHashMapKeyIterable<1>"));
+ }
+ return new A._JsonMapKeyIterable(this);
+ },
+ forEach$1(_, f) {
+ var keys, i, key, value, _this = this;
+ type$.void_Function_String_dynamic._as(f);
+ if (_this._processed == null)
+ return _this._data.forEach$1(0, f);
+ keys = _this._convert$_computeKeys$0();
+ for (i = 0; i < keys.length; ++i) {
+ key = keys[i];
+ value = _this._processed[key];
+ if (typeof value == "undefined") {
+ value = A._convertJsonToDartLazy(_this._original[key]);
+ _this._processed[key] = value;
+ }
+ f.call$2(key, value);
+ if (keys !== _this._data)
+ throw A.wrapException(A.ConcurrentModificationError$(_this));
+ }
+ },
+ _convert$_computeKeys$0() {
+ var keys = type$.nullable_List_dynamic._as(this._data);
+ if (keys == null)
+ keys = this._data = A._setArrayType(Object.keys(this._original), type$.JSArray_String);
+ return keys;
+ },
+ _process$1(key) {
+ var result;
+ if (!Object.prototype.hasOwnProperty.call(this._original, key))
+ return null;
+ result = A._convertJsonToDartLazy(this._original[key]);
+ return this._processed[key] = result;
+ }
+ };
+ A._JsonMapKeyIterable.prototype = {
+ get$length(_) {
+ return this._parent.get$length(0);
+ },
+ elementAt$1(_, index) {
+ var t1 = this._parent;
+ if (t1._processed == null)
+ t1 = t1.get$keys().elementAt$1(0, index);
+ else {
+ t1 = t1._convert$_computeKeys$0();
+ if (!(index >= 0 && index < t1.length))
+ return A.ioore(t1, index);
+ t1 = t1[index];
+ }
+ return t1;
+ },
+ get$iterator(_) {
+ var t1 = this._parent;
+ if (t1._processed == null) {
+ t1 = t1.get$keys();
+ t1 = t1.get$iterator(t1);
+ } else {
+ t1 = t1._convert$_computeKeys$0();
+ t1 = new J.ArrayIterator(t1, t1.length, A._arrayInstanceType(t1)._eval$1("ArrayIterator<1>"));
+ }
+ return t1;
+ }
+ };
+ A.Codec.prototype = {};
+ A.Converter.prototype = {};
+ A.JsonUnsupportedObjectError.prototype = {
+ toString$0(_) {
+ var safeString = A.Error_safeToString(this.unsupportedObject);
+ return (this.cause != null ? "Converting object to an encodable object failed:" : "Converting object did not return an encodable object:") + " " + safeString;
+ }
+ };
+ A.JsonCyclicError.prototype = {
+ toString$0(_) {
+ return "Cyclic error in JSON stringify";
+ }
+ };
+ A.JsonCodec.prototype = {
+ decode$2$reviver(source, reviver) {
+ var t1 = A._parseJson(source, this.get$decoder()._reviver);
+ return t1;
+ },
+ encode$2$toEncodable(value, toEncodable) {
+ var t1 = A._JsonStringStringifier_stringify(value, this.get$encoder()._toEncodable, null);
+ return t1;
+ },
+ get$encoder() {
+ return B.JsonEncoder_null;
+ },
+ get$decoder() {
+ return B.JsonDecoder_null;
+ }
+ };
+ A.JsonEncoder.prototype = {};
+ A.JsonDecoder.prototype = {};
+ A._JsonStringifier.prototype = {
+ writeStringContent$1(s) {
+ var offset, i, charCode, t1, t2, _this = this,
+ $length = s.length;
+ for (offset = 0, i = 0; i < $length; ++i) {
+ charCode = s.charCodeAt(i);
+ if (charCode > 92) {
+ if (charCode >= 55296) {
+ t1 = charCode & 64512;
+ if (t1 === 55296) {
+ t2 = i + 1;
+ t2 = !(t2 < $length && (s.charCodeAt(t2) & 64512) === 56320);
+ } else
+ t2 = false;
+ if (!t2)
+ if (t1 === 56320) {
+ t1 = i - 1;
+ t1 = !(t1 >= 0 && (s.charCodeAt(t1) & 64512) === 55296);
+ } else
+ t1 = false;
+ else
+ t1 = true;
+ if (t1) {
+ if (i > offset)
+ _this.writeStringSlice$3(s, offset, i);
+ offset = i + 1;
+ _this.writeCharCode$1(92);
+ _this.writeCharCode$1(117);
+ _this.writeCharCode$1(100);
+ t1 = charCode >>> 8 & 15;
+ _this.writeCharCode$1(t1 < 10 ? 48 + t1 : 87 + t1);
+ t1 = charCode >>> 4 & 15;
+ _this.writeCharCode$1(t1 < 10 ? 48 + t1 : 87 + t1);
+ t1 = charCode & 15;
+ _this.writeCharCode$1(t1 < 10 ? 48 + t1 : 87 + t1);
+ }
+ }
+ continue;
+ }
+ if (charCode < 32) {
+ if (i > offset)
+ _this.writeStringSlice$3(s, offset, i);
+ offset = i + 1;
+ _this.writeCharCode$1(92);
+ switch (charCode) {
+ case 8:
+ _this.writeCharCode$1(98);
+ break;
+ case 9:
+ _this.writeCharCode$1(116);
+ break;
+ case 10:
+ _this.writeCharCode$1(110);
+ break;
+ case 12:
+ _this.writeCharCode$1(102);
+ break;
+ case 13:
+ _this.writeCharCode$1(114);
+ break;
+ default:
+ _this.writeCharCode$1(117);
+ _this.writeCharCode$1(48);
+ _this.writeCharCode$1(48);
+ t1 = charCode >>> 4 & 15;
+ _this.writeCharCode$1(t1 < 10 ? 48 + t1 : 87 + t1);
+ t1 = charCode & 15;
+ _this.writeCharCode$1(t1 < 10 ? 48 + t1 : 87 + t1);
+ break;
+ }
+ } else if (charCode === 34 || charCode === 92) {
+ if (i > offset)
+ _this.writeStringSlice$3(s, offset, i);
+ offset = i + 1;
+ _this.writeCharCode$1(92);
+ _this.writeCharCode$1(charCode);
+ }
+ }
+ if (offset === 0)
+ _this.writeString$1(s);
+ else if (offset < $length)
+ _this.writeStringSlice$3(s, offset, $length);
+ },
+ _checkCycle$1(object) {
+ var t1, t2, i, t3;
+ for (t1 = this._seen, t2 = t1.length, i = 0; i < t2; ++i) {
+ t3 = t1[i];
+ if (object == null ? t3 == null : object === t3)
+ throw A.wrapException(new A.JsonCyclicError(object, null));
+ }
+ B.JSArray_methods.add$1(t1, object);
+ },
+ writeObject$1(object) {
+ var customJson, e, t1, exception, _this = this;
+ if (_this.writeJsonValue$1(object))
+ return;
+ _this._checkCycle$1(object);
+ try {
+ customJson = _this._toEncodable.call$1(object);
+ if (!_this.writeJsonValue$1(customJson)) {
+ t1 = A.JsonUnsupportedObjectError$(object, null, _this.get$_partialResult());
+ throw A.wrapException(t1);
+ }
+ t1 = _this._seen;
+ if (0 >= t1.length)
+ return A.ioore(t1, -1);
+ t1.pop();
+ } catch (exception) {
+ e = A.unwrapException(exception);
+ t1 = A.JsonUnsupportedObjectError$(object, e, _this.get$_partialResult());
+ throw A.wrapException(t1);
+ }
+ },
+ writeJsonValue$1(object) {
+ var t1, success, _this = this;
+ if (typeof object == "number") {
+ if (!isFinite(object))
+ return false;
+ _this.writeNumber$1(object);
+ return true;
+ } else if (object === true) {
+ _this.writeString$1("true");
+ return true;
+ } else if (object === false) {
+ _this.writeString$1("false");
+ return true;
+ } else if (object == null) {
+ _this.writeString$1("null");
+ return true;
+ } else if (typeof object == "string") {
+ _this.writeString$1('"');
+ _this.writeStringContent$1(object);
+ _this.writeString$1('"');
+ return true;
+ } else if (type$.List_dynamic._is(object)) {
+ _this._checkCycle$1(object);
+ _this.writeList$1(object);
+ t1 = _this._seen;
+ if (0 >= t1.length)
+ return A.ioore(t1, -1);
+ t1.pop();
+ return true;
+ } else if (type$.Map_dynamic_dynamic._is(object)) {
+ _this._checkCycle$1(object);
+ success = _this.writeMap$1(object);
+ t1 = _this._seen;
+ if (0 >= t1.length)
+ return A.ioore(t1, -1);
+ t1.pop();
+ return success;
+ } else
+ return false;
+ },
+ writeList$1(list) {
+ var t1, i, _this = this;
+ _this.writeString$1("[");
+ t1 = J.getInterceptor$asx(list);
+ if (t1.get$isNotEmpty(list)) {
+ _this.writeObject$1(t1.$index(list, 0));
+ for (i = 1; i < t1.get$length(list); ++i) {
+ _this.writeString$1(",");
+ _this.writeObject$1(t1.$index(list, i));
+ }
+ }
+ _this.writeString$1("]");
+ },
+ writeMap$1(map) {
+ var t1, keyValueList, i, separator, t2, _this = this, _box_0 = {};
+ if (map.get$isEmpty(map)) {
+ _this.writeString$1("{}");
+ return true;
+ }
+ t1 = map.get$length(map) * 2;
+ keyValueList = A.List_List$filled(t1, null, false, type$.nullable_Object);
+ i = _box_0.i = 0;
+ _box_0.allStringKeys = true;
+ map.forEach$1(0, new A._JsonStringifier_writeMap_closure(_box_0, keyValueList));
+ if (!_box_0.allStringKeys)
+ return false;
+ _this.writeString$1("{");
+ for (separator = '"'; i < t1; i += 2, separator = ',"') {
+ _this.writeString$1(separator);
+ _this.writeStringContent$1(A._asString(keyValueList[i]));
+ _this.writeString$1('":');
+ t2 = i + 1;
+ if (!(t2 < t1))
+ return A.ioore(keyValueList, t2);
+ _this.writeObject$1(keyValueList[t2]);
+ }
+ _this.writeString$1("}");
+ return true;
+ }
+ };
+ A._JsonStringifier_writeMap_closure.prototype = {
+ call$2(key, value) {
+ var t1, t2;
+ if (typeof key != "string")
+ this._box_0.allStringKeys = false;
+ t1 = this.keyValueList;
+ t2 = this._box_0;
+ B.JSArray_methods.$indexSet(t1, t2.i++, key);
+ B.JSArray_methods.$indexSet(t1, t2.i++, value);
+ },
+ $signature: 10
+ };
+ A._JsonStringStringifier.prototype = {
+ get$_partialResult() {
+ var t1 = this._sink._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ writeNumber$1(number) {
+ var t1 = this._sink,
+ t2 = B.JSNumber_methods.toString$0(number);
+ t1._contents += t2;
+ },
+ writeString$1(string) {
+ this._sink._contents += string;
+ },
+ writeStringSlice$3(string, start, end) {
+ this._sink._contents += B.JSString_methods.substring$2(string, start, end);
+ },
+ writeCharCode$1(charCode) {
+ var t1 = this._sink,
+ t2 = A.Primitives_stringFromCharCode(charCode);
+ t1._contents += t2;
+ }
+ };
+ A.NoSuchMethodError_toString_closure.prototype = {
+ call$2(key, value) {
+ var t1, t2, t3;
+ type$.Symbol._as(key);
+ t1 = this.sb;
+ t2 = this._box_0;
+ t3 = t1._contents += t2.comma;
+ t3 += key._name;
+ t1._contents = t3;
+ t1._contents = t3 + ": ";
+ t3 = A.Error_safeToString(value);
+ t1._contents += t3;
+ t2.comma = ", ";
+ },
+ $signature: 19
+ };
+ A.DateTime.prototype = {
+ $eq(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof A.DateTime && this._value === other._value && this.isUtc === other.isUtc;
+ },
+ get$hashCode(_) {
+ var t1 = this._value;
+ return (t1 ^ B.JSInt_methods._shrOtherPositive$1(t1, 30)) & 1073741823;
+ },
+ toString$0(_) {
+ var _this = this,
+ y = A.DateTime__fourDigits(A.Primitives_getYear(_this)),
+ m = A.DateTime__twoDigits(A.Primitives_getMonth(_this)),
+ d = A.DateTime__twoDigits(A.Primitives_getDay(_this)),
+ h = A.DateTime__twoDigits(A.Primitives_getHours(_this)),
+ min = A.DateTime__twoDigits(A.Primitives_getMinutes(_this)),
+ sec = A.DateTime__twoDigits(A.Primitives_getSeconds(_this)),
+ ms = A.DateTime__threeDigits(A.Primitives_getMilliseconds(_this)),
+ t1 = y + "-" + m;
+ if (_this.isUtc)
+ return t1 + "-" + d + " " + h + ":" + min + ":" + sec + "." + ms + "Z";
+ else
+ return t1 + "-" + d + " " + h + ":" + min + ":" + sec + "." + ms;
+ }
+ };
+ A.Duration.prototype = {
+ $eq(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof A.Duration && this._duration === other._duration;
+ },
+ get$hashCode(_) {
+ return B.JSInt_methods.get$hashCode(this._duration);
+ },
+ toString$0(_) {
+ var minutesPadding, seconds, secondsPadding,
+ microseconds = this._duration,
+ microseconds0 = microseconds % 3600000000,
+ minutes = B.JSInt_methods._tdivFast$1(microseconds0, 60000000);
+ microseconds0 %= 60000000;
+ minutesPadding = minutes < 10 ? "0" : "";
+ seconds = B.JSInt_methods._tdivFast$1(microseconds0, 1000000);
+ secondsPadding = seconds < 10 ? "0" : "";
+ return "" + (microseconds / 3600000000 | 0) + ":" + minutesPadding + minutes + ":" + secondsPadding + seconds + "." + B.JSString_methods.padLeft$2(B.JSInt_methods.toString$0(microseconds0 % 1000000), 6, "0");
+ }
+ };
+ A.Error.prototype = {
+ get$stackTrace() {
+ return A.getTraceFromException(this.$thrownJsError);
+ }
+ };
+ A.AssertionError.prototype = {
+ toString$0(_) {
+ var t1 = this.message;
+ if (t1 != null)
+ return "Assertion failed: " + A.Error_safeToString(t1);
+ return "Assertion failed";
+ }
+ };
+ A.TypeError.prototype = {};
+ A.ArgumentError.prototype = {
+ get$_errorName() {
+ return "Invalid argument" + (!this._hasValue ? "(s)" : "");
+ },
+ get$_errorExplanation() {
+ return "";
+ },
+ toString$0(_) {
+ var _this = this,
+ $name = _this.name,
+ nameString = $name == null ? "" : " (" + $name + ")",
+ message = _this.message,
+ messageString = message == null ? "" : ": " + A.S(message),
+ prefix = _this.get$_errorName() + nameString + messageString;
+ if (!_this._hasValue)
+ return prefix;
+ return prefix + _this.get$_errorExplanation() + ": " + A.Error_safeToString(_this.get$invalidValue());
+ },
+ get$invalidValue() {
+ return this.invalidValue;
+ }
+ };
+ A.RangeError.prototype = {
+ get$invalidValue() {
+ return A._asNumQ(this.invalidValue);
+ },
+ get$_errorName() {
+ return "RangeError";
+ },
+ get$_errorExplanation() {
+ var explanation,
+ start = this.start,
+ end = this.end;
+ if (start == null)
+ explanation = end != null ? ": Not less than or equal to " + A.S(end) : "";
+ else if (end == null)
+ explanation = ": Not greater than or equal to " + A.S(start);
+ else if (end > start)
+ explanation = ": Not in inclusive range " + A.S(start) + ".." + A.S(end);
+ else
+ explanation = end < start ? ": Valid value range is empty" : ": Only valid value is " + A.S(start);
+ return explanation;
+ }
+ };
+ A.IndexError.prototype = {
+ get$invalidValue() {
+ return A._asInt(this.invalidValue);
+ },
+ get$_errorName() {
+ return "RangeError";
+ },
+ get$_errorExplanation() {
+ if (A._asInt(this.invalidValue) < 0)
+ return ": index must not be negative";
+ var t1 = this.length;
+ if (t1 === 0)
+ return ": no indices are valid";
+ return ": index should be less than " + t1;
+ },
+ get$length(receiver) {
+ return this.length;
+ }
+ };
+ A.NoSuchMethodError.prototype = {
+ toString$0(_) {
+ var $arguments, t1, _i, t2, t3, argument, receiverText, actualParameters, _this = this, _box_0 = {},
+ sb = new A.StringBuffer("");
+ _box_0.comma = "";
+ $arguments = _this._core$_arguments;
+ for (t1 = $arguments.length, _i = 0, t2 = "", t3 = ""; _i < t1; ++_i, t3 = ", ") {
+ argument = $arguments[_i];
+ sb._contents = t2 + t3;
+ t2 = A.Error_safeToString(argument);
+ t2 = sb._contents += t2;
+ _box_0.comma = ", ";
+ }
+ _this._namedArguments.forEach$1(0, new A.NoSuchMethodError_toString_closure(_box_0, sb));
+ receiverText = A.Error_safeToString(_this._core$_receiver);
+ actualParameters = sb.toString$0(0);
+ return "NoSuchMethodError: method not found: '" + _this._core$_memberName._name + "'\nReceiver: " + receiverText + "\nArguments: [" + actualParameters + "]";
+ }
+ };
+ A.UnsupportedError.prototype = {
+ toString$0(_) {
+ return "Unsupported operation: " + this.message;
+ }
+ };
+ A.UnimplementedError.prototype = {
+ toString$0(_) {
+ return "UnimplementedError: " + this.message;
+ }
+ };
+ A.StateError.prototype = {
+ toString$0(_) {
+ return "Bad state: " + this.message;
+ }
+ };
+ A.ConcurrentModificationError.prototype = {
+ toString$0(_) {
+ var t1 = this.modifiedObject;
+ if (t1 == null)
+ return "Concurrent modification during iteration.";
+ return "Concurrent modification during iteration: " + A.Error_safeToString(t1) + ".";
+ }
+ };
+ A.OutOfMemoryError.prototype = {
+ toString$0(_) {
+ return "Out of Memory";
+ },
+ get$stackTrace() {
+ return null;
+ },
+ $isError: 1
+ };
+ A.StackOverflowError.prototype = {
+ toString$0(_) {
+ return "Stack Overflow";
+ },
+ get$stackTrace() {
+ return null;
+ },
+ $isError: 1
+ };
+ A._Exception.prototype = {
+ toString$0(_) {
+ return "Exception: " + this.message;
+ }
+ };
+ A.FormatException.prototype = {
+ toString$0(_) {
+ var t1, lineEnd, lineNum, lineStart, previousCharWasCR, i, char, end, start, prefix, postfix,
+ message = this.message,
+ report = "" !== message ? "FormatException: " + message : "FormatException",
+ offset = this.offset,
+ source = this.source;
+ if (typeof source == "string") {
+ if (offset != null)
+ t1 = offset < 0 || offset > source.length;
+ else
+ t1 = false;
+ if (t1)
+ offset = null;
+ if (offset == null) {
+ if (source.length > 78)
+ source = B.JSString_methods.substring$2(source, 0, 75) + "...";
+ return report + "\n" + source;
+ }
+ for (lineEnd = source.length, lineNum = 1, lineStart = 0, previousCharWasCR = false, i = 0; i < offset; ++i) {
+ if (!(i < lineEnd))
+ return A.ioore(source, i);
+ char = source.charCodeAt(i);
+ if (char === 10) {
+ if (lineStart !== i || !previousCharWasCR)
+ ++lineNum;
+ lineStart = i + 1;
+ previousCharWasCR = false;
+ } else if (char === 13) {
+ ++lineNum;
+ lineStart = i + 1;
+ previousCharWasCR = true;
+ }
+ }
+ report = lineNum > 1 ? report + (" (at line " + lineNum + ", character " + (offset - lineStart + 1) + ")\n") : report + (" (at character " + (offset + 1) + ")\n");
+ for (i = offset; i < lineEnd; ++i) {
+ if (!(i >= 0))
+ return A.ioore(source, i);
+ char = source.charCodeAt(i);
+ if (char === 10 || char === 13) {
+ lineEnd = i;
+ break;
+ }
+ }
+ if (lineEnd - lineStart > 78)
+ if (offset - lineStart < 75) {
+ end = lineStart + 75;
+ start = lineStart;
+ prefix = "";
+ postfix = "...";
+ } else {
+ if (lineEnd - offset < 75) {
+ start = lineEnd - 75;
+ end = lineEnd;
+ postfix = "";
+ } else {
+ start = offset - 36;
+ end = offset + 36;
+ postfix = "...";
+ }
+ prefix = "...";
+ }
+ else {
+ end = lineEnd;
+ start = lineStart;
+ prefix = "";
+ postfix = "";
+ }
+ return report + prefix + B.JSString_methods.substring$2(source, start, end) + postfix + "\n" + B.JSString_methods.$mul(" ", offset - start + prefix.length) + "^\n";
+ } else
+ return offset != null ? report + (" (at offset " + A.S(offset) + ")") : report;
+ }
+ };
+ A.Iterable.prototype = {
+ get$length(_) {
+ var count,
+ it = this.get$iterator(this);
+ for (count = 0; it.moveNext$0();)
+ ++count;
+ return count;
+ },
+ elementAt$1(_, index) {
+ var iterator, skipCount;
+ A.RangeError_checkNotNegative(index, "index");
+ iterator = this.get$iterator(this);
+ for (skipCount = index; iterator.moveNext$0();) {
+ if (skipCount === 0)
+ return iterator.get$current();
+ --skipCount;
+ }
+ throw A.wrapException(A.IndexError$withLength(index, index - skipCount, this, null, "index"));
+ },
+ toString$0(_) {
+ return A.Iterable_iterableToShortString(this, "(", ")");
+ }
+ };
+ A.Null.prototype = {
+ get$hashCode(_) {
+ return A.Object.prototype.get$hashCode.call(this, 0);
+ },
+ toString$0(_) {
+ return "null";
+ }
+ };
+ A.Object.prototype = {$isObject: 1,
+ $eq(_, other) {
+ return this === other;
+ },
+ get$hashCode(_) {
+ return A.Primitives_objectHashCode(this);
+ },
+ toString$0(_) {
+ return "Instance of '" + A.Primitives_objectTypeName(this) + "'";
+ },
+ noSuchMethod$1(_, invocation) {
+ throw A.wrapException(A.NoSuchMethodError_NoSuchMethodError$withInvocation(this, type$.Invocation._as(invocation)));
+ },
+ get$runtimeType(_) {
+ return A.getRuntimeTypeOfDartObject(this);
+ },
+ toString() {
+ return this.toString$0(this);
+ }
+ };
+ A._StringStackTrace.prototype = {
+ toString$0(_) {
+ return this._stackTrace;
+ },
+ $isStackTrace: 1
+ };
+ A.StringBuffer.prototype = {
+ get$length(_) {
+ return this._contents.length;
+ },
+ toString$0(_) {
+ var t1 = this._contents;
+ return t1.charCodeAt(0) == 0 ? t1 : t1;
+ },
+ $isStringSink: 1
+ };
+ A.promiseToFuture_closure.prototype = {
+ call$1(r) {
+ return this.completer.complete$1(this.T._eval$1("0/?")._as(r));
+ },
+ $signature: 3
+ };
+ A.promiseToFuture_closure0.prototype = {
+ call$1(e) {
+ if (e == null)
+ return this.completer.completeError$1(new A.NullRejectionException(e === undefined));
+ return this.completer.completeError$1(e);
+ },
+ $signature: 3
+ };
+ A.dartify_convert.prototype = {
+ call$1(o) {
+ var t1, millisSinceEpoch, proto, t2, dartObject, originalKeys, dartKeys, i, jsKey, dartKey, l, $length;
+ if (A._noDartifyRequired(o))
+ return o;
+ t1 = this._convertedObjects;
+ o.toString;
+ if (t1.containsKey$1(o))
+ return t1.$index(0, o);
+ if (o instanceof Date) {
+ millisSinceEpoch = o.getTime();
+ if (Math.abs(millisSinceEpoch) > 864e13)
+ A.throwExpression(A.ArgumentError$("DateTime is outside valid range: " + millisSinceEpoch, null));
+ A.checkNotNullable(true, "isUtc", type$.bool);
+ return new A.DateTime(millisSinceEpoch, true);
+ }
+ if (o instanceof RegExp)
+ throw A.wrapException(A.ArgumentError$("structured clone of RegExp", null));
+ if (typeof Promise != "undefined" && o instanceof Promise)
+ return A.promiseToFuture(o, type$.nullable_Object);
+ proto = Object.getPrototypeOf(o);
+ if (proto === Object.prototype || proto === null) {
+ t2 = type$.nullable_Object;
+ dartObject = A.LinkedHashMap_LinkedHashMap$_empty(t2, t2);
+ t1.$indexSet(0, o, dartObject);
+ originalKeys = Object.keys(o);
+ dartKeys = [];
+ for (t1 = J.getInterceptor$ax(originalKeys), t2 = t1.get$iterator(originalKeys); t2.moveNext$0();)
+ dartKeys.push(A.dartify(t2.get$current()));
+ for (i = 0; i < t1.get$length(originalKeys); ++i) {
+ jsKey = t1.$index(originalKeys, i);
+ if (!(i < dartKeys.length))
+ return A.ioore(dartKeys, i);
+ dartKey = dartKeys[i];
+ if (jsKey != null)
+ dartObject.$indexSet(0, dartKey, this.call$1(o[jsKey]));
+ }
+ return dartObject;
+ }
+ if (o instanceof Array) {
+ l = o;
+ dartObject = [];
+ t1.$indexSet(0, o, dartObject);
+ $length = A._asInt(o.length);
+ for (t1 = J.getInterceptor$asx(l), i = 0; i < $length; ++i)
+ dartObject.push(this.call$1(t1.$index(l, i)));
+ return dartObject;
+ }
+ return o;
+ },
+ $signature: 20
+ };
+ A.NullRejectionException.prototype = {
+ toString$0(_) {
+ return "Promise was rejected with a value of `" + (this.isUndefined ? "undefined" : "null") + "`.";
+ }
+ };
+ A._JSRandom.prototype = {
+ nextInt$1(max) {
+ if (max <= 0 || max > 4294967296)
+ throw A.wrapException(A.RangeError$("max must be in range 0 < max \u2264 2^32, was " + max));
+ return Math.random() * max >>> 0;
+ }
+ };
+ A.AsyncMemoizer.prototype = {};
+ A.Level.prototype = {
+ $eq(_, other) {
+ if (other == null)
+ return false;
+ return other instanceof A.Level && this.value === other.value;
+ },
+ get$hashCode(_) {
+ return this.value;
+ },
+ toString$0(_) {
+ return this.name;
+ }
+ };
+ A.LogRecord.prototype = {
+ toString$0(_) {
+ return "[" + this.level.name + "] " + this.loggerName + ": " + this.message;
+ }
+ };
+ A.Logger.prototype = {
+ get$fullName() {
+ var t1 = this.parent,
+ t2 = t1 == null ? null : t1.name.length !== 0,
+ t3 = this.name;
+ return t2 === true ? t1.get$fullName() + "." + t3 : t3;
+ },
+ get$level() {
+ var t1, effectiveLevel;
+ if (this.parent == null) {
+ t1 = this._level;
+ t1.toString;
+ effectiveLevel = t1;
+ } else {
+ t1 = $.$get$Logger_root()._level;
+ t1.toString;
+ effectiveLevel = t1;
+ }
+ return effectiveLevel;
+ },
+ log$4(logLevel, message, error, stackTrace) {
+ var record, _this = this,
+ t1 = logLevel.value;
+ if (t1 >= _this.get$level().value) {
+ if (t1 >= 2000) {
+ A.StackTrace_current();
+ logLevel.toString$0(0);
+ }
+ t1 = _this.get$fullName();
+ Date.now();
+ $.LogRecord__nextNumber = $.LogRecord__nextNumber + 1;
+ record = new A.LogRecord(logLevel, message, t1);
+ if (_this.parent == null)
+ _this._publish$1(record);
+ else
+ $.$get$Logger_root()._publish$1(record);
+ }
+ },
+ _publish$1(record) {
+ return null;
+ }
+ };
+ A.Logger_Logger_closure.prototype = {
+ call$0() {
+ var dot, $parent, t1,
+ thisName = this.name;
+ if (B.JSString_methods.startsWith$1(thisName, "."))
+ A.throwExpression(A.ArgumentError$("name shouldn't start with a '.'", null));
+ if (B.JSString_methods.endsWith$1(thisName, "."))
+ A.throwExpression(A.ArgumentError$("name shouldn't end with a '.'", null));
+ dot = B.JSString_methods.lastIndexOf$1(thisName, ".");
+ if (dot === -1)
+ $parent = thisName !== "" ? A.Logger_Logger("") : null;
+ else {
+ $parent = A.Logger_Logger(B.JSString_methods.substring$2(thisName, 0, dot));
+ thisName = B.JSString_methods.substring$1(thisName, dot + 1);
+ }
+ t1 = new A.Logger(thisName, $parent, A.LinkedHashMap_LinkedHashMap$_empty(type$.String, type$.Logger));
+ if ($parent == null)
+ t1._level = B.Level_INFO_800;
+ else
+ $parent._children.$indexSet(0, thisName, t1);
+ return t1;
+ },
+ $signature: 21
+ };
+ A.Pool.prototype = {
+ request$0() {
+ var t1, t2, _this = this;
+ if ((_this._closeMemo._completer.future._state & 30) !== 0)
+ throw A.wrapException(A.StateError$("request() may not be called on a closed Pool."));
+ t1 = _this._allocatedResources;
+ if (t1 < _this._maxAllocatedResources) {
+ _this._allocatedResources = t1 + 1;
+ return A.Future_Future$value(new A.PoolResource(_this), type$.PoolResource);
+ } else {
+ t1 = _this._onReleaseCallbacks;
+ if (!t1.get$isEmpty(0))
+ return _this._runOnRelease$1(t1.removeFirst$0());
+ else {
+ t1 = new A._Future($.Zone__current, type$._Future_PoolResource);
+ t2 = _this._requestedResources;
+ t2._add$1(t2.$ti._precomputed1._as(new A._AsyncCompleter(t1, type$._AsyncCompleter_PoolResource)));
+ _this._resetTimer$0();
+ return t1;
+ }
+ }
+ },
+ withResource$1$1(callback, $T) {
+ return this.withResource$body$Pool($T._eval$1("0/()")._as(callback), $T, $T);
+ },
+ withResource$body$Pool(callback, $T, $async$type) {
+ var $async$goto = 0,
+ $async$completer = A._makeAsyncAwaitCompleter($async$type),
+ $async$returnValue, $async$handler = 2, $async$currentError, $async$next = [], $async$self = this, resource, t1, t2;
+ var $async$withResource$1$1 = A._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1) {
+ $async$currentError = $async$result;
+ $async$goto = $async$handler;
+ }
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ if (($async$self._closeMemo._completer.future._state & 30) !== 0)
+ throw A.wrapException(A.StateError$("withResource() may not be called on a closed Pool."));
+ $async$goto = 3;
+ return A._asyncAwait($async$self.request$0(), $async$withResource$1$1);
+ case 3:
+ // returning from await.
+ resource = $async$result;
+ $async$handler = 4;
+ t1 = callback.call$0();
+ $async$goto = 7;
+ return A._asyncAwait($T._eval$1("Future<0>")._is(t1) ? t1 : A._Future$value($T._as(t1), $T), $async$withResource$1$1);
+ case 7:
+ // returning from await.
+ t1 = $async$result;
+ $async$returnValue = t1;
+ $async$next = [1];
+ // goto finally
+ $async$goto = 5;
+ break;
+ $async$next.push(6);
+ // goto finally
+ $async$goto = 5;
+ break;
+ case 4:
+ // uncaught
+ $async$next = [2];
+ case 5:
+ // finally
+ $async$handler = 2;
+ t1 = resource;
+ if (t1._released)
+ A.throwExpression(A.StateError$("A PoolResource may only be released once."));
+ t1._released = true;
+ t1 = t1._pool;
+ t1._resetTimer$0();
+ t2 = t1._requestedResources;
+ if (!t2.get$isEmpty(0))
+ t2.removeFirst$0().complete$1(new A.PoolResource(t1));
+ else {
+ t2 = --t1._allocatedResources;
+ if ((t1._closeMemo._completer.future._state & 30) !== 0 && t2 === 0)
+ null.close$0();
+ }
+ // goto the next finally handler
+ $async$goto = $async$next.pop();
+ break;
+ case 6:
+ // after finally
+ case 1:
+ // return
+ return A._asyncReturn($async$returnValue, $async$completer);
+ case 2:
+ // rethrow
+ return A._asyncRethrow($async$currentError, $async$completer);
+ }
+ });
+ return A._asyncStartSync($async$withResource$1$1, $async$completer);
+ },
+ _runOnRelease$1(onRelease) {
+ var t1 = A.Future_Future$sync(type$.dynamic_Function._as(onRelease), type$.dynamic).then$1$1(new A.Pool__runOnRelease_closure(this), type$.Null),
+ onError = new A.Pool__runOnRelease_closure0(this),
+ t2 = t1.$ti,
+ t3 = $.Zone__current;
+ if (t3 !== B.C__RootZone)
+ onError = A._registerErrorHandler(onError, t3);
+ t1._addListener$1(new A._FutureListener(new A._Future(t3, t2), 2, null, onError, t2._eval$1("@<1>")._bind$1(t2._precomputed1)._eval$1("_FutureListener<1,2>")));
+ t1 = new A._Future($.Zone__current, type$._Future_PoolResource);
+ t2 = this._onReleaseCompleters;
+ t2._add$1(t2.$ti._precomputed1._as(new A._SyncCompleter(t1, type$._SyncCompleter_PoolResource)));
+ return t1;
+ },
+ _resetTimer$0() {
+ var t2,
+ t1 = this._timer;
+ if (t1 == null)
+ return;
+ t2 = this._requestedResources;
+ if (t2._head === t2._tail)
+ t1._restartable_timer$_timer.cancel$0();
+ else {
+ t1._restartable_timer$_timer.cancel$0();
+ t1._restartable_timer$_timer = A.Timer_Timer(t1._restartable_timer$_duration, t1._callback);
+ }
+ }
+ };
+ A.Pool__runOnRelease_closure.prototype = {
+ call$1(value) {
+ var t1 = this.$this;
+ t1._onReleaseCompleters.removeFirst$0().complete$1(new A.PoolResource(t1));
+ },
+ $signature: 4
+ };
+ A.Pool__runOnRelease_closure0.prototype = {
+ call$2(error, stackTrace) {
+ type$.Object._as(error);
+ type$.StackTrace._as(stackTrace);
+ this.$this._onReleaseCompleters.removeFirst$0().completeError$2(error, stackTrace);
+ },
+ $signature: 5
+ };
+ A.PoolResource.prototype = {};
+ A.SseClient.prototype = {
+ SseClient$2$debugKey(serverUrl, debugKey) {
+ var t2, t3, _this = this,
+ t1 = serverUrl + "?sseClientId=" + _this._clientId;
+ _this.__SseClient__serverUrl_A = t1;
+ t2 = type$.JSObject;
+ t1 = t2._as(new self.EventSource(t1, {withCredentials: true}));
+ _this.__SseClient__eventSource_A = t1;
+ new A._EventStream(t1, "open", false, type$._EventStream_JSObject).get$first(0).whenComplete$1(new A.SseClient_closure(_this));
+ t1 = type$.Function;
+ t3 = type$.JavaScriptFunction;
+ _this.__SseClient__eventSource_A.addEventListener("message", t3._as(A.allowInterop(_this.get$_onIncomingMessage(), t1)));
+ _this.__SseClient__eventSource_A.addEventListener("control", t3._as(A.allowInterop(_this.get$_onIncomingControlMessage(), t1)));
+ t1 = type$.nullable_void_Function_JSObject;
+ A._EventStreamSubscription$(_this.__SseClient__eventSource_A, "open", t1._as(new A.SseClient_closure0(_this)), false, t2);
+ A._EventStreamSubscription$(_this.__SseClient__eventSource_A, "error", t1._as(new A.SseClient_closure1(_this)), false, t2);
+ },
+ close$0() {
+ var _this = this,
+ t1 = _this.__SseClient__eventSource_A;
+ t1 === $ && A.throwLateFieldNI("_eventSource");
+ t1.close();
+ if ((_this._onConnected.future._state & 30) === 0) {
+ t1 = _this._outgoingController;
+ new A._ControllerStream(t1, A._instanceType(t1)._eval$1("_ControllerStream<1>")).listen$2$cancelOnError(null, true).asFuture$1$1(null, type$.void);
+ }
+ _this._incomingController.close$0();
+ _this._outgoingController.close$0();
+ },
+ _closeWithError$1(error) {
+ var stackTrace, t2,
+ t1 = this._incomingController;
+ A.checkNotNullable(error, "error", type$.Object);
+ if (t1._state >= 4)
+ A.throwExpression(t1._badEventState$0());
+ stackTrace = A.AsyncError_defaultStackTrace(error);
+ t2 = t1._state;
+ if ((t2 & 1) !== 0)
+ t1._sendError$2(error, stackTrace);
+ else if ((t2 & 3) === 0)
+ t1._ensurePendingEvents$0().add$1(0, new A._DelayedError(error, stackTrace));
+ this.close$0();
+ t1 = this._onConnected;
+ if ((t1.future._state & 30) === 0)
+ t1.completeError$1(error);
+ },
+ _onIncomingControlMessage$1(message) {
+ var data = type$.JSObject._as(message).data;
+ if (J.$eq$(A.dartify(data), "close"))
+ this.close$0();
+ else
+ throw A.wrapException(A.UnsupportedError$("[" + this._clientId + '] Illegal Control Message "' + A.S(data) + '"'));
+ },
+ _onIncomingMessage$1(message) {
+ this._incomingController.add$1(0, A._asString(B.C_JsonCodec.decode$2$reviver(A._asString(type$.JSObject._as(message).data), null)));
+ },
+ _onOutgoingDone$0() {
+ this.close$0();
+ },
+ _onOutgoingMessage$1(message) {
+ return this._onOutgoingMessage$body$SseClient(A._asStringQ(message));
+ },
+ _onOutgoingMessage$body$SseClient(message) {
+ var $async$goto = 0,
+ $async$completer = A._makeAsyncAwaitCompleter(type$.void),
+ $async$self = this, t1;
+ var $async$_onOutgoingMessage$1 = A._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1)
+ return A._asyncRethrow($async$result, $async$completer);
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ t1 = {};
+ t1.encodedMessage = null;
+ $async$goto = 2;
+ return A._asyncAwait($.$get$_requestPool().withResource$1$1(new A.SseClient__onOutgoingMessage_closure(t1, $async$self, message), type$.Null), $async$_onOutgoingMessage$1);
+ case 2:
+ // returning from await.
+ // implicit return
+ return A._asyncReturn(null, $async$completer);
+ }
+ });
+ return A._asyncStartSync($async$_onOutgoingMessage$1, $async$completer);
+ }
+ };
+ A.SseClient_closure.prototype = {
+ call$0() {
+ var t2,
+ t1 = this.$this;
+ t1._onConnected.complete$0();
+ t2 = t1._outgoingController;
+ new A._ControllerStream(t2, A._instanceType(t2)._eval$1("_ControllerStream<1>")).listen$2$onDone(t1.get$_onOutgoingMessage(), t1.get$_onOutgoingDone());
+ },
+ $signature: 2
+ };
+ A.SseClient_closure0.prototype = {
+ call$1(_) {
+ var t1 = this.$this._errorTimer;
+ if (t1 != null)
+ t1.cancel$0();
+ },
+ $signature: 1
+ };
+ A.SseClient_closure1.prototype = {
+ call$1(error) {
+ var t1 = this.$this,
+ t2 = t1._errorTimer;
+ t2 = t2 == null ? null : t2._handle != null;
+ if (t2 !== true)
+ t1._errorTimer = A.Timer_Timer(B.Duration_5000000, new A.SseClient__closure(t1, error));
+ },
+ $signature: 1
+ };
+ A.SseClient__closure.prototype = {
+ call$0() {
+ this.$this._closeWithError$1(this.error);
+ },
+ $signature: 0
+ };
+ A.SseClient__onOutgoingMessage_closure.prototype = {
+ call$0() {
+ var $async$goto = 0,
+ $async$completer = A._makeAsyncAwaitCompleter(type$.Null),
+ $async$handler = 1, $async$currentError, $async$self = this, e, e0, url, error, augmentedError, exception, t1, t2, $async$exception;
+ var $async$call$0 = A._wrapJsFunctionForAsync(function($async$errorCode, $async$result) {
+ if ($async$errorCode === 1) {
+ $async$currentError = $async$result;
+ $async$goto = $async$handler;
+ }
+ while (true)
+ switch ($async$goto) {
+ case 0:
+ // Function start
+ try {
+ $async$self._box_0.encodedMessage = B.C_JsonCodec.encode$2$toEncodable($async$self.message, null);
+ } catch (exception) {
+ t1 = A.unwrapException(exception);
+ if (t1 instanceof A.JsonUnsupportedObjectError) {
+ e = t1;
+ t1 = $async$self.$this;
+ t1._logger.log$4(B.Level_WARNING_900, "[" + t1._clientId + "] Unable to encode outgoing message: " + A.S(e), null, null);
+ } else if (t1 instanceof A.ArgumentError) {
+ e0 = t1;
+ t1 = $async$self.$this;
+ t1._logger.log$4(B.Level_WARNING_900, "[" + t1._clientId + "] Invalid argument: " + A.S(e0), null, null);
+ } else
+ throw exception;
+ }
+ $async$handler = 3;
+ t1 = $async$self.$this;
+ t2 = t1.__SseClient__serverUrl_A;
+ t2 === $ && A.throwLateFieldNI("_serverUrl");
+ url = t2 + "&messageId=" + ++t1._lastMessageId;
+ t1 = $async$self._box_0.encodedMessage;
+ if (t1 == null)
+ t1 = null;
+ t1 = {method: "POST", body: t1, credentials: "include"};
+ t2 = type$.JSObject;
+ $async$goto = 6;
+ return A._asyncAwait(A.promiseToFuture(t2._as(t2._as(self.window).fetch(url, t1)), t2), $async$call$0);
+ case 6:
+ // returning from await.
+ $async$handler = 1;
+ // goto after finally
+ $async$goto = 5;
+ break;
+ case 3:
+ // catch
+ $async$handler = 2;
+ $async$exception = $async$currentError;
+ error = A.unwrapException($async$exception);
+ t1 = $async$self.$this;
+ augmentedError = "[" + t1._clientId + "] SSE client failed to send " + A.S($async$self.message) + ":\n " + A.S(error);
+ t1._logger.log$4(B.Level_SEVERE_1000, augmentedError, null, null);
+ t1._closeWithError$1(augmentedError);
+ // goto after finally
+ $async$goto = 5;
+ break;
+ case 2:
+ // uncaught
+ // goto rethrow
+ $async$goto = 1;
+ break;
+ case 5:
+ // after finally
+ // implicit return
+ return A._asyncReturn(null, $async$completer);
+ case 1:
+ // rethrow
+ return A._asyncRethrow($async$currentError, $async$completer);
+ }
+ });
+ return A._asyncStartSync($async$call$0, $async$completer);
+ },
+ $signature: 7
+ };
+ A.generateUuidV4_generateBits.prototype = {
+ call$1(bitCount) {
+ return this.random.nextInt$1(B.JSInt_methods._shlPositive$1(1, bitCount));
+ },
+ $signature: 23
+ };
+ A.generateUuidV4_printDigits.prototype = {
+ call$2(value, count) {
+ return B.JSString_methods.padLeft$2(B.JSInt_methods.toRadixString$1(value, 16), count, "0");
+ },
+ $signature: 11
+ };
+ A.generateUuidV4_bitsDigits.prototype = {
+ call$2(bitCount, digitCount) {
+ return this.printDigits.call$2(this.generateBits.call$1(bitCount), digitCount);
+ },
+ $signature: 11
+ };
+ A.StreamChannelMixin.prototype = {};
+ A.EventStreamProvider.prototype = {};
+ A._EventStream.prototype = {
+ listen$4$cancelOnError$onDone$onError(onData, cancelOnError, onDone, onError) {
+ var t1 = A._instanceType(this);
+ t1._eval$1("~(1)?")._as(onData);
+ type$.nullable_void_Function._as(onDone);
+ return A._EventStreamSubscription$(this._target, this._eventType, onData, false, t1._precomputed1);
+ }
+ };
+ A._ElementEventStreamImpl.prototype = {};
+ A._EventStreamSubscription.prototype = {
+ cancel$0() {
+ var _this = this,
+ emptyFuture = A.Future_Future$value(null, type$.void);
+ if (_this._target == null)
+ return emptyFuture;
+ _this._unlisten$0();
+ _this._streams$_onData = _this._target = null;
+ return emptyFuture;
+ },
+ onData$1(handleData) {
+ var t1, _this = this;
+ _this.$ti._eval$1("~(1)?")._as(handleData);
+ if (_this._target == null)
+ throw A.wrapException(A.StateError$("Subscription has been canceled."));
+ _this._unlisten$0();
+ t1 = A._wrapZone(new A._EventStreamSubscription_onData_closure(handleData), type$.JSObject);
+ t1 = t1 == null ? null : type$.JavaScriptFunction._as(A.allowInterop(t1, type$.Function));
+ _this._streams$_onData = t1;
+ _this._tryResume$0();
+ },
+ _tryResume$0() {
+ var t1 = this._streams$_onData;
+ if (t1 != null)
+ this._target.addEventListener(this._eventType, t1, false);
+ },
+ _unlisten$0() {
+ var t1 = this._streams$_onData;
+ if (t1 != null)
+ this._target.removeEventListener(this._eventType, t1, false);
+ },
+ $isStreamSubscription: 1
+ };
+ A._EventStreamSubscription_closure.prototype = {
+ call$1(e) {
+ return this.onData.call$1(type$.JSObject._as(e));
+ },
+ $signature: 1
+ };
+ A._EventStreamSubscription_onData_closure.prototype = {
+ call$1(e) {
+ return this.handleData.call$1(type$.JSObject._as(e));
+ },
+ $signature: 1
+ };
+ A.main_closure.prototype = {
+ call$1(_) {
+ this.channel._outgoingController.close$0();
+ },
+ $signature: 1
+ };
+ A.main_closure0.prototype = {
+ call$1(s) {
+ var count, t1, t2, t3, i, t4, t5, lastEvent;
+ A._asString(s);
+ if (B.JSString_methods.startsWith$1(s, "send ")) {
+ count = A.int_parse(B.JSArray_methods.get$last(s.split(" ")), null);
+ for (t1 = this.channel._outgoingController, t2 = A._instanceType(t1), t3 = t2._precomputed1, t2 = t2._eval$1("_DelayedData<1>"), i = 0; i < count; ++i) {
+ t4 = t3._as("" + i);
+ t5 = t1._state;
+ if (t5 >= 4)
+ A.throwExpression(t1._badEventState$0());
+ if ((t5 & 1) !== 0)
+ t1._sendData$1(t4);
+ else if ((t5 & 3) === 0) {
+ t5 = t1._ensurePendingEvents$0();
+ t4 = new A._DelayedData(t4, t2);
+ lastEvent = t5.lastPendingEvent;
+ if (lastEvent == null)
+ t5.firstPendingEvent = t5.lastPendingEvent = t4;
+ else {
+ lastEvent.set$next(t4);
+ t5.lastPendingEvent = t4;
+ }
+ }
+ }
+ } else {
+ t1 = this.channel._outgoingController;
+ t1.add$1(0, A._instanceType(t1)._precomputed1._as(s));
+ }
+ },
+ $signature: 24
+ };
+ (function aliases() {
+ var _ = J.LegacyJavaScriptObject.prototype;
+ _.super$LegacyJavaScriptObject$toString = _.toString$0;
+ })();
+ (function installTearOffs() {
+ var _static_1 = hunkHelpers._static_1,
+ _static_0 = hunkHelpers._static_0,
+ _static_2 = hunkHelpers._static_2,
+ _instance_2_u = hunkHelpers._instance_2u,
+ _instance_1_u = hunkHelpers._instance_1u,
+ _instance_0_u = hunkHelpers._instance_0u;
+ _static_1(A, "async__AsyncRun__scheduleImmediateJsOverride$closure", "_AsyncRun__scheduleImmediateJsOverride", 6);
+ _static_1(A, "async__AsyncRun__scheduleImmediateWithSetImmediate$closure", "_AsyncRun__scheduleImmediateWithSetImmediate", 6);
+ _static_1(A, "async__AsyncRun__scheduleImmediateWithTimer$closure", "_AsyncRun__scheduleImmediateWithTimer", 6);
+ _static_0(A, "async___startMicrotaskLoop$closure", "_startMicrotaskLoop", 0);
+ _static_1(A, "async___nullDataHandler$closure", "_nullDataHandler", 3);
+ _static_2(A, "async___nullErrorHandler$closure", "_nullErrorHandler", 9);
+ _static_0(A, "async___nullDoneHandler$closure", "_nullDoneHandler", 0);
+ _instance_2_u(A._Future.prototype, "get$_completeError", "_completeError$2", 9);
+ _static_1(A, "convert___defaultToEncodable$closure", "_defaultToEncodable", 8);
+ var _;
+ _instance_1_u(_ = A.SseClient.prototype, "get$_onIncomingControlMessage", "_onIncomingControlMessage$1", 1);
+ _instance_1_u(_, "get$_onIncomingMessage", "_onIncomingMessage$1", 1);
+ _instance_0_u(_, "get$_onOutgoingDone", "_onOutgoingDone$0", 0);
+ _instance_1_u(_, "get$_onOutgoingMessage", "_onOutgoingMessage$1", 22);
+ })();
+ (function inheritance() {
+ var _mixin = hunkHelpers.mixin,
+ _inherit = hunkHelpers.inherit,
+ _inheritMany = hunkHelpers.inheritMany;
+ _inherit(A.Object, null);
+ _inheritMany(A.Object, [A.JS_CONST, J.Interceptor, J.ArrayIterator, A.Error, A.Closure, A.Iterable, A.ListIterator, A.FixedLengthListMixin, A.Symbol, A.MapView, A.ConstantMap, A.JSInvocationMirror, A.TypeErrorDecoder, A.NullThrownFromJavaScriptException, A.ExceptionAndStackTrace, A._StackTrace, A._Required, A.MapBase, A.LinkedHashMapCell, A.LinkedHashMapKeyIterator, A.StringMatch, A.Rti, A._FunctionParameters, A._Type, A._TimerImpl, A._AsyncAwaitCompleter, A.AsyncError, A._Completer, A._FutureListener, A._Future, A._AsyncCallbackEntry, A.Stream, A._StreamController, A._AsyncStreamControllerDispatch, A._BufferingStreamSubscription, A._StreamSinkWrapper, A._DelayedEvent, A._DelayedDone, A._PendingEvents, A._StreamIterator, A._Zone, A._HashMapKeyIterator, A.ListBase, A._UnmodifiableMapMixin, A._ListQueueIterator, A.Codec, A.Converter, A._JsonStringifier, A.DateTime, A.Duration, A.OutOfMemoryError, A.StackOverflowError, A._Exception, A.FormatException, A.Null, A._StringStackTrace, A.StringBuffer, A.NullRejectionException, A._JSRandom, A.AsyncMemoizer, A.Level, A.LogRecord, A.Logger, A.Pool, A.PoolResource, A.StreamChannelMixin, A.EventStreamProvider, A._EventStreamSubscription]);
+ _inheritMany(J.Interceptor, [J.JSBool, J.JSNull, J.JavaScriptObject, J.JavaScriptBigInt, J.JavaScriptSymbol, J.JSNumber, J.JSString]);
+ _inheritMany(J.JavaScriptObject, [J.LegacyJavaScriptObject, J.JSArray, A.NativeByteBuffer, A.NativeTypedData]);
+ _inheritMany(J.LegacyJavaScriptObject, [J.PlainJavaScriptObject, J.UnknownJavaScriptObject, J.JavaScriptFunction]);
+ _inherit(J.JSUnmodifiableArray, J.JSArray);
+ _inheritMany(J.JSNumber, [J.JSInt, J.JSNumNotInt]);
+ _inheritMany(A.Error, [A.LateError, A.TypeError, A.JsNoSuchMethodError, A.UnknownJsTypeError, A._CyclicInitializationError, A.RuntimeError, A._Error, A.JsonUnsupportedObjectError, A.AssertionError, A.ArgumentError, A.NoSuchMethodError, A.UnsupportedError, A.UnimplementedError, A.StateError, A.ConcurrentModificationError]);
+ _inheritMany(A.Closure, [A.Closure0Args, A.Closure2Args, A.TearOffClosure, A.initHooks_closure, A.initHooks_closure1, A._AsyncRun__initializeScheduleImmediate_internalCallback, A._AsyncRun__initializeScheduleImmediate_closure, A._awaitOnObject_closure, A._Future__chainForeignFuture_closure, A._Future__propagateToListeners_handleWhenCompleteCallback_closure, A.Stream_length_closure, A.Stream_first_closure0, A._RootZone_bindUnaryCallbackGuarded_closure, A.promiseToFuture_closure, A.promiseToFuture_closure0, A.dartify_convert, A.Pool__runOnRelease_closure, A.SseClient_closure0, A.SseClient_closure1, A.generateUuidV4_generateBits, A._EventStreamSubscription_closure, A._EventStreamSubscription_onData_closure, A.main_closure, A.main_closure0]);
+ _inheritMany(A.Closure0Args, [A.nullFuture_closure, A._AsyncRun__scheduleImmediateJsOverride_internalCallback, A._AsyncRun__scheduleImmediateWithSetImmediate_internalCallback, A._TimerImpl_internalCallback, A._Future__addListener_closure, A._Future__prependListeners_closure, A._Future__chainForeignFuture_closure1, A._Future__chainCoreFutureAsync_closure, A._Future__asyncCompleteWithValue_closure, A._Future__asyncCompleteError_closure, A._Future__propagateToListeners_handleWhenCompleteCallback, A._Future__propagateToListeners_handleValueCallback, A._Future__propagateToListeners_handleError, A.Stream_length_closure0, A.Stream_first_closure, A._StreamController__subscribe_closure, A._StreamController__recordCancel_complete, A._BufferingStreamSubscription_asFuture_closure, A._BufferingStreamSubscription_asFuture__closure, A._BufferingStreamSubscription__sendError_sendError, A._BufferingStreamSubscription__sendDone_sendDone, A._PendingEvents_schedule_closure, A._cancelAndValue_closure, A._rootHandleError_closure, A._RootZone_bindCallbackGuarded_closure, A.Logger_Logger_closure, A.SseClient_closure, A.SseClient__closure, A.SseClient__onOutgoingMessage_closure]);
+ _inherit(A.EfficientLengthIterable, A.Iterable);
+ _inheritMany(A.EfficientLengthIterable, [A.ListIterable, A.LinkedHashMapKeyIterable, A._HashMapKeyIterable]);
+ _inherit(A._UnmodifiableMapView_MapView__UnmodifiableMapMixin, A.MapView);
+ _inherit(A.UnmodifiableMapView, A._UnmodifiableMapView_MapView__UnmodifiableMapMixin);
+ _inherit(A.ConstantMapView, A.UnmodifiableMapView);
+ _inherit(A.ConstantStringMap, A.ConstantMap);
+ _inheritMany(A.Closure2Args, [A.Primitives_functionNoSuchMethod_closure, A.initHooks_closure0, A._awaitOnObject_closure0, A._wrapJsFunctionForAsync_closure, A._Future__chainForeignFuture_closure0, A._BufferingStreamSubscription_asFuture_closure0, A.MapBase_mapToString_closure, A._JsonStringifier_writeMap_closure, A.NoSuchMethodError_toString_closure, A.Pool__runOnRelease_closure0, A.generateUuidV4_printDigits, A.generateUuidV4_bitsDigits]);
+ _inherit(A.NullError, A.TypeError);
+ _inheritMany(A.TearOffClosure, [A.StaticClosure, A.BoundClosure]);
+ _inheritMany(A.MapBase, [A.JsLinkedHashMap, A._HashMap, A._JsonMap]);
+ _inheritMany(A.NativeTypedData, [A.NativeByteData, A.NativeTypedArray]);
+ _inheritMany(A.NativeTypedArray, [A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin, A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin]);
+ _inherit(A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin, A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin);
+ _inherit(A.NativeTypedArrayOfDouble, A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin);
+ _inherit(A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin, A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin);
+ _inherit(A.NativeTypedArrayOfInt, A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin);
+ _inheritMany(A.NativeTypedArrayOfDouble, [A.NativeFloat32List, A.NativeFloat64List]);
+ _inheritMany(A.NativeTypedArrayOfInt, [A.NativeInt16List, A.NativeInt32List, A.NativeInt8List, A.NativeUint16List, A.NativeUint32List, A.NativeUint8ClampedList, A.NativeUint8List]);
+ _inherit(A._TypeError, A._Error);
+ _inheritMany(A._Completer, [A._AsyncCompleter, A._SyncCompleter]);
+ _inherit(A._AsyncStreamController, A._StreamController);
+ _inheritMany(A.Stream, [A._StreamImpl, A._EventStream]);
+ _inherit(A._ControllerStream, A._StreamImpl);
+ _inherit(A._ControllerSubscription, A._BufferingStreamSubscription);
+ _inheritMany(A._DelayedEvent, [A._DelayedData, A._DelayedError]);
+ _inherit(A._RootZone, A._Zone);
+ _inherit(A._IdentityHashMap, A._HashMap);
+ _inheritMany(A.ListIterable, [A.ListQueue, A._JsonMapKeyIterable]);
+ _inherit(A.JsonCyclicError, A.JsonUnsupportedObjectError);
+ _inherit(A.JsonCodec, A.Codec);
+ _inheritMany(A.Converter, [A.JsonEncoder, A.JsonDecoder]);
+ _inherit(A._JsonStringStringifier, A._JsonStringifier);
+ _inheritMany(A.ArgumentError, [A.RangeError, A.IndexError]);
+ _inherit(A.SseClient, A.StreamChannelMixin);
+ _inherit(A._ElementEventStreamImpl, A._EventStream);
+ _mixin(A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin, A.ListBase);
+ _mixin(A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin, A.FixedLengthListMixin);
+ _mixin(A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin, A.ListBase);
+ _mixin(A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin, A.FixedLengthListMixin);
+ _mixin(A._AsyncStreamController, A._AsyncStreamControllerDispatch);
+ _mixin(A._UnmodifiableMapView_MapView__UnmodifiableMapMixin, A._UnmodifiableMapMixin);
+ })();
+ var init = {
+ typeUniverse: {eC: new Map(), tR: {}, eT: {}, tPV: {}, sEA: []},
+ mangledGlobalNames: {int: "int", double: "double", num: "num", String: "String", bool: "bool", Null: "Null", List: "List", Object: "Object", Map: "Map"},
+ mangledNames: {},
+ types: ["~()", "~(JSObject)", "Null()", "~(@)", "Null(@)", "Null(Object,StackTrace)", "~(~())", "Future<Null>()", "@(@)", "~(Object,StackTrace)", "~(Object?,Object?)", "String(int,int)", "~(String,@)", "@(@,String)", "@(String)", "Null(~())", "Null(@,StackTrace)", "~(int,@)", "_Future<@>(@)", "~(Symbol0,@)", "Object?(Object?)", "Logger()", "~(String?)", "int(int)", "~(String)"],
+ interceptorsByTag: null,
+ leafTags: null,
+ arrayRti: Symbol("$ti")
+ };
+ A._Universe_addRules(init.typeUniverse, JSON.parse('{"PlainJavaScriptObject":"LegacyJavaScriptObject","UnknownJavaScriptObject":"LegacyJavaScriptObject","JavaScriptFunction":"LegacyJavaScriptObject","JSBool":{"bool":[],"TrustedGetRuntimeType":[]},"JSNull":{"Null":[],"TrustedGetRuntimeType":[]},"JavaScriptObject":{"JSObject":[]},"LegacyJavaScriptObject":{"JSObject":[]},"JSArray":{"List":["1"],"JSObject":[],"Iterable":["1"]},"JSUnmodifiableArray":{"JSArray":["1"],"List":["1"],"JSObject":[],"Iterable":["1"]},"JSNumber":{"double":[],"num":[]},"JSInt":{"double":[],"int":[],"num":[],"TrustedGetRuntimeType":[]},"JSNumNotInt":{"double":[],"num":[],"TrustedGetRuntimeType":[]},"JSString":{"String":[],"Pattern":[],"TrustedGetRuntimeType":[]},"LateError":{"Error":[]},"EfficientLengthIterable":{"Iterable":["1"]},"ListIterable":{"Iterable":["1"]},"Symbol":{"Symbol0":[]},"ConstantMapView":{"UnmodifiableMapView":["1","2"],"_UnmodifiableMapView_MapView__UnmodifiableMapMixin":["1","2"],"MapView":["1","2"],"_UnmodifiableMapMixin":["1","2"],"Map":["1","2"]},"ConstantMap":{"Map":["1","2"]},"ConstantStringMap":{"ConstantMap":["1","2"],"Map":["1","2"]},"JSInvocationMirror":{"Invocation":[]},"NullError":{"TypeError":[],"Error":[]},"JsNoSuchMethodError":{"Error":[]},"UnknownJsTypeError":{"Error":[]},"_StackTrace":{"StackTrace":[]},"Closure":{"Function":[]},"Closure0Args":{"Function":[]},"Closure2Args":{"Function":[]},"TearOffClosure":{"Function":[]},"StaticClosure":{"Function":[]},"BoundClosure":{"Function":[]},"_CyclicInitializationError":{"Error":[]},"RuntimeError":{"Error":[]},"JsLinkedHashMap":{"MapBase":["1","2"],"Map":["1","2"],"MapBase.K":"1","MapBase.V":"2"},"LinkedHashMapKeyIterable":{"Iterable":["1"]},"NativeByteBuffer":{"JSObject":[],"TrustedGetRuntimeType":[]},"NativeTypedData":{"JSObject":[]},"NativeByteData":{"JSObject":[],"TrustedGetRuntimeType":[]},"NativeTypedArray":{"JavaScriptIndexingBehavior":["1"],"JSObject":[]},"NativeTypedArrayOfDouble":{"ListBase":["double"],"List":["double"],"JavaScriptIndexingBehavior":["double"],"JSObject":[],"Iterable":["double"],"FixedLengthListMixin":["double"]},"NativeTypedArrayOfInt":{"ListBase":["int"],"List":["int"],"JavaScriptIndexingBehavior":["int"],"JSObject":[],"Iterable":["int"],"FixedLengthListMixin":["int"]},"NativeFloat32List":{"ListBase":["double"],"List":["double"],"JavaScriptIndexingBehavior":["double"],"JSObject":[],"Iterable":["double"],"FixedLengthListMixin":["double"],"TrustedGetRuntimeType":[],"ListBase.E":"double"},"NativeFloat64List":{"ListBase":["double"],"List":["double"],"JavaScriptIndexingBehavior":["double"],"JSObject":[],"Iterable":["double"],"FixedLengthListMixin":["double"],"TrustedGetRuntimeType":[],"ListBase.E":"double"},"NativeInt16List":{"ListBase":["int"],"List":["int"],"JavaScriptIndexingBehavior":["int"],"JSObject":[],"Iterable":["int"],"FixedLengthListMixin":["int"],"TrustedGetRuntimeType":[],"ListBase.E":"int"},"NativeInt32List":{"ListBase":["int"],"List":["int"],"JavaScriptIndexingBehavior":["int"],"JSObject":[],"Iterable":["int"],"FixedLengthListMixin":["int"],"TrustedGetRuntimeType":[],"ListBase.E":"int"},"NativeInt8List":{"ListBase":["int"],"List":["int"],"JavaScriptIndexingBehavior":["int"],"JSObject":[],"Iterable":["int"],"FixedLengthListMixin":["int"],"TrustedGetRuntimeType":[],"ListBase.E":"int"},"NativeUint16List":{"ListBase":["int"],"List":["int"],"JavaScriptIndexingBehavior":["int"],"JSObject":[],"Iterable":["int"],"FixedLengthListMixin":["int"],"TrustedGetRuntimeType":[],"ListBase.E":"int"},"NativeUint32List":{"ListBase":["int"],"List":["int"],"JavaScriptIndexingBehavior":["int"],"JSObject":[],"Iterable":["int"],"FixedLengthListMixin":["int"],"TrustedGetRuntimeType":[],"ListBase.E":"int"},"NativeUint8ClampedList":{"ListBase":["int"],"List":["int"],"JavaScriptIndexingBehavior":["int"],"JSObject":[],"Iterable":["int"],"FixedLengthListMixin":["int"],"TrustedGetRuntimeType":[],"ListBase.E":"int"},"NativeUint8List":{"ListBase":["int"],"List":["int"],"JavaScriptIndexingBehavior":["int"],"JSObject":[],"Iterable":["int"],"FixedLengthListMixin":["int"],"TrustedGetRuntimeType":[],"ListBase.E":"int"},"_Error":{"Error":[]},"_TypeError":{"TypeError":[],"Error":[]},"_Future":{"Future":["1"]},"_TimerImpl":{"Timer":[]},"_AsyncAwaitCompleter":{"Completer":["1"]},"AsyncError":{"Error":[]},"_Completer":{"Completer":["1"]},"_AsyncCompleter":{"_Completer":["1"],"Completer":["1"]},"_SyncCompleter":{"_Completer":["1"],"Completer":["1"]},"_StreamController":{"StreamController":["1"],"_StreamControllerLifecycle":["1"],"_EventDispatch":["1"]},"_AsyncStreamController":{"_AsyncStreamControllerDispatch":["1"],"_StreamController":["1"],"StreamController":["1"],"_StreamControllerLifecycle":["1"],"_EventDispatch":["1"]},"_ControllerStream":{"_StreamImpl":["1"],"Stream":["1"]},"_ControllerSubscription":{"_BufferingStreamSubscription":["1"],"StreamSubscription":["1"],"_EventDispatch":["1"]},"_BufferingStreamSubscription":{"StreamSubscription":["1"],"_EventDispatch":["1"]},"_StreamImpl":{"Stream":["1"]},"_DelayedData":{"_DelayedEvent":["1"]},"_DelayedError":{"_DelayedEvent":["@"]},"_DelayedDone":{"_DelayedEvent":["@"]},"_Zone":{"Zone":[]},"_RootZone":{"_Zone":[],"Zone":[]},"_HashMap":{"MapBase":["1","2"],"Map":["1","2"]},"_IdentityHashMap":{"_HashMap":["1","2"],"MapBase":["1","2"],"Map":["1","2"],"MapBase.K":"1","MapBase.V":"2"},"_HashMapKeyIterable":{"Iterable":["1"]},"MapBase":{"Map":["1","2"]},"MapView":{"Map":["1","2"]},"UnmodifiableMapView":{"_UnmodifiableMapView_MapView__UnmodifiableMapMixin":["1","2"],"MapView":["1","2"],"_UnmodifiableMapMixin":["1","2"],"Map":["1","2"]},"ListQueue":{"Queue":["1"],"ListIterable":["1"],"Iterable":["1"],"ListIterable.E":"1"},"_JsonMap":{"MapBase":["String","@"],"Map":["String","@"],"MapBase.K":"String","MapBase.V":"@"},"_JsonMapKeyIterable":{"ListIterable":["String"],"Iterable":["String"],"ListIterable.E":"String"},"JsonUnsupportedObjectError":{"Error":[]},"JsonCyclicError":{"Error":[]},"JsonCodec":{"Codec":["Object?","String"]},"JsonEncoder":{"Converter":["Object?","String"]},"JsonDecoder":{"Converter":["String","Object?"]},"double":{"num":[]},"int":{"num":[]},"String":{"Pattern":[]},"AssertionError":{"Error":[]},"TypeError":{"Error":[]},"ArgumentError":{"Error":[]},"RangeError":{"Error":[]},"IndexError":{"Error":[]},"NoSuchMethodError":{"Error":[]},"UnsupportedError":{"Error":[]},"UnimplementedError":{"Error":[]},"StateError":{"Error":[]},"ConcurrentModificationError":{"Error":[]},"OutOfMemoryError":{"Error":[]},"StackOverflowError":{"Error":[]},"_StringStackTrace":{"StackTrace":[]},"StringBuffer":{"StringSink":[]},"_EventStream":{"Stream":["1"]},"_ElementEventStreamImpl":{"_EventStream":["1"],"Stream":["1"]},"_EventStreamSubscription":{"StreamSubscription":["1"]},"Int8List":{"List":["int"],"Iterable":["int"]},"Uint8List":{"List":["int"],"Iterable":["int"]},"Uint8ClampedList":{"List":["int"],"Iterable":["int"]},"Int16List":{"List":["int"],"Iterable":["int"]},"Uint16List":{"List":["int"],"Iterable":["int"]},"Int32List":{"List":["int"],"Iterable":["int"]},"Uint32List":{"List":["int"],"Iterable":["int"]},"Float32List":{"List":["double"],"Iterable":["double"]},"Float64List":{"List":["double"],"Iterable":["double"]}}'));
+ A._Universe_addErasedTypes(init.typeUniverse, JSON.parse('{"EfficientLengthIterable":1,"NativeTypedArray":1,"_DelayedEvent":1,"StreamChannelMixin":1}'));
+ var string$ = {
+ Error_: "Error handler must accept one Object or one Object and a StackTrace as arguments, and return a value of the returned future's type"
+ };
+ var type$ = (function rtii() {
+ var findType = A.findType;
+ return {
+ $env_1_1_void: findType("@<~>"),
+ AsyncError: findType("AsyncError"),
+ ConstantMapView_Symbol_dynamic: findType("ConstantMapView<Symbol0,@>"),
+ Error: findType("Error"),
+ Function: findType("Function"),
+ Future_dynamic: findType("Future<@>"),
+ Invocation: findType("Invocation"),
+ Iterable_dynamic: findType("Iterable<@>"),
+ JSArray_String: findType("JSArray<String>"),
+ JSArray_dynamic: findType("JSArray<@>"),
+ JSNull: findType("JSNull"),
+ JSObject: findType("JSObject"),
+ JavaScriptFunction: findType("JavaScriptFunction"),
+ JavaScriptIndexingBehavior_dynamic: findType("JavaScriptIndexingBehavior<@>"),
+ JsLinkedHashMap_Symbol_dynamic: findType("JsLinkedHashMap<Symbol0,@>"),
+ List_dynamic: findType("List<@>"),
+ Logger: findType("Logger"),
+ Map_dynamic_dynamic: findType("Map<@,@>"),
+ Null: findType("Null"),
+ Object: findType("Object"),
+ PoolResource: findType("PoolResource"),
+ Record: findType("Record"),
+ StackTrace: findType("StackTrace"),
+ String: findType("String"),
+ Symbol: findType("Symbol0"),
+ TrustedGetRuntimeType: findType("TrustedGetRuntimeType"),
+ TypeError: findType("TypeError"),
+ UnknownJavaScriptObject: findType("UnknownJavaScriptObject"),
+ _AsyncCompleter_PoolResource: findType("_AsyncCompleter<PoolResource>"),
+ _AsyncCompleter_void: findType("_AsyncCompleter<~>"),
+ _ElementEventStreamImpl_JSObject: findType("_ElementEventStreamImpl<JSObject>"),
+ _EventStream_JSObject: findType("_EventStream<JSObject>"),
+ _Future_PoolResource: findType("_Future<PoolResource>"),
+ _Future_dynamic: findType("_Future<@>"),
+ _Future_int: findType("_Future<int>"),
+ _Future_void: findType("_Future<~>"),
+ _IdentityHashMap_of_nullable_Object_and_nullable_Object: findType("_IdentityHashMap<Object?,Object?>"),
+ _StreamControllerAddStreamState_nullable_Object: findType("_StreamControllerAddStreamState<Object?>"),
+ _SyncCompleter_PoolResource: findType("_SyncCompleter<PoolResource>"),
+ bool: findType("bool"),
+ bool_Function_Object: findType("bool(Object)"),
+ double: findType("double"),
+ dynamic: findType("@"),
+ dynamic_Function: findType("@()"),
+ dynamic_Function_Object: findType("@(Object)"),
+ dynamic_Function_Object_StackTrace: findType("@(Object,StackTrace)"),
+ int: findType("int"),
+ legacy_Never: findType("0&*"),
+ legacy_Object: findType("Object*"),
+ nullable_Future_Null: findType("Future<Null>?"),
+ nullable_JSObject: findType("JSObject?"),
+ nullable_List_dynamic: findType("List<@>?"),
+ nullable_Object: findType("Object?"),
+ nullable_StackTrace: findType("StackTrace?"),
+ nullable__DelayedEvent_dynamic: findType("_DelayedEvent<@>?"),
+ nullable__FutureListener_dynamic_dynamic: findType("_FutureListener<@,@>?"),
+ nullable_void_Function: findType("~()?"),
+ nullable_void_Function_JSObject: findType("~(JSObject)?"),
+ num: findType("num"),
+ void: findType("~"),
+ void_Function: findType("~()"),
+ void_Function_Object: findType("~(Object)"),
+ void_Function_Object_StackTrace: findType("~(Object,StackTrace)"),
+ void_Function_String_dynamic: findType("~(String,@)")
+ };
+ })();
+ (function constants() {
+ var makeConstList = hunkHelpers.makeConstList;
+ B.Interceptor_methods = J.Interceptor.prototype;
+ B.JSArray_methods = J.JSArray.prototype;
+ B.JSInt_methods = J.JSInt.prototype;
+ B.JSNumber_methods = J.JSNumber.prototype;
+ B.JSString_methods = J.JSString.prototype;
+ B.JavaScriptFunction_methods = J.JavaScriptFunction.prototype;
+ B.JavaScriptObject_methods = J.JavaScriptObject.prototype;
+ B.PlainJavaScriptObject_methods = J.PlainJavaScriptObject.prototype;
+ B.UnknownJavaScriptObject_methods = J.UnknownJavaScriptObject.prototype;
+ B.C_JS_CONST = function getTagFallback(o) {
+ var s = Object.prototype.toString.call(o);
+ return s.substring(8, s.length - 1);
+};
+ B.C_JS_CONST0 = function() {
+ var toStringFunction = Object.prototype.toString;
+ function getTag(o) {
+ var s = toStringFunction.call(o);
+ return s.substring(8, s.length - 1);
+ }
+ function getUnknownTag(object, tag) {
+ if (/^HTML[A-Z].*Element$/.test(tag)) {
+ var name = toStringFunction.call(object);
+ if (name == "[object Object]") return null;
+ return "HTMLElement";
+ }
+ }
+ function getUnknownTagGenericBrowser(object, tag) {
+ if (object instanceof HTMLElement) return "HTMLElement";
+ return getUnknownTag(object, tag);
+ }
+ function prototypeForTag(tag) {
+ if (typeof window == "undefined") return null;
+ if (typeof window[tag] == "undefined") return null;
+ var constructor = window[tag];
+ if (typeof constructor != "function") return null;
+ return constructor.prototype;
+ }
+ function discriminator(tag) { return null; }
+ var isBrowser = typeof HTMLElement == "function";
+ return {
+ getTag: getTag,
+ getUnknownTag: isBrowser ? getUnknownTagGenericBrowser : getUnknownTag,
+ prototypeForTag: prototypeForTag,
+ discriminator: discriminator };
+};
+ B.C_JS_CONST6 = function(getTagFallback) {
+ return function(hooks) {
+ if (typeof navigator != "object") return hooks;
+ var userAgent = navigator.userAgent;
+ if (typeof userAgent != "string") return hooks;
+ if (userAgent.indexOf("DumpRenderTree") >= 0) return hooks;
+ if (userAgent.indexOf("Chrome") >= 0) {
+ function confirm(p) {
+ return typeof window == "object" && window[p] && window[p].name == p;
+ }
+ if (confirm("Window") && confirm("HTMLElement")) return hooks;
+ }
+ hooks.getTag = getTagFallback;
+ };
+};
+ B.C_JS_CONST1 = function(hooks) {
+ if (typeof dartExperimentalFixupGetTag != "function") return hooks;
+ hooks.getTag = dartExperimentalFixupGetTag(hooks.getTag);
+};
+ B.C_JS_CONST5 = function(hooks) {
+ if (typeof navigator != "object") return hooks;
+ var userAgent = navigator.userAgent;
+ if (typeof userAgent != "string") return hooks;
+ if (userAgent.indexOf("Firefox") == -1) return hooks;
+ var getTag = hooks.getTag;
+ var quickMap = {
+ "BeforeUnloadEvent": "Event",
+ "DataTransfer": "Clipboard",
+ "GeoGeolocation": "Geolocation",
+ "Location": "!Location",
+ "WorkerMessageEvent": "MessageEvent",
+ "XMLDocument": "!Document"};
+ function getTagFirefox(o) {
+ var tag = getTag(o);
+ return quickMap[tag] || tag;
+ }
+ hooks.getTag = getTagFirefox;
+};
+ B.C_JS_CONST4 = function(hooks) {
+ if (typeof navigator != "object") return hooks;
+ var userAgent = navigator.userAgent;
+ if (typeof userAgent != "string") return hooks;
+ if (userAgent.indexOf("Trident/") == -1) return hooks;
+ var getTag = hooks.getTag;
+ var quickMap = {
+ "BeforeUnloadEvent": "Event",
+ "DataTransfer": "Clipboard",
+ "HTMLDDElement": "HTMLElement",
+ "HTMLDTElement": "HTMLElement",
+ "HTMLPhraseElement": "HTMLElement",
+ "Position": "Geoposition"
+ };
+ function getTagIE(o) {
+ var tag = getTag(o);
+ var newTag = quickMap[tag];
+ if (newTag) return newTag;
+ if (tag == "Object") {
+ if (window.DataView && (o instanceof window.DataView)) return "DataView";
+ }
+ return tag;
+ }
+ function prototypeForTagIE(tag) {
+ var constructor = window[tag];
+ if (constructor == null) return null;
+ return constructor.prototype;
+ }
+ hooks.getTag = getTagIE;
+ hooks.prototypeForTag = prototypeForTagIE;
+};
+ B.C_JS_CONST2 = function(hooks) {
+ var getTag = hooks.getTag;
+ var prototypeForTag = hooks.prototypeForTag;
+ function getTagFixed(o) {
+ var tag = getTag(o);
+ if (tag == "Document") {
+ if (!!o.xmlVersion) return "!Document";
+ return "!HTMLDocument";
+ }
+ return tag;
+ }
+ function prototypeForTagFixed(tag) {
+ if (tag == "Document") return null;
+ return prototypeForTag(tag);
+ }
+ hooks.getTag = getTagFixed;
+ hooks.prototypeForTag = prototypeForTagFixed;
+};
+ B.C_JS_CONST3 = function(hooks) { return hooks; }
+;
+ B.C_JsonCodec = new A.JsonCodec();
+ B.C_OutOfMemoryError = new A.OutOfMemoryError();
+ B.C__DelayedDone = new A._DelayedDone();
+ B.C__JSRandom = new A._JSRandom();
+ B.C__Required = new A._Required();
+ B.C__RootZone = new A._RootZone();
+ B.Duration_0 = new A.Duration(0);
+ B.Duration_5000000 = new A.Duration(5000000);
+ B.JsonDecoder_null = new A.JsonDecoder(null);
+ B.JsonEncoder_null = new A.JsonEncoder(null);
+ B.Level_INFO_800 = new A.Level("INFO", 800);
+ B.Level_SEVERE_1000 = new A.Level("SEVERE", 1000);
+ B.Level_WARNING_900 = new A.Level("WARNING", 900);
+ B.List_empty = A._setArrayType(makeConstList([]), type$.JSArray_dynamic);
+ B.Object_empty = {};
+ B.Map_empty = new A.ConstantStringMap(B.Object_empty, [], A.findType("ConstantStringMap<Symbol0,@>"));
+ B.Symbol_call = new A.Symbol("call");
+ B.Type_ByteBuffer_RkP = A.typeLiteral("ByteBuffer");
+ B.Type_ByteData_zNC = A.typeLiteral("ByteData");
+ B.Type_Float32List_LB7 = A.typeLiteral("Float32List");
+ B.Type_Float64List_LB7 = A.typeLiteral("Float64List");
+ B.Type_Int16List_uXf = A.typeLiteral("Int16List");
+ B.Type_Int32List_O50 = A.typeLiteral("Int32List");
+ B.Type_Int8List_ekJ = A.typeLiteral("Int8List");
+ B.Type_Uint16List_2bx = A.typeLiteral("Uint16List");
+ B.Type_Uint32List_2bx = A.typeLiteral("Uint32List");
+ B.Type_Uint8ClampedList_Jik = A.typeLiteral("Uint8ClampedList");
+ B.Type_Uint8List_WLA = A.typeLiteral("Uint8List");
+ B._StringStackTrace_3uE = new A._StringStackTrace("");
+ })();
+ (function staticFields() {
+ $._JS_INTEROP_INTERCEPTOR_TAG = null;
+ $.toStringVisiting = A._setArrayType([], A.findType("JSArray<Object>"));
+ $.Primitives__identityHashCodeProperty = null;
+ $.BoundClosure__receiverFieldNameCache = null;
+ $.BoundClosure__interceptorFieldNameCache = null;
+ $.getTagFunction = null;
+ $.alternateTagFunction = null;
+ $.prototypeForTagFunction = null;
+ $.dispatchRecordsForInstanceTags = null;
+ $.interceptorsForUncacheableTags = null;
+ $.initNativeDispatchFlag = null;
+ $._nextCallback = null;
+ $._lastCallback = null;
+ $._lastPriorityCallback = null;
+ $._isInCallbackLoop = false;
+ $.Zone__current = B.C__RootZone;
+ $.LogRecord__nextNumber = 0;
+ $.Logger__loggers = A.LinkedHashMap_LinkedHashMap$_empty(type$.String, type$.Logger);
+ })();
+ (function lazyInitializers() {
+ var _lazyFinal = hunkHelpers.lazyFinal;
+ _lazyFinal($, "DART_CLOSURE_PROPERTY_NAME", "$get$DART_CLOSURE_PROPERTY_NAME", () => A.getIsolateAffinityTag("_$dart_dartClosure"));
+ _lazyFinal($, "nullFuture", "$get$nullFuture", () => B.C__RootZone.run$1$1(new A.nullFuture_closure(), A.findType("Future<Null>")));
+ _lazyFinal($, "TypeErrorDecoder_noSuchMethodPattern", "$get$TypeErrorDecoder_noSuchMethodPattern", () => A.TypeErrorDecoder_extractPattern(A.TypeErrorDecoder_provokeCallErrorOn({
+ toString: function() {
+ return "$receiver$";
+ }
+ })));
+ _lazyFinal($, "TypeErrorDecoder_notClosurePattern", "$get$TypeErrorDecoder_notClosurePattern", () => A.TypeErrorDecoder_extractPattern(A.TypeErrorDecoder_provokeCallErrorOn({$method$: null,
+ toString: function() {
+ return "$receiver$";
+ }
+ })));
+ _lazyFinal($, "TypeErrorDecoder_nullCallPattern", "$get$TypeErrorDecoder_nullCallPattern", () => A.TypeErrorDecoder_extractPattern(A.TypeErrorDecoder_provokeCallErrorOn(null)));
+ _lazyFinal($, "TypeErrorDecoder_nullLiteralCallPattern", "$get$TypeErrorDecoder_nullLiteralCallPattern", () => A.TypeErrorDecoder_extractPattern(function() {
+ var $argumentsExpr$ = "$arguments$";
+ try {
+ null.$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+ }()));
+ _lazyFinal($, "TypeErrorDecoder_undefinedCallPattern", "$get$TypeErrorDecoder_undefinedCallPattern", () => A.TypeErrorDecoder_extractPattern(A.TypeErrorDecoder_provokeCallErrorOn(void 0)));
+ _lazyFinal($, "TypeErrorDecoder_undefinedLiteralCallPattern", "$get$TypeErrorDecoder_undefinedLiteralCallPattern", () => A.TypeErrorDecoder_extractPattern(function() {
+ var $argumentsExpr$ = "$arguments$";
+ try {
+ (void 0).$method$($argumentsExpr$);
+ } catch (e) {
+ return e.message;
+ }
+ }()));
+ _lazyFinal($, "TypeErrorDecoder_nullPropertyPattern", "$get$TypeErrorDecoder_nullPropertyPattern", () => A.TypeErrorDecoder_extractPattern(A.TypeErrorDecoder_provokePropertyErrorOn(null)));
+ _lazyFinal($, "TypeErrorDecoder_nullLiteralPropertyPattern", "$get$TypeErrorDecoder_nullLiteralPropertyPattern", () => A.TypeErrorDecoder_extractPattern(function() {
+ try {
+ null.$method$;
+ } catch (e) {
+ return e.message;
+ }
+ }()));
+ _lazyFinal($, "TypeErrorDecoder_undefinedPropertyPattern", "$get$TypeErrorDecoder_undefinedPropertyPattern", () => A.TypeErrorDecoder_extractPattern(A.TypeErrorDecoder_provokePropertyErrorOn(void 0)));
+ _lazyFinal($, "TypeErrorDecoder_undefinedLiteralPropertyPattern", "$get$TypeErrorDecoder_undefinedLiteralPropertyPattern", () => A.TypeErrorDecoder_extractPattern(function() {
+ try {
+ (void 0).$method$;
+ } catch (e) {
+ return e.message;
+ }
+ }()));
+ _lazyFinal($, "_AsyncRun__scheduleImmediateClosure", "$get$_AsyncRun__scheduleImmediateClosure", () => A._AsyncRun__initializeScheduleImmediate());
+ _lazyFinal($, "Future__nullFuture", "$get$Future__nullFuture", () => A.findType("_Future<Null>")._as($.$get$nullFuture()));
+ _lazyFinal($, "Logger_root", "$get$Logger_root", () => A.Logger_Logger(""));
+ _lazyFinal($, "_requestPool", "$get$_requestPool", () => {
+ var t4,
+ t1 = A.findType("Completer<PoolResource>"),
+ t2 = A.ListQueue$(t1),
+ t3 = A.ListQueue$(type$.void_Function);
+ t1 = A.ListQueue$(t1);
+ t4 = A.Completer_Completer(type$.dynamic);
+ return new A.Pool(t2, t3, t1, 1000, new A.AsyncMemoizer(t4, A.findType("AsyncMemoizer<@>")));
+ });
+ })();
+ (function nativeSupport() {
+ !function() {
+ var intern = function(s) {
+ var o = {};
+ o[s] = 1;
+ return Object.keys(hunkHelpers.convertToFastObject(o))[0];
+ };
+ init.getIsolateTag = function(name) {
+ return intern("___dart_" + name + init.isolateTag);
+ };
+ var tableProperty = "___dart_isolate_tags_";
+ var usedProperties = Object[tableProperty] || (Object[tableProperty] = Object.create(null));
+ var rootProperty = "_ZxYxX";
+ for (var i = 0;; i++) {
+ var property = intern(rootProperty + "_" + i + "_");
+ if (!(property in usedProperties)) {
+ usedProperties[property] = 1;
+ init.isolateTag = property;
+ break;
+ }
+ }
+ init.dispatchPropertyName = init.getIsolateTag("dispatch_record");
+ }();
+ hunkHelpers.setOrUpdateInterceptorsByTag({ArrayBuffer: A.NativeByteBuffer, ArrayBufferView: A.NativeTypedData, DataView: A.NativeByteData, Float32Array: A.NativeFloat32List, Float64Array: A.NativeFloat64List, Int16Array: A.NativeInt16List, Int32Array: A.NativeInt32List, Int8Array: A.NativeInt8List, Uint16Array: A.NativeUint16List, Uint32Array: A.NativeUint32List, Uint8ClampedArray: A.NativeUint8ClampedList, CanvasPixelArray: A.NativeUint8ClampedList, Uint8Array: A.NativeUint8List});
+ hunkHelpers.setOrUpdateLeafTags({ArrayBuffer: true, ArrayBufferView: false, DataView: true, Float32Array: true, Float64Array: true, Int16Array: true, Int32Array: true, Int8Array: true, Uint16Array: true, Uint32Array: true, Uint8ClampedArray: true, CanvasPixelArray: true, Uint8Array: false});
+ A.NativeTypedArray.$nativeSuperclassTag = "ArrayBufferView";
+ A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin.$nativeSuperclassTag = "ArrayBufferView";
+ A._NativeTypedArrayOfDouble_NativeTypedArray_ListMixin_FixedLengthListMixin.$nativeSuperclassTag = "ArrayBufferView";
+ A.NativeTypedArrayOfDouble.$nativeSuperclassTag = "ArrayBufferView";
+ A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin.$nativeSuperclassTag = "ArrayBufferView";
+ A._NativeTypedArrayOfInt_NativeTypedArray_ListMixin_FixedLengthListMixin.$nativeSuperclassTag = "ArrayBufferView";
+ A.NativeTypedArrayOfInt.$nativeSuperclassTag = "ArrayBufferView";
+ })();
+ Function.prototype.call$1 = function(a) {
+ return this(a);
+ };
+ Function.prototype.call$0 = function() {
+ return this();
+ };
+ Function.prototype.call$2 = function(a, b) {
+ return this(a, b);
+ };
+ Function.prototype.call$3 = function(a, b, c) {
+ return this(a, b, c);
+ };
+ Function.prototype.call$4 = function(a, b, c, d) {
+ return this(a, b, c, d);
+ };
+ Function.prototype.call$1$1 = function(a) {
+ return this(a);
+ };
+ convertAllToFastObject(holders);
+ convertToFastObject($);
+ (function(callback) {
+ if (typeof document === "undefined") {
+ callback(null);
+ return;
+ }
+ if (typeof document.currentScript != "undefined") {
+ callback(document.currentScript);
+ return;
+ }
+ var scripts = document.scripts;
+ function onLoad(event) {
+ for (var i = 0; i < scripts.length; ++i) {
+ scripts[i].removeEventListener("load", onLoad, false);
+ }
+ callback(event.target);
+ }
+ for (var i = 0; i < scripts.length; ++i) {
+ scripts[i].addEventListener("load", onLoad, false);
+ }
+ })(function(currentScript) {
+ init.currentScript = currentScript;
+ var callMain = A.main;
+ if (typeof dartMainRunner === "function") {
+ dartMainRunner(callMain, []);
+ } else {
+ callMain([]);
+ }
+ });
+})();
diff --git a/pkgs/sse/test/web/index.html b/pkgs/sse/test/web/index.html
new file mode 100644
index 0000000..be26763
--- /dev/null
+++ b/pkgs/sse/test/web/index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>SSE Broadcast Channel Test</title>
+</head>
+
+<body>
+ <button type="button">Close Sink</button>
+ <script type="application/javascript" src="index.dart.js"></script>
+</body>
+
+</html>
diff --git a/pkgs/sse/tool/build_js.sh b/pkgs/sse/tool/build_js.sh
new file mode 100755
index 0000000..ef29b70
--- /dev/null
+++ b/pkgs/sse/tool/build_js.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+dart compile js --no-source-maps test/web/index.dart -o test/web/index.dart.js
diff --git a/pkgs/unified_analytics/.gitignore b/pkgs/unified_analytics/.gitignore
new file mode 100644
index 0000000..9377e38
--- /dev/null
+++ b/pkgs/unified_analytics/.gitignore
@@ -0,0 +1,14 @@
+# Files and directories created by pub.
+.dart_tool/
+.packages
+
+# Conventional directory for build outputs.
+build/
+
+# Omit committing pubspec.lock for library packages; see
+# https://dart.dev/guides/libraries/private-files#pubspeclock.
+pubspec.lock
+
+.vscode/
+coverage/
+*.DS_Store
diff --git a/pkgs/unified_analytics/CHANGELOG.md b/pkgs/unified_analytics/CHANGELOG.md
new file mode 100644
index 0000000..7e42cba
--- /dev/null
+++ b/pkgs/unified_analytics/CHANGELOG.md
@@ -0,0 +1,188 @@
+## 7.0.1
+- Fixed `UnsupportedError` thrown when Event.exception is called without providing a value for `args`.
+
+## 7.0.0
+- Added a required parameter `screen` to the `Event.devtoolsEvent` constructor.
+- Added an optional parameter `additionalMetrics` to the `Event.devtoolsEvent` constructor.
+- Added `CustomMetrics` class for unified_analytics clients to define custom event metrics.
+- Removed parameters `uiDurationMicros`, `rasterDurationMicros`, `shaderCompilationDurationMicros`,
+`traceEventCount`, `cpuSampleCount`, `cpuStackDepth`, `heapDiffObjectsBefore`, `heapDiffObjectsAfter`,
+`heapObjectsTotal`, `rootSetCount`, `rowCount`, `inspectorTreeControllerId`, `androidAppId`, `iosBundleId`
+from the `Event.devtoolsEvent` constructor.
+
+## 6.1.5
+- Remove any `data` entries with a null value in the `Event.exception` constructor.
+
+## 6.1.4
+
+- Fix formatting and remove dependency on `package:intl`.
+- Remove direct usage of `package:path` in favor of `package:file`.
+- Added `androidAppId` and `iosBundleId` to the `Event.devtoolsEvent` constructor.
+
+## 6.1.3
+
+- Require Dart 3.4.
+- Added `isWasm` parameter to the `Event.devtoolsEvent` constructor.
+- Added an optional parameter `data` to the `Event.exception` constructor.
+
+## 6.1.2
+
+- Avoid opening large telemetry log files to prevent out of memory errors.
+
+## 6.1.1
+
+- Fixed bug where calling `Analytics.send` could result in a `FileSystemException` when unable to write to a log file.
+
+## 6.1.0
+
+- Added new event constructor `Event.devtoolsEvent` for the single devtools event with a new enum value `DashEvent.devtoolsEvent`
+
+## 6.0.0
+
+- Consolidate `Session` functionality into `UserProperty` to prevent race condition crash where session logic crashed before initializing `UserProperty`
+- Get rid of `late` variables throughout implementation class, `AnalyticsImpl`
+- Any error events (`Event.analyticsException`) encountered within package will be sent when invoking `Analytics.close`; replacing `ErrorHandler` functionality
+- Exposing new method for `FakeAnalytics.sendPendingErrorEvents` to send error events on command
+- Added `Event.fromJson` static method to generate instance of `Event` from JSON
+- Remove unused parameters `measurementId` and `apiSecret` from the `Analytics.test` constructor
+- Remove `Analytics.test` factory constructor in favor of `Analytics.fake` static method to return a `FakeAnalytics` instance
+- Remove `FakeAnalytics` default constructor in favor of `Analytics.fake`
+
+## 5.8.8
+
+- [Bug fix](https://github.com/dart-lang/tools/issues/252) rewrite the other call site for the session file
+
+## 5.8.7
+
+- [Bug fix](https://github.com/dart-lang/tools/issues/252) to rewrite the `last_ping` key into the session json file
+
+## 5.8.6
+
+- Refactored session handler class to use the last modified timestamp as the last ping value to prevent writing to file with each send
+- Bumping intl package to 0.19.0 to fix version solving issue with flutter_tools
+
+## 5.8.5
+
+- Fix late initialization error for `Analytics.userProperty` [bug](https://github.com/dart-lang/tools/issues/238)
+
+## 5.8.4
+
+- Exporting all enums from [`enums.dart`](https://github.com/dart-lang/tools/blob/main/pkgs/unified_analytics/lib/src/enums.dart) through `lib/testing.dart`
+
+## 5.8.3
+
+- [Fix bug](https://github.com/flutter/flutter/issues/143792) when parsing session json file
+
+## 5.8.2
+
+- Added new event `Event.analyticsException` to track internal errors for this package
+- Redirecting the `Analytics.test` factory to return an instance of `FakeAnalytics`
+- Exposing new helper function that can be used to parse the Dart SDK version
+
+## 5.8.1
+
+- Refactor logic for `okToSend` and `shouldShowMessage`
+- Check devtools config file for legacy opt out status
+
+## 5.8.0
+
+- Fix template string for consent message
+- Add `enabledFeatures` to constructor to collect features enabled for each dash tool
+
+## 5.7.0
+
+- Added the `Event.commandUsageValues` constructor
+
+## 5.6.0
+
+- Added the `Event.timing` constructor
+
+## 5.5.0
+
+- Edit to the `Event.flutterCommandResult` constructor to add `commandHasTerminal`
+- Added timeout for `Analytics.setTelemetry` to prevent the clients from hanging
+- Added the `Event.appleUsageEvent` constructor
+- Added the `Event.exception` constructor
+
+## 5.4.0
+
+- Added the `Event.codeSizeAnalysis` constructor
+
+## 5.3.0
+
+- User property "host_os_version" added to provide detail version information about the host
+- User property "locale" added to provide language related information
+- User property "client_ide" (optional) added to provide the IDE used by the Dash tool using this package, if applicable
+- Added the `Event.flutterCommandResult` constructor
+
+## 5.2.0
+
+- Added the `Event.hotRunnerInfo` constructor
+
+## 5.1.0
+
+- Added the `Event.flutterBuildInfo` constructor
+
+## 5.0.0
+
+- Update to the latest version of `package:dart_flutter_team_lints`
+- Using internal futures list to store send events
+- Added the `Event.doctorValidatorResult` constructor
+
+## 4.0.1
+
+- Adding constant for the NoOpAnalytics instance client ID to enable clients to reference it in tests
+
+## 4.0.0
+
+- Enhanced `LogFileStats` data to include information about flutter channel counts and tool counts
+- Added new method to suppress telemetry collection temporarily for current invocation via `analytics.suppressTelemetry()`
+- Added `SurveyHandler` feature to `Analytics` instance to fetch available surveys from remote endpoint to display to users along with functionality to dismiss them
+- Surveys will be disabled for any users that have been opted out
+- Shipping `FakeAnalytics` for clients of this tool that need to ensure workflows are sending events in tests
+- Adding getter to `Analytics` instance to fetch the client ID being sent to GA4
+
+## 3.0.0
+
+- Allow latest package versions for `file` and `http`
+- Introducing new `Event` class that will standardize what event data can be sent with each event
+- Deprecating the `sendEvent` method in favor of the `send` method
+
+## 2.0.0
+
+- Refactoring `dateStamp` utility function to be defined in `utils.dart` instead of having static methods in `Initializer` and `ConfigHandler`
+- Remove the `pddFlag` now that the revisions to the PDD have been finalized to persist data in the log file and session json file
+- Opting out will now delete the contents of the CLIENT ID, session json, and log files; opting back in will regenerate them as events send
+- `enableAsserts` parameter added to constructors for `Analytics` to check body of POST request for Google Analytics 4 limitations
+- Now checking if write permissions are enabled for user's home directory, if not allowed, `NoOpAnalytics` returned by `Analytics` factory constructor
+
+## 1.1.0
+
+- Added a `okToSend` getter so that clients can easily and accurately check the state of the consent mechanism.
+- Initialize the config file with user opted out if user was opted out in legacy Flutter and Dart analytics
+
+## 1.0.1
+
+- Error handling on the `analytics.sendEvent(...)` method to silently error out and return a `500` http status code to let tools using this package know Google Analytics did not receive the event (all successful requests will have a status code of `2xx` provided by Google Analytics)
+
+## 1.0.0
+
+- Error handling functionality added to prevent malformed session json data from causing a crash
+- Creating a new analytics constructor to point to a test instance of Google Analytics for developers
+- Align supported tool list with PDD
+- Exposing a new instance method that will need to be invoked when a client has successfully shown the consent message to the user `clientShowedMessage()`
+- Adding and incrementing a tool's version will automatically use the current consent message version instead of incrementing by 1
+- Default constructor has disabled the usage of local log file and session json file until revisions have landed to the privacy document
+
+## 0.1.2
+
+- Implemented fake Google Analytics Client for `Analytics.test(...)` constructor; marked with visible for testing annotation
+
+## 0.1.1
+
+- Bumping intl package to 0.18.0 to fix version solving issue with flutter_tools
+- LogFileStats includes more information about how many events are persisted and total count of how many times each event was sent
+
+## 0.1.0
+
+- Initial version
diff --git a/pkgs/unified_analytics/LICENSE b/pkgs/unified_analytics/LICENSE
new file mode 100644
index 0000000..ac90031
--- /dev/null
+++ b/pkgs/unified_analytics/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2023, the Dart project authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/pkgs/unified_analytics/README.md b/pkgs/unified_analytics/README.md
new file mode 100644
index 0000000..4263cfb
--- /dev/null
+++ b/pkgs/unified_analytics/README.md
@@ -0,0 +1,17 @@
+[](https://github.com/dart-lang/tools/actions/workflows/unified_analytics.yml)
+[](https://pub.dev/packages/unified_analytics)
+[](https://pub.dev/packages/unified_analytics/publisher)
+
+## What's this?
+
+This package is intended to be used on Dart and Flutter related
+tooling only. It provides APIs to send events to Google Analytics using the
+Measurement Protocol.
+
+This is not intended to be general purpose or consumed by the community. It is
+responsible for toggling analytics collection for related tooling on each
+developer's machine.
+
+## Using this package
+
+Refer to the [usage guide](USAGE_GUIDE.md).
diff --git a/pkgs/unified_analytics/USAGE_GUIDE.md b/pkgs/unified_analytics/USAGE_GUIDE.md
new file mode 100644
index 0000000..ef5bbea
--- /dev/null
+++ b/pkgs/unified_analytics/USAGE_GUIDE.md
@@ -0,0 +1,202 @@
+This package is intended to be used on Dart and Flutter related tooling only.
+It provides APIs to send events to Google Analytics using the Measurement Protocol.
+
+## Usage
+
+To get started using this package, import at the entrypoint dart file and
+initialize with the required parameters.
+
+The example file shows an end-to-end usage guide for using this package and
+can be referred to here [unified_analytics_example.dart](example/unified_analytics_example.dart).
+
+**IMPORTANT**: It is best practice to close the http client connection when finished
+sending events, otherwise, you may notice that the dart process hangs on exit. The example below
+shows how to handle closing the connection via `analytics.close()` method.
+
+[Link to documentation for http client's close method](https://pub.dev/documentation/http/latest/http/Client-class.html)
+
+
+## Opting In and Out of Analytics Collection
+
+It will be important for each tool to expose a trivial method to
+disabling or enabling analytics collection. Based on how the user interacts
+with the tool, this can be done through the CLI, IDE, etc. The tool will
+then pass a boolean to an API exposed by the package as shown below.
+
+```dart
+// Begin by initializing the class
+final Analytics analytics = Analytics(...);
+
+// The boolean below simulates the user deciding to opt-out
+// of Analytics collection
+final bool status = false;
+
+// Call the method to pass the boolean
+analytics.setTelemetry(status);
+```
+
+## Displaying Consent Message to Users
+
+When a user first uses any tool with this package enabled, the tool using
+this package will need to ensure that the user has seen the consent message.
+The tool using this package should check with the `Analytics` instance
+by invoking the `shouldShowMessage` getter. When this getter returns
+`true`, this means that the user has not been enrolled into analytics
+collection yet. It is at this point that the tool using this package will
+invoke the `getConsentMessage` getter to return a string to share with the
+user (each tool will have their own method of displaying the message
+through cli stdout, popup modal, etc.). Once the message has been shown,
+the tool using this package will need to confirm to the `Analytics` instance
+that it has shown the message; it is at this point that the user has
+officially been onboarded to analytics collection.
+
+
+
+```dart
+// Begin by initializing the class near the entrypoint
+final Analytics analytics = Analytics(...);
+
+// This conditional should always run; the first time it is run, this
+// will return true since the consent message has never been shown
+if (analytics.shouldShowMessage) {
+
+ // Simulates displaying the message, this will vary from
+ // client to client; ie. stdout, popup in IDE, etc.
+ print(analytics.getConsentMessage);
+
+ // After receiving confirmation that the message has been
+ // displayed, invoking the below method will successfully
+ // onboard the tool into the config file and allow for
+ // events to be sent on the next creation of the analytics
+ // instance
+ analytics.clientShowedMessage();
+}
+```
+
+## Checking User Opt-In Status
+
+Some tools may need to know if the user has opted in for Analytics
+collection in order to enable additional functionality. The example below
+shows how to check the status.
+
+```dart
+// Begin by initializing the class
+final Analytics analytics = Analytics(...);
+
+// This getter will return a boolean showing the status;
+// print statement used for trivial usage example
+print('This user's status: ${analytics.telemetryEnabled}'); // true if opted-in
+```
+
+## Checking for New Versions of Consent Message
+
+In the event that the package consent messaging needs has been updated, an
+API has been exposed on an instance of `Analytics` that will notify the tool
+using this package whether to display the message again.
+
+```dart
+// Begin by initializing the class
+//
+// This is assuming that the tool has already been onboarded
+// and that the user has already seen the previous version of
+// the consent message
+final Analytics analytics = Analytics(...);
+
+
+// Much like the first example, if there is a new version of
+// the tools message that needs to be shown, use the same work
+// workflow
+if (analytics.shouldShowMessage) {
+
+ // Simulates displaying the message, this will vary from
+ // client to client; ie. stdout, popup in IDE, etc.
+ print(analytics.getConsentMessage);
+
+ // After receiving confirmation that the message has been
+ // displayed, invoking the below method will successfully
+ // onboard the tool into the config file and allow for
+ // events to be sent on the next creation of the analytics
+ // instance
+ analytics.clientShowedMessage();
+}
+```
+
+It is important to note events will not be sent if there is a new version of
+the consent message.
+
+## Developing Within `package:unified_analytics`
+
+### Adding new data classes
+
+#### User properties
+In Google Analytics, new data fields can be collected as user properties
+or events.
+
+User properties are key-value pairs that can be used to segment users. For example,
+the Flutter channel used. To request that a new user property
+be added, file an issue [using this template](https://github.com/dart-lang/tools/issues/new?template=unified_analytics_user_property.yml).
+
+To add a new user property, add a new property to the `UserProperty` class
+in the [`user_property.dart` file](./lib/src/user_property.dart).
+
+#### Events
+Events are actions that the user, or tool, performs. In Google Analytics,
+events can have associated data. This event data is stored
+in key-value pairs.
+
+To request new events, or event data, file an issue
+[using this template](https://github.com/dart-lang/tools/issues/new?template=unified_analytics_event.yml).
+
+To add a new event, create a new field in the `DashEvent` enum (if necessary) in
+the [`enums.dart` file](./lib/src/enums.dart).
+
+Then, add event data, create a new constructor for the `Event` class
+in the [`event.dart` file](./lib/src/event.dart).
+
+
+### Testing event collection
+
+When contributing to this package, if the developer needs to verify that
+events have been sent, the developer should the use development constructor
+so that the events being sent are not going into the production instance.
+
+```dart
+final Analytics analytics = Analytics.development(...);
+```
+
+Reach out to maintainers to get access to the test Google Analytics endpoint.
+
+## Advanced Usage: Querying Locally Persisted Logs
+
+This package enables tools to persist the events that have been sent
+to Google Analytics for logging by default. This can be very helpful if
+tools would like to understand the user's activity level across all
+related tooling. For example, if querying the locally persisted logs
+shows that the user has not been active for N number of days, a tool that
+works within an IDE can prompt the user with a survey to understand why their
+level of activity has dropped.
+
+The snippet below shows how to invoke the query and a sample response.
+
+```dart
+// Begin by initializing the class
+final Analytics analytics = Analytics(...);
+
+// Printing the query results returns json formatted
+// string to view; data can also be accessed through
+// [LogFileStats] getters
+print(analytics.logFileStats());
+```
+Refer to the `LogFileStats` instance [variables](lib/src/log_handler.dart) for details on the result.
+
+Explanation of the each key above
+
+- startDateTime: the earliest event that was sent
+- minsFromStartDateTime: the number of minutes elapsed since the earliest message
+- endDateTime: the latest, most recent event that was sent
+- minsFromEndDateTime: the number of minutes elapsed since the latest message
+- sessionCount: count of sessions; sessions have a minimum time of 30 minutes
+- flutterChannelCount: count of flutter channels (can be 0 if developer is a Dart dev only)
+- toolCount: count of the Dart and Flutter tools sending analytics
+- recordCount: count of the total number of events in the log file
+- eventCount: counts each unique event and how many times they occurred in the log file
\ No newline at end of file
diff --git a/pkgs/unified_analytics/analysis_options.yaml b/pkgs/unified_analytics/analysis_options.yaml
new file mode 100644
index 0000000..746ad64
--- /dev/null
+++ b/pkgs/unified_analytics/analysis_options.yaml
@@ -0,0 +1,10 @@
+# This file configures the static analysis results for your project (errors,
+# warnings, and lints).
+
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+linter:
+ rules:
+ - avoid_catches_without_on_clauses
+ - prefer_final_in_for_each
+ - prefer_final_locals
diff --git a/pkgs/unified_analytics/coverage_runner.sh b/pkgs/unified_analytics/coverage_runner.sh
new file mode 100755
index 0000000..4043614
--- /dev/null
+++ b/pkgs/unified_analytics/coverage_runner.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Generate `coverage/lcov.info` file
+flutter test --coverage
+
+# Generate HTML report
+# Note: on macOS you need to have lcov installed on your system (`brew install lcov`) to use this:
+genhtml coverage/lcov.info -o coverage/html
+
+# Open the report
+open coverage/html/index.html
diff --git a/pkgs/unified_analytics/example/sample_rate.dart b/pkgs/unified_analytics/example/sample_rate.dart
new file mode 100644
index 0000000..51b0cdb
--- /dev/null
+++ b/pkgs/unified_analytics/example/sample_rate.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:unified_analytics/src/utils.dart';
+
+/// The purpose of this example file is to demonstrate the sampling
+/// rate functionality from the survey handler.
+///
+/// It defines a `remoteUniqueId` that subs in for a real survey's unique
+/// ID that is hosted in the remote json file.
+///
+/// Begin the simulation by setting the `testSampleRate` and `iterations`
+/// variables, where `iterations` simulates real users and `testSampleRate`
+/// represents a fraction of how many people should be sampled.
+///
+/// In this example, we have set the `testSampleRate` to `0.3`, meaning we want
+/// sample 30% of users, and `iterations` to `10,000`, which simulates `10,000`
+/// users.
+///
+/// Running the script with predefined seed of `123` will
+/// generate the below `stdout`
+/// ```
+/// Test sample rate = 0.3
+/// Number of iterations = 10000
+/// ---
+///
+/// Count of iterations sampled (successes) = 3046
+/// Actual sample rate = 0.3046
+/// ---
+///
+/// Runtime = 8ms
+/// ```
+///
+/// The actual results yielded 3,046 people selected for a rate
+/// of `30.46%` which is about the `30%` defined in `testSampleRate`.
+void main() {
+ // Seed has been set to replicate results
+ //
+ // Test with your own seed and alter other parameters
+ // as needed
+ final uuidGenerator = Uuid(123);
+
+ // Randomly generate an ID that will simulate being used for
+ // a given survey
+ final remoteUniqueId = uuidGenerator.generateV4();
+
+ // Define a sampling rate that we would like to test
+ //
+ // Setting 0.3 means any generated doubles less than or
+ // equal to 0.3 results in a survey getting delievered
+ const testSampleRate = 0.3;
+
+ // Define how many iterations to run, each iteration can
+ // be thought of as a developer using a dash tool
+ const iterations = 10000;
+
+ // Initializing a counter that will count the number of
+ // iterations that were below the sampling rate
+ var count = 0;
+
+ final start = DateTime.now();
+ for (var i = 0; i < iterations; i++) {
+ // Each newly generated ID is simulating a unique
+ // developer's CLIENT ID that is persisted on their disk
+ final clientId = uuidGenerator.generateV4();
+
+ // Generate a double that will be compared against the sampleRate
+ final generatedDouble = sampleRate(remoteUniqueId, clientId);
+
+ // Count successes if the generated double is less than our
+ // testing sample rate
+ if (generatedDouble <= testSampleRate) {
+ count++;
+ }
+ }
+ final end = DateTime.now();
+
+ print('''
+Test sample rate = $testSampleRate
+Number of iterations = $iterations
+---
+
+Count of iterations sampled (successes) = $count
+Actual sample rate = ${(count / iterations).toStringAsFixed(4)}
+---
+
+Runtime = ${end.difference(start).inMilliseconds}ms
+''');
+}
diff --git a/pkgs/unified_analytics/example/serving_surveys.dart b/pkgs/unified_analytics/example/serving_surveys.dart
new file mode 100644
index 0000000..d56339e
--- /dev/null
+++ b/pkgs/unified_analytics/example/serving_surveys.dart
@@ -0,0 +1,165 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:clock/clock.dart';
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+
+import 'package:unified_analytics/src/constants.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/src/survey_handler.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+/// This example code is intended to only be used as guidance for
+/// clients using this package. Clients using this package should avoid
+/// the use of the [Analytics.fake] static method.
+///
+/// It was used in this example file so that the real [FileSystem] was swapped
+/// out for a [MemoryFileSystem] so that repeated runs of this script yield
+/// the same results.
+void main() async {
+ late final MemoryFileSystem fs;
+ late final Analytics analytics;
+ late final Directory home;
+ // We need to initialize with a fake clock since the surveys have
+ // a period of time they are valid for
+ await withClock(Clock.fixed(DateTime(2023, 3, 3, 12, 0)), () async {
+ // Use a memory file system to repeatedly run this example
+ // file with the test instance
+ fs = MemoryFileSystem(style: FileSystemStyle.posix);
+ home = fs.directory('home');
+ home.createSync();
+
+ // The purpose of `initialAnalytics` is so that the tool is able to
+ // send events after its first run; this instance won't be used below
+ //
+ // ignore: invalid_use_of_visible_for_testing_member
+ final initialAnalytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: home,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ );
+ // The below command allows `DashTool.flutterTool` to send telemetry
+ initialAnalytics.clientShowedMessage();
+
+ // ignore: invalid_use_of_visible_for_testing_member
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: home,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: home
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName),
+ initializedSurveys: [
+ Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 5, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: [],
+ buttonList: [
+ SurveyButton(
+ buttonText: 'View Survey',
+ action: 'accept',
+ promptRemainsVisible: false,
+ url: 'http://example.com',
+ ),
+ SurveyButton(
+ buttonText: 'More Info',
+ action: 'snooze',
+ promptRemainsVisible: true,
+ url: 'http://example2.com',
+ ),
+ SurveyButton(
+ buttonText: 'Dismiss Survey',
+ action: 'dismiss',
+ promptRemainsVisible: false,
+ )
+ ],
+ ),
+ ],
+ ));
+ });
+
+ // Each client of this package will be able to fetch all of
+ // the available surveys with the below method
+ //
+ // Sample rate will be applied automatically; it also won't
+ // fetch any surveys in the snooze period or if they have
+ // been dismissed
+ final surveyList = await analytics.fetchAvailableSurveys();
+ assert(surveyList.length == 1);
+
+ // Grab the first and only survey to simulate displaying it to a user
+ final survey = surveyList.first;
+ print('Simulating displaying the survey with a print below:');
+ print('Survey id: ${survey.uniqueId}\n');
+
+ // Immediately after displaying the survey, the method below
+ // should be run so that no other clients using this tool will show
+ // it at the same time
+ //
+ // It will "snoozed" when the below is run as well as reported to
+ // Google Analytics 4 that this survey was shown
+ analytics.surveyShown(survey);
+
+ // Get the file where this is persisted to show it getting updated
+ final persistedSurveyFile = home
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName);
+ print('The contents of the json file '
+ 'after invoking `analytics.surveyShown(survey);`');
+ print('${persistedSurveyFile.readAsStringSync()}\n');
+
+ // Change the index below to decide which button to simulate pressing
+ //
+ // 0 - accept
+ // 1 - snooze
+ // 2 - dismiss
+ final selectedButtonIndex = 1;
+ assert([0, 1, 2].contains(selectedButtonIndex));
+
+ // Get the survey button by index that will need to be passed along with
+ // the survey to simulate an interaction with the survey
+ final selectedSurveyButton = survey.buttonList[selectedButtonIndex];
+ print('The simulated button pressed was: '
+ '"${selectedSurveyButton.buttonText}" '
+ '(action = ${selectedSurveyButton.action})\n');
+
+ // The below method will handle whatever action the button
+ analytics.surveyInteracted(
+ survey: survey,
+ surveyButton: selectedSurveyButton,
+ );
+
+ // Conditional to check if there is a URl to route to
+ if (selectedSurveyButton.url != null) {
+ print('***This button also has a survey URL link '
+ 'to route to at "${selectedSurveyButton.url}"***\n');
+ }
+
+ // Conditional to check what simulating a popup to stay up
+ if (selectedSurveyButton.promptRemainsVisible) {
+ print('***This button has its promptRemainsVisible field set to `true` '
+ 'so this simulates what seeing a pop up again would look like***\n');
+ }
+
+ print('The contents of the json file '
+ 'after invoking '
+ '`analytics.surveyInteracted(survey: survey, '
+ 'surveyButton: selectedSurveyButton);`');
+ print('${persistedSurveyFile.readAsStringSync()}\n');
+
+ // Demonstrating that the survey doesn't get returned again
+ print('Attempting to fetch surveys again will result in an empty list');
+ print(await analytics.fetchAvailableSurveys());
+}
diff --git a/pkgs/unified_analytics/example/unified_analytics_example.dart b/pkgs/unified_analytics/example/unified_analytics_example.dart
new file mode 100644
index 0000000..e0ddaff
--- /dev/null
+++ b/pkgs/unified_analytics/example/unified_analytics_example.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:unified_analytics/unified_analytics.dart';
+
+// Globally instantiate the analytics class at the entry
+// point of the tool
+//
+// Development constructor used here so we don't push
+// to production when running
+final Analytics analytics = Analytics.development(
+ tool: DashTool.flutterTool,
+ flutterChannel: 'ey-test-channel',
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ clientIde: 'VSCode',
+ dartVersion: 'Dart 2.19.0',
+ // This can be set to true while testing to validate
+ // against GA4 usage limitations (character limits, etc.)
+ enableAsserts: false,
+ enabledFeatures: 'feature-1,feature-2',
+);
+
+// Timing a process and sending the event
+void main() async {
+ final start = DateTime.now();
+
+ // Each client using this package will have it's own
+ // method to show the message but the below is a trivial
+ // example of how to properly initialize the analytics instance
+ if (analytics.shouldShowMessage) {
+ // Simulates displaying the message, this will vary from
+ // client to client; ie. stdout, popup in IDE, etc.
+ print(analytics.getConsentMessage);
+
+ // After receiving confirmation that the message has been
+ // displayed, invoking the below method will successfully
+ // onboard the tool into the config file and allow for
+ // events to be sent on the next creation of the analytics
+ // instance
+ //
+ // The rest of the example below assumes that the tool has
+ // already been onboarded in a previous run
+ analytics.clientShowedMessage();
+ }
+
+ print('Current user ${analytics.clientId} '
+ 'is opted in: ${analytics.telemetryEnabled}');
+
+ // Example of long running process
+ await Future<void>.delayed(const Duration(milliseconds: 100));
+
+ // Calculate the metric to send
+ final runTime = DateTime.now().difference(start).inMilliseconds;
+
+ // Create the event that will be sent for the hot reload time
+ // as an example
+ final hotReloadEvent = Event.hotReloadTime(timeMs: runTime);
+
+ // Make a call to the [Analytics] api to send the data
+ analytics.send(hotReloadEvent);
+
+ // Close the client connection on exit
+ await analytics.close();
+}
diff --git a/pkgs/unified_analytics/lib/src/analytics.dart b/pkgs/unified_analytics/lib/src/analytics.dart
new file mode 100644
index 0000000..cc8b4bc
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/analytics.dart
@@ -0,0 +1,857 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' as io;
+
+import 'package:file/file.dart';
+import 'package:file/local.dart';
+import 'package:file/memory.dart';
+import 'package:http/http.dart';
+import 'package:meta/meta.dart';
+
+import 'asserts.dart';
+import 'config_handler.dart';
+import 'constants.dart';
+import 'enums.dart';
+import 'event.dart';
+import 'ga_client.dart';
+import 'initializer.dart';
+import 'log_handler.dart';
+import 'survey_handler.dart';
+import 'user_property.dart';
+import 'utils.dart';
+
+abstract class Analytics {
+ /// The default factory constructor that will return an implementation
+ /// of the [Analytics] abstract class using the [LocalFileSystem].
+ ///
+ /// If [enableAsserts] is set to `true`, then asserts for GA4 limitations
+ /// will be enabled.
+ ///
+ /// [flutterChannel] and [flutterVersion] are nullable in case the client
+ /// using this package is unable to resolve those values.
+ ///
+ /// An optional parameter [clientIde] is also available for dart and flutter
+ /// tooling that are running from IDEs can be resolved. Such as "VSCode"
+ /// running the flutter-tool.
+ ///
+ /// [enabledFeatures] is also an optional field that can be added to collect
+ /// any features that are enabled for a user. For example,
+ /// "enable-linux-desktop,cli-animations" are two features that can be enabled
+ /// for the flutter-tool.
+ factory Analytics({
+ required DashTool tool,
+ required String dartVersion,
+ String? flutterChannel,
+ String? flutterVersion,
+ String? clientIde,
+ String? enabledFeatures,
+ bool enableAsserts = false,
+ }) {
+ // Create the instance of the file system so clients don't need
+ // resolve on their own
+ const FileSystem fs = LocalFileSystem();
+
+ // Ensure that the home directory has permissions enabled to write
+ final homeDirectory = getHomeDirectory(fs);
+ if (homeDirectory == null ||
+ !checkDirectoryForWritePermissions(homeDirectory)) {
+ return const NoOpAnalytics();
+ }
+
+ // Resolve the OS using dart:io
+ final DevicePlatform platform;
+ if (io.Platform.operatingSystem == 'linux') {
+ platform = DevicePlatform.linux;
+ } else if (io.Platform.operatingSystem == 'macos') {
+ platform = DevicePlatform.macos;
+ } else {
+ platform = DevicePlatform.windows;
+ }
+
+ // Create the instance of the GA Client which will create
+ // an [http.Client] to send requests
+ final gaClient = GAClient(
+ measurementId: kGoogleAnalyticsMeasurementId,
+ apiSecret: kGoogleAnalyticsApiSecret,
+ );
+
+ final firstRun = runInitialization(homeDirectory: homeDirectory);
+
+ return AnalyticsImpl(
+ tool: tool,
+ homeDirectory: homeDirectory,
+ flutterChannel: flutterChannel,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ platform: platform,
+ toolsMessageVersion: kToolsMessageVersion,
+ fs: fs,
+ gaClient: gaClient,
+ surveyHandler: SurveyHandler(
+ dismissedSurveyFile: homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName),
+ ),
+ enableAsserts: enableAsserts,
+ clientIde: clientIde,
+ enabledFeatures: enabledFeatures,
+ firstRun: firstRun,
+ );
+ }
+
+ /// Factory constructor to return the [AnalyticsImpl] class with
+ /// Google Analytics credentials that point to a test instance and
+ /// not the production instance where live data will be sent.
+ ///
+ /// By default, [enableAsserts] is set to `true` to check against
+ /// GA4 limitations.
+ ///
+ /// [flutterChannel] and [flutterVersion] are nullable in case the client
+ /// using this package is unable to resolve those values.
+ factory Analytics.development({
+ required DashTool tool,
+ required String dartVersion,
+ String? flutterChannel,
+ String? flutterVersion,
+ String? clientIde,
+ String? enabledFeatures,
+ bool enableAsserts = true,
+ }) {
+ // Create the instance of the file system so clients don't need
+ // resolve on their own
+ const FileSystem fs = LocalFileSystem();
+
+ // Ensure that the home directory has permissions enabled to write
+ final homeDirectory = getHomeDirectory(fs);
+ if (homeDirectory == null) {
+ throw Exception('Unable to determine the home directory, '
+ 'ensure it is available in the environment');
+ }
+ if (!checkDirectoryForWritePermissions(homeDirectory)) {
+ throw Exception('Permissions error on the home directory!');
+ }
+
+ // Resolve the OS using dart:io
+ final DevicePlatform platform;
+ if (io.Platform.operatingSystem == 'linux') {
+ platform = DevicePlatform.linux;
+ } else if (io.Platform.operatingSystem == 'macos') {
+ platform = DevicePlatform.macos;
+ } else {
+ platform = DevicePlatform.windows;
+ }
+
+ // Credentials defined below for the test Google Analytics instance
+ const kTestMeasurementId = 'G-N1NXG28J5B';
+ const kTestApiSecret = '4yT8__oER3Cd84dtx6r-_A';
+
+ // Create the instance of the GA Client which will create
+ // an [http.Client] to send requests
+ final gaClient = GAClient(
+ measurementId: kTestMeasurementId,
+ apiSecret: kTestApiSecret,
+ );
+
+ final firstRun = runInitialization(homeDirectory: homeDirectory);
+
+ return AnalyticsImpl(
+ tool: tool,
+ homeDirectory: homeDirectory,
+ flutterChannel: flutterChannel,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ platform: platform,
+ toolsMessageVersion: kToolsMessageVersion,
+ fs: fs,
+ gaClient: gaClient,
+ surveyHandler: SurveyHandler(
+ dismissedSurveyFile: homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName),
+ ),
+ enableAsserts: enableAsserts,
+ clientIde: clientIde,
+ enabledFeatures: enabledFeatures,
+ firstRun: firstRun,
+ );
+ }
+
+ /// The shared identifier for Flutter and Dart related tooling using
+ /// package:unified_analytics.
+ String get clientId;
+
+ /// Retrieves the consent message to prompt users with on first
+ /// run or when the message has been updated.
+ String get getConsentMessage;
+
+ /// Returns true if it is OK to send an analytics message. Do not cache,
+ /// as this depends on factors that can change, such as the configuration
+ /// file contents.
+ bool get okToSend;
+
+ /// Returns a map object with all of the tools that have been parsed
+ /// out of the configuration file.
+ Map<String, ToolInfo> get parsedTools;
+
+ /// Boolean that lets the client know if they should display the message.
+ bool get shouldShowMessage;
+
+ /// Boolean indicating whether or not telemetry is enabled.
+ bool get telemetryEnabled;
+
+ /// Returns a map representation of the [UserProperty] for the [Analytics]
+ /// instance.
+ ///
+ /// This is what will get sent to Google Analytics with every request.
+ Map<String, Map<String, Object?>> get userPropertyMap;
+
+ /// Method to be invoked by the client using this package to confirm
+ /// that the client has shown the message and that it can be added to
+ /// the config file and start sending events the next time it starts up.
+ void clientShowedMessage();
+
+ /// Call this method when the tool using this package is closed.
+ ///
+ /// Prevents the tool from hanging when if there are still requests
+ /// that need to be sent off.
+ ///
+ /// Providing [delayDuration] in milliseconds will allow the instance
+ /// to wait the provided time before closing the http connection. Keeping
+ /// the connection open for some time will allow any pending events that
+ /// are waiting to be sent to the Google Analytics server. Default value
+ /// of 250 ms applied.
+ Future<void> close({int delayDuration = kDelayDuration});
+
+ /// Method to fetch surveys from the endpoint [kContextualSurveyUrl].
+ ///
+ /// Any survey that is returned by this method has already passed
+ /// the survey conditions specified in the remote survey metadata file.
+ ///
+ /// If the method returns an empty list, then there are no surveys to be
+ /// shared with the user.
+ Future<List<Survey>> fetchAvailableSurveys();
+
+ /// Query the persisted event data stored on the user's machine.
+ ///
+ /// Returns null if there are no persisted logs.
+ LogFileStats? logFileStats();
+
+ /// Send preconfigured events using specific named constructors
+ /// on the [Event] class.
+ ///
+ /// Example
+ /// ```dart
+ /// analytics.send(Event.memory(periodSec: 123));
+ /// ```
+ void send(Event event);
+
+ /// Pass a boolean to either enable or disable telemetry and make
+ /// the necessary changes in the persisted configuration file.
+ ///
+ /// Setting the telemetry status will also send an event to GA
+ /// indicating the latest status of the telemetry from [reportingBool].
+ Future<void> setTelemetry(bool reportingBool);
+
+ /// Calling this will result in telemetry collection being suppressed for
+ /// the current invocation.
+ ///
+ /// If you would like to permanently disable telemetry
+ /// collection use:
+ ///
+ /// ```dart
+ /// analytics.setTelemetry(false)
+ /// ```
+ void suppressTelemetry();
+
+ /// Method to run after interacting with a [Survey] instance.
+ ///
+ /// Pass a [Survey] instance which can be retrieved from
+ /// [Analytics.fetchAvailableSurveys].
+ ///
+ /// [surveyButton] is the button that was interacted with by the user.
+ void surveyInteracted({
+ required Survey survey,
+ required SurveyButton surveyButton,
+ });
+
+ /// Method to be called after a survey has been shown to the user.
+ ///
+ /// Calling this will snooze the survey so it won't be shown immediately.
+ ///
+ /// The snooze period is defined by the [Survey.snoozeForMinutes] field.
+ void surveyShown(Survey survey);
+
+ /// Returns an instance of [FakeAnalytics] which can be used in tests to check
+ /// for certain [Event] instances within [FakeAnalytics.sentEvents].
+ @visibleForTesting
+ static FakeAnalytics fake({
+ required DashTool tool,
+ required Directory homeDirectory,
+ required String dartVersion,
+ required MemoryFileSystem fs,
+ String? flutterChannel,
+ String? flutterVersion,
+ String? clientIde,
+ String? enabledFeatures,
+ SurveyHandler? surveyHandler,
+ GAClient? gaClient,
+ DevicePlatform platform = DevicePlatform.linux,
+ int toolsMessageVersion = kToolsMessageVersion,
+ String toolsMessage = kToolsMessage,
+ bool enableAsserts = true,
+ }) {
+ final firstRun = runInitialization(homeDirectory: homeDirectory);
+
+ return FakeAnalytics._(
+ tool: tool,
+ homeDirectory: homeDirectory,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ platform: platform,
+ fs: fs,
+ surveyHandler: surveyHandler ??
+ FakeSurveyHandler.fromList(
+ dismissedSurveyFile: homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName),
+ initializedSurveys: [],
+ ),
+ gaClient: gaClient ?? const FakeGAClient(),
+ clientIde: clientIde,
+ enabledFeatures: enabledFeatures,
+ firstRun: firstRun,
+ enableAsserts: enableAsserts,
+ );
+ }
+}
+
+class AnalyticsImpl implements Analytics {
+ final DashTool tool;
+ final FileSystem fs;
+ final int toolsMessageVersion;
+ final ConfigHandler _configHandler;
+ final GAClient _gaClient;
+ final SurveyHandler _surveyHandler;
+ final File _clientIdFile;
+ final UserProperty _userProperty;
+ final LogHandler _logHandler;
+
+ /// Tells the client if they need to show a message to the
+ /// user; this will return true if it is the first time the
+ /// package is being used for a developer or if the consent
+ /// message has been updated by the package.
+ bool _showMessage = false;
+
+ /// When set to `true`, various assert statements will be enabled
+ /// to ensure usage of this class is within GA4 limitations.
+ final bool _enableAsserts;
+
+ /// Telemetry suppression flag that is set via [Analytics.suppressTelemetry].
+ bool _telemetrySuppressed = false;
+
+ /// Indicates if this is the first run for a given tool.
+ bool _firstRun = false;
+
+ /// The list of futures that will contain all of the send events
+ /// from the [GAClient].
+ final _futures = <Future<Response>>[];
+
+ /// Internal value for the client id which will be lazily loaded.
+ String? _clientId;
+
+ /// Internal collection of [Event]s that have been sent
+ /// for errors encountered within package:unified_analytics.
+ ///
+ /// Stores each of the events that have been sent to GA4 so that the
+ /// same error doesn't get sent twice.
+ final Set<Event> _sentErrorEvents = {};
+
+ AnalyticsImpl({
+ required this.tool,
+ required Directory homeDirectory,
+ required String? flutterChannel,
+ required String? flutterVersion,
+ required String? clientIde,
+ required String? enabledFeatures,
+ required String dartVersion,
+ required DevicePlatform platform,
+ required this.toolsMessageVersion,
+ required this.fs,
+ required GAClient gaClient,
+ required SurveyHandler surveyHandler,
+ required bool enableAsserts,
+ required bool firstRun,
+ }) : _gaClient = gaClient,
+ _surveyHandler = surveyHandler,
+ _enableAsserts = enableAsserts,
+ _clientIdFile = homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kClientIdFileName),
+ _userProperty = UserProperty(
+ sessionFile: homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kSessionFileName),
+ flutterChannel: flutterChannel,
+ host: platform.label,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ tool: tool.label,
+ // We truncate this to a maximum of 36 characters since this can
+ // a very long string for some operating systems
+ hostOsVersion:
+ truncateStringToLength(io.Platform.operatingSystemVersion, 36),
+ locale: io.Platform.localeName,
+ clientIde: clientIde,
+ enabledFeatures: enabledFeatures,
+ ),
+ _configHandler = ConfigHandler(
+ homeDirectory: homeDirectory,
+ configFile: homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kConfigFileName),
+ ),
+ _logHandler = LogHandler(
+ logFile: homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kLogFileName),
+ ) {
+ // This initializer class will let the instance know
+ // if it was the first run; if it is, nothing will be sent
+ // on the first run
+ if (firstRun) {
+ _showMessage = true;
+ _firstRun = true;
+ } else {
+ _showMessage = false;
+ _firstRun = false;
+ }
+
+ // Check if the tool has already been onboarded, and if it
+ // has, check if the latest message version is greater to
+ // prompt the client to show a message
+ //
+ // If the tool has not been added to the config file, then
+ // we will show the message as well
+ final currentVersion =
+ _configHandler.parsedTools[tool.label]?.versionNumber ?? -1;
+ if (currentVersion < toolsMessageVersion) {
+ _showMessage = true;
+
+ // If the message version has been updated, it will be considered
+ // as if it was a first run and any events attempting to get sent
+ // will be blocked
+ _firstRun = true;
+ }
+ }
+
+ @override
+ String get clientId {
+ if (!_clientIdFile.existsSync()) {
+ createClientIdFile(clientIdFile: _clientIdFile);
+ }
+ _clientId ??= _clientIdFile.readAsStringSync();
+
+ return _clientId!;
+ }
+
+ @override
+ String get getConsentMessage {
+ // The command to swap in the consent message
+ final commandString =
+ tool == DashTool.flutterTool || tool == DashTool.devtools
+ ? 'flutter'
+ : 'dart';
+
+ return kToolsMessage
+ .replaceAll('{{ toolDescription }}', tool.description)
+ .replaceAll('{{ toolName }}', commandString);
+ }
+
+ /// Checking the [telemetryEnabled] boolean reflects what the
+ /// config file reflects.
+ ///
+ /// Checking the [_showMessage] boolean indicates if the consent
+ /// message has been shown for the user, this boolean is set to `true`
+ /// when the tool using this package invokes the [clientShowedMessage]
+ /// method.
+ ///
+ /// If the user has suppressed telemetry [_telemetrySuppressed] will
+ /// return `true` to prevent events from being sent for current invocation.
+ ///
+ /// Checking if it is the first time a tool is running with this package
+ /// as indicated by [_firstRun].
+ @override
+ bool get okToSend =>
+ telemetryEnabled && !_showMessage && !_telemetrySuppressed && !_firstRun;
+
+ @override
+ Map<String, ToolInfo> get parsedTools => _configHandler.parsedTools;
+
+ @override
+ bool get shouldShowMessage => _showMessage;
+
+ @override
+ bool get telemetryEnabled => _configHandler.telemetryEnabled;
+
+ @override
+ Map<String, Map<String, Object?>> get userPropertyMap =>
+ _userProperty.preparePayload();
+
+ @override
+ void clientShowedMessage() {
+ // Check the tool needs to be added to the config file
+ if (!_configHandler.parsedTools.containsKey(tool.label)) {
+ _configHandler.addTool(
+ tool: tool.label,
+ versionNumber: toolsMessageVersion,
+ );
+ }
+
+ // When the tool already exists but the consent message version
+ // has been updated
+ if (_configHandler.parsedTools[tool.label]!.versionNumber <
+ toolsMessageVersion) {
+ _configHandler.incrementToolVersion(
+ tool: tool.label,
+ newVersionNumber: toolsMessageVersion,
+ );
+ }
+ _showMessage = false;
+ }
+
+ @override
+ Future<void> close({int delayDuration = kDelayDuration}) async {
+ // Collect any errors encountered and send
+ _sendPendingErrorEvents();
+
+ await Future.wait(_futures).timeout(
+ Duration(milliseconds: delayDuration),
+ onTimeout: () => [],
+ );
+ _gaClient.close();
+ }
+
+ @override
+ Future<List<Survey>> fetchAvailableSurveys() async {
+ final surveysToShow = <Survey>[];
+ if (!okToSend) return surveysToShow;
+
+ final logFileStats = _logHandler.logFileStats();
+
+ // Call for surveys that have already been dismissed from
+ // persisted survey ids on disk
+ final persistedSurveyMap = _surveyHandler.fetchPersistedSurveys();
+
+ for (final survey in await _surveyHandler.fetchSurveyList()) {
+ // If the survey has listed the tool running this package in the exclude
+ // list, it will not be returned
+ if (survey.excludeDashToolList.contains(tool)) continue;
+
+ // Apply the survey's sample rate; if the generated value from
+ // the client id and survey's uniqueId are less, it will not get
+ // sent to the user
+ if (survey.samplingRate < sampleRate(clientId, survey.uniqueId)) {
+ continue;
+ }
+
+ // If the survey has been permanently dismissed or has temporarily
+ // been snoozed, skip it
+ if (surveySnoozedOrDismissed(survey, persistedSurveyMap)) continue;
+
+ // Counter to check each survey condition, if all are met, then
+ // this integer will be equal to the number of conditions in
+ // [Survey.conditionList]
+ var conditionsMet = 0;
+ if (logFileStats != null) {
+ for (final condition in survey.conditionList) {
+ // Retrieve the value from the [LogFileStats] with
+ // the label provided in the condtion
+ final logFileStatsValue =
+ logFileStats.getValueByString(condition.field);
+
+ if (logFileStatsValue == null) continue;
+
+ switch (condition.operatorString) {
+ case '>=':
+ if (logFileStatsValue >= condition.value) conditionsMet++;
+ case '<=':
+ if (logFileStatsValue <= condition.value) conditionsMet++;
+ case '>':
+ if (logFileStatsValue > condition.value) conditionsMet++;
+ case '<':
+ if (logFileStatsValue < condition.value) conditionsMet++;
+ case '==':
+ if (logFileStatsValue == condition.value) conditionsMet++;
+ case '!=':
+ if (logFileStatsValue != condition.value) conditionsMet++;
+ }
+ }
+ }
+
+ if (conditionsMet == survey.conditionList.length) {
+ surveysToShow.add(survey);
+ }
+ }
+
+ return surveysToShow;
+ }
+
+ @override
+ LogFileStats? logFileStats() => _logHandler.logFileStats();
+
+ @override
+ void send(Event event) {
+ if (!okToSend) return;
+
+ // Construct the body of the request
+ final body = generateRequestBody(
+ clientId: clientId,
+ eventName: event.eventName,
+ eventData: event.eventData,
+ userProperty: _userProperty,
+ );
+
+ if (_enableAsserts) checkBody(body);
+
+ _logHandler.save(data: body);
+
+ final gaClientFuture = _gaClient.sendData(body);
+ _futures.add(gaClientFuture);
+ gaClientFuture.whenComplete(() => _futures.remove(gaClientFuture));
+ }
+
+ @override
+ Future<void> setTelemetry(bool reportingBool) {
+ _configHandler.setTelemetry(reportingBool);
+
+ // Creation of the [Event] for opting out
+ final collectionEvent =
+ Event.analyticsCollectionEnabled(status: reportingBool);
+
+ // The body of the request that will be sent to GA4
+ final Map<String, Object?> body;
+
+ if (reportingBool) {
+ // Recreate the session and client id file; no need to
+ // recreate the log file since it will only receives events
+ // to persist from events sent
+ createClientIdFile(clientIdFile: _clientIdFile);
+ createSessionFile(sessionFile: _userProperty.sessionFile);
+
+ // Reread the client ID string so an empty string is not being
+ // sent to GA4 since the persisted files are cleared when a user
+ // decides to opt out of telemetry collection
+ _clientId = _clientIdFile.readAsStringSync();
+
+ // We must construct the body at this point after we have read in the
+ // new client id string that was generated
+ body = generateRequestBody(
+ clientId: clientId,
+ eventName: collectionEvent.eventName,
+ eventData: collectionEvent.eventData,
+ userProperty: _userProperty,
+ );
+
+ _logHandler.save(data: body);
+ } else {
+ // Construct the body of the request to signal
+ // telemetry status toggling
+ body = generateRequestBody(
+ clientId: clientId,
+ eventName: collectionEvent.eventName,
+ eventData: collectionEvent.eventData,
+ userProperty: _userProperty,
+ );
+
+ // For opted out users, data in the persisted files is cleared
+ _userProperty.sessionFile.writeAsStringSync('');
+ _logHandler.logFile.writeAsStringSync('');
+ _clientIdFile.writeAsStringSync('');
+
+ _clientId = '';
+ }
+
+ // Pass to the google analytics client to send with a
+ // timeout incase http clients hang
+ return _gaClient.sendData(body).timeout(
+ const Duration(milliseconds: kDelayDuration),
+ onTimeout: () => Response('', 200),
+ );
+ }
+
+ @override
+ void suppressTelemetry() => _telemetrySuppressed = true;
+
+ @override
+ void surveyInteracted({
+ required Survey survey,
+ required SurveyButton surveyButton,
+ }) {
+ // Any action, except for 'snooze' will permanently dismiss a given survey
+ final permanentlyDismissed = surveyButton.action == 'snooze' ? false : true;
+ _surveyHandler.dismiss(survey, permanentlyDismissed);
+ send(Event.surveyAction(
+ surveyId: survey.uniqueId,
+ status: surveyButton.action,
+ ));
+ }
+
+ @override
+ void surveyShown(Survey survey) {
+ _surveyHandler.dismiss(survey, false);
+ send(Event.surveyShown(surveyId: survey.uniqueId));
+ }
+
+ /// Send any pending error events, useful for tests to avoid closing
+ /// the connection.
+ ///
+ /// In the main implementation, [AnalyticsImpl], error events are only
+ /// sent on exit when [close] is invoked. This helper method can instead
+ /// have those error events sent immediately to help with tests that check
+ /// [FakeAnalytics.sentEvents].
+ void _sendPendingErrorEvents() {
+ // Collect any errors encountered and send
+ final errorEvents = {..._userProperty.errorSet, ..._logHandler.errorSet};
+ errorEvents
+ .where((event) =>
+ event.eventName == DashEvent.analyticsException &&
+ !_sentErrorEvents.contains(event))
+ .forEach(send);
+
+ // Ensure the same event doesn't get sent again
+ _sentErrorEvents.addAll(errorEvents);
+
+ // Clear error sets
+ _userProperty.errorSet.clear();
+ _logHandler.errorSet.clear();
+ }
+}
+
+/// This fake instance of [Analytics] is intended to be used by clients of
+/// this package for testing purposes. It exposes a list [sentEvents] that
+/// keeps track of all events that have been sent.
+///
+/// This is useful for confirming that events are being sent for a given
+/// workflow. Invoking the [send] method on this instance will not make any
+/// network requests to Google Analytics.
+class FakeAnalytics extends AnalyticsImpl {
+ /// Use this list to check for events that have been emitted when
+ /// invoking the send method
+ final List<Event> sentEvents = [];
+
+ /// Class to use when you want to see which events were sent
+ FakeAnalytics._({
+ required super.tool,
+ required super.homeDirectory,
+ required super.dartVersion,
+ required super.platform,
+ required super.fs,
+ required super.surveyHandler,
+ required super.firstRun,
+ super.flutterChannel,
+ super.flutterVersion,
+ super.clientIde,
+ super.enabledFeatures,
+ super.toolsMessageVersion = kToolsMessageVersion,
+ super.gaClient = const FakeGAClient(),
+ super.enableAsserts = true,
+ });
+
+ /// Getter to reference the private [UserProperty].
+ UserProperty get userProperty => _userProperty;
+
+ @override
+ void send(Event event) {
+ if (!okToSend) return;
+
+ // Construct the body of the request
+ final body = generateRequestBody(
+ clientId: clientId,
+ eventName: event.eventName,
+ eventData: event.eventData,
+ userProperty: _userProperty,
+ );
+
+ if (_enableAsserts) checkBody(body);
+
+ _logHandler.save(data: body);
+
+ // Using this list to validate that events are being sent
+ // for internal methods in the `Analytics` instance
+ sentEvents.add(event);
+ }
+
+ /// Public instance method to invoke private method that sends any
+ /// pending error events.
+ ///
+ /// If this is never invoked, any pending error events will be sent
+ /// when invoking the [close] method.
+ void sendPendingErrorEvents() => _sendPendingErrorEvents();
+}
+
+/// An implementation that will never send events.
+///
+/// This is for clients that opt to either not send analytics, or will migrate
+/// to use [AnalyticsImpl] at a later time.
+class NoOpAnalytics implements Analytics {
+ /// The hard-coded client ID value for each NoOp instance.
+ static String get staticClientId => 'xxxx-xxxx';
+
+ @override
+ final String getConsentMessage = '';
+
+ @override
+ final bool okToSend = false;
+
+ @override
+ final Map<String, ToolInfo> parsedTools = const <String, ToolInfo>{};
+
+ @override
+ final bool shouldShowMessage = false;
+
+ @override
+ final bool telemetryEnabled = false;
+
+ @override
+ final Map<String, Map<String, Object?>> userPropertyMap =
+ const <String, Map<String, Object?>>{};
+
+ const NoOpAnalytics();
+
+ @override
+ String get clientId => staticClientId;
+
+ @override
+ void clientShowedMessage() {}
+
+ @override
+ Future<void> close({int delayDuration = kDelayDuration}) async {}
+
+ @override
+ Future<List<Survey>> fetchAvailableSurveys() async => const <Survey>[];
+
+ @override
+ LogFileStats? logFileStats() => null;
+
+ @override
+ Future<Response>? send(Event event) => null;
+
+ @override
+ Future<void> setTelemetry(bool reportingBool) async {}
+
+ @override
+ void suppressTelemetry() {}
+
+ @override
+ void surveyInteracted({
+ required Survey survey,
+ required SurveyButton surveyButton,
+ }) {}
+
+ @override
+ void surveyShown(Survey survey) {}
+}
diff --git a/pkgs/unified_analytics/lib/src/asserts.dart b/pkgs/unified_analytics/lib/src/asserts.dart
new file mode 100644
index 0000000..199f4ee
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/asserts.dart
@@ -0,0 +1,172 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Matches only alphabetic characters.
+final RegExp alphabeticPattern = RegExp(r'^[A-Za-z]+$');
+
+/// Matches strings that contain alphanumeric characters and underscores.
+final RegExp alphaNumericPattern = RegExp(r'^[A-Za-z0-9_]+$');
+
+/// Checks that the body of the request being sent to
+/// GA4 is within the limitations.
+///
+/// Limitations can be found:
+/// https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events?client_type=gtag#limitations
+void checkBody(Map<String, Object?> body) {
+ // Ensure we have the correct top level keys
+ if (!body.keys.contains('client_id')) {
+ throw AnalyticsException('client_id missing from top level keys');
+ }
+ if (!body.keys.contains('events')) {
+ throw AnalyticsException('events missing from top level keys');
+ }
+ if (!body.keys.contains('user_properties')) {
+ throw AnalyticsException('user_properties missing from top level keys');
+ }
+
+ final events = body['events'] as List;
+ final userProperties = body['user_properties'] as Map<String, Object?>;
+
+ // GA4 Limitation:
+ // Requests can have a maximum of 25 events
+ if (events.length > 25) {
+ throw AnalyticsException('25 is the max number of events');
+ }
+
+ // Checks for each event object
+ for (final eventMap in events.cast<Map<String, Object?>>()) {
+ final eventName = eventMap['name'] as String;
+
+ // GA4 Limitation:
+ // Event names must be 40 characters or fewer, may only contain
+ // alpha-numeric characters and underscores, and must start
+ // with an alphabetic character
+ if (eventName.length > 40) {
+ throw AnalyticsException(
+ 'Limit event names to 40 chars or less\n'
+ 'Event name: "$eventName" is too long',
+ );
+ }
+ if (!alphaNumericPattern.hasMatch(eventName)) {
+ throw AnalyticsException(
+ 'Event name can only have alphanumeric chars and underscores\n'
+ 'Event name: "$eventName" contains invalid characters',
+ );
+ }
+ if (!alphabeticPattern.hasMatch(eventName[0])) {
+ throw AnalyticsException(
+ 'Event name first char must be alphabetic char\n'
+ 'Event name: "$eventName" must begin with a valid character',
+ );
+ }
+
+ final eventParams = eventMap['params'] as Map<String, Object?>;
+
+ // GA4 Limitation:
+ // Events can have a maximum of 25 parameters
+ if (eventParams.length > 25) {
+ throw AnalyticsException(
+ 'Limit params for each event to less than 25\n'
+ 'Event: "$eventName" has too many parameters',
+ );
+ }
+
+ // Loop through each of the event parameters
+ for (final entry in eventParams.entries) {
+ final key = entry.key;
+ final value = entry.value;
+
+ // GA4 Limitation:
+ // Ensure that each value for the event params is one
+ // of the following types:
+ // `String`, `int`, `double`, or `bool`
+ if (!(value is String ||
+ value is int ||
+ value is double ||
+ value is bool)) {
+ throw AnalyticsException(
+ 'Values for event params have to be String, int, double, or bool\n'
+ 'Value for "$key" is not a valid type for event: "$eventName"',
+ );
+ }
+
+ // GA4 Limitation:
+ // Parameter names (including item parameters) must be 40 characters
+ // or fewer, may only contain alpha-numeric characters and underscores,
+ // and must start with an alphabetic character
+ if (key.length > 40) {
+ throw AnalyticsException(
+ 'Limit event param names to 40 chars or less\n'
+ 'The key: "$key" under the event: "$eventName" is too long',
+ );
+ }
+ if (!alphaNumericPattern.hasMatch(key)) {
+ throw AnalyticsException(
+ 'Event param name can only have alphanumeric chars and underscores\n'
+ 'The key: "$key" under the event: "$eventName" contains '
+ 'invalid characters',
+ );
+ }
+ if (!alphabeticPattern.hasMatch(key[0])) {
+ throw AnalyticsException(
+ 'Event param name first char must be alphabetic char\n'
+ 'The key: "$key" under the event: "$eventName" must begin '
+ 'in a valid character',
+ );
+ }
+
+ // GA4 Limitation:
+ // Parameter values (including item parameter values) must be 100
+ // characters or fewer
+ if (value.runtimeType == String) {
+ value as String;
+ if (value.length > 100) {
+ throw AnalyticsException(
+ 'Limit characters in event param value to 100 chars or less\n'
+ 'Value for "$key" is too long, value="$value"',
+ );
+ }
+ }
+ }
+ }
+
+ // GA4 Limitation:
+ // Events can have a maximum of 25 user properties
+ if (userProperties.length > 25) {
+ throw AnalyticsException('Limit user properties to 25 or less');
+ }
+
+ // Checks for each user property item
+ for (final entry in userProperties.entries) {
+ final key = entry.key;
+ final value = entry.value as Map<String, Object?>;
+
+ // GA4 Limitation:
+ // User property names must be 24 characters or fewer
+ if (key.length > 24) {
+ throw AnalyticsException('Limit user property names to 24 chars or less\n'
+ 'The user property key: "$key" is too long');
+ }
+
+ // GA4 Limitation:
+ // User property values must be 36 characters or fewer
+ final userPropValue = value['value'];
+ if (userPropValue is String && userPropValue.length > 36) {
+ throw AnalyticsException(
+ 'Limit user property values to 36 chars or less\n'
+ 'For the user property key "$key", the value "${value['value']}" '
+ 'is too long',
+ );
+ }
+ }
+}
+
+class AnalyticsException implements Exception {
+ final String message;
+
+ AnalyticsException(this.message);
+
+ @override
+ String toString() => 'AnalyticsException: $message';
+}
diff --git a/pkgs/unified_analytics/lib/src/config_handler.dart b/pkgs/unified_analytics/lib/src/config_handler.dart
new file mode 100644
index 0000000..8db4660
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/config_handler.dart
@@ -0,0 +1,224 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:clock/clock.dart';
+import 'package:convert/convert.dart';
+import 'package:file/file.dart';
+
+import 'initializer.dart';
+import 'utils.dart';
+
+/// The regex pattern used to parse the disable analytics line.
+const String telemetryFlagPattern = r'^reporting=([0|1]) *$';
+
+/// The regex pattern used to parse the tools info
+/// from the configuration file.
+///
+/// Example:
+/// ```text
+/// flutter-tool=2022-10-26,1
+/// devtools=2022-11-26,1
+/// ```
+const String toolPattern =
+ r'^([A-Za-z0-9]+[A-Za-z0-9_-]*)=([0-9]{4}-[0-9]{2}-[0-9]{2}),([0-9]+)$';
+
+class ConfigHandler {
+ /// Regex pattern implementation for matching a line in the config file.
+ static RegExp telemetryFlagRegex =
+ RegExp(telemetryFlagPattern, multiLine: true);
+ static RegExp toolRegex = RegExp(toolPattern, multiLine: true);
+
+ final Directory homeDirectory;
+ final File configFile;
+
+ final Map<String, ToolInfo> parsedTools = <String, ToolInfo>{};
+
+ DateTime configFileLastModified;
+
+ /// Reporting enabled unless specified by user
+ bool _telemetryEnabled = true;
+
+ ConfigHandler({
+ required this.homeDirectory,
+ required this.configFile,
+ }) : configFileLastModified = configFile.lastModifiedSync() {
+ // Call the method to parse the contents of the config file when
+ // this class is initialized
+ parseConfig();
+ }
+
+ /// Returns the telemetry state from the config file.
+ ///
+ /// Method will reparse the config file if it detects that the
+ /// last modified datetime is different from what was parsed when
+ /// the class was initialized.
+ bool get telemetryEnabled {
+ if (configFileLastModified.isBefore(configFile.lastModifiedSync())) {
+ parseConfig();
+ configFileLastModified = configFile.lastModifiedSync();
+ }
+
+ return _telemetryEnabled;
+ }
+
+ /// Responsibe for the creation of the configuration line
+ /// for the tool being passed in by the user and adding a
+ /// [ToolInfo] object.
+ void addTool({
+ required String tool,
+ required int versionNumber,
+ }) {
+ // Create the new instance of [ToolInfo] to be added
+ // to the [parsedTools] map
+ parsedTools[tool] = ToolInfo(
+ lastRun: clock.now(),
+ versionNumber: versionNumber,
+ );
+
+ // New string to be appended to the bottom of the configuration file
+ // with a newline character for new tools to be added
+ var newTool = '$tool=$dateStamp,$versionNumber\n';
+ if (!configFile.readAsStringSync().endsWith('\n')) {
+ newTool = '\n$newTool';
+ }
+ configFile.writeAsStringSync(newTool, mode: FileMode.append);
+ configFileLastModified = configFile.lastModifiedSync();
+ }
+
+ /// Will increment the version number and update the date
+ /// in the config file for the provided tool name while
+ /// also incrementing the version number in [ToolInfo].
+ void incrementToolVersion({
+ required String tool,
+ required int newVersionNumber,
+ }) {
+ if (!parsedTools.containsKey(tool)) {
+ return;
+ }
+
+ // Read in the config file contents and use a regex pattern to
+ // match the line for the current tool (ie. flutter-tools=2023-01-05,1)
+ final configString = configFile.readAsStringSync();
+ final pattern = '^($tool)=([0-9]{4}-[0-9]{2}-[0-9]{2}),([0-9]+)\$';
+
+ final regex = RegExp(pattern, multiLine: true);
+ final matches = regex.allMatches(configString);
+
+ // If there isn't exactly one match for the given tool, that suggests the
+ // file has been altered and needs to be reset
+ if (matches.length != 1) {
+ resetConfig();
+ return;
+ }
+
+ // Construct the new tool line for the config line and replace it
+ // in the original config string to prep for writing back out
+ final newToolString = '$tool=$dateStamp,$newVersionNumber';
+ final newConfigString = configString.replaceAll(regex, newToolString);
+ configFile.writeAsStringSync(newConfigString);
+
+ final toolInfo = parsedTools[tool];
+ if (toolInfo == null) {
+ return;
+ }
+
+ // Update the [ToolInfo] object for the current tool
+ toolInfo.lastRun = clock.now();
+ toolInfo.versionNumber = newVersionNumber;
+ }
+
+ /// Method responsible for reading in the config file stored on
+ /// user's machine and parsing out the following: all the tools that
+ /// have been logged in the file, the dates they were last run, and
+ /// determining if telemetry is enabled by parsing the file.
+ void parseConfig() {
+ // Begin with the assumption that telemetry is always enabled
+ _telemetryEnabled = true;
+
+ // Read the configuration file as a string and run the two regex patterns
+ // on it to get information around which tools have been parsed and whether
+ // or not telemetry has been disabled by the user
+ final configString = configFile.readAsStringSync();
+
+ // Collect the tools logged in the configuration file
+ toolRegex.allMatches(configString).forEach((RegExpMatch element) {
+ // Extract the information relevant for the [ToolInfo] class
+ final tool = element.group(1) as String;
+ final lastRun = DateTime.parse(element.group(2) as String);
+ final versionNumber = int.parse(element.group(3) as String);
+
+ // Initialize an instance of the [ToolInfo] class to store
+ // in the [parsedTools] map object
+ parsedTools[tool] = ToolInfo(
+ lastRun: lastRun,
+ versionNumber: versionNumber,
+ );
+ });
+
+ // Check for lines signaling that the user has disabled analytics,
+ // if multiple lines are found, the more conservative value will be used
+ telemetryFlagRegex.allMatches(configString).forEach((RegExpMatch element) {
+ // Conditional for recording telemetry as being disabled
+ if (element.group(1) == '0') {
+ _telemetryEnabled = false;
+ }
+ });
+ }
+
+ /// This will reset the configuration file and clear the
+ /// [parsedTools] map and trigger parsing the config again.
+ void resetConfig() {
+ createConfigFile(
+ configFile: configFile,
+ homeDirectory: homeDirectory,
+ );
+ parsedTools.clear();
+ parseConfig();
+ }
+
+ /// Disables the reporting capabilities if [reportingBool] is set to `false`.
+ Future<void> setTelemetry(bool reportingBool) async {
+ final flag = reportingBool ? '1' : '0';
+ final configString = await configFile.readAsString();
+
+ final matches = telemetryFlagRegex.allMatches(configString);
+
+ // If there isn't exactly one match for the reporting flag, that suggests
+ // the file has been altered and needs to be reset
+ if (matches.length != 1) {
+ resetConfig();
+ return;
+ }
+
+ final newTelemetryString = 'reporting=$flag';
+
+ final newConfigString =
+ configString.replaceAll(telemetryFlagRegex, newTelemetryString);
+
+ await configFile.writeAsString(newConfigString);
+ configFileLastModified = configFile.lastModifiedSync();
+
+ _telemetryEnabled = reportingBool;
+ }
+}
+
+class ToolInfo {
+ DateTime lastRun;
+ int versionNumber;
+
+ ToolInfo({
+ required this.lastRun,
+ required this.versionNumber,
+ });
+
+ @override
+ String toString() {
+ return json.encode(<String, Object?>{
+ 'lastRun': FixedDateTimeFormatter('YYYY-MM-DD').encode(lastRun),
+ 'versionNumber': versionNumber,
+ });
+ }
+}
diff --git a/pkgs/unified_analytics/lib/src/constants.dart b/pkgs/unified_analytics/lib/src/constants.dart
new file mode 100644
index 0000000..2be4d0a
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/constants.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// URL endpoint for sending Google Analytics Events.
+const String kAnalyticsUrl = 'https://www.google-analytics.com/mp/collect';
+
+/// Name for the text file that will contain the user's randomly generated
+/// client id.
+const String kClientIdFileName = 'CLIENT_ID';
+
+/// Name for the file where telemetry status and tools data will be stored.
+const String kConfigFileName = 'dart-flutter-telemetry.config';
+
+/// The string that will provide the boilerplate for the configuration file
+/// stored on the user's machine.
+const String kConfigString = '''
+# INTRODUCTION
+#
+# This is the Flutter and Dart telemetry reporting
+# configuration file.
+#
+# Lines starting with a #" are documentation that
+# the tools maintain automatically.
+#
+# All other lines are configuration lines. They have
+# the form "name=value". If multiple lines contain
+# the same configuration name with different values,
+# the parser will default to a conservative value.
+
+# DISABLING TELEMETRY REPORTING
+#
+# To disable telemetry reporting, set "reporting" to
+# the value "0" and to enable, set to "1":
+reporting=1
+
+# NOTIFICATIONS
+#
+# Each tool records when it last informed the user about
+# analytics reporting and the privacy policy.
+#
+# The following tools have so far read this file:
+#
+# dart-tools (Dart CLI developer tool)
+# devtools (DevTools debugging and performance tools)
+# flutter-tools (Flutter CLI developer tool)
+#
+# For each one, the file may contain a configuration line
+# where the name is the code in the list above, e.g. "dart-tool",
+# and the value is a date in the form YYYY-MM-DD, a comma, and
+# a number representing the version of the message that was
+# displayed.''';
+
+/// Link to contextual survey metadata file.
+const String kContextualSurveyUrl =
+ 'https://storage.googleapis.com/flutter-uxr/surveys/contextual-survey-metadata.json';
+
+/// Name of the directory where all of the files necessary for this package
+/// will be located.
+const String kDartToolDirectoryName = '.dart-tool';
+
+/// The default time to wait before closing the http connection to allow for
+/// pending events to be sent.
+const int kDelayDuration = 250;
+
+/// Name of the file where we persist dismissed survey ids.
+const String kDismissedSurveyFileName =
+ 'dart-flutter-telemetry-dismissed-surveys.json';
+
+/// The API secret associated with the GA4 instance's Measurement Protocol.
+const String kGoogleAnalyticsApiSecret = 'Ka1jc8tZSzWc_GXMWHfPHA';
+
+/// The measurement ID related to the GA4 instance.
+///
+/// Serves as an identifier for a web data stream.
+const String kGoogleAnalyticsMeasurementId = 'G-04BXPVBCWJ';
+
+/// How many data records to store in the log file.
+const int kLogFileLength = 2500;
+
+/// The maximum allowed size of the telemetry log file.
+///
+/// 25 MiB.
+const int kMaxLogFileSize = 25 * (1 << 20);
+
+/// Filename for the log file to persist sent events on user's machine.
+const String kLogFileName = 'dart-flutter-telemetry.log';
+
+/// The current version of the package, should be in line with pubspec version.
+const String kPackageVersion = '7.0.1';
+
+/// The minimum length for a session.
+const int kSessionDurationMinutes = 30;
+
+/// Name for the json file where the session details will be stored.
+const String kSessionFileName = 'dart-flutter-telemetry-session.json';
+
+/// The message that should be shown to the user.
+const String kToolsMessage = '''
+The {{ toolDescription }} uses Google Analytics to report usage and diagnostic
+data along with package dependencies, and crash reporting to send basic crash
+reports. This data is used to help improve the Dart platform, Flutter framework,
+and related tools.
+
+Telemetry is not sent on the very first run. To disable reporting of telemetry,
+run this terminal command:
+
+ {{ toolName }} --disable-analytics
+
+If you opt out of telemetry, an opt-out event will be sent, and then no further
+information will be sent. This data is collected in accordance with the Google
+Privacy Policy (https://policies.google.com/privacy).
+''';
+
+/// The version number for the message below.
+///
+/// If the message below is altered, the version should be incremented so that
+/// users can be prompted with the updated messaging.
+const int kToolsMessageVersion = 1;
diff --git a/pkgs/unified_analytics/lib/src/enums.dart b/pkgs/unified_analytics/lib/src/enums.dart
new file mode 100644
index 0000000..d67ab66
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/enums.dart
@@ -0,0 +1,234 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// The valid dash tool labels stored in the [DashTool] enum.
+List<String> get validDashTools =>
+ DashTool.values.map((e) => e.label).toList()..sort();
+
+/// Values for the event name to be sent to Google Analytics.
+///
+/// The [label] for each enum value is what will be logged, the [description]
+/// is here for documentation purposes.
+///
+/// Set the nullable [toolOwner] parameter if the event belongs to one specific
+/// tool, otherwise, if multiple tools will be sending the event, leave it null.
+enum DashEvent {
+ // Events that can be sent by all tools; these
+ // events should not be tool specific; toolOwner
+ // not necessary for these events
+
+ analyticsCollectionEnabled(
+ label: 'analytics_collection_enabled',
+ description: 'The opt-in status for analytics collection',
+ ),
+ analyticsException(
+ label: 'analytics_exception',
+ description: 'Errors that are encountered within package:unified_analytics',
+ ),
+ exception(
+ label: 'exception',
+ description: 'General errors to log',
+ ),
+ surveyAction(
+ label: 'survey_action',
+ description: 'Actions taken by users when shown survey',
+ ),
+ surveyShown(
+ label: 'survey_shown',
+ description: 'Survey shown to the user',
+ ),
+ timing(
+ label: 'timing',
+ description: 'Events for timing how long a process takes',
+ ),
+
+ // Events for the Dart CLI
+
+ dartCliCommandExecuted(
+ label: 'dart_cli_command_executed',
+ description: 'Information about the execution of a Dart CLI command',
+ toolOwner: DashTool.dartTool,
+ ),
+ pubGet(
+ label: 'pub_get',
+ description: 'Pub package resolution details',
+ toolOwner: DashTool.dartTool,
+ ),
+
+ // Events for Flutter devtools
+
+ devtoolsEvent(
+ label: 'devtools_event',
+ description: 'Information for various devtools events',
+ toolOwner: DashTool.devtools,
+ ),
+
+ // Events for the Flutter CLI
+
+ appleUsageEvent(
+ label: 'apple_usage_event',
+ description:
+ 'Events related to iOS/macOS workflows within the flutter tool',
+ toolOwner: DashTool.flutterTool,
+ ),
+ codeSizeAnalysis(
+ label: 'code_size_analysis',
+ description: 'Indicates when the "--analyize-size" command is run',
+ toolOwner: DashTool.flutterTool,
+ ),
+ commandUsageValues(
+ label: 'command_usage_values',
+ description: 'Contains command level custom dimensions from legacy '
+ 'flutter analytics',
+ toolOwner: DashTool.flutterTool,
+ ),
+ doctorValidatorResult(
+ label: 'doctor_validator_result',
+ description: 'Results from a specific doctor validator',
+ toolOwner: DashTool.flutterTool,
+ ),
+ flutterBuildInfo(
+ label: 'flutter_build_info',
+ description: 'Information for a flutter build invocation',
+ toolOwner: DashTool.flutterTool,
+ ),
+ flutterCommandResult(
+ label: 'flutter_command_result',
+ description: 'Provides information about flutter commands that ran',
+ toolOwner: DashTool.flutterTool,
+ ),
+ hotReloadTime(
+ label: 'hot_reload_time',
+ description: 'Hot reload duration',
+ toolOwner: DashTool.flutterTool,
+ ),
+ hotRunnerInfo(
+ label: 'hot_runner_info',
+ description: 'Information related to the Flutter hot runner',
+ toolOwner: DashTool.flutterTool,
+ ),
+
+ // Events for language_server below
+
+ clientNotification(
+ label: 'client_notification',
+ description: 'Notifications sent from the client',
+ ),
+ clientRequest(
+ label: 'client_request',
+ description: 'Requests sent from the client',
+ ),
+ commandExecuted(
+ label: 'command_executed',
+ description: 'Number of times a command is executed',
+ ),
+ contextStructure(
+ label: 'context_structure',
+ description: 'Structure of the analysis contexts being analyzed',
+ ),
+ lintUsageCount(
+ label: 'lint_usage_count',
+ description: 'Number of times a given lint is enabled',
+ ),
+ memoryInfo(
+ label: 'memory_info',
+ description: 'Memory usage information',
+ ),
+ pluginRequest(
+ label: 'plugin_request',
+ description: 'Request responses from plugins',
+ ),
+ pluginUse(
+ label: 'plugin_use',
+ description: 'Information about how often a plugin was used',
+ ),
+ serverSession(
+ label: 'server_session',
+ description: 'Dart Analyzer Server session data',
+ ),
+ severityAdjustment(
+ label: 'severity_adjustment',
+ description: 'Number of times diagnostic severity is changed',
+ ),
+ ;
+
+ final String label;
+ final String description;
+ final DashTool? toolOwner;
+ const DashEvent({
+ required this.label,
+ required this.description,
+ this.toolOwner,
+ });
+
+ /// This takes in the string label for a given [DashEvent] and returns the
+ /// enum for that string label.
+ static DashEvent? fromLabel(String label) =>
+ DashEvent.values.where((e) => e.label == label).firstOrNull;
+}
+
+/// Officially-supported clients of this package as logical
+/// tools, grouped by user point of view. Derived directly
+/// from the PDD.
+enum DashTool {
+ androidStudioPlugins(
+ label: 'android-studio-plugins',
+ description: 'Android Studio IDE plugins for Dart and Flutter',
+ ),
+ dartTool(
+ label: 'dart-tool',
+ description: 'Dart CLI developer tool',
+ ),
+ devtools(
+ label: 'devtools',
+ description: 'DevTools debugging and performance tools',
+ ),
+ flutterTool(
+ label: 'flutter-tool',
+ description: 'Flutter CLI developer tool',
+ ),
+ intellijPlugins(
+ label: 'intellij-plugins',
+ description: 'IntelliJ IDE plugins for Dart and Flutter',
+ ),
+ vscodePlugins(
+ label: 'vscode-plugins',
+ description: 'VS Code IDE extensions for Dart and Flutter',
+ );
+
+ /// String used as the control flag and the value of the tool key in
+ /// analytics.
+ final String label;
+
+ /// The "notice string", a human-readable description of the logical tool
+ /// grouping.
+ final String description;
+
+ const DashTool({
+ required this.label,
+ required this.description,
+ });
+
+ /// This takes in the string label for a given [DashTool] and returns the
+ /// enum for that string label.
+ static DashTool fromLabel(String label) {
+ final tool = DashTool.values.where((t) => t.label == label).firstOrNull;
+ if (tool != null) return tool;
+
+ throw Exception('The tool $label from the survey metadata file is not '
+ 'a valid DashTool enum value\n'
+ 'Valid labels for dash tools: ${validDashTools.join(', ')}');
+ }
+}
+
+/// Enumerate options for platforms supported.
+enum DevicePlatform {
+ windows('Windows'),
+ macos('macOS'),
+ linux('Linux'),
+ ;
+
+ final String label;
+ const DevicePlatform(this.label);
+}
diff --git a/pkgs/unified_analytics/lib/src/event.dart b/pkgs/unified_analytics/lib/src/event.dart
new file mode 100644
index 0000000..ed30665
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/event.dart
@@ -0,0 +1,860 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'enums.dart';
+
+final class Event {
+ final DashEvent eventName;
+ final Map<String, Object?> eventData;
+
+ /// Event that is emitted whenever a user has opted in
+ /// or out of the analytics collection.
+ ///
+ /// [status] - boolean value where `true` indicates user is opting in.
+ Event.analyticsCollectionEnabled({required bool status})
+ : eventName = DashEvent.analyticsCollectionEnabled,
+ eventData = {'status': status};
+
+ /// Event that is emitted when an error occurs within
+ /// `package:unified_analytics`, tools that are using this package
+ /// should not use this event constructor.
+ ///
+ /// Tools using this package should instead use the more generic
+ /// [Event.exception] constructor.
+ ///
+ /// [workflow] - refers to what process caused the error, such as
+ /// "LogHandler.logFileStats".
+ ///
+ /// [error] - the name of the error, such as "FormatException".
+ ///
+ /// [description] - the description of the error being caught.
+ Event.analyticsException({
+ required String workflow,
+ required String error,
+ String? description,
+ }) : eventName = DashEvent.analyticsException,
+ eventData = {
+ 'workflow': workflow,
+ 'error': error,
+ if (description != null) 'description': description,
+ };
+
+ /// This is for various workflows within the flutter tool related
+ /// to iOS and macOS workflows.
+ ///
+ /// [workflow] - which workflow is running, such as "assemble".
+ ///
+ /// [parameter] - subcategory of the workflow, such as "ios-archive".
+ ///
+ /// [result] - usually to indicate success or failure of the workflow.
+ Event.appleUsageEvent({
+ required String workflow,
+ required String parameter,
+ String? result,
+ }) : eventName = DashEvent.appleUsageEvent,
+ eventData = {
+ 'workflow': workflow,
+ 'parameter': parameter,
+ if (result != null) 'result': result,
+ };
+
+ /// Event that is emitted periodically to report the performance of the
+ /// analysis server's handling of a specific kind of notification from the
+ /// client.
+ ///
+ /// [duration] - json encoded percentile values indicating how long it took
+ /// from the time the server started handling the notification until the
+ /// server had finished handling the notification.
+ ///
+ /// [latency] - json encoded percentile values indicating how long it took
+ /// from the time the notification was sent until the server started
+ /// handling it.
+ ///
+ /// [method] - the name of the notification method that was sent.
+ Event.clientNotification({
+ required String duration,
+ required String latency,
+ required String method,
+ }) : eventName = DashEvent.clientNotification,
+ eventData = {
+ 'duration': duration,
+ 'latency': latency,
+ 'method': method,
+ };
+
+ /// Event that is emitted periodically to report the performance of the
+ /// analysis server's handling of a specific kind of request from the client.
+ ///
+ /// [duration] - json encoded percentile values indicating how long it took
+ /// from the time the server started handling the request until the server
+ /// had send a response.
+ ///
+ /// [latency] - json encoded percentile values indicating how long it took
+ /// from the time the request was sent until the server started handling
+ /// it.
+ ///
+ /// [method] - the name of the request method that was sent.
+ ///
+ /// If the method is `workspace/didChangeWorkspaceFolders`, then the following
+ /// parameters should be included:
+ ///
+ /// [added] - json encoded percentile values indicating the number of folders
+ /// that were added.
+ ///
+ /// [removed] - json encoded percentile values indicating the number of
+ /// folders that were removed.
+ ///
+ /// If the method is `initialized`, then the following parameters should be
+ /// included:
+ ///
+ /// [openWorkspacePaths] - json encoded percentile values indicating the
+ /// number of workspace paths that were opened.
+ ///
+ /// If the method is `analysis.setAnalysisRoots`, then the following
+ /// parameters should be included:
+ ///
+ /// [included] - json encoded percentile values indicating the number of
+ /// analysis roots in the included list.
+ ///
+ /// [excluded] - json encoded percentile values indicating the number of
+ /// analysis roots in the excluded list.
+ ///
+ /// If the method is `analysis.setPriorityFiles`, then the following
+ /// parameters should be included:
+ ///
+ /// [files] - json encoded percentile values indicating the number of priority
+ /// files.
+ ///
+ Event.clientRequest({
+ required String duration,
+ required String latency,
+ required String method,
+ String? added,
+ String? excluded,
+ String? files,
+ String? included,
+ String? openWorkspacePaths,
+ String? removed,
+ }) : eventName = DashEvent.clientRequest,
+ eventData = {
+ if (added != null) 'added': added,
+ 'duration': duration,
+ if (excluded != null) 'excluded': excluded,
+ if (files != null) 'files': files,
+ if (included != null) 'included': included,
+ 'latency': latency,
+ 'method': method,
+ if (openWorkspacePaths != null)
+ 'openWorkspacePaths': openWorkspacePaths,
+ if (removed != null) 'removed': removed,
+ };
+
+ /// An event that reports when the code size measurement is run
+ /// via `--analyze-size`.
+ ///
+ /// [platform] - string identifier for which platform was run "ios", "apk",
+ /// "aab", etc.
+ Event.codeSizeAnalysis({required String platform})
+ : eventName = DashEvent.codeSizeAnalysis,
+ eventData = {
+ 'platform': platform,
+ };
+
+ /// Event that is emitted periodically to report the number of times a given
+ /// command has been executed.
+ ///
+ /// [count] - the number of times the command was executed.
+ ///
+ /// [name] - the name of the command that was executed.
+ Event.commandExecuted({
+ required int count,
+ required String name,
+ }) : eventName = DashEvent.commandExecuted,
+ eventData = {
+ 'count': count,
+ 'name': name,
+ };
+
+ /// Event to capture usage values for different flutter commands.
+ ///
+ /// There are several implementations of the `FlutterCommand` class within the
+ /// flutter-tool that pass information based on the [workflow] being ran. An
+ /// example of a [workflow] can be "create". The optional parameters for this
+ /// constructor are a superset of all the implementations of `FlutterCommand`.
+ /// There should never be a time where all of the parameters are passed to
+ /// this constructor.
+ Event.commandUsageValues({
+ required String workflow,
+ required bool commandHasTerminal,
+
+ // Assemble && build bundle implementation parameters
+ String? buildBundleTargetPlatform,
+ bool? buildBundleIsModule,
+
+ // Build aar implementation parameters
+ String? buildAarProjectType,
+ String? buildAarTargetPlatform,
+
+ // Build apk implementation parameters
+ String? buildApkTargetPlatform,
+ String? buildApkBuildMode,
+ bool? buildApkSplitPerAbi,
+
+ // Build app bundle implementation parameters
+ String? buildAppBundleTargetPlatform,
+ String? buildAppBundleBuildMode,
+
+ // Create implementation parameters
+ String? createProjectType,
+ String? createAndroidLanguage,
+ String? createIosLanguage,
+
+ // Packages implementation parameters
+ int? packagesNumberPlugins,
+ bool? packagesProjectModule,
+ String? packagesAndroidEmbeddingVersion,
+
+ // Run implementation parameters
+ bool? runIsEmulator,
+ String? runTargetName,
+ String? runTargetOsVersion,
+ String? runModeName,
+ bool? runProjectModule,
+ String? runProjectHostLanguage,
+ String? runAndroidEmbeddingVersion,
+ bool? runEnableImpeller,
+ String? runIOSInterfaceType,
+ bool? runIsTest,
+ }) : eventName = DashEvent.commandUsageValues,
+ eventData = {
+ 'workflow': workflow,
+ 'commandHasTerminal': commandHasTerminal,
+ if (buildBundleTargetPlatform != null)
+ 'buildBundleTargetPlatform': buildBundleTargetPlatform,
+ if (buildBundleIsModule != null)
+ 'buildBundleIsModule': buildBundleIsModule,
+ if (buildAarProjectType != null)
+ 'buildAarProjectType': buildAarProjectType,
+ if (buildAarTargetPlatform != null)
+ 'buildAarTargetPlatform': buildAarTargetPlatform,
+ if (buildApkTargetPlatform != null)
+ 'buildApkTargetPlatform': buildApkTargetPlatform,
+ if (buildApkBuildMode != null) 'buildApkBuildMode': buildApkBuildMode,
+ if (buildApkSplitPerAbi != null)
+ 'buildApkSplitPerAbi': buildApkSplitPerAbi,
+ if (buildAppBundleTargetPlatform != null)
+ 'buildAppBundleTargetPlatform': buildAppBundleTargetPlatform,
+ if (buildAppBundleBuildMode != null)
+ 'buildAppBundleBuildMode': buildAppBundleBuildMode,
+ if (createProjectType != null) 'createProjectType': createProjectType,
+ if (createAndroidLanguage != null)
+ 'createAndroidLanguage': createAndroidLanguage,
+ if (createIosLanguage != null) 'createIosLanguage': createIosLanguage,
+ if (packagesNumberPlugins != null)
+ 'packagesNumberPlugins': packagesNumberPlugins,
+ if (packagesProjectModule != null)
+ 'packagesProjectModule': packagesProjectModule,
+ if (packagesAndroidEmbeddingVersion != null)
+ 'packagesAndroidEmbeddingVersion': packagesAndroidEmbeddingVersion,
+ if (runIsEmulator != null) 'runIsEmulator': runIsEmulator,
+ if (runTargetName != null) 'runTargetName': runTargetName,
+ if (runTargetOsVersion != null)
+ 'runTargetOsVersion': runTargetOsVersion,
+ if (runModeName != null) 'runModeName': runModeName,
+ if (runProjectModule != null) 'runProjectModule': runProjectModule,
+ if (runProjectHostLanguage != null)
+ 'runProjectHostLanguage': runProjectHostLanguage,
+ if (runAndroidEmbeddingVersion != null)
+ 'runAndroidEmbeddingVersion': runAndroidEmbeddingVersion,
+ if (runEnableImpeller != null) 'runEnableImpeller': runEnableImpeller,
+ if (runIOSInterfaceType != null)
+ 'runIOSInterfaceType': runIOSInterfaceType,
+ if (runIsTest != null) 'runIsTest': runIsTest,
+ };
+
+ /// Event that is emitted on shutdown to report the structure of the analysis
+ /// contexts created immediately after startup.
+ ///
+ /// [contextsFromBothFiles] - the number of contexts that were created because
+ /// of both a package config and an analysis options file.
+ ///
+ /// [contextsFromOptionsFiles] - the number of contexts that were created
+ /// because of an analysis options file.
+ ///
+ /// [contextsFromPackagesFiles] - the number of contexts that were created
+ /// because of a package config file.
+ ///
+ /// [contextsWithoutFiles] - the number of contexts that were created because
+ /// of the lack of either a package config or an analysis options file.
+ ///
+ /// [immediateFileCount] - the number of files in one of the analysis
+ /// contexts.
+ ///
+ /// [immediateFileLineCount] - the number of lines in the immediate files.
+ ///
+ /// [numberOfContexts] - the number of analysis context created.
+ ///
+ /// [transitiveFileCount] - the number of files reachable from the files in
+ /// each analysis context, where files can be counted multiple times if
+ /// they are reachable from multiple contexts.
+ ///
+ /// [transitiveFileLineCount] - the number of lines in the transitive files,
+ /// where files can be counted multiple times if they are reachable from
+ /// multiple contexts.
+ ///
+ /// [transitiveFileUniqueCount] - the number of unique files reachable from
+ /// the files in each analysis context.
+ ///
+ /// [transitiveFileUniqueLineCount] - the number of lines in the unique
+ /// transitive files.
+ Event.contextStructure({
+ required int contextsFromBothFiles,
+ required int contextsFromOptionsFiles,
+ required int contextsFromPackagesFiles,
+ required int contextsWithoutFiles,
+ required int immediateFileCount,
+ required int immediateFileLineCount,
+ required int numberOfContexts,
+ required int transitiveFileCount,
+ required int transitiveFileLineCount,
+ required int transitiveFileUniqueCount,
+ required int transitiveFileUniqueLineCount,
+ }) : eventName = DashEvent.contextStructure,
+ eventData = {
+ 'contextsFromBothFiles': contextsFromBothFiles,
+ 'contextsFromOptionsFiles': contextsFromOptionsFiles,
+ 'contextsFromPackagesFiles': contextsFromPackagesFiles,
+ 'contextsWithoutFiles': contextsWithoutFiles,
+ 'immediateFileCount': immediateFileCount,
+ 'immediateFileLineCount': immediateFileLineCount,
+ 'numberOfContexts': numberOfContexts,
+ 'transitiveFileCount': transitiveFileCount,
+ 'transitiveFileLineCount': transitiveFileLineCount,
+ 'transitiveFileUniqueCount': transitiveFileUniqueCount,
+ 'transitiveFileUniqueLineCount': transitiveFileUniqueLineCount,
+ };
+
+ /// Event that is emitted when a Dart CLI command has been executed.
+ ///
+ /// [name] - the name of the command that was executed
+ ///
+ /// [enabledExperiments] - a set of Dart language experiments enabled when
+ /// running the command.
+ ///
+ /// [exitCode] - the process exit code set as a result of running the command.
+ Event.dartCliCommandExecuted({
+ required String name,
+ required String enabledExperiments,
+ int? exitCode,
+ }) : eventName = DashEvent.dartCliCommandExecuted,
+ eventData = {
+ 'name': name,
+ 'enabledExperiments': enabledExperiments,
+ if (exitCode != null) 'exitCode': exitCode,
+ };
+
+ /// Event that is sent from DevTools for various different actions as
+ /// indicated by the [eventCategory].
+ ///
+ /// The optional parameters in the parameter list contain metadata that is
+ /// sent with each event, when available.
+ ///
+ /// [additionalMetrics] may contain any additional data for the event being
+ /// sent. This often looks like metrics that are unique to the event or to a
+ /// specific screen.
+ Event.devtoolsEvent({
+ required String screen,
+ required String eventCategory,
+ required String label,
+ required int value,
+
+ // Defaulted values
+ bool userInitiatedInteraction = true,
+
+ // Optional parameters
+ String? g3Username,
+ String? userApp,
+ String? userBuild,
+ String? userPlatform,
+ String? devtoolsPlatform,
+ String? devtoolsChrome,
+ String? devtoolsVersion,
+ String? ideLaunched,
+ String? isExternalBuild,
+ String? isEmbedded,
+ String? ideLaunchedFeature,
+ String? isWasm,
+ CustomMetrics? additionalMetrics,
+ }) : eventName = DashEvent.devtoolsEvent,
+ eventData = {
+ 'screen': screen,
+ 'eventCategory': eventCategory,
+ 'label': label,
+ 'value': value,
+
+ 'userInitiatedInteraction': userInitiatedInteraction,
+
+ // Optional parameters
+ if (g3Username != null) 'g3Username': g3Username,
+ if (userApp != null) 'userApp': userApp,
+ if (userBuild != null) 'userBuild': userBuild,
+ if (userPlatform != null) 'userPlatform': userPlatform,
+ if (devtoolsPlatform != null) 'devtoolsPlatform': devtoolsPlatform,
+ if (devtoolsChrome != null) 'devtoolsChrome': devtoolsChrome,
+ if (devtoolsVersion != null) 'devtoolsVersion': devtoolsVersion,
+ if (ideLaunched != null) 'ideLaunched': ideLaunched,
+ if (isExternalBuild != null) 'isExternalBuild': isExternalBuild,
+ if (isEmbedded != null) 'isEmbedded': isEmbedded,
+ if (ideLaunchedFeature != null)
+ 'ideLaunchedFeature': ideLaunchedFeature,
+ if (isWasm != null) 'isWasm': isWasm,
+ if (additionalMetrics != null) ...additionalMetrics.toMap(),
+ };
+
+ /// Event that contains the results for a specific doctor validator.
+ ///
+ /// [validatorName] - the name for the doctor validator.
+ ///
+ /// [result] - the final result for a specific doctor validator.
+ ///
+ /// [partOfGroupedValidator] - `true` indicates that this validator belongs
+ /// to a grouped validator.
+ ///
+ /// [doctorInvocationId] - epoch formatted timestamp that can be used in
+ /// combination with the client ID in GA4 to group the validators that
+ /// ran in one doctor invocation.
+ ///
+ /// [statusInfo] - optional description of the result from the
+ /// doctor validator.
+ Event.doctorValidatorResult({
+ required String validatorName,
+ required String result,
+ required bool partOfGroupedValidator,
+ required int doctorInvocationId,
+ String? statusInfo,
+ }) : eventName = DashEvent.doctorValidatorResult,
+ eventData = {
+ 'validatorName': validatorName,
+ 'result': result,
+ 'partOfGroupedValidator': partOfGroupedValidator,
+ 'doctorInvocationId': doctorInvocationId,
+ if (statusInfo != null) 'statusInfo': statusInfo,
+ };
+
+ /// Generic event for all dash tools to use when encountering an
+ /// exception that we want to log.
+ ///
+ /// [exception] - string representation of the exception that occured.
+ /// [data] - optional structured data to include with the exception event.
+ Event.exception({
+ required String exception,
+ Map<String, Object?> data = const <String, Object?>{},
+ }) : eventName = DashEvent.exception,
+ eventData = {
+ 'exception': exception,
+ ...Map.from(data)..removeWhere((key, value) => value == null),
+ };
+
+ /// Event that is emitted from the flutter tool when a build invocation
+ /// has been run by the user.
+ ///
+ /// [label] - the identifier for that build event.
+ ///
+ /// [buildType] - the identifier for which platform the build event was for,
+ /// examples include "ios", "gradle", and "web".
+ ///
+ /// [command] - the command that was ran to kick off the build event.
+ ///
+ /// [settings] - the settings used for the build event related to
+ /// configuration and other relevant build information.
+ ///
+ /// [error] - short identifier used to explain the cause of the build error,
+ /// stacktraces should not be passed to this parameter.
+ Event.flutterBuildInfo({
+ required String label,
+ required String buildType,
+ String? command,
+ String? settings,
+ String? error,
+ }) : eventName = DashEvent.flutterBuildInfo,
+ eventData = {
+ 'label': label,
+ 'buildType': buildType,
+ if (command != null) 'command': command,
+ if (settings != null) 'settings': settings,
+ if (error != null) 'error': error,
+ };
+
+ /// Provides information about which flutter command was run
+ /// and whether it was successful.
+ ///
+ /// [commandPath] - information about the flutter command, such as "build/apk".
+ ///
+ /// [result] - if the command failed or succeeded.
+ ///
+ /// [commandHasTerminal] - boolean indicating if the flutter command ran with
+ /// a terminal.
+ ///
+ /// [maxRss] - maximum resident size for a given flutter command.
+ Event.flutterCommandResult({
+ required String commandPath,
+ required String result,
+ required bool commandHasTerminal,
+ int? maxRss,
+ }) : eventName = DashEvent.flutterCommandResult,
+ eventData = {
+ 'commandPath': commandPath,
+ 'result': result,
+ 'commandHasTerminal': commandHasTerminal,
+ if (maxRss != null) 'maxRss': maxRss,
+ };
+
+ // TODO: eliasyishak, remove this or replace once we have a generic
+ // timing event that can be used by potentially more than one DashTool
+ Event.hotReloadTime({required int timeMs})
+ : eventName = DashEvent.hotReloadTime,
+ eventData = {'timeMs': timeMs};
+
+ /// Events to be sent for the Flutter Hot Runner.
+ Event.hotRunnerInfo({
+ required String label,
+ required String targetPlatform,
+ required String sdkName,
+ required bool emulator,
+ required bool fullRestart,
+ String? reason,
+ int? finalLibraryCount,
+ int? syncedLibraryCount,
+ int? syncedClassesCount,
+ int? syncedProceduresCount,
+ int? syncedBytes,
+ int? invalidatedSourcesCount,
+ int? transferTimeInMs,
+ int? overallTimeInMs,
+ int? compileTimeInMs,
+ int? findInvalidatedTimeInMs,
+ int? scannedSourcesCount,
+ int? reassembleTimeInMs,
+ int? reloadVMTimeInMs,
+ }) : eventName = DashEvent.hotRunnerInfo,
+ eventData = {
+ 'label': label,
+ 'targetPlatform': targetPlatform,
+ 'sdkName': sdkName,
+ 'emulator': emulator,
+ 'fullRestart': fullRestart,
+ if (reason != null) 'reason': reason,
+ if (finalLibraryCount != null) 'finalLibraryCount': finalLibraryCount,
+ if (syncedLibraryCount != null)
+ 'syncedLibraryCount': syncedLibraryCount,
+ if (syncedClassesCount != null)
+ 'syncedClassesCount': syncedClassesCount,
+ if (syncedProceduresCount != null)
+ 'syncedProceduresCount': syncedProceduresCount,
+ if (syncedBytes != null) 'syncedBytes': syncedBytes,
+ if (invalidatedSourcesCount != null)
+ 'invalidatedSourcesCount': invalidatedSourcesCount,
+ if (transferTimeInMs != null) 'transferTimeInMs': transferTimeInMs,
+ if (overallTimeInMs != null) 'overallTimeInMs': overallTimeInMs,
+ if (compileTimeInMs != null) 'compileTimeInMs': compileTimeInMs,
+ if (findInvalidatedTimeInMs != null)
+ 'findInvalidatedTimeInMs': findInvalidatedTimeInMs,
+ if (scannedSourcesCount != null)
+ 'scannedSourcesCount': scannedSourcesCount,
+ if (reassembleTimeInMs != null)
+ 'reassembleTimeInMs': reassembleTimeInMs,
+ if (reloadVMTimeInMs != null) 'reloadVMTimeInMs': reloadVMTimeInMs,
+ };
+
+ // TODO: eliasyishak, add better dartdocs to explain each param
+ /// Event that is emitted periodically to report the number of times each lint
+ /// has been enabled.
+ ///
+ /// [count] - the number of contexts in which the lint was enabled.
+ ///
+ /// [name] - the name of the lint.
+ Event.lintUsageCount({
+ required int count,
+ required String name,
+ }) : eventName = DashEvent.lintUsageCount,
+ eventData = {
+ 'count': count,
+ 'name': name,
+ };
+
+ /// Event that is emitted periodically to report the amount of memory being
+ /// used.
+ ///
+ /// [rss] - the resident set size in megabytes.
+ ///
+ /// If this is not the first time memory has been reported for this session,
+ /// then the following parameters should be included:
+ ///
+ /// [periodSec] - the number of seconds since the last memory usage data was
+ /// gathered.
+ ///
+ /// [mbPerSec] - the number of megabytes of memory that were added or
+ /// subtracted per second since the last report.
+ Event.memoryInfo({
+ required int rss,
+ int? periodSec,
+ double? mbPerSec,
+ }) : eventName = DashEvent.memoryInfo,
+ eventData = {
+ 'rss': rss,
+ if (periodSec != null) 'periodSec': periodSec,
+ if (mbPerSec != null) 'mbPerSec': mbPerSec
+ };
+
+ /// Event that is emitted periodically to report the performance of plugins
+ /// when handling requests.
+ ///
+ /// [duration] - json encoded percentile values indicating how long it took
+ /// from the time the request was sent to the plugin until the response
+ /// was processed by the server.
+ ///
+ /// [method] - the name of the request sent to the plugin.
+ ///
+ /// [pluginId] - the id of the plugin whose performance is being reported.
+ Event.pluginRequest({
+ required String duration,
+ required String method,
+ required String pluginId,
+ }) : eventName = DashEvent.pluginRequest,
+ eventData = {
+ 'duration': duration,
+ 'method': method,
+ 'pluginId': pluginId,
+ };
+
+ /// Event that is emitted periodically to report the frequency with which a
+ /// given plugin has been used.
+ ///
+ /// [count] - the number of times plugins usage was changed, which will always
+ /// be at least one.
+ ///
+ /// [enabled] - json encoded percentile values indicating the number of
+ /// contexts for which the plugin was enabled.
+ ///
+ /// [pluginId] - the id of the plugin associated with the data.
+ Event.pluginUse({
+ required int count,
+ required String enabled,
+ required String pluginId,
+ }) : eventName = DashEvent.pluginUse,
+ eventData = {
+ 'count': count,
+ 'enabled': enabled,
+ 'pluginId': pluginId,
+ };
+
+ /// Event that is emitted when `pub get` is run.
+ ///
+ /// [packageName] - the name of the package that was resolved
+ ///
+ /// [version] - the resolved, canonicalized package version
+ ///
+ /// [dependencyType] - the kind of dependency that resulted in this package
+ /// being resolved (e.g., direct, transitive, or dev dependencies).
+ Event.pubGet({
+ required String packageName,
+ required String version,
+ required String dependencyType,
+ }) : eventName = DashEvent.pubGet,
+ eventData = {
+ 'packageName': packageName,
+ 'version': version,
+ 'dependencyType': dependencyType,
+ };
+
+ /// Event that is emitted on shutdown to report information about the whole
+ /// session for which the analysis server was running.
+ ///
+ /// [clientId] - the id of the client that started the server.
+ ///
+ /// [clientVersion] - the version of the client that started the server.
+ ///
+ /// [duration] - the number of milliseconds for which the server was running.
+ ///
+ /// [flags] - the flags passed to the analysis server on startup, without any
+ /// argument values for flags that take values, or an empty string if
+ /// there were no arguments.
+ ///
+ /// [parameters] - the names of the parameters passed to the `initialize`
+ /// request, or an empty string if the `initialize` request was not sent
+ /// or if there were no parameters given.
+ Event.serverSession({
+ required String clientId,
+ required String clientVersion,
+ required int duration,
+ required String flags,
+ required String parameters,
+ }) : eventName = DashEvent.serverSession,
+ eventData = {
+ 'clientId': clientId,
+ 'clientVersion': clientVersion,
+ 'duration': duration,
+ 'flags': flags,
+ 'parameters': parameters,
+ };
+
+ /// Event that is emitted periodically to report the number of times the
+ /// severity of a diagnostic was changed in the analysis options file.
+ ///
+ /// [diagnostic] - the name of the diagnostic whose severity was changed.
+ ///
+ /// [adjustments] - json encoded map of severities to the number of times the
+ /// diagnostic's severity was changed to the key.
+ Event.severityAdjustment({
+ required String diagnostic,
+ required String adjustments,
+ }) : eventName = DashEvent.severityAdjustment,
+ eventData = {
+ 'diagnostic': diagnostic,
+ 'adjustments': adjustments,
+ };
+
+ /// Event that is emitted by `package:unified_analytics` when
+ /// the user takes action when prompted with a survey.
+ ///
+ /// [surveyId] - the unique id for a given survey.
+ ///
+ /// [status] - the string identifier for a given `SurveyButton` under the
+ /// `action` field.
+ Event.surveyAction({
+ required String surveyId,
+ required String status,
+ }) : eventName = DashEvent.surveyAction,
+ eventData = {
+ 'surveyId': surveyId,
+ 'status': status,
+ };
+
+ /// Event that is emitted by `package:unified_analytics` when the
+ /// user has been shown a survey.
+ ///
+ /// [surveyId] - the unique id for a given survey.
+ Event.surveyShown({
+ required String surveyId,
+ }) : eventName = DashEvent.surveyShown,
+ eventData = {
+ 'surveyId': surveyId,
+ };
+
+ /// Event that records how long a given process takes to complete.
+ ///
+ /// [workflow] - the overall process or command being run, for example
+ /// "build" is a possible value for the flutter tool.
+ ///
+ /// [variableName] - the specific variable being measured, for example
+ /// "gradle" would indicate how long it took for a gradle build under the
+ /// "build" [workflow].
+ ///
+ /// [elapsedMilliseconds] - how long the process took in milliseconds.
+ ///
+ /// [label] - an optional field that can be used for further filtering, for
+ /// example, "success" can indicate how long a successful build in gradle
+ /// takes to complete.
+ Event.timing({
+ required String workflow,
+ required String variableName,
+ required int elapsedMilliseconds,
+ String? label,
+ }) : eventName = DashEvent.timing,
+ eventData = {
+ 'workflow': workflow,
+ 'variableName': variableName,
+ 'elapsedMilliseconds': elapsedMilliseconds,
+ if (label != null) 'label': label,
+ };
+
+ /// Private constructor to be used when deserializing JSON into an instance
+ /// of [Event].
+ Event._({required this.eventName, required this.eventData});
+
+ @override
+ int get hashCode => Object.hash(eventName, jsonEncode(eventData));
+
+ @override
+ bool operator ==(Object other) =>
+ other is Event &&
+ other.runtimeType == runtimeType &&
+ other.eventName == eventName &&
+ _compareEventData(other.eventData, eventData);
+
+ /// Converts an instance of [Event] to JSON.
+ String toJson() => jsonEncode({
+ 'eventName': eventName.label,
+ 'eventData': eventData,
+ });
+
+ @override
+ String toString() => toJson();
+
+ /// Utility function to take in two maps [a] and [b] and compares them
+ /// to ensure that they have the same keys and values
+ bool _compareEventData(Map<String, Object?> a, Map<String, Object?> b) {
+ final keySetA = a.keys.toSet();
+ final keySetB = b.keys.toSet();
+ final intersection = keySetA.intersection(keySetB);
+
+ // Ensure that the keys are the same for each object
+ if (intersection.length != keySetA.length ||
+ intersection.length != keySetB.length) {
+ return false;
+ }
+
+ // Ensure that each of the key's values are the same
+ for (final key in a.keys) {
+ if (a[key] != b[key]) return false;
+ }
+
+ return true;
+ }
+
+ /// Returns a valid instance of [Event] if [json] follows the correct schema.
+ ///
+ /// Common use case for this static method involves clients of this package
+ /// that have a client-server setup where the server sends events that the
+ /// client creates.
+ static Event? fromJson(String json) {
+ try {
+ final jsonMap = jsonDecode(json) as Map<String, Object?>;
+
+ // Ensure that eventName is a string and a valid label and
+ // eventData is a nested object
+ if (jsonMap
+ case {
+ 'eventName': final String eventName,
+ 'eventData': final Map<String, Object?> eventData,
+ }) {
+ final dashEvent = DashEvent.fromLabel(eventName);
+ if (dashEvent == null) return null;
+
+ return Event._(
+ eventName: dashEvent,
+ eventData: eventData,
+ );
+ }
+
+ return null;
+ } on FormatException {
+ return null;
+ }
+ }
+}
+
+/// A base class for custom metrics that will be defined by a unified_analytics
+/// client.
+///
+/// This base type can be used as a parameter in any event constructor that
+/// allows custom metrics to be added by a unified_analytics client.
+abstract base class CustomMetrics {
+ /// Converts the custom metrics data to a [Map] object.
+ ///
+ /// This must be a JSON encodable [Map].
+ Map<String, Object> toMap();
+}
diff --git a/pkgs/unified_analytics/lib/src/ga_client.dart b/pkgs/unified_analytics/lib/src/ga_client.dart
new file mode 100644
index 0000000..2c3e83e
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/ga_client.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
+
+import 'constants.dart';
+
+class FakeGAClient implements GAClient {
+ const FakeGAClient();
+
+ @override
+ String get apiSecret => throw UnimplementedError();
+
+ @override
+ String get measurementId => throw UnimplementedError();
+
+ @override
+ String get postUrl => throw UnimplementedError();
+
+ @override
+ http.Client get _client => throw UnimplementedError();
+
+ @override
+ void close() {}
+
+ @override
+ Future<http.Response> sendData(Map<String, Object?> body) =>
+ Future<http.Response>.value(http.Response('', 200));
+}
+
+class GAClient {
+ final String measurementId;
+ final String apiSecret;
+ final String postUrl;
+ final http.Client _client;
+
+ GAClient({
+ required this.measurementId,
+ required this.apiSecret,
+ }) : postUrl = '$kAnalyticsUrl?'
+ 'measurement_id=$measurementId&api_secret=$apiSecret',
+ _client = http.Client();
+
+ /// Closes the http client's connection to prevent lingering requests.
+ void close() => _client.close();
+
+ /// Receive the payload in Map form and parse
+ /// into JSON to send to GA.
+ ///
+ /// The [http.Response] returned from this method can be
+ /// checked to ensure that events have been sent. A response
+ /// status code of `2xx` indicates a successful send event.
+ /// A response status code of `500` indicates an error occured on the send
+ /// can the error message can be found in the [http.Response.body].
+ Future<http.Response> sendData(Map<String, Object?> body) async {
+ final uri = Uri.parse(postUrl);
+
+ // Using a try catch all since post method can result in several
+ // errors; clients using this method can check the awaited status
+ // code to get a specific error message if the status code returned
+ // is a 500 error status code
+ try {
+ return await _client.post(
+ uri,
+ headers: <String, String>{
+ 'Content-Type': 'application/json; charset=UTF-8',
+ },
+ body: jsonEncode(body),
+ );
+ // ignore: avoid_catches_without_on_clauses
+ } catch (error) {
+ return Future<http.Response>.value(
+ http.Response(
+ error.toString(),
+ 500,
+ headers: <String, String>{
+ 'content-type': 'text/plain; charset=utf-8',
+ },
+ ),
+ );
+ }
+ }
+}
diff --git a/pkgs/unified_analytics/lib/src/initializer.dart b/pkgs/unified_analytics/lib/src/initializer.dart
new file mode 100644
index 0000000..131968b
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/initializer.dart
@@ -0,0 +1,118 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:clock/clock.dart';
+import 'package:file/file.dart';
+
+import 'constants.dart';
+import 'utils.dart';
+
+/// Creates the text file that will contain the client ID
+/// which will be used across all related tools for analytics
+/// reporting in GA.
+void createClientIdFile({required File clientIdFile}) {
+ clientIdFile.createSync(recursive: true);
+ clientIdFile.writeAsStringSync(Uuid().generateV4());
+}
+
+/// Creates the configuration file with the default message
+/// in the user's home directory.
+void createConfigFile({
+ required File configFile,
+ required Directory homeDirectory,
+}) {
+ configFile.createSync(recursive: true);
+
+ // If the user was previously opted out, then we will
+ // replace the line that assumes automatic opt in with
+ // an opt out from the start
+ if (legacyOptOut(homeDirectory: homeDirectory)) {
+ configFile.writeAsStringSync(
+ kConfigString.replaceAll('reporting=1', 'reporting=0'));
+ } else {
+ configFile.writeAsStringSync(kConfigString);
+ }
+}
+
+/// Creates that file that will persist dismissed survey ids.
+void createDismissedSurveyFile({required File dismissedSurveyFile}) {
+ dismissedSurveyFile.createSync(recursive: true);
+ dismissedSurveyFile.writeAsStringSync('{}');
+}
+
+/// Creates that log file that will store the record formatted
+/// events locally on the user's machine.
+void createLogFile({required File logFile}) {
+ logFile.createSync(recursive: true);
+}
+
+/// Creates the session file which will contain
+/// the current session id which is the current timestamp.
+///
+/// It also returns the timestamp used for the session if it needs
+/// to be accessed.
+DateTime createSessionFile({required File sessionFile}) {
+ final now = clock.now();
+ sessionFile.createSync(recursive: true);
+ writeSessionContents(sessionFile: sessionFile);
+
+ return now;
+}
+
+/// Performs all of the initialization checks for the required files.
+///
+/// Returns `true` if the config file was created indicating it is the first
+/// time this package was run on a user's machine.
+///
+/// Checks for the following:
+/// - Config file
+/// - Client ID file
+/// - Session JSON file
+/// - Log file
+/// - Dismissed survey JSON file
+bool runInitialization({
+ required Directory homeDirectory,
+}) {
+ var firstRun = false;
+ final dartToolDirectory =
+ homeDirectory.childDirectory(kDartToolDirectoryName);
+
+ // When the config file doesn't exist, initialize it with the default tools
+ // and the current date.
+ final configFile = dartToolDirectory.childFile(kConfigFileName);
+ if (!configFile.existsSync()) {
+ firstRun = true;
+ createConfigFile(
+ configFile: configFile,
+ homeDirectory: homeDirectory,
+ );
+ }
+
+ // Begin initialization checks for the client id.
+ final clientFile = dartToolDirectory.childFile(kClientIdFileName);
+ if (!clientFile.existsSync()) {
+ createClientIdFile(clientIdFile: clientFile);
+ }
+
+ // Begin initialization checks for the session file.
+ final sessionFile = dartToolDirectory.childFile(kSessionFileName);
+ if (!sessionFile.existsSync()) {
+ createSessionFile(sessionFile: sessionFile);
+ }
+
+ // Begin initialization checks for the log file to persist events locally.
+ final logFile = dartToolDirectory.childFile(kLogFileName);
+ if (!logFile.existsSync()) {
+ createLogFile(logFile: logFile);
+ }
+
+ // Begin initialization checks for the dismissed survey file.
+ final dismissedSurveyFile =
+ dartToolDirectory.childFile(kDismissedSurveyFileName);
+ if (!dismissedSurveyFile.existsSync()) {
+ createDismissedSurveyFile(dismissedSurveyFile: dismissedSurveyFile);
+ }
+
+ return firstRun;
+}
diff --git a/pkgs/unified_analytics/lib/src/log_handler.dart b/pkgs/unified_analytics/lib/src/log_handler.dart
new file mode 100644
index 0000000..a6ef2f5
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/log_handler.dart
@@ -0,0 +1,464 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:clock/clock.dart';
+import 'package:file/file.dart';
+
+import 'constants.dart';
+import 'event.dart';
+import 'initializer.dart';
+
+/// Data class that will be returned when analyzing the
+/// persisted log file on the client's machine.
+class LogFileStats {
+ /// The oldest timestamp in the log file.
+ final DateTime startDateTime;
+
+ /// Number of minutes from [startDateTime] to now using [clock].
+ final int minsFromStartDateTime;
+
+ /// The latest timestamp in the log file.
+ final DateTime endDateTime;
+
+ /// Number of minutes from [endDateTime] to now using [clock].
+ final int minsFromEndDateTime;
+
+ /// The number of unique session ids found in the log file.
+ final int sessionCount;
+
+ /// The map containing all of the flutter channels and a count
+ /// of how many events were under each channel.
+ ///
+ /// ```
+ /// {
+ /// 'stable': 123,
+ /// 'beta': 50,
+ /// 'master': 5,
+ /// }
+ /// ```
+ final Map<String, int> flutterChannelCount;
+
+ /// The map containing all of the tools that have sent events
+ /// and how many events were sent by each tool.
+ ///
+ /// ```
+ /// {
+ /// 'flutter-tool': 500,
+ /// 'dart-tool': 45,
+ /// 'vscode-plugins': 321,
+ /// }
+ /// ```
+ final Map<String, int> toolCount;
+
+ /// The map containing all of the events in the file along with
+ /// how many times they have occured.
+ ///
+ /// ```
+ /// {
+ /// 'client_request': 345,
+ /// 'hot_reload_time': 765,
+ /// 'memory_info': 90,
+ /// }
+ /// ```
+ final Map<String, int> eventCount;
+
+ /// Total number of records in the log file.
+ final int recordCount;
+
+ /// Contains the data from the [LogHandler.logFileStats] method.
+ const LogFileStats({
+ required this.startDateTime,
+ required this.minsFromStartDateTime,
+ required this.endDateTime,
+ required this.minsFromEndDateTime,
+ required this.sessionCount,
+ required this.flutterChannelCount,
+ required this.toolCount,
+ required this.recordCount,
+ required this.eventCount,
+ });
+
+ /// Pass in a string label for one of the instance variables
+ /// and return the integer value of that label.
+ ///
+ /// If label passed for [DateTime] instance variable, integer
+ /// in the form of [DateTime.millisecondsSinceEpoch] will be
+ /// returned.
+ ///
+ /// Returns null if the label passed does not match anything.
+ int? getValueByString(String label) {
+ // When querying counts, the label will include the
+ // key for the appropriate map
+ //
+ // Example: logFileStats.toolCount.flutter-tool is asking
+ // for the number of events sent via flutter cli
+ final parts = label.split('.');
+ String? key;
+ if (parts.length >= 3) {
+ // Assign the first two parts of the string as the label
+ // ie. logFileStats.toolCount.flutter-tool -> logFileStats.toolCount
+ label = parts.sublist(0, 2).join('.');
+ key = parts.sublist(2, parts.length).join('.');
+ }
+
+ switch (label) {
+ case 'logFileStats.startDateTime':
+ return startDateTime.millisecondsSinceEpoch;
+ case 'logFileStats.minsFromStartDateTime':
+ return minsFromStartDateTime;
+ case 'logFileStats.endDateTime':
+ return endDateTime.millisecondsSinceEpoch;
+ case 'logFileStats.minsFromEndDateTime':
+ return minsFromEndDateTime;
+ case 'logFileStats.sessionCount':
+ return sessionCount;
+ case 'logFileStats.recordCount':
+ return recordCount;
+ case 'logFileStats.flutterChannelCount':
+ if (key != null && flutterChannelCount.containsKey(key)) {
+ return flutterChannelCount[key];
+ }
+ case 'logFileStats.toolCount':
+ if (key != null && toolCount.containsKey(key)) {
+ return toolCount[key];
+ }
+ case 'logFileStats.eventCount':
+ if (key != null && eventCount.containsKey(key)) {
+ return eventCount[key];
+ }
+ }
+
+ return null;
+ }
+
+ @override
+ String toString() {
+ const encoder = JsonEncoder.withIndent(' ');
+ return encoder.convert({
+ 'startDateTime': startDateTime.toString(),
+ 'minsFromStartDateTime': minsFromStartDateTime,
+ 'endDateTime': endDateTime.toString(),
+ 'minsFromEndDateTime': minsFromEndDateTime,
+ 'sessionCount': sessionCount,
+ 'recordCount': recordCount,
+ 'eventCount': eventCount,
+ 'toolCount': toolCount,
+ 'flutterChannelCount': flutterChannelCount,
+ });
+ }
+}
+
+/// This class is responsible for writing to a log
+/// file that has been initialized by the [createLogFile].
+///
+/// It will be treated as an append only log and will be limited
+/// to have has many data records as specified by [kLogFileLength].
+class LogHandler {
+ final File logFile;
+
+ /// Contains instances of [Event.analyticsException] that were encountered
+ /// during a workflow and will be sent to GA4 for collection.
+ final Set<Event> errorSet = {};
+
+ /// A log handler constructor that will delegate saving
+ /// logs and retrieving stats from the persisted log.
+ LogHandler({required this.logFile});
+
+ /// Get stats from the persisted log file.
+ ///
+ /// Note that some developers may only be Dart
+ /// developers and will not have any data for flutter
+ /// related metrics.
+ LogFileStats? logFileStats() {
+ // Parse each line of the log file through [LogItem],
+ // some returned records may be null if malformed, they will be
+ // removed later through `whereType<LogItem>`
+ final records = logFile
+ .readAsLinesSync()
+ .map((String e) {
+ try {
+ return LogItem.fromRecord(jsonDecode(e) as Map<String, Object?>);
+ } on FormatException catch (err) {
+ errorSet.add(Event.analyticsException(
+ workflow: 'LogFileStats.logFileStats',
+ error: err.runtimeType.toString(),
+ description: 'message: ${err.message}\nsource: ${err.source}',
+ ));
+
+ return null;
+ // ignore: avoid_catching_errors
+ } on TypeError catch (err) {
+ errorSet.add(Event.analyticsException(
+ workflow: 'LogFileStats.logFileStats',
+ error: err.runtimeType.toString(),
+ ));
+
+ return null;
+ }
+ })
+ .whereType<LogItem>()
+ .toList();
+
+ if (records.isEmpty) return null;
+
+ // Get the start and end dates for the log file
+ final startDateTime = records.first.localTime;
+ final endDateTime = records.last.localTime;
+
+ // Map with counters for user properties
+ final counter = <String, Set<Object>>{
+ 'sessions': <int>{},
+ 'flutter_channel': <String>{},
+ 'tool': <String>{},
+ };
+
+ // Map of counters for each event
+ final eventCount = <String, int>{};
+ final flutterChannelCount = <String, int>{};
+ final toolCount = <String, int>{};
+ for (final record in records) {
+ counter['sessions']!.add(record.sessionId);
+ counter['tool']!.add(record.tool);
+ if (record.flutterChannel != null) {
+ counter['flutter_channel']!.add(record.flutterChannel!);
+ }
+
+ // Count each event, if it doesn't exist in the [eventCount]
+ // it will be added first
+ if (!eventCount.containsKey(record.eventName)) {
+ eventCount[record.eventName] = 0;
+ }
+ eventCount[record.eventName] = eventCount[record.eventName]! + 1;
+
+ // Counting how many events were recorded for each tool
+ if (!toolCount.containsKey(record.tool)) {
+ toolCount[record.tool] = 0;
+ }
+ toolCount[record.tool] = toolCount[record.tool]! + 1;
+
+ // Necessary to perform a null check for flutter channel because
+ // not all events will have information about flutter
+ if (record.flutterChannel != null) {
+ final flutterChannel = record.flutterChannel!;
+ if (!flutterChannelCount.containsKey(flutterChannel)) {
+ flutterChannelCount[flutterChannel] = 0;
+ }
+
+ flutterChannelCount[flutterChannel] =
+ flutterChannelCount[flutterChannel]! + 1;
+ }
+ }
+
+ final now = clock.now();
+
+ return LogFileStats(
+ startDateTime: startDateTime,
+ minsFromStartDateTime: now.difference(startDateTime).inMinutes,
+ endDateTime: endDateTime,
+ minsFromEndDateTime: now.difference(endDateTime).inMinutes,
+ sessionCount: counter['sessions']!.length,
+ flutterChannelCount: flutterChannelCount,
+ toolCount: toolCount,
+ eventCount: eventCount,
+ recordCount: records.length,
+ );
+ }
+
+ /// Saves the data passed in as a single line in the log file.
+ ///
+ /// This will keep the max number of records limited to equal to
+ /// or less than [kLogFileLength] records.
+ void save({required Map<String, Object?> data}) {
+ try {
+ final stat = logFile.statSync();
+ List<String> records;
+ if (stat.size > kMaxLogFileSize) {
+ logFile.deleteSync();
+ logFile.createSync();
+ records = [];
+ } else {
+ records = logFile.readAsLinesSync();
+ }
+ final content = '${jsonEncode(data)}\n';
+
+ // When the record count is less than the max, add as normal;
+ // else drop the oldest records until equal to max
+ if (records.length < kLogFileLength) {
+ logFile.writeAsStringSync(content, mode: FileMode.writeOnlyAppend);
+ } else {
+ records.add(content);
+ records = records.skip(records.length - kLogFileLength).toList();
+
+ logFile.writeAsStringSync(records.join('\n'));
+ }
+ } on FileSystemException {
+ // Logging isn't important enough to warrant raising a
+ // FileSystemException that will surprise consumers of this package.
+ }
+ }
+}
+
+/// Data class for each record persisted on the client's machine.
+class LogItem {
+ final String eventName;
+ final int sessionId;
+ final String? flutterChannel;
+ final String host;
+ final String? flutterVersion;
+ final String dartVersion;
+ final String tool;
+ final DateTime localTime;
+ final String hostOsVersion;
+ final String locale;
+ final String? clientIde;
+
+ LogItem({
+ required this.eventName,
+ required this.sessionId,
+ this.flutterChannel,
+ required this.host,
+ this.flutterVersion,
+ required this.dartVersion,
+ required this.tool,
+ required this.localTime,
+ required this.hostOsVersion,
+ required this.locale,
+ required this.clientIde,
+ });
+
+ /// Serves a parser for each record in the log file.
+ ///
+ /// Using this method guarantees that we have parsed out
+ /// fields that are necessary for the [LogHandler.logFileStats]
+ /// method.
+ ///
+ /// If the returned value is null, that indicates a malformed
+ /// record which can be discarded during analysis.
+ ///
+ /// Example of what a record looks like:
+ /// ```
+ /// {
+ /// "client_id": "ffcea97b-db5e-4c66-98c2-3942de4fac40",
+ /// "events": [
+ /// {
+ /// "name": "hot_reload_time",
+ /// "params": {
+ /// "timeMs": 135
+ /// }
+ /// }
+ /// ],
+ /// "user_properties": {
+ /// "session_id": {
+ /// "value": 1699385899950
+ /// },
+ /// "flutter_channel": {
+ /// "value": "ey-test-channel"
+ /// },
+ /// "host": {
+ /// "value": "macOS"
+ /// },
+ /// "flutter_version": {
+ /// "value": "Flutter 3.6.0-7.0.pre.47"
+ /// },
+ /// "dart_version": {
+ /// "value": "Dart 2.19.0"
+ /// },
+ /// "analytics_pkg_version": {
+ /// "value": "5.2.0"
+ /// },
+ /// "tool": {
+ /// "value": "flutter-tool"
+ /// },
+ /// "local_time": {
+ /// "value": "2023-11-07 15:09:03.025559 -0500"
+ /// },
+ /// "host_os_version": {
+ /// "value": "Version 14.1 (Build 23B74)"
+ /// },
+ /// "locale": {
+ /// "value": "en"
+ /// },
+ /// "clientIde": {
+ /// "value": "VSCode"
+ /// }
+ /// }
+ /// }
+ /// ```
+ static LogItem? fromRecord(Map<String, Object?> record) {
+ if (!record.containsKey('user_properties') ||
+ !record.containsKey('events')) {
+ return null;
+ }
+
+ // Parse out values from the top level key = 'events' and return
+ // a map for the one event in the value
+ final eventProp =
+ (record['events']! as List<Object?>).first as Map<String, Object?>;
+ final eventName = eventProp['name'] as String;
+
+ // Parse the data out of the `user_properties` value
+ final userProps = record['user_properties'] as Map<String, Object?>;
+
+ // Parse out the values from the top level key = 'user_properties`
+ final sessionId =
+ (userProps['session_id']! as Map<String, Object?>)['value'] as int?;
+ final flutterChannel = (userProps['flutter_channel']!
+ as Map<String, Object?>)['value'] as String?;
+ final host =
+ (userProps['host']! as Map<String, Object?>)['value'] as String?;
+ final flutterVersion = (userProps['flutter_version']!
+ as Map<String, Object?>)['value'] as String?;
+ final dartVersion = (userProps['dart_version']!
+ as Map<String, Object?>)['value'] as String?;
+ final tool =
+ (userProps['tool']! as Map<String, Object?>)['value'] as String?;
+ final localTimeString =
+ (userProps['local_time']! as Map<String, Object?>)['value'] as String?;
+ final hostOsVersion = (userProps['host_os_version']!
+ as Map<String, Object?>)['value'] as String?;
+ final locale =
+ (userProps['locale']! as Map<String, Object?>)['value'] as String?;
+ final clientIde =
+ (userProps['client_ide']! as Map<String, Object?>)['value'] as String?;
+
+ // If any of the above values are null, return null since that
+ // indicates the record is malformed; note that `flutter_version`,
+ // `flutter_channel`, and `client_ide` are nullable fields in the log file
+ final values = <Object?>[
+ // Values associated with the top level key = 'events'
+ eventName,
+
+ // Values associated with the top level key = 'events'
+ sessionId,
+ host,
+ dartVersion,
+ tool,
+ localTimeString,
+ hostOsVersion,
+ locale,
+ ];
+ for (final value in values) {
+ if (value == null) return null;
+ }
+
+ // Parse the local time from the string extracted
+ final localTime = DateTime.parse(localTimeString!).toLocal();
+
+ return LogItem(
+ eventName: eventName,
+ sessionId: sessionId!,
+ flutterChannel: flutterChannel,
+ host: host!,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion!,
+ tool: tool!,
+ localTime: localTime,
+ hostOsVersion: hostOsVersion!,
+ locale: locale!,
+ clientIde: clientIde,
+ );
+ }
+}
diff --git a/pkgs/unified_analytics/lib/src/survey_handler.dart b/pkgs/unified_analytics/lib/src/survey_handler.dart
new file mode 100644
index 0000000..7461dfc
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/survey_handler.dart
@@ -0,0 +1,366 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:clock/clock.dart';
+import 'package:file/file.dart';
+import 'package:http/http.dart' as http;
+
+import 'constants.dart';
+import 'enums.dart';
+import 'initializer.dart';
+import 'log_handler.dart';
+
+class Condition {
+ /// How to query the log file.
+ ///
+ ///
+ /// Example: logFileStats.recordCount refers to the
+ /// total record count being returned by [LogFileStats].
+ final String field;
+
+ /// String representation of operator.
+ ///
+ ///
+ /// Allowed values:
+ /// - '>=' `greater than or equal to`
+ /// - '<=' `less than or equal to`
+ /// - '>' `greater than`
+ /// - '<' `less then`
+ /// - '==' `equals`
+ /// - '!=' `not equal`
+ final String operatorString;
+
+ /// The value we will be comparing against using the [operatorString].
+ final int value;
+
+ /// One of the conditions that need to be valid for
+ /// a survey to be returned to the user.
+ ///
+ /// Example of raw json:
+ /// ```
+ /// {
+ /// "field": "logFileStats.recordCount",
+ /// "operator": ">=",
+ /// "value": 1000
+ /// }
+ /// ```
+ Condition(
+ this.field,
+ this.operatorString,
+ this.value,
+ );
+
+ Condition.fromJson(Map<String, dynamic> json)
+ : field = json['field'] as String,
+ operatorString = json['operator'] as String,
+ value = json['value'] as int;
+
+ Map<String, Object?> toMap() => <String, Object?>{
+ 'field': field,
+ 'operator': operatorString,
+ 'value': value,
+ };
+
+ @override
+ String toString() => jsonEncode(toMap());
+}
+
+/// Data class for the persisted survey contents.
+///
+/// [uniqueId] is the identifier for each survey, [timestamp] refers
+/// to when the survey was added to the persisted file.
+///
+/// The boolean [snoozed] is set to `true` if the survey has been dismissed
+/// temporarily by the user. When set to `false` this indicates that the survey
+/// has been dismissed permanently and will not be shown to the user again.
+class PersistedSurvey {
+ final String uniqueId;
+ final bool snoozed;
+ final DateTime timestamp;
+
+ PersistedSurvey({
+ required this.uniqueId,
+ required this.snoozed,
+ required this.timestamp,
+ });
+
+ @override
+ String toString() => jsonEncode({
+ 'uniqueId': uniqueId,
+ 'snoozed': snoozed,
+ 'timestamp': timestamp.toString(),
+ });
+}
+
+class Survey {
+ final String uniqueId;
+ final DateTime startDate;
+ final DateTime endDate;
+ final String description;
+ final int snoozeForMinutes;
+ final double samplingRate;
+ final List<DashTool> excludeDashToolList;
+ final List<Condition> conditionList;
+ final List<SurveyButton> buttonList;
+
+ /// A data class that contains the relevant information for a given
+ /// survey parsed from the survey's metadata file.
+ const Survey({
+ required this.uniqueId,
+ required this.startDate,
+ required this.endDate,
+ required this.description,
+ required this.snoozeForMinutes,
+ required this.samplingRate,
+ required this.excludeDashToolList,
+ required this.conditionList,
+ required this.buttonList,
+ });
+
+ /// Parse the contents of the json metadata file hosted externally.
+ Survey.fromJson(Map<String, dynamic> json)
+ : uniqueId = json['uniqueId'] as String,
+ startDate = DateTime.parse(json['startDate'] as String),
+ endDate = DateTime.parse(json['endDate'] as String),
+ description = json['description'] as String,
+ // Handle both string and integer fields
+ snoozeForMinutes = json['snoozeForMinutes'] is String
+ ? int.parse(json['snoozeForMinutes'] as String)
+ : json['snoozeForMinutes'] as int,
+ // Handle both string and double fields
+ samplingRate = json['samplingRate'] is String
+ ? double.parse(json['samplingRate'] as String)
+ : json['samplingRate'] as double,
+ excludeDashToolList = (json['excludeDashTools'] as List<dynamic>)
+ .map((e) => DashTool.fromLabel(e as String))
+ .toList(),
+ conditionList = (json['conditions'] as List<dynamic>).map((e) {
+ return Condition.fromJson(e as Map<String, dynamic>);
+ }).toList(),
+ buttonList = (json['buttons'] as List<dynamic>).map((e) {
+ return SurveyButton.fromJson(e as Map<String, dynamic>);
+ }).toList();
+
+ @override
+ String toString() {
+ const encoder = JsonEncoder.withIndent(' ');
+ return encoder.convert({
+ 'uniqueId': uniqueId,
+ 'startDate': startDate.toString(),
+ 'endDate': endDate.toString(),
+ 'description': description,
+ 'snoozeForMinutes': snoozeForMinutes,
+ 'samplingRate': samplingRate,
+ 'conditionList': conditionList.map((e) => e.toMap()).toList(),
+ 'buttonList': buttonList.map((e) => e.toMap()).toList(),
+ });
+ }
+}
+
+class SurveyButton {
+ final String buttonText;
+ final String action;
+ final bool promptRemainsVisible;
+ final String? url;
+
+ SurveyButton({
+ required this.buttonText,
+ required this.action,
+ required this.promptRemainsVisible,
+ this.url,
+ });
+
+ SurveyButton.fromJson(Map<String, dynamic> json)
+ : buttonText = json['buttonText'] as String,
+ action = json['action'] as String,
+ promptRemainsVisible = json['promptRemainsVisible'] as bool,
+ url = json['url'] as String?;
+
+ Map<String, Object?> toMap() => <String, Object?>{
+ 'buttonText': buttonText,
+ 'action': action,
+ 'promptRemainsVisible': promptRemainsVisible,
+ 'url': url,
+ };
+}
+
+class SurveyHandler {
+ final File dismissedSurveyFile;
+
+ SurveyHandler({required this.dismissedSurveyFile});
+
+ /// Invoking this method will persist the survey's id in
+ /// the local file with either a snooze or permanently dismissed
+ /// indicator.
+ ///
+ /// In the snoozed state, the survey will be prompted again after
+ /// the survey's specified snooze period.
+ ///
+ /// Each entry for a survey will have the following format:
+ /// ```
+ /// {
+ /// "survey-unique-id": {
+ /// "status": "snoozed", // status is either snoozed or dismissed
+ /// "timestamp": 1690219834859
+ /// }
+ /// }
+ /// ```
+ void dismiss(Survey survey, bool permanently) {
+ final contents = _parseJsonFile();
+
+ // Add the new data and write back out to the file
+ final status = permanently ? 'dismissed' : 'snoozed';
+ contents[survey.uniqueId] = {
+ 'status': status,
+ 'timestamp': clock.now().millisecondsSinceEpoch,
+ };
+
+ dismissedSurveyFile.writeAsStringSync(jsonEncode(contents));
+ }
+
+ /// Retrieve a list of strings for each [Survey] persisted on disk.
+ ///
+ /// The survey may be in a snoozed or dismissed state based on user action.
+ Map<String, PersistedSurvey> fetchPersistedSurveys() {
+ final contents = _parseJsonFile();
+
+ // Initialize the list of persisted surveys and add to them
+ // as they are being parsed
+ final persistedSurveys = <String, PersistedSurvey>{};
+ contents.forEach((key, value) {
+ value as Map<String, dynamic>;
+
+ final uniqueId = key;
+ final snoozed = value['status'] == 'snoozed' ? true : false;
+ final timestamp =
+ DateTime.fromMillisecondsSinceEpoch(value['timestamp'] as int);
+
+ persistedSurveys[uniqueId] = PersistedSurvey(
+ uniqueId: uniqueId,
+ snoozed: snoozed,
+ timestamp: timestamp,
+ );
+ });
+
+ return persistedSurveys;
+ }
+
+ /// Retrieves the survey metadata file from [kContextualSurveyUrl].
+ Future<List<Survey>> fetchSurveyList() async {
+ final List<dynamic> body;
+ try {
+ final payload = await _fetchContents();
+ body = jsonDecode(payload) as List<dynamic>;
+ // ignore: avoid_catches_without_on_clauses
+ } catch (err) {
+ return [];
+ }
+
+ final surveyList = parseSurveysFromJson(body);
+
+ return surveyList;
+ }
+
+ /// Fetches the json in string form from the remote location.
+ Future<String> _fetchContents() async {
+ final uri = Uri.parse(kContextualSurveyUrl);
+ final response = await http.get(uri);
+ return response.body;
+ }
+
+ /// Method to return a Map representation of the json persisted file.
+ Map<String, dynamic> _parseJsonFile() {
+ Map<String, dynamic> contents;
+ try {
+ contents = jsonDecode(dismissedSurveyFile.readAsStringSync())
+ as Map<String, dynamic>;
+ } on FormatException {
+ createDismissedSurveyFile(dismissedSurveyFile: dismissedSurveyFile);
+ contents = {};
+ } on FileSystemException {
+ createDismissedSurveyFile(dismissedSurveyFile: dismissedSurveyFile);
+ contents = {};
+ }
+
+ return contents;
+ }
+
+ /// Function to ensure that each survey is still valid by
+ /// checking the [Survey.startDate] and [Survey.endDate]
+ /// against the current [clock] now date.
+ static bool checkSurveyDate(Survey survey) {
+ final now = clock.now();
+ return survey.startDate.isBefore(now) && survey.endDate.isAfter(now);
+ }
+
+ /// Function that takes in a json data structure that is in
+ /// the form of a list and returns a list of [Survey] items.
+ ///
+ /// This will also check the survey's dates to make sure it
+ /// has not expired.
+ static List<Survey> parseSurveysFromJson(List<dynamic> body) => body
+ .map((element) {
+ // Error handling to skip any surveys from the remote location
+ // that fail to parse
+ try {
+ return Survey.fromJson(element as Map<String, dynamic>);
+ // ignore: avoid_catching_errors
+ } on TypeError {
+ return null;
+ } on FormatException {
+ return null;
+ } on Exception {
+ return null;
+ }
+ })
+ .whereType<Survey>()
+ .where(checkSurveyDate)
+ .toList();
+}
+
+class FakeSurveyHandler extends SurveyHandler {
+ final List<Survey> _fakeInitializedSurveys = [];
+
+ /// Use this class in tests if you can provide the
+ /// list of [Survey] objects.
+ ///
+ /// Important: the surveys in the [initializedSurveys] list
+ /// will have their dates checked to ensure they are valid; it is
+ /// recommended to use `package:clock` to set a fixed time for testing.
+ FakeSurveyHandler.fromList({
+ required super.dismissedSurveyFile,
+ required List<Survey> initializedSurveys,
+ }) {
+ // We must pass the surveys from the list to the
+ // `checkSurveyDate` function here and not for the
+ // `.fromString()` constructor because the `parseSurveysFromJson`
+ // method already checks their date
+ for (final survey in initializedSurveys) {
+ if (SurveyHandler.checkSurveyDate(survey)) {
+ _fakeInitializedSurveys.add(survey);
+ }
+ }
+ }
+
+ /// Use this class in tests if you can provide raw
+ /// json strings to simulate a response from a remote server.
+ FakeSurveyHandler.fromString({
+ required super.dismissedSurveyFile,
+ required String content,
+ }) {
+ final body = jsonDecode(content) as List<dynamic>;
+ for (final fakeSurvey in SurveyHandler.parseSurveysFromJson(body)) {
+ _fakeInitializedSurveys.add(fakeSurvey);
+ }
+ }
+
+ @override
+ Future<List<Survey>> fetchSurveyList() =>
+ Future<List<Survey>>.value(_fakeInitializedSurveys);
+
+ @override
+ Future<String> _fetchContents() => throw UnimplementedError();
+}
diff --git a/pkgs/unified_analytics/lib/src/user_property.dart b/pkgs/unified_analytics/lib/src/user_property.dart
new file mode 100644
index 0000000..f0e177d
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/user_property.dart
@@ -0,0 +1,162 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:clock/clock.dart';
+import 'package:file/file.dart';
+
+import 'constants.dart';
+import 'event.dart';
+import 'initializer.dart';
+import 'utils.dart';
+
+class UserProperty {
+ final String? flutterChannel;
+ final String host;
+ final String? flutterVersion;
+ final String dartVersion;
+ final String tool;
+ final String hostOsVersion;
+ final String locale;
+ final String? clientIde;
+ final String? enabledFeatures;
+
+ final File sessionFile;
+
+ /// Contains instances of [Event.analyticsException] that were encountered
+ /// during a workflow and will be sent to GA4 for collection.
+ final Set<Event> errorSet = {};
+
+ int? _sessionId;
+
+ /// This class is intended to capture all of the user's
+ /// metadata when the class gets initialized as well as collecting
+ /// session data to send in the json payload to Google Analytics.
+ UserProperty({
+ required this.flutterChannel,
+ required this.host,
+ required this.flutterVersion,
+ required this.dartVersion,
+ required this.tool,
+ required this.hostOsVersion,
+ required this.locale,
+ required this.clientIde,
+ required this.enabledFeatures,
+ required this.sessionFile,
+ });
+
+ /// This will use the data parsed from the
+ /// session file in the dart-tool directory
+ /// to get the session id if the last ping was within
+ /// [kSessionDurationMinutes].
+ ///
+ /// If time since last ping exceeds the duration, then the file
+ /// will be updated with a new session id and that will be returned.
+ ///
+ /// Note, the file will always be updated when calling this method
+ /// because the last ping variable will always need to be persisted.
+ int? getSessionId() {
+ _refreshSessionData();
+ final now = clock.now();
+
+ // Convert the epoch time from the last ping into datetime and check if we
+ // are within the kSessionDurationMinutes.
+ final lastPingDateTime = sessionFile.lastModifiedSync();
+ if (now.difference(lastPingDateTime).inMinutes > kSessionDurationMinutes) {
+ // Update the session file with the latest session id
+ _sessionId = now.millisecondsSinceEpoch;
+ writeSessionContents(sessionFile: sessionFile);
+ } else {
+ // Update the last modified timestamp with the current timestamp so that
+ // we can use it for the next _lastPing calculation
+ sessionFile.setLastModifiedSync(now);
+ }
+
+ return _sessionId;
+ }
+
+ /// This method will take the data in this class and convert it into
+ /// a Map that is suitable for the POST request schema.
+ ///
+ /// This will call the [UserProperty] object's [UserProperty.getSessionId]
+ /// method which will update the session file and get a new session id
+ /// if necessary.
+ ///
+ /// https://developers.google.com/analytics/devguides/collection/protocol/ga4/user-properties?client_type=gtag
+ Map<String, Map<String, Object?>> preparePayload() {
+ return <String, Map<String, Object?>>{
+ for (final entry in _toMap().entries)
+ entry.key: <String, Object?>{'value': entry.value}
+ };
+ }
+
+ @override
+ String toString() {
+ return jsonEncode(_toMap());
+ }
+
+ /// This will go to the session file within the dart-tool
+ /// directory and fetch the latest data from the session file to update
+ /// the class's variables. If the session file is malformed, a new
+ /// session file will be recreated.
+ ///
+ /// This allows the session data in this class to always be up
+ /// to date incase another tool is also calling this package and
+ /// making updates to the session file.
+ void _refreshSessionData() {
+ /// Using a nested function here to reduce verbosity
+ void parseContents() {
+ final sessionFileContents = sessionFile.readAsStringSync();
+ final sessionObj =
+ jsonDecode(sessionFileContents) as Map<String, Object?>;
+ _sessionId = sessionObj['session_id'] as int;
+ }
+
+ try {
+ // Failing to parse the contents will result in the current timestamp
+ // being used as the session id and will get used to recreate the file
+ parseContents();
+ } on FormatException catch (err) {
+ final now = createSessionFile(sessionFile: sessionFile);
+
+ errorSet.add(Event.analyticsException(
+ workflow: 'UserProperty._refreshSessionData',
+ error: err.runtimeType.toString(),
+ description: 'message: ${err.message}\nsource: ${err.source}',
+ ));
+
+ // Fallback to setting the session id as the current time
+ _sessionId = now.millisecondsSinceEpoch;
+ } on FileSystemException catch (err) {
+ final now = createSessionFile(sessionFile: sessionFile);
+
+ errorSet.add(Event.analyticsException(
+ workflow: 'UserProperty._refreshSessionData',
+ error: err.runtimeType.toString(),
+ description: err.osError?.toString(),
+ ));
+
+ // Fallback to setting the session id as the current time
+ _sessionId = now.millisecondsSinceEpoch;
+ }
+ }
+
+ /// Convert the data stored in this class into a map while also
+ /// getting the latest session id using the [UserProperty] class.
+ Map<String, Object?> _toMap() => <String, Object?>{
+ 'session_id': getSessionId(),
+ 'flutter_channel': flutterChannel,
+ 'host': host,
+ 'flutter_version': flutterVersion,
+ 'dart_version': dartVersion,
+ 'analytics_pkg_version': kPackageVersion,
+ 'tool': tool,
+ 'local_time': formatDateTime(clock.now()),
+ 'host_os_version': hostOsVersion,
+ 'locale': locale,
+ 'client_ide': clientIde,
+ 'enabled_features': enabledFeatures,
+ };
+}
diff --git a/pkgs/unified_analytics/lib/src/utils.dart b/pkgs/unified_analytics/lib/src/utils.dart
new file mode 100644
index 0000000..41848a2
--- /dev/null
+++ b/pkgs/unified_analytics/lib/src/utils.dart
@@ -0,0 +1,340 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io' as io;
+import 'dart:math' show Random;
+
+import 'package:clock/clock.dart';
+import 'package:convert/convert.dart';
+import 'package:file/file.dart';
+
+import 'enums.dart';
+import 'event.dart';
+import 'survey_handler.dart';
+import 'user_property.dart';
+
+/// Get a string representation of the current date in the following format:
+/// ```text
+/// yyyy-MM-dd (2023-01-09)
+/// ```
+String get dateStamp {
+ return FixedDateTimeFormatter('YYYY-MM-DD').encode(clock.now());
+}
+
+/// Reads in a directory and returns `true` if write permissions are enabled.
+///
+/// Uses the [FileStat] method `modeString()` to return a string in the form
+/// of `rwxrwxrwx` where the second character in the string indicates if write
+/// is enabled with a `w` or disabled with `-`.
+bool checkDirectoryForWritePermissions(Directory directory) {
+ if (!directory.existsSync()) return false;
+
+ final fileStat = directory.statSync();
+ return fileStat.modeString()[1] == 'w';
+}
+
+/// Format time as 'yyyy-MM-dd HH:mm:ss Z' where Z is the difference between the
+/// timezone of t and UTC formatted according to RFC 822.
+String formatDateTime(DateTime t) {
+ final sign = t.timeZoneOffset.isNegative ? '-' : '+';
+ final tzOffset = t.timeZoneOffset.abs();
+ final hoursOffset = tzOffset.inHours;
+ final minutesOffset =
+ tzOffset.inMinutes - (Duration.minutesPerHour * hoursOffset);
+ assert(hoursOffset < 24);
+ assert(minutesOffset < 60);
+
+ String twoDigits(int n) => (n >= 10) ? '$n' : '0$n';
+ return '$t $sign${twoDigits(hoursOffset)}${twoDigits(minutesOffset)}';
+}
+
+/// Construct the Map that will be converted to json for the
+/// body of the request.
+///
+/// Follows the following schema:
+///
+/// ```
+/// {
+/// "client_id": "46cc0ba6-f604-4fd9-aa2f-8a20beb24cd4",
+/// "events": [{ "name": "testing", "params": { "time_ns": 345 } }],
+/// "user_properties": {
+/// "session_id": { "value": 1673466750423 },
+/// "flutter_channel": { "value": "ey-test-channel" },
+/// "host": { "value": "macos" },
+/// "flutter_version": { "value": "Flutter 3.6.0-7.0.pre.47" },
+/// "dart_version": { "value": "Dart 2.19.0" },
+/// "tool": { "value": "flutter-tools" },
+/// "local_time": { "value": "2023-01-11 14:53:31.471816 -0500" }
+/// }
+/// }
+/// ```
+/// https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events?client_type=gtag
+Map<String, Object?> generateRequestBody({
+ required String clientId,
+ required DashEvent eventName,
+ required Map<String, Object?> eventData,
+ required UserProperty userProperty,
+}) =>
+ <String, Object?>{
+ 'client_id': clientId,
+ 'events': <Map<String, Object?>>[
+ <String, Object?>{
+ 'name': eventName.label,
+ 'params': eventData,
+ }
+ ],
+ 'user_properties': userProperty.preparePayload()
+ };
+
+/// This will use environment variables to get the user's
+/// home directory where all the directory will be created that will
+/// contain all of the analytics files.
+Directory? getHomeDirectory(FileSystem fs) {
+ String? home;
+ final envVars = io.Platform.environment;
+
+ if (io.Platform.isMacOS) {
+ home = envVars['HOME'];
+ } else if (io.Platform.isLinux) {
+ home = envVars['HOME'];
+ } else if (io.Platform.isWindows) {
+ home = envVars['AppData'];
+ }
+
+ if (home == null) return null;
+
+ return fs.directory(home);
+}
+
+/// Returns `true` if user has opted out of legacy analytics in
+/// Dart or Flutter.
+///
+/// Checks legacy opt-out status for the Flutter
+/// and Dart in the following locations.
+///
+/// Dart: `$HOME/.dart/dartdev.json`
+/// ```
+/// {
+/// "firstRun": false,
+/// "enabled": false, <-- THIS USER HAS OPTED OUT
+/// "disclosureShown": true,
+/// "clientId": "52710e60-7c70-4335-b3a4-9d922630f12a"
+/// }
+/// ```
+///
+/// Flutter: `$HOME/.flutter`
+/// ```
+/// {
+/// "firstRun": false,
+/// "clientId": "4c3a3d1e-e545-47e7-b4f8-10129f6ab169",
+/// "enabled": false <-- THIS USER HAS OPTED OUT
+/// }
+/// ```
+///
+/// Devtools: `$HOME/.flutter-devtools/.devtools`
+/// ```
+/// {
+/// "analyticsEnabled": false, <-- THIS USER HAS OPTED OUT
+/// "isFirstRun": false,
+/// "lastReleaseNotesVersion": "2.31.0",
+/// "2023-Q4": {
+/// "surveyActionTaken": false,
+/// "surveyShownCount": 0
+/// }
+/// }
+/// ```
+bool legacyOptOut({required Directory homeDirectory}) {
+ // List of Maps for each of the config file, `key` refers to the
+ // key in the json file that indicates if the user has been opted
+ // out or not
+ final legacyConfigFiles = [
+ (
+ tool: DashTool.dartTool,
+ file: homeDirectory.childDirectory('.dart').childFile('dartdev.json'),
+ key: 'enabled',
+ ),
+ (
+ tool: DashTool.flutterTool,
+ file: homeDirectory.childFile('.flutter'),
+ key: 'enabled',
+ ),
+ (
+ tool: DashTool.devtools,
+ file: homeDirectory
+ .childDirectory('.flutter-devtools')
+ .childFile('.devtools'),
+ key: 'analyticsEnabled',
+ ),
+ ];
+ for (final legacyConfigObj in legacyConfigFiles) {
+ final legacyFile = legacyConfigObj.file;
+ final lookupKey = legacyConfigObj.key;
+
+ if (legacyFile.existsSync()) {
+ try {
+ final legacyFileObj =
+ jsonDecode(legacyFile.readAsStringSync()) as Map<String, Object?>;
+ if (legacyFileObj.containsKey(lookupKey) &&
+ legacyFileObj[lookupKey] == false) {
+ return true;
+ }
+ } on FormatException {
+ // In the case of an error when parsing the json file, return true
+ // which will result in the user being opted out of unified_analytics
+ //
+ // A corrupted file could mean they opted out previously but for some
+ // reason, the file was written incorrectly
+ return true;
+ } on FileSystemException {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/// Helper method that can be used to resolve the Dart SDK version for clients
+/// of package:unified_analytics.
+///
+/// Input [versionString] for this method should be the returned string from
+/// [io.Platform.version].
+///
+/// For tools that don't already have a method for resolving the Dart
+/// SDK version in semver notation, this helper can be used. This uses
+/// the [io.Platform.version] to parse the semver.
+///
+/// Example for stable version:
+/// `3.3.0 (stable) (Tue Feb 13 10:25:19 2024 +0000) on "macos_arm64"` into
+/// `3.3.0`.
+///
+/// Example for non-stable version:
+/// `2.1.0-dev.8.0.flutter-312ae32` into `2.1.0 (build 2.1.0-dev.8.0 312ae32)`.
+String parseDartSDKVersion(String versionString) {
+ versionString = versionString.trim();
+ final justVersion = versionString.split(' ')[0];
+
+ // For non-stable versions, this regex will include build information
+ return justVersion.replaceFirstMapped(RegExp(r'(\d+\.\d+\.\d+)(.+)'),
+ (Match match) {
+ final noFlutter = match[2]!.replaceAll('.flutter-', ' ');
+ return '${match[1]} (build ${match[1]}$noFlutter)'.trim();
+ });
+}
+
+/// Will use two strings to produce a double for applying a sampling
+/// rate for [Survey] to be returned to the user.
+double sampleRate(String string1, String string2) =>
+ ((string1.hashCode + string2.hashCode) % 101) / 100;
+
+/// Function to check if a given [Survey] can be shown again
+/// by checking if it was snoozed or permanently dismissed.
+///
+/// If the [Survey] doesn't exist in the persisted file, then it
+/// will be shown to the user.
+///
+/// If the [Survey] has been permanently dismissed, we will not
+/// show it to the user.
+///
+/// If the [Survey] has been snoozed, we will check the timestamp
+/// that it was snoozed at with the current time from [clock]
+/// and if the snooze period has elapsed, then we will show it to the user.
+bool surveySnoozedOrDismissed(
+ Survey survey,
+ Map<String, PersistedSurvey> persistedSurveyMap,
+) {
+ // If this survey hasn't been persisted yet, it is okay to pass
+ // to the user
+ if (!persistedSurveyMap.containsKey(survey.uniqueId)) return false;
+
+ final persistedSurveyObj = persistedSurveyMap[survey.uniqueId]!;
+
+ // If the survey has been dismissed permanently, we will not show the
+ // survey
+ if (!persistedSurveyObj.snoozed) return true;
+
+ // Find how many minutes has elapsed from the timestamp and now
+ final minutesElapsed =
+ clock.now().difference(persistedSurveyObj.timestamp).inMinutes;
+
+ return survey.snoozeForMinutes > minutesElapsed;
+}
+
+/// Due to some limitations for GA4, this function can be used to
+/// truncate fields that we may not care about truncating, such as
+/// the host os details.
+///
+/// [maxLength] represents the maximum length allowed for the string.
+///
+/// Example:
+/// "Linux 6.2.0-1015-azure #15~22.04.1-Ubuntu SMP Fri Oct 6 13:20:44 UTC 2023"
+///
+/// The above string is what is returned by [io.Platform.operatingSystemVersion]
+/// for certain machines running GitHub Actions, this function will truncate
+/// that value down to the maximum length at 36 characters and return the below
+///
+/// Return:
+/// "Linux 6.2.0-1015-azure #15~22."
+///
+/// This should only be used on fields that are okay to be truncated, this
+/// should not be used for parameters on the [Event] constructors.
+String truncateStringToLength(String str, int maxLength) {
+ if (maxLength <= 0) {
+ throw ArgumentError(
+ 'The length to truncate a string must be greater than 0');
+ }
+
+ if (maxLength > str.length) return str;
+
+ return str.substring(0, maxLength);
+}
+
+/// Writes the JSON string payload to the provided [sessionFile].
+///
+/// The `last_ping` key:value pair has been deprecated, it remains included
+/// for backward compatibility.
+void writeSessionContents({required File sessionFile}) {
+ final now = clock.now();
+ sessionFile.writeAsStringSync('{"session_id": ${now.millisecondsSinceEpoch}, '
+ '"last_ping": ${now.millisecondsSinceEpoch}}');
+}
+
+/// A UUID generator.
+///
+/// This will generate unique IDs in the format:
+///
+/// f47ac10b-58cc-4372-a567-0e02b2c3d479
+///
+/// The generated uuids are 128 bit numbers encoded in a specific string format.
+/// For more information, see
+/// [en.wikipedia.org/wiki/Universally_unique_identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier).
+///
+/// This class was taken from the previous `usage` package (https://github.com/dart-lang/usage/blob/master/lib/uuid/uuid.dart).
+class Uuid {
+ final Random _random;
+
+ Uuid([int? seed]) : _random = Random(seed);
+
+ /// Generate a version 4 (random) uuid. This is a uuid scheme that only uses
+ /// random numbers as the source of the generated uuid.
+ String generateV4() {
+ // Generate xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx / 8-4-4-4-12.
+ final special = 8 + _random.nextInt(4);
+
+ return '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}-'
+ '${_bitsDigits(16, 4)}-'
+ '4${_bitsDigits(12, 3)}-'
+ '${_printDigits(special, 1)}${_bitsDigits(12, 3)}-'
+ '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}';
+ }
+
+ String _bitsDigits(int bitCount, int digitCount) =>
+ _printDigits(_generateBits(bitCount), digitCount);
+
+ int _generateBits(int bitCount) => _random.nextInt(1 << bitCount);
+
+ String _printDigits(int value, int count) =>
+ value.toRadixString(16).padLeft(count, '0');
+}
diff --git a/pkgs/unified_analytics/lib/testing.dart b/pkgs/unified_analytics/lib/testing.dart
new file mode 100644
index 0000000..900212f
--- /dev/null
+++ b/pkgs/unified_analytics/lib/testing.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/enums.dart';
diff --git a/pkgs/unified_analytics/lib/unified_analytics.dart b/pkgs/unified_analytics/lib/unified_analytics.dart
new file mode 100644
index 0000000..bd8e17a
--- /dev/null
+++ b/pkgs/unified_analytics/lib/unified_analytics.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/analytics.dart' show Analytics, FakeAnalytics, NoOpAnalytics;
+export 'src/config_handler.dart' show ToolInfo;
+export 'src/enums.dart' show DashTool;
+export 'src/event.dart' show CustomMetrics, Event;
+export 'src/log_handler.dart' show LogFileStats;
+export 'src/survey_handler.dart' show Survey, SurveyButton, SurveyHandler;
+export 'src/utils.dart' show parseDartSDKVersion;
diff --git a/pkgs/unified_analytics/pubspec.yaml b/pkgs/unified_analytics/pubspec.yaml
new file mode 100644
index 0000000..f0a99f1
--- /dev/null
+++ b/pkgs/unified_analytics/pubspec.yaml
@@ -0,0 +1,26 @@
+name: unified_analytics
+description: >-
+ A package for logging analytics for all Dart and Flutter related tooling
+ to Google Analytics.
+# LINT.IfChange
+# When updating this, keep the version consistent with the changelog and the
+# value in lib/src/constants.dart.
+version: 7.0.1
+# LINT.ThenChange(lib/src/constants.dart)
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/unified_analytics
+issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aunified_analytics
+
+environment:
+ sdk: ^3.4.0
+
+dependencies:
+ clock: ^1.1.1
+ convert: ^3.1.1
+ file: '>=6.1.4 <8.0.0'
+ http: '>=0.13.5 <2.0.0'
+ meta: ^1.9.0
+
+dev_dependencies:
+ dart_flutter_team_lints: ^3.0.0
+ test: ^1.16.6
+ yaml: ^3.1.1
diff --git a/pkgs/unified_analytics/test/asserts_test.dart b/pkgs/unified_analytics/test/asserts_test.dart
new file mode 100644
index 0000000..9230fc6
--- /dev/null
+++ b/pkgs/unified_analytics/test/asserts_test.dart
@@ -0,0 +1,413 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+import 'package:unified_analytics/src/asserts.dart';
+
+void main() {
+ test('Failure if client_id top level key is missing', () {
+ final body = <String, Object?>{};
+
+ final expectedErrorMessage = 'client_id missing from top level keys';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure if events top level key is missing', () {
+ final body = <String, Object?>{'client_id': 'xxxxxxx'};
+
+ final expectedErrorMessage = 'events missing from top level keys';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure if user_properties top level key is missing', () {
+ final body = <String, Object?>{'client_id': 'xxxxxxx', 'events': []};
+
+ final expectedErrorMessage = 'user_properties missing from top level keys';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure if more than 25 events found in events list', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[],
+ 'user_properties': <String, Object?>{}
+ };
+
+ // Add more than the 25 allowed events
+ for (var i = 0; i < 30; i++) {
+ (body['events'] as List).add({'name': i});
+ }
+
+ final expectedErrorMessage = '25 is the max number of events';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when event name is greater than 40 chars', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name':
+ 'hot_reload_timehot_reload_timehot_reload_timehot_reload_time',
+ 'params': {'time_ms': 133, 'count': 1999000}
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage = 'Limit event names to 40 chars or less\n'
+ 'Event name: '
+ '"hot_reload_timehot_reload_timehot_reload_timehot_reload_time"'
+ ' is too long';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when event name has invalid chars', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time!!',
+ 'params': {'time_ms': 133, 'count': 1999000}
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage =
+ 'Event name can only have alphanumeric chars and underscores\n'
+ 'Event name: "hot_reload_time!!" contains invalid characters';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when event name does not start with alphabetic char', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': '2hot_reload_time',
+ 'params': {'time_ms': 133, 'count': 1999000}
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage =
+ 'Event name first char must be alphabetic char\n'
+ 'Event name: "2hot_reload_time" must begin with a valid character';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when an event has more than 25 event params', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ // 'params': {...} SUBBING THIS VALUE OUT 30 Maps
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final params = <String, Object?>{};
+ for (var i = 0; i < 30; i++) {
+ params['$i'] = i;
+ }
+
+ // Add the params to the first event in the body
+ ((body['events'] as List).first as Map)['params'] = params;
+
+ final expectedErrorMessage = 'Limit params for each event to less than 25\n'
+ 'Event: "hot_reload_time" has too many parameters';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when an value for event params is not a supported type (list)',
+ () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {
+ 'time_ms': 133,
+ // Lists and Maps are not supported
+ 'count': <int>[1999000],
+ }
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage =
+ 'Values for event params have to be String, int, double, or bool\n'
+ 'Value for "count" is not a valid type for event: "hot_reload_time"';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when an value for event params is not a supported type (map)',
+ () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {
+ 'time_ms': 133,
+ // Lists and Maps are not supported
+ 'count': <int, int>{5: 20},
+ }
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage =
+ 'Values for event params have to be String, int, double, or bool\n'
+ 'Value for "count" is not a valid type for event: "hot_reload_time"';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when event param name is more than 40 chars', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {'time_mstime_mstime_mstime_mstime_mstime_ms': 133}
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage = 'Limit event param names to 40 chars or less\n'
+ 'The key: "time_mstime_mstime_mstime_mstime_mstime_ms" '
+ 'under the event: "hot_reload_time" is too long';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure for event param name that has invalid chars', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {'time_ns!': 133}
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage =
+ 'Event param name can only have alphanumeric chars and underscores\n'
+ 'The key: "time_ns!" under the event: "hot_reload_time" contains '
+ 'invalid characters';
+
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test(
+ 'Failure for event param name that does not start with an alphabetic char',
+ () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {'22time_ns': 133}
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage =
+ 'Event param name first char must be alphabetic char\n'
+ 'The key: "22time_ns" under the event: "hot_reload_time" must begin '
+ 'in a valid character';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ },
+ );
+
+ test('Failure for event param values that are greater than 100 chars', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {
+ 'time_ns': 'dsfjlksdjfajlfdsfjlks'
+ 'djfajlfdsfjlksdjfajlfdsfjlksdjfaj'
+ 'lfdsfjlksdjfajlfdsfjlksdjfajlfdsf'
+ 'jlksdjfajlfdsfjlksdjfajlf'
+ }
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ final expectedErrorMessage =
+ 'Limit characters in event param value to 100 chars or less\n'
+ 'Value for "time_ns" is too long, value="'
+ 'dsfjlksdjfajlfdsfjlks'
+ 'djfajlfdsfjlksdjfajlfdsfjlksdjfaj'
+ 'lfdsfjlksdjfajlfdsfjlksdjfajlfdsf'
+ 'jlksdjfajlfdsfjlksdjfajlf"';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when body has more than 25 user properties', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {'time_ns': 123}
+ }
+ ],
+ 'user_properties': <String, Object?>{}
+ };
+
+ for (var i = 0; i < 30; i++) {
+ (body['user_properties']! as Map<String, Object?>)['$i'] = i;
+ }
+
+ final expectedErrorMessage = 'Limit user properties to 25 or less';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when user properties names are greater than 24 chars', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {'time_ns': 123}
+ }
+ ],
+ 'user_properties': <String, Object?>{
+ 'testtesttesttesttesttesttest': <String, Object?>{}, // TOO LONG
+ }
+ };
+
+ final expectedErrorMessage =
+ 'Limit user property names to 24 chars or less\n'
+ 'The user property key: "testtesttesttesttesttesttest" is too long';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Failure when user properties values are greater than 36 chars', () {
+ final body = <String, Object?>{
+ 'client_id': 'xxxxxxx',
+ 'events': <Map<String, Object?>>[
+ {
+ 'name': 'hot_reload_time',
+ 'params': {'time_ns': 123}
+ }
+ ],
+ 'user_properties': <String, Object?>{
+ 'test': <String, Object?>{
+ 'value': 'testtesttesttesttesttesttesttesttesttest' // TOO LONG
+ },
+ }
+ };
+
+ final expectedErrorMessage =
+ 'Limit user property values to 36 chars or less\n'
+ 'For the user property key "test", the value '
+ '"testtesttesttesttesttesttesttesttesttest" is too long';
+ expect(
+ () => checkBody(body),
+ throwsA(predicate(
+ (AnalyticsException e) => e.message == expectedErrorMessage,
+ expectedErrorMessage)));
+ });
+
+ test('Successful body passes all asserts', () {
+ final body = <String, Object?>{
+ 'client_id': '46cc0ba6-f604-4fd9-aa2f-8a20beb24cd4',
+ 'events': [
+ {
+ 'name': 'testing',
+ 'params': {'time_ns': 345}
+ }
+ ],
+ 'user_properties': {
+ 'session_id': {'value': 1673466750423},
+ 'flutter_channel': {'value': 'ey-test-channel'},
+ 'host': {'value': 'macos'},
+ 'flutter_version': {'value': 'Flutter 3.6.0-7.0.pre.47'},
+ 'dart_version': {'value': 'Dart 2.19.0'},
+ 'tool': {'value': 'flutter-tools'},
+ 'local_time': {'value': '2023-01-11 14:53:31.471816 -0500'}
+ }
+ };
+
+ expect(() => checkBody(body), returnsNormally);
+ });
+}
diff --git a/pkgs/unified_analytics/test/error_handler_test.dart b/pkgs/unified_analytics/test/error_handler_test.dart
new file mode 100644
index 0000000..39b2df8
--- /dev/null
+++ b/pkgs/unified_analytics/test/error_handler_test.dart
@@ -0,0 +1,346 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' as io;
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/test.dart';
+
+import 'package:unified_analytics/src/constants.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ late MemoryFileSystem fs;
+ late Directory home;
+ late FakeAnalytics initializationAnalytics;
+ late FakeAnalytics analytics;
+ late File sessionFile;
+ late File logFile;
+
+ const homeDirName = 'home';
+ const initialTool = DashTool.flutterTool;
+ const toolsMessageVersion = 1;
+ const toolsMessage = 'toolsMessage';
+ const flutterChannel = 'flutterChannel';
+ const flutterVersion = 'flutterVersion';
+ const dartVersion = 'dartVersion';
+ const platform = DevicePlatform.macos;
+ const clientIde = 'VSCode';
+
+ final testEvent = Event.codeSizeAnalysis(platform: 'platform');
+
+ setUp(() {
+ // Setup the filesystem with the home directory
+ final fsStyle =
+ io.Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix;
+ fs = MemoryFileSystem.test(style: fsStyle);
+ home = fs.directory(homeDirName);
+
+ // This is the first analytics instance that will be used to demonstrate
+ // that events will not be sent with the first run of analytics
+ initializationAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+ expect(initializationAnalytics.shouldShowMessage, true);
+ initializationAnalytics.clientShowedMessage();
+ expect(initializationAnalytics.shouldShowMessage, false);
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ //
+ // This instance should have the same parameters as the one above for
+ // [initializationAnalytics]
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ clientIde: clientIde,
+ );
+ analytics.clientShowedMessage();
+
+ // The files that should have been generated that will be used for tests
+ sessionFile =
+ home.childDirectory(kDartToolDirectoryName).childFile(kSessionFileName);
+ logFile =
+ home.childDirectory(kDartToolDirectoryName).childFile(kLogFileName);
+ });
+
+ group('Session handler:', () {
+ test('no error when opted out already and opting in', () async {
+ // When we opt out from an analytics instance, we clear the contents of
+ // session file, as required by the privacy document. When creating a
+ // second instance of [Analytics], it should not detect that the file is
+ // empty and recreate it, it should remain opted out and no error event
+ // should have been sent
+ await analytics.setTelemetry(false);
+ expect(analytics.telemetryEnabled, false);
+ expect(sessionFile.readAsStringSync(), isEmpty);
+
+ final secondAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ clientIde: clientIde,
+ );
+ expect(sessionFile.readAsStringSync(), isEmpty);
+ expect(secondAnalytics.telemetryEnabled, false);
+
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ isEmpty,
+ );
+ expect(
+ secondAnalytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ isEmpty,
+ );
+
+ await secondAnalytics.setTelemetry(true);
+ expect(sessionFile.readAsStringSync(), isNotEmpty,
+ reason: 'Toggling telemetry should bring back the session data');
+ });
+ test('only sends one event for FormatException', () {
+ // Begin with the session file empty, it should recreate the file
+ // and send an error event
+ sessionFile.writeAsStringSync('');
+ expect(sessionFile.readAsStringSync(), isEmpty);
+ analytics.send(testEvent);
+ expect(sessionFile.readAsStringSync(), isNotEmpty);
+
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(1));
+
+ // Making the file empty again and sending an event should not send
+ // an additional event
+ sessionFile.writeAsStringSync('');
+ expect(sessionFile.readAsStringSync(), isEmpty);
+ analytics.send(testEvent);
+ expect(sessionFile.readAsStringSync(), isNotEmpty);
+
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(1),
+ reason: 'We should not have added a new error event');
+ });
+
+ test('only sends one event for FileSystemException', () {
+ // Deleting the session file should cause the file system exception and
+ // sending a new event should log the error the first time and recreate
+ // the file. If we delete the file again and attempt to send an event,
+ // the session file should get recreated without sending a second error.
+ sessionFile.deleteSync();
+ expect(sessionFile.existsSync(), isFalse);
+ analytics.send(testEvent);
+
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(1),
+ );
+ expect(sessionFile.existsSync(), isTrue);
+ expect(sessionFile.readAsStringSync(), isNotEmpty);
+
+ // Remove the file again and send an event
+ sessionFile.deleteSync();
+ expect(sessionFile.existsSync(), isFalse);
+ analytics.send(testEvent);
+
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(1),
+ reason: 'Only the first error event should exist',
+ );
+ expect(sessionFile.existsSync(), isTrue);
+ expect(sessionFile.readAsStringSync(), isNotEmpty);
+ });
+
+ test('sends two unique errors', () {
+ // Begin with the session file empty, it should recreate the file
+ // and send an error event
+ sessionFile.writeAsStringSync('');
+ expect(sessionFile.readAsStringSync(), isEmpty);
+ analytics.send(testEvent);
+ expect(sessionFile.readAsStringSync(), isNotEmpty);
+
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(1));
+
+ // Deleting the file now before sending an additional event should
+ // cause a different test error
+ sessionFile.deleteSync();
+ expect(sessionFile.existsSync(), isFalse);
+
+ analytics.send(testEvent);
+ expect(sessionFile.readAsStringSync(), isNotEmpty);
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(2));
+ expect(analytics.sentEvents, hasLength(4));
+
+ sessionFile.deleteSync();
+ expect(sessionFile.existsSync(), isFalse);
+
+ analytics.send(testEvent);
+ expect(sessionFile.readAsStringSync(), isNotEmpty);
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(2));
+ });
+ });
+
+ group('Log handler:', () {
+ test('only sends one event for FormatException', () {
+ expect(logFile.existsSync(), isTrue);
+
+ // Write invalid lines to the log file to have a FormatException
+ // thrown when trying to parse the log file
+ logFile.writeAsStringSync('''
+{{}
+{{}
+''');
+
+ // Send one event so that the logFileStats method returns a valid value
+ analytics.send(testEvent);
+ expect(analytics.sentEvents, hasLength(1));
+ expect(logFile.readAsLinesSync(), hasLength(3));
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ isEmpty,
+ );
+
+ // This call below will cause a FormatException while parsing the log file
+ final logFileStats = analytics.logFileStats();
+ expect(logFileStats, isNotNull);
+ expect(logFileStats!.recordCount, 1,
+ reason: 'The error event is not counted');
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(1),
+ );
+ expect(logFile.readAsLinesSync(), hasLength(4));
+ });
+
+ test('only sends one event for TypeError', () {
+ expect(logFile.existsSync(), isTrue);
+ // Write valid json but have one of the types wrong for
+ // the keys so that we throw a TypeError while casting the values
+ //
+ // In the json below, we have made the session id value a string when
+ // it should be an integer
+ logFile.writeAsStringSync('''
+{"client_id":"fcd6c0d5-6582-4c36-b09e-3ecedee9145c","events":[{"name":"command_usage_values","params":{"workflow":"doctor","commandHasTerminal":true}}],"user_properties":{"session_id":{"value":"this should be a string"},"flutter_channel":{"value":"master"},"host":{"value":"macOS"},"flutter_version":{"value":"3.20.0-2.0.pre.9"},"dart_version":{"value":"3.4.0 (build 3.4.0-99.0.dev)"},"analytics_pkg_version":{"value":"5.8.1"},"tool":{"value":"flutter-tool"},"local_time":{"value":"2024-02-07 15:46:19.920784 -0500"},"host_os_version":{"value":"Version 14.3 (Build 23D56)"},"locale":{"value":"en"},"client_ide":{"value":null},"enabled_features":{"value":"enable-native-assets"}}}
+''');
+ expect(logFile.readAsLinesSync(), hasLength(1));
+
+ // Send the test event so that the LogFileStats object is not null
+ analytics.send(testEvent);
+
+ final logFileStats = analytics.logFileStats();
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(1),
+ );
+ expect(logFileStats, isNotNull);
+ expect(logFileStats!.recordCount, 1);
+ });
+
+ test('sends two unique errors', () {
+ expect(logFile.existsSync(), isTrue);
+
+ // Write invalid lines to the log file to have a FormatException
+ // thrown when trying to parse the log file
+ logFile.writeAsStringSync('''
+{{}
+{{}
+''');
+
+ // Send one event so that the logFileStats method returns a valid value
+ analytics.send(testEvent);
+ expect(analytics.sentEvents, hasLength(1));
+ expect(logFile.readAsLinesSync(), hasLength(3));
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ isEmpty,
+ );
+
+ // This will cause the first error
+ analytics.logFileStats();
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(1),
+ );
+
+ // Overwrite the contents of the log file now to include something that
+ // will cause a TypeError by changing the expected value for session id
+ // from integer to a string
+ logFile.writeAsStringSync('''
+{"client_id":"fcd6c0d5-6582-4c36-b09e-3ecedee9145c","events":[{"name":"command_usage_values","params":{"workflow":"doctor","commandHasTerminal":true}}],"user_properties":{"session_id":{"value":"this should be a string"},"flutter_channel":{"value":"master"},"host":{"value":"macOS"},"flutter_version":{"value":"3.20.0-2.0.pre.9"},"dart_version":{"value":"3.4.0 (build 3.4.0-99.0.dev)"},"analytics_pkg_version":{"value":"5.8.1"},"tool":{"value":"flutter-tool"},"local_time":{"value":"2024-02-07 15:46:19.920784 -0500"},"host_os_version":{"value":"Version 14.3 (Build 23D56)"},"locale":{"value":"en"},"client_ide":{"value":null},"enabled_features":{"value":"enable-native-assets"}}}
+''');
+ expect(logFile.readAsLinesSync(), hasLength(1));
+
+ // This will cause the second error
+ analytics.logFileStats();
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(2),
+ );
+
+ // Attempting to cause the same error won't send another error event
+ analytics.logFileStats();
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents.where(
+ (element) => element.eventName == DashEvent.analyticsException),
+ hasLength(2),
+ );
+ });
+ });
+}
diff --git a/pkgs/unified_analytics/test/event_test.dart b/pkgs/unified_analytics/test/event_test.dart
new file mode 100644
index 0000000..2db0b2a
--- /dev/null
+++ b/pkgs/unified_analytics/test/event_test.dart
@@ -0,0 +1,714 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:mirrors';
+
+import 'package:test/test.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/src/event.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ test('Event.analyticsCollectionEnabled constructed', () {
+ Event generateEvent() => Event.analyticsCollectionEnabled(status: false);
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.analyticsCollectionEnabled);
+ expect(constructedEvent.eventData['status'], false);
+ expect(constructedEvent.eventData.length, 1);
+ });
+
+ test('Event.clientNotification constructed', () {
+ Event generateEvent() => Event.clientNotification(
+ duration: 'duration',
+ latency: 'latency',
+ method: 'method',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.clientNotification);
+ expect(constructedEvent.eventData['duration'], 'duration');
+ expect(constructedEvent.eventData['latency'], 'latency');
+ expect(constructedEvent.eventData['method'], 'method');
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.clientRequest constructed', () {
+ Event generateEvent() => Event.clientRequest(
+ duration: 'duration',
+ latency: 'latency',
+ method: 'method',
+ added: 'added',
+ excluded: 'excluded',
+ files: 'files',
+ included: 'included',
+ openWorkspacePaths: 'openWorkspacePaths',
+ removed: 'removed',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.clientRequest);
+ expect(constructedEvent.eventData['duration'], 'duration');
+ expect(constructedEvent.eventData['latency'], 'latency');
+ expect(constructedEvent.eventData['method'], 'method');
+ expect(constructedEvent.eventData['added'], 'added');
+ expect(constructedEvent.eventData['excluded'], 'excluded');
+ expect(constructedEvent.eventData['files'], 'files');
+ expect(constructedEvent.eventData['included'], 'included');
+ expect(
+ constructedEvent.eventData['openWorkspacePaths'], 'openWorkspacePaths');
+ expect(constructedEvent.eventData['removed'], 'removed');
+ expect(constructedEvent.eventData.length, 9);
+ });
+
+ test('Event.commandExecuted constructed', () {
+ Event generateEvent() => Event.commandExecuted(
+ count: 5,
+ name: 'name',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.commandExecuted);
+ expect(constructedEvent.eventData['count'], 5);
+ expect(constructedEvent.eventData['name'], 'name');
+ expect(constructedEvent.eventData.length, 2);
+ });
+
+ test('Event.contextStructure constructed', () {
+ Event generateEvent() => Event.contextStructure(
+ contextsFromBothFiles: 1,
+ contextsFromOptionsFiles: 2,
+ contextsFromPackagesFiles: 3,
+ contextsWithoutFiles: 4,
+ immediateFileCount: 5,
+ immediateFileLineCount: 6,
+ numberOfContexts: 7,
+ transitiveFileCount: 8,
+ transitiveFileLineCount: 9,
+ transitiveFileUniqueCount: 10,
+ transitiveFileUniqueLineCount: 11,
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.contextStructure);
+ expect(constructedEvent.eventData['contextsFromBothFiles'], 1);
+ expect(constructedEvent.eventData['contextsFromOptionsFiles'], 2);
+ expect(constructedEvent.eventData['contextsFromPackagesFiles'], 3);
+ expect(constructedEvent.eventData['contextsWithoutFiles'], 4);
+ expect(constructedEvent.eventData['immediateFileCount'], 5);
+ expect(constructedEvent.eventData['immediateFileLineCount'], 6);
+ expect(constructedEvent.eventData['numberOfContexts'], 7);
+ expect(constructedEvent.eventData['transitiveFileCount'], 8);
+ expect(constructedEvent.eventData['transitiveFileLineCount'], 9);
+ expect(constructedEvent.eventData['transitiveFileUniqueCount'], 10);
+ expect(constructedEvent.eventData['transitiveFileUniqueLineCount'], 11);
+ expect(constructedEvent.eventData.length, 11);
+ });
+
+ test('Event.dartCliCommandExecuted constructed', () {
+ Event generateEvent() => Event.dartCliCommandExecuted(
+ name: 'name',
+ enabledExperiments: 'enabledExperiments',
+ exitCode: 0,
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.dartCliCommandExecuted);
+ expect(constructedEvent.eventData['name'], 'name');
+ expect(
+ constructedEvent.eventData['enabledExperiments'], 'enabledExperiments');
+ expect(constructedEvent.eventData['exitCode'], 0);
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.doctorValidatorResult constructed', () {
+ Event generateEvent() => Event.doctorValidatorResult(
+ validatorName: 'validatorName',
+ result: 'success',
+ partOfGroupedValidator: false,
+ doctorInvocationId: 123,
+ statusInfo: 'statusInfo',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.doctorValidatorResult);
+ expect(constructedEvent.eventData['validatorName'], 'validatorName');
+ expect(constructedEvent.eventData['result'], 'success');
+ expect(constructedEvent.eventData['partOfGroupedValidator'], false);
+ expect(constructedEvent.eventData['doctorInvocationId'], 123);
+ expect(constructedEvent.eventData['statusInfo'], 'statusInfo');
+ expect(constructedEvent.eventData.length, 5);
+ });
+
+ test('Event.hotReloadTime constructed', () {
+ Event generateEvent() => Event.hotReloadTime(timeMs: 500);
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.hotReloadTime);
+ expect(constructedEvent.eventData['timeMs'], 500);
+ expect(constructedEvent.eventData.length, 1);
+ });
+
+ test('Event.lintUsageCount constructed', () {
+ Event generateEvent() => Event.lintUsageCount(
+ count: 5,
+ name: 'name',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.lintUsageCount);
+ expect(constructedEvent.eventData['count'], 5);
+ expect(constructedEvent.eventData['name'], 'name');
+ expect(constructedEvent.eventData.length, 2);
+ });
+
+ test('Event.memoryInfo constructed', () {
+ Event generateEvent() => Event.memoryInfo(
+ rss: 4,
+ periodSec: 5,
+ mbPerSec: 5.55,
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.memoryInfo);
+ expect(constructedEvent.eventData['rss'], 4);
+ expect(constructedEvent.eventData['periodSec'], 5);
+ expect(constructedEvent.eventData['mbPerSec'], 5.55);
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.pluginRequest constructed', () {
+ Event generateEvent() => Event.pluginRequest(
+ duration: 'duration',
+ method: 'method',
+ pluginId: 'pluginId',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.pluginRequest);
+ expect(constructedEvent.eventData['duration'], 'duration');
+ expect(constructedEvent.eventData['method'], 'method');
+ expect(constructedEvent.eventData['pluginId'], 'pluginId');
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.pluginUse constructed', () {
+ Event generateEvent() => Event.pluginUse(
+ count: 5,
+ enabled: 'enabled',
+ pluginId: 'pluginId',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.pluginUse);
+ expect(constructedEvent.eventData['count'], 5);
+ expect(constructedEvent.eventData['enabled'], 'enabled');
+ expect(constructedEvent.eventData['pluginId'], 'pluginId');
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.pubGet constructed', () {
+ Event generateEvent() => Event.pubGet(
+ packageName: 'packageName',
+ version: 'version',
+ dependencyType: 'dependencyType',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.pubGet);
+ expect(constructedEvent.eventData['packageName'], 'packageName');
+ expect(constructedEvent.eventData['version'], 'version');
+ expect(constructedEvent.eventData['dependencyType'], 'dependencyType');
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.serverSession constructed', () {
+ Event generateEvent() => Event.serverSession(
+ clientId: 'clientId',
+ clientVersion: 'clientVersion',
+ duration: 5,
+ flags: 'flags',
+ parameters: 'parameters',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.serverSession);
+ expect(constructedEvent.eventData['clientId'], 'clientId');
+ expect(constructedEvent.eventData['clientVersion'], 'clientVersion');
+ expect(constructedEvent.eventData['duration'], 5);
+ expect(constructedEvent.eventData['flags'], 'flags');
+ expect(constructedEvent.eventData['parameters'], 'parameters');
+ expect(constructedEvent.eventData.length, 5);
+ });
+
+ test('Event.severityAdjustment constructed', () {
+ Event generateEvent() => Event.severityAdjustment(
+ diagnostic: 'diagnostic',
+ adjustments: 'adjustments',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.severityAdjustment);
+ expect(constructedEvent.eventData['diagnostic'], 'diagnostic');
+ expect(constructedEvent.eventData['adjustments'], 'adjustments');
+ expect(constructedEvent.eventData.length, 2);
+ });
+
+ test('Event.surveyAction constructed', () {
+ Event generateEvent() => Event.surveyAction(
+ surveyId: 'surveyId',
+ status: 'status',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.surveyAction);
+ expect(constructedEvent.eventData['surveyId'], 'surveyId');
+ expect(constructedEvent.eventData['status'], 'status');
+ expect(constructedEvent.eventData.length, 2);
+ });
+
+ test('Event.surveyShown constructed', () {
+ Event generateEvent() => Event.surveyShown(surveyId: 'surveyId');
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.surveyShown);
+ expect(constructedEvent.eventData['surveyId'], 'surveyId');
+ expect(constructedEvent.eventData.length, 1);
+ });
+
+ test('Event.flutterBuildInfo constructed', () {
+ Event generateEvent() => Event.flutterBuildInfo(
+ label: 'label',
+ buildType: 'buildType',
+ command: 'command',
+ settings: 'settings',
+ error: 'error',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.flutterBuildInfo);
+ expect(constructedEvent.eventData['label'], 'label');
+ expect(constructedEvent.eventData['buildType'], 'buildType');
+ expect(constructedEvent.eventData['command'], 'command');
+ expect(constructedEvent.eventData['settings'], 'settings');
+ expect(constructedEvent.eventData['error'], 'error');
+ expect(constructedEvent.eventData.length, 5);
+ });
+
+ test('Event.hotRunnerInfo constructed', () {
+ Event generateEvent() => Event.hotRunnerInfo(
+ label: 'label',
+ targetPlatform: 'targetPlatform',
+ sdkName: 'sdkName',
+ emulator: false,
+ fullRestart: true,
+ reason: 'reason',
+ finalLibraryCount: 5,
+ syncedLibraryCount: 6,
+ syncedClassesCount: 7,
+ syncedProceduresCount: 8,
+ syncedBytes: 9,
+ invalidatedSourcesCount: 10,
+ transferTimeInMs: 11,
+ overallTimeInMs: 12,
+ compileTimeInMs: 13,
+ findInvalidatedTimeInMs: 14,
+ scannedSourcesCount: 15,
+ reassembleTimeInMs: 16,
+ reloadVMTimeInMs: 17,
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.hotRunnerInfo);
+ expect(constructedEvent.eventData['label'], 'label');
+ expect(constructedEvent.eventData['targetPlatform'], 'targetPlatform');
+ expect(constructedEvent.eventData['sdkName'], 'sdkName');
+ expect(constructedEvent.eventData['emulator'], false);
+ expect(constructedEvent.eventData['fullRestart'], true);
+ expect(constructedEvent.eventData['reason'], 'reason');
+ expect(constructedEvent.eventData['finalLibraryCount'], 5);
+ expect(constructedEvent.eventData['syncedLibraryCount'], 6);
+ expect(constructedEvent.eventData['syncedClassesCount'], 7);
+ expect(constructedEvent.eventData['syncedProceduresCount'], 8);
+ expect(constructedEvent.eventData['syncedBytes'], 9);
+ expect(constructedEvent.eventData['invalidatedSourcesCount'], 10);
+ expect(constructedEvent.eventData['transferTimeInMs'], 11);
+ expect(constructedEvent.eventData['overallTimeInMs'], 12);
+ expect(constructedEvent.eventData['compileTimeInMs'], 13);
+ expect(constructedEvent.eventData['findInvalidatedTimeInMs'], 14);
+ expect(constructedEvent.eventData['scannedSourcesCount'], 15);
+ expect(constructedEvent.eventData['reassembleTimeInMs'], 16);
+ expect(constructedEvent.eventData['reloadVMTimeInMs'], 17);
+ expect(constructedEvent.eventData.length, 19);
+ });
+
+ test('Event.flutterCommandResult constructed', () {
+ Event generateEvent() => Event.flutterCommandResult(
+ commandPath: 'commandPath',
+ result: 'result',
+ commandHasTerminal: true,
+ maxRss: 123,
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.flutterCommandResult);
+ expect(constructedEvent.eventData['commandPath'], 'commandPath');
+ expect(constructedEvent.eventData['result'], 'result');
+ expect(constructedEvent.eventData['commandHasTerminal'], true);
+ expect(constructedEvent.eventData['maxRss'], 123);
+ expect(constructedEvent.eventData.length, 4);
+ });
+
+ test('Event.codeSizeAnalysis constructed', () {
+ Event generateEvent() => Event.codeSizeAnalysis(platform: 'platform');
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.codeSizeAnalysis);
+ expect(constructedEvent.eventData['platform'], 'platform');
+ expect(constructedEvent.eventData.length, 1);
+ });
+
+ test('Event.appleUsageEvent constructed', () {
+ Event generateEvent() => Event.appleUsageEvent(
+ workflow: 'workflow',
+ parameter: 'parameter',
+ result: 'result',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.appleUsageEvent);
+ expect(constructedEvent.eventData['workflow'], 'workflow');
+ expect(constructedEvent.eventData['parameter'], 'parameter');
+ expect(constructedEvent.eventData['result'], 'result');
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.exception constructed', () {
+ Event generateEvent() => Event.exception(
+ exception: 'exception',
+ data: {'foo': 'bar', 'baz': 1, 'shouldBeRemoved': null},
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.exception);
+ expect(constructedEvent.eventData['exception'], 'exception');
+ expect(constructedEvent.eventData['foo'], 'bar');
+ expect(constructedEvent.eventData['baz'], 1);
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.exception constructor works when no data is provided', () {
+ Event generateEvent() => Event.exception(
+ exception: 'exception',
+ );
+
+ expect(generateEvent, returnsNormally);
+ });
+
+ test('Event.timing constructed', () {
+ Event generateEvent() => Event.timing(
+ workflow: 'workflow',
+ variableName: 'variableName',
+ elapsedMilliseconds: 123,
+ label: 'label',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.timing);
+ expect(constructedEvent.eventData['workflow'], 'workflow');
+ expect(constructedEvent.eventData['variableName'], 'variableName');
+ expect(constructedEvent.eventData['elapsedMilliseconds'], 123);
+ expect(constructedEvent.eventData['label'], 'label');
+ expect(constructedEvent.eventData.length, 4);
+ });
+
+ test('Event.commandUsageValues constructed', () {
+ Event generateEvent() => Event.commandUsageValues(
+ workflow: 'workflow',
+ commandHasTerminal: true,
+ buildBundleTargetPlatform: 'buildBundleTargetPlatform',
+ buildBundleIsModule: true,
+ buildAarProjectType: 'buildAarProjectType',
+ buildAarTargetPlatform: 'buildAarTargetPlatform',
+ buildApkTargetPlatform: 'buildApkTargetPlatform',
+ buildApkBuildMode: 'buildApkBuildMode',
+ buildApkSplitPerAbi: true,
+ buildAppBundleTargetPlatform: 'buildAppBundleTargetPlatform',
+ buildAppBundleBuildMode: 'buildAppBundleBuildMode',
+ createProjectType: 'createProjectType',
+ createAndroidLanguage: 'createAndroidLanguage',
+ createIosLanguage: 'createIosLanguage',
+ packagesNumberPlugins: 123,
+ packagesProjectModule: true,
+ packagesAndroidEmbeddingVersion: 'packagesAndroidEmbeddingVersion',
+ runIsEmulator: true,
+ runTargetName: 'runTargetName',
+ runTargetOsVersion: 'runTargetOsVersion',
+ runModeName: 'runModeName',
+ runProjectModule: true,
+ runProjectHostLanguage: 'runProjectHostLanguage',
+ runAndroidEmbeddingVersion: 'runAndroidEmbeddingVersion',
+ runEnableImpeller: true,
+ runIOSInterfaceType: 'runIOSInterfaceType',
+ runIsTest: true,
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.commandUsageValues);
+ expect(constructedEvent.eventData['workflow'], 'workflow');
+ expect(constructedEvent.eventData['buildBundleTargetPlatform'],
+ 'buildBundleTargetPlatform');
+ expect(constructedEvent.eventData['buildBundleIsModule'], true);
+ expect(constructedEvent.eventData['buildAarProjectType'],
+ 'buildAarProjectType');
+ expect(constructedEvent.eventData['buildAarTargetPlatform'],
+ 'buildAarTargetPlatform');
+ expect(constructedEvent.eventData['buildApkTargetPlatform'],
+ 'buildApkTargetPlatform');
+ expect(
+ constructedEvent.eventData['buildApkBuildMode'], 'buildApkBuildMode');
+ expect(constructedEvent.eventData['buildApkSplitPerAbi'], true);
+ expect(constructedEvent.eventData['buildAppBundleTargetPlatform'],
+ 'buildAppBundleTargetPlatform');
+ expect(constructedEvent.eventData['buildAppBundleBuildMode'],
+ 'buildAppBundleBuildMode');
+ expect(
+ constructedEvent.eventData['createProjectType'], 'createProjectType');
+ expect(constructedEvent.eventData['createAndroidLanguage'],
+ 'createAndroidLanguage');
+ expect(
+ constructedEvent.eventData['createIosLanguage'], 'createIosLanguage');
+ expect(constructedEvent.eventData['packagesNumberPlugins'], 123);
+ expect(constructedEvent.eventData['packagesProjectModule'], true);
+ expect(constructedEvent.eventData['packagesAndroidEmbeddingVersion'],
+ 'packagesAndroidEmbeddingVersion');
+ expect(constructedEvent.eventData['runIsEmulator'], true);
+ expect(constructedEvent.eventData['runTargetName'], 'runTargetName');
+ expect(
+ constructedEvent.eventData['runTargetOsVersion'], 'runTargetOsVersion');
+ expect(constructedEvent.eventData['runModeName'], 'runModeName');
+ expect(constructedEvent.eventData['runProjectModule'], true);
+ expect(constructedEvent.eventData['runProjectHostLanguage'],
+ 'runProjectHostLanguage');
+ expect(constructedEvent.eventData['runAndroidEmbeddingVersion'],
+ 'runAndroidEmbeddingVersion');
+ expect(constructedEvent.eventData['runEnableImpeller'], true);
+ expect(constructedEvent.eventData['runIOSInterfaceType'],
+ 'runIOSInterfaceType');
+ expect(constructedEvent.eventData.length, 27);
+ });
+
+ test('Event.analyticsException constructed', () {
+ Event generateEvent() => Event.analyticsException(
+ workflow: 'workflow',
+ error: 'error',
+ description: 'description',
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventName, DashEvent.analyticsException);
+ expect(constructedEvent.eventData['workflow'], 'workflow');
+ expect(constructedEvent.eventData['error'], 'error');
+ expect(constructedEvent.eventData['description'], 'description');
+ expect(constructedEvent.eventData.length, 3);
+ });
+
+ test('Event.devtoolsEvent constructed', () {
+ Event generateEvent() => Event.devtoolsEvent(
+ screen: 'screen',
+ eventCategory: 'eventCategory',
+ label: 'label',
+ value: 1,
+ userInitiatedInteraction: true,
+ g3Username: 'g3Username',
+ userApp: 'userApp',
+ userBuild: 'userBuild',
+ userPlatform: 'userPlatform',
+ devtoolsPlatform: 'devtoolsPlatform',
+ devtoolsChrome: 'devtoolsChrome',
+ devtoolsVersion: 'devtoolsVersion',
+ ideLaunched: 'ideLaunched',
+ isExternalBuild: 'isExternalBuild',
+ isEmbedded: 'isEmbedded',
+ ideLaunchedFeature: 'ideLaunchedFeature',
+ isWasm: 'true',
+ additionalMetrics: _TestMetrics(
+ stringField: 'test',
+ intField: 100,
+ boolField: false,
+ ),
+ );
+
+ final constructedEvent = generateEvent();
+
+ expect(generateEvent, returnsNormally);
+ expect(constructedEvent.eventData['screen'], 'screen');
+ expect(constructedEvent.eventData['eventCategory'], 'eventCategory');
+ expect(constructedEvent.eventData['label'], 'label');
+ expect(constructedEvent.eventData['value'], 1);
+ expect(constructedEvent.eventData['userInitiatedInteraction'], true);
+ expect(constructedEvent.eventData['g3Username'], 'g3Username');
+ expect(constructedEvent.eventData['userApp'], 'userApp');
+ expect(constructedEvent.eventData['userBuild'], 'userBuild');
+ expect(constructedEvent.eventData['userPlatform'], 'userPlatform');
+ expect(constructedEvent.eventData['devtoolsPlatform'], 'devtoolsPlatform');
+ expect(constructedEvent.eventData['devtoolsChrome'], 'devtoolsChrome');
+ expect(constructedEvent.eventData['devtoolsVersion'], 'devtoolsVersion');
+ expect(constructedEvent.eventData['ideLaunched'], 'ideLaunched');
+ expect(constructedEvent.eventData['isExternalBuild'], 'isExternalBuild');
+ expect(constructedEvent.eventData['isEmbedded'], 'isEmbedded');
+ expect(
+ constructedEvent.eventData['ideLaunchedFeature'],
+ 'ideLaunchedFeature',
+ );
+ expect(constructedEvent.eventData['isWasm'], 'true');
+ expect(constructedEvent.eventData['stringField'], 'test');
+ expect(constructedEvent.eventData['intField'], 100);
+ expect(constructedEvent.eventData['boolField'], false);
+ expect(constructedEvent.eventData.containsKey('nullableField'), false);
+ expect(constructedEvent.eventData.length, 20);
+ });
+
+ test('Confirm all constructors were checked', () {
+ var constructorCount = 0;
+ for (final declaration in reflectClass(Event).declarations.keys) {
+ // Count public constructors but omit private constructors
+ if (declaration.toString().contains('Event.') &&
+ !declaration.toString().contains('Event._')) {
+ constructorCount++;
+ }
+ }
+
+ // Change this integer below if your PR either adds or removes
+ // an Event constructor
+ final eventsAccountedForInTests = 27;
+ expect(eventsAccountedForInTests, constructorCount,
+ reason: 'If you added or removed an event constructor, '
+ 'ensure you have updated '
+ '`pkgs/unified_analytics/test/event_test.dart` '
+ 'to reflect the changes made');
+ });
+
+ test('Serializing event to json successful', () {
+ final event = Event.analyticsException(
+ workflow: 'workflow',
+ error: 'error',
+ description: 'description',
+ );
+
+ final expectedResult = '{"eventName":"analytics_exception",'
+ '"eventData":{"workflow":"workflow",'
+ '"error":"error",'
+ '"description":"description"}}';
+
+ expect(event.toJson(), expectedResult);
+ });
+
+ test('Deserializing string to event successful', () {
+ final eventJson = '{"eventName":"analytics_exception",'
+ '"eventData":{"workflow":"workflow",'
+ '"error":"error",'
+ '"description":"description"}}';
+
+ final eventConstructed = Event.fromJson(eventJson);
+ expect(eventConstructed, isNotNull);
+ eventConstructed!;
+
+ expect(eventConstructed.eventName, DashEvent.analyticsException);
+ expect(eventConstructed.eventData, {
+ 'workflow': 'workflow',
+ 'error': 'error',
+ 'description': 'description',
+ });
+ });
+
+ test('Deserializing string to event unsuccessful for invalid eventName', () {
+ final eventJson = '{"eventName":"NOT_VALID_NAME",'
+ '"eventData":{"workflow":"workflow",'
+ '"error":"error",'
+ '"description":"description"}}';
+
+ final eventConstructed = Event.fromJson(eventJson);
+ expect(eventConstructed, isNull);
+ });
+
+ test('Deserializing string to event unsuccessful for invalid eventData', () {
+ final eventJson = '{"eventName":"analytics_exception",'
+ '"eventData": "not_valid_event_data"}';
+
+ final eventConstructed = Event.fromJson(eventJson);
+ expect(eventConstructed, isNull);
+ });
+}
+
+final class _TestMetrics extends CustomMetrics {
+ _TestMetrics({
+ required this.stringField,
+ required this.intField,
+ required this.boolField,
+ });
+
+ final String stringField;
+ final int intField;
+ final bool boolField;
+
+ @override
+ Map<String, Object> toMap() => {
+ 'stringField': stringField,
+ 'intField': intField,
+ 'boolField': boolField,
+ };
+}
diff --git a/pkgs/unified_analytics/test/events_with_fake_test.dart b/pkgs/unified_analytics/test/events_with_fake_test.dart
new file mode 100644
index 0000000..9794275
--- /dev/null
+++ b/pkgs/unified_analytics/test/events_with_fake_test.dart
@@ -0,0 +1,146 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:clock/clock.dart';
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/test.dart';
+
+import 'package:unified_analytics/src/constants.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/src/survey_handler.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ // The fake analytics instance can be used to ensure events
+ // are being sent when invoking methods on the `Analytics` instance
+
+ late FakeAnalytics fakeAnalytics;
+ late MemoryFileSystem fs;
+ late Directory homeDirectory;
+ late File dismissedSurveyFile;
+
+ /// Survey to load into the fake instance to fetch
+ ///
+ /// The 1.0 sample rate means that this will always show
+ /// up from the method to fetch available surveys
+ final testSurvey = Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2022, 1, 1),
+ endDate: DateTime(2022, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0, // 100% sample rate
+ excludeDashToolList: [],
+ conditionList: <Condition>[],
+ buttonList: [
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'accept',
+ promptRemainsVisible: false,
+ ),
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'dismiss',
+ promptRemainsVisible: false,
+ ),
+ ],
+ );
+
+ setUp(() async {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.posix);
+ homeDirectory = fs.directory('home');
+ dismissedSurveyFile = homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName);
+
+ final initialAnalytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ toolsMessageVersion: 1,
+ fs: fs,
+ platform: DevicePlatform.macos,
+ );
+ initialAnalytics.clientShowedMessage();
+
+ // Recreate a second instance since events cannot be sent on
+ // the first run
+ withClock(Clock.fixed(DateTime(2022, 3, 3)), () {
+ final toolsMessageVersion = kToolsMessageVersion;
+ fakeAnalytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ platform: DevicePlatform.macos,
+ fs: fs,
+ toolsMessageVersion: toolsMessageVersion,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: [testSurvey],
+ ),
+ );
+ });
+ });
+
+ test('event sent when survey shown', () async {
+ final surveyList = await fakeAnalytics.fetchAvailableSurveys();
+ expect(surveyList.length, 1);
+ expect(fakeAnalytics.sentEvents.length, 0);
+
+ final survey = surveyList.first;
+ expect(survey.uniqueId, 'uniqueId');
+
+ // Simulate the survey being shown
+ fakeAnalytics.surveyShown(survey);
+
+ expect(fakeAnalytics.sentEvents.length, 1);
+ expect(fakeAnalytics.sentEvents.last.eventName, DashEvent.surveyShown);
+ expect(fakeAnalytics.sentEvents.last.eventData, {'surveyId': 'uniqueId'});
+ });
+
+ test('event sent when survey accepted', () async {
+ final surveyList = await fakeAnalytics.fetchAvailableSurveys();
+ expect(surveyList.length, 1);
+ expect(fakeAnalytics.sentEvents.length, 0);
+
+ final survey = surveyList.first;
+ expect(survey.uniqueId, 'uniqueId');
+
+ // Simulate the survey being shown
+ //
+ // The first button is the accept button
+ fakeAnalytics.surveyInteracted(
+ survey: survey,
+ surveyButton: survey.buttonList.first,
+ );
+
+ expect(fakeAnalytics.sentEvents.length, 1);
+ expect(fakeAnalytics.sentEvents.last.eventName, DashEvent.surveyAction);
+ expect(fakeAnalytics.sentEvents.last.eventData,
+ {'surveyId': 'uniqueId', 'status': 'accept'});
+ });
+
+ test('event sent when survey rejected', () async {
+ final surveyList = await fakeAnalytics.fetchAvailableSurveys();
+ expect(surveyList.length, 1);
+ expect(fakeAnalytics.sentEvents.length, 0);
+
+ final survey = surveyList.first;
+ expect(survey.uniqueId, 'uniqueId');
+
+ // Simulate the survey being shown
+ //
+ // The last button is the reject button
+ fakeAnalytics.surveyInteracted(
+ survey: survey,
+ surveyButton: survey.buttonList.last,
+ );
+
+ expect(fakeAnalytics.sentEvents.length, 1);
+ expect(fakeAnalytics.sentEvents.last.eventName, DashEvent.surveyAction);
+ expect(fakeAnalytics.sentEvents.last.eventData,
+ {'surveyId': 'uniqueId', 'status': 'dismiss'});
+ });
+}
diff --git a/pkgs/unified_analytics/test/legacy_analytics_test.dart b/pkgs/unified_analytics/test/legacy_analytics_test.dart
new file mode 100644
index 0000000..36acee9
--- /dev/null
+++ b/pkgs/unified_analytics/test/legacy_analytics_test.dart
@@ -0,0 +1,325 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' as io;
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/test.dart';
+
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ late MemoryFileSystem fs;
+ late Directory home;
+ late Analytics analytics;
+
+ const homeDirName = 'home';
+ const initialTool = DashTool.flutterTool;
+ const toolsMessageVersion = 1;
+ const toolsMessage = 'toolsMessage';
+ const flutterChannel = 'flutterChannel';
+ const flutterVersion = 'flutterVersion';
+ const dartVersion = 'dartVersion';
+ const platform = DevicePlatform.macos;
+
+ setUp(() {
+ // Setup the filesystem with the home directory
+ final fsStyle =
+ io.Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix;
+ fs = MemoryFileSystem.test(style: fsStyle);
+ home = fs.directory(homeDirName);
+ });
+
+ test('Honor legacy dart analytics opt out', () {
+ // Create the file for the dart legacy opt out
+ final dartLegacyConfigFile =
+ home.childDirectory('.dart').childFile('dartdev.json');
+ dartLegacyConfigFile.createSync(recursive: true);
+ dartLegacyConfigFile.writeAsStringSync('''
+{
+ "firstRun": false,
+ "enabled": false,
+ "disclosureShown": true,
+ "clientId": "52710e60-7c70-4335-b3a4-9d922630f12a"
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, false);
+ });
+
+ test('Telemetry enabled if legacy dart analytics is enabled', () {
+ // Create the file for the dart legacy opt out
+ final dartLegacyConfigFile =
+ home.childDirectory('.dart').childFile('dartdev.json');
+ dartLegacyConfigFile.createSync(recursive: true);
+ dartLegacyConfigFile.writeAsStringSync('''
+{
+ "firstRun": false,
+ "enabled": true,
+ "disclosureShown": true,
+ "clientId": "52710e60-7c70-4335-b3a4-9d922630f12a"
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, true);
+ });
+
+ test('Honor legacy flutter analytics opt out', () {
+ // Create the file for the flutter legacy opt out
+ final flutterLegacyConfigFile =
+ home.childDirectory('.dart').childFile('dartdev.json');
+ flutterLegacyConfigFile.createSync(recursive: true);
+ flutterLegacyConfigFile.writeAsStringSync('''
+{
+ "firstRun": false,
+ "clientId": "4c3a3d1e-e545-47e7-b4f8-10129f6ab169",
+ "enabled": false
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, false);
+ });
+
+ test('Telemetry enabled if legacy flutter analytics is enabled', () {
+ // Create the file for the flutter legacy opt out
+ final flutterLegacyConfigFile =
+ home.childDirectory('.dart').childFile('dartdev.json');
+ flutterLegacyConfigFile.createSync(recursive: true);
+ flutterLegacyConfigFile.writeAsStringSync('''
+{
+ "firstRun": false,
+ "clientId": "4c3a3d1e-e545-47e7-b4f8-10129f6ab169",
+ "enabled": true
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, true);
+ });
+
+ test('Honor legacy devtools analytics opt out', () {
+ // Create the file for the devtools legacy opt out
+ final devtoolsLegacyConfigFile =
+ home.childDirectory('.flutter-devtools').childFile('.devtools');
+ devtoolsLegacyConfigFile.createSync(recursive: true);
+ devtoolsLegacyConfigFile.writeAsStringSync('''
+{
+ "analyticsEnabled": false,
+ "isFirstRun": false,
+ "lastReleaseNotesVersion": "2.31.0",
+ "2023-Q4": {
+ "surveyActionTaken": false,
+ "surveyShownCount": 0
+ }
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, false);
+ });
+
+ test('Telemetry enabled if legacy devtools analytics is enabled', () {
+ // Create the file for the devtools legacy opt out
+ final devtoolsLegacyConfigFile =
+ home.childDirectory('.flutter-devtools').childFile('.devtools');
+ devtoolsLegacyConfigFile.createSync(recursive: true);
+ devtoolsLegacyConfigFile.writeAsStringSync('''
+{
+ "analyticsEnabled": true,
+ "isFirstRun": false,
+ "lastReleaseNotesVersion": "2.31.0",
+ "2023-Q4": {
+ "surveyActionTaken": false,
+ "surveyShownCount": 0
+ }
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, true);
+ });
+
+ test('Telemetry disabled if dart config file corrupted', () {
+ // Create the file for the dart legacy opt out with text that
+ // is not valid JSON
+ final dartLegacyConfigFile =
+ home.childDirectory('.dart').childFile('dartdev.json');
+ dartLegacyConfigFile.createSync(recursive: true);
+ dartLegacyConfigFile.writeAsStringSync('''
+NOT VALID JSON
+{
+ "firstRun": false,
+ "clientId": "4c3a3d1e-e545-47e7-b4f8-10129f6ab169",
+ "enabled": true
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, false);
+ });
+
+ test('Telemetry disabled if devtools config file corrupted', () {
+ // Create the file for the devtools legacy opt out with text that
+ // is not valid JSON
+ final devtoolsLegacyConfigFile =
+ home.childDirectory('.flutter-devtools').childFile('.devtools');
+ devtoolsLegacyConfigFile.createSync(recursive: true);
+ devtoolsLegacyConfigFile.writeAsStringSync('''
+NOT VALID JSON
+{
+ "analyticsEnabled": true,
+ "isFirstRun": false,
+ "lastReleaseNotesVersion": "2.31.0",
+ "2023-Q4": {
+ "surveyActionTaken": false,
+ "surveyShownCount": 0
+ }
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, false);
+ });
+
+ test('Telemetry disabled if flutter config file corrupted', () {
+ // Create the file for the flutter legacy opt out with text that
+ // is not valid JSON
+ final fluttterLegacyConfigFile =
+ home.childDirectory('.dart').childFile('dartdev.json');
+ fluttterLegacyConfigFile.createSync(recursive: true);
+ fluttterLegacyConfigFile.writeAsStringSync('''
+NOT VALID JSON
+{
+ "firstRun": false,
+ "clientId": "4c3a3d1e-e545-47e7-b4f8-10129f6ab169",
+ "enabled": true
+}
+''');
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(analytics.telemetryEnabled, false);
+ });
+}
diff --git a/pkgs/unified_analytics/test/log_handler_test.dart b/pkgs/unified_analytics/test/log_handler_test.dart
new file mode 100644
index 0000000..db14d96
--- /dev/null
+++ b/pkgs/unified_analytics/test/log_handler_test.dart
@@ -0,0 +1,381 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/fake.dart';
+import 'package:test/test.dart';
+
+import 'package:unified_analytics/src/constants.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/src/log_handler.dart';
+import 'package:unified_analytics/src/utils.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ late FakeAnalytics analytics;
+ late Directory homeDirectory;
+ late MemoryFileSystem fs;
+ late File logFile;
+
+ final testEvent = Event.hotReloadTime(timeMs: 10);
+
+ setUp(() {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.posix);
+ homeDirectory = fs.directory('home');
+ logFile = homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kLogFileName);
+
+ // Create the initialization analytics instance to onboard the tool
+ final initializationAnalytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ );
+ initializationAnalytics.clientShowedMessage();
+
+ // This instance is free to send events since the instance above
+ // has confirmed that the client has shown the message
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ );
+ });
+
+ test('Ensure that log file is created', () {
+ expect(logFile.existsSync(), true);
+ });
+
+ test('LogFileStats is null before events are sent', () {
+ expect(analytics.logFileStats(), isNull);
+ });
+
+ test('LogFileStats returns valid response after sent events', () async {
+ final countOfEventsToSend = 10;
+
+ for (var i = 0; i < countOfEventsToSend; i++) {
+ analytics.send(testEvent);
+ }
+
+ expect(analytics.logFileStats(), isNotNull);
+ expect(logFile.readAsLinesSync().length, countOfEventsToSend);
+ expect(analytics.logFileStats()!.recordCount, countOfEventsToSend);
+ });
+
+ test('The only record in the log file is malformed', () async {
+ // Write invalid json for the only log record
+ logFile.writeAsStringSync('{{\n');
+
+ expect(logFile.readAsLinesSync().length, 1);
+ final logFileStats = analytics.logFileStats();
+ expect(logFileStats, isNull,
+ reason: 'Null should be returned since only '
+ 'one record is in there and it is malformed');
+
+ analytics.sendPendingErrorEvents();
+ expect(
+ analytics.sentEvents,
+ contains(
+ Event.analyticsException(
+ workflow: 'LogFileStats.logFileStats',
+ error: 'FormatException',
+ description: 'message: Unexpected character\nsource: {{',
+ ),
+ ));
+ });
+
+ test('The first record is malformed, but rest are valid', () async {
+ // Write invalid json for the only log record
+ logFile.writeAsStringSync('{{\n');
+
+ final countOfEventsToSend = 10;
+
+ for (var i = 0; i < countOfEventsToSend; i++) {
+ analytics.send(testEvent);
+ }
+ expect(logFile.readAsLinesSync().length, countOfEventsToSend + 1);
+ final logFileStats = analytics.logFileStats();
+
+ expect(logFileStats, isNotNull);
+ expect(logFileStats!.recordCount, countOfEventsToSend);
+ });
+
+ test('Several records are malformed', () async {
+ final countOfMalformedRecords = 4;
+ for (var i = 0; i < countOfMalformedRecords; i++) {
+ final currentContents = logFile.readAsStringSync();
+ logFile.writeAsStringSync('$currentContents{{\n');
+ }
+
+ final countOfEventsToSend = 10;
+
+ for (var i = 0; i < countOfEventsToSend; i++) {
+ analytics.send(testEvent);
+ }
+
+ expect(logFile.readAsLinesSync().length,
+ countOfEventsToSend + countOfMalformedRecords);
+ final logFileStats = analytics.logFileStats();
+
+ analytics.sendPendingErrorEvents();
+ expect(logFile.readAsLinesSync().length,
+ countOfEventsToSend + countOfMalformedRecords + 1,
+ reason:
+ 'There should have been on error event sent when getting stats');
+
+ expect(logFileStats, isNotNull);
+ expect(logFileStats!.recordCount, countOfEventsToSend);
+ });
+
+ test('Valid json but invalid keys', () {
+ // The second line here is missing the "events" top level
+ // key which should cause an error for that record only
+ //
+ // Important to note that this won't actually cause a FormatException
+ // like the other malformed records, instead the LogItem.fromRecord
+ // constructor will return null if all the keys are not available
+ final contents = '''
+{"client_id":"ffcea97b-db5e-4c66-98c2-3942de4fac40","events":[{"name":"hot_reload_time","params":{"timeMs":136}}],"user_properties":{"session_id":{"value":1699385899950},"flutter_channel":{"value":"ey-test-channel"},"host":{"value":"macOS"},"flutter_version":{"value":"Flutter 3.6.0-7.0.pre.47"},"dart_version":{"value":"Dart 2.19.0"},"analytics_pkg_version":{"value":"5.2.0"},"tool":{"value":"flutter-tool"},"local_time":{"value":"2023-11-07 15:37:26.685761 -0500"},"host_os_version":{"value":"Version 14.1 (Build 23B74)"},"locale":{"value":"en"},"client_ide":{"value":"VSCode"}}}
+{"client_id":"ffcea97b-db5e-4c66-98c2-3942de4fac40","WRONG_EVENT_KEY":[{"name":"hot_reload_time","params":{"timeMs":136}}],"user_properties":{"session_id":{"value":1699385899950},"flutter_channel":{"value":"ey-test-channel"},"host":{"value":"macOS"},"flutter_version":{"value":"Flutter 3.6.0-7.0.pre.47"},"dart_version":{"value":"Dart 2.19.0"},"analytics_pkg_version":{"value":"5.2.0"},"tool":{"value":"flutter-tool"},"local_time":{"value":"2023-11-07 15:37:26.685761 -0500"},"host_os_version":{"value":"Version 14.1 (Build 23B74)"},"locale":{"value":"en"},"client_ide":{"value":"VSCode"}}}
+{"client_id":"ffcea97b-db5e-4c66-98c2-3942de4fac40","events":[{"name":"hot_reload_time","params":{"timeMs":136}}],"user_properties":{"session_id":{"value":1699385899950},"flutter_channel":{"value":"ey-test-channel"},"host":{"value":"macOS"},"flutter_version":{"value":"Flutter 3.6.0-7.0.pre.47"},"dart_version":{"value":"Dart 2.19.0"},"analytics_pkg_version":{"value":"5.2.0"},"tool":{"value":"flutter-tool"},"local_time":{"value":"2023-11-07 15:37:26.685761 -0500"},"host_os_version":{"value":"Version 14.1 (Build 23B74)"},"locale":{"value":"en"},"client_ide":{"value":"VSCode"}}}
+''';
+ logFile.writeAsStringSync(contents);
+
+ final logFileStats = analytics.logFileStats();
+
+ expect(logFile.readAsLinesSync().length, 3);
+ expect(logFileStats, isNotNull);
+ expect(logFileStats!.recordCount, 2);
+ });
+
+ test('Malformed record gets phased out after several events', () async {
+ // Write invalid json for the only log record
+ logFile.writeAsStringSync('{{\n');
+
+ // Send the max number of events minus two so that we have
+ // one malformed record on top of the logs and the rest
+ // are valid log records
+ //
+ // We need to account for the event that is sent when
+ // calling [logFileStats()] fails and sends an instance
+ // of [Event.analyticsException]
+ final recordsToSendInitially = kLogFileLength - 2;
+ for (var i = 0; i < recordsToSendInitially; i++) {
+ analytics.send(testEvent);
+ }
+ final logFileStats = analytics.logFileStats();
+ analytics.sendPendingErrorEvents();
+ expect(analytics.sentEvents.last.eventName, DashEvent.analyticsException,
+ reason: 'Calling for the stats should have caused an error');
+ expect(logFile.readAsLinesSync().length, kLogFileLength);
+ expect(logFileStats, isNotNull);
+ expect(logFileStats!.recordCount, recordsToSendInitially,
+ reason: 'The first record should be malformed');
+ expect(logFile.readAsLinesSync()[0].trim(), '{{');
+
+ // Sending one more event should flush out the malformed record
+ analytics.send(testEvent);
+
+ final secondLogFileStats = analytics.logFileStats();
+ expect(analytics.sentEvents.last, testEvent);
+ expect(secondLogFileStats, isNotNull);
+ expect(secondLogFileStats!.recordCount, kLogFileLength);
+ expect(logFile.readAsLinesSync()[0].trim(), isNot('{{'));
+ });
+
+ test(
+ 'Catches and discards any FileSystemException raised from attempting '
+ 'to write to the log file', () async {
+ final logFilePath = 'log.txt';
+ final fs = MemoryFileSystem.test(opHandle: (context, operation) {
+ if (context == logFilePath && operation == FileSystemOp.write) {
+ throw FileSystemException(
+ 'writeFrom failed',
+ logFilePath,
+ const OSError('No space left on device', 28),
+ );
+ }
+ });
+ final logFile = fs.file(logFilePath);
+ logFile.createSync();
+ final logHandler = LogHandler(logFile: logFile);
+
+ logHandler.save(data: {});
+ });
+
+ test('deletes log file larger than kMaxLogFileSize', () async {
+ var deletedLargeLogFile = false;
+ var wroteDataToLogFile = false;
+ const data = <String, Object?>{};
+ final logFile = _FakeFile('log.txt')
+ .._deleteSyncImpl = (() => deletedLargeLogFile = true)
+ .._createSyncImpl = () {}
+ .._statSyncImpl = (() => _FakeFileStat(kMaxLogFileSize + 1))
+ .._writeAsStringSync = (contents, {mode = FileMode.append}) {
+ expect(contents.trim(), data.toString());
+ expect(mode, FileMode.writeOnlyAppend);
+ wroteDataToLogFile = true;
+ };
+ final logHandler = LogHandler(logFile: logFile);
+
+ logHandler.save(data: data);
+ expect(deletedLargeLogFile, isTrue);
+ expect(wroteDataToLogFile, isTrue);
+ });
+
+ test('does not delete log file if smaller than kMaxLogFileSize', () async {
+ var wroteDataToLogFile = false;
+ const data = <String, Object?>{};
+ final logFile = _FakeFile('log.txt')
+ .._deleteSyncImpl =
+ (() => fail('called logFile.deleteSync() when file was less than '
+ 'kMaxLogFileSize'))
+ .._createSyncImpl = () {}
+ .._readAsLinesSyncImpl = (() => ['three', 'previous', 'lines'])
+ .._statSyncImpl = (() => _FakeFileStat(kMaxLogFileSize - 1))
+ .._writeAsStringSync = (contents, {mode = FileMode.append}) {
+ expect(contents.trim(), data.toString());
+ expect(mode, FileMode.writeOnlyAppend);
+ wroteDataToLogFile = true;
+ };
+ final logHandler = LogHandler(logFile: logFile);
+
+ logHandler.save(data: data);
+ expect(wroteDataToLogFile, isTrue);
+ });
+
+ test('Catching cast errors for each log record silently', () async {
+ // Write a json array to the log file which will cause
+ // a cast error when parsing each line
+ logFile.writeAsStringSync('[{}, 1, 2, 3]\n');
+
+ final logFileStats = analytics.logFileStats();
+ expect(logFileStats, isNull);
+
+ // Ensure it will work as expected after writing correct logs
+ final countOfEventsToSend = 10;
+ for (var i = 0; i < countOfEventsToSend; i++) {
+ analytics.send(testEvent);
+ }
+ analytics.sendPendingErrorEvents();
+ final secondLogFileStats = analytics.logFileStats();
+
+ expect(secondLogFileStats, isNotNull);
+ expect(secondLogFileStats!.recordCount, countOfEventsToSend + 1,
+ reason: 'Plus one for the error event that is sent '
+ 'from the first logFileStats call');
+ });
+
+ test(
+ 'truncateStringToLength returns same string when '
+ 'max length greater than string length', () {
+ final testString = 'Version 14.1 (Build 23B74)';
+ final maxLength = 100;
+
+ expect(testString.length < maxLength, true);
+
+ String runTruncateString() => truncateStringToLength(testString, maxLength);
+
+ expect(runTruncateString, returnsNormally);
+
+ final newString = runTruncateString();
+ expect(newString, testString);
+ });
+
+ test(
+ 'truncateStringToLength returns truncated string when '
+ 'max length less than string length', () {
+ final testString = 'Version 14.1 (Build 23B74)';
+ final maxLength = 10;
+
+ expect(testString.length > maxLength, true);
+
+ String runTruncateString() => truncateStringToLength(testString, maxLength);
+
+ expect(runTruncateString, returnsNormally);
+
+ final newString = runTruncateString();
+ expect(newString.length, maxLength);
+ expect(newString, 'Version 14');
+ });
+
+ test('truncateStringToLength handle errors for invalid max length', () {
+ final testString = 'Version 14.1 (Build 23B74)';
+ var maxLength = 0;
+ String runTruncateString() => truncateStringToLength(testString, maxLength);
+
+ expect(runTruncateString, throwsArgumentError);
+
+ maxLength = -1;
+ expect(runTruncateString, throwsArgumentError);
+ });
+
+ test('truncateStringToLength same string when max length is the same', () {
+ final testString = 'Version 14.1 (Build 23B74)';
+ final maxLength = testString.length;
+
+ String runTruncateString() => truncateStringToLength(testString, maxLength);
+ expect(runTruncateString, returnsNormally);
+
+ final newString = runTruncateString();
+ expect(newString.length, maxLength);
+ expect(newString, testString);
+ });
+}
+
+class _FakeFileStat extends Fake implements FileStat {
+ _FakeFileStat(this.size);
+
+ @override
+ final int size;
+}
+
+class _FakeFile extends Fake implements File {
+ _FakeFile(this.path);
+
+ List<String> Function()? _readAsLinesSyncImpl;
+
+ @override
+ List<String> readAsLinesSync({Encoding encoding = utf8}) =>
+ _readAsLinesSyncImpl!();
+
+ @override
+ final String path;
+
+ FileStat Function()? _statSyncImpl;
+
+ @override
+ FileStat statSync() => _statSyncImpl!();
+
+ void Function()? _deleteSyncImpl;
+
+ @override
+ void deleteSync({bool recursive = false}) => _deleteSyncImpl!();
+
+ void Function()? _createSyncImpl;
+
+ @override
+ void createSync({bool recursive = false, bool exclusive = false}) {
+ return _createSyncImpl!();
+ }
+
+ void Function(String contents, {FileMode mode})? _writeAsStringSync;
+
+ @override
+ void writeAsStringSync(
+ String contents, {
+ FileMode mode = FileMode.write,
+ Encoding encoding = utf8,
+ bool flush = false,
+ }) =>
+ _writeAsStringSync!(contents, mode: mode);
+}
diff --git a/pkgs/unified_analytics/test/no_op_analytics_test.dart b/pkgs/unified_analytics/test/no_op_analytics_test.dart
new file mode 100644
index 0000000..66c1ef6
--- /dev/null
+++ b/pkgs/unified_analytics/test/no_op_analytics_test.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:test/fake.dart';
+import 'package:test/test.dart';
+
+import 'package:unified_analytics/src/utils.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ final testEvent = Event.hotReloadTime(timeMs: 50);
+
+ test('NoOpAnalytics.telemetryEnabled is always false', () async {
+ final analytics = const NoOpAnalytics();
+
+ expect(analytics.telemetryEnabled, isFalse);
+ await analytics.setTelemetry(true);
+ expect(analytics.telemetryEnabled, isFalse);
+ });
+
+ test('NoOpAnalytics.shouldShowMessage is always false', () async {
+ final analytics = const NoOpAnalytics();
+
+ expect(analytics.shouldShowMessage, isFalse);
+ analytics.clientShowedMessage();
+ expect(analytics.shouldShowMessage, isFalse);
+ });
+
+ test('NoOpAnalytics.sendEvent() always returns null', () async {
+ final analytics = const NoOpAnalytics();
+
+ await analytics.setTelemetry(true);
+ analytics.clientShowedMessage();
+ expect(
+ analytics.send(testEvent),
+ isNull,
+ );
+ });
+
+ test('NoOpAnalytics.logFileStats() always returns null', () async {
+ final analytics = const NoOpAnalytics();
+
+ expect(analytics.logFileStats(), isNull);
+
+ await analytics.setTelemetry(true);
+ analytics.clientShowedMessage();
+ await analytics.send(testEvent);
+
+ expect(analytics.logFileStats(), isNull);
+ });
+
+ test('Home directory without write permissions', () {
+ final home = FakeDirectory(writeEnabled: false);
+
+ expect(checkDirectoryForWritePermissions(home), false);
+ });
+
+ test('Home directory with write permissions', () {
+ final home = FakeDirectory(writeEnabled: true);
+
+ expect(checkDirectoryForWritePermissions(home), true);
+ });
+
+ test('Fetching the client id', () {
+ final analytics = const NoOpAnalytics();
+ expect(analytics.clientId, 'xxxx-xxxx');
+ });
+}
+
+class FakeDirectory extends Fake implements Directory {
+ final String _fakeModeString;
+
+ /// This fake directory class allows you to pass the permissions for
+ /// the user level, the group and global permissions will default to
+ /// being denied as indicated by the last 6 characters in the mode string.
+ FakeDirectory({
+ required bool writeEnabled,
+ bool readEnabled = true,
+ bool executeEnabled = true,
+ }) : _fakeModeString = '${readEnabled ? "r" : "-"}'
+ '${writeEnabled ? "w" : "-"}'
+ '${executeEnabled ? "x" : "-"}'
+ '------' {
+ assert(_fakeModeString.length == 9);
+ }
+
+ @override
+ bool existsSync() => true;
+
+ @override
+ FileStat statSync() => FakeFileStat(_fakeModeString);
+}
+
+class FakeFileStat extends Fake implements FileStat {
+ final String _fakeModeString;
+
+ FakeFileStat(this._fakeModeString);
+
+ @override
+ String modeString() => _fakeModeString;
+}
diff --git a/pkgs/unified_analytics/test/suppression_test.dart b/pkgs/unified_analytics/test/suppression_test.dart
new file mode 100644
index 0000000..05fab15
--- /dev/null
+++ b/pkgs/unified_analytics/test/suppression_test.dart
@@ -0,0 +1,132 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' as io;
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/test.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ late MemoryFileSystem fs;
+ late Directory home;
+ late Analytics initializationAnalytics;
+ late Analytics analytics;
+
+ const homeDirName = 'home';
+ const initialTool = DashTool.flutterTool;
+ const toolsMessageVersion = 1;
+ const toolsMessage = 'toolsMessage';
+ const flutterChannel = 'flutterChannel';
+ const flutterVersion = 'flutterVersion';
+ const dartVersion = 'dartVersion';
+ const platform = DevicePlatform.macos;
+
+ final testEvent = Event.hotReloadTime(timeMs: 50);
+
+ setUp(() {
+ // Setup the filesystem with the home directory
+ final fsStyle =
+ io.Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix;
+ fs = MemoryFileSystem.test(style: fsStyle);
+ home = fs.directory(homeDirName);
+
+ // This is the first analytics instance that will be used to demonstrate
+ // that events will not be sent with the first run of analytics
+ initializationAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+ initializationAnalytics.clientShowedMessage();
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ //
+ // This instance should have the same parameters as the one above for
+ // [initializationAnalytics]
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+ analytics.clientShowedMessage();
+ });
+
+ test('Suppression works as expected', () async {
+ analytics.suppressTelemetry();
+ analytics.send(testEvent);
+
+ final logFileStats = analytics.logFileStats();
+
+ expect(logFileStats, isNull,
+ reason: 'Returns null because no records have been recorded');
+ });
+
+ test('Second instance is not suppressed', () async {
+ analytics.suppressTelemetry();
+ analytics.send(testEvent);
+
+ final logFileStats = analytics.logFileStats();
+
+ expect(logFileStats, isNull,
+ reason: 'Returns null because no records have been recorded');
+
+ // The newly created instance will not be suppressed
+ final secondAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ // Using a new event here to differentiate from the first one
+ final newEvent = Event.commandExecuted(count: 2, name: 'commandName');
+ secondAnalytics.send(newEvent);
+
+ // Both instances of `Analytics` should now have data retrieved
+ // from `LogFileStats()` even though only the second instance
+ // was the instance to send an event
+ final secondLogFileStats = analytics.logFileStats()!;
+ final thirdLogFileStats = secondAnalytics.logFileStats()!;
+
+ // Series of checks for each parameter in logFileStats
+ expect(secondLogFileStats.startDateTime, thirdLogFileStats.startDateTime);
+ expect(secondLogFileStats.minsFromStartDateTime,
+ thirdLogFileStats.minsFromStartDateTime);
+ expect(secondLogFileStats.endDateTime, thirdLogFileStats.endDateTime);
+ expect(secondLogFileStats.minsFromEndDateTime,
+ thirdLogFileStats.minsFromEndDateTime);
+ expect(secondLogFileStats.sessionCount, thirdLogFileStats.sessionCount);
+ expect(secondLogFileStats.flutterChannelCount,
+ thirdLogFileStats.flutterChannelCount);
+ expect(secondLogFileStats.toolCount, thirdLogFileStats.toolCount);
+ expect(secondLogFileStats.recordCount, thirdLogFileStats.recordCount);
+ expect(secondLogFileStats.eventCount, thirdLogFileStats.eventCount);
+
+ // Ensure the correct data is in the object
+ expect(secondLogFileStats.eventCount.containsKey(newEvent.eventName.label),
+ true);
+ expect(secondLogFileStats.eventCount[newEvent.eventName.label], 1);
+ });
+}
diff --git a/pkgs/unified_analytics/test/survey_handler_test.dart b/pkgs/unified_analytics/test/survey_handler_test.dart
new file mode 100644
index 0000000..3d8c8dd
--- /dev/null
+++ b/pkgs/unified_analytics/test/survey_handler_test.dart
@@ -0,0 +1,1229 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:clock/clock.dart';
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/test.dart';
+
+import 'package:unified_analytics/src/constants.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/src/survey_handler.dart';
+import 'package:unified_analytics/src/utils.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ final testEvent = Event.hotReloadTime(timeMs: 10);
+
+ group('Unit testing function sampleRate:', () {
+ // Set a string that can be used in place of a survey's unique ID
+ final iterations = 1000;
+ final uuid = Uuid(123);
+ final uniqueSurveyId = uuid.generateV4();
+
+ // Set how much the actual sampled rate can be (allowing 5% of variability)
+ final marginOfError = 0.05;
+
+ test('Unit testing the sampleRate method', () {
+ // These strings had a predetermined output from the utility function
+ final string1 = 'string1';
+ final string2 = 'string2';
+ expect(sampleRate(string1, string2), 0.40);
+ });
+
+ test('Simulating with various sample rates', () {
+ final sampleRateToTestList = [
+ 0.10,
+ 0.25,
+ 0.50,
+ 0.75,
+ 0.80,
+ 0.95,
+ ];
+ for (final sampleRateToTest in sampleRateToTestList) {
+ var count = 0;
+ for (var i = 0; i < iterations; i++) {
+ // Regenerate the client id to simulate a unique user
+ final generatedClientId = uuid.generateV4();
+ if (sampleRate(uniqueSurveyId, generatedClientId) <=
+ sampleRateToTest) {
+ count += 1;
+ }
+ }
+
+ final actualSampledRate = count / iterations;
+ final actualMarginOfError =
+ (sampleRateToTest - actualSampledRate).abs();
+
+ expect(actualMarginOfError < marginOfError, true,
+ reason: 'Failed on sample rate = $sampleRateToTest with'
+ ' actual rate $actualMarginOfError '
+ 'and a margin of error = $marginOfError');
+ }
+ });
+ });
+
+ group('Unit testing function checkSurveyDate:', () {
+ final date = DateTime(2023, 5, 1);
+ // Two surveys created, one that is within the survey date
+ // range, and one that is not
+ final validSurvey = Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[],
+ buttonList: [],
+ );
+ final invalidSurvey = Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2022, 1, 1),
+ endDate: DateTime(2022, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[],
+ buttonList: [],
+ );
+
+ test('expired survey', () {
+ final clock = Clock.fixed(date);
+ withClock(clock, () {
+ expect(SurveyHandler.checkSurveyDate(invalidSurvey), false);
+ });
+ });
+
+ test('valid survey', () {
+ final clock = Clock.fixed(date);
+ withClock(clock, () {
+ expect(SurveyHandler.checkSurveyDate(validSurvey), true);
+ });
+ });
+ });
+
+ group('Unit testing function parseSurveysFromJson', () {
+ final validContents = '''
+[
+ {
+ "uniqueId": "xxxxx",
+ "startDate": "2023-06-01T09:00:00-07:00",
+ "endDate": "2023-06-30T09:00:00-07:00",
+ "description": "xxxxxxx",
+ "snoozeForMinutes": "10",
+ "samplingRate": "1.0",
+ "excludeDashTools": [],
+ "conditions": [
+ {
+ "field": "logFileStats.recordCount",
+ "operator": ">=",
+ "value": 1000
+ },
+ {
+ "field": "logFileStats.toolCount.flutter-tool",
+ "operator": "<",
+ "value": 3
+ }
+ ],
+ "buttons": [
+ {
+ "buttonText": "Take Survey",
+ "action": "accept",
+ "url": "https://google.qualtrics.com/jfe/form/SV_5gsB2EuG324y2",
+ "promptRemainsVisible": false
+ }
+ ]
+ }
+]
+''';
+
+ // The value for the condition is not a valid integer
+ final invalidConditionValueContents = '''
+[
+ {
+ "uniqueId": "xxxxx",
+ "startDate": "2023-06-01T09:00:00-07:00",
+ "endDate": "2023-06-30T09:00:00-07:00",
+ "description": "xxxxxxx",
+ "snoozeForMinutes": "10",
+ "samplingRate": "1.0",
+ "excludeDashTools": [],
+ "conditions": [
+ {
+ "field": "logFileStats.recordCount",
+ "operator": ">=",
+ "value": "1000xxxx"
+ }
+ ],
+ "buttons": [
+ {
+ "buttonText": "Take Survey",
+ "action": "accept",
+ "url": "https://google.qualtrics.com/jfe/form/SV_5gsB2EuG324y2",
+ "promptRemainsVisible": false
+ }
+ ]
+ }
+]
+''';
+
+ // Using a dash tool in the excludeDashTools array that is not a valid
+ // DashTool label
+ final invalidDashToolContents = '''
+[
+ {
+ "uniqueId": "xxxxx",
+ "startDate": "2023-06-01T09:00:00-07:00",
+ "endDate": "2023-06-30T09:00:00-07:00",
+ "description": "xxxxxxx",
+ "snoozeForMinutes": "10",
+ "samplingRate": "1.0",
+ "excludeDashTools": [
+ "not-a-valid-dash-tool"
+ ],
+ "conditions": [
+ {
+ "field": "logFileStats.recordCount",
+ "operator": ">=",
+ "value": 1000
+ },
+ {
+ "field": "logFileStats.toolCount.flutter-tool",
+ "operator": "<",
+ "value": 3
+ }
+ ],
+ "buttons": [
+ {
+ "buttonText": "Take Survey",
+ "action": "accept",
+ "url": "https://google.qualtrics.com/jfe/form/SV_5gsB2EuG324y2",
+ "promptRemainsVisible": false
+ }
+ ]
+ }
+]
+''';
+
+ test('valid json', () {
+ withClock(Clock.fixed(DateTime(2023, 6, 15)), () {
+ final parsedSurveys = SurveyHandler.parseSurveysFromJson(
+ jsonDecode(validContents) as List);
+
+ expect(parsedSurveys.length, 1);
+ expect(parsedSurveys.first.conditionList.length, 2);
+
+ final firstCondition = parsedSurveys.first.conditionList.first;
+ final secondCondition = parsedSurveys.first.conditionList[1];
+
+ expect(firstCondition.field, 'logFileStats.recordCount');
+ expect(firstCondition.operatorString, '>=');
+ expect(firstCondition.value, 1000);
+
+ expect(secondCondition.field, 'logFileStats.toolCount.flutter-tool');
+ expect(secondCondition.operatorString, '<');
+ expect(secondCondition.value, 3);
+
+ expect(parsedSurveys.first.buttonList.length, 1);
+ expect(
+ parsedSurveys.first.buttonList.first.promptRemainsVisible, false);
+ });
+ });
+
+ test('invalid condition json', () {
+ withClock(Clock.fixed(DateTime(2023, 6, 15)), () {
+ final parsedSurveys = SurveyHandler.parseSurveysFromJson(
+ jsonDecode(invalidConditionValueContents) as List);
+
+ expect(parsedSurveys.length, 0,
+ reason: 'The condition value is not a '
+ 'proper integer so it should error returning no surveys');
+ });
+ });
+
+ test('invalid dash tool json', () {
+ withClock(Clock.fixed(DateTime(2023, 6, 15)), () {
+ final parsedSurveys = SurveyHandler.parseSurveysFromJson(
+ jsonDecode(invalidDashToolContents) as List);
+
+ expect(parsedSurveys.length, 0,
+ reason: 'The dash tool in the exclude array is not valid '
+ 'so it should error returning no surveys');
+ });
+ });
+ });
+
+ group('Testing with FakeSurveyHandler', () {
+ late Analytics analytics;
+ late Directory homeDirectory;
+ late MemoryFileSystem fs;
+ late File clientIdFile;
+ late File dismissedSurveyFile;
+
+ setUp(() {
+ fs = MemoryFileSystem.test(style: FileSystemStyle.posix);
+ homeDirectory = fs.directory('home');
+
+ // Write the client ID file out so that we don't get
+ // a randomly assigned id for this test generated within
+ // the analytics constructor
+ clientIdFile = homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kClientIdFileName);
+ clientIdFile.createSync(recursive: true);
+ clientIdFile.writeAsStringSync('string1');
+
+ // Assign the json file that will hold the persisted surveys
+ dismissedSurveyFile = homeDirectory
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName);
+
+ // Setup two tools to be onboarded with this package so
+ // that we can simulate two different tools interacting with
+ // surveys
+ //
+ // This is especially useful when testing the "excludeDashTools" array
+ // to prevent certain tools from getting a survey from this package
+ final initialAnalyticsFlutter = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ );
+ final initialAnalyticsDart = Analytics.fake(
+ tool: DashTool.dartTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ );
+ initialAnalyticsFlutter.clientShowedMessage();
+ initialAnalyticsDart.clientShowedMessage();
+ });
+
+ test('returns valid survey', () async {
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[
+ Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[
+ Condition('logFileStats.recordCount', '>=', 50),
+ Condition('logFileStats.toolCount.flutter-tool', '>', 0),
+ ],
+ buttonList: [
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'accept',
+ url: 'http://example.com',
+ promptRemainsVisible: false,
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(fetchedSurveys.length, 1);
+
+ final survey = fetchedSurveys.first;
+ expect(survey.conditionList.length, 2);
+ expect(survey.buttonList.length, 1);
+ });
+ });
+
+ test('does not return expired survey', () async {
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[
+ Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2022, 1, 1),
+ endDate: DateTime(2022, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[
+ Condition('logFileStats.recordCount', '>=', 50),
+ Condition('logFileStats.toolCount.flutter-tool', '>', 0),
+ ],
+ buttonList: [],
+ ),
+ ],
+ ),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(fetchedSurveys.length, 0);
+ });
+ });
+
+ test('does not return survey if opted out of telemetry', () async {
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[
+ Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[
+ Condition('logFileStats.recordCount', '>=', 50),
+ Condition('logFileStats.toolCount.flutter-tool', '>', 0),
+ ],
+ buttonList: [],
+ ),
+ ],
+ ),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ await analytics.setTelemetry(false);
+ expect(analytics.okToSend, false);
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(fetchedSurveys.length, 0);
+ });
+ });
+
+ test('returns valid survey from json', () async {
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromString(
+ dismissedSurveyFile: dismissedSurveyFile, content: '''
+[
+ {
+ "uniqueId": "uniqueId123",
+ "startDate": "2023-01-01T09:00:00-07:00",
+ "endDate": "2023-12-31T09:00:00-07:00",
+ "description": "description123",
+ "snoozeForMinutes": "10",
+ "samplingRate": "1.0",
+ "excludeDashTools": [],
+ "conditions": [
+ {
+ "field": "logFileStats.recordCount",
+ "operator": ">=",
+ "value": 50
+ }
+ ],
+ "buttons": [
+ {
+ "buttonText": "Take Survey",
+ "action": "accept",
+ "url": "https://google.qualtrics.com/jfe/form/SV_5gsB2EuG324y2",
+ "promptRemainsVisible": false
+ },
+ {
+ "buttonText": "Dismiss",
+ "action": "dismiss",
+ "url": null,
+ "promptRemainsVisible": false
+ },
+ {
+ "buttonText": "More Info",
+ "action": "snooze",
+ "url": "https://docs.flutter.dev/reference/crash-reporting",
+ "promptRemainsVisible": true
+ }
+ ]
+ }
+]
+'''),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(fetchedSurveys.length, 1);
+
+ final survey = fetchedSurveys.first;
+ expect(survey.uniqueId, 'uniqueId123');
+ expect(survey.startDate.year, 2023);
+ expect(survey.startDate.month, 1);
+ expect(survey.startDate.day, 1);
+ expect(survey.endDate.year, 2023);
+ expect(survey.endDate.month, 12);
+ expect(survey.endDate.day, 31);
+ expect(survey.description, 'description123');
+ expect(survey.snoozeForMinutes, 10);
+ expect(survey.samplingRate, 1.0);
+ expect(survey.conditionList.length, 1);
+
+ final condition = survey.conditionList.first;
+ expect(condition.field, 'logFileStats.recordCount');
+ expect(condition.operatorString, '>=');
+ expect(condition.value, 50);
+
+ final buttonList = survey.buttonList;
+ expect(buttonList.length, 3);
+ expect(buttonList.first.buttonText, 'Take Survey');
+ expect(buttonList.first.action, 'accept');
+ expect(buttonList.first.url,
+ 'https://google.qualtrics.com/jfe/form/SV_5gsB2EuG324y2');
+ expect(buttonList.first.promptRemainsVisible, false);
+
+ expect(buttonList.elementAt(1).buttonText, 'Dismiss');
+ expect(buttonList.elementAt(1).action, 'dismiss');
+ expect(buttonList.elementAt(1).url, isNull);
+ expect(buttonList.elementAt(1).promptRemainsVisible, false);
+
+ expect(buttonList.last.buttonText, 'More Info');
+ expect(buttonList.last.action, 'snooze');
+ expect(buttonList.last.url,
+ 'https://docs.flutter.dev/reference/crash-reporting');
+ expect(buttonList.last.promptRemainsVisible, true);
+ });
+ });
+
+ test('no survey returned from malformed json', () async {
+ // The date is not valid for the start date
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromString(
+ dismissedSurveyFile: dismissedSurveyFile, content: '''
+[
+ {
+ "uniqueId": "uniqueId123",
+ "startDate": "NOT A REAL DATE",
+ "endDate": "2023-07-30T09:00:00-07:00",
+ "description": "Help improve Flutter's release builds with this 3-question survey!",
+ "snoozeForMinutes": "7200",
+ "samplingRate": "0.1",
+ "excludeDashTools": [],
+ "conditions": [
+ {
+ "field": "logFileStats.recordCount",
+ "operator": ">=",
+ "value": 50
+ }
+ ],
+ "buttons": [
+ {
+ "buttonText": "Take Survey",
+ "action": "accept",
+ "url": "https://google.qualtrics.com/jfe/form/SV_5gsB2EuG5Et5Yy2",
+ "promptRemainsVisible": false
+ },
+ {
+ "buttonText": "Dismiss",
+ "action": "dismiss",
+ "url": null,
+ "promptRemainsVisible": false
+ },
+ {
+ "buttonText": "More Info",
+ "action": "snooze",
+ "url": "https://docs.flutter.dev/reference/crash-reporting",
+ "promptRemainsVisible": false
+ }
+ ]
+ }
+]
+'''),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(fetchedSurveys.length, 0);
+ });
+ });
+
+ test('returns two valid survey from json', () async {
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromString(
+ dismissedSurveyFile: dismissedSurveyFile, content: '''
+[
+ {
+ "uniqueId": "12345",
+ "startDate": "2023-01-01T09:00:00-07:00",
+ "endDate": "2023-12-31T09:00:00-07:00",
+ "description": "xxxxxxx",
+ "snoozeForMinutes": "10",
+ "samplingRate": "1.0",
+ "excludeDashTools": [],
+ "conditions": [
+ {
+ "field": "logFileStats.recordCount",
+ "operator": ">=",
+ "value": 50
+ }
+ ],
+ "buttons": []
+ },
+ {
+ "uniqueId": "67890",
+ "startDate": "2023-01-01T09:00:00-07:00",
+ "endDate": "2023-12-31T09:00:00-07:00",
+ "description": "xxxxxxx",
+ "snoozeForMinutes": "10",
+ "samplingRate": "1.0",
+ "excludeDashTools": [],
+ "conditions": [
+ {
+ "field": "logFileStats.recordCount",
+ "operator": ">=",
+ "value": 50
+ }
+ ],
+ "buttons": [
+ {
+ "buttonText": "More Info",
+ "action": "snooze",
+ "url": "https://docs.flutter.dev/reference/crash-reporting",
+ "promptRemainsVisible": true
+ }
+ ]
+ }
+]
+'''),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(fetchedSurveys.length, 2);
+
+ final firstSurvey = fetchedSurveys.first;
+ final secondSurvey = fetchedSurveys.last;
+
+ expect(firstSurvey.uniqueId, '12345');
+ expect(secondSurvey.uniqueId, '67890');
+
+ final secondSurveyButtons = secondSurvey.buttonList;
+ expect(secondSurveyButtons.length, 1);
+ expect(secondSurveyButtons.first.buttonText, 'More Info');
+ expect(secondSurveyButtons.first.action, 'snooze');
+ expect(secondSurveyButtons.first.url,
+ 'https://docs.flutter.dev/reference/crash-reporting');
+ expect(secondSurveyButtons.first.promptRemainsVisible, true);
+ });
+ });
+
+ test('valid survey not returned if opted out', () async {
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[
+ Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[
+ Condition('logFileStats.recordCount', '>=', 50),
+ Condition('logFileStats.toolCount.flutter-tool', '>', 0),
+ ],
+ buttonList: [],
+ ),
+ ],
+ ),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ // Setting to false will prevent anything from getting returned
+ await analytics.setTelemetry(false);
+ var fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 0);
+
+ // Setting telemetry back to true should enable the surveys to get
+ // returned again; we will also need to send the fake events again
+ // because on opt out, the log file will get cleared and one of
+ // the conditions for the fake survey loaded is that we need
+ // at least 50 records for one of the conditions
+ await analytics.setTelemetry(true);
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+ fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 1);
+ });
+ });
+
+ test('Sampling rate correctly returns a valid survey', () async {
+ // This test will use a predefined client ID string of `string1`
+ // which has been set in the setup along with a predefined
+ // string for the survey ID of `string2` to get a sample rate value
+ //
+ // The combination of `string1` and `string2` will return 0.40
+ // from the sampleRate utility function so we have set the threshold
+ // to be 0.6 which should return surveys
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ final survey = Survey(
+ uniqueId: 'string2',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 0.6,
+ excludeDashToolList: [],
+ conditionList: <Condition>[
+ Condition('logFileStats.recordCount', '>=', 50),
+ Condition('logFileStats.toolCount.flutter-tool', '>', 0),
+ ],
+ buttonList: [],
+ );
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[survey],
+ ),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(survey.samplingRate, 0.6);
+ expect(fetchedSurveys.length, 1);
+ });
+ });
+
+ test('Sampling rate filters out a survey', () async {
+ // We will reduce the survey's sampling rate to be 0.3 which is
+ // less than value returned from the predefined client ID and
+ // survey sample
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ final survey = Survey(
+ uniqueId: 'string2',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 0.15,
+ excludeDashToolList: [],
+ conditionList: <Condition>[
+ Condition('logFileStats.recordCount', '>=', 50),
+ Condition('logFileStats.toolCount.flutter-tool', '>', 0),
+ ],
+ buttonList: [],
+ );
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[survey],
+ ),
+ );
+
+ // Simulate 60 events to send so that the first condition is satisified
+ for (var i = 0; i < 60; i++) {
+ analytics.send(testEvent);
+ }
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(survey.samplingRate, 0.15);
+ expect(fetchedSurveys.length, 0);
+ });
+ });
+
+ test('Snoozing survey is successful with snooze timeout from survey',
+ () async {
+ expect(dismissedSurveyFile.readAsStringSync(), '{}',
+ reason: 'Should be an empty object');
+
+ // Initialize the survey class that we will use for this test
+ final minutesToSnooze = 30;
+ final surveyToLoad = Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes:
+ minutesToSnooze, // Initialized survey with `minutesToSnooze`
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[],
+ buttonList: [],
+ );
+
+ await withClock(Clock.fixed(DateTime(2023, 3, 3, 12, 0)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 1);
+
+ final survey = fetchedSurveys.first;
+ expect(survey.snoozeForMinutes, minutesToSnooze);
+
+ // We will snooze the survey now and it should not show up
+ // if we fetch surveys again before the minutes to snooze time
+ // has finished
+ analytics.surveyShown(survey);
+ });
+
+ // This analytics instance will be simulated to be shortly after the first
+ // snooze, but before the snooze period has elapsed
+ await withClock(Clock.fixed(DateTime(2023, 3, 3, 12, 15)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 0,
+ reason: 'The snooze period has not elapsed yet');
+ });
+
+ // This analytics instance will be simulated to be after the snooze period
+ await withClock(Clock.fixed(DateTime(2023, 3, 3, 12, 35)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 1,
+ reason: 'The snooze period has elapsed');
+ });
+ });
+
+ test('Dimissing permanently is successful', () async {
+ final minutesToSnooze = 10;
+ final surveyToLoad = Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: minutesToSnooze,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[],
+ buttonList: [
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'accept',
+ promptRemainsVisible: false,
+ ),
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'dismiss',
+ promptRemainsVisible: false,
+ ),
+ ],
+ );
+
+ await withClock(Clock.fixed(DateTime(2023, 3, 3, 12, 0)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 1);
+
+ // Dismissing permanently will ensure that this survey is not
+ // shown again
+ final survey = fetchedSurveys.first;
+ analytics.surveyInteracted(
+ survey: survey,
+ surveyButton: survey.buttonList.first,
+ );
+ });
+
+ // Moving out a week
+ await withClock(Clock.fixed(DateTime(2023, 3, 10, 12, 0)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 0);
+ });
+ });
+
+ test('malformed persisted json file for surveys', () async {
+ // When the survey handler encounters an error when parsing the
+ // persisted json file, it will reset it using the static method
+ // under the [Initializer] class and reset it to be an empty json object
+ final minutesToSnooze = 10;
+ final surveyToLoad = Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: minutesToSnooze,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[],
+ buttonList: [
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'accept',
+ promptRemainsVisible: false,
+ ),
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'dismiss',
+ promptRemainsVisible: false,
+ ),
+ ],
+ );
+
+ await withClock(Clock.fixed(DateTime(2023, 3, 3, 12, 0)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 1);
+
+ // Dismissing permanently will ensure that this survey is not
+ // shown again
+ final survey = fetchedSurveys.first;
+ expect(survey.buttonList.length, 2);
+ analytics.surveyInteracted(
+ survey: survey,
+ surveyButton: survey.buttonList.first,
+ );
+ });
+
+ // Purposefully write invalid json into the persisted file
+ dismissedSurveyFile.writeAsStringSync('{');
+
+ // Moving out a week
+ await withClock(Clock.fixed(DateTime(2023, 3, 10, 12, 0)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 1);
+ });
+ });
+
+ test('persisted json file goes missing handled', () async {
+ // If the persisted json file with the dismissed surveys is missing
+ // there should be error handling to recreate the file again with
+ // an empty json object
+ final minutesToSnooze = 10;
+ final surveyToLoad = Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: minutesToSnooze,
+ samplingRate: 1.0,
+ excludeDashToolList: [],
+ conditionList: <Condition>[],
+ buttonList: [
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'accept',
+ promptRemainsVisible: false,
+ ),
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'dismiss',
+ promptRemainsVisible: false,
+ ),
+ ],
+ );
+
+ await withClock(Clock.fixed(DateTime(2023, 3, 3, 12, 0)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 1);
+
+ // Dismissing permanently will ensure that this survey is not
+ // shown again
+ final survey = fetchedSurveys.first;
+ expect(survey.buttonList.length, 2);
+ analytics.surveyInteracted(
+ survey: survey,
+ surveyButton: survey.buttonList.first,
+ );
+ });
+
+ // Moving out a week
+ await withClock(Clock.fixed(DateTime(2023, 3, 10, 12, 0)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[surveyToLoad],
+ ),
+ );
+
+ // Purposefully delete the file
+ dismissedSurveyFile.deleteSync();
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+ expect(fetchedSurveys.length, 1);
+ });
+ });
+
+ test('Filtering out with excludeDashTool array', () async {
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[
+ Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ // This should be the same as the tool in the
+ // Analytics constructor above
+ excludeDashToolList: [
+ DashTool.flutterTool,
+ ],
+ conditionList: [],
+ buttonList: [
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'accept',
+ url: 'http://example.com',
+ promptRemainsVisible: false,
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(fetchedSurveys.length, 0);
+ });
+ });
+
+ test(
+ 'Filter from excludeDashTool array does not '
+ 'apply for different tool', () async {
+ await withClock(Clock.fixed(DateTime(2023, 3, 3)), () async {
+ analytics = Analytics.fake(
+ tool: DashTool.flutterTool,
+ homeDirectory: homeDirectory,
+ dartVersion: 'dartVersion',
+ fs: fs,
+ platform: DevicePlatform.macos,
+ surveyHandler: FakeSurveyHandler.fromList(
+ dismissedSurveyFile: dismissedSurveyFile,
+ initializedSurveys: <Survey>[
+ Survey(
+ uniqueId: 'uniqueId',
+ startDate: DateTime(2023, 1, 1),
+ endDate: DateTime(2023, 12, 31),
+ description: 'description',
+ snoozeForMinutes: 10,
+ samplingRate: 1.0,
+ // This should be different from the tool in the
+ // Analytics constructor above
+ excludeDashToolList: [
+ DashTool.devtools,
+ ],
+ conditionList: [],
+ buttonList: [
+ SurveyButton(
+ buttonText: 'buttonText',
+ action: 'accept',
+ url: 'http://example.com',
+ promptRemainsVisible: false,
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+
+ final fetchedSurveys = await analytics.fetchAvailableSurveys();
+
+ expect(fetchedSurveys.length, 1);
+
+ final survey = fetchedSurveys.first;
+ expect(survey.excludeDashToolList.length, 1);
+ expect(survey.excludeDashToolList.contains(DashTool.devtools), true);
+ });
+ });
+ });
+}
diff --git a/pkgs/unified_analytics/test/unified_analytics_test.dart b/pkgs/unified_analytics/test/unified_analytics_test.dart
new file mode 100644
index 0000000..2e78df4
--- /dev/null
+++ b/pkgs/unified_analytics/test/unified_analytics_test.dart
@@ -0,0 +1,1275 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: lines_longer_than_80_chars, avoid_dynamic_calls
+
+import 'dart:convert';
+import 'dart:io' as io;
+import 'dart:math';
+
+import 'package:clock/clock.dart';
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/test.dart';
+import 'package:unified_analytics/src/constants.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/src/utils.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+import 'package:yaml/yaml.dart';
+
+void main() {
+ late MemoryFileSystem fs;
+ late Directory home;
+ late Directory dartToolDirectory;
+ late Analytics initializationAnalytics;
+ late FakeAnalytics analytics;
+ late File clientIdFile;
+ late File sessionFile;
+ late File configFile;
+ late File logFile;
+ late File dismissedSurveyFile;
+
+ const homeDirName = 'home';
+ const initialTool = DashTool.flutterTool;
+ const secondTool = DashTool.dartTool;
+ const toolsMessageVersion = 1;
+ const toolsMessage = 'toolsMessage';
+ const flutterChannel = 'flutterChannel';
+ const flutterVersion = 'flutterVersion';
+ const dartVersion = 'dartVersion';
+ const platform = DevicePlatform.macos;
+ const clientIde = 'VSCode';
+
+ final testEvent = Event.hotReloadTime(timeMs: 50);
+
+ setUp(() {
+ // Setup the filesystem with the home directory
+ final fsStyle =
+ io.Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix;
+ fs = MemoryFileSystem.test(style: fsStyle);
+ home = fs.directory(homeDirName);
+ dartToolDirectory = home.childDirectory(kDartToolDirectoryName);
+
+ // This is the first analytics instance that will be used to demonstrate
+ // that events will not be sent with the first run of analytics
+ initializationAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+ expect(initializationAnalytics.shouldShowMessage, true);
+ initializationAnalytics.clientShowedMessage();
+ expect(initializationAnalytics.shouldShowMessage, false);
+
+ // The main analytics instance, other instances can be spawned within tests
+ // to test how to instances running together work
+ //
+ // This instance should have the same parameters as the one above for
+ // [initializationAnalytics]
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ clientIde: clientIde,
+ );
+ analytics.clientShowedMessage();
+
+ // The 5 files that should have been generated
+ clientIdFile = home
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kClientIdFileName);
+ sessionFile =
+ home.childDirectory(kDartToolDirectoryName).childFile(kSessionFileName);
+ configFile =
+ home.childDirectory(kDartToolDirectoryName).childFile(kConfigFileName);
+ logFile =
+ home.childDirectory(kDartToolDirectoryName).childFile(kLogFileName);
+ dismissedSurveyFile = home
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName);
+ });
+
+ test('Initializer properly sets up on first run', () {
+ expect(dartToolDirectory.existsSync(), true,
+ reason: 'The directory should have been created');
+ expect(clientIdFile.existsSync(), true,
+ reason: 'The $kClientIdFileName file was not found');
+ expect(sessionFile.existsSync(), true,
+ reason: 'The $kSessionFileName file was not found');
+ expect(configFile.existsSync(), true,
+ reason: 'The $kConfigFileName was not found');
+ expect(logFile.existsSync(), true,
+ reason: 'The $kLogFileName file was not found');
+ expect(dismissedSurveyFile.existsSync(), true,
+ reason: 'The $dismissedSurveyFile file was not found');
+ expect(dartToolDirectory.listSync().length, equals(5),
+ reason:
+ 'There should only be 5 files in the $kDartToolDirectoryName directory');
+ expect(configFile.readAsLinesSync().length,
+ kConfigString.split('\n').length + 1,
+ reason: 'The number of lines should equal lines in constant value + 1 '
+ 'for the initialized tool');
+ });
+
+ test('Resetting session file when data is malformed', () {
+ // Purposefully write content to the session file that
+ // can't be decoded as an integer
+ sessionFile.writeAsStringSync('contents');
+
+ // Define the initial time to start
+ final start = DateTime(1995, 3, 3, 12, 0);
+
+ // Set the clock to the start value defined above
+ withClock(Clock.fixed(start), () {
+ final timestamp = clock.now().millisecondsSinceEpoch.toString();
+ expect(sessionFile.readAsStringSync(), 'contents');
+ analytics.userProperty.preparePayload();
+ expect(sessionFile.readAsStringSync(),
+ '{"session_id": $timestamp, "last_ping": $timestamp}');
+
+ analytics.sendPendingErrorEvents();
+
+ // Attempting to fetch the session id when malformed should also
+ // send an error event while parsing
+ final lastEvent = analytics.sentEvents.last;
+ expect(lastEvent, isNotNull);
+ expect(lastEvent.eventName, DashEvent.analyticsException);
+ expect(
+ lastEvent.eventData['workflow']!, 'UserProperty._refreshSessionData');
+ expect(lastEvent.eventData['error']!, 'FormatException');
+ });
+ });
+
+ test('Handles malformed session file on startup', () {
+ // Ensure that we are able to send an error message on startup if
+ // we encounter an error while parsing the contents of the session file
+ // for session data
+ sessionFile.writeAsStringSync('not a valid session id');
+
+ analytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ clientIde: clientIde,
+ );
+ analytics.clientShowedMessage();
+
+ // Invoking a send command should reset the session file to a good state
+ //
+ // Having it reformat the session file before any send event happens will just
+ // add additional work on startup
+ analytics.send(testEvent);
+
+ analytics.sendPendingErrorEvents();
+ final errorEvent = analytics.sentEvents
+ .where((element) => element.eventName == DashEvent.analyticsException)
+ .firstOrNull;
+ expect(errorEvent, isNotNull);
+ expect(
+ errorEvent!.eventData['workflow'], 'UserProperty._refreshSessionData');
+ expect(errorEvent.eventData['error'], 'FormatException');
+ expect(errorEvent.eventData['description'],
+ 'message: Unexpected character\nsource: not a valid session id');
+ });
+
+ test('Resetting session file when file is removed', () {
+ // Purposefully write delete the file
+ sessionFile.deleteSync();
+
+ // Define the initial time to start
+ final start = DateTime(1995, 3, 3, 12, 0);
+
+ // Set the clock to the start value defined above
+ withClock(Clock.fixed(start), () {
+ final timestamp = clock.now().millisecondsSinceEpoch.toString();
+ expect(sessionFile.existsSync(), false);
+ analytics.userProperty.preparePayload();
+ expect(sessionFile.readAsStringSync(),
+ '{"session_id": $timestamp, "last_ping": $timestamp}');
+
+ analytics.sendPendingErrorEvents();
+
+ // Attempting to fetch the session id when malformed should also
+ // send an error event while parsing
+ final lastEvent = analytics.sentEvents.last;
+ expect(lastEvent, isNotNull);
+ expect(lastEvent.eventName, DashEvent.analyticsException);
+ expect(
+ lastEvent.eventData['workflow']!, 'UserProperty._refreshSessionData');
+ expect(lastEvent.eventData['error']!, 'FileSystemException');
+ });
+ });
+
+ test('New tool is successfully added to config file', () {
+ // Create a new instance of the analytics class with the new tool
+ final secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: 'ey-test-channel',
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+
+ expect(secondAnalytics.parsedTools.length, equals(2),
+ reason: 'There should be only 2 tools that have '
+ 'been parsed into the config file');
+ expect(secondAnalytics.parsedTools.containsKey(initialTool.label), true,
+ reason: 'The first tool: ${initialTool.label} should be in the map');
+ expect(secondAnalytics.parsedTools.containsKey(secondTool.label), true,
+ reason: 'The second tool: $secondAnalytics should be in the map');
+ expect(configFile.readAsStringSync().startsWith(kConfigString), true,
+ reason:
+ 'The config file should have the same message from the constants file');
+ });
+
+ test('First time analytics run will not send events, second time will', () {
+ // Send an event with the first analytics class; this should result
+ // in no logs in the log file which keeps track of all the events
+ // that have been sent
+ initializationAnalytics.send(testEvent);
+ initializationAnalytics.send(testEvent);
+
+ // Use the second instance of analytics defined in setUp() to send the actual
+ // events to simulate the second time the tool ran
+ analytics.send(testEvent);
+
+ expect(logFile.readAsLinesSync().length, 1,
+ reason: 'The second analytics instance should have logged an event');
+ });
+
+ test('Toggling telemetry boolean through Analytics class api', () async {
+ final originalClientId = clientIdFile.readAsStringSync();
+
+ expect(analytics.telemetryEnabled, true,
+ reason: 'Telemetry should be enabled by default '
+ 'when initialized for the first time');
+ // Use the API to disable analytics
+ expect(logFile.readAsLinesSync().length, 0);
+ await analytics.setTelemetry(false);
+ expect(analytics.telemetryEnabled, false,
+ reason: 'Analytics telemetry should be disabled');
+ expect(logFile.readAsLinesSync().length, 0,
+ reason: 'Log file should have been cleared after opting out');
+ expect(clientIdFile.readAsStringSync().length, 0,
+ reason: 'CLIENT ID file gets cleared on opt out');
+ expect(sessionFile.readAsStringSync().length, 0,
+ reason: 'Session file gets cleared on opt out');
+
+ // Toggle it back to being enabled
+ await analytics.setTelemetry(true);
+ expect(analytics.telemetryEnabled, true,
+ reason: 'Analytics telemetry should be enabled');
+ expect(logFile.readAsLinesSync().length, 1,
+ reason: 'There should only one event since it was cleared on opt out');
+ expect(clientIdFile.readAsStringSync().length, greaterThan(0),
+ reason: 'CLIENT ID file gets regenerated on opt in');
+ expect(sessionFile.readAsStringSync().length, greaterThan(0),
+ reason: 'Session file gets regenerated on opt in');
+
+ // Extract the last log item to check for the keys
+ final lastLogItem =
+ jsonDecode(logFile.readAsLinesSync().last) as Map<String, Object?>;
+ expect((lastLogItem['events'] as List).last['name'],
+ 'analytics_collection_enabled',
+ reason: 'Check on event name');
+ expect((lastLogItem['events'] as List).last['params']['status'], true,
+ reason: 'Status should be false');
+ expect((lastLogItem['client_id'] as String).isNotEmpty, true);
+ expect(originalClientId != lastLogItem['client_id'], true,
+ reason: 'When opting in again, the client id should be regenerated');
+ });
+
+ test('Confirm client id is not empty string after opting in', () async {
+ await analytics.setTelemetry(false);
+ expect(logFile.readAsLinesSync().length, 0,
+ reason: 'Log file should have been cleared after opting out');
+ expect(clientIdFile.readAsStringSync().length, 0,
+ reason: 'CLIENT ID file gets cleared on opt out');
+
+ // Start up a second instance to simulate starting another
+ // command being run
+ final secondAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ // Setting telemetry back on will emit a new event
+ // where the client id string should not be empty
+ await secondAnalytics.setTelemetry(true);
+ expect(analytics.telemetryEnabled, true,
+ reason: 'Analytics telemetry should be enabled');
+ expect(logFile.readAsLinesSync().length, 1,
+ reason: 'There should only one event since it was cleared on opt out');
+ expect(clientIdFile.readAsStringSync().length, greaterThan(0),
+ reason: 'CLIENT ID file gets regenerated on opt in');
+
+ // Extract the last log item to check for the keys
+ final lastLogItem =
+ jsonDecode(logFile.readAsLinesSync().last) as Map<String, Object?>;
+ expect((lastLogItem['client_id'] as String).isNotEmpty, true,
+ reason: 'The client id should have been regenerated and '
+ 'emitted in the opt in event');
+ });
+
+ test(
+ 'Telemetry has been disabled by one '
+ 'tool and second tool correctly shows telemetry is disabled', () async {
+ expect(analytics.telemetryEnabled, true,
+ reason: 'Analytics telemetry should be enabled on initialization');
+ // Use the API to disable analytics
+ await analytics.setTelemetry(false);
+ expect(analytics.telemetryEnabled, false,
+ reason: 'Analytics telemetry should be disabled');
+
+ // Initialize a second analytics class, which simulates a second tool
+ // Create a new instance of the analytics class with the new tool
+ final secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: 'ey-test-channel',
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+
+ expect(secondAnalytics.telemetryEnabled, false,
+ reason: 'Analytics telemetry should be disabled by the first class '
+ 'and the second class should show telemetry is disabled');
+ });
+
+ test(
+ 'Two concurrent instances are running '
+ 'and reflect an accurate up to date telemetry status', () async {
+ // Initialize a second analytics class, which simulates a second tool
+ final secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: 'ey-test-channel',
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+
+ expect(analytics.telemetryEnabled, true,
+ reason: 'Telemetry should be enabled on initialization for '
+ 'first analytics instance');
+ expect(secondAnalytics.telemetryEnabled, true,
+ reason: 'Telemetry should be enabled on initialization for '
+ 'second analytics instance');
+
+ // Use the API to disable analytics on the first instance
+ await analytics.setTelemetry(false);
+ expect(analytics.telemetryEnabled, false,
+ reason: 'Analytics telemetry should be disabled on first instance');
+
+ expect(secondAnalytics.telemetryEnabled, false,
+ reason: 'Analytics telemetry should be disabled by the first class '
+ 'and the second class should show telemetry is disabled'
+ ' by checking the timestamp on the config file');
+ });
+
+ test('New line character is added if missing', () {
+ String currentConfigFileString;
+
+ expect(configFile.readAsStringSync().endsWith('\n'), true,
+ reason: 'When initialized, the tool should correctly '
+ 'add a trailing new line character');
+
+ // Remove the trailing new line character before initializing a second
+ // analytics class; the new class should correctly format the config file
+ currentConfigFileString = configFile.readAsStringSync();
+ currentConfigFileString = currentConfigFileString.substring(
+ 0, currentConfigFileString.length - 1);
+
+ // Write back out to the config file to be processed again
+ configFile.writeAsStringSync(currentConfigFileString);
+
+ expect(configFile.readAsStringSync().endsWith('\n'), false,
+ reason: 'The trailing new line should be missing');
+
+ // Initialize a second analytics class, which simulates a second tool
+ // which should correct the missing trailing new line character
+ final secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: 'ey-test-channel',
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+
+ expect(secondAnalytics.telemetryEnabled, true);
+
+ expect(configFile.readAsStringSync().endsWith('\n'), true,
+ reason: 'The second analytics class will correct '
+ 'the missing new line character');
+ });
+
+ test('Incrementing the version for a tool is successful', () {
+ expect(analytics.parsedTools[initialTool.label]?.versionNumber,
+ toolsMessageVersion,
+ reason: 'On initialization, the first version number should '
+ 'be what is set in the setup method');
+
+ // Initialize a second analytics class for the same tool as
+ // the first analytics instance except with a newer version for
+ // the tools message and version
+ final secondAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion + 1,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+ expect(secondAnalytics.shouldShowMessage, true);
+ expect(secondAnalytics.okToSend, false);
+ secondAnalytics.clientShowedMessage();
+ expect(secondAnalytics.shouldShowMessage, false);
+ expect(secondAnalytics.okToSend, false,
+ reason: 'New version for the message will be treated as a first run');
+
+ expect(secondAnalytics.parsedTools[initialTool.label]?.versionNumber,
+ toolsMessageVersion + 1,
+ reason:
+ 'The second analytics instance should have incremented the version');
+ });
+
+ test(
+ 'Config file resets when there is not exactly one match for the reporting flag',
+ () async {
+ // Write to the config file a string that is not formatted correctly
+ // (ie. there is more than one match for the reporting flag)
+ configFile.writeAsStringSync('''
+# INTRODUCTION
+#
+# This is the Flutter and Dart telemetry reporting
+# configuration file.
+#
+# Lines starting with a #" are documentation that
+# the tools maintain automatically.
+#
+# All other lines are configuration lines. They have
+# the form "name=value". If multiple lines contain
+# the same configuration name with different values,
+# the parser will default to a conservative value.
+
+# DISABLING TELEMETRY REPORTING
+#
+# To disable telemetry reporting, set "reporting" to
+# the value "0" and to enable, set to "1":
+reporting=1
+reporting=1
+
+# NOTIFICATIONS
+#
+# Each tool records when it last informed the user about
+# analytics reporting and the privacy policy.
+#
+# The following tools have so far read this file:
+#
+# dart-tools (Dart CLI developer tool)
+# devtools (DevTools debugging and performance tools)
+# flutter-tools (Flutter CLI developer tool)
+#
+# For each one, the file may contain a configuration line
+# where the name is the code in the list above, e.g. "dart-tool",
+# and the value is a date in the form YYYY-MM-DD, a comma, and
+# a number representing the version of the message that was
+# displayed.''');
+
+ // Disable telemetry which should result in a reset of the config file
+ await analytics.setTelemetry(false);
+
+ expect(configFile.readAsStringSync().startsWith(kConfigString), true,
+ reason: 'The tool should have reset the config file '
+ 'because it was not formatted correctly');
+ });
+
+ test('Config file resets when there is not exactly one match for the tool',
+ () {
+ // Write to the config file a string that is not formatted correctly
+ // (ie. there is more than one match for the reporting flag)
+ configFile.writeAsStringSync('''
+# INTRODUCTION
+#
+# This is the Flutter and Dart telemetry reporting
+# configuration file.
+#
+# Lines starting with a #" are documentation that
+# the tools maintain automatically.
+#
+# All other lines are configuration lines. They have
+# the form "name=value". If multiple lines contain
+# the same configuration name with different values,
+# the parser will default to a conservative value.
+
+# DISABLING TELEMETRY REPORTING
+#
+# To disable telemetry reporting, set "reporting" to
+# the value "0" and to enable, set to "1":
+reporting=1
+
+# NOTIFICATIONS
+#
+# Each tool records when it last informed the user about
+# analytics reporting and the privacy policy.
+#
+# The following tools have so far read this file:
+#
+# dart-tools (Dart CLI developer tool)
+# devtools (DevTools debugging and performance tools)
+# flutter-tools (Flutter CLI developer tool)
+#
+# For each one, the file may contain a configuration line
+# where the name is the code in the list above, e.g. "dart-tool",
+# and the value is a date in the form YYYY-MM-DD, a comma, and
+# a number representing the version of the message that was
+# displayed.
+${initialTool.label}=$dateStamp,$toolsMessageVersion
+${initialTool.label}=$dateStamp,$toolsMessageVersion
+''');
+
+ // Initialize a second analytics class for the same tool as
+ // the first analytics instance except with a newer version for
+ // the tools message and version
+ //
+ // This second instance should reset the config file when it goes
+ // to increment the version in the file
+ final secondAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion + 1,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+
+ expect(
+ configFile.readAsStringSync(),
+ kConfigString,
+ reason: 'The config file should have been reset completely '
+ 'due to a malformed file that contained two lines for the same tool',
+ );
+
+ // Creating a third instance after the second instance
+ // has reset the config file should include the newly added
+ // tool again with its incremented version number
+ final thirdAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion + 1,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+ thirdAnalytics.clientShowedMessage();
+
+ expect(
+ configFile.readAsStringSync().endsWith(
+ '# displayed.\n${initialTool.label}=$dateStamp,${toolsMessageVersion + 1}\n'),
+ true,
+ reason: 'The config file ends with the correctly formatted ending '
+ 'after removing the duplicate lines for a given tool',
+ );
+ expect(
+ thirdAnalytics.parsedTools[initialTool.label]?.versionNumber,
+ toolsMessageVersion + 1,
+ reason: 'The new version should have been incremented',
+ );
+ });
+
+ test('Check that UserProperty class has all the necessary keys', () {
+ const userPropertyKeys = <String>[
+ 'session_id',
+ 'flutter_channel',
+ 'host',
+ 'flutter_version',
+ 'dart_version',
+ 'analytics_pkg_version',
+ 'tool',
+ 'local_time',
+ 'host_os_version',
+ 'locale',
+ 'client_ide',
+ 'enabled_features',
+ ];
+ expect(analytics.userPropertyMap.keys.length, userPropertyKeys.length,
+ reason: 'There should only be ${userPropertyKeys.length} keys');
+ for (final key in userPropertyKeys) {
+ expect(analytics.userPropertyMap.keys.contains(key), true,
+ reason: 'The $key variable is required');
+ }
+ });
+
+ test('The minimum session duration should be at least 30 minutes', () {
+ expect(kSessionDurationMinutes < 30, false,
+ reason: 'Session is less than 30 minutes');
+ });
+
+ test(
+ 'The session id stays the same when duration'
+ ' is less than the constraint', () {
+ // For this test, we will need control clock time so we will delete
+ // the [dartToolDirectory] and all of its contents and reconstruct a
+ // new [Analytics] instance at a specific time
+ dartToolDirectory.deleteSync(recursive: true);
+ expect(dartToolDirectory.existsSync(), false,
+ reason: 'The directory should have been cleared');
+
+ // Define the initial time to start
+ final start = DateTime(1995, 3, 3, 12, 0);
+
+ // Set the clock to the start value defined above
+ withClock(Clock.fixed(start), () {
+ // This class will be constructed at a fixed time
+ final secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+
+ expect(secondAnalytics.userPropertyMap['session_id']?['value'],
+ start.millisecondsSinceEpoch);
+ expect(sessionFile.lastModifiedSync().millisecondsSinceEpoch,
+ start.millisecondsSinceEpoch);
+ });
+
+ // Add time to the start time that is less than the duration
+ final end = start.add(const Duration(minutes: kSessionDurationMinutes - 1));
+
+ // Use a new clock to ensure that the session id didn't change
+ withClock(Clock.fixed(end), () {
+ // A new instance will need to be created since the second
+ // instance in the previous block is scoped - this new instance
+ // should not reset the files generated by the second instance
+ final thirdAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ thirdAnalytics.clientShowedMessage();
+
+ // Calling the send event method will result in the session file
+ // getting updated but because we use the `Analytics.fake()` constructor
+ // no events will be sent
+ thirdAnalytics.send(testEvent);
+
+ expect(thirdAnalytics.userPropertyMap['session_id']?['value'],
+ start.millisecondsSinceEpoch,
+ reason: 'The session id should not have changed since it was made '
+ 'within the duration');
+ expect(sessionFile.lastModifiedSync().millisecondsSinceEpoch,
+ end.millisecondsSinceEpoch,
+ reason: 'The last modified value should have been updated');
+ });
+ });
+
+ test('The session id is refreshed once event is sent after duration', () {
+ // For this test, we will need control clock time so we will delete
+ // the [dartToolDirectory] and all of its contents and reconstruct a
+ // new [Analytics] instance at a specific time
+ dartToolDirectory.deleteSync(recursive: true);
+ expect(dartToolDirectory.existsSync(), false,
+ reason: 'The directory should have been cleared');
+
+ // Define the initial time to start
+ final start = DateTime(1995, 3, 3, 12, 0);
+
+ // Set the clock to the start value defined above
+ withClock(Clock.fixed(start), () {
+ // This class will be constructed at a fixed time
+ final secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+
+ expect(secondAnalytics.userPropertyMap['session_id']?['value'],
+ start.millisecondsSinceEpoch);
+ expect(sessionFile.lastModifiedSync().millisecondsSinceEpoch,
+ start.millisecondsSinceEpoch);
+
+ secondAnalytics.send(testEvent);
+ expect(sessionFile.readAsStringSync(),
+ '{"session_id": ${start.millisecondsSinceEpoch}, "last_ping": ${start.millisecondsSinceEpoch}}');
+ });
+
+ // Add time to the start time that is less than the duration
+ final end = start.add(const Duration(minutes: kSessionDurationMinutes + 1));
+
+ // Use a new clock to ensure that the session id didn't change
+ withClock(Clock.fixed(end), () {
+ // A new instance will need to be created since the second
+ // instance in the previous block is scoped - this new instance
+ // should not reset the files generated by the second instance
+ final thirdAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ thirdAnalytics.clientShowedMessage();
+
+ // Calling the send event method will result in the session file
+ // getting updated but because we use the `Analytics.fake()` constructor
+ // no events will be sent
+ thirdAnalytics.send(testEvent);
+
+ expect(thirdAnalytics.userPropertyMap['session_id']?['value'],
+ end.millisecondsSinceEpoch,
+ reason: 'The session id should have changed since it was made '
+ 'outside the duration');
+ expect(sessionFile.lastModifiedSync().millisecondsSinceEpoch,
+ end.millisecondsSinceEpoch,
+ reason: 'The last modified value should have been updated');
+ expect(sessionFile.readAsStringSync(),
+ '{"session_id": ${end.millisecondsSinceEpoch}, "last_ping": ${end.millisecondsSinceEpoch}}');
+ });
+ });
+
+ test('Validate the available enum types for DevicePlatform', () {
+ expect(DevicePlatform.values.length, 3,
+ reason: 'There should only be 3 supported device platforms');
+ expect(DevicePlatform.values.contains(DevicePlatform.windows), true);
+ expect(DevicePlatform.values.contains(DevicePlatform.macos), true);
+ expect(DevicePlatform.values.contains(DevicePlatform.linux), true);
+ });
+
+ test('Validate the request body', () {
+ // Sample map for event data
+ final eventData = <String, dynamic>{
+ 'time': 5,
+ 'command': 'run',
+ };
+
+ final Map<String, dynamic> body = generateRequestBody(
+ clientId: Uuid().generateV4(),
+ eventName: DashEvent.hotReloadTime,
+ eventData: eventData,
+ userProperty: analytics.userProperty,
+ );
+
+ // Checks for the top level keys
+ expect(body.containsKey('client_id'), true,
+ reason: '"client_id" is required at the top level');
+ expect(body.containsKey('events'), true,
+ reason: '"events" is required at the top level');
+ expect(body.containsKey('user_properties'), true,
+ reason: '"user_properties" is required at the top level');
+
+ // Regex for the client id
+ final clientIdPattern = RegExp(
+ r'^[0-9a-z]{8}\-[0-9a-z]{4}\-[0-9a-z]{4}\-[0-9a-z]{4}\-[0-9a-z]{12}$');
+
+ // Checks for the top level values
+ expect(body['client_id'].runtimeType, String,
+ reason: 'The client id must be a string');
+ expect(clientIdPattern.hasMatch(body['client_id'] as String), true,
+ reason: 'The client id is not properly formatted, ie '
+ '46cc0ba6-f604-4fd9-aa2f-8a20beb24cd4');
+ expect(
+ (body['events'][0] as Map<String, dynamic>).containsKey('name'), true,
+ reason: 'Each event in the events array needs a name');
+ expect(
+ (body['events'][0] as Map<String, dynamic>).containsKey('params'), true,
+ reason: 'Each event in the events array needs a params key');
+ });
+
+ test('Check that log file is correctly persisting events sent', () {
+ final int numberOfEvents = max((kLogFileLength * 0.1).floor(), 5);
+
+ for (var i = 0; i < numberOfEvents; i++) {
+ analytics.send(testEvent);
+ }
+
+ expect(logFile.readAsLinesSync().length, numberOfEvents,
+ reason: 'The number of events should be $numberOfEvents');
+
+ // Add the max number of events to confirm it does not exceed the max
+ for (var i = 0; i < kLogFileLength; i++) {
+ analytics.send(testEvent);
+ }
+
+ expect(logFile.readAsLinesSync().length, kLogFileLength,
+ reason: 'The number of events should be capped at $kLogFileLength');
+ });
+
+ test('Check the query on the log file works as expected', () {
+ // Define a new clock so that we can check the output of the
+ // log file stats method explicitly
+ final start = DateTime(1995, 3, 3, 12, 0);
+ final firstClock = Clock.fixed(start);
+
+ // Run with the simulated clock for the initial events
+ withClock(firstClock, () {
+ expect(analytics.logFileStats(), isNull,
+ reason: 'The result for the log file stats should be null when '
+ 'there are no logs');
+ analytics.send(testEvent);
+
+ final firstQuery = analytics.logFileStats()!;
+ expect(firstQuery.sessionCount, 1,
+ reason:
+ 'There should only be one session after the initial send event');
+ expect(firstQuery.flutterChannelCount, {'flutterChannel': 1},
+ reason: 'There should only be one flutter channel logged');
+ expect(firstQuery.toolCount, {'flutter-tool': 1},
+ reason: 'There should only be one tool logged');
+ });
+
+ // Define a new clock that is outside of the session duration
+ final secondClock =
+ start.add(const Duration(minutes: kSessionDurationMinutes + 1));
+
+ // Use the new clock to send an event that will change the session identifier
+ withClock(Clock.fixed(secondClock), () {
+ analytics.send(testEvent);
+
+ final secondQuery = analytics.logFileStats()!;
+
+ // Construct the expected response for the second query
+ expect(secondQuery.startDateTime, DateTime(1995, 3, 3, 12, 0));
+ expect(secondQuery.minsFromStartDateTime, 31);
+ expect(secondQuery.endDateTime, DateTime(1995, 3, 3, 12, 31));
+ expect(secondQuery.minsFromEndDateTime, 0);
+ expect(secondQuery.sessionCount, 2);
+ expect(secondQuery.flutterChannelCount, {'flutterChannel': 2});
+ expect(secondQuery.toolCount, {'flutter-tool': 2});
+ expect(secondQuery.recordCount, 2);
+ expect(secondQuery.eventCount, {'hot_reload_time': 2});
+ });
+ });
+
+ test('Check that the log file shows two different tools being used', () {
+ // Use a for loop two initialize the second analytics instance
+ // twice to account for no events being sent on the first instance
+ // run for a given tool
+ Analytics? secondAnalytics;
+ for (var i = 0; i < 2; i++) {
+ secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+ }
+
+ // Send events with both instances of the classes
+ analytics.send(testEvent);
+ secondAnalytics!.send(testEvent);
+
+ // Query the log file stats to verify that there are two tools
+ final query = analytics.logFileStats()!;
+
+ expect(query.toolCount, {'flutter-tool': 1, 'dart-tool': 1},
+ reason: 'There should have been two tools in the persisted logs');
+ });
+
+ test('Check that log data missing some keys results in null for stats', () {
+ // The following string represents a log item that is malformed (missing the `tool` key)
+ const malformedLog = '{"client_id":"d40133a0-7ea6-4347-b668-ffae94bb8774",'
+ '"events":[{"name":"hot_reload_time","params":{"time_ns":345}}],'
+ '"user_properties":{'
+ '"session_id":{"value":1675193534342},'
+ '"flutter_channel":{"value":"ey-test-channel"},'
+ '"host":{"value":"macOS"},'
+ '"flutter_version":{"value":"Flutter 3.6.0-7.0.pre.47"},'
+ '"dart_version":{"value":"Dart 2.19.0"},'
+ // '"tool":{"value":"flutter-tools"},' NEEDS REMAIN REMOVED
+ '"local_time":{"value":"2023-01-31 14:32:14.592898 -0500"}}}';
+
+ logFile.writeAsStringSync(malformedLog);
+ final query = analytics.logFileStats();
+
+ expect(query, isNull,
+ reason:
+ 'The query should be null because `tool` is missing under `user_properties`');
+ });
+
+ test('Malformed local_time string should result in null for stats', () {
+ // The following string represents a log item that is malformed (missing the `tool` key)
+ const malformedLog = '{"client_id":"d40133a0-7ea6-4347-b668-ffae94bb8774",'
+ '"events":[{"name":"hot_reload_time","params":{"time_ns":345}}],'
+ '"user_properties":{'
+ '"session_id":{"value":1675193534342},'
+ '"flutter_channel":{"value":"ey-test-channel"},'
+ '"host":{"value":"macOS"},'
+ '"flutter_version":{"value":"Flutter 3.6.0-7.0.pre.47"},'
+ '"dart_version":{"value":"Dart 2.19.0"},'
+ '"tool":{"value":"flutter-tools"},'
+ '"local_time":{"value":"2023-xx-31 14:32:14.592898 -0500"}}}'; // PURPOSEFULLY MALFORMED
+
+ logFile.writeAsStringSync(malformedLog);
+ final query = analytics.logFileStats();
+
+ expect(query, isNull,
+ reason:
+ 'The query should be null because the `local_time` value is malformed');
+ });
+
+ test('Version is the same in the change log, pubspec, and constants.dart',
+ () {
+ // Parse the contents of the pubspec.yaml
+ final pubspecYamlString = io.File('pubspec.yaml').readAsStringSync();
+
+ // Parse into a yaml document to extract the version number
+ final doc = loadYaml(pubspecYamlString) as YamlMap;
+ final version = doc['version'] as String;
+
+ expect(version, kPackageVersion,
+ reason: 'The package version in the pubspec and '
+ 'constants.dart need to match\n'
+ 'Pubspec: $version && constants.dart: $kPackageVersion\n\n'
+ 'Make sure both are the same');
+
+ // Parse the contents of the change log file
+ final changeLogFirstLineString =
+ io.File('CHANGELOG.md').readAsLinesSync().first;
+ expect(changeLogFirstLineString.substring(3), kPackageVersion,
+ reason: 'The CHANGELOG.md file needs the first line to '
+ 'be the same version as the pubspec and constants.dart');
+ });
+
+ test('Null values for flutter parameters is reflected properly in log file',
+ () {
+ // Because we are using the `MemoryFileSystem.test` constructor,
+ // we don't have a real clock in the filesystem, and because we
+ // are checking the last modified timestamp for the session file
+ // to determine if we need to update the session id, manually setting
+ // that timestamp will ensure we are not updating session id when it
+ // first gets created
+ sessionFile.setLastModifiedSync(DateTime.now());
+
+ // Use a for loop two initialize the second analytics instance
+ // twice to account for no events being sent on the first instance
+ // run for a given tool
+ Analytics? secondAnalytics;
+ for (var i = 0; i < 2; i++) {
+ secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ // flutterChannel: flutterChannel, THIS NEEDS TO REMAIN REMOVED
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+ }
+
+ // Send an event and check that the query stats reflects what is expected
+ secondAnalytics!.send(testEvent);
+
+ // Query the log file stats to verify that there are two tools
+ final query = analytics.logFileStats()!;
+
+ expect(query.toolCount, {'dart-tool': 1},
+ reason: 'There should have only been on tool that sent events');
+ expect(query.flutterChannelCount.isEmpty, true,
+ reason:
+ 'The instance does not have flutter information so it should be 0');
+
+ // Sending a query with the first analytics instance which has flutter information
+ // available should reflect in the query that there is 1 flutter channel present
+ analytics.send(testEvent);
+ final query2 = analytics.logFileStats()!;
+
+ expect(query2.toolCount, {'dart-tool': 1, 'flutter-tool': 1},
+ reason: 'Two different analytics instances have '
+ 'been initialized and sent events');
+ expect(query2.sessionCount, query.sessionCount,
+ reason: 'The session should have remained the same');
+ expect(query2.flutterChannelCount, {'flutterChannel': 1},
+ reason: 'The first instance has flutter information initialized');
+ });
+
+ group('Testing against Google Analytics limitations:', () {
+ // Link to limitations documentation
+ // https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events?client_type=gtag#limitations
+ //
+ // Only the limitations specified below have been added, the other
+ // are not able to be validated because it will vary by each tool
+ //
+ // 1. Events can have a maximum of 25 user properties
+ // 2. User property names must be 24 characters or fewer
+ // 3. (Only for `tool` name) User property values must be 36 characters or fewer
+ // 4. Event names must be 40 characters or fewer, may only contain alpha-numeric
+ // characters and underscores, and must start with an alphabetic character
+ test('max 25 user properties per event', () {
+ final Map<String, Object> userPropPayload =
+ analytics.userProperty.preparePayload();
+ const maxUserPropKeys = 25;
+
+ expect(userPropPayload.keys.length < maxUserPropKeys, true,
+ reason: 'There are too many keys in the UserProperty payload');
+ });
+
+ test('max 24 characters for user prop keys', () {
+ final Map<String, Object> userPropPayload =
+ analytics.userProperty.preparePayload();
+ const maxUserPropLength = 24;
+
+ var userPropLengthValid = true;
+ final invalidUserProps = <String>[];
+ for (final key in userPropPayload.keys) {
+ if (key.length > maxUserPropLength) {
+ userPropLengthValid = false;
+ invalidUserProps.add(key);
+ }
+ }
+ expect(userPropLengthValid, true,
+ reason:
+ 'The max length for each user prop is $maxUserPropLength chars\n'
+ 'The below keys are too long:\n$invalidUserProps');
+ });
+
+ test('max 36 characters for user prop values (only `tool` key)', () {
+ // Checks item 3
+ // All tools must be under 36 characters (and enforce each tool
+ // begins with a letter)
+ final toolLabelPattern = RegExp(r'^[a-zA-Z][a-zA-Z\_-]{0,35}$');
+ var toolLengthValid = true;
+ final invalidTools = <DashTool>[];
+ for (final tool in DashTool.values) {
+ if (!toolLabelPattern.hasMatch(tool.label)) {
+ toolLengthValid = false;
+ invalidTools.add(tool);
+ }
+ }
+
+ expect(toolLengthValid, true,
+ reason:
+ 'All tool labels must be under 36 characters and begin with a letter\n'
+ 'The following are invalid\n$invalidTools');
+ });
+
+ test('max 40 characters for event names', () {
+ // Check that each event name is less than 40 chars and starts with
+ // an alphabetic character; the entire string has to be alphanumeric
+ // and underscores
+ final eventLabelPattern = RegExp(r'^[a-zA-Z]{1}[a-zA-Z0-9\_]{0,39}$');
+ var eventValid = true;
+ final invalidEvents = <DashEvent>[];
+ for (final event in DashEvent.values) {
+ if (!eventLabelPattern.hasMatch(event.label)) {
+ eventValid = false;
+ invalidEvents.add(event);
+ }
+ }
+
+ expect(eventValid, true,
+ reason: 'All event labels should have letters and underscores '
+ 'as a delimiter if needed; invalid events below\n$invalidEvents');
+ });
+ });
+
+ test('Confirm credentials for GA', () {
+ expect(kGoogleAnalyticsApiSecret, 'Ka1jc8tZSzWc_GXMWHfPHA');
+ expect(kGoogleAnalyticsMeasurementId, 'G-04BXPVBCWJ');
+ });
+
+ test('Consent message is formatted correctly for the flutter tool', () {
+ // Retrieve the consent message for flutter tools
+ final consentMessage = analytics.getConsentMessage;
+
+ expect(consentMessage, equalsIgnoringWhitespace(r'''
+The Flutter CLI developer tool uses Google Analytics to report usage and diagnostic
+data along with package dependencies, and crash reporting to send basic crash
+reports. This data is used to help improve the Dart platform, Flutter framework,
+and related tools.
+
+Telemetry is not sent on the very first run. To disable reporting of telemetry,
+run this terminal command:
+
+ flutter --disable-analytics
+
+If you opt out of telemetry, an opt-out event will be sent, and then no further
+information will be sent. This data is collected in accordance with the Google
+Privacy Policy (https://policies.google.com/privacy).
+'''));
+ });
+
+ test('Consent message is formatted correctly for any tool other than flutter',
+ () {
+ // Create a new instance of the analytics class with the new tool
+ final secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: 'ey-test-channel',
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+
+ // Retrieve the consent message for flutter tools
+ final consentMessage = secondAnalytics.getConsentMessage;
+
+ expect(consentMessage, equalsIgnoringWhitespace(r'''
+The Dart CLI developer tool uses Google Analytics to report usage and diagnostic
+data along with package dependencies, and crash reporting to send basic crash
+reports. This data is used to help improve the Dart platform, Flutter framework,
+and related tools.
+
+Telemetry is not sent on the very first run. To disable reporting of telemetry,
+run this terminal command:
+
+ dart --disable-analytics
+
+If you opt out of telemetry, an opt-out event will be sent, and then no further
+information will be sent. This data is collected in accordance with the Google
+Privacy Policy (https://policies.google.com/privacy).
+'''));
+ });
+
+ test('Equality operator works for identical events', () {
+ final eventOne = Event.clientRequest(
+ duration: 'duration',
+ latency: 'latency',
+ method: 'method',
+ );
+ final eventTwo = Event.clientRequest(
+ duration: 'duration',
+ latency: 'latency',
+ method: 'method',
+ );
+
+ expect(eventOne == eventTwo, true);
+ });
+
+ test('Equality operator works for non-identical events', () {
+ final eventOne = Event.clientRequest(
+ duration: 'duration',
+ latency: 'latency',
+ method: 'method',
+ added: 'DIFFERENT FROM EVENT TWO',
+ );
+ final eventTwo = Event.clientRequest(
+ duration: 'duration',
+ latency: 'latency',
+ method: 'method',
+ );
+
+ expect(eventOne == eventTwo, false);
+ });
+
+ test('Find a match for an event in a list of events', () {
+ final eventList = [
+ Event.analyticsCollectionEnabled(status: true),
+ Event.memoryInfo(rss: 500),
+ Event.clientRequest(
+ duration: 'duration', latency: 'latency', method: 'method'),
+ ];
+
+ final eventToMatch = Event.memoryInfo(rss: 500);
+
+ expect(eventList.contains(eventToMatch), true);
+ expect(eventList.where((element) => element == eventToMatch).length, 1);
+ });
+
+ group('Unit tests for util dartSDKVersion', () {
+ test('parses correctly for non-stable version', () {
+ final originalVersion =
+ '3.4.0-148.0.dev (dev) (Thu Feb 15 12:05:45 2024 -0800) on "macos_arm64"';
+
+ expect(parseDartSDKVersion(originalVersion),
+ '3.4.0 (build 3.4.0-148.0.dev)');
+ });
+
+ test('parses correctly for stable version', () {
+ final originalVersion =
+ '3.3.0 (stable) (Tue Feb 13 10:25:19 2024 +0000) on "macos_arm64"';
+
+ expect(parseDartSDKVersion(originalVersion), '3.3.0');
+ });
+ });
+}
diff --git a/pkgs/unified_analytics/test/workflow_test.dart b/pkgs/unified_analytics/test/workflow_test.dart
new file mode 100644
index 0000000..3a623a0
--- /dev/null
+++ b/pkgs/unified_analytics/test/workflow_test.dart
@@ -0,0 +1,382 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' as io;
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:test/test.dart';
+import 'package:unified_analytics/src/constants.dart';
+import 'package:unified_analytics/src/enums.dart';
+import 'package:unified_analytics/src/utils.dart';
+import 'package:unified_analytics/unified_analytics.dart';
+
+void main() {
+ late MemoryFileSystem fs;
+ late Directory home;
+ late Directory dartToolDirectory;
+ late File clientIdFile;
+ late File sessionFile;
+ late File configFile;
+ late File logFile;
+ late File dismissedSurveyFile;
+
+ const homeDirName = 'home';
+ const initialTool = DashTool.flutterTool;
+ const secondTool = DashTool.dartTool;
+ const toolsMessageVersion = 1;
+ const toolsMessage = 'toolsMessage';
+ const flutterChannel = 'flutterChannel';
+ const flutterVersion = 'flutterVersion';
+ const dartVersion = 'dartVersion';
+ const platform = DevicePlatform.macos;
+
+ final testEvent = Event.hotReloadTime(timeMs: 50);
+
+ setUp(() {
+ // Setup the filesystem with the home directory
+ final fsStyle =
+ io.Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix;
+ fs = MemoryFileSystem.test(style: fsStyle);
+ home = fs.directory(homeDirName);
+ dartToolDirectory = home.childDirectory(kDartToolDirectoryName);
+
+ // The 3 files that should have been generated
+ clientIdFile = home
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kClientIdFileName);
+ sessionFile =
+ home.childDirectory(kDartToolDirectoryName).childFile(kSessionFileName);
+ configFile =
+ home.childDirectory(kDartToolDirectoryName).childFile(kConfigFileName);
+ logFile =
+ home.childDirectory(kDartToolDirectoryName).childFile(kLogFileName);
+ dismissedSurveyFile = home
+ .childDirectory(kDartToolDirectoryName)
+ .childFile(kDismissedSurveyFileName);
+ });
+
+ test('Confirm workflow for first run', () {
+ final firstAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(firstAnalytics.shouldShowMessage, true);
+ expect(firstAnalytics.okToSend, false);
+
+ firstAnalytics.clientShowedMessage();
+ expect(firstAnalytics.shouldShowMessage, false);
+ expect(firstAnalytics.okToSend, false,
+ reason: 'On the first run, we should not be ok '
+ 'to send any events, even if the user accepts');
+ });
+
+ test('Confirm workflow for updated tools message version + new tool', () {
+ // Helper function to check the state of the instance
+ void checkAnalyticsInstance(Analytics instance) {
+ expect(instance.shouldShowMessage, true);
+ expect(instance.okToSend, false);
+
+ instance.clientShowedMessage();
+ expect(instance.shouldShowMessage, false);
+ expect(instance.okToSend, false,
+ reason: 'On the first run, we should not be ok '
+ 'to send any events, even if the user accepts');
+ }
+
+ final firstAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ checkAnalyticsInstance(firstAnalytics);
+
+ // Instance where we increment the version of the message
+ final secondAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion + 1, // Incrementing version
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ // Running the same checks for the second instance, it should
+ // behave the same as if it was a first run
+ checkAnalyticsInstance(secondAnalytics);
+
+ // Instance for a different tool with the incremented version
+ final thirdAnalytics = Analytics.fake(
+ tool: secondTool, // Different tool
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion + 1, // Incrementing version
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ // The instance with a new tool getting onboarded should be
+ // treated the same as the 2 previous instances
+ checkAnalyticsInstance(thirdAnalytics);
+ });
+
+ test('Confirm workflow for checking tools into the config file', () {
+ final firstAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ // Host of assertions to ensure all required artifacts
+ // are created
+ expect(dartToolDirectory.existsSync(), true,
+ reason: 'The directory should have been created');
+ expect(clientIdFile.existsSync(), true,
+ reason: 'The $kClientIdFileName file was not found');
+ expect(sessionFile.existsSync(), true,
+ reason: 'The $kSessionFileName file was not found');
+ expect(configFile.existsSync(), true,
+ reason: 'The $kConfigFileName was not found');
+ expect(logFile.existsSync(), true,
+ reason: 'The $kLogFileName file was not found');
+ expect(dismissedSurveyFile.existsSync(), true,
+ reason: 'The $dismissedSurveyFile file was not found');
+ expect(
+ dartToolDirectory.listSync().length,
+ equals(5),
+ reason: 'There should only be 5 files in the $kDartToolDirectoryName '
+ 'directory',
+ );
+ expect(configFile.readAsStringSync(), kConfigString);
+
+ expect(firstAnalytics.shouldShowMessage, true);
+
+ // Attempting to send a message with this instance should be
+ // blocked because it has not invoked `clientShowedMessage()`
+ // and it is the first run
+ //
+ // Even after invoking the method, it should be prevented from
+ // sending a message because it is the first time the tool was
+ // run in this instance
+ firstAnalytics.send(testEvent);
+ expect(logFile.readAsLinesSync().length, 0);
+ firstAnalytics.clientShowedMessage();
+
+ // Attempt to send two events, both should be blocked because it is
+ // part of the first instance
+ firstAnalytics.send(testEvent);
+ firstAnalytics.send(testEvent);
+ expect(logFile.readAsLinesSync().length, 0);
+
+ // Creating a second analytics instance from the same tool now should
+ // allow for events to be sent
+ final secondAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(secondAnalytics.shouldShowMessage, false);
+ secondAnalytics.send(testEvent);
+ expect(logFile.readAsLinesSync().length, 1,
+ reason: 'Events will be blocked until invoking method '
+ 'ensuring client has seen message');
+
+ secondAnalytics.send(testEvent);
+ secondAnalytics.send(testEvent);
+ expect(logFile.readAsLinesSync().length, 3);
+
+ // Next, we will want to confirm that the message should be showing when
+ // a new analytics instance has been created with a newer version for
+ // message that should be shown
+ //
+ // In this case, it should be treated as a new tool being added for the
+ // first time and all events should be blocked
+
+ // Delete the log file to reset the counter of events sent
+ logFile.deleteSync();
+ final thirdAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion + 1, // Incrementing version
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(logFile.existsSync(), true,
+ reason: 'The $kLogFileName file was not found');
+ expect(thirdAnalytics.shouldShowMessage, true,
+ reason: 'New version number should require showing message');
+ thirdAnalytics.send(testEvent);
+ expect(logFile.readAsLinesSync().length, 0);
+ thirdAnalytics.clientShowedMessage();
+
+ // Attempt to send two events, both should be blocked because it is
+ // part of the third instance which has a new version for the consent
+ // message which will be treated as a new tool being onboarded
+ thirdAnalytics.send(testEvent);
+ thirdAnalytics.send(testEvent);
+ expect(logFile.readAsLinesSync().length, 0);
+
+ // The fourth instance of the analytics class with the consent message
+ // version incremented should now be able to send messages
+ final fourthAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion + 1, // Incrementing version
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(fourthAnalytics.shouldShowMessage, false);
+ fourthAnalytics.send(testEvent);
+ expect(logFile.readAsLinesSync().length, 1,
+ reason: 'Events will be blocked until invoking method '
+ 'ensuring client has seen message');
+
+ fourthAnalytics.send(testEvent);
+ fourthAnalytics.send(testEvent);
+ expect(logFile.readAsLinesSync().length, 3);
+ });
+
+ test('Disable second instance if first one did not show message', () {
+ final firstAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(firstAnalytics.shouldShowMessage, true);
+
+ final secondAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(secondAnalytics.shouldShowMessage, true);
+
+ secondAnalytics.clientShowedMessage();
+
+ final thirdAnalytics = Analytics.fake(
+ tool: initialTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: toolsMessageVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: flutterVersion,
+ dartVersion: dartVersion,
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(thirdAnalytics.shouldShowMessage, false);
+ });
+
+ test('Passing large version number gets logged in config', () {
+ final firstVersion = toolsMessageVersion + 3;
+ final secondAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: firstVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+ secondAnalytics.clientShowedMessage();
+
+ expect(
+ configFile
+ .readAsStringSync()
+ .endsWith('${secondTool.label}=$dateStamp,$firstVersion\n'),
+ true);
+
+ // Create a new instane of the secondTool with an even
+ // bigger version
+ final secondVersion = firstVersion + 3;
+ final thirdAnalytics = Analytics.fake(
+ tool: secondTool,
+ homeDirectory: home,
+ flutterChannel: flutterChannel,
+ toolsMessageVersion: secondVersion,
+ toolsMessage: toolsMessage,
+ flutterVersion: 'Flutter 3.6.0-7.0.pre.47',
+ dartVersion: 'Dart 2.19.0',
+ fs: fs,
+ platform: platform,
+ );
+
+ expect(
+ configFile
+ .readAsStringSync()
+ .endsWith('${secondTool.label}=$dateStamp,$firstVersion\n'),
+ true);
+
+ // After invoking this method, it will get updated
+ // in the config with the next version
+ thirdAnalytics.clientShowedMessage();
+
+ expect(
+ configFile
+ .readAsStringSync()
+ .endsWith('${secondTool.label}=$dateStamp,$secondVersion\n'),
+ true);
+ });
+}